DOSBox-X
|
00001 /* 00002 * Copyright (C) 2002-2020 The DOSBox Team 00003 * 00004 * This program is free software; you can redistribute it and/or modify 00005 * it under the terms of the GNU General Public License as published by 00006 * the Free Software Foundation; either version 2 of the License, or 00007 * (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License along 00015 * with this program; if not, write to the Free Software Foundation, Inc., 00016 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 */ 00018 00019 #include "../dos/drives.h" 00020 #include "control.h" 00021 #include "cpu.h" 00022 #include "render.h" 00023 #include "menu.h" 00024 #include "SDL.h" 00025 #include "SDL_syswm.h" 00026 #include "bios_disk.h" 00027 #include "ide.h" // for ide support 00028 #include "mapper.h" 00029 #include "keyboard.h" 00030 #include "timer.h" 00031 #include "inout.h" 00032 00033 #if DOSBOXMENU_TYPE == DOSBOXMENU_SDLDRAW 00034 unsigned int min_sdldraw_menu_width = 500; 00035 unsigned int min_sdldraw_menu_height = 300; 00036 #endif 00037 00038 #if DOSBOXMENU_TYPE == DOSBOXMENU_NSMENU /* Mac OS X menu handle */ 00039 void sdl_hax_nsMenuAddApplicationMenu(void *nsMenu); 00040 void* sdl_hax_nsMenuItemFromTag(void *nsMenu, unsigned int tag); 00041 void sdl_hax_nsMenuItemUpdateFromItem(void *nsMenuItem, DOSBoxMenu::item &item); 00042 void sdl_hax_nsMenuItemSetTag(void *nsMenuItem, unsigned int id); 00043 void sdl_hax_nsMenuItemSetSubmenu(void *nsMenuItem,void *nsMenu); 00044 void sdl_hax_nsMenuAddItem(void *nsMenu,void *nsMenuItem); 00045 void* sdl_hax_nsMenuAllocSeparator(void); 00046 void* sdl_hax_nsMenuAlloc(const char *initWithText); 00047 void sdl_hax_nsMenuRelease(void *nsMenu); 00048 void* sdl_hax_nsMenuItemAlloc(const char *initWithText); 00049 void sdl_hax_nsMenuItemRelease(void *nsMenuItem); 00050 #endif 00051 00052 #if DOSBOXMENU_TYPE == DOSBOXMENU_HMENU 00053 extern "C" void SDL1_hax_SetMenu(HMENU menu); 00054 #endif 00055 00056 void reflectmenu_INITMENU_cb(); 00057 bool GFX_GetPreventFullscreen(void); 00058 void RENDER_CallBack( GFX_CallBackFunctions_t function ); 00059 bool OpenGL_using(void); 00060 00061 void MAPPER_TriggerEventByName(const std::string& name); 00062 void RENDER_CallBack( GFX_CallBackFunctions_t function ); 00063 00064 const DOSBoxMenu::mapper_event_t DOSBoxMenu::unassigned_mapper_event; /* empty std::string */ 00065 00066 static DOSBoxMenu::item_handle_t separator_alloc = 0; 00067 static std::vector<DOSBoxMenu::item_handle_t> separators; 00068 00069 static std::string not_recommended = "Mounting C:\\ is NOT recommended.\nDo you want to continue?"; 00070 00071 /* this is THE menu */ 00072 DOSBoxMenu mainMenu; 00073 00074 extern const char* drive_opts[][2]; 00075 extern const char* scaler_menu_opts[][2]; 00076 extern int NonUserResizeCounter; 00077 00078 extern bool dos_kernel_disabled; 00079 extern bool dos_shell_running_program; 00080 00081 bool GFX_GetPreventFullscreen(void); 00082 void DOSBox_ShowConsole(); 00083 00084 void GUI_ResetResize(bool pressed); 00085 00086 MENU_Block menu; 00087 00088 unsigned int hdd_defsize=16000; 00089 char hdd_size[20]=""; 00090 00091 extern "C" void (*SDL1_hax_INITMENU_cb)(); 00092 00093 /* top level menu ("") */ 00094 static const char *def_menu__toplevel[] = 00095 { 00096 "MainMenu", 00097 "CpuMenu", 00098 "VideoMenu", 00099 "SoundMenu", 00100 "DOSMenu", 00101 #if !defined(C_EMSCRIPTEN) 00102 "CaptureMenu", 00103 #endif 00104 "DriveMenu", 00105 NULL 00106 }; 00107 00108 /* main menu ("MainMenu") */ 00109 static const char *def_menu_main[] = 00110 { 00111 "mapper_mapper", 00112 "mapper_gui", 00113 "--", 00114 "MainSendKey", 00115 "--", 00116 #if !defined(C_EMSCRIPTEN) 00117 "wait_on_error", 00118 #endif 00119 "showdetails", 00120 #if C_DEBUG 00121 "--", 00122 "mapper_debugger", 00123 #endif 00124 #if !defined(MACOSX) && !defined(LINUX) && !defined(HX_DOS) && !defined(C_EMSCRIPTEN) 00125 "show_console", 00126 #endif 00127 "--", 00128 "mapper_capmouse", 00129 "auto_lock_mouse", 00130 #if !defined(C_EMSCRIPTEN)//FIXME: Reset causes problems with Emscripten 00131 "--", 00132 "mapper_pause", 00133 "mapper_pauseints", 00134 #endif 00135 #if !defined(C_EMSCRIPTEN)//FIXME: Reset causes problems with Emscripten 00136 "--", 00137 "mapper_reset", 00138 #endif 00139 #if !defined(C_EMSCRIPTEN)//FIXME: Shutdown causes problems with Emscripten 00140 "--", 00141 #endif 00142 #if !defined(C_EMSCRIPTEN)//FIXME: Shutdown causes problems with Emscripten 00143 "mapper_shutdown", 00144 #endif 00145 NULL 00146 }; 00147 00148 /* main -> send key menu ("MenuSendKey") */ 00149 static const char *def_menu_main_sendkey[] = 00150 { 00151 "sendkey_ctrlesc", 00152 "sendkey_alttab", 00153 "sendkey_winlogo", 00154 "sendkey_winmenu", 00155 "--", 00156 "sendkey_cad", 00157 NULL 00158 }; 00159 00160 /* cpu -> core menu ("CpuCoreMenu") */ 00161 static const char *def_menu_cpu_core[] = 00162 { 00163 "mapper_cycauto", 00164 "--", 00165 "mapper_normal", 00166 #if !defined(C_EMSCRIPTEN)//FIXME: Shutdown causes problems with Emscripten 00167 "mapper_full", 00168 "mapper_simple", 00169 #endif 00170 #if defined(C_DYNAMIC_X86) || defined(C_DYNREC) 00171 "mapper_dynamic", 00172 #endif 00173 NULL 00174 }; 00175 00176 /* cpu -> type menu ("CpuTypeMenu") */ 00177 static const char *def_menu_cpu_type[] = 00178 { 00179 "cputype_auto", 00180 "--", 00181 "cputype_8086", 00182 "cputype_8086_prefetch", 00183 "cputype_80186", 00184 "cputype_80186_prefetch", 00185 "cputype_286", 00186 "cputype_286_prefetch", 00187 "cputype_386", 00188 "cputype_386_prefetch", 00189 "cputype_486old", 00190 "cputype_486old_prefetch", 00191 "cputype_486", 00192 "cputype_486_prefetch", 00193 "cputype_pentium", 00194 "cputype_pentium_mmx", 00195 "cputype_ppro_slow", 00196 NULL 00197 }; 00198 00199 /* cpu menu ("CpuMenu") */ 00200 static const char *def_menu_cpu[] = 00201 { 00202 "mapper_speedlock2", /* NTS: "mapper_speedlock" doesn't work for a menu item because it requires holding the key */ 00203 "mapper_speednorm", 00204 "mapper_speedup", 00205 "mapper_slowdown", 00206 "--", 00207 "mapper_cycleup", 00208 "mapper_cycledown", 00209 "mapper_editcycles", 00210 "--", 00211 "CpuCoreMenu", 00212 "CpuTypeMenu", 00213 NULL 00214 }; 00215 00216 /* video frameskip menu ("VideoFrameskipMenu") */ 00217 static const char *def_menu_video_frameskip[] = 00218 { 00219 "frameskip_0", 00220 "frameskip_1", 00221 "frameskip_2", 00222 "frameskip_3", 00223 "frameskip_4", 00224 "frameskip_5", 00225 "frameskip_6", 00226 "frameskip_7", 00227 "frameskip_8", 00228 "frameskip_9", 00229 "frameskip_10", 00230 NULL 00231 }; 00232 00233 /* video scaler menu ("VideoScalerMenu") */ 00234 static const char *def_menu_video_scaler[] = 00235 { 00236 NULL 00237 }; 00238 00239 /* video output menu ("VideoOutputMenu") */ 00240 static const char *def_menu_video_output[] = 00241 { 00242 "output_surface", 00243 #if !defined(C_SDL2) && !defined(HX_DOS) 00244 # if (HAVE_D3D9_H) && defined(WIN32) 00245 "output_direct3d", 00246 # endif 00247 #endif 00248 #if defined(C_OPENGL) && !defined(HX_DOS) 00249 "output_opengl", 00250 "output_openglnb", 00251 #endif 00252 NULL 00253 }; 00254 00255 /* video vsync menu ("VideoVsyncMenu") */ 00256 static const char *def_menu_video_vsync[] = 00257 { 00258 #if !defined(C_SDL2) 00259 "vsync_on", 00260 "vsync_force", 00261 "vsync_host", 00262 "vsync_off", 00263 "--", 00264 "vsync_set_syncrate", 00265 #endif 00266 NULL 00267 }; 00268 00269 /* video overscan menu ("VideoOverscanMenu") */ 00270 static const char *def_menu_video_overscan[] = 00271 { 00272 "overscan_0", 00273 "overscan_1", 00274 "overscan_2", 00275 "overscan_3", 00276 "overscan_4", 00277 "overscan_5", 00278 "overscan_6", 00279 "overscan_7", 00280 "overscan_8", 00281 "overscan_9", 00282 "overscan_10", 00283 NULL 00284 }; 00285 00286 /* video output menu ("VideoCompatMenu") */ 00287 static const char *def_menu_video_compat[] = 00288 { 00289 "vga_9widetext", 00290 "doublescan", 00291 NULL 00292 }; 00293 00294 /* video output menu ("VideoPC98Menu") */ 00295 static const char *def_menu_video_pc98[] = 00296 { 00297 "pc98_5mhz_gdc", 00298 "pc98_allow_200scanline", 00299 "pc98_allow_4partitions", 00300 "--", 00301 "pc98_enable_egc", 00302 "pc98_enable_grcg", 00303 "pc98_enable_analog", 00304 "pc98_enable_analog256", 00305 "pc98_enable_188user", 00306 "--", 00307 "pc98_clear_text", 00308 "pc98_clear_graphics", 00309 NULL 00310 }; 00311 00312 /* video output debug ("VideoDebugMenu") */ 00313 static const char *def_menu_video_debug[] = 00314 { 00315 "mapper_blankrefreshtest", 00316 "--", 00317 "debug_pageflip", 00318 "debug_retracepoll", 00319 NULL 00320 }; 00321 00322 /* video menu ("VideoMenu") */ 00323 static const char *def_menu_video[] = 00324 { 00325 "mapper_aspratio", 00326 "--", 00327 #if !defined(HX_DOS) 00328 "mapper_fullscr", 00329 "--", 00330 #endif 00331 #if !defined(HX_DOS) && (defined(LINUX) || !defined(C_SDL2)) 00332 "alwaysontop", 00333 #endif 00334 #if !defined(C_SDL2) && defined(MACOSX) 00335 "highdpienable", 00336 #endif 00337 #if !defined(C_SDL2) 00338 "doublebuf", 00339 "--", 00340 #endif 00341 #ifndef MACOSX 00342 "mapper_togmenu", 00343 # if !defined(HX_DOS) 00344 "--", 00345 # endif 00346 #endif 00347 #if !defined(HX_DOS) 00348 "mapper_resetsize", 00349 #endif 00350 "--", 00351 "VideoFrameskipMenu", 00352 "--", 00353 "scaler_forced", 00354 "VideoScalerMenu", 00355 "VideoOutputMenu", 00356 #if !defined(C_SDL2) 00357 "VideoVsyncMenu", 00358 #endif 00359 "VideoOverscanMenu", 00360 "VideoCompatMenu", 00361 "VideoPC98Menu", 00362 "--", 00363 "VideoDebugMenu", 00364 #ifdef C_D3DSHADERS 00365 "--", 00366 "load_d3d_shader", 00367 #endif 00368 NULL 00369 }; 00370 00371 /* DOS menu ("DOSMenu") */ 00372 static const char *def_menu_dos[] = 00373 { 00374 "DOSMouseMenu", 00375 "--", 00376 "DOSLFNMenu", 00377 "--", 00378 "DOSPC98Menu", 00379 "--", 00380 "mapper_swapimg", 00381 "mapper_swapcd", 00382 "--", 00383 "mapper_rescanall", 00384 "--", 00385 "DOSDebugMenu", 00386 NULL 00387 }; 00388 00389 /* DOS mouse menu ("DOSMouseMenu") */ 00390 static const char *def_menu_dos_mouse[] = 00391 { 00392 "dos_mouse_enable_int33", 00393 "dos_mouse_y_axis_reverse", 00394 "--", 00395 "dos_mouse_sensitivity", 00396 NULL 00397 }; 00398 00399 /* DOS LFN menu ("DOSLFNMenu") */ 00400 static const char *def_menu_dos_lfn[] = 00401 { 00402 "dos_lfn_auto", 00403 "--", 00404 "dos_lfn_enable", 00405 "dos_lfn_disable", 00406 NULL 00407 }; 00408 00409 /* DOS pc-98 menu ("DOSPC98Menu") */ 00410 static const char *def_menu_dos_pc98[] = 00411 { 00412 "dos_pc98_pit_4mhz", 00413 "dos_pc98_pit_5mhz", 00414 NULL 00415 }; 00416 00417 /* DOS debug ("DOSDebugMenu") */ 00418 static const char *def_menu_dos_debug[] = 00419 { 00420 "debug_logint21", 00421 "debug_logfileio", 00422 NULL 00423 }; 00424 00425 /* sound menu ("SoundMenu") */ 00426 static const char *def_menu_sound[] = 00427 { 00428 "mapper_volup", 00429 "mapper_voldown", 00430 "--", 00431 "mixer_mute", 00432 "mixer_swapstereo", 00433 NULL 00434 }; 00435 00436 /* capture menu ("CaptureMenu") */ 00437 static const char *def_menu_capture[] = 00438 { 00439 #if defined(C_SSHOT) 00440 "mapper_scrshot", 00441 "--", 00442 #endif 00443 #if !defined(C_EMSCRIPTEN) 00444 # if (C_SSHOT) 00445 "CaptureFormatMenu", 00446 "--", 00447 # endif 00448 "mapper_video", 00449 "mapper_recwave", 00450 "mapper_recmtwave", 00451 "mapper_caprawopl", 00452 "mapper_caprawmidi", 00453 "--", 00454 #endif 00455 "force_loadstate", 00456 "mapper_savestate", 00457 "mapper_loadstate", 00458 "saveslotmenu", 00459 NULL 00460 }; 00461 00462 #if !defined(C_EMSCRIPTEN) 00463 # if (C_SSHOT) 00464 /* capture format menu ("CaptureFormatMenu") */ 00465 static const char *def_menu_capture_format[] = 00466 { 00467 "capture_fmt_avi_zmbv", 00468 # if (C_AVCODEC) 00469 "capture_fmt_mpegts_h264", 00470 # endif 00471 NULL 00472 }; 00473 # endif 00474 #endif 00475 00476 /* Save slots */ 00477 static const char *def_save_slots[] = 00478 { 00479 "mapper_prevslot", 00480 "mapper_nextslot", 00481 "--", 00482 "slot0", 00483 "slot1", 00484 "slot2", 00485 "slot3", 00486 "slot4", 00487 "slot5", 00488 "slot6", 00489 "slot7", 00490 "slot8", 00491 "slot9", 00492 "--", 00493 "refreshslot", 00494 NULL 00495 }; 00496 00497 /* Drive menu ("DriveMenu") */ 00498 static const char *def_menu_drive[] = 00499 { 00500 "DriveA", 00501 "DriveB", 00502 "DriveC", 00503 "DriveD", 00504 "DriveE", 00505 "DriveF", 00506 "DriveG", 00507 "DriveH", 00508 "DriveI", 00509 "DriveJ", 00510 "DriveK", 00511 "DriveL", 00512 "DriveM", 00513 00514 #if DOSBOXMENU_TYPE == DOSBOXMENU_SDLDRAW 00515 "||", 00516 #endif 00517 00518 "DriveN", 00519 "DriveO", 00520 "DriveP", 00521 "DriveQ", 00522 "DriveR", 00523 "DriveS", 00524 "DriveT", 00525 "DriveU", 00526 "DriveV", 00527 "DriveW", 00528 "DriveX", 00529 "DriveY", 00530 "DriveZ", 00531 00532 NULL 00533 }; 00534 00535 bool DOSBox_isMenuVisible(void) { 00536 return menu.toggle; 00537 } 00538 00539 DOSBoxMenu::DOSBoxMenu() { 00540 } 00541 00542 DOSBoxMenu::~DOSBoxMenu() { 00543 unbuild(); 00544 clear_all_menu_items(); 00545 } 00546 00547 DOSBoxMenu::displaylist::displaylist() { 00548 } 00549 00550 DOSBoxMenu::displaylist::~displaylist() { 00551 } 00552 00553 bool DOSBoxMenu::item_exists(const std::string &name) { 00554 const auto i = name_map.find(name); 00555 00556 if (i == name_map.end()) 00557 return false; 00558 00559 return item_exists(i->second); 00560 } 00561 00562 bool DOSBoxMenu::item_exists(const item_handle_t i) { 00563 if (i == unassigned_item_handle) 00564 return false; 00565 else if (i >= master_list.size()) 00566 return false; 00567 00568 item &ret = master_list[(size_t)i]; 00569 00570 if (!ret.status.allocated || ret.master_id == unassigned_item_handle) 00571 return false; 00572 else if (ret.master_id != i) 00573 return false; 00574 00575 return true; 00576 } 00577 00578 DOSBoxMenu::item_handle_t DOSBoxMenu::get_item_id_by_name(const std::string &name) { 00579 const auto i = name_map.find(name); 00580 00581 if (i == name_map.end()) 00582 return unassigned_item_handle; 00583 00584 return i->second; 00585 } 00586 00587 DOSBoxMenu::item& DOSBoxMenu::get_item(const std::string &name) { 00588 const item_handle_t handle = get_item_id_by_name(name); 00589 00590 if (handle == unassigned_item_handle) 00591 E_Exit("DOSBoxMenu::get_item() No such item '%s'",name.c_str()); 00592 00593 return get_item(handle); 00594 } 00595 00596 DOSBoxMenu::item& DOSBoxMenu::get_item(const item_handle_t i) { 00597 if (i == unassigned_item_handle) 00598 E_Exit("DOSBoxMenu::get_item() attempt to get unassigned handle"); 00599 else if (i >= master_list.size()) 00600 E_Exit("DOSBoxMenu::get_item() attempt to get out of range handle"); 00601 00602 item &ret = master_list[(size_t)i]; 00603 00604 if (!ret.status.allocated || ret.master_id == unassigned_item_handle) 00605 E_Exit("DOSBoxMenu::get_item() attempt to read unallocated item"); 00606 else if (ret.master_id != i) 00607 E_Exit("DOSBoxMenu::get_item() ID mismatch"); 00608 00609 return ret; 00610 } 00611 00612 DOSBoxMenu::item& DOSBoxMenu::alloc_item(const enum item_type_t type,const std::string &name) { 00613 if (type >= MAX_id) 00614 E_Exit("DOSBoxMenu::alloc_item() illegal menu type value"); 00615 00616 if (name_map.find(name) != name_map.end()) 00617 E_Exit("DOSBoxMenu::alloc_item() name '%s' already taken",name.c_str()); 00618 00619 while (master_list_alloc < master_list.size()) { 00620 if (!master_list[master_list_alloc].status.allocated) { 00621 name_map[name] = master_list_alloc; 00622 return master_list[master_list_alloc].allocate(master_list_alloc,type,name); 00623 } 00624 00625 master_list_alloc++; 00626 } 00627 00628 if (master_list_alloc >= master_list_limit) 00629 E_Exit("DOSBoxMenu::alloc_item() no slots are free"); 00630 00631 size_t newsize = master_list.size() + (master_list.size() / 2); 00632 if (newsize < 64) newsize = 64; 00633 if (newsize > master_list_limit) newsize = master_list_limit; 00634 master_list.resize(newsize); 00635 00636 assert(master_list_alloc < master_list.size()); 00637 00638 name_map[name] = master_list_alloc; 00639 return master_list[master_list_alloc].allocate(master_list_alloc,type,name); 00640 } 00641 00642 void DOSBoxMenu::delete_item(const item_handle_t i) { 00643 if (i == unassigned_item_handle) 00644 E_Exit("DOSBoxMenu::delete_item() attempt to get unassigned handle"); 00645 else if (i >= master_list.size()) 00646 E_Exit("DOSBoxMenu::delete_item() attempt to get out of range handle"); 00647 00648 { 00649 const auto it = name_map.find(master_list[i].name); 00650 if (it != name_map.end()) { 00651 if (it->second != i) E_Exit("DOSBoxMenu::delete_item() master_id mismatch"); 00652 name_map.erase(it); 00653 } 00654 } 00655 00656 master_list[i].deallocate(); 00657 master_list_alloc = i; 00658 } 00659 00660 const char *DOSBoxMenu::TypeToString(const enum item_type_t type) { 00661 switch (type) { 00662 case item_type_id: return "Item"; 00663 case submenu_type_id: return "Submenu"; 00664 case separator_type_id: return "Separator"; 00665 case vseparator_type_id: return "VSeparator"; 00666 default: break; 00667 } 00668 00669 return ""; 00670 } 00671 00672 void DOSBoxMenu::dump_log_displaylist(DOSBoxMenu::displaylist &ls, unsigned int indent) { 00673 std::string prep; 00674 00675 for (unsigned int i=0;i < indent;i++) 00676 prep += "+ "; 00677 00678 for (const auto &id : ls.disp_list) { 00679 DOSBoxMenu::item &item = get_item(id); 00680 00681 if (!item.is_allocated()) { 00682 LOG_MSG("%s (NOT ALLOCATED!!!)",prep.c_str()); 00683 continue; 00684 } 00685 00686 LOG_MSG("%sid=%u type=\"%s\" name=\"%s\" text=\"%s\"", 00687 prep.c_str(), 00688 (unsigned int)item.master_id, 00689 TypeToString(item.type), 00690 item.name.c_str(), 00691 item.text.c_str()); 00692 00693 if (item.type == submenu_type_id) 00694 dump_log_displaylist(item.display_list, indent+1); 00695 } 00696 } 00697 00698 void DOSBoxMenu::dump_log_debug(void) { 00699 LOG_MSG("Menu dump log (%p)",(void*)this); 00700 LOG_MSG("---- Master list ----"); 00701 for (auto &id : master_list) { 00702 if (id.is_allocated()) { 00703 LOG_MSG("+ id=%u type=\"%s\" name=\"%s\" text=\"%s\" shortcut=\"%s\" desc=\"%s\"", 00704 (unsigned int)id.master_id, 00705 TypeToString(id.type), 00706 id.name.c_str(), 00707 id.text.c_str(), 00708 id.shortcut_text.c_str(), 00709 id.description.c_str()); 00710 00711 if (!id.get_mapper_event().empty()) 00712 LOG_MSG("+ + mapper_event=\"%s\"",id.get_mapper_event().c_str()); 00713 } 00714 } 00715 LOG_MSG("---- display list ----"); 00716 dump_log_displaylist(display_list, 1); 00717 } 00718 00719 void DOSBoxMenu::clear_all_menu_items(void) { 00720 for (auto &id : master_list) { 00721 if (id.is_allocated()) 00722 id.deallocate(); 00723 } 00724 master_list_alloc = 0; 00725 master_list.clear(); 00726 name_map.clear(); 00727 } 00728 00729 DOSBoxMenu::item::item() { 00730 } 00731 00732 DOSBoxMenu::item::~item() { 00733 } 00734 00735 DOSBoxMenu::item &DOSBoxMenu::item::allocate(const item_handle_t id,const enum item_type_t new_type,const std::string &new_name) { 00736 if (master_id != unassigned_item_handle || status.allocated) 00737 E_Exit("DOSBoxMenu::item::allocate() called on item already allocated"); 00738 00739 status.allocated = 1; 00740 name = new_name; 00741 type = new_type; 00742 master_id = id; 00743 return *this; 00744 } 00745 00746 void DOSBoxMenu::item::deallocate(void) { 00747 if (master_id == unassigned_item_handle || !status.allocated) 00748 E_Exit("DOSBoxMenu::item::deallocate() called on item already deallocated"); 00749 00750 master_id = unassigned_item_handle; 00751 status.allocated = 0; 00752 status.changed = 1; 00753 shortcut_text.clear(); 00754 description.clear(); 00755 text.clear(); 00756 name.clear(); 00757 } 00758 00759 void DOSBoxMenu::displaylist_append(displaylist &ls,const DOSBoxMenu::item_handle_t item_id) { 00760 DOSBoxMenu::item &item = get_item(item_id); 00761 00762 if (item.status.in_use) 00763 E_Exit("DOSBoxMenu::displaylist_append() item already in use"); 00764 00765 ls.disp_list.push_back(item.master_id); 00766 item.status.in_use = true; 00767 ls.order_changed = true; 00768 } 00769 00770 void DOSBoxMenu::displaylist_clear(DOSBoxMenu::displaylist &ls) { 00771 uint16_t id = DOSBoxMenu::unassigned_item_handle; 00772 std::fill(ls.disp_list.begin(), ls.disp_list.end(), id); 00773 00774 ls.disp_list.clear(); 00775 ls.items_changed = true; 00776 ls.order_changed = true; 00777 } 00778 00779 void DOSBoxMenu::rebuild(void) { 00780 #if DOSBOXMENU_TYPE == DOSBOXMENU_HMENU /* Windows menu handle */ 00781 if (winMenu == NULL) { 00782 if (!winMenuInit()) 00783 return; 00784 } 00785 #endif 00786 #if DOSBOXMENU_TYPE == DOSBOXMENU_NSMENU /* Mac OS X menu handle */ 00787 if (nsMenu == NULL) { 00788 if (!nsMenuInit()) 00789 return; 00790 } 00791 #endif 00792 #if DOSBOXMENU_TYPE == DOSBOXMENU_SDLDRAW /* SDL drawn menus */ 00793 layoutMenu(); 00794 #endif 00795 } 00796 00797 void DOSBoxMenu::unbuild(void) { 00798 #if DOSBOXMENU_TYPE == DOSBOXMENU_HMENU /* Windows menu handle */ 00799 winMenuDestroy(); 00800 #endif 00801 #if DOSBOXMENU_TYPE == DOSBOXMENU_NSMENU /* Mac OS X menu handle */ 00802 nsMenuDestroy(); 00803 #endif 00804 } 00805 00806 #if DOSBOXMENU_TYPE == DOSBOXMENU_NSMENU /* Mac OS X menu handle */ 00807 bool DOSBoxMenu::mainMenuAction(unsigned int id) { 00808 if (id < nsMenuMinimumID) return false; 00809 id -= nsMenuMinimumID; 00810 00811 if (id >= master_list.size()) return false; 00812 00813 item &item = master_list[id]; 00814 if (!item.status.allocated || item.master_id == unassigned_item_handle) return false; 00815 00816 dispatchItemCommand(item); 00817 return true; 00818 } 00819 00820 void DOSBoxMenu::item::nsAppendMenu(void* parent_nsMenu) { 00821 if (type == separator_type_id) { 00822 sdl_hax_nsMenuAddItem(parent_nsMenu, sdl_hax_nsMenuAllocSeparator()); 00823 } 00824 else if (type == vseparator_type_id) { 00825 sdl_hax_nsMenuAddItem(parent_nsMenu, sdl_hax_nsMenuAllocSeparator()); 00826 } 00827 else if (type == submenu_type_id) { 00828 if (nsMenu != NULL) { 00829 // NTS: You have to make a menu ITEM who's submenu is the submenu object 00830 nsMenuItem = sdl_hax_nsMenuItemAlloc(text.c_str()); 00831 00832 sdl_hax_nsMenuItemSetTag(nsMenuItem, master_id + nsMenuMinimumID); 00833 sdl_hax_nsMenuItemSetSubmenu(nsMenuItem, nsMenu); 00834 sdl_hax_nsMenuAddItem(parent_nsMenu, nsMenuItem); 00835 sdl_hax_nsMenuItemUpdateFromItem(nsMenuItem, *this); 00836 sdl_hax_nsMenuItemRelease(nsMenuItem); 00837 } 00838 } 00839 else if (type == item_type_id) { 00840 nsMenuItem = sdl_hax_nsMenuItemAlloc(text.c_str()); 00841 00842 sdl_hax_nsMenuItemSetTag(nsMenuItem, master_id + nsMenuMinimumID); 00843 sdl_hax_nsMenuAddItem(parent_nsMenu, nsMenuItem); 00844 sdl_hax_nsMenuItemUpdateFromItem(nsMenuItem, *this); 00845 sdl_hax_nsMenuItemRelease(nsMenuItem); 00846 } 00847 } 00848 00849 bool DOSBoxMenu::nsMenuSubInit(DOSBoxMenu::item &p_item) { 00850 if (p_item.nsMenu == NULL) { 00851 p_item.nsMenu = sdl_hax_nsMenuAlloc(p_item.get_text().c_str()); 00852 if (p_item.nsMenu != NULL) { 00853 for (const auto id : p_item.display_list.disp_list) { 00854 DOSBoxMenu::item &item = get_item(id); 00855 00856 /* if a submenu, make the submenu */ 00857 if (item.type == submenu_type_id) { 00858 item.parent_id = p_item.master_id; 00859 nsMenuSubInit(item); 00860 } 00861 00862 item.nsAppendMenu(p_item.nsMenu); 00863 } 00864 } 00865 } 00866 00867 return true; 00868 } 00869 00870 bool DOSBoxMenu::nsMenuInit(void) { 00871 if (nsMenu == NULL) { 00872 if ((nsMenu = sdl_hax_nsMenuAlloc("")) == NULL) 00873 return false; 00874 00875 /* For whatever reason, Mac OS X will always make the first top level menu 00876 the Application menu and will put the name of the app there NO MATTER WHAT */ 00877 sdl_hax_nsMenuAddApplicationMenu(nsMenu); 00878 00879 /* top level */ 00880 for (const auto id : display_list.disp_list) { 00881 DOSBoxMenu::item &item = get_item(id); 00882 00883 /* if a submenu, make the submenu */ 00884 if (item.type == submenu_type_id) { 00885 item.parent_id = unassigned_item_handle; 00886 nsMenuSubInit(item); 00887 } 00888 00889 item.nsAppendMenu(nsMenu); 00890 } 00891 00892 /* release our handle on the nsMenus. Mac OS X will keep them alive with it's 00893 reference until the menu is destroyed at which point all items and submenus 00894 will be automatically destroyed */ 00895 for (auto &id : master_list) { 00896 if (id.nsMenu != NULL) { 00897 sdl_hax_nsMenuRelease(id.nsMenu); 00898 id.nsMenu = NULL; 00899 } 00900 } 00901 } 00902 00903 return true; 00904 } 00905 00906 void DOSBoxMenu::nsMenuDestroy(void) { 00907 if (nsMenu != NULL) { 00908 sdl_hax_nsMenuRelease(nsMenu); 00909 nsMenu = NULL; 00910 } 00911 } 00912 00913 void* DOSBoxMenu::getNsMenu(void) const { 00914 return nsMenu; 00915 } 00916 #endif 00917 00918 #if DOSBOXMENU_TYPE == DOSBOXMENU_HMENU /* Windows menu handle */ 00919 std::string DOSBoxMenu::item::winConstructMenuText(void) { 00920 std::string r; 00921 00922 /* copy text, converting '&' to '&&' for Windows. 00923 * TODO: Use accelerator to place '&' for underline */ 00924 for (auto i=text.begin();i!=text.end();i++) { 00925 const char c = *i; 00926 00927 if (c == '&') { 00928 r += "&&"; 00929 } 00930 else { 00931 r += c; 00932 } 00933 } 00934 00935 /* then the shortcut text */ 00936 if (!shortcut_text.empty()) { 00937 r += "\t"; 00938 00939 for (auto i=shortcut_text.begin();i!=shortcut_text.end();i++) { 00940 const char c = *i; 00941 00942 if (c == '&') { 00943 r += "&&"; 00944 } 00945 else { 00946 r += c; 00947 } 00948 } 00949 } 00950 00951 return r; 00952 } 00953 00954 void DOSBoxMenu::item::winAppendMenu(HMENU handle) { 00955 if (type == separator_type_id) { 00956 AppendMenu(handle, MF_SEPARATOR, 0, NULL); 00957 } 00958 else if (type == vseparator_type_id) { 00959 AppendMenu(handle, MF_MENUBREAK, 0, NULL); 00960 } 00961 else if (type == submenu_type_id) { 00962 if (winMenu != NULL) 00963 AppendMenu(handle, MF_POPUP | MF_STRING, (uintptr_t)winMenu, winConstructMenuText().c_str()); 00964 } 00965 else if (type == item_type_id) { 00966 unsigned int attr = MF_STRING; 00967 00968 attr |= (status.checked) ? MF_CHECKED : MF_UNCHECKED; 00969 attr |= (status.enabled) ? MF_ENABLED : (MF_DISABLED | MF_GRAYED); 00970 00971 AppendMenu(handle, attr, (uintptr_t)(master_id + winMenuMinimumID), winConstructMenuText().c_str()); 00972 } 00973 } 00974 00975 bool DOSBoxMenu::winMenuSubInit(DOSBoxMenu::item &p_item) { 00976 if (p_item.winMenu == NULL) { 00977 p_item.winMenu = CreatePopupMenu(); 00978 if (p_item.winMenu != NULL) { 00979 for (const auto id : p_item.display_list.disp_list) { 00980 DOSBoxMenu::item &item = get_item(id); 00981 00982 /* if a submenu, make the submenu */ 00983 if (item.type == submenu_type_id) { 00984 item.parent_id = p_item.master_id; 00985 winMenuSubInit(item); 00986 } 00987 00988 item.winAppendMenu(p_item.winMenu); 00989 } 00990 } 00991 } 00992 00993 return true; 00994 } 00995 00996 bool DOSBoxMenu::winMenuInit(void) { 00997 if (winMenu == NULL) { 00998 winMenu = CreateMenu(); 00999 if (winMenu == NULL) return false; 01000 01001 /* top level */ 01002 for (const auto id : display_list.disp_list) { 01003 DOSBoxMenu::item &item = get_item(id); 01004 01005 /* if a submenu, make the submenu */ 01006 if (item.type == submenu_type_id) { 01007 item.parent_id = unassigned_item_handle; 01008 winMenuSubInit(item); 01009 } 01010 01011 item.winAppendMenu(winMenu); 01012 } 01013 } 01014 01015 return true; 01016 } 01017 01018 void DOSBoxMenu::winMenuDestroy(void) { 01019 if (winMenu != NULL) { 01020 /* go through all menu items, and clear the menu handle */ 01021 for (auto &id : master_list) 01022 id.winMenu = NULL; 01023 01024 /* destroy the menu. 01025 * By MSDN docs it destroys submenus automatically */ 01026 DestroyMenu(winMenu); 01027 winMenu = NULL; 01028 } 01029 } 01030 01031 HMENU DOSBoxMenu::getWinMenu(void) const { 01032 return winMenu; 01033 } 01034 01035 /* call this from WM_COMMAND */ 01036 bool DOSBoxMenu::mainMenuWM_COMMAND(unsigned int id) { 01037 if (id < winMenuMinimumID) return false; 01038 id -= winMenuMinimumID; 01039 01040 if (id >= master_list.size()) return false; 01041 01042 item &item = master_list[id]; 01043 if (!item.status.allocated || item.master_id == unassigned_item_handle) return false; 01044 01045 dispatchItemCommand(item); 01046 return true; 01047 } 01048 #endif 01049 01050 void DOSBoxMenu::item::refresh_item(DOSBoxMenu &menu) { 01051 (void)menu;//POSSIBLY UNUSED 01052 #if DOSBOXMENU_TYPE == DOSBOXMENU_HMENU /* Windows menu handle */ 01053 if (menu.winMenu != NULL && status.in_use && status.changed) { 01054 HMENU phandle = NULL; 01055 01056 if (parent_id != unassigned_item_handle) 01057 phandle = menu.get_item(parent_id).winMenu; 01058 else 01059 phandle = menu.winMenu; 01060 01061 if (phandle != NULL) { 01062 if (type == separator_type_id) { 01063 /* none */ 01064 } 01065 else if (type == vseparator_type_id) { 01066 /* none */ 01067 } 01068 else if (type == submenu_type_id) { 01069 /* TODO: Can't change by ID, have to change by position */ 01070 } 01071 else if (type == item_type_id) { 01072 unsigned int attr = MF_STRING; 01073 01074 attr |= (status.checked) ? MF_CHECKED : MF_UNCHECKED; 01075 attr |= (status.enabled) ? MF_ENABLED : (MF_DISABLED | MF_GRAYED); 01076 01077 ModifyMenu(phandle, (uintptr_t)(master_id + winMenuMinimumID), 01078 attr | MF_BYCOMMAND, (uintptr_t)(master_id + winMenuMinimumID), 01079 winConstructMenuText().c_str()); 01080 } 01081 } 01082 } 01083 01084 status.changed = false; 01085 #endif 01086 #if DOSBOXMENU_TYPE == DOSBOXMENU_NSMENU /* Mac OS X menu handle */ 01087 if (nsMenuItem != NULL) 01088 sdl_hax_nsMenuItemUpdateFromItem(nsMenuItem, *this); 01089 #endif 01090 } 01091 01092 void DOSBoxMenu::dispatchItemCommand(item &item) { 01093 if (item.callback_func) 01094 item.callback_func(this,&item); 01095 01096 if (item.mapper_event != unassigned_mapper_event) 01097 MAPPER_TriggerEventByName(item.mapper_event); 01098 } 01099 01100 static std::string separator_id(const DOSBoxMenu::item_handle_t r) { 01101 char tmp[32]; 01102 01103 sprintf(tmp,"%u",(unsigned int)r); 01104 return std::string("_separator_") + std::string(tmp); 01105 } 01106 01107 static DOSBoxMenu::item_handle_t separator_get(const DOSBoxMenu::item_type_t t=DOSBoxMenu::separator_type_id) { 01108 assert(separator_alloc <= separators.size()); 01109 if (separator_alloc == separators.size()) { 01110 DOSBoxMenu::item &nitem = mainMenu.alloc_item(t, separator_id(separator_alloc)); 01111 separators.push_back(nitem.get_master_id()); 01112 } 01113 01114 assert(separator_alloc < separators.size()); 01115 mainMenu.get_item(separators[separator_alloc]).set_type(t); 01116 return separators[separator_alloc++]; 01117 } 01118 01119 void ConstructSubMenu(DOSBoxMenu::item_handle_t item_id, const char * const * list) { 01120 for (size_t i=0;list[i] != NULL;i++) { 01121 const char *ref = list[i]; 01122 01123 /* NTS: This code calls mainMenu.get_item(item_id) every iteration. 01124 * 01125 * This seemingly inefficient method of populating the display 01126 * list is REQUIRED because DOSBoxMenu::item& is a reference 01127 * to a std::vector, and the reference becomes invalid when 01128 * the vector reallocates to accomodate more entries. 01129 * 01130 * Holding onto one reference for the entire loop risks a 01131 * segfault (use after free) bug if the vector should reallocate 01132 * in separator_get() -> alloc_item() 01133 * 01134 * Since get_item(item_id) is literally just a constant time 01135 * array lookup, this is not very inefficient at all. */ 01136 01137 if (!strcmp(ref,"--")) { 01138 mainMenu.displaylist_append( 01139 mainMenu.get_item(item_id).display_list, separator_get(DOSBoxMenu::separator_type_id)); 01140 } 01141 else if (!strcmp(ref,"||")) { 01142 mainMenu.displaylist_append( 01143 mainMenu.get_item(item_id).display_list, separator_get(DOSBoxMenu::vseparator_type_id)); 01144 } 01145 else if (mainMenu.item_exists(ref)) { 01146 mainMenu.displaylist_append( 01147 mainMenu.get_item(item_id).display_list, mainMenu.get_item_id_by_name(ref)); 01148 } 01149 } 01150 } 01151 01152 void ConstructMenu(void) { 01153 mainMenu.displaylist_clear(mainMenu.display_list); 01154 separator_alloc = 0; 01155 01156 /* top level */ 01157 for (size_t i=0;def_menu__toplevel[i] != NULL;i++) 01158 mainMenu.displaylist_append( 01159 mainMenu.display_list, 01160 mainMenu.get_item_id_by_name(def_menu__toplevel[i])); 01161 01162 /* main menu */ 01163 ConstructSubMenu(mainMenu.get_item("MainMenu").get_master_id(), def_menu_main); 01164 01165 /* main sendkey menu */ 01166 ConstructSubMenu(mainMenu.get_item("MainSendKey").get_master_id(), def_menu_main_sendkey); 01167 01168 /* cpu menu */ 01169 ConstructSubMenu(mainMenu.get_item("CpuMenu").get_master_id(), def_menu_cpu); 01170 01171 /* cpu core menu */ 01172 ConstructSubMenu(mainMenu.get_item("CpuCoreMenu").get_master_id(), def_menu_cpu_core); 01173 01174 /* cpu type menu */ 01175 ConstructSubMenu(mainMenu.get_item("CpuTypeMenu").get_master_id(), def_menu_cpu_type); 01176 01177 /* video menu */ 01178 ConstructSubMenu(mainMenu.get_item("VideoMenu").get_master_id(), def_menu_video); 01179 01180 /* video frameskip menu */ 01181 ConstructSubMenu(mainMenu.get_item("VideoFrameskipMenu").get_master_id(), def_menu_video_frameskip); 01182 01183 /* video scaler menu */ 01184 ConstructSubMenu(mainMenu.get_item("VideoScalerMenu").get_master_id(), def_menu_video_scaler); 01185 { 01186 size_t count=0; 01187 01188 for (size_t i=0;scaler_menu_opts[i][0] != NULL;i++) { 01189 const std::string name = std::string("scaler_set_") + scaler_menu_opts[i][0]; 01190 01191 if (mainMenu.item_exists(name)) { 01192 mainMenu.displaylist_append( 01193 mainMenu.get_item("VideoScalerMenu").display_list, 01194 mainMenu.get_item_id_by_name(name)); 01195 01196 #if DOSBOXMENU_TYPE == DOSBOXMENU_SDLDRAW 01197 if ((count % 15) == 14) { 01198 mainMenu.displaylist_append( 01199 mainMenu.get_item("VideoScalerMenu").display_list, 01200 separator_get(DOSBoxMenu::vseparator_type_id)); 01201 } 01202 #endif 01203 01204 count++; 01205 } 01206 } 01207 } 01208 01209 /* video output menu */ 01210 ConstructSubMenu(mainMenu.get_item("VideoOutputMenu").get_master_id(), def_menu_video_output); 01211 01212 /* video vsync menu */ 01213 ConstructSubMenu(mainMenu.get_item("VideoVsyncMenu").get_master_id(), def_menu_video_vsync); 01214 01215 /* video overscan menu */ 01216 ConstructSubMenu(mainMenu.get_item("VideoOverscanMenu").get_master_id(), def_menu_video_overscan); 01217 01218 /* video compat menu */ 01219 ConstructSubMenu(mainMenu.get_item("VideoCompatMenu").get_master_id(), def_menu_video_compat); 01220 01221 /* video PC-98 menu */ 01222 ConstructSubMenu(mainMenu.get_item("VideoPC98Menu").get_master_id(), def_menu_video_pc98); 01223 01224 /* video debug menu */ 01225 ConstructSubMenu(mainMenu.get_item("VideoDebugMenu").get_master_id(), def_menu_video_debug); 01226 01227 /* sound menu */ 01228 ConstructSubMenu(mainMenu.get_item("SoundMenu").get_master_id(), def_menu_sound); 01229 01230 /* DOS menu */ 01231 ConstructSubMenu(mainMenu.get_item("DOSMenu").get_master_id(), def_menu_dos); 01232 01233 /* DOS mouse menu */ 01234 ConstructSubMenu(mainMenu.get_item("DOSMouseMenu").get_master_id(), def_menu_dos_mouse); 01235 01236 /* DOS LFN menu */ 01237 ConstructSubMenu(mainMenu.get_item("DOSLFNMenu").get_master_id(), def_menu_dos_lfn); 01238 01239 /* DOS PC-98 menu */ 01240 ConstructSubMenu(mainMenu.get_item("DOSPC98Menu").get_master_id(), def_menu_dos_pc98); 01241 01242 /* DOS debug menu */ 01243 ConstructSubMenu(mainMenu.get_item("DOSDebugMenu").get_master_id(), def_menu_dos_debug); 01244 01245 #if !defined(C_EMSCRIPTEN) 01246 /* capture menu */ 01247 ConstructSubMenu(mainMenu.get_item("CaptureMenu").get_master_id(), def_menu_capture); 01248 #endif 01249 01250 #if !defined(C_EMSCRIPTEN) 01251 # if (C_SSHOT) 01252 /* capture format menu */ 01253 ConstructSubMenu(mainMenu.get_item("CaptureFormatMenu").get_master_id(), def_menu_capture_format); 01254 # endif 01255 #endif 01256 ConstructSubMenu(mainMenu.get_item("saveslotmenu").get_master_id(), def_save_slots); 01257 01258 /* Drive menu */ 01259 ConstructSubMenu(mainMenu.get_item("DriveMenu").get_master_id(), def_menu_drive); 01260 for (char drv='A';drv <= 'Z';drv++) { 01261 const std::string dname = std::string("Drive") + drv; 01262 for (size_t i=0;drive_opts[i][0] != NULL;i++) { 01263 const std::string name = std::string("drive_") + drv + "_" + drive_opts[i][0]; 01264 01265 if (mainMenu.item_exists(name)) { 01266 mainMenu.displaylist_append( 01267 mainMenu.get_item(dname).display_list, 01268 mainMenu.get_item_id_by_name(name)); 01269 } 01270 } 01271 } 01272 } 01273 01274 bool MENU_SetBool(std::string secname, std::string value) { 01275 Section_prop * sec = static_cast<Section_prop *>(control->GetSection(secname)); 01276 if(sec) SetVal(secname, value, sec->Get_bool(value) ? "false" : "true"); 01277 return sec->Get_bool(value); 01278 } 01279 01280 // Sets the scaler 'forced' flag. 01281 void SetScaleForced(bool forced) 01282 { 01283 render.scale.forced = forced; 01284 01285 Section_prop * section=static_cast<Section_prop *>(control->GetSection("render")); 01286 Prop_multival* prop = section->Get_multival("scaler"); 01287 std::string scaler = prop->GetSection()->Get_string("type"); 01288 01289 auto value = scaler + (render.scale.forced ? " forced" : ""); 01290 SetVal("render", "scaler", value); 01291 01292 RENDER_CallBack(GFX_CallBackReset); 01293 mainMenu.get_item("scaler_forced").check(render.scale.forced).refresh_item(mainMenu); 01294 } 01295 01296 // Sets the scaler to use. 01297 void SetScaler(scalerOperation_t op, Bitu size, std::string& prefix) 01298 { 01299 auto value = prefix + (render.scale.forced ? " forced" : ""); 01300 SetVal("render", "scaler", value); 01301 render.scale.size = size; 01302 render.scale.op = op; 01303 RENDER_CallBack(GFX_CallBackReset); 01304 } 01305 01306 std::string MSCDEX_Output(int num) { 01307 std::string MSCDEX_MSG = "GUI: MSCDEX "; 01308 std::string MSCDEX_MSG_Failure = "Failure: "; 01309 switch (num) { 01310 case 0: return MSCDEX_MSG + "installed"; 01311 case 1: return MSCDEX_MSG + MSCDEX_MSG_Failure + "Drive-letters of multiple CDRom-drives have to be continuous."; 01312 case 2: return MSCDEX_MSG + MSCDEX_MSG_Failure + "Not yet supported."; 01313 case 3: return MSCDEX_MSG + MSCDEX_MSG_Failure + "Path not valid."; 01314 case 4: return MSCDEX_MSG + MSCDEX_MSG_Failure + "Too many CDRom-drives (max: 5). MSCDEX Installation failed"; 01315 case 5: return MSCDEX_MSG + "Mounted subdirectory: limited support."; 01316 case 6: return MSCDEX_MSG + MSCDEX_MSG_Failure + "Unknown error"; 01317 default: return 0; 01318 } 01319 } 01320 01321 void SetVal(const std::string& secname, const std::string& preval, const std::string& val) { 01322 if(preval=="keyboardlayout" && !dos_kernel_disabled) { 01323 DOS_MCB mcb(dos.psp()-1); 01324 static char name[9]; 01325 mcb.GetFileName(name); 01326 if (strlen(name)) { 01327 LOG_MSG("GUI: Exit %s running in DOSBox, and then try again.",name); 01328 return; 01329 } 01330 } 01331 Section* sec = control->GetSection(secname); 01332 if(sec) { 01333 std::string real_val=preval+"="+val; 01334 sec->HandleInputline(real_val); 01335 } 01336 } 01337 01338 void DOSBox_SetMenu(DOSBoxMenu &altMenu) { 01339 #if DOSBOXMENU_TYPE == DOSBOXMENU_SDLDRAW 01340 /* nothing to do */ 01341 (void)altMenu; 01342 #endif 01343 #if DOSBOXMENU_TYPE == DOSBOXMENU_NSMENU /* TODO: Move to menu.cpp DOSBox_SetMenu() and add setmenu(NULL) to DOSBox_NoMenu() @emendelson request showmenu=false */ 01344 void sdl_hax_macosx_setmenu(void *nsMenu); 01345 void menu_osx_set_menuobj(DOSBoxMenu *altMenu); 01346 sdl_hax_macosx_setmenu(altMenu.getNsMenu()); 01347 menu_osx_set_menuobj(&altMenu); 01348 #endif 01349 #if DOSBOXMENU_TYPE == DOSBOXMENU_HMENU 01350 if(!menu.gui) return; 01351 if(!menu.toggle) return; 01352 01353 LOG(LOG_MISC,LOG_DEBUG)("Win32: loading and attaching custom menu resource to DOSBox's window"); 01354 01355 NonUserResizeCounter=1; 01356 SDL1_hax_SetMenu(altMenu.getWinMenu()); 01357 #endif 01358 } 01359 01360 void DOSBox_SetMenu(void) { 01361 #if DOSBOXMENU_TYPE == DOSBOXMENU_SDLDRAW 01362 { 01363 menu.toggle=true; 01364 mainMenu.showMenu(); 01365 mainMenu.setRedraw(); 01366 GFX_ResetScreen(); 01367 } 01368 #endif 01369 #if DOSBOXMENU_TYPE == DOSBOXMENU_NSMENU /* TODO: Move to menu.cpp DOSBox_SetMenu() and add setmenu(NULL) to DOSBox_NoMenu() @emendelson request showmenu=false */ 01370 void sdl_hax_macosx_setmenu(void *nsMenu); 01371 sdl_hax_macosx_setmenu(mainMenu.getNsMenu()); 01372 #endif 01373 #if DOSBOXMENU_TYPE == DOSBOXMENU_HMENU 01374 if(!menu.gui) return; 01375 01376 LOG(LOG_MISC,LOG_DEBUG)("Win32: loading and attaching menu resource to DOSBox's window"); 01377 01378 menu.toggle=true; 01379 NonUserResizeCounter=1; 01380 SDL1_hax_SetMenu(mainMenu.getWinMenu()); 01381 mainMenu.get_item("mapper_togmenu").check(!menu.toggle).refresh_item(mainMenu); 01382 01383 Reflect_Menu(); 01384 01385 if(menu.startup) { 01386 RENDER_CallBack( GFX_CallBackReset ); 01387 } 01388 01389 void DOSBox_SetSysMenu(void); 01390 DOSBox_SetSysMenu(); 01391 #endif 01392 } 01393 01394 void DOSBox_NoMenu(void) { 01395 #if DOSBOXMENU_TYPE == DOSBOXMENU_SDLDRAW 01396 { 01397 menu.toggle=false; 01398 mainMenu.showMenu(false); 01399 mainMenu.setRedraw(); 01400 GFX_ResetScreen(); 01401 } 01402 #endif 01403 #if DOSBOXMENU_TYPE == DOSBOXMENU_NSMENU 01404 void sdl_hax_macosx_setmenu(void *nsMenu); 01405 sdl_hax_macosx_setmenu(NULL); 01406 #endif 01407 #if DOSBOXMENU_TYPE == DOSBOXMENU_HMENU 01408 if(!menu.gui) return; 01409 menu.toggle=false; 01410 NonUserResizeCounter=1; 01411 SDL1_hax_SetMenu(NULL); 01412 mainMenu.get_item("mapper_togmenu").check(!menu.toggle).refresh_item(mainMenu); 01413 RENDER_CallBack( GFX_CallBackReset ); 01414 01415 void DOSBox_SetSysMenu(void); 01416 DOSBox_SetSysMenu(); 01417 #endif 01418 } 01419 01420 void ToggleMenu(bool pressed) { 01421 bool GFX_GetPreventFullscreen(void); 01422 01423 /* prevent removing the menu in 3Dfx mode */ 01424 if (GFX_GetPreventFullscreen()) 01425 return; 01426 01427 menu.resizeusing=true; 01428 int width, height; bool fullscreen; 01429 void GFX_GetSize(int &width, int &height, bool &fullscreen); 01430 GFX_GetSize(width, height, fullscreen); 01431 if(!menu.gui || !pressed || fullscreen) return; 01432 if(!menu.toggle) { 01433 menu.toggle=true; 01434 DOSBox_SetMenu(); 01435 } else { 01436 menu.toggle=false; 01437 DOSBox_NoMenu(); 01438 } 01439 01440 void DOSBox_SetSysMenu(void); 01441 DOSBox_SetSysMenu(); 01442 } 01443 01444 #if !(defined(WIN32) && !defined(C_SDL2) && !defined(HX_DOS)) 01445 int Reflect_Menu(void) { 01446 return 0; 01447 } 01448 01449 void DOSBox_RefreshMenu(void) { 01450 } 01451 01452 void DOSBox_CheckOS(int &id, int &major, int &minor) { 01453 id=major=minor=0; 01454 } 01455 #endif 01456 01457 #if defined(WIN32) 01458 # if defined(HX_DOS) || !defined(C_SDL2) 01459 HWND GetHWND(void) { 01460 SDL_SysWMinfo wmi; 01461 SDL_VERSION(&wmi.version); 01462 01463 if(!SDL_GetWMInfo(&wmi)) { 01464 return NULL; 01465 } 01466 return wmi.window; 01467 } 01468 01469 HWND GetSurfaceHWND(void) { 01470 SDL_SysWMinfo wmi; 01471 SDL_VERSION(&wmi.version); 01472 01473 if (!SDL_GetWMInfo(&wmi)) { 01474 return NULL; 01475 } 01476 return wmi.child_window; 01477 } 01478 # endif 01479 #endif 01480 01481 #if defined(WIN32) && !defined(C_SDL2) && !defined(HX_DOS) 01482 #include <shlobj.h> 01483 01484 void GetDefaultSize(void) { 01485 char sizetemp[20]="512,32,32765,"; 01486 char sizetemp2[20]=""; 01487 sprintf(sizetemp2,"%d",hdd_defsize); 01488 strcat(sizetemp,sizetemp2); 01489 sprintf(hdd_size,sizetemp); 01490 } 01491 01492 void SearchFolder( char path[MAX_PATH], char drive, std::string drive_type ) { 01493 WIN32_FIND_DATA FindFileData; 01494 HANDLE hFind; 01495 01496 hFind = FindFirstFile ( "*.*", &FindFileData ); 01497 01498 if ( hFind != INVALID_HANDLE_VALUE ) MountDrive_2(drive,path,drive_type); 01499 FindClose ( hFind ); 01500 } 01501 01502 void BrowseFolder( char drive , std::string drive_type ) { 01503 #if !defined(HX_DOS) 01504 if (Drives[drive-'A']) { 01505 LOG_MSG("Unmount drive %c first, and then try again.",drive); 01506 return; 01507 } 01508 std::string title = "Select a drive/directory to mount"; 01509 char path[MAX_PATH]; 01510 BROWSEINFO bi = { 0 }; 01511 if(drive_type=="CDROM") 01512 bi.lpszTitle = ( title + " CD-ROM\nMounting a directory as CD-ROM gives an limited support" ).c_str(); 01513 else if(drive_type=="FLOPPY") 01514 bi.lpszTitle = ( title + " as Floppy" ).c_str(); 01515 else if(drive_type=="LOCAL") 01516 bi.lpszTitle = ( title + " as Local").c_str(); 01517 else 01518 bi.lpszTitle = (title.c_str()); 01519 LPITEMIDLIST pidl = SHBrowseForFolder ( &bi ); 01520 01521 if ( pidl != 0 ) { 01522 SHGetPathFromIDList ( pidl, path ); 01523 // SetCurrentDirectory ( path ); 01524 SearchFolder( path , drive, drive_type ); 01525 IMalloc * imalloc = 0; 01526 if ( SUCCEEDED( SHGetMalloc ( &imalloc )) ) { 01527 imalloc->Free ( pidl ); 01528 imalloc->Release ( ); 01529 } 01530 } 01531 #endif 01532 } 01533 01534 void mem_conf(std::string memtype, int option) { 01535 std::string tmp; 01536 Section* sec = control->GetSection("dos"); 01537 Section_prop * section=static_cast<Section_prop *>(sec); 01538 if (!option) { 01539 tmp = section->Get_bool(memtype) ? "false" : "true"; 01540 } else { 01541 switch (option) { 01542 case 1: tmp = "true"; break; 01543 case 2: tmp = "false"; break; 01544 case 3: tmp = "emsboard"; break; 01545 case 4: tmp = "emm386"; break; 01546 default: return; 01547 } 01548 } 01549 if(sec) { 01550 memtype += "=" + tmp; 01551 sec->HandleInputline(memtype); 01552 } 01553 } 01554 01555 void UnMount(int i_drive) { 01556 if (dos_kernel_disabled) 01557 return; 01558 01559 i_drive = toupper(i_drive); 01560 if(i_drive-'A' == DOS_GetDefaultDrive()) { 01561 DOS_MCB mcb(dos.psp()-1); 01562 static char name[9]; 01563 mcb.GetFileName(name); 01564 if (!strlen(name)) goto umount; 01565 LOG_MSG("GUI:Drive %c is being used. Aborted.",i_drive); 01566 return; 01567 } 01568 umount: 01569 if (i_drive-'A' < DOS_DRIVES && i_drive-'A' >= 0 && Drives[i_drive-'A']) { 01570 switch (DriveManager::UnmountDrive(i_drive-'A')) { 01571 case 0: 01572 Drives[i_drive-'A'] = 0; 01573 if(i_drive-'A' == DOS_GetDefaultDrive()) 01574 DOS_SetDrive(toupper('Z') - 'A'); 01575 LOG_MSG("GUI:Drive %c has succesfully been removed.",i_drive); break; 01576 case 1: 01577 LOG_MSG("GUI:Virtual Drives can not be unMOUNTed."); break; 01578 case 2: 01579 LOG_MSG(MSCDEX_Output(1).c_str()); break; 01580 } 01581 } 01582 } 01583 01584 void MountDrive_2(char drive, const char drive2[DOS_PATHLENGTH], std::string drive_type) { 01585 (void)drive_type; 01586 (void)drive2; 01587 (void)drive; 01588 } 01589 01590 void MountDrive(char drive, const char drive2[DOS_PATHLENGTH]) { 01591 (void)drive2; 01592 (void)drive; 01593 } 01594 01595 void Mount_Img_Floppy(char drive, std::string realpath) { 01596 (void)realpath; 01597 (void)drive; 01598 } 01599 01600 void Mount_Img_HDD(char drive, std::string realpath) { 01601 (void)realpath; 01602 (void)drive; 01603 } 01604 01605 void Mount_Img(char drive, std::string realpath) { 01606 (void)realpath; 01607 (void)drive; 01608 } 01609 01610 void DOSBox_SetSysMenu(void) { 01611 #if !defined(HX_DOS) 01612 MENUITEMINFO mii; 01613 HMENU sysmenu; 01614 01615 sysmenu = GetSystemMenu(GetHWND(), TRUE); // revert, so we can reapply menu items 01616 sysmenu = GetSystemMenu(GetHWND(), FALSE); 01617 if (sysmenu == NULL) return; 01618 01619 AppendMenu(sysmenu, MF_SEPARATOR, -1, ""); 01620 01621 { 01622 const char *msg = "Show menu &bar"; 01623 01624 memset(&mii, 0, sizeof(mii)); 01625 mii.cbSize = sizeof(mii); 01626 mii.fMask = MIIM_ID | MIIM_STRING | MIIM_STATE; 01627 mii.fState = (menu.toggle ? MFS_CHECKED : 0) | (GFX_GetPreventFullscreen() ? MFS_DISABLED : MFS_ENABLED); 01628 mii.wID = ID_WIN_SYSMENU_TOGGLEMENU; 01629 mii.dwTypeData = (LPTSTR)(msg); 01630 mii.cch = (UINT)(strlen(msg)+1); 01631 01632 InsertMenuItem(sysmenu, GetMenuItemCount(sysmenu), TRUE, &mii); 01633 } 01634 01635 AppendMenu(sysmenu, MF_SEPARATOR, -1, ""); 01636 01637 { 01638 const char *msg = "&Pause"; 01639 01640 memset(&mii, 0, sizeof(mii)); 01641 mii.cbSize = sizeof(mii); 01642 mii.fMask = MIIM_ID | MIIM_STRING | MIIM_STATE; 01643 mii.fState = MFS_ENABLED; 01644 mii.wID = ID_WIN_SYSMENU_PAUSE; 01645 mii.dwTypeData = (LPTSTR)(msg); 01646 mii.cch = (UINT)(strlen(msg) + 1); 01647 01648 InsertMenuItem(sysmenu, GetMenuItemCount(sysmenu), TRUE, &mii); 01649 } 01650 01651 AppendMenu(sysmenu, MF_SEPARATOR, -1, ""); 01652 01653 { 01654 const char *msg = "Show &mapper interface"; 01655 01656 memset(&mii, 0, sizeof(mii)); 01657 mii.cbSize = sizeof(mii); 01658 mii.fMask = MIIM_ID | MIIM_STRING | MIIM_STATE; 01659 mii.fState = MFS_ENABLED; 01660 mii.wID = ID_WIN_SYSMENU_MAPPER; 01661 mii.dwTypeData = (LPTSTR)(msg); 01662 mii.cch = (UINT)(strlen(msg) + 1); 01663 01664 InsertMenuItem(sysmenu, GetMenuItemCount(sysmenu), TRUE, &mii); 01665 } 01666 01667 { 01668 const char *msg = "Show configuration &GUI"; 01669 01670 memset(&mii, 0, sizeof(mii)); 01671 mii.cbSize = sizeof(mii); 01672 mii.fMask = MIIM_ID | MIIM_STRING | MIIM_STATE; 01673 mii.fState = MFS_ENABLED; 01674 mii.wID = ID_WIN_SYSMENU_CFG_GUI; 01675 mii.dwTypeData = (LPTSTR)(msg); 01676 mii.cch = (UINT)(strlen(msg) + 1); 01677 01678 InsertMenuItem(sysmenu, GetMenuItemCount(sysmenu), TRUE, &mii); 01679 } 01680 #endif 01681 } 01682 01683 void DOSBox_CheckOS(int &id, int &major, int &minor) { 01684 OSVERSIONINFO osi; 01685 ZeroMemory(&osi, sizeof(OSVERSIONINFO)); 01686 osi.dwOSVersionInfoSize = sizeof(osi); 01687 GetVersionEx(&osi); 01688 id=osi.dwPlatformId; 01689 if(id==1) { major=0; minor=0; return; } 01690 major=osi.dwMajorVersion; 01691 minor=osi.dwMinorVersion; 01692 } 01693 01694 bool DOSBox_Kor(void) { 01695 if(menu.compatible) return false; 01696 char Buffer[30]; 01697 GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SABBREVLANGNAME, Buffer, sizeof(Buffer)); 01698 return (!strcmp(Buffer,"KOR") ? true : false); 01699 } 01700 01701 void DOSBox_RefreshMenu(void) { 01702 #if DOSBOXMENU_TYPE == DOSBOXMENU_HMENU 01703 int width, height; bool fullscreen; 01704 void GFX_GetSize(int &width, int &height, bool &fullscreen); 01705 GFX_GetSize(width,height,fullscreen); 01706 void SDL_Prepare(void); 01707 SDL_Prepare(); 01708 if(!menu.gui) return; 01709 01710 bool GFX_GetPreventFullscreen(void); 01711 01712 /* prevent removing the menu in 3Dfx mode */ 01713 if (GFX_GetPreventFullscreen()) 01714 return; 01715 01716 if(fullscreen) { 01717 NonUserResizeCounter=1; 01718 SetMenu(GetHWND(), NULL); 01719 DrawMenuBar(GetHWND()); 01720 return; 01721 } 01722 DOSBox_SetSysMenu(); 01723 if(menu.toggle) 01724 DOSBox_SetMenu(); 01725 else 01726 DOSBox_NoMenu(); 01727 #endif 01728 } 01729 01730 void DOSBox_RefreshMenu2(void) { 01731 #if DOSBOXMENU_TYPE == DOSBOXMENU_HMENU 01732 if(!menu.gui) return; 01733 int width, height; bool fullscreen; 01734 void GFX_GetSize(int &width, int &height, bool &fullscreen); 01735 GFX_GetSize(width,height,fullscreen); 01736 void SDL_Prepare(void); 01737 SDL_Prepare(); 01738 if(!menu.gui) return; 01739 01740 if(fullscreen) { 01741 NonUserResizeCounter=1; 01742 return; 01743 } 01744 if(menu.toggle) { 01745 menu.toggle=true; 01746 NonUserResizeCounter=1; 01747 SDL1_hax_SetMenu(mainMenu.getWinMenu()); 01748 } else { 01749 menu.toggle=false; 01750 NonUserResizeCounter=1; 01751 SDL1_hax_SetMenu(NULL); 01752 } 01753 01754 void DOSBox_SetSysMenu(void); 01755 DOSBox_SetSysMenu(); 01756 #endif 01757 } 01758 01759 void MENU_Check_Drive(HMENU handle, int cdrom, int floppy, int local, int image, int automount, int umount, char drive) { 01760 #if !defined(HX_DOS) 01761 std::string full_drive(1, drive); 01762 Section_prop * sec = static_cast<Section_prop *>(control->GetSection("dos")); 01763 full_drive += ":\\"; 01764 EnableMenuItem(handle, cdrom, (Drives[drive - 'A'] || menu.boot) ? MF_GRAYED : MF_ENABLED); 01765 EnableMenuItem(handle, floppy, (Drives[drive - 'A'] || menu.boot) ? MF_GRAYED : MF_ENABLED); 01766 EnableMenuItem(handle, local, (Drives[drive - 'A'] || menu.boot) ? MF_GRAYED : MF_ENABLED); 01767 EnableMenuItem(handle, image, (Drives[drive - 'A'] || menu.boot) ? MF_GRAYED : MF_ENABLED); 01768 if(sec) EnableMenuItem(handle, automount, AUTOMOUNT(full_drive.c_str(), drive) && !menu.boot && sec->Get_bool("automount") ? MF_ENABLED : MF_GRAYED); 01769 EnableMenuItem(handle, umount, (!Drives[drive - 'A']) || menu.boot ? MF_GRAYED : MF_ENABLED); 01770 #endif 01771 } 01772 01773 void MENU_KeyDelayRate(int delay, int rate) { 01774 IO_Write(0x60,0xf3); IO_Write(0x60,(Bit8u)(((delay-1)<<5)|(32-rate))); 01775 LOG_MSG("GUI: Keyboard rate %d, delay %d", rate, delay); 01776 } 01777 01778 int Reflect_Menu(void) { 01779 #if !defined(HX_DOS) 01780 SDL1_hax_INITMENU_cb = reflectmenu_INITMENU_cb; 01781 #endif 01782 return 1; 01783 } 01784 01785 void reflectmenu_INITMENU_cb() { 01786 /* WARNING: SDL calls this from Parent Window Thread! 01787 This executes in the context of the Parent Window Thread, NOT the main thread! 01788 As stupid as that seems, this is the only way the Parent Window Thread can make 01789 sure to keep Windows waiting while we take our time to reset the checkmarks in 01790 the menus before the menu is displayed. */ 01791 Reflect_Menu(); 01792 } 01793 01794 void MSG_WM_COMMAND_handle(SDL_SysWMmsg &Message) { 01795 bool GFX_GetPreventFullscreen(void); 01796 01797 if (Message.msg != WM_COMMAND) return; 01798 #if defined(WIN32) && !defined(HX_DOS) 01799 bool MAPPER_IsRunning(void); 01800 bool GUI_IsRunning(void); 01801 01802 if (!MAPPER_IsRunning() && !GUI_IsRunning()) { 01803 if (LOWORD(Message.wParam) == ID_WIN_SYSMENU_MAPPER) { 01804 extern void MAPPER_Run(bool pressed); 01805 MAPPER_Run(false); 01806 } 01807 if (LOWORD(Message.wParam) == ID_WIN_SYSMENU_CFG_GUI) { 01808 extern void GUI_Run(bool pressed); 01809 GUI_Run(false); 01810 } 01811 if (LOWORD(Message.wParam) == ID_WIN_SYSMENU_PAUSE) { 01812 extern void PauseDOSBox(bool pressed); 01813 PauseDOSBox(true); 01814 } 01815 } 01816 #endif 01817 std::string fullScreenString = std::string("desktop.fullscreen"); 01818 if (!menu.gui || GetSetSDLValue(1, fullScreenString, 0)) return; 01819 if (!GetMenu(GetHWND())) return; 01820 #if DOSBOXMENU_TYPE == DOSBOXMENU_HMENU 01821 if (mainMenu.mainMenuWM_COMMAND((unsigned int)LOWORD(Message.wParam))) return; 01822 #endif 01823 } 01824 #else 01825 void DOSBox_SetSysMenu(void) { 01826 } 01827 #endif 01828 01829 #if DOSBOXMENU_TYPE == DOSBOXMENU_SDLDRAW 01830 void DOSBoxMenu::item::showItem(DOSBoxMenu &menu,bool show) { 01831 (void)menu;//UNUSED 01832 if (itemVisible != show) { 01833 itemVisible = show; 01834 needRedraw = true; 01835 } 01836 else { 01837 } 01838 } 01839 01840 DOSBoxMenu::item &DOSBoxMenu::item::setHilight(DOSBoxMenu &menu,bool hi) { 01841 (void)menu;//UNUSED 01842 itemHilight = hi; 01843 01844 return *this; 01845 } 01846 01847 DOSBoxMenu::item &DOSBoxMenu::item::setHover(DOSBoxMenu &menu,bool ho) { 01848 (void)menu;//UNUSED 01849 itemHover = ho; 01850 01851 return *this; 01852 } 01853 01854 void DOSBoxMenu::item::removeFocus(DOSBoxMenu &menu) { 01855 if (menu.menuUserAttentionAt == master_id) { 01856 menu.menuUserAttentionAt = unassigned_item_handle; 01857 setHilight(menu,false); 01858 } 01859 } 01860 01861 void DOSBoxMenu::item::removeHover(DOSBoxMenu &menu) { 01862 if (menu.menuUserHoverAt == master_id) { 01863 menu.menuUserHoverAt = unassigned_item_handle; 01864 setHover(menu,false); 01865 } 01866 } 01867 01868 void DOSBoxMenu::showMenu(bool show) { 01869 if (menuVisible != show) { 01870 menuVisible = show; 01871 needRedraw = true; 01872 removeFocus(); 01873 updateRect(); 01874 } 01875 } 01876 01877 void DOSBoxMenu::removeFocus(void) { 01878 if (menuUserAttentionAt != unassigned_item_handle) { 01879 for (auto &id : master_list) { 01880 id.removeFocus(*this); 01881 id.showItem(*this,false); 01882 } 01883 menuUserAttentionAt = unassigned_item_handle; 01884 needRedraw = true; 01885 } 01886 } 01887 01888 void DOSBoxMenu::setScale(size_t s) { 01889 if (s == 0) s = 1; 01890 if (s > 2) s = 2; 01891 01892 if (fontCharScale != s) { 01893 fontCharScale = s; 01894 menuBarHeight = menuBarHeightBase * fontCharScale; 01895 fontCharWidth = fontCharWidthBase * fontCharScale; 01896 fontCharHeight = fontCharHeightBase * fontCharScale; 01897 updateRect(); 01898 layoutMenu(); 01899 } 01900 } 01901 01902 void DOSBoxMenu::removeHover(void) { 01903 if (menuUserHoverAt != unassigned_item_handle) { 01904 get_item(menuUserHoverAt).removeHover(*this); 01905 menuUserHoverAt = unassigned_item_handle; 01906 needRedraw = true; 01907 } 01908 } 01909 01910 void DOSBoxMenu::updateRect(void) { 01911 menuBox.x = 0; 01912 menuBox.y = 0; 01913 menuBox.w = menuVisible ? (unsigned int)screenWidth : 0; 01914 menuBox.h = menuVisible ? (unsigned int)menuBarHeight : 0; 01915 #if 0 01916 LOG_MSG("SDL menuBox w=%d h=%d",menuBox.w,menuBox.h); 01917 #endif 01918 layoutMenu(); 01919 } 01920 01921 void DOSBoxMenu::layoutMenu(void) { 01922 int x, y; 01923 01924 x = menuBox.x; 01925 y = menuBox.y; 01926 01927 for (auto i=display_list.disp_list.begin();i!=display_list.disp_list.end();i++) { 01928 DOSBoxMenu::item &item = get_item(*i); 01929 01930 item.placeItem(*this, x, y, /*toplevel*/true); 01931 x += item.screenBox.w; 01932 } 01933 01934 for (auto i=display_list.disp_list.begin();i!=display_list.disp_list.end();i++) 01935 get_item(*i).placeItemFinal(*this, /*finalwidth*/x - menuBox.x, /*toplevel*/true); 01936 01937 for (auto i=display_list.disp_list.begin();i!=display_list.disp_list.end();i++) 01938 get_item(*i).layoutSubmenu(*this, /*toplevel*/true); 01939 01940 #if 0 01941 LOG_MSG("Layout complete"); 01942 #endif 01943 } 01944 01945 void DOSBoxMenu::item::layoutSubmenu(DOSBoxMenu &menu, bool isTopLevel) { 01946 int x, y, minx, maxx; 01947 01948 x = screenBox.x; 01949 y = screenBox.y; 01950 01951 if (isTopLevel) { 01952 y += textBox.h; 01953 } 01954 else { 01955 x += screenBox.w + 2/*popup border*/; 01956 } 01957 01958 popupBox.x = x; 01959 popupBox.y = y; 01960 01961 minx = x; 01962 maxx = x; 01963 01964 auto arr_follow=display_list.disp_list.begin(); 01965 for (auto i=display_list.disp_list.begin();i!=display_list.disp_list.end();i++) { 01966 DOSBoxMenu::item &item = menu.get_item(*i); 01967 01968 if (item.get_type() == DOSBoxMenu::vseparator_type_id) { 01969 for (;arr_follow < i;arr_follow++) 01970 menu.get_item(*arr_follow).placeItemFinal(menu, /*finalwidth*/maxx - minx, /*toplevel*/false); 01971 01972 x = maxx; 01973 01974 item.screenBox.x = x; 01975 item.screenBox.y = popupBox.y; 01976 item.screenBox.w = (unsigned int)((4 * menu.fontCharScale) + 1); 01977 item.screenBox.h = y - popupBox.y; 01978 01979 minx = maxx = x = item.screenBox.x + item.screenBox.w; 01980 y = popupBox.y; 01981 } 01982 else { 01983 item.placeItem(menu, x, y, /*toplevel*/false); 01984 y += item.screenBox.h; 01985 01986 if (maxx < (item.screenBox.x + item.screenBox.w)) 01987 maxx = (item.screenBox.x + item.screenBox.w); 01988 } 01989 } 01990 01991 for (;arr_follow < display_list.disp_list.end();arr_follow++) 01992 menu.get_item(*arr_follow).placeItemFinal(menu, /*finalwidth*/maxx - minx, /*toplevel*/false); 01993 01994 for (auto i=display_list.disp_list.begin();i!=display_list.disp_list.end();i++) { 01995 DOSBoxMenu::item &item = menu.get_item(*i); 01996 int my = item.screenBox.y + item.screenBox.h; 01997 if (y < my) y = my; 01998 } 01999 02000 popupBox.w = maxx - popupBox.x; 02001 popupBox.h = y - popupBox.y; 02002 02003 /* keep it on the screen if possible */ 02004 { 02005 int new_y = 0; 02006 02007 new_y = popupBox.y; 02008 if ((new_y + (int)popupBox.h) > (int)menu.screenHeight) 02009 new_y = (int)menu.screenHeight - popupBox.h; 02010 if (new_y < ((int)menu.menuBarHeight - 1)) 02011 new_y = ((int)menu.menuBarHeight - 1); 02012 02013 int adj_y = new_y - popupBox.y; 02014 if (adj_y != 0) { 02015 popupBox.y += adj_y; 02016 02017 for (auto &i : display_list.disp_list) { 02018 DOSBoxMenu::item &item = menu.get_item(i); 02019 item.screenBox.y += adj_y; 02020 } 02021 } 02022 } 02023 { 02024 int new_x = 0; 02025 02026 new_x = popupBox.x; 02027 if ((new_x + (int)popupBox.w) > (int)menu.screenWidth) 02028 new_x = (int)menu.screenWidth - popupBox.w; 02029 if (new_x < (int)0) 02030 new_x = (int)0; 02031 02032 int adj_x = new_x - popupBox.x; 02033 if (adj_x != 0) { 02034 popupBox.x += adj_x; 02035 02036 for (auto &i : display_list.disp_list) { 02037 DOSBoxMenu::item &item = menu.get_item(i); 02038 item.screenBox.x += adj_x; 02039 } 02040 } 02041 } 02042 02043 /* 1 pixel border, top */ 02044 if (!isTopLevel) { 02045 borderTop = true; 02046 popupBox.y -= 1; 02047 popupBox.h += 1; 02048 } 02049 else { 02050 borderTop = false; 02051 } 02052 /* 1 pixel border, left */ 02053 popupBox.x -= 1; 02054 popupBox.w += 1; 02055 /* 1 pixel border, right */ 02056 popupBox.w += 1; 02057 /* 1 pixel border, bottom */ 02058 popupBox.h += 1; 02059 02060 for (auto i=display_list.disp_list.begin();i!=display_list.disp_list.end();i++) 02061 menu.get_item(*i).layoutSubmenu(menu, /*toplevel*/false); 02062 } 02063 02064 void DOSBoxMenu::item::placeItemFinal(DOSBoxMenu &menu,int finalwidth,bool isTopLevel) { 02065 if (type < separator_type_id) { 02066 int x = 0,rx = 0; 02067 02068 if (!isTopLevel) { 02069 screenBox.w = finalwidth; 02070 } 02071 02072 /* from the left */ 02073 checkBox.x = x; 02074 x += checkBox.w; 02075 02076 textBox.x = x; 02077 x += textBox.w; 02078 02079 /* from the right */ 02080 rx = screenBox.w; 02081 02082 rx -= (int)menu.fontCharWidth; 02083 02084 rx -= shortBox.w; 02085 shortBox.x = rx; 02086 02087 if (!isTopLevel) { 02088 screenBox.w = finalwidth; 02089 } 02090 02091 /* check */ 02092 if (x > rx) LOG_MSG("placeItemFinal warning: text and shorttext overlap by %d pixels",x-rx); 02093 } 02094 else if (type == separator_type_id) { 02095 if (!isTopLevel) { 02096 screenBox.w = finalwidth; 02097 } 02098 } 02099 02100 #if 0 02101 LOG_MSG("Item id=%u name=\"%s\" placed at x,y,w,h=%d,%d,%d,%d. text:x,y,w,h=%d,%d,%d,%d", 02102 master_id,name.c_str(), 02103 screenBox.x,screenBox.y, 02104 screenBox.w,screenBox.h, 02105 textBox.x,textBox.y, 02106 textBox.w,textBox.h); 02107 #endif 02108 02109 boxInit = true; 02110 } 02111 02112 void DOSBoxMenu::item::placeItem(DOSBoxMenu &menu,int x,int y,bool isTopLevel) { 02113 if (type < separator_type_id) { 02114 screenBox.x = x; 02115 screenBox.y = y; 02116 screenBox.w = 0; 02117 screenBox.h = (unsigned int)menu.fontCharHeight; 02118 02119 checkBox.x = 0; 02120 checkBox.y = 0; 02121 checkBox.w = (unsigned int)menu.fontCharWidth; 02122 checkBox.h = (unsigned int)menu.fontCharHeight; 02123 screenBox.w += (unsigned int)checkBox.w; 02124 02125 textBox.x = 0; 02126 textBox.y = 0; 02127 textBox.w = (unsigned int)menu.fontCharWidth * (unsigned int)text.length(); 02128 textBox.h = (unsigned int)menu.fontCharHeight; 02129 screenBox.w += (unsigned int)textBox.w; 02130 02131 shortBox.x = 0; 02132 shortBox.y = 0; 02133 shortBox.w = 0; 02134 shortBox.h = 0; 02135 if (!isTopLevel && !shortcut_text.empty()) { 02136 screenBox.w += (unsigned int)menu.fontCharWidth; 02137 shortBox.w += (unsigned int)menu.fontCharWidth * (unsigned int)shortcut_text.length(); 02138 shortBox.h = (unsigned int)menu.fontCharHeight; 02139 screenBox.w += (unsigned int)shortBox.w; 02140 } 02141 02142 if (!isTopLevel && type == submenu_type_id) 02143 screenBox.w += (unsigned int)menu.fontCharWidth; 02144 02145 screenBox.w += (unsigned int)menu.fontCharWidth; 02146 } 02147 else { 02148 screenBox.x = x; 02149 screenBox.y = y; 02150 screenBox.w = (unsigned int)menu.fontCharWidth * 2; 02151 screenBox.h = (unsigned int)((4 * menu.fontCharScale) + 1); 02152 02153 checkBox.x = 0; 02154 checkBox.y = 0; 02155 checkBox.w = 0; 02156 checkBox.h = 0; 02157 02158 textBox.x = 0; 02159 textBox.y = 0; 02160 textBox.w = 0; 02161 textBox.h = 0; 02162 02163 shortBox.x = 0; 02164 shortBox.y = 0; 02165 shortBox.w = 0; 02166 shortBox.h = 0; 02167 } 02168 } 02169 #endif 02170