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 #if defined(_MSC_VER) 00020 #pragma warning(disable:4065) /* Please do not warn on default case without other case statements */ 00021 #endif 00022 00023 #include "SDL.h" 00024 #include "menu.h" 00025 #include "../libs/gui_tk/gui_tk.h" 00026 00027 #include "build_timestamp.h" 00028 00029 #include "dosbox.h" 00030 #include "keyboard.h" 00031 #include "video.h" 00032 #include "render.h" 00033 #include "mapper.h" 00034 #include "setup.h" 00035 #include "control.h" 00036 #include "shell.h" 00037 #include "cpu.h" 00038 00039 #include <iostream> 00040 #include <sstream> 00041 #include <stdexcept> 00042 #include <algorithm> 00043 #include <cctype> 00044 #include <functional> 00045 #include <assert.h> 00046 00047 #include "SDL_syswm.h" 00048 00049 #ifdef DOSBOXMENU_EXTERNALLY_MANAGED 00050 static DOSBoxMenu guiMenu; 00051 #endif 00052 00053 /* helper class for command execution */ 00054 class VirtualBatch : public BatchFile { 00055 public: 00056 VirtualBatch(DOS_Shell *host, const std::string& cmds); 00057 bool ReadLine(char *line); 00058 protected: 00059 std::istringstream lines; 00060 }; 00061 00062 extern Bit8u int10_font_14[256 * 14]; 00063 00064 extern uint32_t GFX_Rmask; 00065 extern unsigned char GFX_Rshift; 00066 extern uint32_t GFX_Gmask; 00067 extern unsigned char GFX_Gshift; 00068 extern uint32_t GFX_Bmask; 00069 extern unsigned char GFX_Bshift; 00070 00071 extern bool dos_kernel_disabled; 00072 extern Bitu currentWindowWidth, currentWindowHeight; 00073 00074 extern bool MSG_Write(const char *); 00075 extern void LoadMessageFile(const char * fname); 00076 extern void GFX_SetTitle(Bit32s cycles,Bits frameskip,Bits timing,bool paused); 00077 00078 static int cursor; 00079 static bool running; 00080 static int saved_bpp; 00081 static bool shell_idle; 00082 static bool in_gui = false; 00083 #if !defined(C_SDL2) 00084 static int old_unicode; 00085 #endif 00086 static bool mousetoggle; 00087 static bool shortcut=false; 00088 static SDL_Surface* screenshot = NULL; 00089 static SDL_Surface* background = NULL; 00090 #ifdef DOSBOXMENU_EXTERNALLY_MANAGED 00091 static bool gui_menu_init = true; 00092 #endif 00093 00094 void GFX_GetSizeAndPos(int &x,int &y,int &width, int &height, bool &fullscreen); 00095 00096 #if defined(WIN32) && !defined(HX_DOS) 00097 void WindowsTaskbarUpdatePreviewRegion(void); 00098 void WindowsTaskbarResetPreviewRegion(void); 00099 #endif 00100 00101 /* Prepare screen for UI */ 00102 void GUI_LoadFonts(void) { 00103 GUI::Font::addFont("default",new GUI::BitmapFont(int10_font_14,14,10)); 00104 } 00105 00106 static void getPixel(Bits x, Bits y, int &r, int &g, int &b, int shift) 00107 { 00108 if (x >= (Bits)render.src.width) x = (Bits)render.src.width-1; 00109 if (y >= (Bits)render.src.height) x = (Bits)render.src.height-1; 00110 if (x < 0) x = 0; 00111 if (y < 0) y = 0; 00112 00113 Bit8u* src = (Bit8u *)&scalerSourceCache; 00114 Bit32u pixel; 00115 switch (render.scale.inMode) { 00116 case scalerMode8: 00117 pixel = *((unsigned int)x+(Bit8u*)(src+(unsigned int)y*(unsigned int)render.scale.cachePitch)); 00118 r += (int)((unsigned int)render.pal.rgb[pixel].red >> (unsigned int)shift); 00119 g += (int)((unsigned int)render.pal.rgb[pixel].green >> (unsigned int)shift); 00120 b += (int)((unsigned int)render.pal.rgb[pixel].blue >> (unsigned int)shift); 00121 break; 00122 case scalerMode15: 00123 pixel = *((unsigned int)x+(Bit16u*)(src+(unsigned int)y*(unsigned int)render.scale.cachePitch)); 00124 r += (int)((pixel >> (7u+(unsigned int)shift)) & (0xf8u >> (unsigned int)shift)); 00125 g += (int)((pixel >> (2u+(unsigned int)shift)) & (0xf8u >> (unsigned int)shift)); 00126 b += (int)((pixel << (3u-(unsigned int)shift)) & (0xf8u >> (unsigned int)shift)); 00127 break; 00128 case scalerMode16: 00129 pixel = *((unsigned int)x+(Bit16u*)(src+(unsigned int)y*(unsigned int)render.scale.cachePitch)); 00130 r += (int)((pixel >> (8u+(unsigned int)shift)) & (0xf8u >> shift)); 00131 g += (int)((pixel >> (3u+(unsigned int)shift)) & (0xfcu >> shift)); 00132 b += (int)((pixel << (3u-(unsigned int)shift)) & (0xf8u >> shift)); 00133 break; 00134 case scalerMode32: 00135 pixel = *((unsigned int)x+(Bit32u*)(src+(unsigned int)y*(unsigned int)render.scale.cachePitch)); 00136 r += (int)(((pixel & GFX_Rmask) >> (GFX_Rshift + shift)) & (0xffu >> shift)); 00137 g += (int)(((pixel & GFX_Gmask) >> (GFX_Gshift + shift)) & (0xffu >> shift)); 00138 b += (int)(((pixel & GFX_Bmask) >> (GFX_Bshift + shift)) & (0xffu >> shift)); 00139 break; 00140 } 00141 } 00142 00143 bool gui_menu_exit(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) { 00144 (void)menu;//UNUSED 00145 (void)menuitem;//UNUSED 00146 running = false; 00147 return true; 00148 } 00149 00150 static GUI::ScreenSDL *UI_Startup(GUI::ScreenSDL *screen) { 00151 in_gui = true; 00152 00153 GFX_EndUpdate(0); 00154 GFX_SetTitle(-1,-1,-1,true); 00155 if(!screen) { //Coming from DOSBox. Clean up the keyboard buffer. 00156 KEYBOARD_ClrBuffer();//Clear buffer 00157 } 00158 GFX_LosingFocus();//Release any keys pressed (buffer gets filled again). (could be in above if, but clearing the mapper input when exiting the mapper is sensible as well 00159 SDL_Delay(20); 00160 00161 LoadMessageFile(static_cast<Section_prop*>(control->GetSection("dosbox"))->Get_string("language")); 00162 00163 // Comparable to the code of intro.com, but not the same! (the code of intro.com is called from within a com file) 00164 shell_idle = !dos_kernel_disabled && first_shell && (DOS_PSP(dos.psp()).GetSegment() == DOS_PSP(dos.psp()).GetParent()); 00165 00166 int sx, sy, sw, sh; 00167 bool fs; 00168 GFX_GetSizeAndPos(sx, sy, sw, sh, fs); 00169 00170 int dw,dh; 00171 #if defined(C_SDL2) 00172 { 00173 dw = 640; dh = 480; 00174 00175 SDL_Window* GFX_GetSDLWindow(void); 00176 SDL_Window *w = GFX_GetSDLWindow(); 00177 SDL_GetWindowSize(w,&dw,&dh); 00178 } 00179 #elif defined(C_HX_DOS) 00180 /* FIXME: HX DOS builds are not updating the window dimensions vars.. */ 00181 /* However our window is always fullscreen (maximized) */ 00182 { 00183 dw = GetSystemMetrics(SM_CXSCREEN); 00184 dh = GetSystemMetrics(SM_CYSCREEN); 00185 } 00186 #else 00187 void UpdateWindowDimensions(void); 00188 UpdateWindowDimensions(); 00189 dw = (int)currentWindowWidth; 00190 dh = (int)currentWindowHeight; 00191 #endif 00192 00193 if (dw < 640) dw = 640; 00194 if (dh < 350) dh = 350; 00195 00196 assert(sx < dw); 00197 assert(sy < dh); 00198 00199 int sw_draw = sw,sh_draw = sh; 00200 00201 if ((sx+sw_draw) > dw) sw_draw = dw-sx; 00202 if ((sy+sh_draw) > dh) sh_draw = dh-sy; 00203 00204 assert((sx+sw_draw) <= dw); 00205 assert((sy+sh_draw) <= dh); 00206 00207 assert(sw_draw <= sw); 00208 assert(sh_draw <= sh); 00209 00210 #if !defined(C_SDL2) 00211 old_unicode = SDL_EnableUNICODE(1); 00212 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY,SDL_DEFAULT_REPEAT_INTERVAL); 00213 #endif 00214 00215 if (sw_draw > 0 && sh_draw > 0) { 00216 screenshot = SDL_CreateRGBSurface(SDL_SWSURFACE, dw, dh, 32, GUI::Color::RedMask, GUI::Color::GreenMask, GUI::Color::BlueMask, 0); 00217 SDL_FillRect(screenshot,0,0); 00218 00219 unsigned int rs = screenshot->format->Rshift, gs = screenshot->format->Gshift, bs = screenshot->format->Bshift; 00220 00221 // create screenshot for fade effect 00222 for (unsigned int y = 0; (int)y < sh_draw; y++) { 00223 Bit32u *bg = (Bit32u*)((y+(unsigned int)sy)*(unsigned int)screenshot->pitch + (char*)screenshot->pixels) + (unsigned int)sx; 00224 for (unsigned int x = 0; (int)x < sw_draw; x++) { 00225 int r = 0, g = 0, b = 0; 00226 getPixel((int)(x*(unsigned int)render.src.width/(unsigned int)sw), 00227 (int)(y*(unsigned int)render.src.height/(unsigned int)sh), 00228 r, g, b, 0); 00229 bg[x] = ((unsigned int)r << (unsigned int)rs) | 00230 ((unsigned int)g << (unsigned int)gs) | 00231 ((unsigned int)b << (unsigned int)bs); 00232 } 00233 } 00234 00235 background = SDL_CreateRGBSurface(SDL_SWSURFACE, dw, dh, 32, GUI::Color::RedMask, GUI::Color::GreenMask, GUI::Color::BlueMask, 0); 00236 SDL_FillRect(background,0,0); 00237 for (int y = 0; y < sh_draw; y++) { 00238 Bit32u *bg = (Bit32u*)((unsigned int)(y+sy)*(unsigned int)background->pitch + (char*)background->pixels) + sx; 00239 for (int x = 0; x < sw_draw; x++) { 00240 int r = 0, g = 0, b = 0; 00241 getPixel(x *(int)render.src.width/sw, y *(int)render.src.height/sh, r, g, b, 3); 00242 getPixel((x-1)*(int)render.src.width/sw, y *(int)render.src.height/sh, r, g, b, 3); 00243 getPixel(x *(int)render.src.width/sw, (y-1)*(int)render.src.height/sh, r, g, b, 3); 00244 getPixel((x-1)*(int)render.src.width/sw, (y-1)*(int)render.src.height/sh, r, g, b, 3); 00245 getPixel((x+1)*(int)render.src.width/sw, y *(int)render.src.height/sh, r, g, b, 3); 00246 getPixel(x *(int)render.src.width/sw, (y+1)*(int)render.src.height/sh, r, g, b, 3); 00247 getPixel((x+1)*(int)render.src.width/sw, (y+1)*(int)render.src.height/sh, r, g, b, 3); 00248 getPixel((x-1)*(int)render.src.width/sw, (y+1)*(int)render.src.height/sh, r, g, b, 3); 00249 int r1 = (int)((r * 393 + g * 769 + b * 189) / 1351); // 1351 -- tweak colors 00250 int g1 = (int)((r * 349 + g * 686 + b * 168) / 1503); // 1203 -- for a nice 00251 int b1 = (int)((r * 272 + g * 534 + b * 131) / 2340); // 2140 -- golden hue 00252 bg[x] = ((unsigned int)r1 << (unsigned int)rs) | 00253 ((unsigned int)g1 << (unsigned int)gs) | 00254 ((unsigned int)b1 << (unsigned int)bs); 00255 } 00256 } 00257 } 00258 00259 cursor = SDL_ShowCursor(SDL_QUERY); 00260 SDL_ShowCursor(SDL_ENABLE); 00261 00262 mousetoggle = mouselocked; 00263 if (mouselocked) GFX_CaptureMouse(); 00264 00265 #if defined(C_SDL2) 00266 extern SDL_Window * GFX_SetSDLSurfaceWindow(Bit16u width, Bit16u height); 00267 00268 void GFX_SetResizeable(bool enable); 00269 GFX_SetResizeable(false); 00270 00271 SDL_Window* window = GFX_SetSDLSurfaceWindow(dw, dh); 00272 if (window == NULL) E_Exit("Could not initialize video mode for mapper: %s",SDL_GetError()); 00273 SDL_Surface* sdlscreen = SDL_GetWindowSurface(window); 00274 if (sdlscreen == NULL) E_Exit("Could not initialize video mode for mapper: %s",SDL_GetError()); 00275 00276 if (screenshot != NULL && background != NULL) { 00277 // fade out 00278 // Jonathan C: do it FASTER! 00279 SDL_Event event; 00280 SDL_SetSurfaceBlendMode(screenshot, SDL_BLENDMODE_BLEND); 00281 for (int i = 0xff; i > 0; i -= 0x40) { 00282 SDL_SetSurfaceAlphaMod(screenshot, i); 00283 SDL_BlitSurface(background, NULL, sdlscreen, NULL); 00284 SDL_BlitSurface(screenshot, NULL, sdlscreen, NULL); 00285 SDL_Window* GFX_GetSDLWindow(void); 00286 SDL_UpdateWindowSurface(GFX_GetSDLWindow()); 00287 while (SDL_PollEvent(&event)); 00288 SDL_Delay(40); 00289 } 00290 SDL_SetSurfaceBlendMode(screenshot, SDL_BLENDMODE_NONE); 00291 } 00292 #else 00293 SDL_Surface* sdlscreen = SDL_SetVideoMode(dw, dh, 32, SDL_SWSURFACE|(fs?SDL_FULLSCREEN:0)); 00294 if (sdlscreen == NULL) E_Exit("Could not initialize video mode %ix%ix32 for UI: %s", dw, dh, SDL_GetError()); 00295 00296 if (screenshot != NULL && background != NULL) { 00297 // fade out 00298 // Jonathan C: do it FASTER! 00299 SDL_Event event; 00300 for (int i = 0xff; i > 0; i -= 0x40) { 00301 SDL_SetAlpha(screenshot, SDL_SRCALPHA, i); 00302 SDL_BlitSurface(background, NULL, sdlscreen, NULL); 00303 SDL_BlitSurface(screenshot, NULL, sdlscreen, NULL); 00304 SDL_UpdateRect(sdlscreen, 0, 0, 0, 0); 00305 while (SDL_PollEvent(&event)); 00306 SDL_Delay(40); 00307 } 00308 } 00309 #endif 00310 00311 if (screenshot != NULL && background != NULL) 00312 SDL_BlitSurface(background, NULL, sdlscreen, NULL); 00313 #if defined(C_SDL2) 00314 SDL_Window* GFX_GetSDLWindow(void); 00315 SDL_UpdateWindowSurface(GFX_GetSDLWindow()); 00316 #else 00317 SDL_UpdateRect(sdlscreen, 0, 0, 0, 0); 00318 #endif 00319 00320 #if defined(WIN32) && !defined(HX_DOS) 00321 WindowsTaskbarResetPreviewRegion(); 00322 #endif 00323 00324 #ifdef DOSBOXMENU_EXTERNALLY_MANAGED 00325 if (gui_menu_init) { 00326 gui_menu_init = false; 00327 00328 { 00329 DOSBoxMenu::item &item = guiMenu.alloc_item(DOSBoxMenu::submenu_type_id,"ConfigGuiMenu"); 00330 item.set_text("Configuration GUI"); 00331 } 00332 00333 { 00334 DOSBoxMenu::item &item = guiMenu.alloc_item(DOSBoxMenu::item_type_id,"ExitGUI"); 00335 item.set_callback_function(gui_menu_exit); 00336 item.set_text("Exit configuration GUI"); 00337 } 00338 00339 guiMenu.displaylist_clear(guiMenu.display_list); 00340 00341 guiMenu.displaylist_append( 00342 guiMenu.display_list, 00343 guiMenu.get_item_id_by_name("ConfigGuiMenu")); 00344 00345 { 00346 guiMenu.displaylist_append( 00347 guiMenu.get_item("ConfigGuiMenu").display_list, guiMenu.get_item_id_by_name("ExitGUI")); 00348 } 00349 } 00350 00351 guiMenu.rebuild(); 00352 DOSBox_SetMenu(guiMenu); 00353 #endif 00354 00355 if (screen) screen->setSurface(sdlscreen); 00356 else screen = new GUI::ScreenSDL(sdlscreen); 00357 00358 saved_bpp = (int)render.src.bpp; 00359 render.src.bpp = 0; 00360 running = true; 00361 00362 #if defined(MACOSX) 00363 void osx_reload_touchbar(void); 00364 osx_reload_touchbar(); 00365 #endif 00366 00367 return screen; 00368 } 00369 00370 /* Restore screen */ 00371 static void UI_Shutdown(GUI::ScreenSDL *screen) { 00372 SDL_Surface *sdlscreen = screen->getSurface(); 00373 render.src.bpp = (Bitu)saved_bpp; 00374 00375 #ifdef DOSBOXMENU_EXTERNALLY_MANAGED 00376 DOSBox_SetMenu(mainMenu); 00377 #endif 00378 00379 #if defined(MACOSX) 00380 void osx_reload_touchbar(void); 00381 osx_reload_touchbar(); 00382 #endif 00383 00384 #if defined(C_SDL2) 00385 if (screenshot != NULL && background != NULL) { 00386 // fade in 00387 // Jonathan C: do it FASTER! 00388 SDL_Event event; 00389 SDL_SetSurfaceBlendMode(screenshot, SDL_BLENDMODE_BLEND); 00390 for (unsigned int i = 0x00; i < 0xff; i += 0x60) { 00391 SDL_SetSurfaceAlphaMod(screenshot, i); 00392 SDL_BlitSurface(background, NULL, sdlscreen, NULL); 00393 SDL_BlitSurface(screenshot, NULL, sdlscreen, NULL); 00394 SDL_Window* GFX_GetSDLWindow(void); 00395 SDL_UpdateWindowSurface(GFX_GetSDLWindow()); 00396 while (SDL_PollEvent(&event)); 00397 SDL_Delay(40); 00398 } 00399 SDL_SetSurfaceBlendMode(screenshot, SDL_BLENDMODE_NONE); 00400 } 00401 00402 void GFX_SetResizeable(bool enable); 00403 GFX_SetResizeable(true); 00404 #else 00405 if (screenshot != NULL && background != NULL) { 00406 // fade in 00407 // Jonathan C: do it FASTER! 00408 SDL_Event event; 00409 for (unsigned int i = 0x00; i < 0xff; i += 0x60) { 00410 SDL_SetAlpha(screenshot, SDL_SRCALPHA, i); 00411 SDL_BlitSurface(background, NULL, sdlscreen, NULL); 00412 SDL_BlitSurface(screenshot, NULL, sdlscreen, NULL); 00413 SDL_UpdateRect(sdlscreen, 0, 0, 0, 0); 00414 while (SDL_PollEvent(&event)) {} 00415 SDL_Delay(40); 00416 } 00417 } 00418 #endif 00419 00420 // clean up 00421 if (mousetoggle) GFX_CaptureMouse(); 00422 SDL_ShowCursor(cursor); 00423 if (background != NULL) { 00424 SDL_FreeSurface(background); 00425 background = NULL; 00426 } 00427 if (screenshot != NULL) { 00428 SDL_FreeSurface(screenshot); 00429 screenshot = NULL; 00430 } 00431 SDL_FreeSurface(sdlscreen); 00432 screen->setSurface(NULL); 00433 #ifdef WIN32 00434 void res_init(void); 00435 void change_output(int output); 00436 res_init(); 00437 change_output(7); 00438 #else 00439 #if 1 00440 GFX_RestoreMode(); 00441 #else 00442 GFX_ResetScreen(); 00443 #endif 00444 #endif 00445 00446 #if defined(WIN32) && !defined(HX_DOS) 00447 WindowsTaskbarUpdatePreviewRegion(); 00448 #endif 00449 00450 #if !defined(C_SDL2) 00451 SDL_EnableUNICODE(old_unicode); 00452 SDL_EnableKeyRepeat(0,0); 00453 #endif 00454 GFX_SetTitle(-1,-1,-1,false); 00455 00456 void GFX_ForceRedrawScreen(void); 00457 GFX_ForceRedrawScreen(); 00458 00459 in_gui = false; 00460 } 00461 00462 bool GUI_IsRunning(void) { 00463 return in_gui; 00464 } 00465 00466 static void UI_RunCommands(GUI::ScreenSDL *s, const std::string &cmds) { 00467 DOS_Shell temp; 00468 temp.call = true; 00469 UI_Shutdown(s); 00470 Bit16u n=1; Bit8u c='\n'; 00471 DOS_WriteFile(STDOUT,&c,&n); 00472 temp.bf = new VirtualBatch(&temp, cmds); 00473 temp.RunInternal(); 00474 temp.ShowPrompt(); 00475 UI_Startup(s); 00476 } 00477 00478 VirtualBatch::VirtualBatch(DOS_Shell *host, const std::string& cmds) : BatchFile(host, "CON", "", ""), lines(cmds) { 00479 } 00480 00481 bool VirtualBatch::ReadLine(char *line) { 00482 std::string l; 00483 00484 if (!std::getline(lines,l)) { 00485 delete this; 00486 return false; 00487 } 00488 00489 strcpy(line,l.c_str()); 00490 return true; 00491 } 00492 00493 /* stringification and conversion from the c++ FAQ */ 00494 class BadConversion : public std::runtime_error { 00495 public: BadConversion(const std::string& s) : std::runtime_error(s) { } 00496 }; 00497 00498 template<typename T> inline std::string stringify(const T& x, std::ios_base& ( *pf )(std::ios_base&) = NULL) { 00499 std::ostringstream o; 00500 if (pf) o << pf; 00501 if (!(o << x)) throw BadConversion(std::string("stringify(") + typeid(x).name() + ")"); 00502 return o.str(); 00503 } 00504 00505 template<typename T> inline void convert(const std::string& s, T& x, bool failIfLeftoverChars = true, std::ios_base& ( *pf )(std::ios_base&) = NULL) { 00506 std::istringstream i(s); 00507 if (pf) i >> pf; 00508 char c; 00509 if (!(i >> x) || (failIfLeftoverChars && i.get(c))) throw BadConversion(s); 00510 } 00511 00512 /*****************************************************************************************************************************************/ 00513 /* UI classes */ 00514 00515 class PropertyEditor : public GUI::Window, public GUI::ActionEventSource_Callback { 00516 protected: 00517 Section_prop * section; 00518 Property *prop; 00519 public: 00520 PropertyEditor(Window *parent, int x, int y, Section_prop *section, Property *prop) : 00521 Window(parent, x, y, 500, 25), section(section), prop(prop) { } 00522 00523 virtual bool prepare(std::string &buffer) = 0; 00524 00525 void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) { 00526 (void)b;//UNUSED 00527 // HACK: Attempting to cast a String to void causes "forming reference to void" errors when building with GCC 4.7 00528 (void)arg.size();//UNUSED 00529 std::string line; 00530 if (prepare(line)) { 00531 prop->SetValue(GUI::String(line)); 00532 } 00533 } 00534 00535 void paintVisGuideLineBetween(GUI::Drawable &d,const GUI::Window *lm,const GUI::Window *rm,const GUI::Window *pm) const { 00536 int sx = lm->getX() + lm->getWidth(); 00537 int ex = rm->getX(); 00538 int y = pm->getHeight() / 2; 00539 00540 sx += 4; 00541 ex -= 4; 00542 00543 d.setColor(GUI::Color::Shadow3D); 00544 d.drawDotLine(sx,y,ex,y); 00545 } 00546 }; 00547 00548 class PropertyEditorBool : public PropertyEditor { 00549 GUI::Checkbox *input; 00550 GUI::Label *label; 00551 public: 00552 PropertyEditorBool(Window *parent, int x, int y, Section_prop *section, Property *prop) : 00553 PropertyEditor(parent, x, y, section, prop) { 00554 label = new GUI::Label(this, 0, 5, prop->propname); 00555 input = new GUI::Checkbox(this, 480, 3, ""); 00556 input->setChecked(static_cast<bool>(prop->GetValue())); 00557 } 00558 00559 bool prepare(std::string &buffer) { 00560 if (input->isChecked() == static_cast<bool>(prop->GetValue())) return false; 00561 buffer.append(input->isChecked()?"true":"false"); 00562 return true; 00563 } 00564 00566 virtual void paint(GUI::Drawable &d) const { 00567 paintVisGuideLineBetween(d,label,input,this); 00568 } 00569 }; 00570 00571 class PropertyEditorString : public PropertyEditor { 00572 protected: 00573 GUI::Input *input; 00574 GUI::Label *label; 00575 public: 00576 PropertyEditorString(Window *parent, int x, int y, Section_prop *section, Property *prop) : 00577 PropertyEditor(parent, x, y, section, prop) { 00578 label = new GUI::Label(this, 0, 5, prop->propname); 00579 input = new GUI::Input(this, 270, 0, 230); 00580 std::string temps = prop->GetValue().ToString(); 00581 input->setText(stringify(temps)); 00582 } 00583 00584 bool prepare(std::string &buffer) { 00585 std::string temps = prop->GetValue().ToString(); 00586 if (input->getText() == GUI::String(temps)) return false; 00587 buffer.append(static_cast<const std::string&>(input->getText())); 00588 return true; 00589 } 00590 00592 virtual void paint(GUI::Drawable &d) const { 00593 paintVisGuideLineBetween(d,label,input,this); 00594 } 00595 }; 00596 00597 class PropertyEditorFloat : public PropertyEditor { 00598 protected: 00599 GUI::Input *input; 00600 GUI::Label *label; 00601 public: 00602 PropertyEditorFloat(Window *parent, int x, int y, Section_prop *section, Property *prop) : 00603 PropertyEditor(parent, x, y, section, prop) { 00604 label = new GUI::Label(this, 0, 5, prop->propname); 00605 input = new GUI::Input(this, 380, 0, 120); 00606 input->setText(stringify((double)prop->GetValue())); 00607 } 00608 00609 bool prepare(std::string &buffer) { 00610 double val; 00611 convert(input->getText(), val, false); 00612 if (val == (double)prop->GetValue()) return false; 00613 buffer.append(stringify(val)); 00614 return true; 00615 } 00616 00618 virtual void paint(GUI::Drawable &d) const { 00619 paintVisGuideLineBetween(d,label,input,this); 00620 } 00621 }; 00622 00623 class PropertyEditorHex : public PropertyEditor { 00624 protected: 00625 GUI::Input *input; 00626 GUI::Label *label; 00627 public: 00628 PropertyEditorHex(Window *parent, int x, int y, Section_prop *section, Property *prop) : 00629 PropertyEditor(parent, x, y, section, prop) { 00630 label = new GUI::Label(this, 0, 5, prop->propname); 00631 input = new GUI::Input(this, 380, 0, 120); 00632 std::string temps = prop->GetValue().ToString(); 00633 input->setText(temps.c_str()); 00634 } 00635 00636 bool prepare(std::string &buffer) { 00637 int val; 00638 convert(input->getText(), val, false, std::hex); 00639 if ((Hex)val == prop->GetValue()) return false; 00640 buffer.append(stringify(val, std::hex)); 00641 return true; 00642 } 00643 00645 virtual void paint(GUI::Drawable &d) const { 00646 paintVisGuideLineBetween(d,label,input,this); 00647 } 00648 }; 00649 00650 class PropertyEditorInt : public PropertyEditor { 00651 protected: 00652 GUI::Input *input; 00653 GUI::Label *label; 00654 public: 00655 PropertyEditorInt(Window *parent, int x, int y, Section_prop *section, Property *prop) : 00656 PropertyEditor(parent, x, y, section, prop) { 00657 label = new GUI::Label(this, 0, 5, prop->propname); 00658 input = new GUI::Input(this, 380, 0, 120); 00659 //Maybe use ToString() of Value 00660 input->setText(stringify(static_cast<int>(prop->GetValue()))); 00661 }; 00662 00663 bool prepare(std::string &buffer) { 00664 int val; 00665 convert(input->getText(), val, false); 00666 if (val == static_cast<int>(prop->GetValue())) return false; 00667 buffer.append(stringify(val)); 00668 return true; 00669 }; 00670 00672 virtual void paint(GUI::Drawable &d) const { 00673 paintVisGuideLineBetween(d,label,input,this); 00674 } 00675 }; 00676 00677 static std::map< std::vector<GUI::Char>, GUI::ToplevelWindow* > cfg_windows_active; 00678 00679 class HelpWindow : public GUI::MessageBox2 { 00680 public: 00681 std::vector<GUI::Char> cfg_sname; 00682 public: 00683 HelpWindow(GUI::Screen *parent, int x, int y, Section *section) : 00684 MessageBox2(parent, x, y, 580, "", "") { // 740 00685 if (section == NULL) { 00686 LOG_MSG("BUG: HelpWindow constructor called with section == NULL\n"); 00687 return; 00688 } 00689 00690 std::string title(section->GetName()); 00691 title.at(0) = std::toupper(title.at(0)); 00692 setTitle("Help for "+title); 00693 00694 Section_prop* sec = dynamic_cast<Section_prop*>(section); 00695 if (sec) { 00696 std::string msg; 00697 Property *p; 00698 int i = 0; 00699 while ((p = sec->Get_prop(i++))) { 00700 msg += std::string("\033[31m")+p->propname+":\033[0m\n"+p->Get_help()+"\n\n"; 00701 } 00702 if (!msg.empty()) msg.replace(msg.end()-1,msg.end(),""); 00703 setText(msg); 00704 } else { 00705 std::string name = section->GetName(); 00706 std::transform(name.begin(), name.end(), name.begin(), (int(*)(int))std::toupper); 00707 name += "_CONFIGFILE_HELP"; 00708 setText(MSG_Get(name.c_str())); 00709 } 00710 }; 00711 00712 ~HelpWindow() { 00713 if (!cfg_sname.empty()) { 00714 auto i = cfg_windows_active.find(cfg_sname); 00715 if (i != cfg_windows_active.end()) cfg_windows_active.erase(i); 00716 } 00717 } 00718 }; 00719 00720 class SectionEditor : public GUI::ToplevelWindow { 00721 Section_prop * section; 00722 GUI::Button * closeButton = NULL; 00723 GUI::WindowInWindow * wiw = NULL; 00724 public: 00725 std::vector<GUI::Char> cfg_sname; 00726 public: 00727 SectionEditor(GUI::Screen *parent, int x, int y, Section_prop *section) : 00728 ToplevelWindow(parent, x, y, 510, 442, ""), section(section) { 00729 if (section == NULL) { 00730 LOG_MSG("BUG: SectionEditor constructor called with section == NULL\n"); 00731 return; 00732 } 00733 00734 int first_row_y = 5; 00735 int row_height = 25; 00736 int column_width = 500; 00737 int button_row_h = 26; 00738 int button_row_padding_y = 5 + 5; 00739 00740 int num_prop = 0; 00741 while (section->Get_prop(num_prop) != NULL) num_prop++; 00742 00743 int allowed_dialog_y = parent->getHeight() - 25 - (border_top + border_bottom) - 50; 00744 00745 int items_per_col = num_prop; 00746 int columns = 1; 00747 00748 int scroll_h = items_per_col * row_height; 00749 if (scroll_h > allowed_dialog_y) 00750 scroll_h = allowed_dialog_y; 00751 00752 scroll_h += 2; /* border */ 00753 00754 wiw = new GUI::WindowInWindow(this, 5, 5, width-border_left-border_right-10, scroll_h); 00755 00756 int button_row_y = first_row_y + scroll_h + 5; 00757 int button_w = 70; 00758 int button_pad_w = 10; 00759 int button_row_w = ((button_pad_w + button_w) * 3) - button_pad_w; 00760 int button_row_cx = (((columns * column_width) - button_row_w) / 2) + 5; 00761 00762 resize((columns * column_width) + border_left + border_right + 2/*wiw border*/ + wiw->vscroll_display_width/*scrollbar*/ + 10, 00763 button_row_y + button_row_h + button_row_padding_y + border_top + border_bottom); 00764 00765 if ((this->y + this->getHeight()) > parent->getHeight()) 00766 move(this->x,parent->getHeight() - this->getHeight()); 00767 00768 std::string title(section->GetName()); 00769 title[0] = std::toupper(title[0]); 00770 setTitle("Configuration for "+title); 00771 00772 GUI::Button *b = new GUI::Button(this, button_row_cx, button_row_y, "Cancel", button_w); 00773 b->addActionHandler(this); 00774 closeButton = b; 00775 00776 b = new GUI::Button(this, button_row_cx + (button_w + button_pad_w), button_row_y, "Help", button_w); 00777 b->addActionHandler(this); 00778 00779 b = new GUI::Button(this, button_row_cx + (button_w + button_pad_w)*2, button_row_y, "OK", button_w); 00780 00781 int i = 0; 00782 Property *prop; 00783 while ((prop = section->Get_prop(i))) { 00784 Prop_bool *pbool = dynamic_cast<Prop_bool*>(prop); 00785 Prop_int *pint = dynamic_cast<Prop_int*>(prop); 00786 Prop_double *pdouble = dynamic_cast<Prop_double*>(prop); 00787 Prop_hex *phex = dynamic_cast<Prop_hex*>(prop); 00788 Prop_string *pstring = dynamic_cast<Prop_string*>(prop); 00789 Prop_multival* pmulti = dynamic_cast<Prop_multival*>(prop); 00790 Prop_multival_remain* pmulti_remain = dynamic_cast<Prop_multival_remain*>(prop); 00791 00792 PropertyEditor *p; 00793 if (pbool) p = new PropertyEditorBool(wiw, column_width*(i/items_per_col), (i%items_per_col)*row_height, section, prop); 00794 else if (phex) p = new PropertyEditorHex(wiw, column_width*(i/items_per_col), (i%items_per_col)*row_height, section, prop); 00795 else if (pint) p = new PropertyEditorInt(wiw, column_width*(i/items_per_col), (i%items_per_col)*row_height, section, prop); 00796 else if (pdouble) p = new PropertyEditorFloat(wiw, column_width*(i/items_per_col), (i%items_per_col)*row_height, section, prop); 00797 else if (pstring) p = new PropertyEditorString(wiw, column_width*(i/items_per_col), (i%items_per_col)*row_height, section, prop); 00798 else if (pmulti) p = new PropertyEditorString(wiw, column_width*(i/items_per_col), (i%items_per_col)*row_height, section, prop); 00799 else if (pmulti_remain) p = new PropertyEditorString(wiw, column_width*(i/items_per_col), (i%items_per_col)*row_height, section, prop); 00800 else { i++; continue; } 00801 b->addActionHandler(p); 00802 i++; 00803 } 00804 b->addActionHandler(this); 00805 00806 /* first child is first tabbable */ 00807 { 00808 Window *w = wiw->getChild(0); 00809 if (w) w->first_tabbable = true; 00810 } 00811 00812 /* last child is first tabbable */ 00813 { 00814 Window *w = wiw->getChild(wiw->getChildCount()-1); 00815 if (w) w->last_tabbable = true; 00816 } 00817 00818 /* the FIRST field needs to come first when tabbed to */ 00819 { 00820 Window *w = wiw->getChild(0); 00821 if (w) w->raise(); /* NTS: This CHANGES the child element order, getChild(0) will return something else */ 00822 } 00823 00824 wiw->resize((columns * column_width) + 2/*border*/ + wiw->vscroll_display_width, scroll_h); 00825 00826 if (wiw->scroll_pos_h != 0) { 00827 wiw->enableScrollBars(false/*h*/,true/*v*/); 00828 wiw->enableBorder(true); 00829 } 00830 else { 00831 wiw->enableScrollBars(false/*h*/,false/*v*/); 00832 wiw->enableBorder(false); 00833 00834 resize((columns * column_width) + border_left + border_right + 2/*wiw border*/ + /*wiw->vscroll_display_width*//*scrollbar*/ + 10, 00835 button_row_y + button_row_h + button_row_padding_y + border_top + border_bottom); 00836 } 00837 } 00838 00839 ~SectionEditor() { 00840 if (!cfg_sname.empty()) { 00841 auto i = cfg_windows_active.find(cfg_sname); 00842 if (i != cfg_windows_active.end()) cfg_windows_active.erase(i); 00843 } 00844 } 00845 00846 void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) { 00847 if (arg == "OK" || arg == "Cancel" || arg == "Close") { close(); if(shortcut) running=false; } 00848 else if (arg == "Help") { 00849 std::vector<GUI::Char> new_cfg_sname; 00850 00851 if (!cfg_sname.empty()) { 00852 // new_cfg_sname = "help_"; 00853 new_cfg_sname.resize(5); 00854 new_cfg_sname[0] = 'h'; 00855 new_cfg_sname[1] = 'e'; 00856 new_cfg_sname[2] = 'l'; 00857 new_cfg_sname[3] = 'p'; 00858 new_cfg_sname[4] = '_'; 00859 new_cfg_sname.insert(new_cfg_sname.end(),cfg_sname.begin(),cfg_sname.end()); 00860 } 00861 00862 auto lookup = cfg_windows_active.find(new_cfg_sname); 00863 if (lookup == cfg_windows_active.end()) { 00864 int nx = getX() - 10; 00865 int ny = getY() - 10; 00866 if (nx < 0) nx = 0; 00867 if (ny < 0) ny = 0; 00868 auto *np = new HelpWindow(static_cast<GUI::Screen*>(parent), nx, ny, section); 00869 cfg_windows_active[new_cfg_sname] = np; 00870 np->cfg_sname = new_cfg_sname; 00871 np->raise(); 00872 } 00873 else { 00874 lookup->second->raise(); 00875 } 00876 } 00877 else 00878 ToplevelWindow::actionExecuted(b, arg); 00879 } 00880 00881 virtual bool keyDown(const GUI::Key &key) { 00882 if (GUI::ToplevelWindow::keyDown(key)) return true; 00883 return false; 00884 } 00885 00886 virtual bool keyUp(const GUI::Key &key) { 00887 if (GUI::ToplevelWindow::keyUp(key)) return true; 00888 00889 if (key.special == GUI::Key::Escape) { 00890 closeButton->executeAction(); 00891 return true; 00892 } 00893 00894 return false; 00895 } 00896 00897 }; 00898 00899 class AutoexecEditor : public GUI::ToplevelWindow { 00900 GUI::Button *closeButton = NULL; 00901 Section_line * section; 00902 GUI::Input *content = NULL; 00903 public: 00904 std::vector<GUI::Char> cfg_sname; 00905 public: 00906 AutoexecEditor(GUI::Screen *parent, int x, int y, Section_line *section) : 00907 ToplevelWindow(parent, x, y, 450, 260 + GUI::titlebar_y_stop, ""), section(section) { 00908 if (section == NULL) { 00909 LOG_MSG("BUG: AutoexecEditor constructor called with section == NULL\n"); 00910 return; 00911 } 00912 00913 std::string title(section->GetName()); 00914 title[0] = std::toupper(title[0]); 00915 setTitle("Edit "+title); 00916 new GUI::Label(this, 5, 10, "Content:"); 00917 content = new GUI::Input(this, 5, 30, 450 - 10 - border_left - border_right, 185); 00918 content->setText(section->data); 00919 if (first_shell) (new GUI::Button(this, 5, 220, "Append History"))->addActionHandler(this); 00920 if (shell_idle) (new GUI::Button(this, 180, 220, "Execute Now"))->addActionHandler(this); 00921 (closeButton = new GUI::Button(this, 290, 220, "Cancel", 70))->addActionHandler(this); 00922 (new GUI::Button(this, 360, 220, "OK", 70))->addActionHandler(this); 00923 } 00924 00925 ~AutoexecEditor() { 00926 if (!cfg_sname.empty()) { 00927 auto i = cfg_windows_active.find(cfg_sname); 00928 if (i != cfg_windows_active.end()) cfg_windows_active.erase(i); 00929 } 00930 } 00931 00932 void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) { 00933 if (arg == "OK") section->data = *(std::string*)content->getText(); 00934 if (arg == "OK" || arg == "Cancel" || arg == "Close") { close(); if(shortcut) running=false; } 00935 else if (arg == "Append History") { 00936 std::list<std::string>::reverse_iterator i = first_shell->l_history.rbegin(); 00937 std::string lines = *(std::string*)content->getText(); 00938 while (i != first_shell->l_history.rend()) { 00939 lines += "\n"; 00940 lines += *i; 00941 ++i; 00942 } 00943 content->setText(lines); 00944 } else if (arg == "Execute Now") { 00945 UI_RunCommands(dynamic_cast<GUI::ScreenSDL*>(getScreen()), content->getText()); 00946 } else ToplevelWindow::actionExecuted(b, arg); 00947 } 00948 00949 virtual bool keyDown(const GUI::Key &key) { 00950 if (GUI::ToplevelWindow::keyDown(key)) return true; 00951 return false; 00952 } 00953 00954 virtual bool keyUp(const GUI::Key &key) { 00955 if (GUI::ToplevelWindow::keyUp(key)) return true; 00956 00957 if (key.special == GUI::Key::Escape) { 00958 closeButton->executeAction(); 00959 return true; 00960 } 00961 00962 return false; 00963 } 00964 00965 }; 00966 00967 class SaveDialog : public GUI::ToplevelWindow { 00968 protected: 00969 GUI::Input *name; 00970 public: 00971 SaveDialog(GUI::Screen *parent, int x, int y, const char *title) : 00972 ToplevelWindow(parent, x, y, 400, 100 + GUI::titlebar_y_stop, title) { 00973 new GUI::Label(this, 5, 10, "Enter filename for configuration file:"); 00974 name = new GUI::Input(this, 5, 30, width - 10 - border_left - border_right); 00975 extern std::string capturedir; 00976 std::string fullpath,file; 00977 Cross::GetPlatformConfigName(file); 00978 const size_t last_slash_idx = capturedir.find_last_of("\\/"); 00979 if (std::string::npos != last_slash_idx) { 00980 fullpath = capturedir.substr(0, last_slash_idx); 00981 fullpath += CROSS_FILESPLIT; 00982 fullpath += file; 00983 } else 00984 fullpath = "dosbox-x.conf"; 00985 name->setText(fullpath.c_str()); 00986 (new GUI::Button(this, 120, 60, "Cancel", 70))->addActionHandler(this); 00987 (new GUI::Button(this, 210, 60, "OK", 70))->addActionHandler(this); 00988 } 00989 00990 void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) { 00991 (void)b;//UNUSED 00992 // HACK: Attempting to cast a String to void causes "forming reference to void" errors when building with GCC 4.7 00993 (void)arg.size();//UNUSED 00994 if (arg == "OK") control->PrintConfig(name->getText()); 00995 close(); 00996 if(shortcut) running=false; 00997 } 00998 }; 00999 01000 class SaveLangDialog : public GUI::ToplevelWindow { 01001 protected: 01002 GUI::Input *name; 01003 public: 01004 SaveLangDialog(GUI::Screen *parent, int x, int y, const char *title) : 01005 ToplevelWindow(parent, x, y, 400, 100 + GUI::titlebar_y_stop, title) { 01006 new GUI::Label(this, 5, 10, "Enter filename for language file:"); 01007 name = new GUI::Input(this, 5, 30, width - 10 - border_left - border_right); 01008 name->setText("messages.txt"); 01009 (new GUI::Button(this, 120, 60, "Cancel", 70))->addActionHandler(this); 01010 (new GUI::Button(this, 210, 60, "OK", 70))->addActionHandler(this); 01011 } 01012 01013 void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) { 01014 (void)b;//UNUSED 01015 if (arg == "OK") MSG_Write(name->getText()); 01016 close(); 01017 if(shortcut) running=false; 01018 } 01019 }; 01020 01021 // override Input field with one that responds to the Enter key as a keyboard-based cue to click "OK" 01022 class InputWithEnterKey : public GUI::Input { 01023 public: 01024 InputWithEnterKey(Window *parent, int x, int y, int w, int h = 0) : GUI::Input(parent,x,y,w,h) { }; 01025 public: 01026 void set_trigger_target(GUI::ToplevelWindow *_who) { trigger_who = _who; }; 01027 protected: 01028 GUI::ToplevelWindow* trigger_who = NULL; 01029 public: 01030 std::string trigger_enter = "OK"; 01031 std::string trigger_esc = "Cancel"; 01032 public: 01033 virtual bool keyDown(const GUI::Key &key) { 01034 if (key.special == GUI::Key::Special::Enter) { 01035 if (trigger_who != NULL && !trigger_enter.empty()) 01036 trigger_who->actionExecuted(this, trigger_enter); 01037 01038 return true; 01039 } 01040 else if (key.special == GUI::Key::Special::Escape) { 01041 if (trigger_who != NULL && !trigger_esc.empty()) 01042 trigger_who->actionExecuted(this, trigger_esc); 01043 01044 return true; 01045 } 01046 else { 01047 return GUI::Input::keyDown(key); 01048 } 01049 } 01050 }; 01051 01052 class SetCycles : public GUI::ToplevelWindow { 01053 protected: 01054 InputWithEnterKey *name; 01055 public: 01056 SetCycles(GUI::Screen *parent, int x, int y, const char *title) : 01057 ToplevelWindow(parent, x, y, 400, 100 + GUI::titlebar_y_stop, title) { 01058 new GUI::Label(this, 5, 10, "Enter CPU cycles:"); 01059 // name = new GUI::Input(this, 5, 30, 350); 01060 name = new InputWithEnterKey(this, 5, 30, width - 10 - border_left - border_right); 01061 name->set_trigger_target(this); 01062 std::ostringstream str; 01063 str << "fixed " << CPU_CycleMax; 01064 01065 std::string cycles=str.str(); 01066 name->setText(cycles.c_str()); 01067 (new GUI::Button(this, 120, 60, "Cancel", 70))->addActionHandler(this); 01068 (new GUI::Button(this, 210, 60, "OK", 70))->addActionHandler(this); 01069 01070 name->raise(); /* make sure keyboard focus is on the text field, ready for the user */ 01071 name->posToEnd(); /* position the cursor at the end where the user is most likely going to edit */ 01072 } 01073 01074 void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) { 01075 (void)b;//UNUSED 01076 if (arg == "OK") { 01077 Section* sec = control->GetSection("cpu"); 01078 if (sec) { 01079 std::string tmp("cycles="); 01080 tmp.append((const char*)(name->getText())); 01081 sec->HandleInputline(tmp); 01082 } 01083 } 01084 close(); 01085 if(shortcut) running=false; 01086 } 01087 }; 01088 01089 class SetVsyncrate : public GUI::ToplevelWindow { 01090 protected: 01091 GUI::Input *name; 01092 public: 01093 SetVsyncrate(GUI::Screen *parent, int x, int y, const char *title) : 01094 ToplevelWindow(parent, x, y, 400, 150, title) { 01095 new GUI::Label(this, 5, 10, "Enter vertical syncrate (Hz):"); 01096 name = new GUI::Input(this, 5, 30, 350); 01097 Section_prop * sec = static_cast<Section_prop *>(control->GetSection("vsync")); 01098 if (sec) 01099 name->setText(sec->Get_string("vsyncrate")); 01100 else 01101 name->setText(""); 01102 (new GUI::Button(this, 120, 70, "Cancel", 70))->addActionHandler(this); 01103 (new GUI::Button(this, 210, 70, "OK", 70))->addActionHandler(this); 01104 } 01105 01106 void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) { 01107 (void)b;//UNUSED 01108 Section_prop * sec = static_cast<Section_prop *>(control->GetSection("vsync")); 01109 if (arg == "OK") { 01110 if (sec) { 01111 const char* well = name->getText(); 01112 std::string s(well, 20); 01113 std::string tmp("vsyncrate="); 01114 tmp.append(s); 01115 sec->HandleInputline(tmp); 01116 delete well; 01117 } 01118 } 01119 if (sec) LOG_MSG("GUI: Current Vertical Sync Rate: %s Hz", sec->Get_string("vsyncrate")); 01120 close(); 01121 if(shortcut) running=false; 01122 } 01123 }; 01124 01125 class SetLocalSize : public GUI::ToplevelWindow { 01126 protected: 01127 GUI::Input *name; 01128 public: 01129 SetLocalSize(GUI::Screen *parent, int x, int y, const char *title) : 01130 ToplevelWindow(parent, x, y, 450, 150, title) { 01131 new GUI::Label(this, 5, 10, "Enter default local freesize (MB, min=0, max=1024):"); 01132 name = new GUI::Input(this, 5, 30, 400); 01133 extern unsigned int hdd_defsize; 01134 unsigned int human_readable = 512u * 32u * hdd_defsize / 1024u / 1024u; 01135 char buffer[6]; 01136 sprintf(buffer, "%u", human_readable); 01137 name->setText(buffer); 01138 (new GUI::Button(this, 120, 70, "Cancel", 70))->addActionHandler(this); 01139 (new GUI::Button(this, 210, 70, "OK", 70))->addActionHandler(this); 01140 } 01141 01142 void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) { 01143 (void)b;//UNUSED 01144 if (arg == "OK") { 01145 extern unsigned int hdd_defsize; 01146 int human_readable = atoi(name->getText()); 01147 if (human_readable < 0) 01148 hdd_defsize = 0u; 01149 else if (human_readable > 1024) 01150 hdd_defsize = 256000u; 01151 else 01152 hdd_defsize = (unsigned int)human_readable * 1024u * 1024u / 512u / 32u; 01153 LOG_MSG("GUI: Current default freesize for local disk: %dMB", 512u * 32u * hdd_defsize / 1024u / 1024u); 01154 } 01155 close(); 01156 if (shortcut) running = false; 01157 } 01158 }; 01159 01160 class ConfigurationWindow : public GUI::ToplevelWindow { 01161 public: 01162 GUI::Button *closeButton; 01163 ConfigurationWindow(GUI::Screen *parent, GUI::Size x, GUI::Size y, GUI::String& title) : 01164 GUI::ToplevelWindow(parent, (int)x, (int)y, 30/*initial*/, 30/*initial*/, title) { 01165 cfg_windows_active.clear(); 01166 01167 GUI::Menubar *bar = new GUI::Menubar(this, 0, 0, getWidth()/*initial*/); 01168 bar->addMenu("Configuration"); 01169 bar->addItem(0,"Save..."); 01170 bar->addItem(0,"Save Language File..."); 01171 bar->addItem(0,""); 01172 bar->addItem(0,"Close"); 01173 bar->addMenu("Settings"); 01174 bar->addMenu("Help"); 01175 if (!dos_kernel_disabled) { 01176 /* these do not work until shell help text is registerd */ 01177 bar->addItem(2,"Introduction"); 01178 bar->addItem(2,"Getting Started"); 01179 bar->addItem(2,"CD-ROM Support"); 01180 bar->addItem(2,""); 01181 } 01182 bar->addItem(2,"About"); 01183 bar->addActionHandler(this); 01184 01185 new GUI::Label(this, 10, 30, "Choose a settings group to configure:"); 01186 01187 Section *sec; 01188 int gridbtnwidth = 130; 01189 int gridbtnheight = 28; 01190 int gridbtnx = 12; 01191 int gridbtny = 50; 01192 int btnperrow = 4; 01193 int i = 0; 01194 01195 std::function< std::pair<int,int>(const int) > gridfunc = [&/*access to locals here*/](const int i){ 01196 return std::pair<int,int>(gridbtnx+(i%btnperrow)*gridbtnwidth, gridbtny+(i/btnperrow)*gridbtnheight); 01197 }; 01198 01199 while ((sec = control->GetSection(i))) { 01200 if (i != 0 && (i%15) == 0) bar->addItem(1, "|"); 01201 std::string name = sec->GetName(); 01202 name[0] = std::toupper(name[0]); 01203 const auto sz = gridfunc(i); 01204 GUI::Button *b = new GUI::Button(this, sz.first, sz.second, name, gridbtnwidth, gridbtnheight); 01205 b->addActionHandler(this); 01206 bar->addItem(1, name); 01207 i++; 01208 } 01209 01210 const auto finalgridpos = gridfunc(i - 1); 01211 int closerow_y = finalgridpos.second + 12 + gridbtnheight; 01212 01213 (closeButton = new GUI::Button(this, 240, closerow_y, "Close", 80))->addActionHandler(this); 01214 01215 resize(gridbtnx + (gridbtnwidth * btnperrow) + 12 + border_left + border_right, 01216 closerow_y + closeButton->getHeight() + 12 + border_top + border_bottom); 01217 01218 bar->resize(getWidth(),bar->getHeight()); 01219 } 01220 01221 ~ConfigurationWindow() { running = false; cfg_windows_active.clear(); } 01222 01223 virtual bool keyDown(const GUI::Key &key) { 01224 if (GUI::ToplevelWindow::keyDown(key)) return true; 01225 return false; 01226 } 01227 01228 virtual bool keyUp(const GUI::Key &key) { 01229 if (GUI::ToplevelWindow::keyUp(key)) return true; 01230 01231 if (key.special == GUI::Key::Escape) { 01232 closeButton->executeAction(); 01233 return true; 01234 } 01235 01236 return false; 01237 } 01238 01239 void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) { 01240 GUI::String sname = arg; 01241 sname.at(0) = (unsigned int)std::tolower((int)sname.at(0)); 01242 Section *sec; 01243 if (arg == "Close" || arg == "Cancel" || arg == "Close") { 01244 running = false; 01245 } else if (sname == "autoexec") { 01246 auto lookup = cfg_windows_active.find(sname); 01247 if (lookup == cfg_windows_active.end()) { 01248 Section_line *section = static_cast<Section_line *>(control->GetSection((const char *)sname)); 01249 auto *np = new AutoexecEditor(getScreen(), 50, 30, section); 01250 cfg_windows_active[sname] = np; 01251 np->cfg_sname = sname; 01252 np->raise(); 01253 } 01254 else { 01255 lookup->second->raise(); 01256 } 01257 } else if ((sec = control->GetSection((const char *)sname))) { 01258 auto lookup = cfg_windows_active.find(sname); 01259 if (lookup == cfg_windows_active.end()) { 01260 Section_prop *section = static_cast<Section_prop *>(sec); 01261 auto *np = new SectionEditor(getScreen(), 50, 30, section); 01262 cfg_windows_active[sname] = np; 01263 np->cfg_sname = sname; 01264 np->raise(); 01265 } 01266 else { 01267 lookup->second->raise(); 01268 } 01269 } else if (arg == "About") { 01270 const char *msg = PACKAGE_STRING " (C) 2002-" COPYRIGHT_END_YEAR " The DOSBox Team\nA fork of DOSBox 0.74 by TheGreatCodeholio\nBuild date: " UPDATED_STR "\n\nFor more info visit http://dosbox-x.com\nBased on DOSBox (http://dosbox.com)\n\n"; 01271 new GUI::MessageBox2(getScreen(), 100, 150, 480, "About DOSBox-X", msg); 01272 } else if (arg == "Introduction") { 01273 new GUI::MessageBox2(getScreen(), 20, 50, 540, "Introduction", MSG_Get("PROGRAM_INTRO")); 01274 } else if (arg == "Getting Started") { 01275 std::string msg = MSG_Get("PROGRAM_INTRO_MOUNT_START"); 01276 #ifdef WIN32 01277 msg += MSG_Get("PROGRAM_INTRO_MOUNT_WINDOWS"); 01278 #else 01279 msg += MSG_Get("PROGRAM_INTRO_MOUNT_OTHER"); 01280 #endif 01281 msg += MSG_Get("PROGRAM_INTRO_MOUNT_END"); 01282 01283 new GUI::MessageBox2(getScreen(), 0, 50, 680, std::string("Getting Started"), msg); 01284 } else if (arg == "CD-ROM Support") { 01285 new GUI::MessageBox2(getScreen(), 20, 50, 640, "CD-ROM Support", MSG_Get("PROGRAM_INTRO_CDROM")); 01286 } else if (arg == "Save...") { 01287 new SaveDialog(getScreen(), 90, 100, "Save Configuration..."); 01288 } else if (arg == "Save Language File...") { 01289 new SaveLangDialog(getScreen(), 90, 100, "Save Language File..."); 01290 } else { 01291 return ToplevelWindow::actionExecuted(b, arg); 01292 } 01293 } 01294 }; 01295 01296 /*********************************************************************************************************************/ 01297 /* UI control functions */ 01298 01299 static void UI_Execute(GUI::ScreenSDL *screen) { 01300 SDL_Surface *sdlscreen; 01301 SDL_Event event; 01302 GUI::String configString = GUI::String("DOSBox-X Configuration"); 01303 01304 sdlscreen = screen->getSurface(); 01305 auto *cfg_wnd = new ConfigurationWindow(screen, 30, 30, configString); 01306 cfg_wnd->raise(); 01307 01308 // event loop 01309 while (running) { 01310 while (SDL_PollEvent(&event)) { 01311 switch (event.type) { 01312 #if !defined(C_SDL2) && defined(_WIN32) && !defined(HX_DOS) 01313 case SDL_SYSWMEVENT : { 01314 switch ( event.syswm.msg->msg ) { 01315 case WM_COMMAND: 01316 # if DOSBOXMENU_TYPE == DOSBOXMENU_HMENU 01317 if (GetMenu(GetHWND())) { 01318 if (guiMenu.mainMenuWM_COMMAND((unsigned int)LOWORD(event.syswm.msg->wParam))) return; 01319 } 01320 # endif 01321 break; 01322 } 01323 } break; 01324 #endif 01325 default: 01326 break; 01327 } 01328 01329 if (!screen->event(event)) { 01330 if (event.type == SDL_QUIT) running = false; 01331 } 01332 } 01333 01334 //Selecting keyboard will create a new surface. 01335 screen->watchTime(); 01336 sdlscreen = screen->getSurface(); 01337 01338 if (background) 01339 SDL_BlitSurface(background, NULL, sdlscreen, NULL); 01340 else 01341 SDL_FillRect(sdlscreen,0,0); 01342 01343 screen->update(screen->getTime()); 01344 01345 #if defined(C_SDL2) 01346 SDL_Window* GFX_GetSDLWindow(void); 01347 SDL_UpdateWindowSurface(GFX_GetSDLWindow()); 01348 #else 01349 SDL_UpdateRect(sdlscreen, 0, 0, 0, 0); 01350 #endif 01351 01352 SDL_Delay(40); 01353 } 01354 } 01355 01356 static void UI_Select(GUI::ScreenSDL *screen, int select) { 01357 SDL_Surface *sdlscreen = NULL; 01358 Section_line *section2 = NULL; 01359 Section_prop *section = NULL; 01360 Section *sec = NULL; 01361 SDL_Event event; 01362 GUI::String configString = GUI::String("DOSBox-X Configuration"); 01363 01364 sdlscreen = screen->getSurface(); 01365 switch (select) { 01366 case 0: 01367 new GUI::MessageBox2(screen, 200, 150, 280, "", ""); 01368 running=false; 01369 break; 01370 case 1: 01371 new SaveDialog(screen, 90, 100, "Save Configuration..."); 01372 break; 01373 case 2: { 01374 sec = control->GetSection("sdl"); 01375 section=static_cast<Section_prop *>(sec); 01376 auto *p = new SectionEditor(screen,50,30,section); 01377 p->raise(); 01378 } break; 01379 case 3: 01380 sec = control->GetSection("dosbox"); 01381 section=static_cast<Section_prop *>(sec); 01382 new SectionEditor(screen,50,30,section); 01383 break; 01384 case 4: 01385 sec = control->GetSection("mixer"); 01386 section=static_cast<Section_prop *>(sec); 01387 new SectionEditor(screen,50,30,section); 01388 break; 01389 case 5: 01390 sec = control->GetSection("serial"); 01391 section=static_cast<Section_prop *>(sec); 01392 new SectionEditor(screen,50,30,section); 01393 break; 01394 case 6: 01395 sec = control->GetSection("ne2000"); 01396 section=static_cast<Section_prop *>(sec); 01397 new SectionEditor(screen,50,30,section); 01398 break; 01399 case 7: 01400 section2 = static_cast<Section_line *>(control->GetSection("autoexec")); 01401 new AutoexecEditor(screen, 50, 30, section2); 01402 break; 01403 case 8: 01404 sec = control->GetSection("glide"); 01405 section=static_cast<Section_prop *>(sec); 01406 new SectionEditor(screen,50,30,section); 01407 break; 01408 case 9: 01409 new SaveLangDialog(screen, 90, 100, "Save Language File..."); 01410 break; 01411 case 10: { 01412 auto *np = new ConfigurationWindow(screen, 30, 30, configString); 01413 np->raise(); 01414 } break; 01415 case 11: 01416 sec = control->GetSection("parallel"); 01417 section=static_cast<Section_prop *>(sec); 01418 new SectionEditor(screen,50,30,section); 01419 break; 01420 case 12: 01421 sec = control->GetSection("printer"); 01422 section=static_cast<Section_prop *>(sec); 01423 new SectionEditor(screen,50,30,section); 01424 break; 01425 case 13: 01426 sec = control->GetSection("cpu"); 01427 section=static_cast<Section_prop *>(sec); 01428 new SectionEditor(screen,50,30,section); 01429 break; 01430 case 14: 01431 sec = control->GetSection("dos"); 01432 section=static_cast<Section_prop *>(sec); 01433 new SectionEditor(screen,50,30,section); 01434 break; 01435 case 15: 01436 sec = control->GetSection("midi"); 01437 section=static_cast<Section_prop *>(sec); 01438 new SectionEditor(screen,50,30,section); 01439 break; 01440 case 16: { 01441 auto *np1 = new SetCycles(screen, 90, 100, "Set CPU Cycles..."); 01442 np1->raise(); 01443 } break; 01444 case 17: { 01445 auto *np2 = new SetVsyncrate(screen, 90, 100, "Set vertical syncrate..."); 01446 np2->raise(); 01447 } break; 01448 case 18: { 01449 auto *np3 = new SetLocalSize(screen, 90, 100, "Set Default Local Freesize..."); 01450 np3->raise(); 01451 } break; 01452 default: 01453 break; 01454 } 01455 01456 // event loop 01457 while (running) { 01458 while (SDL_PollEvent(&event)) { 01459 switch (event.type) { 01460 #if !defined(C_SDL2) && defined(_WIN32) && !defined(HX_DOS) 01461 case SDL_SYSWMEVENT : { 01462 switch ( event.syswm.msg->msg ) { 01463 case WM_COMMAND: 01464 # if DOSBOXMENU_TYPE == DOSBOXMENU_HMENU 01465 if (GetMenu(GetHWND())) { 01466 if (guiMenu.mainMenuWM_COMMAND((unsigned int)LOWORD(event.syswm.msg->wParam))) return; 01467 } 01468 # endif 01469 break; 01470 } 01471 } break; 01472 #endif 01473 default: 01474 break; 01475 } 01476 01477 if (!screen->event(event)) { 01478 if (event.type == SDL_QUIT) running = false; 01479 } 01480 } 01481 01482 if (background) 01483 SDL_BlitSurface(background, NULL, sdlscreen, NULL); 01484 else 01485 SDL_FillRect(sdlscreen,0,0); 01486 01487 screen->update(4); 01488 #if defined(C_SDL2) 01489 SDL_Window* GFX_GetSDLWindow(void); 01490 SDL_UpdateWindowSurface(GFX_GetSDLWindow()); 01491 #else 01492 SDL_UpdateRect(sdlscreen, 0, 0, 0, 0); 01493 #endif 01494 SDL_Delay(20); 01495 } 01496 } 01497 01498 void GUI_Shortcut(int select) { 01499 if(!select || running) return; 01500 01501 bool GFX_GetPreventFullscreen(void); 01502 01503 /* Sorry, the UI screws up 3Dfx OpenGL emulation. 01504 * Remove this block when fixed. */ 01505 if (GFX_GetPreventFullscreen()) { 01506 LOG_MSG("GUI is not available while 3Dfx OpenGL emulation is running"); 01507 return; 01508 } 01509 01510 shortcut=true; 01511 GUI::ScreenSDL *screen = UI_Startup(NULL); 01512 UI_Select(screen,select); 01513 UI_Shutdown(screen); 01514 shortcut=false; 01515 delete screen; 01516 } 01517 01518 void GUI_Run(bool pressed) { 01519 if (pressed || running) return; 01520 01521 bool GFX_GetPreventFullscreen(void); 01522 01523 /* Sorry, the UI screws up 3Dfx OpenGL emulation. 01524 * Remove this block when fixed. */ 01525 if (GFX_GetPreventFullscreen()) { 01526 LOG_MSG("GUI is not available while 3Dfx OpenGL emulation is running"); 01527 return; 01528 } 01529 01530 GUI::ScreenSDL *screen = UI_Startup(NULL); 01531 UI_Execute(screen); 01532 UI_Shutdown(screen); 01533 delete screen; 01534 }