/****** Main menu constructor ******/ main_menu::main_menu(QWidget *parent) : QWidget(parent) { //Setup actions QAction* open = new QAction("Open", this); QAction* quit = new QAction ("Quit", this); QAction* pause = new QAction("Pause", this); QAction* reset = new QAction("Reset", this); QAction* fullscreen = new QAction("Fullscreen", this); QAction* screenshot = new QAction("Screenshot", this); QAction* nplay_start = new QAction("Start Netplay", this); QAction* nplay_stop = new QAction("Stop Netplay", this); QAction* general = new QAction("General Settings...", this); QAction* display = new QAction("Display", this); QAction* sound = new QAction("Sound", this); QAction* controls = new QAction("Controls", this); QAction* netplay = new QAction("Netplay", this); QAction* paths = new QAction("Paths", this); QAction* custom_gfx = new QAction("Custom Graphics...", this); QAction* debugging = new QAction("Debugger", this); QAction* about = new QAction("About", this); //Set shortcuts for actions open->setShortcut(tr("CTRL+O")); quit->setShortcut(tr("CTRL+Q")); pause->setShortcut(tr("CTRL+P")); reset->setShortcut(tr("F8")); fullscreen->setShortcut(tr("F12")); screenshot->setShortcut(tr("F9")); nplay_start->setShortcut(tr("F5")); nplay_stop->setShortcut(tr("F6")); pause->setCheckable(true); pause->setObjectName("pause_action"); fullscreen->setCheckable(true); fullscreen->setObjectName("fullscreen_action"); menu_bar = new QMenuBar(this); //Setup File menu QMenu* file; file = new QMenu(tr("File"), this); file->addAction(open); recent_list = file->addMenu(tr("Recent Files")); file->addSeparator(); state_save_list = file->addMenu(tr("Save State")); state_load_list = file->addMenu(tr("Load State")); file->addSeparator(); file->addAction(quit); menu_bar->addMenu(file); //Setup Emulation menu QMenu* emulation; emulation = new QMenu(tr("Emulation"), this); emulation->addAction(pause); emulation->addAction(reset); emulation->addSeparator(); emulation->addAction(fullscreen); emulation->addAction(screenshot); emulation->addSeparator(); emulation->addAction(nplay_start); emulation->addAction(nplay_stop); menu_bar->addMenu(emulation); //Setup Options menu QMenu* options; options = new QMenu(tr("Options"), this); options->addAction(general); options->addSeparator(); options->addAction(display); options->addAction(sound); options->addAction(controls); options->addAction(netplay); options->addAction(paths); menu_bar->addMenu(options); //Advanced menu QMenu* advanced; advanced = new QMenu(tr("Advanced"), this); advanced->addAction(custom_gfx); advanced->addAction(debugging); menu_bar->addMenu(advanced); //Setup Help menu QMenu* help; help = new QMenu(tr("Help"), this); help->addAction(about); menu_bar->addMenu(help); //Setup signals connect(quit, SIGNAL(triggered()), this, SLOT(quit())); connect(open, SIGNAL(triggered()), this, SLOT(open_file())); connect(pause, SIGNAL(triggered()), this, SLOT(pause())); connect(fullscreen, SIGNAL(triggered()), this, SLOT(fullscreen())); connect(screenshot, SIGNAL(triggered()), this, SLOT(screenshot())); connect(nplay_start, SIGNAL(triggered()), this, SLOT(start_netplay())); connect(nplay_stop, SIGNAL(triggered()), this, SLOT(stop_netplay())); connect(reset, SIGNAL(triggered()), this, SLOT(reset())); connect(general, SIGNAL(triggered()), this, SLOT(show_settings())); connect(display, SIGNAL(triggered()), this, SLOT(show_display_settings())); connect(sound, SIGNAL(triggered()), this, SLOT(show_sound_settings())); connect(controls, SIGNAL(triggered()), this, SLOT(show_control_settings())); connect(netplay, SIGNAL(triggered()), this, SLOT(show_netplay_settings())); connect(paths, SIGNAL(triggered()), this, SLOT(show_paths_settings())); connect(custom_gfx, SIGNAL(triggered()), this, SLOT(show_cgfx())); connect(debugging, SIGNAL(triggered()), this, SLOT(show_debugger())); connect(about, SIGNAL(triggered()), this, SLOT(show_about())); sw_screen = new soft_screen(); hw_screen = new hard_screen(); QVBoxLayout* layout = new QVBoxLayout; layout->setContentsMargins(0, 0, 0, -1); layout->addWidget(sw_screen); layout->addWidget(hw_screen); layout->setMenuBar(menu_bar); setLayout(layout); config::scaling_factor = 2; hw_screen->hide(); hw_screen->setEnabled(false); //Parse .ini options parse_ini_file(); //Parse cheats file if(config::use_cheats) { parse_cheats_file(); } //Parse command-line arguments //These will override .ini options! if(!parse_cli_args()) { exit(0); } //Some command-line arguments are invalid for the Qt version config::use_debugger = false; //Setup Recent Files list_mapper = new QSignalMapper(this); for(int x = (config::recent_files.size() - 1); x >= 0; x--) { QString path = QString::fromStdString(config::recent_files[x]); QFileInfo file(path); path = file.fileName(); QAction* temp = new QAction(path, this); recent_list->addAction(temp); connect(temp, SIGNAL(triggered()), list_mapper, SLOT(map())); list_mapper->setMapping(temp, x); } connect(list_mapper, SIGNAL(mapped(int)), this, SLOT(load_recent(int))); //Setup Save States QSignalMapper* save_mapper = new QSignalMapper(this); for(int x = 0; x < 10; x++) { QAction* temp; if(x == 0) { temp = new QAction(tr("Quick Save"), this); temp->setShortcut(tr("F1")); } else { std::string slot_id = "Slot " + util::to_str(x); QString slot_name = QString::fromStdString(slot_id); temp = new QAction(slot_name, this); } state_save_list->addAction(temp); connect(temp, SIGNAL(triggered()), save_mapper, SLOT(map())); save_mapper->setMapping(temp, x); } connect(save_mapper, SIGNAL(mapped(int)), this, SLOT(save_state(int))); //Setup Load States QSignalMapper* load_mapper = new QSignalMapper(this); for(int x = 0; x < 10; x++) { QAction* temp; if(x == 0) { temp = new QAction(tr("Quick Load"), this); temp->setShortcut(tr("F2")); } else { std::string slot_id = "Slot " + util::to_str(x); QString slot_name = QString::fromStdString(slot_id); temp = new QAction(slot_name, this); } state_load_list->addAction(temp); connect(temp, SIGNAL(triggered()), load_mapper, SLOT(map())); load_mapper->setMapping(temp, x); } connect(load_mapper, SIGNAL(mapped(int)), this, SLOT(load_state(int))); //Set up settings dialog settings = new gen_settings(); settings->set_ini_options(); //Set up custom graphics dialog cgfx = new gbe_cgfx(); cgfx->hide(); cgfx->advanced->setChecked(true); //Set up DMG-GBC debugger main_menu::dmg_debugger = new dmg_debug(); main_menu::dmg_debugger->hide(); //Setup About pop-up about_box = new QWidget(); about_box->resize(300, 250); about_box->setWindowTitle("About GBE+"); QDialogButtonBox* about_button = new QDialogButtonBox(QDialogButtonBox::Close); connect(about_button->button(QDialogButtonBox::Close), SIGNAL(clicked()), about_box, SLOT(close())); QLabel* emu_title = new QLabel("GBE+ 1.0"); QFont font = emu_title->font(); font.setPointSize(18); font.setBold(true); emu_title->setFont(font); QImage logo(QString::fromStdString(config::cfg_path + "data/icons/gbe_plus.png")); logo = logo.scaled(128, 128); QLabel* emu_desc = new QLabel("A GB/GBC/GBA emulator with enhancements"); QLabel* emu_copyright = new QLabel("Copyright D.S. Baxter 2014-2016"); QLabel* emu_proj_copyright = new QLabel("Copyright GBE+ Team 2014-2016"); QLabel* emu_license = new QLabel("This program is licensed under the GNU GPLv2"); QLabel* emu_site = new QLabel("<a href=\"https://github.com/shonumi/gbe-plus/\">GBE+ on GitHub</a>"); emu_site->setOpenExternalLinks(true); QLabel* emu_logo = new QLabel; emu_logo->setPixmap(QPixmap::fromImage(logo)); QVBoxLayout* about_layout = new QVBoxLayout; about_layout->addWidget(emu_title, 0, Qt::AlignCenter | Qt::AlignTop); about_layout->addWidget(emu_desc, 0, Qt::AlignCenter | Qt::AlignTop); about_layout->addWidget(emu_copyright, 0, Qt::AlignCenter | Qt::AlignTop); about_layout->addWidget(emu_proj_copyright, 0, Qt::AlignCenter | Qt::AlignTop); about_layout->addWidget(emu_license, 0, Qt::AlignCenter | Qt::AlignTop); about_layout->addWidget(emu_site, 0, Qt::AlignCenter | Qt::AlignTop); about_layout->addWidget(emu_logo, 0, Qt::AlignCenter | Qt::AlignTop); about_layout->addWidget(about_button); about_box->setLayout(about_layout); about_box->setWindowIcon(QIcon(QString::fromStdString(config::cfg_path + "data/icons/gbe_plus.png"))); about_box->hide(); //Setup warning message box warning_box = new QMessageBox; QPushButton* warning_box_ok = warning_box->addButton("OK", QMessageBox::AcceptRole); warning_box->setIcon(QMessageBox::Warning); warning_box->hide(); display_width = QApplication::desktop()->screenGeometry().width(); display_height = QApplication::desktop()->screenGeometry().height(); fullscreen_mode = false; }
/****** Handle keypress input ******/ void main_menu::keyPressEvent(QKeyEvent* event) { int sdl_key = qtkey_to_sdlkey(event->key()); //Force input processing in the core if(main_menu::gbe_plus != NULL) { gbe_plus->feed_key_input(sdl_key, true); //Handle fullscreen hotkeys if necessary if(findChild<QAction*>("fullscreen_action")->isChecked()) { switch(sdl_key) { //Quick Save State case SDLK_F1: save_state(0); break; //Netplay start case SDLK_F5: start_netplay(); break; //Netplay stop case SDLK_F6: stop_netplay(); break; //Reset case SDLK_F8: reset(); break; //Screenshot case SDLK_F9: screenshot(); break; //Quick Load State case SDLK_F2: load_state(0); break; //Fullscreen case SDLK_F12: findChild<QAction*>("fullscreen_action")->setChecked(false); fullscreen(); break; } } //Mute audio if(sdl_key == config::hotkey_mute) { if(settings->sound_on->isChecked()) { settings->sound_on->setChecked(false); } else { settings->sound_on->setChecked(true); } settings->update_volume(); } } }
/****** Process hotkey input ******/ void AGB_core::handle_hotkey(SDL_Event& event) { //Disallow key repeats if(event.key.repeat) { return; } //Quit on Q or ESC if((event.type == SDL_KEYDOWN) && ((event.key.keysym.sym == SDLK_q) || (event.key.keysym.sym == SDLK_ESCAPE))) { running = false; SDL_Quit(); } //Mute or unmute sound on M else if((event.type == SDL_KEYDOWN) && (event.key.keysym.sym == config::hotkey_mute) && (!config::use_external_interfaces)) { if(config::volume == 0) { update_volume(config::old_volume); } else { config::old_volume = config::volume; update_volume(0); } } //Quick save state on F1 else if((event.type == SDL_KEYDOWN) && (event.key.keysym.sym == SDLK_F1)) { save_state(0); } //Quick load save state on F2 else if((event.type == SDL_KEYDOWN) && (event.key.keysym.sym == SDLK_F2)) { load_state(0); } //Pause and wait for netplay connection on F5 else if((event.type == SDL_KEYDOWN) && (event.key.keysym.sym == SDLK_F5)) { start_netplay(); } //Disconnect netplay connection on F6 else if((event.type == SDL_KEYDOWN) && (event.key.keysym.sym == SDLK_F6)) { stop_netplay(); } //Start CLI debugger on F7 else if((event.type == SDL_KEYDOWN) && (event.key.keysym.sym == SDLK_F7) && (!config::use_external_interfaces)) { //Start a new CLI debugger session or interrupt an existing one in Continue Mode if((!db_unit.debug_mode) || ((db_unit.debug_mode) && (db_unit.last_command == "c"))) { db_unit.debug_mode = true; db_unit.last_command = "n"; db_unit.last_mnemonic = ""; } } //Screenshot on F9 else if((event.type == SDL_KEYDOWN) && (event.key.keysym.sym == SDLK_F9)) { std::stringstream save_stream; std::string save_name = config::ss_path; //Prefix SDL Ticks to screenshot name save_stream << SDL_GetTicks(); save_name += save_stream.str(); save_stream.str(std::string()); //Append random number to screenshot name srand(SDL_GetTicks()); save_stream << rand() % 1024 << rand() % 1024 << rand() % 1024; save_name += save_stream.str() + ".bmp"; SDL_SaveBMP(core_cpu.controllers.video.final_screen, save_name.c_str()); //OSD config::osd_message = "SAVED SCREENSHOT"; config::osd_count = 180; } //Toggle Fullscreen on F12 else if((event.type == SDL_KEYDOWN) && (event.key.keysym.sym == SDLK_F12)) { //Unset fullscreen if(config::flags & SDL_WINDOW_FULLSCREEN_DESKTOP) { config::flags &= ~SDL_WINDOW_FULLSCREEN_DESKTOP; config::scaling_factor = config::old_scaling_factor; } //Set fullscreen else { config::flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; config::old_scaling_factor = config::scaling_factor; } //Destroy old window SDL_DestroyWindow(core_cpu.controllers.video.window); //Initialize new window - SDL if(!config::use_opengl) { core_cpu.controllers.video.window = SDL_CreateWindow("GBE+", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, config::sys_width, config::sys_height, config::flags); core_cpu.controllers.video.final_screen = SDL_GetWindowSurface(core_cpu.controllers.video.window); SDL_GetWindowSize(core_cpu.controllers.video.window, &config::win_width, &config::win_height); //Find the maximum fullscreen dimensions that maintain the original aspect ratio if(config::flags & SDL_WINDOW_FULLSCREEN_DESKTOP) { double max_width, max_height, ratio = 0.0; max_width = (double)config::win_width / config::sys_width; max_height = (double)config::win_height / config::sys_height; if(max_width <= max_height) { ratio = max_width; } else { ratio = max_height; } core_cpu.controllers.video.max_fullscreen_ratio = ratio; } } //Initialize new window - OpenGL else { core_cpu.controllers.video.opengl_init(); } } //Pause emulation else if((event.type == SDL_KEYDOWN) && (event.key.keysym.sym == SDLK_PAUSE)) { config::pause_emu = true; SDL_PauseAudio(1); std::cout<<"EMU::Paused\n"; //Delay until pause key is hit again while(config::pause_emu) { SDL_Delay(50); if((SDL_PollEvent(&event)) && (event.type == SDL_KEYDOWN) && (event.key.keysym.sym == SDLK_PAUSE)) { config::pause_emu = false; SDL_PauseAudio(0); std::cout<<"EMU::Unpaused\n"; } } } //Toggle turbo on else if((event.type == SDL_KEYDOWN) && (event.key.keysym.sym == config::hotkey_turbo)) { config::turbo = true; if((config::sdl_render) && (config::use_opengl)) { SDL_GL_SetSwapInterval(0); } } //Toggle turbo off else if((event.type == SDL_KEYUP) && (event.key.keysym.sym == config::hotkey_turbo)) { config::turbo = false; if((config::sdl_render) && (config::use_opengl)) { SDL_GL_SetSwapInterval(1); } } //Reset emulation on F8 else if((event.type == SDL_KEYDOWN) && (event.key.keysym.sym == SDLK_F8)) { reset(); } //Initiate various communication functions //Soul Doll Adapter - Reset Soul Doll //Battle Chip Gate - Insert Battle Chip else if((event.type == SDL_KEYDOWN) && (event.key.keysym.sym == SDLK_F3)) { switch(core_cpu.controllers.serial_io.sio_stat.sio_type) { //Reset adapter case GBA_SOUL_DOLL_ADAPTER: core_cpu.controllers.serial_io.soul_doll_adapter_reset(); //OSD config::osd_message = "SOUL DOLL ADAPTER RESET"; config::osd_count = 180; break; } } }