redquark-amiberry-rb/src/osdep/gui/main_window.cpp

647 lines
19 KiB
C++
Raw Normal View History

#include <iostream>
#include <guisan.hpp>
#include <SDL_ttf.h>
#include <guisan/sdl.hpp>
#include "guisan/sdl/sdltruetypefont.hpp"
2015-05-13 18:47:23 +00:00
#include "SelectorEntry.hpp"
#include "sysconfig.h"
#include "sysdeps.h"
#include "config.h"
#include "options.h"
#include "uae.h"
#include "gui.h"
#include "gui_handling.h"
#include "memory.h"
#include "pandora_gfx.h"
2015-05-13 18:47:23 +00:00
bool gui_running = false;
static int last_active_panel = 1;
2016-10-15 20:49:53 +02:00
ConfigCategory categories[] =
{
{ "Paths", "data/paths.ico", NULL, NULL, InitPanelPaths, ExitPanelPaths, RefreshPanelPaths },
{ "Configurations", "data/file.ico", NULL, NULL, InitPanelConfig, ExitPanelConfig, RefreshPanelConfig },
{ "CPU and FPU", "data/cpu.ico", NULL, NULL, InitPanelCPU, ExitPanelCPU, RefreshPanelCPU },
{ "Chipset", "data/cpu.ico", NULL, NULL, InitPanelChipset, ExitPanelChipset, RefreshPanelChipset },
{ "ROM", "data/chip.ico", NULL, NULL, InitPanelROM, ExitPanelROM, RefreshPanelROM },
{ "RAM", "data/chip.ico", NULL, NULL, InitPanelRAM, ExitPanelRAM, RefreshPanelRAM },
{ "Floppy drives", "data/35floppy.ico", NULL, NULL, InitPanelFloppy, ExitPanelFloppy, RefreshPanelFloppy },
{ "Hard drives / CD", "data/drive.ico", NULL, NULL, InitPanelHD, ExitPanelHD, RefreshPanelHD },
{ "Display", "data/screen.ico", NULL, NULL, InitPanelDisplay, ExitPanelDisplay, RefreshPanelDisplay },
{ "Sound", "data/sound.ico", NULL, NULL, InitPanelSound, ExitPanelSound, RefreshPanelSound },
{ "Input", "data/joystick.ico", NULL, NULL, InitPanelInput, ExitPanelInput, RefreshPanelInput },
{ "Miscellaneous", "data/misc.ico", NULL, NULL, InitPanelMisc, ExitPanelMisc, RefreshPanelMisc },
{ "Savestates", "data/savestate.png", NULL, NULL, InitPanelSavestate, ExitPanelSavestate, RefreshPanelSavestate },
{ NULL, NULL, NULL, NULL, NULL, NULL, NULL }
2015-05-13 18:47:23 +00:00
};
enum { PANEL_PATHS, PANEL_CONFIGURATIONS, PANEL_CPU, PANEL_CHIPSET, PANEL_ROM, PANEL_RAM,
PANEL_FLOPPY, PANEL_HD, PANEL_DISPLAY, PANEL_SOUND, PANEL_INPUT, PANEL_MISC, PANEL_SAVESTATES,
NUM_PANELS
};
2015-05-13 18:47:23 +00:00
2016-09-23 00:01:16 +02:00
/*
* SDL Stuff we need
*/
SDL_Surface* gui_screen;
SDL_Texture* gui_texture;
SDL_Event event;
/*
* Guisan SDL stuff we need
*/
gcn::SDLInput* gui_input;
gcn::SDLGraphics* gui_graphics;
gcn::SDLImageLoader* gui_imageLoader;
gcn::SDLTrueTypeFont* gui_font;
/*
* Guisan stuff we need
*/
2015-05-13 18:47:23 +00:00
gcn::Gui* uae_gui;
gcn::Container* gui_top;
gcn::Container* selectors;
2015-05-13 18:47:23 +00:00
gcn::Color gui_baseCol;
gcn::Color gui_baseColLabel;
gcn::Color colSelectorInactive;
gcn::Color colSelectorActive;
namespace widgets
2015-10-11 14:23:51 +02:00
{
// Main buttons
gcn::Button* cmdQuit;
gcn::Button* cmdReset;
gcn::Button* cmdRestart;
gcn::Button* cmdStart;
gcn::Button* cmdShutdown;
2015-10-11 14:23:51 +02:00
}
2016-10-15 20:49:53 +02:00
/* Flag for changes in rtarea:
Bit 0: any HD in config?
Bit 1: force because add/remove HD was clicked
Bit 2: socket_emu on
Bit 3: mousehack on
Bit 4: rtgmem on
Bit 5: chipmem larger than 2MB
gui_rtarea_flags_onenter is set before GUI is shown, bit 1 may change during GUI display.
*/
static int gui_rtarea_flags_onenter;
static int gui_create_rtarea_flag(struct uae_prefs *p)
2015-10-11 14:23:51 +02:00
{
int flag = 0;
if(count_HDs(p) > 0)
flag |= 1;
if (p->socket_emu)
flag |= 4;
if (p->input_tablet > 0)
flag |= 8;
if(p->rtgmem_size)
flag |= 16;
2015-10-11 14:23:51 +02:00
if (p->chipmem_size > 2 * 1024 * 1024)
flag |= 32;
return flag;
}
2017-01-29 10:36:18 +01:00
void gui_force_rtarea_hdchange()
{
gui_rtarea_flags_onenter |= 2;
2015-10-11 14:23:51 +02:00
}
2017-01-29 10:36:18 +01:00
static void (*refreshFuncAfterDraw)() = nullptr;
2017-01-29 10:36:18 +01:00
void RegisterRefreshFunc(void (*func)())
{
refreshFuncAfterDraw = func;
}
2015-10-11 14:23:51 +02:00
2015-05-13 18:47:23 +00:00
namespace sdl
{
void gui_init()
{
//-------------------------------------------------
// Create new screen for GUI
//-------------------------------------------------
gui_screen = SDL_CreateRGBSurface(0, GUI_WIDTH, GUI_HEIGHT, 32, 0, 0, 0, 0);
check_error_sdl(gui_screen == nullptr, "Unable to create a surface");
SDL_RenderSetLogicalSize(renderer, GUI_WIDTH, GUI_HEIGHT);
gui_texture = SDL_CreateTexture(renderer,
SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STREAMING,
GUI_WIDTH,
GUI_HEIGHT);
check_error_sdl(gui_texture == nullptr, "Unable to create texture");
SDL_ShowCursor(SDL_ENABLE);
//-------------------------------------------------
// Create helpers for guichan
//-------------------------------------------------
gui_imageLoader = new gcn::SDLImageLoader();
// The ImageLoader in use is static and must be set to be
// able to load images
gcn::Image::setImageLoader(gui_imageLoader);
gui_graphics = new gcn::SDLGraphics();
// Set the target for the graphics object to be the screen.
// In other words, we will draw to the screen.
// Note, any surface will do, it doesn't have to be the screen.
gui_graphics->setTarget(gui_screen);
gui_input = new gcn::SDLInput();
uae_gui = new gcn::Gui();
uae_gui->setGraphics(gui_graphics);
uae_gui->setInput(gui_input);
}
void gui_halt()
{
delete uae_gui;
delete gui_imageLoader;
delete gui_input;
delete gui_graphics;
SDL_FreeSurface(gui_screen);
SDL_DestroyTexture(gui_texture);
2017-01-29 10:36:18 +01:00
gui_screen = nullptr;
}
void checkInput()
{
while (SDL_PollEvent(&event))
{
if (event.type == SDL_KEYDOWN)
{
gcn::FocusHandler* focusHdl;
gcn::Widget* activeWidget;
if (event.key.keysym.sym == currprefs.key_for_menu)
{
if (emulating && widgets::cmdStart->isEnabled())
2016-09-23 00:01:16 +02:00
{
//------------------------------------------------
// Continue emulation
//------------------------------------------------
gui_running = false;
2016-09-23 00:01:16 +02:00
}
2016-10-15 20:49:53 +02:00
else
{
//------------------------------------------------
// First start of emulator -> reset Amiga
//------------------------------------------------
uae_reset(0, 1);
gui_running = false;
}
}
else
switch (event.key.keysym.sym)
{
case SDLK_q:
//-------------------------------------------------
// Quit entire program via Q on keyboard
//-------------------------------------------------
focusHdl = gui_top->_getFocusHandler();
activeWidget = focusHdl->getFocused();
2017-01-29 10:36:18 +01:00
if (dynamic_cast<gcn::TextField*>(activeWidget) == nullptr)
2016-10-15 20:49:53 +02:00
{
// ...but only if we are not in a Textfield...
uae_quit();
2016-10-15 20:49:53 +02:00
gui_running = false;
}
break;
case VK_ESCAPE:
case VK_R:
//-------------------------------------------------
// Reset Amiga
//-------------------------------------------------
uae_reset(1, 1);
gui_running = false;
break;
case VK_X:
case VK_A:
//------------------------------------------------
// Simulate press of enter when 'X' pressed
//------------------------------------------------
event.key.keysym.sym = SDLK_RETURN;
gui_input->pushInput(event); // Fire key down
event.type = SDL_KEYUP; // and the key up
break;
case VK_UP:
if (HandleNavigation(DIRECTION_UP))
continue; // Don't change value when enter ComboBox -> don't send event to control
break;
case VK_DOWN:
if (HandleNavigation(DIRECTION_DOWN))
continue; // Don't change value when enter ComboBox -> don't send event to control
break;
case VK_LEFT:
if (HandleNavigation(DIRECTION_LEFT))
continue; // Don't change value when enter Slider -> don't send event to control
break;
case VK_RIGHT:
if (HandleNavigation(DIRECTION_RIGHT))
continue; // Don't change value when enter Slider -> don't send event to control
break;
}
}
else if (event.type == SDL_QUIT)
{
//-------------------------------------------------
// Quit entire program via SQL-Quit
//-------------------------------------------------
uae_quit();
gui_running = false;
}
//-------------------------------------------------
// Send event to guichan-controls
//-------------------------------------------------
gui_input->pushInput(event);
}
}
void gui_run()
{
//-------------------------------------------------
// The main loop
//-------------------------------------------------
while(gui_running)
{
// Poll input
checkInput();
if(gui_rtarea_flags_onenter != gui_create_rtarea_flag(&changed_prefs))
DisableResume();
// Now we let the Gui object perform its logic.
uae_gui->logic();
// Now we let the Gui object draw itself.
uae_gui->draw();
2016-10-15 20:49:53 +02:00
// Finally we update the screen.
// Update the texture from the surface
2017-01-29 10:36:18 +01:00
SDL_UpdateTexture(gui_texture, nullptr, gui_screen->pixels, gui_screen->pitch);
// Copy the texture on the renderer
2017-01-29 10:36:18 +01:00
SDL_RenderCopy(renderer, gui_texture, nullptr, nullptr);
// Update the window surface (show the renderer)
SDL_RenderPresent(renderer);
2016-10-15 20:49:53 +02:00
2017-01-29 10:36:18 +01:00
if(refreshFuncAfterDraw != nullptr)
2016-10-15 20:49:53 +02:00
{
void (*currFunc)(void) = refreshFuncAfterDraw;
2017-01-29 10:36:18 +01:00
refreshFuncAfterDraw = nullptr;
2016-10-15 20:49:53 +02:00
currFunc();
}
}
}
2016-10-15 20:49:53 +02:00
2015-05-13 18:47:23 +00:00
}
2015-10-11 14:23:51 +02:00
namespace widgets
{
class MainButtonActionListener : public gcn::ActionListener
{
public:
void action(const gcn::ActionEvent& actionEvent)
{
if (actionEvent.getSource() == cmdShutdown)
{
// ------------------------------------------------
// Shutdown the host (power off)
// ------------------------------------------------
uae_quit();
gui_running = false;
host_shutdown();
}
if (actionEvent.getSource() == cmdQuit)
{
//-------------------------------------------------
// Quit entire program via click on Quit-button
//-------------------------------------------------
uae_quit();
gui_running = false;
}
else if(actionEvent.getSource() == cmdReset)
{
//-------------------------------------------------
// Reset Amiga via click on Reset-button
//-------------------------------------------------
uae_reset(1, 1);
gui_running = false;
}
else if(actionEvent.getSource() == cmdRestart)
{
//-------------------------------------------------
// Restart emulator
//-------------------------------------------------
char tmp[MAX_PATH];
fetch_configurationpath (tmp, sizeof (tmp));
if(strlen(last_loaded_config) > 0)
strcat (tmp, last_loaded_config);
else
{
strcat (tmp, OPTIONSFILENAME);
strcat (tmp, ".uae");
}
uae_restart(0, tmp);
gui_running = false;
}
else if(actionEvent.getSource() == cmdStart)
{
if(emulating && widgets::cmdStart->isEnabled())
{
//------------------------------------------------
// Continue emulation
//------------------------------------------------
gui_running = false;
}
else
{
//------------------------------------------------
// First start of emulator -> reset Amiga
//------------------------------------------------
uae_reset(0, 1);
gui_running = false;
}
}
}
};
MainButtonActionListener* mainButtonActionListener;
class PanelFocusListener : public gcn::FocusListener
{
public:
void focusGained(const gcn::Event& event)
{
int i;
2017-01-29 10:36:18 +01:00
for(i=0; categories[i].category != nullptr; ++i)
{
if(event.getSource() == categories[i].selector)
{
categories[i].selector->setActive(true);
categories[i].panel->setVisible(true);
last_active_panel = i;
}
else
{
categories[i].selector->setActive(false);
categories[i].panel->setVisible(false);
}
}
}
};
PanelFocusListener* panelFocusListener;
2015-05-13 18:47:23 +00:00
void gui_init()
{
2015-05-13 18:47:23 +00:00
int i;
int yPos;
//-------------------------------------------------
// Define base colors
//-------------------------------------------------
gui_baseCol.r = 192;
gui_baseCol.g = 192;
gui_baseCol.b = 208;
gui_baseColLabel.r = gui_baseCol.r;
gui_baseColLabel.g = gui_baseCol.g;
gui_baseColLabel.b = gui_baseCol.b;
gui_baseColLabel.a = 192;
colSelectorInactive.r = 255;
colSelectorInactive.g = 255;
colSelectorInactive.b = 255;
colSelectorActive.r = 192;
colSelectorActive.g = 192;
colSelectorActive.b = 255;
//-------------------------------------------------
// Create container for main page
//-------------------------------------------------
gui_top = new gcn::Container();
gui_top->setDimension(gcn::Rectangle(0, 0, GUI_WIDTH, GUI_HEIGHT));
// gui_top->setDimension(gcn::Rectangle((gui_screen->w - GUI_WIDTH) / 2, (gui_screen->h - GUI_HEIGHT) / 2, GUI_WIDTH, GUI_HEIGHT));
2015-05-13 18:47:23 +00:00
gui_top->setBaseColor(gui_baseCol);
uae_gui->setTop(gui_top);
//-------------------------------------------------
// Initialize fonts
//-------------------------------------------------
TTF_Init();
gui_font = new gcn::SDLTrueTypeFont("data/FreeSans.ttf", 14);
2015-05-13 18:47:23 +00:00
gcn::Widget::setGlobalFont(gui_font);
//--------------------------------------------------
// Create main buttons
//--------------------------------------------------
2015-05-13 18:47:23 +00:00
mainButtonActionListener = new MainButtonActionListener();
cmdQuit = new gcn::Button("Quit");
cmdQuit->setSize(BUTTON_WIDTH, BUTTON_HEIGHT);
2015-05-13 18:47:23 +00:00
cmdQuit->setBaseColor(gui_baseCol);
cmdQuit->setId("Quit");
cmdQuit->addActionListener(mainButtonActionListener);
cmdShutdown = new gcn::Button("Shutdown");
cmdShutdown->setSize(BUTTON_WIDTH, BUTTON_HEIGHT);
cmdShutdown->setBaseColor(gui_baseCol);
cmdShutdown->setId("Shutdown");
cmdShutdown->addActionListener(mainButtonActionListener);
cmdReset = new gcn::Button("Reset");
cmdReset->setSize(BUTTON_WIDTH, BUTTON_HEIGHT);
2015-05-13 18:47:23 +00:00
cmdReset->setBaseColor(gui_baseCol);
cmdReset->setId("Reset");
2015-05-13 18:47:23 +00:00
cmdReset->addActionListener(mainButtonActionListener);
cmdRestart = new gcn::Button("Restart");
cmdRestart->setSize(BUTTON_WIDTH, BUTTON_HEIGHT);
2015-05-13 18:47:23 +00:00
cmdRestart->setBaseColor(gui_baseCol);
cmdRestart->setId("Restart");
2015-05-13 18:47:23 +00:00
cmdRestart->addActionListener(mainButtonActionListener);
cmdStart = new gcn::Button("Start");
if(emulating)
cmdStart->setCaption("Resume");
cmdStart->setSize(BUTTON_WIDTH, BUTTON_HEIGHT);
2015-05-13 18:47:23 +00:00
cmdStart->setBaseColor(gui_baseCol);
cmdStart->setId("Start");
2015-05-13 18:47:23 +00:00
cmdStart->addActionListener(mainButtonActionListener);
//--------------------------------------------------
2015-05-13 18:47:23 +00:00
// Create selector entries
//--------------------------------------------------
int workAreaHeight = GUI_HEIGHT - 2 * DISTANCE_BORDER - BUTTON_HEIGHT - DISTANCE_NEXT_Y;
2015-05-13 18:47:23 +00:00
selectors = new gcn::Container();
selectors->setSize(150, workAreaHeight - 2);
selectors->setBaseColor(colSelectorInactive);
selectors->setBorderSize(1);
int panelStartX = DISTANCE_BORDER + selectors->getWidth() + 2 + 11;
2015-05-13 18:47:23 +00:00
panelFocusListener = new PanelFocusListener();
2017-01-29 10:36:18 +01:00
for(i=0; categories[i].category != nullptr; ++i)
2015-05-13 18:47:23 +00:00
{
categories[i].selector = new gcn::SelectorEntry(categories[i].category, categories[i].imagepath);
categories[i].selector->setActiveColor(colSelectorActive);
categories[i].selector->setInactiveColor(colSelectorInactive);
categories[i].selector->setSize(150, 24);
categories[i].selector->addFocusListener(panelFocusListener);
categories[i].panel = new gcn::Container();
categories[i].panel->setId(categories[i].category);
categories[i].panel->setSize(GUI_WIDTH - panelStartX - DISTANCE_BORDER - 1, workAreaHeight - 2);
categories[i].panel->setBaseColor(gui_baseCol);
categories[i].panel->setBorderSize(1);
categories[i].panel->setVisible(false);
2015-05-13 18:47:23 +00:00
}
//--------------------------------------------------
// Initialize panels
//--------------------------------------------------
2017-01-29 10:36:18 +01:00
for(i=0; categories[i].category != nullptr; ++i)
2015-05-13 18:47:23 +00:00
{
2017-01-29 10:36:18 +01:00
if(categories[i].InitFunc != nullptr)
(*categories[i].InitFunc) (categories[i]);
2015-05-13 18:47:23 +00:00
}
//--------------------------------------------------
2015-05-13 18:47:23 +00:00
// Place everything on main form
//--------------------------------------------------
2015-05-13 18:47:23 +00:00
gui_top->add(cmdReset, DISTANCE_BORDER, GUI_HEIGHT - DISTANCE_BORDER - BUTTON_HEIGHT);
gui_top->add(cmdQuit, DISTANCE_BORDER + BUTTON_WIDTH + DISTANCE_NEXT_X, GUI_HEIGHT - DISTANCE_BORDER - BUTTON_HEIGHT);
gui_top->add(cmdShutdown, DISTANCE_BORDER + 2 * BUTTON_WIDTH + 2 * DISTANCE_NEXT_X, GUI_HEIGHT - DISTANCE_BORDER - BUTTON_HEIGHT);
gui_top->add(cmdStart, GUI_WIDTH - DISTANCE_BORDER - BUTTON_WIDTH, GUI_HEIGHT - DISTANCE_BORDER - BUTTON_HEIGHT);
2015-05-13 18:47:23 +00:00
gui_top->add(selectors, DISTANCE_BORDER + 1, DISTANCE_BORDER + 1);
2017-01-29 10:36:18 +01:00
for(i=0, yPos=0; categories[i].category != nullptr; ++i, yPos += 24)
2015-05-13 18:47:23 +00:00
{
selectors->add(categories[i].selector, 0, yPos);
gui_top->add(categories[i].panel, panelStartX, DISTANCE_BORDER + 1);
2015-05-13 18:47:23 +00:00
}
//--------------------------------------------------
// Activate last active panel
//--------------------------------------------------
categories[last_active_panel].selector->requestFocus();
}
2015-05-13 18:47:23 +00:00
void gui_halt()
{
2015-05-13 18:47:23 +00:00
int i;
2017-01-29 10:36:18 +01:00
for(i=0; categories[i].category != nullptr; ++i)
2015-05-13 18:47:23 +00:00
{
2017-01-29 10:36:18 +01:00
if(categories[i].ExitFunc != nullptr)
(*categories[i].ExitFunc) ();
2015-05-13 18:47:23 +00:00
}
2017-01-29 10:36:18 +01:00
for(i=0; categories[i].category != nullptr; ++i)
delete categories[i].selector;
2015-05-13 18:47:23 +00:00
delete panelFocusListener;
delete selectors;
delete cmdQuit;
delete cmdShutdown;
2015-05-13 18:47:23 +00:00
delete cmdReset;
delete cmdRestart;
delete cmdStart;
2015-05-13 18:47:23 +00:00
delete mainButtonActionListener;
2015-05-13 18:47:23 +00:00
delete gui_font;
delete gui_top;
}
2015-05-13 18:47:23 +00:00
}
2017-01-29 10:36:18 +01:00
void RefreshAllPanels()
2015-05-13 18:47:23 +00:00
{
int i;
2017-01-29 10:36:18 +01:00
for(i=0; categories[i].category != nullptr; ++i)
{
2017-01-29 10:36:18 +01:00
if(categories[i].RefreshFunc != nullptr)
(*categories[i].RefreshFunc) ();
}
2015-05-13 18:47:23 +00:00
}
2017-01-29 10:36:18 +01:00
void DisableResume()
2015-10-11 14:23:51 +02:00
{
if(emulating)
{
widgets::cmdStart->setEnabled(false);
gcn::Color backCol;
backCol.r = 128;
backCol.g = 128;
backCol.b = 128;
widgets::cmdStart->setForegroundColor(backCol);
}
2015-10-11 14:23:51 +02:00
}
2017-01-29 10:36:18 +01:00
void run_gui()
2015-05-13 18:47:23 +00:00
{
gui_running = true;
gui_rtarea_flags_onenter = gui_create_rtarea_flag(&currprefs);
try
{
sdl::gui_init();
widgets::gui_init();
sdl::gui_run();
widgets::gui_halt();
sdl::gui_halt();
}
// Catch all guisan exceptions.
catch (gcn::Exception e)
{
2017-01-29 10:36:18 +01:00
cout << e.getMessage() << endl;
uae_quit();
}
// Catch all Std exceptions.
2017-01-29 10:36:18 +01:00
catch (exception e)
{
2017-01-29 10:36:18 +01:00
cout << "Std exception: " << e.what() << endl;
uae_quit();
}
// Catch all unknown exceptions.
catch (...)
{
2017-01-29 10:36:18 +01:00
cout << "Unknown exception" << endl;
uae_quit();
}
if(quit_program > UAE_QUIT || quit_program < -UAE_QUIT)
{
//--------------------------------------------------
// Prepare everything for Reset of Amiga
//--------------------------------------------------
currprefs.nr_floppies = changed_prefs.nr_floppies;
if(gui_rtarea_flags_onenter != gui_create_rtarea_flag(&changed_prefs))
quit_program = -UAE_RESET_HARD; // Hardreset required...
}
2015-05-13 18:47:23 +00:00
}