mirror of
https://github.com/joncampbell123/dosbox-x.git
synced 2025-05-09 11:51:09 +08:00
4866 lines
184 KiB
C++
4866 lines
184 KiB
C++
/*
|
|
* Copyright (C) 2002-2021 The DOSBox Team
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#if defined(_MSC_VER)
|
|
#pragma warning(disable:4065) /* Please do not warn on default case without other case statements */
|
|
#endif
|
|
|
|
#include "SDL.h"
|
|
|
|
#include "dosbox.h"
|
|
#include "menu.h"
|
|
#include "../libs/gui_tk/gui_tk.h"
|
|
|
|
#include "build_timestamp.h"
|
|
#include "keyboard.h"
|
|
#include "video.h"
|
|
#include "render.h"
|
|
#include "mapper.h"
|
|
#include "setup.h"
|
|
#include "control.h"
|
|
#include "paging.h"
|
|
#include "shell.h"
|
|
#include "cpu.h"
|
|
#include "pic.h"
|
|
#include "midi.h"
|
|
#include "bios_disk.h"
|
|
#include "../dos/drives.h"
|
|
|
|
#if C_OPENGL
|
|
#include "voodoo.h"
|
|
#include "../hardware/voodoo_types.h"
|
|
#include "../hardware/voodoo_data.h"
|
|
#include "../hardware/voodoo_opengl.h"
|
|
#endif
|
|
|
|
#if defined(WIN32)
|
|
#include "shellapi.h"
|
|
#endif
|
|
|
|
#include <iostream>
|
|
#include <sstream>
|
|
#include <stdexcept>
|
|
#include <algorithm>
|
|
#include <cctype>
|
|
#include <functional>
|
|
#include <assert.h>
|
|
#include <sys/stat.h>
|
|
|
|
#include "SDL_syswm.h"
|
|
#include "sdlmain.h"
|
|
#include "version_string.h"
|
|
|
|
#if !defined(HX_DOS)
|
|
#include "../libs/tinyfiledialogs/tinyfiledialogs.h"
|
|
#endif
|
|
|
|
#include <unordered_map>
|
|
#include <output/output_ttf.h>
|
|
|
|
#ifdef DOSBOXMENU_EXTERNALLY_MANAGED
|
|
static DOSBoxMenu guiMenu, nullMenu;
|
|
#endif
|
|
|
|
/* helper class for command execution */
|
|
class VirtualBatch : public BatchFile {
|
|
public:
|
|
VirtualBatch(DOS_Shell *host, const std::string& cmds);
|
|
bool ReadLine(char *line) override;
|
|
protected:
|
|
std::istringstream lines;
|
|
};
|
|
|
|
extern uint8_t int10_font_14[256 * 14], int10_font_14_init[256 * 14];
|
|
|
|
extern uint32_t GFX_Rmask;
|
|
extern unsigned char GFX_Rshift;
|
|
extern uint32_t GFX_Gmask;
|
|
extern unsigned char GFX_Gshift;
|
|
extern uint32_t GFX_Bmask;
|
|
extern unsigned char GFX_Bshift;
|
|
|
|
extern unsigned int maincp;
|
|
extern int aspect_ratio_x, aspect_ratio_y;
|
|
extern int statusdrive, swapInDisksSpecificDrive;
|
|
extern bool ttfswitch, switch_output_from_ttf, loadlang;
|
|
extern bool dos_kernel_disabled, swapad, confres, font_14_init;
|
|
extern Bitu currentWindowWidth, currentWindowHeight;
|
|
extern std::string strPasteBuffer, langname;
|
|
|
|
extern void resetFontSize(void);
|
|
extern void MAPPER_ReleaseAllKeys(void);
|
|
extern void PasteClipboard(bool bPressed);
|
|
extern bool MSG_Write(const char *, const char *);
|
|
extern void LoadMessageFile(const char * fname);
|
|
extern void GFX_SetTitle(int32_t cycles, int frameskip, Bits timing, bool paused);
|
|
|
|
static int cursor;
|
|
static bool running;
|
|
static int saved_bpp;
|
|
static bool shell_idle;
|
|
static bool in_gui = false;
|
|
static bool resetcfg = false;
|
|
#if !defined(C_SDL2)
|
|
static int old_unicode;
|
|
#endif
|
|
static bool mousetoggle;
|
|
static bool shortcut=false;
|
|
static SDL_Surface* screenshot = NULL;
|
|
static SDL_Surface* background = NULL;
|
|
#ifdef DOSBOXMENU_EXTERNALLY_MANAGED
|
|
static bool gui_menu_init = true, null_menu_init = true;
|
|
#endif
|
|
int shortcutid = -1;
|
|
bool GFX_GetPreventFullscreen(void);
|
|
void GFX_GetSizeAndPos(int &x,int &y,int &width, int &height, bool &fullscreen);
|
|
|
|
#if defined(WIN32) && !defined(HX_DOS)
|
|
void DOSBox_SetSysMenu(void);
|
|
void WindowsTaskbarUpdatePreviewRegion(void);
|
|
void WindowsTaskbarResetPreviewRegion(void);
|
|
#endif
|
|
|
|
#if defined(MACOSX)
|
|
void macosx_reload_touchbar(void);
|
|
#endif
|
|
|
|
std::list<std::string> proplist = {};
|
|
GUI::Checkbox *advopt, *saveall, *imgfd360, *imgfd400, *imgfd720, *imgfd1200, *imgfd1440, *imgfd2880, *imghd250, *imghd520, *imghd1gig, *imghd2gig, *imghd4gig, *imghd8gig;
|
|
|
|
// user pick of 'show advanced options' for the session
|
|
bool advOptUser = false;
|
|
|
|
std::string GetDOSBoxXPath(bool withexe);
|
|
static std::map< std::vector<GUI::Char>, GUI::ToplevelWindow* > cfg_windows_active;
|
|
void getlogtext(std::string &str), getcodetext(std::string &text), ApplySetting(std::string pvar, std::string inputline, bool quiet), GUI_Run(bool pressed);
|
|
void ttf_switch_on(bool ss=true), ttf_switch_off(bool ss=true), setAspectRatio(Section_prop * section), GFX_ForceRedrawScreen(void), SetWindowTransparency(int trans);
|
|
bool CheckQuit(void), OpenGL_using(void);
|
|
char tmp1[CROSS_LEN*2], tmp2[CROSS_LEN];
|
|
const char *aboutmsg = "DOSBox-X ver." VERSION " (" OS_PLATFORM " " SDL_STRING " " OS_BIT "-bit)\n" \
|
|
"Build date/time: " UPDATED_STR "\nCopyright 2011-" COPYRIGHT_END_YEAR \
|
|
" The DOSBox-X Team\nProject maintainer: joncampbell123\nDOSBox-X homepage: https://dosbox-x.com";
|
|
|
|
void RebootConfig(std::string filename, bool confirm=false) {
|
|
std::string exepath=GetDOSBoxXPath(true), para="-conf \""+filename+"\"";
|
|
if ((!confirm||CheckQuit())&&exepath.size()) {
|
|
#if defined(WIN32)
|
|
ShellExecute(NULL, "open", exepath.c_str(), para.c_str(), NULL, SW_NORMAL);
|
|
#else
|
|
system((exepath+" "+para+ " &").c_str());
|
|
#endif
|
|
throw(0);
|
|
}
|
|
}
|
|
|
|
void RebootLanguage(std::string filename, bool confirm=false) {
|
|
std::string exepath=GetDOSBoxXPath(true), tmpconfig = "~dbxtemp.conf", para=(filename.size()?"-langcp \""+filename+"\"":"");
|
|
#if defined(USE_TTF)
|
|
para+=ttfswitch||switch_output_from_ttf?" -set output=ttf":"";
|
|
#endif
|
|
struct stat st;
|
|
if ((!confirm||CheckQuit())&&exepath.size()) {
|
|
if (!stat(tmpconfig.c_str(), &st)) remove(tmpconfig.c_str());
|
|
if (control->PrintConfig(tmpconfig.c_str(),false,true)&&!stat(tmpconfig.c_str(), &st)) para="-conf "+tmpconfig+" -eraseconf "+para;
|
|
#if defined(WIN32)
|
|
ShellExecute(NULL, "open", exepath.c_str(), para.c_str(), NULL, SW_NORMAL);
|
|
#else
|
|
system((exepath+" "+para+ " &").c_str());
|
|
#endif
|
|
throw(0);
|
|
}
|
|
}
|
|
|
|
/* Prepare screen for UI */
|
|
void GUI_LoadFonts(void) {
|
|
GUI::Font::addFont("default",new GUI::BitmapFont(font_14_init&&dos.loaded_codepage&&dos.loaded_codepage!=437?int10_font_14_init:int10_font_14,14,10));
|
|
}
|
|
|
|
static void getPixel(Bits x, Bits y, int &r, int &g, int &b, int shift)
|
|
{
|
|
if (x >= (Bits)render.src.width) x = (Bits)render.src.width-1;
|
|
if (y >= (Bits)render.src.height) x = (Bits)render.src.height-1;
|
|
if (x < 0) x = 0;
|
|
if (y < 0) y = 0;
|
|
|
|
uint8_t* src = (uint8_t *)&scalerSourceCache;
|
|
uint32_t pixel;
|
|
switch (render.scale.inMode) {
|
|
case scalerMode8:
|
|
pixel = *((unsigned int)x+(uint8_t*)(src+(unsigned int)y*(unsigned int)render.scale.cachePitch));
|
|
r += (int)((unsigned int)render.pal.rgb[pixel].red >> (unsigned int)shift);
|
|
g += (int)((unsigned int)render.pal.rgb[pixel].green >> (unsigned int)shift);
|
|
b += (int)((unsigned int)render.pal.rgb[pixel].blue >> (unsigned int)shift);
|
|
break;
|
|
case scalerMode15:
|
|
pixel = *((unsigned int)x+(uint16_t*)(src+(unsigned int)y*(unsigned int)render.scale.cachePitch));
|
|
r += (int)((pixel >> (7u+(unsigned int)shift)) & (0xf8u >> (unsigned int)shift));
|
|
g += (int)((pixel >> (2u+(unsigned int)shift)) & (0xf8u >> (unsigned int)shift));
|
|
b += (int)((pixel << (3u-(unsigned int)shift)) & (0xf8u >> (unsigned int)shift));
|
|
break;
|
|
case scalerMode16:
|
|
pixel = *((unsigned int)x+(uint16_t*)(src+(unsigned int)y*(unsigned int)render.scale.cachePitch));
|
|
r += (int)((pixel >> (8u+(unsigned int)shift)) & (0xf8u >> shift));
|
|
g += (int)((pixel >> (3u+(unsigned int)shift)) & (0xfcu >> shift));
|
|
b += (int)((pixel << (3u-(unsigned int)shift)) & (0xf8u >> shift));
|
|
break;
|
|
case scalerMode32:
|
|
pixel = *((unsigned int)x+(uint32_t*)(src+(unsigned int)y*(unsigned int)render.scale.cachePitch));
|
|
r += (int)(((pixel & GFX_Rmask) >> (GFX_Rshift + shift)) & (0xffu >> shift));
|
|
g += (int)(((pixel & GFX_Gmask) >> (GFX_Gshift + shift)) & (0xffu >> shift));
|
|
b += (int)(((pixel & GFX_Bmask) >> (GFX_Bshift + shift)) & (0xffu >> shift));
|
|
break;
|
|
}
|
|
}
|
|
|
|
bool gui_menu_exit(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) {
|
|
(void)menu;//UNUSED
|
|
(void)menuitem;//UNUSED
|
|
running = false;
|
|
return true;
|
|
}
|
|
|
|
extern uint8_t int10_font_08[256 * 8];
|
|
extern uint8_t int10_font_14[256 * 14];
|
|
extern uint8_t int10_font_16[256 * 16];
|
|
|
|
/* Windows-Like GUI toolkit (to better emulate the look and feel of Windows 3.1) */
|
|
namespace WLGUI {
|
|
|
|
typedef size_t Handle;
|
|
typedef size_t HandleIndex;
|
|
typedef uint32_t DevicePixel;/*pixel value, in target device format i.e. 16bpp rrrrrggggggbbbbb*/
|
|
|
|
static constexpr uint32_t Mask24 = uint32_t(0xFFFFFFu);
|
|
static constexpr Handle InvalidHandleValue = ~Handle(0u);
|
|
static constexpr HandleIndex InvalidHandleIndex = ~HandleIndex(0u);
|
|
|
|
enum class HandleType {
|
|
NoType=0, /* FIXME: Why can't I use "None", GCC? Are you reserving identifiers for future Python support or something? */
|
|
DC=1,
|
|
FontHandle=2
|
|
};
|
|
|
|
struct DevicePixelDescription {
|
|
struct mask {
|
|
DevicePixel r,g,b,a;
|
|
} mask;
|
|
struct shift {
|
|
uint8_t r,g,b,a;
|
|
} shift;
|
|
struct width {
|
|
uint8_t r,g,b,a;
|
|
} width;
|
|
|
|
uint8_t BitsPerPixel;
|
|
uint8_t BytesPerPixel; /* 0 if less than 8, use BitsPerPixel */
|
|
|
|
DevicePixel Make8(const unsigned int rv,const unsigned int gv,const unsigned int bv,const unsigned int av=0xFF) const;
|
|
};
|
|
|
|
struct Dimensions {
|
|
unsigned int w,h;
|
|
|
|
Dimensions() { }
|
|
Dimensions(const unsigned int _w,const unsigned int _h) : w(_w), h(_h) { }
|
|
};
|
|
|
|
struct Point {
|
|
long x,y;
|
|
|
|
Point() { }
|
|
Point(const long _x,const long _y) : x(_x), y(_y) { }
|
|
};
|
|
|
|
class ResourceList {
|
|
public:
|
|
HandleIndex ListAlloc = 0;
|
|
std::vector<void*> List;
|
|
void *GetVoid(const HandleIndex i);
|
|
void SetVoid(const HandleIndex i,void *p);
|
|
size_t Size(void) const;
|
|
HandleIndex AllocateHandleIndex(void);
|
|
};
|
|
|
|
template <class T> class TypedResourceList : public ResourceList {
|
|
public:
|
|
T *Get(const HandleIndex i) {
|
|
return (T*)GetVoid(i);
|
|
}
|
|
void Set(const HandleIndex i,T *p) {
|
|
SetVoid(i,(void*)p);
|
|
}
|
|
};
|
|
|
|
struct ReferenceCountTracking {
|
|
int refcount = 0;
|
|
int AddRef(void);
|
|
int Release(void); /* which does NOT delete the object when refcount == 0 */
|
|
};
|
|
|
|
static Handle MakeHandle(const HandleType ht,const HandleIndex idx);
|
|
static HandleIndex GetHandleIndex(const HandleType ht,const Handle h);
|
|
static unsigned int MaskToWidth(DevicePixel m);
|
|
static unsigned int Pixel8ToWidth(const unsigned int v,const unsigned int width);
|
|
static const DevicePixelDescription ColorDescription_DefaultRGB32(const bool withAlpha);
|
|
|
|
namespace FontHandle {
|
|
|
|
enum class ObjType {
|
|
Base=0, /* you shouldn't use this */
|
|
VGAFont=1
|
|
};
|
|
|
|
struct Obj;
|
|
TypedResourceList<Obj> List;
|
|
|
|
struct Bitmap {
|
|
uint8_t bpp = 1; /* 1bpp (mono) or 8bpp (grayscale) */
|
|
uint16_t pitch = 0,height = 0;
|
|
const unsigned char* base = NULL;
|
|
uint16_t sx = 0,sy = 0; /* source pixels to draw */
|
|
uint16_t dw = 0,dh = 0; /* dimensions of pixels to draw */
|
|
int16_t dx = 0,dy = 0; /* dest pixels offset from origin to draw */
|
|
int16_t advancex256 = 0; /* advance x in 1/256th of a pixel */
|
|
uint16_t cw = 0; /* calculation width, for centering and such */
|
|
};
|
|
|
|
struct Obj {
|
|
struct Flags {
|
|
static constexpr uint32_t Antialiased = uint32_t(1u) << uint32_t(0u); /* make anti-aliased TrueType where possible */
|
|
static constexpr uint32_t TrueType = uint32_t(1u) << uint32_t(1u); /* font is TrueType */
|
|
static constexpr uint32_t FixedPitch = uint32_t(1u) << uint32_t(2u); /* font is fixed pitch */
|
|
uint32_t v = 0;
|
|
};
|
|
|
|
Flags Flags;
|
|
ObjType type; /* init by constructor */
|
|
int16_t totalHeight = 0; /* font cell (top to bottom) */
|
|
int16_t ascentY = 0; /* height from baseline upward */
|
|
int16_t internalLeading = 0;
|
|
int16_t externalLeading = 0;
|
|
|
|
Obj();
|
|
Obj(const ObjType t);
|
|
virtual ~Obj();
|
|
|
|
virtual signed int GlyphLookup(int32_t uc);
|
|
|
|
static constexpr unsigned int GCF_BITMAP = 1u << 0u;
|
|
virtual bool GetChar(unsigned int glyph,Bitmap &bmp,unsigned int flags=0);
|
|
};
|
|
|
|
/* VGA font */
|
|
struct ObjVGAFont : public Obj {
|
|
const unsigned char* font = (const unsigned char*)NULL;
|
|
uint16_t fontheight = 0;
|
|
|
|
ObjVGAFont(const unsigned int height);
|
|
virtual ~ObjVGAFont();
|
|
|
|
/* TODO: Callback function to convert unicode -> CP437 */
|
|
virtual signed int GlyphLookup(int32_t uc) override;
|
|
virtual bool GetChar(unsigned int glyph,Bitmap &bmp,unsigned int flags) override;
|
|
};
|
|
|
|
}
|
|
|
|
namespace DC {
|
|
|
|
enum class ObjType {
|
|
Base=0, /* you shouldn't use this */
|
|
SDLSurface=1
|
|
};
|
|
|
|
struct Obj;
|
|
TypedResourceList<Obj> List;
|
|
|
|
/* A bit of polymorphism because like a real Windows DC it can be a display, a printer, etc.
|
|
* In this toolkit, it can be a SDL surface, OpenGL texture, etc. Unlike Windows there's
|
|
* no need to worry about partial redraw because this toolkit takes the DWM approach where
|
|
* every window is a surface, texture, etc.
|
|
*
|
|
* In most cases you should GetDC and ReleaseDC to draw on your window just like real Windows.
|
|
* Don't keep the DC open except to draw. */
|
|
struct Obj {
|
|
struct Flags {
|
|
uint32_t v = 0;
|
|
};
|
|
|
|
ObjType type; /* init by constructor */
|
|
Dimensions viewport = {0,0}; /* the viewport in device pixels i.e. SDL surface pixels */
|
|
Point originSrc = {0,0}; /* coordinate system origin */
|
|
Point originDst = {0,0}; /* coordinate system origin */
|
|
DevicePixel BackgroundColor = 0;
|
|
DevicePixel ForegroundColor = 0;
|
|
DevicePixelDescription ColorDescription; /* init by constructor if base, otherwise UNINITIALIZED */
|
|
ReferenceCountTracking ref;
|
|
Handle CurrentFont = InvalidHandleValue;
|
|
Flags Flags;
|
|
|
|
DevicePixel (*GetPixel)(Obj &obj,long x,long y) = &GetPixel_stub;
|
|
void (*SetPixel)(Obj &obj,long x,long y,const DevicePixel c) = &SetPixel_stub;
|
|
|
|
Obj();
|
|
Obj(const ObjType t);
|
|
virtual ~Obj();
|
|
virtual DevicePixel MakeRGB8(const unsigned int r,const unsigned int g,const unsigned int b,const unsigned int a=0xFF);
|
|
virtual DevicePixel SetBackgroundColor(const DevicePixel c);
|
|
virtual DevicePixel SetForegroundColor(const DevicePixel c);
|
|
virtual bool SetLogicalOrigin(const long x=0,const long y=0,Point *po=NULL);
|
|
virtual bool SetDeviceOrigin(const long x=0,const long y=0,Point *po=NULL);
|
|
virtual void ConvertLogicalToDeviceCoordinates(long &x,long &y);
|
|
virtual Handle SelectFont(Handle newValue);
|
|
virtual bool TextOut(long x,long y,const char *str/*TODO UTF-8*/);
|
|
virtual bool DrawTextChar1bpp(long x,long y,FontHandle::Bitmap &bmp);
|
|
virtual bool DrawTextChar(long x,long y,FontHandle::Bitmap &bmp);
|
|
|
|
static DevicePixel GetPixel_stub(Obj &obj,long x,long y);
|
|
static void SetPixel_stub(Obj &obj,long x,long y,const DevicePixel c);
|
|
};
|
|
|
|
/* SDL surface DC */
|
|
struct ObjSDLSurface : public Obj {
|
|
SDL_Surface* surface = NULL;
|
|
Point viewport_origin = {0,0}; /* in case we do subregions of a surface as "window objects" */
|
|
|
|
ObjSDLSurface(SDL_Surface *surf);
|
|
virtual ~ObjSDLSurface();
|
|
|
|
virtual void ConvertLogicalToDeviceCoordinates(long &x,long &y) override;
|
|
|
|
void initFromSurface(void);
|
|
void *GetSurfaceRowPtr(long x,long y);
|
|
|
|
static void SetPixel_32bpp(Obj &bobj,long x,long y,const DevicePixel c);
|
|
static void SetPixel_24bpp(Obj &bobj,long x,long y,const DevicePixel c);
|
|
static void SetPixel_16bpp(Obj &bobj,long x,long y,const DevicePixel c);
|
|
static void SetPixel_8bpp(Obj &bobj,long x,long y,const DevicePixel c);
|
|
|
|
static DevicePixel GetPixel_32bpp(Obj &bobj,long x,long y);
|
|
static DevicePixel GetPixel_24bpp(Obj &bobj,long x,long y);
|
|
static DevicePixel GetPixel_16bpp(Obj &bobj,long x,long y);
|
|
static DevicePixel GetPixel_8bpp(Obj &bobj,long x,long y);
|
|
};
|
|
|
|
Handle CreateSDLSurfaceDC(SDL_Surface *surf);
|
|
Obj* GetObject(const Handle h);
|
|
DevicePixel MakeRGB8(const Handle h,const unsigned int r,const unsigned int g,const unsigned int b,const unsigned int a=0xFF);
|
|
void SetPixel(const Handle h,const long x,const long y,const DevicePixel c);
|
|
bool GetDevicePixelFormat(const Handle h,DevicePixelDescription &d);
|
|
DevicePixel SetBackgroundColor(const Handle h,const DevicePixel c);
|
|
DevicePixel SetForegroundColor(const Handle h,const DevicePixel c);
|
|
bool SetLogicalOrigin(const Handle h,const long x=0,const long y=0,Point *po=NULL);
|
|
bool SetDeviceOrigin(const Handle h,const long x=0,const long y=0,Point *po=NULL);
|
|
bool Delete(const Handle h);
|
|
Handle SelectFont(const Handle DC,const Handle newValue);
|
|
bool TextOut(const Handle h,long x,long y,const char *str/*TODO UTF-8*/);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
namespace WLGUI {
|
|
|
|
static Handle MakeHandle(const HandleType ht,const HandleIndex idx) {
|
|
return ((Handle)ht << (Handle)24u) + Handle(idx & 0xFFFFFFu);
|
|
}
|
|
|
|
static HandleType GetHandleType(const Handle h) {
|
|
return HandleType(h >> (Handle)24u);
|
|
}
|
|
|
|
static HandleIndex GetHandleIndex(const HandleType ht,const Handle h) {
|
|
if (ht == HandleType(h >> (Handle)24u))
|
|
return HandleIndex(h & 0xFFFFFFu);
|
|
else
|
|
return InvalidHandleIndex;
|
|
}
|
|
|
|
static unsigned int MaskToWidth(DevicePixel m) {
|
|
if (m != DevicePixel(0)) {
|
|
unsigned int count = 0;
|
|
while ((m & DevicePixel(1)) == DevicePixel(0)) m >>= DevicePixel(1);
|
|
while (m) { m >>= DevicePixel(1); count++; }
|
|
return count;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static unsigned int Pixel8ToWidth(const unsigned int v,const unsigned int width) {
|
|
if (width != 0) {
|
|
const unsigned int mv = (1u << width) - 1u;
|
|
return ((v * mv) + 128u) / 255u;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
DevicePixel DevicePixelDescription::Make8(const unsigned int rv,const unsigned int gv,const unsigned int bv,const unsigned int av) const {
|
|
return (DevicePixel(Pixel8ToWidth(rv,width.r)) << DevicePixel(shift.r)) +
|
|
(DevicePixel(Pixel8ToWidth(gv,width.g)) << DevicePixel(shift.g)) +
|
|
(DevicePixel(Pixel8ToWidth(bv,width.b)) << DevicePixel(shift.b)) +
|
|
(DevicePixel(Pixel8ToWidth(av,width.a)) << DevicePixel(shift.a));
|
|
}
|
|
|
|
static const DevicePixelDescription ColorDescription_DefaultRGB32(const bool withAlpha) {
|
|
DevicePixelDescription r;
|
|
|
|
r.BitsPerPixel = 32;
|
|
r.BytesPerPixel = 4;
|
|
|
|
r.mask.a = withAlpha ? (0xFFu << 24u) : 0u;
|
|
r.shift.a = withAlpha ? 24u : 0u;
|
|
r.width.a = withAlpha ? 8u : 0u;
|
|
|
|
r.mask.r = 0xFFu << 16u;
|
|
r.shift.r = 16u;
|
|
r.width.r = 8u;
|
|
|
|
r.mask.g = 0xFFu << 8u;
|
|
r.shift.g = 8u;
|
|
r.width.g = 8u;
|
|
|
|
r.mask.b = 0xFFu << 0u;
|
|
r.shift.b = 0u;
|
|
r.width.b = 8u;
|
|
|
|
return r;
|
|
}
|
|
|
|
void *ResourceList::GetVoid(const HandleIndex i) {
|
|
if (i < HandleIndex(List.size())) return List[i];
|
|
return NULL;
|
|
}
|
|
|
|
void ResourceList::SetVoid(const HandleIndex i,void *p) {
|
|
if (i < HandleIndex(List.size())) {
|
|
List[i] = p;
|
|
if (p == NULL) ListAlloc = i;
|
|
}
|
|
}
|
|
|
|
size_t ResourceList::Size(void) const {
|
|
return List.size();
|
|
}
|
|
|
|
int ReferenceCountTracking::AddRef(void) {
|
|
return ++refcount;
|
|
}
|
|
|
|
int ReferenceCountTracking::Release(void) {
|
|
return --refcount;
|
|
}
|
|
|
|
HandleIndex ResourceList::AllocateHandleIndex(void) {
|
|
/* scan forward from ListAlloc */
|
|
const HandleIndex pListAlloc = ListAlloc;
|
|
while (ListAlloc < List.size()) {
|
|
const HandleIndex index = ListAlloc++;
|
|
if (List[index] == NULL) return index;
|
|
}
|
|
|
|
ListAlloc = 0; /* No opening, scan again but only up to where the first loop started scanning */
|
|
while (ListAlloc < List.size() && ListAlloc <= pListAlloc) {
|
|
const HandleIndex index = ListAlloc++;
|
|
if (List[index] == NULL) return index;
|
|
}
|
|
|
|
/* Well then, enlarge the list */
|
|
{
|
|
const size_t osz = List.size();
|
|
if (osz >= 1024u) return InvalidHandleIndex; /* but not too much! */
|
|
ListAlloc = HandleIndex(osz); /* neither of the first two found anything, scan from where we extend the list */
|
|
List.resize(osz + (osz / 4u) + 64u);
|
|
for (size_t i=osz;i < List.size();i++) List[i] = NULL;
|
|
}
|
|
|
|
/* one more time */
|
|
while (ListAlloc < List.size()) {
|
|
const HandleIndex index = ListAlloc++;
|
|
if (List[index] == NULL) return index;
|
|
}
|
|
|
|
return InvalidHandleIndex;
|
|
}
|
|
|
|
namespace FontHandle {
|
|
|
|
Obj::Obj() : type(ObjType::Base) {
|
|
}
|
|
|
|
Obj::Obj(const ObjType t) : type(t) {
|
|
}
|
|
|
|
Obj::~Obj() {
|
|
}
|
|
|
|
signed int Obj::GlyphLookup(int32_t uc) {
|
|
(void)uc;
|
|
return -1;
|
|
}
|
|
|
|
bool Obj::GetChar(unsigned int glyph,Bitmap &bmp,unsigned int flags) {
|
|
(void)glyph;
|
|
(void)bmp;
|
|
(void)flags;
|
|
return false;
|
|
}
|
|
|
|
/////////////////
|
|
|
|
ObjVGAFont::ObjVGAFont(const unsigned int height) : Obj(ObjType::VGAFont) {
|
|
Flags.v |= Flags::FixedPitch;
|
|
if (height >= 16) {
|
|
font = int10_font_16;
|
|
fontheight = 16;
|
|
}
|
|
else if (height >= 14) {
|
|
font = int10_font_14;
|
|
fontheight = 14;
|
|
}
|
|
else {
|
|
font = int10_font_08;
|
|
fontheight = 8;
|
|
}
|
|
}
|
|
|
|
ObjVGAFont::~ObjVGAFont() {
|
|
}
|
|
|
|
signed int ObjVGAFont::GlyphLookup(int32_t uc) {
|
|
/* TODO: Map unicode to CP437 since that is what the stock VGA font uses */
|
|
if (uc >= 0 && uc <= 255)
|
|
return (int)uc;
|
|
|
|
return -1;
|
|
}
|
|
|
|
bool ObjVGAFont::GetChar(unsigned int glyph,Bitmap &bmp,unsigned int flags) {
|
|
if (glyph < 256) {
|
|
bmp = Bitmap();
|
|
bmp.bpp = 1;
|
|
bmp.pitch = 1;
|
|
bmp.height = fontheight;
|
|
bmp.base = font + (glyph * fontheight);
|
|
bmp.sx = 0;
|
|
bmp.sy = 0;
|
|
bmp.dw = 8;
|
|
bmp.dh = fontheight;
|
|
bmp.dx = 0;
|
|
bmp.dy = 0;
|
|
bmp.advancex256 = 8u << 8u;
|
|
bmp.cw = 8;
|
|
(void)flags;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//////////////////
|
|
|
|
Handle CreateVGAFont(const unsigned int height) {
|
|
const size_t idx = List.AllocateHandleIndex();
|
|
if (idx != InvalidHandleIndex) {
|
|
List.Set(idx,(Obj*)(new ObjVGAFont(height)));
|
|
return MakeHandle(HandleType::FontHandle,HandleIndex(idx));
|
|
}
|
|
|
|
return InvalidHandleValue;
|
|
}
|
|
|
|
bool Destroy(Handle h) {
|
|
const HandleIndex idx = GetHandleIndex(HandleType::FontHandle,h);
|
|
if (idx != InvalidHandleIndex && idx < List.Size()) {
|
|
Obj *obj = List.Get(idx);
|
|
if (obj != NULL) {
|
|
List.Set(idx,NULL);
|
|
delete obj;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
namespace DC {
|
|
|
|
Obj::Obj() : type(ObjType::Base) {
|
|
ColorDescription_DefaultRGB32(false);
|
|
}
|
|
|
|
Obj::Obj(const ObjType t) : type(t) {
|
|
}
|
|
|
|
Obj::~Obj() {
|
|
if (ref.refcount != 0) LOG_MSG("Object release when refcount != 0 (this=%p)",(void*)this);
|
|
}
|
|
|
|
DevicePixel Obj::MakeRGB8(const unsigned int r,const unsigned int g,const unsigned int b,const unsigned int a) {
|
|
/* you must override this if your colorspace is not RGB (but this toolkit will be used where RGB is always used) */
|
|
return ColorDescription.Make8(r,g,b,a);
|
|
}
|
|
|
|
DevicePixel Obj::SetBackgroundColor(const DevicePixel c) {
|
|
const DevicePixel prev = BackgroundColor;
|
|
BackgroundColor = c;
|
|
return prev;
|
|
}
|
|
|
|
DevicePixel Obj::SetForegroundColor(const DevicePixel c) {
|
|
const DevicePixel prev = ForegroundColor;
|
|
ForegroundColor = c;
|
|
return prev;
|
|
}
|
|
|
|
bool Obj::SetLogicalOrigin(const long x,const long y,Point *po) {
|
|
if (po) *po = originSrc;
|
|
originSrc = Point(x,y);
|
|
return true;
|
|
}
|
|
|
|
bool Obj::SetDeviceOrigin(const long x,const long y,Point *po) {
|
|
if (po) *po = originDst;
|
|
originDst = Point(x,y);
|
|
return true;
|
|
}
|
|
|
|
void Obj::ConvertLogicalToDeviceCoordinates(long &x,long &y) {
|
|
x += originSrc.x;
|
|
y += originSrc.y;
|
|
x += originDst.x;
|
|
y += originDst.y;
|
|
}
|
|
|
|
Handle Obj::SelectFont(Handle newValue) {
|
|
if (GetHandleType(newValue) == HandleType::FontHandle) {
|
|
Handle pv = CurrentFont;
|
|
CurrentFont = newValue;
|
|
return pv;
|
|
}
|
|
else if (newValue == InvalidHandleValue) {
|
|
CurrentFont = newValue;
|
|
}
|
|
|
|
return InvalidHandleValue;
|
|
}
|
|
|
|
bool Obj::DrawTextChar1bpp(long x,long y,FontHandle::Bitmap &bmp) {
|
|
long dx = x + bmp.dx;
|
|
for (unsigned int subx=0;subx < bmp.dw;subx++) {
|
|
const unsigned int bsx = bmp.sx + subx;
|
|
unsigned char msk = 0x80 >> (bsx & 7u);
|
|
const unsigned char *s =
|
|
bmp.base +
|
|
(bmp.sy * bmp.pitch) +
|
|
(bsx >> 3u);
|
|
|
|
long dy = y + bmp.dy;
|
|
for (unsigned int suby=0;suby < bmp.dh;suby++) {
|
|
if (*s & msk) SetPixel(*this,dx,dy,ForegroundColor);
|
|
s += bmp.pitch;
|
|
dy++;
|
|
}
|
|
|
|
dx++;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Obj::DrawTextChar(long x,long y,FontHandle::Bitmap &bmp) {
|
|
if (bmp.base != NULL) {
|
|
if (bmp.bpp == 1)
|
|
return DrawTextChar1bpp(x,y,bmp);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool Obj::TextOut(long x,long y,const char *str) {
|
|
FontHandle::Obj *fh = FontHandle::List.Get(GetHandleIndex(HandleType::FontHandle,CurrentFont));
|
|
|
|
if (fh) {
|
|
long fx = x << 8l;
|
|
int32_t c;
|
|
|
|
while ((c=(unsigned char)(*str++)/*TODO: Read UTF-8 char*/) != 0) {
|
|
int glyph = fh->GlyphLookup(c);
|
|
if (glyph >= 0) {
|
|
FontHandle::Bitmap bmp;
|
|
if (fh->GetChar((unsigned int)glyph,bmp)) {
|
|
DrawTextChar(fx >> 8l,y,bmp);
|
|
fx += bmp.advancex256;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
DevicePixel Obj::GetPixel_stub(Obj &obj,long x,long y) {
|
|
(void)obj;
|
|
(void)x;
|
|
(void)y;
|
|
return DevicePixel(0);
|
|
}
|
|
|
|
void Obj::SetPixel_stub(Obj &obj,long x,long y,const DevicePixel c) {
|
|
(void)obj;
|
|
(void)x;
|
|
(void)y;
|
|
(void)c;
|
|
}
|
|
|
|
///////////////////////////
|
|
|
|
ObjSDLSurface::ObjSDLSurface(SDL_Surface *surf) : Obj(ObjType::SDLSurface), surface(surf) {
|
|
initFromSurface();
|
|
}
|
|
|
|
ObjSDLSurface::~ObjSDLSurface() {
|
|
}
|
|
|
|
void ObjSDLSurface::initFromSurface(void) {
|
|
viewport.w = abs(surface->w);
|
|
viewport.h = abs(surface->h);
|
|
ColorDescription.BitsPerPixel = surface->format->BitsPerPixel;
|
|
ColorDescription.BytesPerPixel = surface->format->BytesPerPixel;
|
|
|
|
ColorDescription.mask.r = surface->format->Rmask;
|
|
ColorDescription.shift.r = surface->format->Rshift;
|
|
ColorDescription.width.r = MaskToWidth(surface->format->Rmask);
|
|
|
|
ColorDescription.mask.g = surface->format->Gmask;
|
|
ColorDescription.shift.g = surface->format->Gshift;
|
|
ColorDescription.width.g = MaskToWidth(surface->format->Gmask);
|
|
|
|
ColorDescription.mask.b = surface->format->Bmask;
|
|
ColorDescription.shift.b = surface->format->Bshift;
|
|
ColorDescription.width.b = MaskToWidth(surface->format->Bmask);
|
|
|
|
ColorDescription.mask.a = surface->format->Amask;
|
|
ColorDescription.shift.a = surface->format->Ashift;
|
|
ColorDescription.width.a = MaskToWidth(surface->format->Amask);
|
|
|
|
BackgroundColor = ColorDescription.Make8(0xFF,0xFF,0xFF);
|
|
ForegroundColor = ColorDescription.Make8(0x00,0x00,0x00);
|
|
|
|
if (ColorDescription.BytesPerPixel == 4) {
|
|
GetPixel = GetPixel_32bpp;
|
|
SetPixel = SetPixel_32bpp;
|
|
}
|
|
else if (ColorDescription.BytesPerPixel == 3) {
|
|
GetPixel = GetPixel_24bpp;
|
|
SetPixel = SetPixel_24bpp;
|
|
}
|
|
else if (ColorDescription.BytesPerPixel == 2) {
|
|
GetPixel = GetPixel_16bpp;
|
|
SetPixel = SetPixel_16bpp;
|
|
}
|
|
else if (ColorDescription.BytesPerPixel == 1) {
|
|
GetPixel = GetPixel_8bpp;
|
|
SetPixel = SetPixel_8bpp;
|
|
}
|
|
}
|
|
|
|
void ObjSDLSurface::ConvertLogicalToDeviceCoordinates(long &x,long &y) {
|
|
Obj::ConvertLogicalToDeviceCoordinates(x,y);
|
|
x += viewport_origin.x;
|
|
y += viewport_origin.y;
|
|
}
|
|
|
|
/* WARNING: This is not suitable for surfaces less than 8bpp if x != 0 however SDL doesn't support those either */
|
|
void *ObjSDLSurface::GetSurfaceRowPtr(long x,long y) {
|
|
/* We trust the viewport has not been corrupted to extend outside the SDL surface! */
|
|
if (x >= 0l && x < (long)viewport.w && y >= 0l && y < (long)viewport.h) {
|
|
unsigned char *p = (unsigned char*)(surface->pixels);
|
|
if (p == NULL) return NULL;
|
|
return
|
|
p +
|
|
((unsigned int)surface->pitch * (unsigned int)y) +
|
|
((unsigned int)ColorDescription.BytesPerPixel * (unsigned int)x);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void ObjSDLSurface::SetPixel_32bpp(Obj &bobj,long x,long y,const DevicePixel c) {
|
|
ObjSDLSurface &obj = reinterpret_cast<ObjSDLSurface&>(bobj);
|
|
uint32_t *row = (uint32_t*)obj.GetSurfaceRowPtr(x,y);
|
|
if (row != NULL) *row = uint32_t(c);
|
|
}
|
|
|
|
DevicePixel ObjSDLSurface::GetPixel_32bpp(Obj &bobj,long x,long y) {
|
|
ObjSDLSurface &obj = reinterpret_cast<ObjSDLSurface&>(bobj);
|
|
uint32_t *row = (uint32_t*)obj.GetSurfaceRowPtr(x,y);
|
|
if (row != NULL) return DevicePixel(*row);
|
|
return DevicePixel(0);
|
|
}
|
|
|
|
void ObjSDLSurface::SetPixel_24bpp(Obj &bobj,long x,long y,const DevicePixel c) {
|
|
ObjSDLSurface &obj = reinterpret_cast<ObjSDLSurface&>(bobj);
|
|
uint8_t *row = (uint8_t*)obj.GetSurfaceRowPtr(x,y);
|
|
if (row != NULL) *row = (uint32_t(c) & Mask24) + ((*row) & (~Mask24));
|
|
}
|
|
|
|
DevicePixel ObjSDLSurface::GetPixel_24bpp(Obj &bobj,long x,long y) {
|
|
ObjSDLSurface &obj = reinterpret_cast<ObjSDLSurface&>(bobj);
|
|
uint32_t *row = (uint32_t*)obj.GetSurfaceRowPtr(x,y);
|
|
if (row != NULL) return DevicePixel(*row & Mask24);
|
|
return DevicePixel(0);
|
|
}
|
|
|
|
void ObjSDLSurface::SetPixel_16bpp(Obj &bobj,long x,long y,const DevicePixel c) {
|
|
ObjSDLSurface &obj = reinterpret_cast<ObjSDLSurface&>(bobj);
|
|
uint16_t *row = (uint16_t*)obj.GetSurfaceRowPtr(x,y);
|
|
if (row != NULL) *row = uint16_t(c);
|
|
}
|
|
|
|
DevicePixel ObjSDLSurface::GetPixel_16bpp(Obj &bobj,long x,long y) {
|
|
ObjSDLSurface &obj = reinterpret_cast<ObjSDLSurface&>(bobj);
|
|
uint16_t *row = (uint16_t*)obj.GetSurfaceRowPtr(x,y);
|
|
if (row != NULL) return DevicePixel(*row);
|
|
return DevicePixel(0);
|
|
}
|
|
|
|
void ObjSDLSurface::SetPixel_8bpp(Obj &bobj,long x,long y,const DevicePixel c) {
|
|
ObjSDLSurface &obj = reinterpret_cast<ObjSDLSurface&>(bobj);
|
|
uint8_t *row = (uint8_t*)obj.GetSurfaceRowPtr(x,y);
|
|
if (row != NULL) *row = uint8_t(c);
|
|
}
|
|
|
|
DevicePixel ObjSDLSurface::GetPixel_8bpp(Obj &bobj,long x,long y) {
|
|
ObjSDLSurface &obj = reinterpret_cast<ObjSDLSurface&>(bobj);
|
|
uint8_t *row = (uint8_t*)obj.GetSurfaceRowPtr(x,y);
|
|
if (row != NULL) return DevicePixel(*row);
|
|
return DevicePixel(0);
|
|
}
|
|
|
|
Handle CreateSDLSurfaceDC(SDL_Surface *surf) {
|
|
const size_t idx = List.AllocateHandleIndex();
|
|
if (idx != InvalidHandleIndex) {
|
|
List.Set(idx,(Obj*)(new ObjSDLSurface(surf)));
|
|
return MakeHandle(HandleType::DC,HandleIndex(idx));
|
|
}
|
|
|
|
return InvalidHandleValue;
|
|
}
|
|
|
|
/* for internal use only */
|
|
Obj* GetObject(const Handle h) {
|
|
const HandleIndex idx = GetHandleIndex(HandleType::DC,h);
|
|
return List.Get(idx);
|
|
}
|
|
|
|
DevicePixel MakeRGB8(const Handle h,const unsigned int r,const unsigned int g,const unsigned int b,const unsigned int a) {
|
|
Obj* obj = GetObject(h);
|
|
if (obj) return obj->ColorDescription.Make8(r,g,b,a);
|
|
return DevicePixel(0);
|
|
}
|
|
|
|
DevicePixel GetPixel(const Handle h,long x,long y) {
|
|
Obj* obj = GetObject(h);
|
|
if (obj) {
|
|
obj->ConvertLogicalToDeviceCoordinates(x,y);
|
|
return obj->GetPixel(*obj,x,y); /* NTS: call through function pointer */
|
|
}
|
|
return DevicePixel(0);
|
|
}
|
|
|
|
void SetPixel(const Handle h,long x,long y,const DevicePixel c) {
|
|
Obj* obj = GetObject(h);
|
|
if (obj) {
|
|
obj->ConvertLogicalToDeviceCoordinates(x,y);
|
|
obj->SetPixel(*obj,x,y,c); /* NTS: call through function pointer */
|
|
}
|
|
}
|
|
|
|
bool GetDevicePixelFormat(const Handle h,DevicePixelDescription &d) {
|
|
Obj* obj = GetObject(h);
|
|
if (obj) { d = obj->ColorDescription; return true; }
|
|
return false;
|
|
}
|
|
|
|
DevicePixel SetBackgroundColor(const Handle h,const DevicePixel c) {
|
|
Obj* obj = GetObject(h);
|
|
if (obj) return obj->SetBackgroundColor(c);
|
|
return DevicePixel(0);
|
|
}
|
|
|
|
DevicePixel SetForegroundColor(const Handle h,const DevicePixel c) {
|
|
Obj* obj = GetObject(h);
|
|
if (obj) return obj->SetForegroundColor(c);
|
|
return DevicePixel(0);
|
|
}
|
|
|
|
bool SetLogicalOrigin(const Handle h,const long x,const long y,Point *po) {
|
|
Obj* obj = GetObject(h);
|
|
if (obj) return obj->SetLogicalOrigin(x,y,po);
|
|
return false;
|
|
}
|
|
|
|
bool SetDeviceOrigin(const Handle h,const long x,const long y,Point *po) {
|
|
Obj* obj = GetObject(h);
|
|
if (obj) return obj->SetDeviceOrigin(x,y,po);
|
|
return false;
|
|
}
|
|
|
|
bool Delete(const Handle h) {
|
|
const HandleIndex idx = GetHandleIndex(HandleType::DC,h);
|
|
if (idx != InvalidHandleIndex && idx < List.Size()) {
|
|
Obj *obj = List.Get(idx);
|
|
if (obj != NULL) {
|
|
List.Set(idx,NULL);
|
|
delete obj;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
Handle SelectFont(const Handle h,const Handle newValue) {
|
|
Obj* obj = GetObject(h);
|
|
if (obj) return obj->SelectFont(newValue);
|
|
return InvalidHandleValue;
|
|
}
|
|
|
|
bool TextOut(const Handle h,long x,long y,const char *str/*TODO UTF-8*/) {
|
|
Obj* obj = GetObject(h);
|
|
if (obj) {
|
|
obj->ConvertLogicalToDeviceCoordinates(x,y);
|
|
return obj->TextOut(x,y,str);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void NewUIExperiment(bool pressed) {
|
|
if (!pressed) return;
|
|
|
|
GFX_EndUpdate(nullptr);
|
|
GFX_SetTitle(-1,-1,-1,true);
|
|
KEYBOARD_ClrBuffer();//Clear buffer
|
|
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
|
|
SDL_Delay(20);
|
|
|
|
#if defined(C_SDL2)
|
|
#elif defined(C_HX_DOS)
|
|
#else
|
|
int dw,dh;
|
|
void UpdateWindowDimensions(void);
|
|
UpdateWindowDimensions();
|
|
dw = (int)currentWindowWidth;
|
|
dh = (int)currentWindowHeight;
|
|
|
|
if (dw < 32) dw = 32;
|
|
if (dh < 32) dh = 32;
|
|
|
|
SDL_Event event;
|
|
|
|
LOG_MSG("NewGUI %d x %d",dw,dh);
|
|
SDL_Surface *gui_surface = SDL_SetVideoMode(dw,dh,32,0);
|
|
if (gui_surface == NULL) E_Exit("Could not initialize video mode for GUI: %s",SDL_GetError());
|
|
SDL_FillRect(gui_surface, nullptr, 0);
|
|
|
|
WLGUI::Handle gui_surface_dc = WLGUI::DC::CreateSDLSurfaceDC(gui_surface);
|
|
if (gui_surface_dc == WLGUI::InvalidHandleValue) E_Exit("Cannot create SDL DC");
|
|
|
|
WLGUI::Handle VGAFont = WLGUI::FontHandle::CreateVGAFont(16);
|
|
if (VGAFont == WLGUI::InvalidHandleValue) E_Exit("Cannot create VGA font");
|
|
|
|
WLGUI::DC::SelectFont(gui_surface_dc,VGAFont);
|
|
WLGUI::DC::SetForegroundColor(gui_surface_dc,WLGUI::DC::MakeRGB8(gui_surface_dc,0xFF,0xFF,0xFF));
|
|
WLGUI::DC::SetBackgroundColor(gui_surface_dc,WLGUI::DC::MakeRGB8(gui_surface_dc,0x00,0x00,0xFF));
|
|
|
|
WLGUI::DC::TextOut(gui_surface_dc,0,0,"Hello!");
|
|
WLGUI::DC::TextOut(gui_surface_dc,0,16,"Hello!");
|
|
|
|
for (long x=-100;x < 100;x++) {
|
|
WLGUI::DC::SetPixel(gui_surface_dc,x, x,WLGUI::DC::MakeRGB8(gui_surface_dc,x+128,x+128,x+128));
|
|
WLGUI::DC::SetPixel(gui_surface_dc,x+10,x,WLGUI::DC::MakeRGB8(gui_surface_dc,x+128,0, 0 ));
|
|
WLGUI::DC::SetPixel(gui_surface_dc,x+20,x,WLGUI::DC::MakeRGB8(gui_surface_dc,0, x+128,0 ));
|
|
WLGUI::DC::SetPixel(gui_surface_dc,x+30,x,WLGUI::DC::MakeRGB8(gui_surface_dc,0, 0, x+128));
|
|
}
|
|
|
|
SDL_UpdateRect(gui_surface, 0, 0, 0, 0);
|
|
while (SDL_PollEvent(&event));
|
|
SDL_Delay(1000);
|
|
SDL_FillRect(gui_surface, nullptr, 0);
|
|
|
|
WLGUI::DC::SetLogicalOrigin(gui_surface_dc,100,0);
|
|
for (long x=-100;x < 100;x++) {
|
|
WLGUI::DC::SetPixel(gui_surface_dc,x, x,WLGUI::DC::MakeRGB8(gui_surface_dc,x+128,x+128,x+128));
|
|
WLGUI::DC::SetPixel(gui_surface_dc,x+10,x,WLGUI::DC::MakeRGB8(gui_surface_dc,x+128,0, 0 ));
|
|
WLGUI::DC::SetPixel(gui_surface_dc,x+20,x,WLGUI::DC::MakeRGB8(gui_surface_dc,0, x+128,0 ));
|
|
WLGUI::DC::SetPixel(gui_surface_dc,x+30,x,WLGUI::DC::MakeRGB8(gui_surface_dc,0, 0, x+128));
|
|
}
|
|
WLGUI::DC::SetLogicalOrigin(gui_surface_dc,0,100);
|
|
for (long x=-100;x < 100;x++) {
|
|
WLGUI::DC::SetPixel(gui_surface_dc,x, x,WLGUI::DC::MakeRGB8(gui_surface_dc,x+128,x+128,x+128));
|
|
WLGUI::DC::SetPixel(gui_surface_dc,x+10,x,WLGUI::DC::MakeRGB8(gui_surface_dc,x+128,0, 0 ));
|
|
WLGUI::DC::SetPixel(gui_surface_dc,x+20,x,WLGUI::DC::MakeRGB8(gui_surface_dc,0, x+128,0 ));
|
|
WLGUI::DC::SetPixel(gui_surface_dc,x+30,x,WLGUI::DC::MakeRGB8(gui_surface_dc,0, 0, x+128));
|
|
}
|
|
WLGUI::DC::SetLogicalOrigin(gui_surface_dc);
|
|
for (long x=-100;x < 100;x++) {
|
|
WLGUI::DC::SetPixel(gui_surface_dc,x, x,WLGUI::DC::MakeRGB8(gui_surface_dc,x+128,x+128,x+128));
|
|
WLGUI::DC::SetPixel(gui_surface_dc,x+10,x,WLGUI::DC::MakeRGB8(gui_surface_dc,x+128,0, 0 ));
|
|
WLGUI::DC::SetPixel(gui_surface_dc,x+20,x,WLGUI::DC::MakeRGB8(gui_surface_dc,0, x+128,0 ));
|
|
WLGUI::DC::SetPixel(gui_surface_dc,x+30,x,WLGUI::DC::MakeRGB8(gui_surface_dc,0, 0, x+128));
|
|
}
|
|
|
|
WLGUI::DC::SetDeviceOrigin(gui_surface_dc,200,0);
|
|
for (long x=-100;x < 100;x++) {
|
|
WLGUI::DC::SetPixel(gui_surface_dc,x, x,WLGUI::DC::MakeRGB8(gui_surface_dc,x+128,x+128,x+128));
|
|
WLGUI::DC::SetPixel(gui_surface_dc,x+10,x,WLGUI::DC::MakeRGB8(gui_surface_dc,x+128,0, 0 ));
|
|
WLGUI::DC::SetPixel(gui_surface_dc,x+20,x,WLGUI::DC::MakeRGB8(gui_surface_dc,0, x+128,0 ));
|
|
WLGUI::DC::SetPixel(gui_surface_dc,x+30,x,WLGUI::DC::MakeRGB8(gui_surface_dc,0, 0, x+128));
|
|
}
|
|
WLGUI::DC::SetDeviceOrigin(gui_surface_dc,0,200);
|
|
for (long x=-100;x < 100;x++) {
|
|
WLGUI::DC::SetPixel(gui_surface_dc,x, x,WLGUI::DC::MakeRGB8(gui_surface_dc,x+128,x+128,x+128));
|
|
WLGUI::DC::SetPixel(gui_surface_dc,x+10,x,WLGUI::DC::MakeRGB8(gui_surface_dc,x+128,0, 0 ));
|
|
WLGUI::DC::SetPixel(gui_surface_dc,x+20,x,WLGUI::DC::MakeRGB8(gui_surface_dc,0, x+128,0 ));
|
|
WLGUI::DC::SetPixel(gui_surface_dc,x+30,x,WLGUI::DC::MakeRGB8(gui_surface_dc,0, 0, x+128));
|
|
}
|
|
WLGUI::DC::SetDeviceOrigin(gui_surface_dc);
|
|
|
|
SDL_UpdateRect(gui_surface, 0, 0, 0, 0);
|
|
while (SDL_PollEvent(&event));
|
|
SDL_Delay(1000);
|
|
SDL_FillRect(gui_surface, nullptr, 0);
|
|
|
|
WLGUI::DC::SetDeviceOrigin(gui_surface_dc,dw/2,dh/2);
|
|
|
|
for (long x=-4000;x < 4000;x++) {
|
|
long cx = ((x+4000l)*255l)/8000l;
|
|
WLGUI::DC::SetPixel(gui_surface_dc,x, x,WLGUI::DC::MakeRGB8(gui_surface_dc,cx,cx,cx));
|
|
WLGUI::DC::SetPixel(gui_surface_dc,x+100,x,WLGUI::DC::MakeRGB8(gui_surface_dc,cx,0, 0 ));
|
|
WLGUI::DC::SetPixel(gui_surface_dc,x+200,x,WLGUI::DC::MakeRGB8(gui_surface_dc,0, cx,0 ));
|
|
WLGUI::DC::SetPixel(gui_surface_dc,x+300,x,WLGUI::DC::MakeRGB8(gui_surface_dc,0, 0, cx));
|
|
}
|
|
|
|
WLGUI::DC::TextOut(gui_surface_dc,0,0,"Hello!");
|
|
WLGUI::DC::TextOut(gui_surface_dc,1000,1000,"Hello!");
|
|
|
|
WLGUI::DC::SetLogicalOrigin(gui_surface_dc,0,0);
|
|
WLGUI::DC::SetDeviceOrigin(gui_surface_dc,0,0);
|
|
|
|
SDL_UpdateRect(gui_surface, 0, 0, 0, 0);
|
|
while (SDL_PollEvent(&event));
|
|
SDL_Delay(1000);
|
|
|
|
{
|
|
const unsigned int sw = dw/4,sh = dh/4;
|
|
const unsigned int sx = dw - sw,sy = dh - sh;
|
|
for (unsigned int y=0;y < sx;y++) {
|
|
for (unsigned int x=0;x < sy;x++) {
|
|
WLGUI::DC::SetPixel(gui_surface_dc,x,y,
|
|
WLGUI::DC::GetPixel(gui_surface_dc,sx+(x/4),sy+(y/4)));
|
|
}
|
|
}
|
|
}
|
|
|
|
SDL_UpdateRect(gui_surface, 0, 0, 0, 0);
|
|
while (SDL_PollEvent(&event));
|
|
SDL_Delay(1000);
|
|
SDL_FillRect(gui_surface, nullptr, 0);
|
|
|
|
if (!WLGUI::DC::Delete(gui_surface_dc)) E_Exit("Cannot delete SDL DC");
|
|
if (!WLGUI::FontHandle::Destroy(VGAFont)) E_Exit("Cannot destroy font");
|
|
#endif
|
|
|
|
GFX_Stop();
|
|
if (sdl.draw.callback) (sdl.draw.callback)( GFX_CallBackReset );
|
|
GFX_Start();
|
|
}
|
|
|
|
extern bool toscale;
|
|
extern const char* RunningProgram;
|
|
static GUI::ScreenSDL *UI_Startup(GUI::ScreenSDL *screen) {
|
|
in_gui = true;
|
|
|
|
GFX_EndUpdate(nullptr);
|
|
GFX_SetTitle(-1,-1,-1,true);
|
|
if(!screen) { //Coming from DOSBox. Clean up the keyboard buffer.
|
|
KEYBOARD_ClrBuffer();//Clear buffer
|
|
}
|
|
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
|
|
SDL_Delay(20);
|
|
|
|
unsigned int cpbak = dos.loaded_codepage;
|
|
if (dos_kernel_disabled&&maincp) dos.loaded_codepage = maincp;
|
|
Section_prop *section = static_cast<Section_prop *>(control->GetSection("dosbox"));
|
|
LoadMessageFile(section->Get_string("language"));
|
|
if (font_14_init) GUI_LoadFonts();
|
|
dos.loaded_codepage = cpbak;
|
|
|
|
// Comparable to the code of intro.com, but not the same! (the code of intro.com is called from within a com file)
|
|
shell_idle = !dos_kernel_disabled && strcmp(RunningProgram, "LOADLIN") && first_shell && (DOS_PSP(dos.psp()).GetSegment() == DOS_PSP(dos.psp()).GetParent());
|
|
|
|
int sx, sy, sw, sh, scalex, scaley, scale;
|
|
bool fs;
|
|
GFX_GetSizeAndPos(sx, sy, sw, sh, fs);
|
|
|
|
int dw,dh;
|
|
#if defined(C_SDL2)
|
|
{
|
|
dw = 640; dh = 480;
|
|
|
|
SDL_Window* GFX_GetSDLWindow(void);
|
|
SDL_Window *w = GFX_GetSDLWindow();
|
|
SDL_GetWindowSize(w,&dw,&dh);
|
|
}
|
|
#elif defined(C_HX_DOS)
|
|
/* FIXME: HX DOS builds are not updating the window dimensions vars.. */
|
|
/* However our window is always fullscreen (maximized) */
|
|
{
|
|
dw = GetSystemMetrics(SM_CXSCREEN);
|
|
dh = GetSystemMetrics(SM_CYSCREEN);
|
|
}
|
|
#else
|
|
void UpdateWindowDimensions(void);
|
|
UpdateWindowDimensions();
|
|
dw = (int)currentWindowWidth;
|
|
dh = (int)currentWindowHeight;
|
|
#endif
|
|
|
|
if (dw < 640) dw = 640;
|
|
if (dh < 350) dh = 350;
|
|
scalex = dw / 640; /* maximum horizontal scale */
|
|
scaley = dh / 350; /* maximum vertical scale */
|
|
if( scalex > scaley ) scale = scaley;
|
|
else scale = scalex;
|
|
if (!toscale) scale = 1;
|
|
|
|
assert(sx < dw);
|
|
assert(sy < dh);
|
|
|
|
int sw_draw = sw,sh_draw = sh;
|
|
|
|
if ((sx+sw_draw) > dw) sw_draw = dw-sx;
|
|
if ((sy+sh_draw) > dh) sh_draw = dh-sy;
|
|
|
|
assert((sx+sw_draw) <= dw);
|
|
assert((sy+sh_draw) <= dh);
|
|
|
|
assert(sw_draw <= sw);
|
|
assert(sh_draw <= sh);
|
|
|
|
#if !defined(C_SDL2)
|
|
old_unicode = SDL_EnableUNICODE(1);
|
|
SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY,SDL_DEFAULT_REPEAT_INTERVAL);
|
|
#endif
|
|
|
|
if (sw_draw > 0 && sh_draw > 0) {
|
|
screenshot = SDL_CreateRGBSurface(SDL_SWSURFACE, dw, dh, 32, GUI::Color::RedMask, GUI::Color::GreenMask, GUI::Color::BlueMask, 0);
|
|
SDL_FillRect(screenshot, nullptr, 0);
|
|
|
|
unsigned int rs = screenshot->format->Rshift, gs = screenshot->format->Gshift, bs = screenshot->format->Bshift;
|
|
|
|
// create screenshot for fade effect
|
|
for (unsigned int y = 0; (int)y < sh_draw; y++) {
|
|
uint32_t *bg = (uint32_t*)((y+(unsigned int)sy)*(unsigned int)screenshot->pitch + (char*)screenshot->pixels) + (unsigned int)sx;
|
|
for (unsigned int x = 0; (int)x < sw_draw; x++) {
|
|
int r = 0, g = 0, b = 0;
|
|
getPixel((int)(x*(unsigned int)render.src.width/(unsigned int)sw),
|
|
(int)(y*(unsigned int)render.src.height/(unsigned int)sh),
|
|
r, g, b, 0);
|
|
bg[x] = ((unsigned int)r << (unsigned int)rs) |
|
|
((unsigned int)g << (unsigned int)gs) |
|
|
((unsigned int)b << (unsigned int)bs);
|
|
}
|
|
}
|
|
|
|
background = SDL_CreateRGBSurface(SDL_SWSURFACE, dw, dh, 32, GUI::Color::RedMask, GUI::Color::GreenMask, GUI::Color::BlueMask, 0);
|
|
SDL_FillRect(background, nullptr, 0);
|
|
for (int y = 0; y < sh_draw; y++) {
|
|
uint32_t *bg = (uint32_t*)((unsigned int)(y+sy)*(unsigned int)background->pitch + (char*)background->pixels) + sx;
|
|
for (int x = 0; x < sw_draw; x++) {
|
|
int r = 0, g = 0, b = 0;
|
|
getPixel(x *(int)render.src.width/sw, y *(int)render.src.height/sh, r, g, b, 3);
|
|
getPixel((x-1)*(int)render.src.width/sw, y *(int)render.src.height/sh, r, g, b, 3);
|
|
getPixel(x *(int)render.src.width/sw, (y-1)*(int)render.src.height/sh, r, g, b, 3);
|
|
getPixel((x-1)*(int)render.src.width/sw, (y-1)*(int)render.src.height/sh, r, g, b, 3);
|
|
getPixel((x+1)*(int)render.src.width/sw, y *(int)render.src.height/sh, r, g, b, 3);
|
|
getPixel(x *(int)render.src.width/sw, (y+1)*(int)render.src.height/sh, r, g, b, 3);
|
|
getPixel((x+1)*(int)render.src.width/sw, (y+1)*(int)render.src.height/sh, r, g, b, 3);
|
|
getPixel((x-1)*(int)render.src.width/sw, (y+1)*(int)render.src.height/sh, r, g, b, 3);
|
|
int r1, g1, b1;
|
|
#if defined(USE_TTF)
|
|
if (ttf.inUse && confres) {
|
|
std::string theme = section->Get_string("bannercolortheme");
|
|
if (theme == "black") {
|
|
r1 = 0; g1 = 0; b1 = 0;
|
|
} else if (theme == "red") {
|
|
r1 = 170; g1 = 0; b1 = 0;
|
|
} else if (theme == "green") {
|
|
r1 = 0; g1 = 170; b1 = 0;
|
|
} else if (theme == "yellow") {
|
|
r1 = 170; g1 = 85; b1 = 0;
|
|
} else if (theme == "magenta") {
|
|
r1 = 170; g1 = 0; b1 = 170;
|
|
} else if (theme == "cyan") {
|
|
r1 = 0; g1 = 170; b1 = 170;
|
|
} else if (theme == "white") {
|
|
r1 = 170; g1 = 170; b1 = 170;
|
|
} else {
|
|
r1 = 0; g1 = 0; b1 = 170;
|
|
}
|
|
} else
|
|
#endif
|
|
{
|
|
r1 = (int)((r * 393 + g * 769 + b * 189) / 1351); // 1351 -- tweak colors
|
|
g1 = (int)((r * 349 + g * 686 + b * 168) / 1503); // 1203 -- for a nice
|
|
b1 = (int)((r * 272 + g * 534 + b * 131) / 2340); // 2140 -- golden hue
|
|
}
|
|
bg[x] = ((unsigned int)r1 << (unsigned int)rs) |
|
|
((unsigned int)g1 << (unsigned int)gs) |
|
|
((unsigned int)b1 << (unsigned int)bs);
|
|
}
|
|
}
|
|
}
|
|
|
|
cursor = SDL_ShowCursor(SDL_QUERY);
|
|
SDL_ShowCursor(SDL_ENABLE);
|
|
|
|
mousetoggle = mouselocked;
|
|
if (mouselocked) GFX_CaptureMouse();
|
|
|
|
#if defined(C_SDL2)
|
|
extern SDL_Window * GFX_SetSDLSurfaceWindow(uint16_t width, uint16_t height);
|
|
|
|
void GFX_SetResizeable(bool enable);
|
|
GFX_SetResizeable(false);
|
|
|
|
SDL_Window* window = OpenGL_using() ? GFX_SetSDLWindowMode(dw, dh, SCREEN_OPENGL) : GFX_SetSDLSurfaceWindow(dw, dh);
|
|
if (window == NULL) E_Exit("Could not initialize video mode for mapper: %s",SDL_GetError());
|
|
SDL_Surface* sdlscreen = SDL_GetWindowSurface(window);
|
|
if (sdlscreen == NULL) E_Exit("Could not initialize video mode for mapper: %s",SDL_GetError());
|
|
|
|
if (screenshot != NULL && background != NULL) {
|
|
// fade out
|
|
// Jonathan C: do it FASTER!
|
|
SDL_Event event;
|
|
SDL_SetSurfaceBlendMode(screenshot, SDL_BLENDMODE_BLEND);
|
|
for (int i = 0xff; i > 0; i -= 0x40) {
|
|
SDL_SetSurfaceAlphaMod(screenshot, i);
|
|
SDL_BlitSurface(background, NULL, sdlscreen, NULL);
|
|
SDL_BlitSurface(screenshot, NULL, sdlscreen, NULL);
|
|
SDL_Window* GFX_GetSDLWindow(void);
|
|
SDL_UpdateWindowSurface(GFX_GetSDLWindow());
|
|
while (SDL_PollEvent(&event));
|
|
SDL_Delay(40);
|
|
}
|
|
SDL_SetSurfaceBlendMode(screenshot, SDL_BLENDMODE_NONE);
|
|
}
|
|
#else
|
|
SDL_Surface* sdlscreen = SDL_SetVideoMode(dw, dh, 32, SDL_SWSURFACE|(fs?SDL_FULLSCREEN:0));
|
|
if (sdlscreen == NULL) E_Exit("Could not initialize video mode %ix%ix32 for UI: %s", dw, dh, SDL_GetError());
|
|
|
|
if (screenshot != NULL && background != NULL) {
|
|
// fade out
|
|
// Jonathan C: do it FASTER!
|
|
SDL_Event event;
|
|
for (int i = 0xff; i > 0; i -= 0x40) {
|
|
SDL_SetAlpha(screenshot, SDL_SRCALPHA, i);
|
|
SDL_BlitSurface(background, NULL, sdlscreen, NULL);
|
|
SDL_BlitSurface(screenshot, NULL, sdlscreen, NULL);
|
|
SDL_UpdateRect(sdlscreen, 0, 0, 0, 0);
|
|
while (SDL_PollEvent(&event));
|
|
SDL_Delay(40);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (screenshot != NULL && background != NULL)
|
|
SDL_BlitSurface(background, NULL, sdlscreen, NULL);
|
|
#if defined(C_SDL2)
|
|
SDL_Window* GFX_GetSDLWindow(void);
|
|
SDL_UpdateWindowSurface(GFX_GetSDLWindow());
|
|
#else
|
|
SDL_UpdateRect(sdlscreen, 0, 0, 0, 0);
|
|
#endif
|
|
|
|
#if defined(WIN32) && !defined(HX_DOS) && !defined(_WIN32_WINDOWS)
|
|
WindowsTaskbarResetPreviewRegion();
|
|
#endif
|
|
|
|
#ifdef DOSBOXMENU_EXTERNALLY_MANAGED
|
|
if (gui_menu_init) {
|
|
gui_menu_init = false;
|
|
|
|
{
|
|
DOSBoxMenu::item &item = guiMenu.alloc_item(DOSBoxMenu::submenu_type_id,"ConfigGuiMenu");
|
|
item.set_text(mainMenu.get_item("mapper_gui").get_text());
|
|
}
|
|
|
|
{
|
|
DOSBoxMenu::item &item = guiMenu.alloc_item(DOSBoxMenu::item_type_id,"ExitGUI");
|
|
item.set_callback_function(gui_menu_exit);
|
|
item.set_text(MSG_Get("CONFIG_TOOL_EXIT"));
|
|
}
|
|
|
|
guiMenu.displaylist_clear(guiMenu.display_list);
|
|
|
|
guiMenu.displaylist_append(
|
|
guiMenu.display_list,
|
|
guiMenu.get_item_id_by_name("ConfigGuiMenu"));
|
|
|
|
{
|
|
guiMenu.displaylist_append(
|
|
guiMenu.get_item("ConfigGuiMenu").display_list, guiMenu.get_item_id_by_name("ExitGUI"));
|
|
}
|
|
} else if (!shortcut || shortcutid<16) {
|
|
{
|
|
DOSBoxMenu::item &item = guiMenu.get_item("ConfigGuiMenu");
|
|
item.set_text(mainMenu.get_item("mapper_gui").get_text());
|
|
}
|
|
{
|
|
DOSBoxMenu::item &item = guiMenu.get_item("ExitGUI");
|
|
item.set_text(MSG_Get("CONFIG_TOOL_EXIT"));
|
|
}
|
|
# if DOSBOXMENU_TYPE == DOSBOXMENU_HMENU || DOSBOXMENU_TYPE == DOSBOXMENU_NSMENU
|
|
if (loadlang) guiMenu.unbuild();
|
|
# endif
|
|
}
|
|
|
|
if (null_menu_init) {
|
|
null_menu_init = false;
|
|
|
|
{
|
|
DOSBoxMenu::item &item = nullMenu.alloc_item(DOSBoxMenu::submenu_type_id,"ConfigGuiMenu");
|
|
item.set_text("");
|
|
}
|
|
|
|
nullMenu.displaylist_clear(nullMenu.display_list);
|
|
|
|
nullMenu.displaylist_append(
|
|
nullMenu.display_list,
|
|
nullMenu.get_item_id_by_name("ConfigGuiMenu"));
|
|
}
|
|
|
|
if (!shortcut || shortcutid<16) {
|
|
guiMenu.rebuild();
|
|
DOSBox_SetMenu(guiMenu);
|
|
} else {
|
|
nullMenu.rebuild();
|
|
DOSBox_SetMenu(nullMenu);
|
|
}
|
|
#endif
|
|
|
|
if (screen) screen->setSurface(sdlscreen);
|
|
else screen = new GUI::ScreenSDL(sdlscreen, scale); // CONF:SCALE
|
|
|
|
saved_bpp = (int)render.src.bpp;
|
|
render.src.bpp = 0;
|
|
running = true;
|
|
|
|
#if defined(MACOSX)
|
|
macosx_reload_touchbar();
|
|
#endif
|
|
|
|
return screen;
|
|
}
|
|
|
|
/* Restore screen */
|
|
static void UI_Shutdown(GUI::ScreenSDL *screen) {
|
|
SDL_Surface *sdlscreen = screen->getSurface();
|
|
render.src.bpp = (Bitu)saved_bpp;
|
|
|
|
#ifdef DOSBOXMENU_EXTERNALLY_MANAGED
|
|
DOSBox_SetMenu(mainMenu);
|
|
#endif
|
|
|
|
#if defined(MACOSX)
|
|
macosx_reload_touchbar();
|
|
#endif
|
|
|
|
#if defined(C_SDL2)
|
|
if (screenshot != NULL && background != NULL) {
|
|
// fade in
|
|
// Jonathan C: do it FASTER!
|
|
SDL_Event event;
|
|
SDL_SetSurfaceBlendMode(screenshot, SDL_BLENDMODE_BLEND);
|
|
for (unsigned int i = 0x00; i < 0xff; i += 0x60) {
|
|
SDL_SetSurfaceAlphaMod(screenshot, i);
|
|
SDL_BlitSurface(background, NULL, sdlscreen, NULL);
|
|
SDL_BlitSurface(screenshot, NULL, sdlscreen, NULL);
|
|
SDL_Window* GFX_GetSDLWindow(void);
|
|
SDL_UpdateWindowSurface(GFX_GetSDLWindow());
|
|
while (SDL_PollEvent(&event));
|
|
SDL_Delay(40);
|
|
}
|
|
SDL_SetSurfaceBlendMode(screenshot, SDL_BLENDMODE_NONE);
|
|
}
|
|
|
|
void GFX_SetResizeable(bool enable);
|
|
GFX_SetResizeable(true);
|
|
#else
|
|
if (screenshot != NULL && background != NULL) {
|
|
// fade in
|
|
// Jonathan C: do it FASTER!
|
|
SDL_Event event;
|
|
for (unsigned int i = 0x00; i < 0xff; i += 0x60) {
|
|
SDL_SetAlpha(screenshot, SDL_SRCALPHA, i);
|
|
SDL_BlitSurface(background, NULL, sdlscreen, NULL);
|
|
SDL_BlitSurface(screenshot, NULL, sdlscreen, NULL);
|
|
SDL_UpdateRect(sdlscreen, 0, 0, 0, 0);
|
|
while (SDL_PollEvent(&event)) {}
|
|
SDL_Delay(40);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// clean up
|
|
if (mousetoggle) GFX_CaptureMouse();
|
|
SDL_ShowCursor(cursor);
|
|
if (background != NULL) {
|
|
SDL_FreeSurface(background);
|
|
background = NULL;
|
|
}
|
|
if (screenshot != NULL) {
|
|
SDL_FreeSurface(screenshot);
|
|
screenshot = NULL;
|
|
}
|
|
SDL_FreeSurface(sdlscreen);
|
|
screen->setSurface(NULL);
|
|
#ifdef WIN32
|
|
void res_init(void);
|
|
void change_output(int output);
|
|
res_init();
|
|
change_output(8);
|
|
#else
|
|
#if 1
|
|
GFX_RestoreMode();
|
|
#else
|
|
GFX_ResetScreen();
|
|
#endif
|
|
#endif
|
|
|
|
#if defined(WIN32) && !defined(HX_DOS) && !defined(_WIN32_WINDOWS)
|
|
DOSBox_SetSysMenu();
|
|
WindowsTaskbarUpdatePreviewRegion();
|
|
#endif
|
|
|
|
#if !defined(C_SDL2)
|
|
SDL_EnableUNICODE(old_unicode);
|
|
SDL_EnableKeyRepeat(0,0);
|
|
#endif
|
|
GFX_SetTitle(-1,-1,-1,false);
|
|
|
|
void GFX_ForceRedrawScreen(void);
|
|
#if defined(USE_TTF)
|
|
if (!TTF_using() || ttf.inUse)
|
|
#endif
|
|
{
|
|
GFX_ForceRedrawScreen();
|
|
#if defined(USE_TTF)
|
|
if (ttf.inUse) resetFontSize();
|
|
#endif
|
|
}
|
|
|
|
in_gui = false;
|
|
if (resetcfg) {
|
|
resetcfg = false;
|
|
std::string sec, line;
|
|
while (proplist.size()>1) {
|
|
sec = proplist.front();
|
|
proplist.pop_front();
|
|
line = proplist.front();
|
|
proplist.pop_front();
|
|
ApplySetting(sec, line, true);
|
|
}
|
|
GUI_Run(false);
|
|
}
|
|
}
|
|
|
|
bool GUI_IsRunning(void) {
|
|
return in_gui;
|
|
}
|
|
|
|
static void UI_RunCommands(GUI::ScreenSDL *s, const std::string &cmds) {
|
|
DOS_Shell temp;
|
|
temp.call = true;
|
|
UI_Shutdown(s);
|
|
uint16_t n=1; uint8_t c='\n';
|
|
DOS_WriteFile(STDOUT,&c,&n);
|
|
temp.bf = new VirtualBatch(&temp, cmds);
|
|
temp.RunInternal();
|
|
temp.ShowPrompt();
|
|
UI_Startup(s);
|
|
}
|
|
|
|
VirtualBatch::VirtualBatch(DOS_Shell *host, const std::string& cmds) : BatchFile(host, "CON", "", ""), lines(cmds) {
|
|
}
|
|
|
|
bool VirtualBatch::ReadLine(char *line) {
|
|
std::string l;
|
|
|
|
if (!std::getline(lines,l)) {
|
|
delete this;
|
|
return false;
|
|
}
|
|
|
|
strcpy(line,l.c_str());
|
|
return true;
|
|
}
|
|
|
|
/* stringification and conversion from the c++ FAQ */
|
|
class BadConversion : public std::runtime_error {
|
|
public: BadConversion(const std::string& s) : std::runtime_error(s) { }
|
|
};
|
|
|
|
template<typename T> inline std::string stringify(const T& x, std::ios_base& ( *pf )(std::ios_base&) = NULL) {
|
|
std::ostringstream o;
|
|
if (pf) o << pf;
|
|
if (!(o << x)) throw BadConversion(std::string("stringify(") + typeid(x).name() + ")");
|
|
return o.str();
|
|
}
|
|
|
|
template<typename T> inline void convert(const std::string& s, T& x, bool failIfLeftoverChars = true, std::ios_base& ( *pf )(std::ios_base&) = NULL) {
|
|
std::istringstream i(s);
|
|
if (pf) i >> pf;
|
|
char c;
|
|
if (!(i >> x) || (failIfLeftoverChars && i.get(c))) throw BadConversion(s);
|
|
}
|
|
|
|
/*****************************************************************************************************************************************/
|
|
/* UI classes */
|
|
|
|
class PropertyEditor : public GUI::Window, public GUI::ActionEventSource_Callback {
|
|
protected:
|
|
Section_prop * section;
|
|
Property *prop;
|
|
|
|
static constexpr auto RightMarginWindow = 10; // TODO find origin, fix
|
|
static constexpr auto RightMarginBool = 55; // TODO find origin, fix
|
|
static constexpr auto RightMarginText = 40; // TODO find origin, fix
|
|
|
|
int GetHostWindowWidth() const
|
|
{
|
|
const int width = parent->getParent()->getWidth();
|
|
|
|
return width;
|
|
}
|
|
|
|
void SetupUI(const bool opts, GUI::Input*& input, GUI::Button*& infoButton)
|
|
{
|
|
const auto windowWidth = GetHostWindowWidth();
|
|
|
|
constexpr auto optionsWidth = 42;
|
|
|
|
const auto defaultSpacing = static_cast<int>(GUI::CurrentTheme.DefaultSpacing);
|
|
|
|
const auto inputWidth = 235 - (opts ? optionsWidth + defaultSpacing : 0);
|
|
|
|
const auto optionsPos = windowWidth - optionsWidth - RightMarginText - defaultSpacing;
|
|
|
|
const auto inputPos = opts
|
|
? optionsPos - defaultSpacing - inputWidth
|
|
: windowWidth - RightMarginText - defaultSpacing - inputWidth;
|
|
|
|
input = new GUI::Input(this, inputPos, 0, inputWidth, static_cast<int>(GUI::CurrentTheme.ButtonHeight));
|
|
|
|
if(opts)
|
|
{
|
|
infoButton = new GUI::Button(this, optionsPos, 0, "...", optionsWidth);
|
|
infoButton->addActionHandler(this);
|
|
}
|
|
}
|
|
|
|
public:
|
|
PropertyEditor(Window *parent, int x, int y, Section_prop *section, Property *prop, bool opts) :
|
|
Window(parent, x, y, parent->getParent()->getWidth() - RightMarginWindow, 25), section(section), prop(prop) { (void)opts; }
|
|
|
|
virtual bool prepare(std::string &buffer) = 0;
|
|
|
|
void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) override {
|
|
(void)b;//UNUSED
|
|
// HACK: Attempting to cast a String to void causes "forming reference to void" errors when building with GCC 4.7
|
|
(void)arg.size();//UNUSED
|
|
std::string line;
|
|
if (prepare(line)) {
|
|
prop->SetValue(GUI::String(line));
|
|
if (!(!strcmp(section->GetName(),"dosbox")&&prop->propname=="language")) {
|
|
proplist.push_back(section->GetName());
|
|
proplist.push_back(prop->propname+"="+line);
|
|
//ApplySetting(section->GetName(), prop->propname+"="+line, true);
|
|
}
|
|
}
|
|
}
|
|
|
|
void paintVisGuideLineBetween(GUI::Drawable &d,const GUI::Window *lm,const GUI::Window *rm,const GUI::Window *pm) const {
|
|
int sx = lm->getX() + lm->getWidth();
|
|
int ex = rm->getX();
|
|
int y = pm->getHeight() / 2;
|
|
|
|
sx += 4;
|
|
ex -= 4;
|
|
|
|
d.setColor(GUI::CurrentTheme.Shadow3D);
|
|
d.drawDotLine(sx,y,ex,y);
|
|
}
|
|
};
|
|
|
|
class PropertyEditorBool : public PropertyEditor {
|
|
GUI::Checkbox *input;
|
|
GUI::Label *label;
|
|
public:
|
|
PropertyEditorBool(Window *parent, int x, int y, Section_prop *section, Property *prop, bool opts) :
|
|
PropertyEditor(parent, x, y, section, prop, opts) {
|
|
label = new GUI::Label(this, 0, 5, prop->propname);
|
|
constexpr auto inputWidth = 3;
|
|
input = new GUI::Checkbox(this, GetHostWindowWidth() - inputWidth - RightMarginBool, inputWidth, "");
|
|
input->setChecked(static_cast<bool>(prop->GetValue()));
|
|
}
|
|
|
|
bool prepare(std::string &buffer) override {
|
|
if (input->isChecked() == static_cast<bool>(prop->GetValue())) return false;
|
|
buffer.append(input->isChecked()?"true":"false");
|
|
return true;
|
|
}
|
|
|
|
/// Paint label
|
|
void paint(GUI::Drawable &d) const override {
|
|
paintVisGuideLineBetween(d,label,input,this);
|
|
}
|
|
};
|
|
|
|
class ShowOptions : public GUI::MessageBox2 {
|
|
protected:
|
|
GUI::Input *name, *inp;
|
|
GUI::Radiobox *opt[200];
|
|
std::vector<Value> pv;
|
|
std::vector<GUI::Char> cfg_sname;
|
|
GUI::WindowInWindow * wiw = NULL;
|
|
public:
|
|
ShowOptions(GUI::Screen *parent, int x, int y, const char *title, const char *msg, Property *prop, GUI::Input *input) :
|
|
MessageBox2(parent, x, y, 310, title, msg) { // 740
|
|
inp = input;
|
|
pv = prop->GetValues();
|
|
Bitu k, j = 0;
|
|
int allowed_dialog_y = parent->getHeight() - 25 - (border_top + border_bottom) - 120;
|
|
int scroll_h = pv.size() * 20;
|
|
if (scroll_h > allowed_dialog_y) scroll_h = allowed_dialog_y;
|
|
scroll_h += 6;
|
|
wiw = new GUI::WindowInWindow(this, 5, 80, 290, scroll_h);
|
|
bool found = false;
|
|
for(k = 0; k < pv.size(); k++) if (pv[k].ToString().size()) {
|
|
opt[k] = new GUI::Radiobox(wiw, 5, j*20+5, pv[k].ToString().c_str());
|
|
if (GUI::String(pv[k].ToString())==inp->getText()) {
|
|
found = true;
|
|
opt[k]->setChecked(true);
|
|
} else
|
|
opt[k]->setChecked(false);
|
|
opt[k]->addActionHandler(this);
|
|
j++;
|
|
}
|
|
if (!found)
|
|
for(k = 0; k < pv.size(); k++)
|
|
if (pv[k].ToString().size() && pv[k].ToString()==prop->GetValue().ToString())
|
|
opt[k]->setChecked(true);
|
|
scroll_h -= (k-j) * 20;
|
|
wiw->resize(290, scroll_h);
|
|
if (wiw->scroll_pos_h != 0) {
|
|
wiw->enableScrollBars(false/*h*/,true/*v*/);
|
|
wiw->enableBorder(true);
|
|
} else {
|
|
wiw->enableScrollBars(false/*h*/,false/*v*/);
|
|
wiw->enableBorder(false);
|
|
}
|
|
(new GUI::Button(this, 70, scroll_h+90, MSG_Get("OK"), 70))->addActionHandler(this);
|
|
close->move(155,scroll_h+90);
|
|
resize(310, scroll_h+156);
|
|
move(parent->getWidth()>this->getWidth()?(parent->getWidth()-this->getWidth())/2:0,parent->getHeight()>this->getHeight()?(parent->getHeight()-this->getHeight())/2:0);
|
|
|
|
/* first child is first tabbable */
|
|
if (pv.size() > 0) {
|
|
Window *w = opt[0];
|
|
if (w) w->first_tabbable = true;
|
|
}
|
|
|
|
/* last child is first tabbable */
|
|
if (pv.size() > 0) {
|
|
Window *w = opt[pv.size()-1];
|
|
if (w) w->last_tabbable = true;
|
|
}
|
|
|
|
/* the FIRST field needs to come first when tabbed to */
|
|
if (pv.size() > 0) {
|
|
Window *w = opt[0];
|
|
if (w) w->raise();
|
|
}
|
|
}
|
|
|
|
void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) override {
|
|
unsigned int j, k;
|
|
for(k = 0; k < pv.size(); k++) if (pv[k].ToString().size()) {
|
|
if (arg == pv[k].ToString() && opt[k]->isChecked())
|
|
for(j = 0; j < pv.size(); j++)
|
|
if (pv[j].ToString().size() && j!=k) opt[j]->setChecked(false);
|
|
}
|
|
if (arg == MSG_Get("OK")) {
|
|
for(k = 0; k < pv.size(); k++)
|
|
if (pv[k].ToString().size() && opt[k]->isChecked()) {
|
|
inp->setText(pv[k].ToString());
|
|
break;
|
|
}
|
|
ToplevelWindow::actionExecuted(b, GUI::String(MSG_Get("CLOSE")));
|
|
}
|
|
else if (arg == MSG_Get("CLOSE")) {
|
|
ToplevelWindow::actionExecuted(b, arg);
|
|
}
|
|
}
|
|
|
|
~ShowOptions() {
|
|
if (!cfg_sname.empty()) {
|
|
auto i = cfg_windows_active.find(cfg_sname);
|
|
if (i != cfg_windows_active.end()) cfg_windows_active.erase(i);
|
|
}
|
|
}
|
|
};
|
|
|
|
class PropertyEditorString : public PropertyEditor {
|
|
protected:
|
|
GUI::Input *input;
|
|
GUI::Label *label;
|
|
GUI::Button *infoButton = NULL;
|
|
public:
|
|
PropertyEditorString(Window *parent, int x, int y, Section_prop *section, Property *prop, bool opts) :
|
|
PropertyEditor(parent, x, y, section, prop, opts) {
|
|
std::string title(section->GetName());
|
|
if (title=="4dos"&&!strcmp(prop->propname.c_str(), "rem"))
|
|
input = new GUI::Input(this, 30, 0, 470);
|
|
else {
|
|
SetupUI(opts, input, infoButton);
|
|
}
|
|
std::string temps = prop->GetValue().ToString();
|
|
input->setText(stringify(temps));
|
|
label = new GUI::Label(this, 0, 5, prop->propname);
|
|
scan_tabbing = true;
|
|
|
|
/* first child is first tabbable */
|
|
{
|
|
Window *w = this->getChild(0);
|
|
if (w) w->first_tabbable = true;
|
|
}
|
|
|
|
/* last child is first tabbable */
|
|
{
|
|
Window *w = this->getChild(this->getChildCount()-1);
|
|
if (w) w->last_tabbable = true;
|
|
}
|
|
|
|
/* the FIRST field needs to come first when tabbed to */
|
|
{
|
|
Window *w = this->getChild(0);
|
|
if (w) w->raise(); /* NTS: This CHANGES the child element order, getChild(0) will return something else */
|
|
}
|
|
}
|
|
|
|
void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) override {
|
|
if (arg == "...")
|
|
new ShowOptions(getScreen(), 300, 300, MSG_Get("SELECT_VALUE"), ("Property: \033[31m" + prop->propname + "\033[0m\n\n"+(prop->Get_Default_Value().ToString().size()?"Default value: \033[32m"+prop->Get_Default_Value().ToString()+"\033[0m\n\n":"")+"Possible values to select:\n").c_str(), prop, input);
|
|
else
|
|
PropertyEditor::actionExecuted(b, arg);
|
|
}
|
|
|
|
bool prepare(std::string &buffer) override {
|
|
std::string temps = prop->GetValue().ToString();
|
|
if (input->getText() == GUI::String(temps)) return false;
|
|
buffer.append(static_cast<const std::string&>(input->getText()));
|
|
return true;
|
|
}
|
|
|
|
/// Paint label
|
|
void paint(GUI::Drawable &d) const override {
|
|
paintVisGuideLineBetween(d,label,input,this);
|
|
}
|
|
};
|
|
|
|
class PropertyEditorFloat : public PropertyEditor {
|
|
protected:
|
|
GUI::Input *input;
|
|
GUI::Label *label;
|
|
GUI::Button *infoButton = NULL;
|
|
public:
|
|
PropertyEditorFloat(Window *parent, int x, int y, Section_prop *section, Property *prop, bool opts) :
|
|
PropertyEditor(parent, x, y, section, prop, opts) {
|
|
SetupUI(opts, input, infoButton);
|
|
input->setText(stringify((double)prop->GetValue()));
|
|
label = new GUI::Label(this, 0, 5, prop->propname);
|
|
scan_tabbing = true;
|
|
|
|
/* first child is first tabbable */
|
|
{
|
|
Window *w = this->getChild(0);
|
|
if (w) w->first_tabbable = true;
|
|
}
|
|
|
|
/* last child is first tabbable */
|
|
{
|
|
Window *w = this->getChild(this->getChildCount()-1);
|
|
if (w) w->last_tabbable = true;
|
|
}
|
|
|
|
/* the FIRST field needs to come first when tabbed to */
|
|
{
|
|
Window *w = this->getChild(0);
|
|
if (w) w->raise(); /* NTS: This CHANGES the child element order, getChild(0) will return something else */
|
|
}
|
|
}
|
|
|
|
void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) override {
|
|
if (arg == "...")
|
|
new ShowOptions(getScreen(), 300, 300, ("Values for " + prop->propname).c_str(), ("Property: \033[31m" + prop->propname + "\033[0m\n\n"+(prop->Get_Default_Value().ToString().size()?"Default value: \033[32m"+prop->Get_Default_Value().ToString()+"\033[0m\n\n":"")+"Possible values to select:\n").c_str(), prop, input);
|
|
else
|
|
PropertyEditor::actionExecuted(b, arg);
|
|
}
|
|
|
|
bool prepare(std::string &buffer) override {
|
|
double val;
|
|
convert(input->getText(), val, false);
|
|
if (val == (double)prop->GetValue()) return false;
|
|
buffer.append(stringify(val));
|
|
return true;
|
|
}
|
|
|
|
/// Paint label
|
|
void paint(GUI::Drawable &d) const override {
|
|
paintVisGuideLineBetween(d,label,input,this);
|
|
}
|
|
};
|
|
|
|
class PropertyEditorHex : public PropertyEditor {
|
|
protected:
|
|
GUI::Input *input;
|
|
GUI::Label *label;
|
|
GUI::Button *infoButton = NULL;
|
|
public:
|
|
PropertyEditorHex(Window *parent, int x, int y, Section_prop *section, Property *prop, bool opts) :
|
|
PropertyEditor(parent, x, y, section, prop, opts) {
|
|
SetupUI(opts, input, infoButton);
|
|
std::string temps = prop->GetValue().ToString();
|
|
input->setText(temps.c_str());
|
|
label = new GUI::Label(this, 0, 5, prop->propname);
|
|
scan_tabbing = true;
|
|
|
|
/* first child is first tabbable */
|
|
{
|
|
Window *w = this->getChild(0);
|
|
if (w) w->first_tabbable = true;
|
|
}
|
|
|
|
/* last child is first tabbable */
|
|
{
|
|
Window *w = this->getChild(this->getChildCount()-1);
|
|
if (w) w->last_tabbable = true;
|
|
}
|
|
|
|
/* the FIRST field needs to come first when tabbed to */
|
|
{
|
|
Window *w = this->getChild(0);
|
|
if (w) w->raise(); /* NTS: This CHANGES the child element order, getChild(0) will return something else */
|
|
}
|
|
}
|
|
|
|
void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) override {
|
|
if (arg == "...")
|
|
new ShowOptions(getScreen(), 300, 300, ("Values for " + prop->propname).c_str(), ("Property: \033[31m" + prop->propname + "\033[0m\n\n"+(prop->Get_Default_Value().ToString().size()?"Default value: \033[32m"+prop->Get_Default_Value().ToString()+"\033[0m\n\n":"")+"Possible values to select:\n").c_str(), prop, input);
|
|
else
|
|
PropertyEditor::actionExecuted(b, arg);
|
|
}
|
|
|
|
bool prepare(std::string &buffer) override {
|
|
int val;
|
|
convert(input->getText(), val, false, std::hex);
|
|
if ((Hex)val == prop->GetValue()) return false;
|
|
buffer.append(stringify(val, std::hex));
|
|
return true;
|
|
}
|
|
|
|
/// Paint label
|
|
virtual void paint(GUI::Drawable &d) const override {
|
|
paintVisGuideLineBetween(d,label,input,this);
|
|
}
|
|
};
|
|
|
|
class PropertyEditorInt : public PropertyEditor {
|
|
protected:
|
|
GUI::Input *input;
|
|
GUI::Label *label;
|
|
GUI::Button *infoButton = NULL;
|
|
public:
|
|
PropertyEditorInt(Window *parent, int x, int y, Section_prop *section, Property *prop, bool opts) :
|
|
PropertyEditor(parent, x, y, section, prop, opts) {
|
|
SetupUI(opts, input, infoButton);
|
|
//Maybe use ToString() of Value
|
|
input->setText(stringify(static_cast<int>(prop->GetValue())));
|
|
label = new GUI::Label(this, 0, 5, prop->propname);
|
|
scan_tabbing = true;
|
|
|
|
/* first child is first tabbable */
|
|
{
|
|
Window *w = this->getChild(0);
|
|
if (w) w->first_tabbable = true;
|
|
}
|
|
|
|
/* last child is first tabbable */
|
|
{
|
|
Window *w = this->getChild(this->getChildCount()-1);
|
|
if (w) w->last_tabbable = true;
|
|
}
|
|
|
|
/* the FIRST field needs to come first when tabbed to */
|
|
{
|
|
Window *w = this->getChild(0);
|
|
if (w) w->raise(); /* NTS: This CHANGES the child element order, getChild(0) will return something else */
|
|
}
|
|
};
|
|
|
|
void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) override {
|
|
if (arg == "...")
|
|
new ShowOptions(getScreen(), 300, 300, ("Values for " + prop->propname).c_str(), ("Property: \033[31m" + prop->propname + "\033[0m\n\n"+(prop->Get_Default_Value().ToString().size()?"Default value: \033[32m"+prop->Get_Default_Value().ToString()+"\033[0m\n\n":"")+"Possible values to select:\n").c_str(), prop, input);
|
|
else
|
|
PropertyEditor::actionExecuted(b, arg);
|
|
}
|
|
|
|
bool prepare(std::string &buffer) override {
|
|
int val;
|
|
convert(input->getText(), val, false);
|
|
if (val == static_cast<int>(prop->GetValue())) return false;
|
|
buffer.append(stringify(val));
|
|
return true;
|
|
};
|
|
|
|
/// Paint label
|
|
void paint(GUI::Drawable &d) const override {
|
|
paintVisGuideLineBetween(d,label,input,this);
|
|
}
|
|
};
|
|
|
|
std::string dispname="";
|
|
std::string CapName(std::string name) {
|
|
dispname = name;
|
|
if (name=="sdl"||name=="cpu"||name=="midi"||name=="gus"||name=="dos"||name=="ipx"||name=="ne2000")
|
|
std::transform(dispname.begin(), dispname.end(), dispname.begin(), ::toupper);
|
|
else if (name=="dosbox")
|
|
dispname="Main";
|
|
else if (name=="pc98")
|
|
dispname="PC-98";
|
|
else if (name=="dosv")
|
|
dispname="DOS/V";
|
|
else if (name=="ttf")
|
|
dispname="TrueType";
|
|
else if (name=="vsync")
|
|
dispname="VSync";
|
|
else if (name=="4dos")
|
|
dispname="4DOS.INI";
|
|
else if (name=="config")
|
|
dispname="CONFIG.SYS";
|
|
else if (name=="autoexec")
|
|
dispname="AUTOEXEC.BAT";
|
|
else if (name=="sblaster")
|
|
dispname="SB";
|
|
else if (name=="speaker")
|
|
dispname="PC Speaker";
|
|
else if (name=="imfc")
|
|
dispname="IMFC";
|
|
else if (name=="innova")
|
|
dispname="SSI-2001";
|
|
else if (name=="serial")
|
|
dispname="Serial";
|
|
else if (name=="parallel")
|
|
dispname="Parallel";
|
|
else if (name=="fdc, primary")
|
|
dispname="Floppy";
|
|
else if (name=="ide, primary")
|
|
dispname="IDE #1";
|
|
else if (name=="ide, secondary")
|
|
dispname="IDE #2";
|
|
else if (name=="ide, tertiary")
|
|
dispname="IDE #3";
|
|
else if (name=="ide, quaternary")
|
|
dispname="IDE #4";
|
|
else if (name=="ide, quinternary")
|
|
dispname="IDE #5";
|
|
else if (name=="ide, sexternary")
|
|
dispname="IDE #6";
|
|
else if (name=="ide, septernary")
|
|
dispname="IDE #7";
|
|
else if (name=="ide, octernary")
|
|
dispname="IDE #8";
|
|
else if (name=="ethernet, pcap")
|
|
dispname="pcap";
|
|
else if (name=="ethernet, slirp")
|
|
dispname="SLiRP";
|
|
else
|
|
dispname[0] = std::toupper(name[0]);
|
|
return dispname;
|
|
}
|
|
|
|
std::string RestoreName(std::string name) {
|
|
dispname = name;
|
|
if (name=="Main")
|
|
dispname="dosbox";
|
|
else if (name=="PC-98")
|
|
dispname="pc98";
|
|
else if (name=="DOS/V")
|
|
dispname="dosv";
|
|
else if (name=="TrueType")
|
|
dispname="ttf";
|
|
else if (name=="VSync")
|
|
dispname="vsync";
|
|
else if (name=="4DOS.INI")
|
|
dispname="4dos";
|
|
else if (name=="CONFIG.SYS")
|
|
dispname="config";
|
|
else if (name=="AUTOEXEC.BAT")
|
|
dispname="autoexec";
|
|
else if (name=="SB")
|
|
dispname="sblaster";
|
|
else if (name=="PC Speaker")
|
|
dispname="speaker";
|
|
else if (name=="IMFC")
|
|
dispname="imfc";
|
|
else if (name=="SSI-2001")
|
|
dispname="innova";
|
|
else if (name=="Serial")
|
|
dispname="serial";
|
|
else if (name=="Parallel")
|
|
dispname="parallel";
|
|
else if (name=="Floppy")
|
|
dispname="fdc, primary";
|
|
else if (name=="IDE #1")
|
|
dispname="ide, primary";
|
|
else if (name=="IDE #2")
|
|
dispname="ide, secondary";
|
|
else if (name=="IDE #3")
|
|
dispname="ide, tertiary";
|
|
else if (name=="IDE #4")
|
|
dispname="ide, quaternary";
|
|
else if (name=="IDE #5")
|
|
dispname="ide, quinternary";
|
|
else if (name=="IDE #6")
|
|
dispname="ide, sexternary";
|
|
else if (name=="IDE #7")
|
|
dispname="ide, septernary";
|
|
else if (name=="IDE #8")
|
|
dispname="ide, octernary";
|
|
else if (name=="pcap")
|
|
dispname="ethernet, pcap";
|
|
else if (name=="SLiRP")
|
|
dispname="ethernet, slirp";
|
|
return dispname;
|
|
}
|
|
|
|
#if C_DEBUG
|
|
bool ParseCommand(char* str);
|
|
int logwin = true;
|
|
GUI::MessageBox3 *npwin = NULL;
|
|
class EnterDebuggerCommand : public GUI::ToplevelWindow {
|
|
protected:
|
|
GUI::Input *cmd;
|
|
GUI::Button *okButton = NULL, *cancelButton = NULL;
|
|
std::string str = "";
|
|
public:
|
|
EnterDebuggerCommand(GUI::Screen *parent, int x, int y, const char *title) :
|
|
ToplevelWindow(parent, x, y, 400, 110 + GUI::titlebar_y_stop, title) {
|
|
new GUI::Label(this, 5, 10, "Enter debugger command:");
|
|
cmd = new GUI::Input(this, 5, 30, width - 10 - border_left - border_right);
|
|
cmd->setText("");
|
|
okButton=new GUI::Button(this, 100, 65, MSG_Get("OK"), 90);
|
|
okButton->addActionHandler(this);
|
|
cancelButton=new GUI::Button(this, 200, 65, MSG_Get("CANCEL"), 90);
|
|
cancelButton->addActionHandler(this);
|
|
move(parent->getWidth()>this->getWidth()?(parent->getWidth()-this->getWidth())/2:0,parent->getHeight()>this->getHeight()?(parent->getHeight()-this->getHeight())/2:0);
|
|
cmd->raise();
|
|
}
|
|
|
|
void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) override {
|
|
(void)b;//UNUSED
|
|
if (arg == MSG_Get("OK")) {
|
|
ParseCommand(cmd->getText());
|
|
if (npwin) {
|
|
if (logwin) getlogtext(str);
|
|
else getcodetext(str);
|
|
npwin->setText(str);
|
|
npwin->wiw->scroll_pos_y = npwin->wiw->scroll_pos_h;
|
|
}
|
|
}
|
|
if (arg == MSG_Get("OK") || arg == MSG_Get("CANCEL"))
|
|
close();
|
|
}
|
|
|
|
bool keyUp(const GUI::Key &key) override {
|
|
if (GUI::ToplevelWindow::keyUp(key)) return true;
|
|
|
|
if (key.special == GUI::Key::Enter) {
|
|
okButton->executeAction();
|
|
return true;
|
|
}
|
|
|
|
if (key.special == GUI::Key::Escape) {
|
|
cancelButton->executeAction();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
};
|
|
|
|
class LogWindow : public GUI::MessageBox3 {
|
|
public:
|
|
std::vector<GUI::Char> cfg_sname;
|
|
std::string str = "";
|
|
public:
|
|
LogWindow(GUI::Screen *parent, int x, int y) :
|
|
MessageBox3(parent, x, y, 630, "", "") { // 740
|
|
setTitle(MSG_Get("LOGGING_OUTPUT"));
|
|
getlogtext(str);
|
|
setText(str.size()?str:"No logging output available.");
|
|
move(parent->getWidth()>this->getWidth()?(parent->getWidth()-this->getWidth())/2:0,parent->getHeight()>this->getHeight()?(parent->getHeight()-this->getHeight())/2:0);
|
|
};
|
|
|
|
void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) override {
|
|
(void)b;//UNUSED
|
|
if (arg == MSG_Get("DEBUGCMD")) {
|
|
logwin = true;
|
|
auto *np = new EnterDebuggerCommand(static_cast<GUI::Screen*>(parent), 90, 100, "Debugger command");
|
|
np->raise();
|
|
} else if (arg == MSG_Get("CLOSE")) {
|
|
if(shortcut) running=false;
|
|
npwin = NULL;
|
|
}
|
|
}
|
|
|
|
~LogWindow() {
|
|
if (!cfg_sname.empty()) {
|
|
auto i = cfg_windows_active.find(cfg_sname);
|
|
if (i != cfg_windows_active.end()) cfg_windows_active.erase(i);
|
|
}
|
|
}
|
|
};
|
|
|
|
class CodeWindow : public GUI::MessageBox3 {
|
|
public:
|
|
std::vector<GUI::Char> cfg_sname;
|
|
std::string str = "";
|
|
public:
|
|
CodeWindow(GUI::Screen *parent, int x, int y) :
|
|
MessageBox3(parent, x, y, 630, "", "") { // 740
|
|
setTitle(MSG_Get("CODE_OVERVIEW"));
|
|
getcodetext(str);
|
|
setText(str);
|
|
move(parent->getWidth()>this->getWidth()?(parent->getWidth()-this->getWidth())/2:0,parent->getHeight()>this->getHeight()?(parent->getHeight()-this->getHeight())/2:0);
|
|
};
|
|
|
|
void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) override {
|
|
(void)b;//UNUSED
|
|
if (arg == MSG_Get("DEBUGCMD")) {
|
|
logwin = false;
|
|
auto *np = new EnterDebuggerCommand(static_cast<GUI::Screen*>(parent), 90, 100, "Debugger command");
|
|
np->raise();
|
|
} else if (arg == MSG_Get("CLOSE")) {
|
|
if(shortcut) running=false;
|
|
npwin = NULL;
|
|
}
|
|
}
|
|
|
|
~CodeWindow() {
|
|
if (!cfg_sname.empty()) {
|
|
auto i = cfg_windows_active.find(cfg_sname);
|
|
if (i != cfg_windows_active.end()) cfg_windows_active.erase(i);
|
|
}
|
|
}
|
|
};
|
|
|
|
#endif
|
|
|
|
class HelpWindow : public GUI::MessageBox2 {
|
|
public:
|
|
std::vector<GUI::Char> cfg_sname;
|
|
public:
|
|
HelpWindow(GUI::Screen *parent, int x, int y, Section *section) :
|
|
MessageBox2(parent, x, y, 580, "", "") { // 740
|
|
if (section == NULL) {
|
|
LOG_MSG("BUG: HelpWindow constructor called with section == NULL\n");
|
|
return;
|
|
}
|
|
|
|
std::string title(section->GetName());
|
|
sprintf(tmp1, MSG_Get("HELP_FOR"), CapName(title).c_str());
|
|
setTitle(tmp1);
|
|
title[0] = std::toupper(title[0]);
|
|
|
|
Section_prop* sec = dynamic_cast<Section_prop*>(title.substr(0, 4)=="Ide,"?control->GetSection("ide, primary"):section);
|
|
if (sec) {
|
|
std::string msg;
|
|
|
|
Property *property;
|
|
std::vector<Property*> properties;
|
|
auto propertyIndex = 0;
|
|
while ((property = sec->Get_prop(propertyIndex++)))
|
|
{
|
|
properties.push_back(property);
|
|
}
|
|
|
|
std::sort(properties.begin(), properties.end(),[](const Property* a, const Property* b)
|
|
{
|
|
return a->propname < b->propname;
|
|
});
|
|
|
|
for(const auto& p : properties)
|
|
{
|
|
std::string help=title=="4dos"&&p->propname=="rem"?"This is the 4DOS.INI file (if you use 4DOS as the command shell).":p->Get_help();
|
|
if (title!="4dos" && title!="Config" && title!="Autoexec" && !advopt->isChecked() && !p->basic()) continue;
|
|
std::string propvalues = "";
|
|
std::vector<Value> pv = p->GetValues();
|
|
if (p->Get_type()==Value::V_BOOL) {
|
|
// possible values for boolean are true, false
|
|
propvalues += "true, false";
|
|
} else if (p->Get_type()==Value::V_INT) {
|
|
// print min, max for integer values if used
|
|
Prop_int* pint = dynamic_cast <Prop_int*>(p);
|
|
if (pint==NULL) E_Exit("Int property dynamic cast failed.");
|
|
if (pint->getMin() != pint->getMax()) {
|
|
std::ostringstream oss;
|
|
oss << pint->getMin();
|
|
oss << "..";
|
|
oss << pint->getMax();
|
|
propvalues += oss.str();
|
|
}
|
|
}
|
|
for(Bitu k = 0; k < pv.size(); k++) {
|
|
if (pv[k].ToString() =="%u")
|
|
propvalues += MSG_Get("PROGRAM_CONFIG_HLP_POSINT");
|
|
else propvalues += pv[k].ToString();
|
|
if ((k+1) < pv.size() && (title != "Config" || p->propname != "numlock" || pv[k+1].ToString() != "")) propvalues += ", ";
|
|
}
|
|
msg += std::string("\033[31m")+p->propname+":\033[0m\n"+help+(propvalues==""?"":"\nPossible values: \033[32m"+propvalues+"\033[0m")+(p->Get_Default_Value().ToString().size()?"\nDefault value: \033[32m"+p->Get_Default_Value().ToString():"")+"\033[0m"+(p->getChange()==Property::Changeable::OnlyAtStart?"\n(Not changeable at runtime)":"")+"\n\n";
|
|
}
|
|
if (!msg.empty()) msg.replace(msg.end()-1,msg.end(),"");
|
|
setText(msg);
|
|
} else {
|
|
std::string name = section->GetName();
|
|
std::transform(name.begin(), name.end(), name.begin(), (int(*)(int))std::toupper);
|
|
name += "_CONFIGFILE_HELP";
|
|
setText(MSG_Get(name.c_str()));
|
|
}
|
|
wiw->raise(); /* focus on the message, not the close button, so the user can immediately arrow up/down */
|
|
move(parent->getWidth()>this->getWidth()?(parent->getWidth()-this->getWidth())/2:0,parent->getHeight()>this->getHeight()?(parent->getHeight()-this->getHeight())/2:0);
|
|
};
|
|
|
|
~HelpWindow() {
|
|
if (!cfg_sname.empty()) {
|
|
auto i = cfg_windows_active.find(cfg_sname);
|
|
if (i != cfg_windows_active.end()) cfg_windows_active.erase(i);
|
|
}
|
|
}
|
|
};
|
|
|
|
class SectionEditor : public GUI::ToplevelWindow {
|
|
Section_prop * section;
|
|
GUI::Button * closeButton = NULL;
|
|
GUI::WindowInWindow * wiw = NULL;
|
|
public:
|
|
std::vector<GUI::Char> cfg_sname;
|
|
public:
|
|
SectionEditor(GUI::Screen *parent, int x, int y, Section_prop *section) :
|
|
ToplevelWindow(parent, x, y, 0, 0, ""), section(section) {
|
|
if (section == NULL) {
|
|
LOG_MSG("BUG: SectionEditor constructor called with section == NULL\n");
|
|
return;
|
|
}
|
|
proplist = {};
|
|
|
|
int first_row_y = 5;
|
|
int row_height = 25;
|
|
int column_width = 600;
|
|
int button_row_h = (int)GUI::CurrentTheme.ButtonHeight;
|
|
int button_row_padding_y = static_cast<int>(GUI::CurrentTheme.DefaultSpacing);
|
|
|
|
int num_prop = 0, k=0;
|
|
while (section->Get_prop(num_prop) != NULL) {
|
|
if (advopt->isChecked() || section->Get_prop(num_prop)->basic()) k++;
|
|
num_prop++;
|
|
}
|
|
|
|
int allowed_dialog_y = parent->getHeight() - 25 - (border_top + border_bottom) - 50;
|
|
|
|
int items_per_col = k;
|
|
int columns = 1;
|
|
|
|
int scroll_h = items_per_col * row_height;
|
|
if (scroll_h > allowed_dialog_y)
|
|
scroll_h = allowed_dialog_y;
|
|
|
|
scroll_h += 2; /* border */
|
|
|
|
wiw = new GUI::WindowInWindow(this, 5, 5, width-border_left-border_right-10, scroll_h);
|
|
|
|
int button_row_y = first_row_y + scroll_h + 5;
|
|
int button_w = 90;
|
|
int button_pad_w = 10;
|
|
int button_row_w = ((button_pad_w + button_w) * 3) - button_pad_w;
|
|
int button_row_cx = (((columns * column_width) - button_row_w) / 2) + 5;
|
|
|
|
resize((columns * column_width) + border_left + border_right + 2/*wiw border*/ + wiw->vscroll_display_width/*scrollbar*/ + 10,
|
|
button_row_y + button_row_h + button_row_padding_y + border_top + border_bottom);
|
|
|
|
if ((this->y + this->getHeight()) > parent->getHeight())
|
|
move(this->x,parent->getHeight() - this->getHeight());
|
|
|
|
setTitle(CapName(std::string(section->GetName())).c_str());
|
|
|
|
GUI::Button *b = new GUI::Button(this, button_row_cx, button_row_y, mainMenu.get_item("HelpMenu").get_text().c_str(), button_w);
|
|
b->addActionHandler(this);
|
|
|
|
b = new GUI::Button(this, button_row_cx + (button_w + button_pad_w), button_row_y, MSG_Get("OK"), button_w);
|
|
|
|
int i = 0, j = 0;
|
|
Property *property;
|
|
std::vector<Property*> properties;
|
|
auto propertyIndex = 0;
|
|
|
|
while ((property = section->Get_prop(propertyIndex++)))
|
|
{
|
|
properties.push_back(property);
|
|
}
|
|
|
|
std::sort(properties.begin(), properties.end(),[](const Property* a, const Property* b)
|
|
{
|
|
return a->propname < b->propname;
|
|
});
|
|
|
|
for(const auto & prop : properties)
|
|
{
|
|
if (!advopt->isChecked() && !prop->basic()) {i++;continue;}
|
|
Prop_bool *pbool = dynamic_cast<Prop_bool*>(prop);
|
|
Prop_int *pint = dynamic_cast<Prop_int*>(prop);
|
|
Prop_double *pdouble = dynamic_cast<Prop_double*>(prop);
|
|
Prop_hex *phex = dynamic_cast<Prop_hex*>(prop);
|
|
Prop_string *pstring = dynamic_cast<Prop_string*>(prop);
|
|
Prop_multival* pmulti = dynamic_cast<Prop_multival*>(prop);
|
|
Prop_multival_remain* pmulti_remain = dynamic_cast<Prop_multival_remain*>(prop);
|
|
bool opts = !prop->suggested_values.empty()&&prop->GetValues().size()>1;
|
|
|
|
PropertyEditor *p;
|
|
if (pbool) p = new PropertyEditorBool(wiw, column_width*(j/items_per_col), (j%items_per_col)*row_height, section, prop, opts);
|
|
else if (phex) p = new PropertyEditorHex(wiw, column_width*(j/items_per_col), (j%items_per_col)*row_height, section, prop, opts);
|
|
else if (pint) p = new PropertyEditorInt(wiw, column_width*(j/items_per_col), (j%items_per_col)*row_height, section, prop, opts);
|
|
else if (pdouble) p = new PropertyEditorFloat(wiw, column_width*(j/items_per_col), (j%items_per_col)*row_height, section, prop, opts);
|
|
else if (pstring) p = new PropertyEditorString(wiw, column_width*(j/items_per_col), (j%items_per_col)*row_height, section, prop, opts);
|
|
else if (pmulti) p = new PropertyEditorString(wiw, column_width*(j/items_per_col), (j%items_per_col)*row_height, section, prop, opts);
|
|
else if (pmulti_remain) p = new PropertyEditorString(wiw, column_width*(j/items_per_col), (j%items_per_col)*row_height, section, prop, opts);
|
|
else { i++; continue; }
|
|
b->addActionHandler(p);
|
|
i++;
|
|
j++;
|
|
}
|
|
b->addActionHandler(this);
|
|
|
|
b = new GUI::Button(this, button_row_cx + (button_w + button_pad_w)*2, button_row_y, MSG_Get("CANCEL"), button_w);
|
|
b->addActionHandler(this);
|
|
scan_tabbing = true;
|
|
closeButton = b;
|
|
|
|
/* first child is first tabbable */
|
|
{
|
|
Window *w = wiw->getChild(0);
|
|
if (w) w->first_tabbable = true;
|
|
}
|
|
|
|
/* last child is first tabbable */
|
|
{
|
|
Window *w = wiw->getChild(wiw->getChildCount()-1);
|
|
if (w) w->last_tabbable = true;
|
|
}
|
|
|
|
/* the FIRST field needs to come first when tabbed to */
|
|
{
|
|
Window *w = wiw->getChild(0);
|
|
if (w) w->raise(); /* NTS: This CHANGES the child element order, getChild(0) will return something else */
|
|
}
|
|
|
|
wiw->resize((columns * column_width) + 2/*border*/ + wiw->vscroll_display_width, scroll_h);
|
|
|
|
if (wiw->scroll_pos_h != 0) {
|
|
wiw->enableScrollBars(false/*h*/,true/*v*/);
|
|
wiw->enableBorder(true);
|
|
}
|
|
else {
|
|
wiw->enableScrollBars(false/*h*/,false/*v*/);
|
|
wiw->enableBorder(false);
|
|
|
|
resize((columns * column_width) + border_left + border_right + 2/*wiw border*/ + /*wiw->vscroll_display_width*//*scrollbar*/ + 10,
|
|
button_row_y + button_row_h + button_row_padding_y + border_top + border_bottom);
|
|
}
|
|
move(parent->getWidth()>this->getWidth()?(parent->getWidth()-this->getWidth())/2:0,parent->getHeight()>this->getHeight()?(parent->getHeight()-this->getHeight())/2:0);
|
|
}
|
|
|
|
~SectionEditor() {
|
|
if (!cfg_sname.empty()) {
|
|
auto i = cfg_windows_active.find(cfg_sname);
|
|
if (i != cfg_windows_active.end()) cfg_windows_active.erase(i);
|
|
}
|
|
}
|
|
|
|
void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) override {
|
|
strcpy(tmp1, mainMenu.get_item("HelpMenu").get_text().c_str());
|
|
if (arg == MSG_Get("OK") && proplist.size()) { close(); running=false; if(!shortcut) resetcfg=true; }
|
|
else if (arg == MSG_Get("OK") || arg == MSG_Get("CANCEL") || arg == MSG_Get("CLOSE")) { close(); if(shortcut) running=false; }
|
|
else if (arg == tmp1) {
|
|
std::vector<GUI::Char> new_cfg_sname;
|
|
|
|
if (!cfg_sname.empty()) {
|
|
// new_cfg_sname = "help_";
|
|
new_cfg_sname.resize(5);
|
|
new_cfg_sname[0] = 'h';
|
|
new_cfg_sname[1] = 'e';
|
|
new_cfg_sname[2] = 'l';
|
|
new_cfg_sname[3] = 'p';
|
|
new_cfg_sname[4] = '_';
|
|
new_cfg_sname.insert(new_cfg_sname.end(),cfg_sname.begin(),cfg_sname.end());
|
|
}
|
|
|
|
auto lookup = cfg_windows_active.find(new_cfg_sname);
|
|
if (lookup == cfg_windows_active.end()) {
|
|
int nx = getX() - 10;
|
|
int ny = getY() - 10;
|
|
if (nx < 0) nx = 0;
|
|
if (ny < 0) ny = 0;
|
|
auto *np = new HelpWindow(static_cast<GUI::Screen*>(parent), nx, ny, section);
|
|
cfg_windows_active[new_cfg_sname] = np;
|
|
np->cfg_sname = new_cfg_sname;
|
|
np->raise();
|
|
}
|
|
else {
|
|
lookup->second->raise();
|
|
}
|
|
}
|
|
else
|
|
ToplevelWindow::actionExecuted(b, arg);
|
|
}
|
|
|
|
bool keyDown(const GUI::Key &key) override {
|
|
if (GUI::ToplevelWindow::keyDown(key)) return true;
|
|
return false;
|
|
}
|
|
|
|
bool keyUp(const GUI::Key &key) override {
|
|
if (GUI::ToplevelWindow::keyUp(key)) return true;
|
|
|
|
if (key.special == GUI::Key::Escape) {
|
|
closeButton->executeAction();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
};
|
|
|
|
class ConfigEditor : public GUI::ToplevelWindow {
|
|
GUI::Button *closeButton = NULL;
|
|
Section_prop * section;
|
|
GUI::Input *content = NULL;
|
|
GUI::WindowInWindow * wiw = NULL;
|
|
public:
|
|
std::vector<GUI::Char> cfg_sname;
|
|
public:
|
|
ConfigEditor(GUI::Screen *parent, int x, int y, Section_prop *section) :
|
|
ToplevelWindow(parent, x, y, 510, 260 + GUI::titlebar_y_stop, ""), section(section) {
|
|
if (section == NULL) {
|
|
LOG_MSG("BUG: ConfigEditor constructor called with section == NULL\n");
|
|
return;
|
|
}
|
|
|
|
int first_row_y = 5;
|
|
int row_height = 25;
|
|
int column_width = 500;
|
|
int button_row_h = 26;
|
|
int button_row_padding_y = 5 + 5;
|
|
|
|
int num_prop = 0;
|
|
while (section->Get_prop(num_prop) != NULL) num_prop++;
|
|
|
|
int allowed_dialog_y = parent->getHeight() - 25 - (border_top + border_bottom) - 50;
|
|
|
|
int items_per_col = num_prop;
|
|
int columns = 1;
|
|
|
|
int scroll_h = items_per_col * row_height;
|
|
if (scroll_h > allowed_dialog_y)
|
|
scroll_h = allowed_dialog_y;
|
|
|
|
setTitle(CapName(std::string(section->GetName())).c_str());
|
|
|
|
char extra_data[4096] = { 0 };
|
|
const char * extra = const_cast<char*>(section->data.c_str());
|
|
if (extra) {
|
|
std::istringstream in(extra);
|
|
char linestr[CROSS_LEN+1], cmdstr[CROSS_LEN], valstr[CROSS_LEN];
|
|
char *cmd=cmdstr, *val=valstr, *p;
|
|
if (in) for (std::string line; std::getline(in, line); ) {
|
|
if (line.length()>CROSS_LEN) {
|
|
strncpy(linestr, line.c_str(), CROSS_LEN);
|
|
linestr[CROSS_LEN]=0;
|
|
} else
|
|
strcpy(linestr, line.c_str());
|
|
p=strchr(linestr, '=');
|
|
if (p!=NULL) {
|
|
*p=0;
|
|
strcpy(cmd, linestr);
|
|
strcpy(val, p+1);
|
|
cmd=trim(cmd);
|
|
val=trim(val);
|
|
if (strcasecmp(cmd, "rem")&&strlen(extra_data)+strlen(cmd)+strlen(val)+3<4096&&(title=="4dos"||!strncasecmp(cmd, "set ", 4)||!strcasecmp(cmd, "install")||!strcasecmp(cmd, "installhigh")||!strcasecmp(cmd, "device")||!strcasecmp(cmd, "devicehigh"))) {
|
|
strcat(extra_data, cmd);
|
|
strcat(extra_data, "=");
|
|
strcat(extra_data, val);
|
|
strcat(extra_data, "\r\n");
|
|
}
|
|
} else if (title=="Config"&&!strncasecmp(line.c_str(), "rem ", 4)) {
|
|
strcat(extra_data, line.c_str());
|
|
strcat(extra_data, "\r\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
int height=title=="Config"?100:81;
|
|
scroll_h += height + 2; /* border */
|
|
|
|
wiw = new GUI::WindowInWindow(this, 5, 5, width-border_left-border_right-10, scroll_h);
|
|
|
|
int button_row_y = first_row_y + scroll_h + 5;
|
|
int button_w = 90;
|
|
int button_pad_w = 10;
|
|
int button_row_w = ((button_pad_w + button_w) * 4 + button_w) - button_pad_w;
|
|
int button_row_cx = (((columns * column_width) - button_row_w) / 2) + 5;
|
|
|
|
resize((columns * column_width) + border_left + border_right + 2/*wiw border*/ + wiw->vscroll_display_width/*scrollbar*/ + 10,
|
|
button_row_y + button_row_h + button_row_padding_y + border_top + border_bottom);
|
|
|
|
if ((this->y + this->getHeight()) > parent->getHeight())
|
|
move(this->x,parent->getHeight() - this->getHeight());
|
|
|
|
new GUI::Label(this, 5, button_row_y-height, MSG_Get(title=="Config"?"ADDITION_CONTENT":"CONTENT"));
|
|
content = new GUI::Input(this, 5, button_row_y-height+20, 510 - border_left - border_right, height-25);
|
|
content->setText(extra_data);
|
|
|
|
GUI::Button *b = new GUI::Button(this, button_row_cx, button_row_y, MSG_Get("PASTE_CLIPBOARD"), button_w*2);
|
|
b->addActionHandler(this);
|
|
|
|
b = new GUI::Button(this, button_row_cx + button_w + (button_w + button_pad_w), button_row_y, mainMenu.get_item("HelpMenu").get_text().c_str(), button_w);
|
|
b->addActionHandler(this);
|
|
|
|
b = new GUI::Button(this, button_row_cx + button_w + (button_w + button_pad_w)*2, button_row_y, MSG_Get("OK"), button_w);
|
|
|
|
int i = 0;
|
|
Property *prop;
|
|
while ((prop = section->Get_prop(i))) {
|
|
Prop_bool *pbool = dynamic_cast<Prop_bool*>(prop);
|
|
Prop_int *pint = dynamic_cast<Prop_int*>(prop);
|
|
Prop_double *pdouble = dynamic_cast<Prop_double*>(prop);
|
|
Prop_hex *phex = dynamic_cast<Prop_hex*>(prop);
|
|
Prop_string *pstring = dynamic_cast<Prop_string*>(prop);
|
|
Prop_multival* pmulti = dynamic_cast<Prop_multival*>(prop);
|
|
Prop_multival_remain* pmulti_remain = dynamic_cast<Prop_multival_remain*>(prop);
|
|
bool opts = !prop->suggested_values.empty()&&prop->GetValues().size()>1;
|
|
|
|
PropertyEditor *p;
|
|
if (pbool) p = new PropertyEditorBool(wiw, column_width*(i/items_per_col), (i%items_per_col)*row_height, section, prop, opts);
|
|
else if (phex) p = new PropertyEditorHex(wiw, column_width*(i/items_per_col), (i%items_per_col)*row_height, section, prop, opts);
|
|
else if (pint) p = new PropertyEditorInt(wiw, column_width*(i/items_per_col), (i%items_per_col)*row_height, section, prop, opts);
|
|
else if (pdouble) p = new PropertyEditorFloat(wiw, column_width*(i/items_per_col), (i%items_per_col)*row_height, section, prop, opts);
|
|
else if (pstring) p = new PropertyEditorString(wiw, column_width*(i/items_per_col), (i%items_per_col)*row_height, section, prop, opts);
|
|
else if (pmulti) p = new PropertyEditorString(wiw, column_width*(i/items_per_col), (i%items_per_col)*row_height, section, prop, opts);
|
|
else if (pmulti_remain) p = new PropertyEditorString(wiw, column_width*(i/items_per_col), (i%items_per_col)*row_height, section, prop, opts);
|
|
else { i++; continue; }
|
|
b->addActionHandler(p);
|
|
i++;
|
|
}
|
|
b->addActionHandler(this);
|
|
|
|
b = new GUI::Button(this, button_row_cx + button_w + (button_w + button_pad_w)*3, button_row_y, MSG_Get("CANCEL"), button_w);
|
|
b->addActionHandler(this);
|
|
scan_tabbing = true;
|
|
closeButton = b;
|
|
|
|
/* first child is first tabbable */
|
|
{
|
|
Window *w = wiw->getChild(0);
|
|
if (w) w->first_tabbable = true;
|
|
}
|
|
|
|
/* last child is first tabbable */
|
|
{
|
|
Window *w = wiw->getChild(wiw->getChildCount()-1);
|
|
if (w) w->last_tabbable = true;
|
|
}
|
|
|
|
/* the FIRST field needs to come first when tabbed to */
|
|
{
|
|
Window *w = wiw->getChild(0);
|
|
if (w) w->raise(); /* NTS: This CHANGES the child element order, getChild(0) will return something else */
|
|
}
|
|
|
|
wiw->resize((columns * column_width) + 2/*border*/ + wiw->vscroll_display_width, scroll_h);
|
|
|
|
if (wiw->scroll_pos_h != 0) {
|
|
wiw->enableScrollBars(false/*h*/,true/*v*/);
|
|
wiw->enableBorder(true);
|
|
}
|
|
else {
|
|
wiw->enableScrollBars(false/*h*/,false/*v*/);
|
|
wiw->enableBorder(false);
|
|
|
|
resize((columns * column_width) + border_left + border_right + 2/*wiw border*/ + /*wiw->vscroll_display_width*//*scrollbar*/ + 10,
|
|
button_row_y + button_row_h + button_row_padding_y + border_top + border_bottom);
|
|
}
|
|
move(parent->getWidth()>this->getWidth()?(parent->getWidth()-this->getWidth())/2:0,parent->getHeight()>this->getHeight()?(parent->getHeight()-this->getHeight())/2:0);
|
|
}
|
|
|
|
~ConfigEditor() {
|
|
if (!cfg_sname.empty()) {
|
|
auto i = cfg_windows_active.find(cfg_sname);
|
|
if (i != cfg_windows_active.end()) cfg_windows_active.erase(i);
|
|
}
|
|
}
|
|
|
|
void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) override {
|
|
if (arg == MSG_Get("OK")) section->data = *(std::string*)content->getText();
|
|
std::string lines = *(std::string*)content->getText();
|
|
strcpy(tmp1, mainMenu.get_item("HelpMenu").get_text().c_str());
|
|
if (arg == MSG_Get("OK") || arg == MSG_Get("CANCEL") || arg == MSG_Get("CLOSE")) { close(); if(shortcut) running=false; }
|
|
else if (arg == tmp1) {
|
|
std::vector<GUI::Char> new_cfg_sname;
|
|
|
|
if (!cfg_sname.empty()) {
|
|
// new_cfg_sname = "help_";
|
|
new_cfg_sname.resize(5);
|
|
new_cfg_sname[0] = 'h';
|
|
new_cfg_sname[1] = 'e';
|
|
new_cfg_sname[2] = 'l';
|
|
new_cfg_sname[3] = 'p';
|
|
new_cfg_sname[4] = '_';
|
|
new_cfg_sname.insert(new_cfg_sname.end(),cfg_sname.begin(),cfg_sname.end());
|
|
}
|
|
|
|
auto lookup = cfg_windows_active.find(new_cfg_sname);
|
|
if (lookup == cfg_windows_active.end()) {
|
|
int nx = getX() - 10;
|
|
int ny = getY() - 10;
|
|
if (nx < 0) nx = 0;
|
|
if (ny < 0) ny = 0;
|
|
auto *np = new HelpWindow(static_cast<GUI::Screen*>(parent), nx, ny, section);
|
|
cfg_windows_active[new_cfg_sname] = np;
|
|
np->cfg_sname = new_cfg_sname;
|
|
np->raise();
|
|
}
|
|
else {
|
|
lookup->second->raise();
|
|
}
|
|
} else if (arg == MSG_Get("PASTE_CLIPBOARD")) {
|
|
strPasteBuffer="";
|
|
swapad=false;
|
|
PasteClipboard(true);
|
|
swapad=true;
|
|
unsigned char head;
|
|
GUI::Key *key;
|
|
GUI::Key::Special ksym = (GUI::Key::Special)0;
|
|
while (strPasteBuffer.length()) {
|
|
key = NULL;
|
|
head = strPasteBuffer[0];
|
|
if (head == 9) for (int i=0; i<8; i++) key = new GUI::Key(' ', ksym, false, false, false, false);
|
|
else if (head == 13) key = new GUI::Key(0, GUI::Key::Enter, false, false, false, false);
|
|
else if (head > 31) key = new GUI::Key(head, ksym, false, false, false, false);
|
|
if (key != NULL) content->keyDown(*key);
|
|
strPasteBuffer = strPasteBuffer.substr(1, strPasteBuffer.length());
|
|
}
|
|
return;
|
|
} else ToplevelWindow::actionExecuted(b, arg);
|
|
}
|
|
|
|
bool keyDown(const GUI::Key &key) override {
|
|
if (GUI::ToplevelWindow::keyDown(key)) return true;
|
|
return false;
|
|
}
|
|
|
|
bool keyUp(const GUI::Key &key) override {
|
|
if (GUI::ToplevelWindow::keyUp(key)) return true;
|
|
|
|
if (key.special == GUI::Key::Escape) {
|
|
closeButton->executeAction();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
};
|
|
|
|
class AutoexecEditor : public GUI::ToplevelWindow {
|
|
GUI::Button *closeButton = NULL, *pasteButton = NULL, *appendButton = NULL;
|
|
Section_line * section;
|
|
GUI::Input *content = NULL;
|
|
public:
|
|
std::vector<GUI::Char> cfg_sname;
|
|
public:
|
|
AutoexecEditor(GUI::Screen *parent, int x, int y, Section_line *section) :
|
|
ToplevelWindow(parent, x, y, 550, 310 + GUI::titlebar_y_stop, ""), section(section) {
|
|
if (section == NULL) {
|
|
LOG_MSG("BUG: AutoexecEditor constructor called with section == NULL\n");
|
|
return;
|
|
}
|
|
|
|
std::string title(section->GetName());
|
|
title[0] = std::toupper(title[0]);
|
|
sprintf(tmp1, MSG_Get("EDIT_FOR"), title.c_str());
|
|
setTitle(tmp1);
|
|
new GUI::Label(this, 5, 10, MSG_Get("CONTENT"));
|
|
content = new GUI::Input(this, 5, 30, 550 - 10 - border_left - border_right, 185);
|
|
content->setText(section->data);
|
|
(pasteButton = new GUI::Button(this, 5, 220, MSG_Get("PASTE_CLIPBOARD")))->addActionHandler(this);
|
|
int last = 25 + pasteButton->getWidth();
|
|
if (first_shell) {
|
|
(appendButton = new GUI::Button(this, last, 220, MSG_Get("APPEND_HISTORY")))->addActionHandler(this);
|
|
last += 20 + appendButton->getWidth();
|
|
}
|
|
if (shell_idle) (new GUI::Button(this, last, 220, MSG_Get("EXECUTE_NOW")))->addActionHandler(this);
|
|
(new GUI::Button(this, 180, 260, MSG_Get("OK"), 90))->addActionHandler(this);
|
|
(closeButton = new GUI::Button(this, 285, 260, MSG_Get("CANCEL"), 90))->addActionHandler(this);
|
|
move(parent->getWidth()>this->getWidth()?(parent->getWidth()-this->getWidth())/2:0,parent->getHeight()>this->getHeight()?(parent->getHeight()-this->getHeight())/2:0);
|
|
}
|
|
|
|
~AutoexecEditor() {
|
|
if (!cfg_sname.empty()) {
|
|
auto i = cfg_windows_active.find(cfg_sname);
|
|
if (i != cfg_windows_active.end()) cfg_windows_active.erase(i);
|
|
}
|
|
}
|
|
|
|
void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) override {
|
|
if (arg == MSG_Get("OK")) section->data = *(std::string*)content->getText();
|
|
if (arg == MSG_Get("OK") || arg == MSG_Get("CANCEL") || arg == MSG_Get("CLOSE")) { close(); if(shortcut) running=false; }
|
|
else if (arg == MSG_Get("PASTE_CLIPBOARD")) {
|
|
strPasteBuffer="";
|
|
swapad=false;
|
|
PasteClipboard(true);
|
|
swapad=true;
|
|
unsigned char head;
|
|
GUI::Key *key;
|
|
GUI::Key::Special ksym = (GUI::Key::Special)0;
|
|
while (strPasteBuffer.length()) {
|
|
key = NULL;
|
|
head = strPasteBuffer[0];
|
|
if (head == 9) for (int i=0; i<8; i++) key = new GUI::Key(' ', ksym, false, false, false, false);
|
|
else if (head == 13) key = new GUI::Key(0, GUI::Key::Enter, false, false, false, false);
|
|
else if (head > 31) key = new GUI::Key(head, ksym, false, false, false, false);
|
|
if (key != NULL) content->keyDown(*key);
|
|
strPasteBuffer = strPasteBuffer.substr(1, strPasteBuffer.length());
|
|
}
|
|
return;
|
|
} else if (arg == MSG_Get("APPEND_HISTORY")) {
|
|
std::list<std::string>::reverse_iterator i = first_shell->l_history.rbegin();
|
|
std::string lines = *(std::string*)content->getText();
|
|
while (i != first_shell->l_history.rend()) {
|
|
lines += "\n";
|
|
lines += *i;
|
|
++i;
|
|
}
|
|
content->setText(lines);
|
|
} else if (arg == MSG_Get("EXECUTE_NOW")) {
|
|
UI_RunCommands(dynamic_cast<GUI::ScreenSDL*>(getScreen()), content->getText());
|
|
} else ToplevelWindow::actionExecuted(b, arg);
|
|
}
|
|
|
|
bool keyDown(const GUI::Key &key) override {
|
|
if (GUI::ToplevelWindow::keyDown(key)) return true;
|
|
return false;
|
|
}
|
|
|
|
bool keyUp(const GUI::Key &key) override {
|
|
if (GUI::ToplevelWindow::keyUp(key)) return true;
|
|
|
|
if (key.special == GUI::Key::Escape) {
|
|
closeButton->executeAction();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
};
|
|
|
|
class SaveDialog : public GUI::ToplevelWindow {
|
|
protected:
|
|
GUI::Input *name;
|
|
GUI::Button *saveButton = NULL, *closeButton = NULL;
|
|
public:
|
|
SaveDialog(GUI::Screen *parent, int x, int y, const char *title) :
|
|
ToplevelWindow(parent, x, y, 620, 160 + GUI::titlebar_y_stop, title) {
|
|
new GUI::Label(this, 5, 10, MSG_Get("CONFIG_SAVETO"));
|
|
name = new GUI::Input(this, 5, 30, width - 10 - border_left - border_right);
|
|
std::string fullpath;
|
|
if (control->configfiles.size())
|
|
fullpath = control->configfiles[0];
|
|
else
|
|
fullpath = "dosbox-x.conf";
|
|
name->setText(fullpath.c_str());
|
|
(new GUI::Button(this, 5, 60, MSG_Get("USE_PRIMARYCONFIG"), 200))->addActionHandler(this);
|
|
(new GUI::Button(this, 210, 60, MSG_Get("USE_PORTABLECONFIG"), 210))->addActionHandler(this);
|
|
(new GUI::Button(this, 425, 60, MSG_Get("USE_USERCONFIG"), 180))->addActionHandler(this);
|
|
Section_prop * section=static_cast<Section_prop *>(control->GetSection("dosbox"));
|
|
saveall = new GUI::Checkbox(this, 5, 95, MSG_Get("CONFIG_SAVEALL"));
|
|
saveall->setChecked(section->Get_bool("show advanced options"));
|
|
(saveButton = new GUI::Button(this, 128, 120, MSG_Get("SAVE"), 90))->addActionHandler(this);
|
|
(new GUI::Button(this, 220, 120, MSG_Get("SAVE_RESTART"), 170))->addActionHandler(this);
|
|
(closeButton = new GUI::Button(this, 392, 120, MSG_Get("CANCEL"), 90))->addActionHandler(this);
|
|
move(parent->getWidth()>this->getWidth()?(parent->getWidth()-this->getWidth())/2:0,parent->getHeight()>this->getHeight()?(parent->getHeight()-this->getHeight())/2:0);
|
|
|
|
name->raise(); /* make sure keyboard focus is on the text field, ready for the user */
|
|
name->posToEnd(); /* position the cursor at the end where the user is most likely going to edit */
|
|
}
|
|
|
|
void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) override {
|
|
(void)b;//UNUSED
|
|
if (arg == MSG_Get("USE_PORTABLECONFIG")) {
|
|
name->setText("dosbox-x.conf");
|
|
return;
|
|
}
|
|
if (arg == MSG_Get("USE_PRIMARYCONFIG")) {
|
|
if (control->configfiles.size())
|
|
name->setText(control->configfiles[0]);
|
|
return;
|
|
}
|
|
if (arg == MSG_Get("USE_USERCONFIG")) {
|
|
std::string config_path;
|
|
Cross::GetPlatformConfigDir(config_path);
|
|
std::string fullpath,file;
|
|
Cross::GetPlatformConfigName(file);
|
|
const size_t last_slash_idx = config_path.find_last_of("\\/");
|
|
if (std::string::npos != last_slash_idx) {
|
|
fullpath = config_path.substr(0, last_slash_idx);
|
|
fullpath += CROSS_FILESPLIT;
|
|
fullpath += file;
|
|
} else
|
|
fullpath = file;
|
|
name->setText(fullpath);
|
|
return;
|
|
}
|
|
if (arg == MSG_Get("SAVE") || arg == MSG_Get("SAVE_RESTART")) control->PrintConfig(name->getText(), saveall->isChecked()?1:-1);
|
|
if (arg == MSG_Get("SAVE_RESTART")) RebootConfig((const char*)name->getText(), true);
|
|
close();
|
|
if(shortcut) running=false;
|
|
}
|
|
|
|
virtual bool keyUp(const GUI::Key &key) override {
|
|
if (GUI::ToplevelWindow::keyUp(key)) return true;
|
|
|
|
if (key.special == GUI::Key::Enter) {
|
|
saveButton->executeAction();
|
|
return true;
|
|
}
|
|
|
|
if (key.special == GUI::Key::Escape) {
|
|
closeButton->executeAction();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
};
|
|
|
|
class SaveLangDialog : public GUI::ToplevelWindow {
|
|
protected:
|
|
GUI::Input *name, *lang;
|
|
GUI::Button *saveButton = NULL, *closeButton = NULL;
|
|
public:
|
|
SaveLangDialog(GUI::Screen *parent, int x, int y, const char *title) :
|
|
ToplevelWindow(parent, x, y, 400, 150 + GUI::titlebar_y_stop, title) {
|
|
new GUI::Label(this, 5, 10, MSG_Get("LANG_FILENAME"));
|
|
name = new GUI::Input(this, 5, 30, width - 10 - border_left - border_right);
|
|
name->setText(control->opt_lang != "" ? control->opt_lang.c_str() : "messages.lng");
|
|
new GUI::Label(this, 5, 60, MSG_Get("LANG_LANGNAME"));
|
|
lang = new GUI::Input(this, 5, 80, width - 10 - border_left - border_right);
|
|
lang->setText(langname.c_str());
|
|
(saveButton = new GUI::Button(this, 100, 110, MSG_Get("OK"), 90))->addActionHandler(this);
|
|
(closeButton = new GUI::Button(this, 200, 110, MSG_Get("CANCEL"), 90))->addActionHandler(this);
|
|
move(parent->getWidth()>this->getWidth()?(parent->getWidth()-this->getWidth())/2:0,parent->getHeight()>this->getHeight()?(parent->getHeight()-this->getHeight())/2:0);
|
|
|
|
name->raise(); /* make sure keyboard focus is on the text field, ready for the user */
|
|
name->posToEnd(); /* position the cursor at the end where the user is most likely going to edit */
|
|
}
|
|
|
|
void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) override {
|
|
(void)b;//UNUSED
|
|
if (arg == MSG_Get("OK")) MSG_Write(name->getText(), lang->getText());
|
|
close();
|
|
if(shortcut) running=false;
|
|
}
|
|
|
|
bool keyUp(const GUI::Key &key) override {
|
|
if (GUI::ToplevelWindow::keyUp(key)) return true;
|
|
|
|
if (key.special == GUI::Key::Enter) {
|
|
saveButton->executeAction();
|
|
return true;
|
|
}
|
|
|
|
if (key.special == GUI::Key::Escape) {
|
|
closeButton->executeAction();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
};
|
|
|
|
// override Input field with one that responds to the Enter key as a keyboard-based cue to click "OK"
|
|
class InputWithEnterKey : public GUI::Input {
|
|
public:
|
|
InputWithEnterKey(Window *parent, int x, int y, int w, int h = 0) : GUI::Input(parent,x,y,w,h) { };
|
|
public:
|
|
void set_trigger_target(GUI::ToplevelWindow *_who) { trigger_who = _who; };
|
|
protected:
|
|
GUI::ToplevelWindow* trigger_who = NULL;
|
|
public:
|
|
std::string trigger_enter = MSG_Get("OK");
|
|
std::string trigger_esc = MSG_Get("CANCEL");
|
|
public:
|
|
bool keyDown(const GUI::Key &key) override {
|
|
if (key.special == GUI::Key::Special::Enter) {
|
|
if (trigger_who != NULL && !trigger_enter.empty())
|
|
trigger_who->actionExecuted(this, trigger_enter);
|
|
|
|
return true;
|
|
}
|
|
else if (key.special == GUI::Key::Special::Escape) {
|
|
if (trigger_who != NULL && !trigger_esc.empty())
|
|
trigger_who->actionExecuted(this, trigger_esc);
|
|
|
|
return true;
|
|
}
|
|
else {
|
|
return GUI::Input::keyDown(key);
|
|
}
|
|
}
|
|
};
|
|
|
|
extern double vga_force_refresh_rate;
|
|
void SetRate(char *x);
|
|
class SetRefreshRate : public GUI::ToplevelWindow {
|
|
protected:
|
|
InputWithEnterKey *name;
|
|
public:
|
|
SetRefreshRate(GUI::Screen *parent, int x, int y, const char *title) :
|
|
ToplevelWindow(parent, x, y, 400, 100 + GUI::titlebar_y_stop, title) {
|
|
new GUI::Label(this, 5, 10, "Enter video refresh rate (0 = unlocked):");
|
|
name = new InputWithEnterKey(this, 5, 30, width - 10 - border_left - border_right);
|
|
name->set_trigger_target(this);
|
|
std::ostringstream str;
|
|
str << (vga_force_refresh_rate < 0 ? 0 : vga_force_refresh_rate);
|
|
|
|
std::string rates=str.str();
|
|
name->setText(rates.c_str());
|
|
(new GUI::Button(this, 100, 60, MSG_Get("OK"), 90))->addActionHandler(this);
|
|
(new GUI::Button(this, 200, 60, MSG_Get("CANCEL"), 90))->addActionHandler(this);
|
|
move(parent->getWidth()>this->getWidth()?(parent->getWidth()-this->getWidth())/2:0,parent->getHeight()>this->getHeight()?(parent->getHeight()-this->getHeight())/2:0);
|
|
|
|
name->raise(); /* make sure keyboard focus is on the text field, ready for the user */
|
|
name->posToEnd(); /* position the cursor at the end where the user is most likely going to edit */
|
|
}
|
|
|
|
void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) override {
|
|
(void)b;//UNUSED
|
|
if (arg == MSG_Get("OK")) {
|
|
char *str = (char*)name->getText();
|
|
if (str == NULL || !strcmp(str, "0"))
|
|
vga_force_refresh_rate = -1;
|
|
else
|
|
SetRate(str);
|
|
if (vga_force_refresh_rate > 0)
|
|
LOG_MSG("Video refresh rate is locked to %.3f fps.",vga_force_refresh_rate);
|
|
else
|
|
LOG_MSG("Video refresh rate is unlocked.");
|
|
}
|
|
close();
|
|
if(shortcut) running=false;
|
|
}
|
|
};
|
|
|
|
class SetSensitivity : public GUI::ToplevelWindow {
|
|
protected:
|
|
InputWithEnterKey *name;
|
|
public:
|
|
SetSensitivity(GUI::Screen *parent, int x, int y, const char *title) :
|
|
ToplevelWindow(parent, x, y, 400, 100 + GUI::titlebar_y_stop, title) {
|
|
new GUI::Label(this, 5, 10, "Enter mouse sensitivity (x-sen,y-sen):");
|
|
// name = new GUI::Input(this, 5, 30, 350);
|
|
name = new InputWithEnterKey(this, 5, 30, width - 10 - border_left - border_right);
|
|
name->set_trigger_target(this);
|
|
std::ostringstream str;
|
|
str << sdl.mouse.xsensitivity << "," << sdl.mouse.ysensitivity;
|
|
|
|
|
|
std::string cycles=str.str();
|
|
name->setText(cycles.c_str());
|
|
(new GUI::Button(this, 100, 60, MSG_Get("OK"), 90))->addActionHandler(this);
|
|
(new GUI::Button(this, 200, 60, MSG_Get("CANCEL"), 90))->addActionHandler(this);
|
|
move(parent->getWidth()>this->getWidth()?(parent->getWidth()-this->getWidth())/2:0,parent->getHeight()>this->getHeight()?(parent->getHeight()-this->getHeight())/2:0);
|
|
|
|
name->raise(); /* make sure keyboard focus is on the text field, ready for the user */
|
|
name->posToEnd(); /* position the cursor at the end where the user is most likely going to edit */
|
|
}
|
|
|
|
void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) override {
|
|
(void)b;//UNUSED
|
|
if (arg == MSG_Get("OK")) {
|
|
Section* sec = control->GetSection("sdl");
|
|
if (sec) {
|
|
std::string tmp("sensitivity=");
|
|
tmp.append((const char*)(name->getText()));
|
|
sec->HandleInputline(tmp);
|
|
Prop_multival* p3 = static_cast<Section_prop *>(sec)->Get_multival("sensitivity");
|
|
sdl.mouse.xsensitivity = p3->GetSection()->Get_int("xsens");
|
|
sdl.mouse.ysensitivity = p3->GetSection()->Get_int("ysens");
|
|
}
|
|
}
|
|
close();
|
|
if(shortcut) running=false;
|
|
}
|
|
};
|
|
|
|
extern bool enable_autosave;
|
|
extern int autosave_second, autosave_count, autosave_start[10], autosave_end[10], autosave_last[10];
|
|
extern std::string autosave_name[10];
|
|
class SetAutoSave : public GUI::ToplevelWindow {
|
|
protected:
|
|
GUI::Input *name[10], *start[10], *end[10];
|
|
public:
|
|
SetAutoSave(GUI::Screen *parent, int x, int y, const char *title) :
|
|
ToplevelWindow(parent, x, y, 630, 400, title) {
|
|
new GUI::Label(this, 5, 15, "Time interval (secs)");
|
|
name[0] = new GUI::Input(this, 175, 10, 80);
|
|
name[0]->setText(std::to_string(autosave_second).c_str());
|
|
new GUI::Label(this, 270, 15, "Start slot");
|
|
start[0] = new GUI::Input(this, 360, 10, 35);
|
|
start[0]->setText(std::to_string(autosave_start[0]).c_str());
|
|
new GUI::Label(this, 410, 15, "End slot (optional)");
|
|
end[0] = new GUI::Input(this, 575, 10, 35);
|
|
end[0]->setText(std::to_string(autosave_end[0]).c_str());
|
|
for (int i=1; i<10; i++) {
|
|
new GUI::Label(this, 5, 15+i*30, "Program "+std::to_string(i)+" (Optional)");
|
|
name[i] = new GUI::Input(this, 175, 10+i*30, 80);
|
|
name[i]->setText(autosave_name[i].c_str());
|
|
new GUI::Label(this, 270, 15+i*30, "Start slot");
|
|
start[i] = new GUI::Input(this, 360, 10+i*30, 35);
|
|
start[i]->setText(std::to_string(autosave_start[i]).c_str());
|
|
new GUI::Label(this, 410, 15+i*30, "End slot (optional)");
|
|
end[i] = new GUI::Input(this, 575, 10+i*30, 35);
|
|
end[i]->setText(std::to_string(autosave_end[i]).c_str());
|
|
}
|
|
new GUI::Label(this, 15, 315, "Note: 0 for start slot = use current slot; -1 for start slot = skip saving");
|
|
(new GUI::Button(this, 225, 335, MSG_Get("OK"), 90))->addActionHandler(this);
|
|
(new GUI::Button(this, 325, 335, MSG_Get("CANCEL"), 90))->addActionHandler(this);
|
|
move(parent->getWidth()>this->getWidth()?(parent->getWidth()-this->getWidth())/2:0,parent->getHeight()>this->getHeight()?(parent->getHeight()-this->getHeight())/2:0);
|
|
}
|
|
|
|
void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) override {
|
|
(void)b;//UNUSED
|
|
if (arg == MSG_Get("OK")) {
|
|
autosave_second = atoi(name[0]->getText());
|
|
autosave_start[0] = atoi(start[0]->getText());
|
|
autosave_end[0] = atoi(end[0]->getText());
|
|
for (int i=1; i<10; i++) {
|
|
autosave_name[i] = (const char*)name[i]->getText();
|
|
if (autosave_name[i].size()) autosave_count=i;
|
|
autosave_start[i] = atoi(start[i]->getText());
|
|
if (autosave_start[i]<-1) autosave_start[i]=-1;
|
|
autosave_end[i] = atoi(end[i]->getText());
|
|
if (autosave_end[i]<autosave_start[i]) autosave_end[i]=0;
|
|
if ((autosave_start[i]>1&&autosave_start[i]<=100&&autosave_last[i]<autosave_start[i])||(autosave_last[i]>(autosave_end[i]>=autosave_start[i]&&autosave_end[i]<=100?autosave_end[i]:autosave_start[i]))) autosave_last[i]=-1;
|
|
}
|
|
if (!mainMenu.get_item("enable_autosave").is_enabled()&&autosave_second) enable_autosave = autosave_second>0;
|
|
if (autosave_second<0) autosave_second=-autosave_second;
|
|
mainMenu.get_item("enable_autosave").check(enable_autosave).enable(autosave_second>0).refresh_item(mainMenu);
|
|
mainMenu.get_item("lastautosaveslot").enable(autosave_second>0).refresh_item(mainMenu);
|
|
}
|
|
close();
|
|
if(shortcut) running=false;
|
|
}
|
|
};
|
|
|
|
class SetCycles : public GUI::ToplevelWindow {
|
|
protected:
|
|
InputWithEnterKey *name;
|
|
public:
|
|
SetCycles(GUI::Screen *parent, int x, int y, const char *title) :
|
|
ToplevelWindow(parent, x, y, 400, 100 + GUI::titlebar_y_stop, title) {
|
|
new GUI::Label(this, 5, 10, "Enter CPU cycles (or 'max' for max cycles):");
|
|
// name = new GUI::Input(this, 5, 30, 350);
|
|
name = new InputWithEnterKey(this, 5, 30, width - 10 - border_left - border_right);
|
|
name->set_trigger_target(this);
|
|
std::ostringstream str;
|
|
str << "fixed " << CPU_CycleMax;
|
|
|
|
std::string cycles=str.str();
|
|
name->setText(cycles.c_str());
|
|
(new GUI::Button(this, 100, 60, MSG_Get("OK"), 90))->addActionHandler(this);
|
|
(new GUI::Button(this, 200, 60, MSG_Get("CANCEL"), 90))->addActionHandler(this);
|
|
move(parent->getWidth()>this->getWidth()?(parent->getWidth()-this->getWidth())/2:0,parent->getHeight()>this->getHeight()?(parent->getHeight()-this->getHeight())/2:0);
|
|
|
|
name->raise(); /* make sure keyboard focus is on the text field, ready for the user */
|
|
name->posToEnd(); /* position the cursor at the end where the user is most likely going to edit */
|
|
}
|
|
|
|
void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) override {
|
|
(void)b;//UNUSED
|
|
if (arg == MSG_Get("OK")) {
|
|
Section* sec = control->GetSection("cpu");
|
|
if (sec) {
|
|
std::string tmp("cycles=");
|
|
tmp.append((const char*)(name->getText()));
|
|
sec->HandleInputline(tmp);
|
|
}
|
|
}
|
|
close();
|
|
if(shortcut) running=false;
|
|
}
|
|
};
|
|
|
|
class SetVsyncrate : public GUI::ToplevelWindow {
|
|
protected:
|
|
GUI::Input *name;
|
|
public:
|
|
SetVsyncrate(GUI::Screen *parent, int x, int y, const char *title) :
|
|
ToplevelWindow(parent, x, y, 400, 100 + GUI::titlebar_y_stop, title) {
|
|
new GUI::Label(this, 5, 10, "Enter vertical syncrate (Hz):");
|
|
name = new GUI::Input(this, 5, 30, width - 10 - border_left - border_right);
|
|
Section_prop * sec = static_cast<Section_prop *>(control->GetSection("vsync"));
|
|
if (sec)
|
|
name->setText(sec->Get_string("vsyncrate"));
|
|
else
|
|
name->setText("");
|
|
(new GUI::Button(this, 100, 60, MSG_Get("OK"), 90))->addActionHandler(this);
|
|
(new GUI::Button(this, 200, 60, MSG_Get("CANCEL"), 90))->addActionHandler(this);
|
|
move(parent->getWidth()>this->getWidth()?(parent->getWidth()-this->getWidth())/2:0,parent->getHeight()>this->getHeight()?(parent->getHeight()-this->getHeight())/2:0);
|
|
|
|
name->raise(); /* make sure keyboard focus is on the text field, ready for the user */
|
|
name->posToEnd(); /* position the cursor at the end where the user is most likely going to edit */
|
|
}
|
|
|
|
void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) override {
|
|
(void)b;//UNUSED
|
|
Section_prop * sec = static_cast<Section_prop *>(control->GetSection("vsync"));
|
|
if (arg == MSG_Get("OK")) {
|
|
if (sec) {
|
|
std::string s((const char *)name->getText());
|
|
if (s.size()>20) s=s.substr(0,20);
|
|
std::string tmp("vsyncrate=");
|
|
tmp.append(s);
|
|
sec->HandleInputline(tmp);
|
|
}
|
|
}
|
|
if (sec) LOG_MSG("GUI: Current Vertical Sync Rate: %s Hz", sec->Get_string("vsyncrate"));
|
|
close();
|
|
if(shortcut) running=false;
|
|
}
|
|
};
|
|
|
|
class SetLocalSize : public GUI::ToplevelWindow {
|
|
protected:
|
|
GUI::Input *name;
|
|
public:
|
|
SetLocalSize(GUI::Screen *parent, int x, int y, const char *title) :
|
|
ToplevelWindow(parent, x, y, 450, 150, title) {
|
|
new GUI::Label(this, 5, 10, "Enter default local freesize (MB, min=0, max=1024):");
|
|
name = new GUI::Input(this, 5, 30, 400);
|
|
extern unsigned int hdd_defsize;
|
|
unsigned int human_readable = 512u * 32u * hdd_defsize / 1024u / 1024u;
|
|
char buffer[6];
|
|
sprintf(buffer, "%u", human_readable);
|
|
name->setText(buffer);
|
|
(new GUI::Button(this, 100, 70, MSG_Get("OK"), 90))->addActionHandler(this);
|
|
(new GUI::Button(this, 200, 70, MSG_Get("CANCEL"), 90))->addActionHandler(this);
|
|
move(parent->getWidth()>this->getWidth()?(parent->getWidth()-this->getWidth())/2:0,parent->getHeight()>this->getHeight()?(parent->getHeight()-this->getHeight())/2:0);
|
|
|
|
name->raise(); /* make sure keyboard focus is on the text field, ready for the user */
|
|
name->posToEnd(); /* position the cursor at the end where the user is most likely going to edit */
|
|
}
|
|
|
|
void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) override {
|
|
(void)b;//UNUSED
|
|
if (arg == MSG_Get("OK")) {
|
|
extern unsigned int hdd_defsize;
|
|
int human_readable = atoi(name->getText());
|
|
if (human_readable < 0)
|
|
hdd_defsize = 0u;
|
|
else if (human_readable > 1024)
|
|
hdd_defsize = 256000u;
|
|
else
|
|
hdd_defsize = (unsigned int)human_readable * 1024u * 1024u / 512u / 32u;
|
|
LOG_MSG("GUI: Current default freesize for local disk: %dMB", 512u * 32u * hdd_defsize / 1024u / 1024u);
|
|
}
|
|
close();
|
|
if (shortcut) running = false;
|
|
}
|
|
};
|
|
|
|
bool set_ver(char *s);
|
|
void dos_ver_menu(bool start);
|
|
class SetDOSVersion : public GUI::ToplevelWindow {
|
|
protected:
|
|
GUI::Input *name;
|
|
public:
|
|
SetDOSVersion(GUI::Screen *parent, int x, int y, const char *title) :
|
|
ToplevelWindow(parent, x, y, 410, 140, title) {
|
|
new GUI::Label(this, 5, 10, "Enter reported DOS version:");
|
|
name = new GUI::Input(this, 5, 30, 390);
|
|
char buffer[8];
|
|
sprintf(buffer, "%d.%02d", dos.version.major,dos.version.minor);
|
|
name->setText(buffer);
|
|
(new GUI::Button(this, 100, 70, MSG_Get("OK"), 90))->addActionHandler(this);
|
|
(new GUI::Button(this, 200, 70, MSG_Get("CANCEL"), 90))->addActionHandler(this);
|
|
move(parent->getWidth()>this->getWidth()?(parent->getWidth()-this->getWidth())/2:0,parent->getHeight()>this->getHeight()?(parent->getHeight()-this->getHeight())/2:0);
|
|
|
|
name->raise(); /* make sure keyboard focus is on the text field, ready for the user */
|
|
name->posToEnd(); /* position the cursor at the end where the user is most likely going to edit */
|
|
}
|
|
|
|
void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) override {
|
|
(void)b;//UNUSED
|
|
if (arg == MSG_Get("OK")) {
|
|
if (set_ver(name->getText()))
|
|
dos_ver_menu(false);
|
|
}
|
|
close();
|
|
if (shortcut) running = false;
|
|
}
|
|
};
|
|
|
|
class SetAspectRatio : public GUI::ToplevelWindow {
|
|
protected:
|
|
GUI::Input *name;
|
|
public:
|
|
SetAspectRatio(GUI::Screen *parent, int x, int y, const char *title) :
|
|
ToplevelWindow(parent, x, y, 410, 140, title) {
|
|
new GUI::Label(this, 5, 10, "Enter aspect ratio (w:h, -1:-1 = original ratio):");
|
|
name = new GUI::Input(this, 5, 30, 390);
|
|
char buffer[8];
|
|
sprintf(buffer, "%d:%d", aspect_ratio_x,aspect_ratio_y);
|
|
name->setText(buffer);
|
|
(new GUI::Button(this, 100, 70, MSG_Get("OK"), 90))->addActionHandler(this);
|
|
(new GUI::Button(this, 200, 70, MSG_Get("CANCEL"), 90))->addActionHandler(this);
|
|
move(parent->getWidth()>this->getWidth()?(parent->getWidth()-this->getWidth())/2:0,parent->getHeight()>this->getHeight()?(parent->getHeight()-this->getHeight())/2:0);
|
|
|
|
name->raise(); /* make sure keyboard focus is on the text field, ready for the user */
|
|
name->posToEnd(); /* position the cursor at the end where the user is most likely going to edit */
|
|
}
|
|
|
|
void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) override {
|
|
(void)b;//UNUSED
|
|
if (arg == MSG_Get("OK")) {
|
|
SetVal("render", "aspect_ratio", name->getText());
|
|
setAspectRatio(static_cast<Section_prop *>(control->GetSection("render")));
|
|
//if (render.aspect) GFX_ForceRedrawScreen();
|
|
}
|
|
close();
|
|
if (shortcut) running = false;
|
|
}
|
|
};
|
|
|
|
extern std::string dosbox_title;
|
|
class SetTitleText : public GUI::ToplevelWindow {
|
|
protected:
|
|
GUI::Input *title1, *title2;
|
|
Section_prop *sec1, *sec2;
|
|
std::string t1, t2;
|
|
public:
|
|
SetTitleText(GUI::Screen *parent, int x, int y, const char *title) :
|
|
ToplevelWindow(parent, x, y, 410, 180, title) {
|
|
sec1 = static_cast<Section_prop *>(control->GetSection("dosbox"));
|
|
sec2 = static_cast<Section_prop *>(control->GetSection("sdl"));
|
|
t1 = sec1->Get_string("title");
|
|
t2 = sec2->Get_string("titlebar");
|
|
trim(t1);
|
|
trim(t2);
|
|
new GUI::Label(this, 5, 10, "Prepend text in title bar:");
|
|
title1 = new GUI::Input(this, 5, 30, 390);
|
|
title1->setText(t1);
|
|
new GUI::Label(this, 5, 60, "Append text in title bar:");
|
|
title2 = new GUI::Input(this, 5, 80, 390);
|
|
title2->setText(t2);
|
|
(new GUI::Button(this, 100, 110, MSG_Get("OK"), 90))->addActionHandler(this);
|
|
(new GUI::Button(this, 200, 110, MSG_Get("CANCEL"), 90))->addActionHandler(this);
|
|
move(parent->getWidth()>this->getWidth()?(parent->getWidth()-this->getWidth())/2:0,parent->getHeight()>this->getHeight()?(parent->getHeight()-this->getHeight())/2:0);
|
|
|
|
title1->raise(); /* make sure keyboard focus is on the text field, ready for the user */
|
|
title1->posToEnd(); /* position the cursor at the end where the user is most likely going to edit */
|
|
}
|
|
|
|
void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) override {
|
|
(void)b;//UNUSED
|
|
if (arg == MSG_Get("OK")) {
|
|
dosbox_title = trim(title1->getText());
|
|
SetVal("dosbox", "title", dosbox_title);
|
|
SetVal("sdl", "titlebar", trim(title2->getText()));
|
|
GFX_SetTitle(-1,-1,-1,false);
|
|
}
|
|
close();
|
|
if (shortcut) running = false;
|
|
}
|
|
};
|
|
|
|
class SetTransparency : public GUI::ToplevelWindow {
|
|
protected:
|
|
GUI::Input *name;
|
|
Section_prop * sec;
|
|
public:
|
|
SetTransparency(GUI::Screen *parent, int x, int y, const char *title) :
|
|
ToplevelWindow(parent, x, y, 410, 140, title) {
|
|
sec = static_cast<Section_prop *>(control->GetSection("sdl"));
|
|
new GUI::Label(this, 5, 10, "Enter transparency (0-90; from low to high):");
|
|
name = new GUI::Input(this, 5, 30, 390);
|
|
std::ostringstream str;
|
|
str << sec->Get_int("transparency");
|
|
std::string transtr=str.str();
|
|
name->setText(transtr.c_str());
|
|
(new GUI::Button(this, 100, 70, MSG_Get("OK"), 90))->addActionHandler(this);
|
|
(new GUI::Button(this, 200, 70, MSG_Get("CANCEL"), 90))->addActionHandler(this);
|
|
move(parent->getWidth()>this->getWidth()?(parent->getWidth()-this->getWidth())/2:0,parent->getHeight()>this->getHeight()?(parent->getHeight()-this->getHeight())/2:0);
|
|
|
|
name->raise(); /* make sure keyboard focus is on the text field, ready for the user */
|
|
name->posToEnd(); /* position the cursor at the end where the user is most likely going to edit */
|
|
}
|
|
|
|
void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) override {
|
|
(void)b;//UNUSED
|
|
if (arg == MSG_Get("OK")) {
|
|
SetVal("sdl", "transparency", name->getText());
|
|
sec = static_cast<Section_prop *>(control->GetSection("sdl"));
|
|
SetWindowTransparency(sec->Get_int("transparency"));
|
|
}
|
|
close();
|
|
if (shortcut) running = false;
|
|
}
|
|
};
|
|
|
|
class ShowMixerInfo : public GUI::ToplevelWindow {
|
|
protected:
|
|
GUI::Input *name;
|
|
public:
|
|
ShowMixerInfo(GUI::Screen *parent, int x, int y, const char *title) :
|
|
ToplevelWindow(parent, x, y, 350, 270, title) {
|
|
extern std::string mixerinfo();
|
|
std::istringstream in(mixerinfo().c_str());
|
|
int r=0;
|
|
if (in) for (std::string line; std::getline(in, line); ) {
|
|
r+=25;
|
|
new GUI::Label(this, 40, r, line.c_str());
|
|
}
|
|
(new GUI::Button(this, 140, r+30, MSG_Get("CLOSE"), 70))->addActionHandler(this);
|
|
resize(350, r+110);
|
|
move(parent->getWidth()>this->getWidth()?(parent->getWidth()-this->getWidth())/2:0,parent->getHeight()>this->getHeight()?(parent->getHeight()-this->getHeight())/2:0);
|
|
}
|
|
|
|
void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) override {
|
|
(void)b;//UNUSED
|
|
if (arg == MSG_Get("CLOSE"))
|
|
close();
|
|
if (shortcut) running = false;
|
|
}
|
|
};
|
|
|
|
std::string GetSBtype(), GetSBbase(), GetSBirq(), GetSBldma(), GetSBhdma();
|
|
|
|
class ShowSBInfo : public GUI::ToplevelWindow {
|
|
protected:
|
|
GUI::Input *name;
|
|
public:
|
|
ShowSBInfo(GUI::Screen *parent, int x, int y, const char *title) :
|
|
ToplevelWindow(parent, x, y, 320, 230, title) {
|
|
std::string sbinfo = "Sound Blaster type: "+GetSBtype()+"\nSound Blaster base: "+GetSBbase()+"\nSound Blaster IRQ: "+GetSBirq()+"\nSound Blaster Low DMA: "+GetSBldma()+"\nSound Blaster High DMA: "+GetSBhdma();
|
|
std::istringstream in(sbinfo.c_str());
|
|
int r=0;
|
|
if (in) for (std::string line; std::getline(in, line); ) {
|
|
r+=25;
|
|
new GUI::Label(this, 40, r, line.c_str());
|
|
}
|
|
(new GUI::Button(this, 130, r+30, MSG_Get("CLOSE"), 70))->addActionHandler(this);
|
|
move(parent->getWidth()>this->getWidth()?(parent->getWidth()-this->getWidth())/2:0,parent->getHeight()>this->getHeight()?(parent->getHeight()-this->getHeight())/2:0);
|
|
}
|
|
|
|
void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) override {
|
|
(void)b;//UNUSED
|
|
if (arg == MSG_Get("CLOSE"))
|
|
close();
|
|
if (shortcut) running = false;
|
|
}
|
|
};
|
|
|
|
extern DB_Midi midi;
|
|
extern std::string sffile;
|
|
class ShowMidiDevice : public GUI::ToplevelWindow {
|
|
protected:
|
|
GUI::Input *name;
|
|
public:
|
|
ShowMidiDevice(GUI::Screen *parent, int x, int y, const char *title) :
|
|
ToplevelWindow(parent, x, y, 320, 260, title) {
|
|
std::string name=!midi.handler||!midi.handler->GetName()?"-":midi.handler->GetName();
|
|
if (name.size()) {
|
|
if (name=="mt32") name="MT32";
|
|
else if (name=="fluidsynth") name="FluidSynth";
|
|
else name[0]=toupper(name[0]);
|
|
}
|
|
extern std::string getoplmode(), getoplemu();
|
|
std::string midiinfo = "MIDI available: "+std::string(midi.available?"Yes":"No")+"\nMIDI device: "+name+"\nMIDI soundfont file / ROM path:\n"+sffile+"\nOPL mode: "+getoplmode()+"\nOPL emulation: "+getoplemu();
|
|
std::istringstream in(midiinfo.c_str());
|
|
int r=0;
|
|
if (in) for (std::string line; std::getline(in, line); ) {
|
|
r+=25;
|
|
new GUI::Label(this, 40, r, line.c_str());
|
|
}
|
|
(new GUI::Button(this, 130, r+30, MSG_Get("CLOSE"), 70))->addActionHandler(this);
|
|
move(parent->getWidth()>this->getWidth()?(parent->getWidth()-this->getWidth())/2:0,parent->getHeight()>this->getHeight()?(parent->getHeight()-this->getHeight())/2:0);
|
|
}
|
|
|
|
void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) override {
|
|
(void)b;//UNUSED
|
|
if (arg == MSG_Get("CLOSE"))
|
|
close();
|
|
if (shortcut) running = false;
|
|
}
|
|
};
|
|
|
|
class ShowDriveInfo : public GUI::ToplevelWindow {
|
|
protected:
|
|
GUI::Input *name;
|
|
public:
|
|
ShowDriveInfo(GUI::Screen *parent, int x, int y, const char *title) :
|
|
ToplevelWindow(parent, x, y, 400, 280, title) {
|
|
char name[DOS_NAMELENGTH_ASCII],lname[LFN_NAMELENGTH];
|
|
uint32_t size,hsize;uint16_t date;uint16_t time;uint8_t attr;
|
|
/* Command uses dta so set it to our internal dta */
|
|
RealPt save_dta = dos.dta();
|
|
dos.dta(dos.tables.tempdta);
|
|
DOS_DTA dta(dos.dta());
|
|
if (Drives[statusdrive]) {
|
|
char root[7] = {(char)('A'+statusdrive),':','\\','*','.','*',0};
|
|
bool ret = DOS_FindFirst(root,DOS_ATTR_VOLUME);
|
|
if (ret) {
|
|
dta.GetResult(name,lname,size,hsize,date,time,attr);
|
|
DOS_FindNext(); //Mark entry as invalid
|
|
} else name[0] = 0;
|
|
|
|
/* Change 8.3 to 11.0 */
|
|
const char* dot = strchr(name, '.');
|
|
if(dot && (dot - name == 8) ) {
|
|
name[8] = name[9];name[9] = name[10];name[10] = name[11];name[11] = 0;
|
|
}
|
|
|
|
root[3] = 0; //This way, the format string can be reused.
|
|
std::string type, path, swappos="-", overlay="-";
|
|
bool readonly=false;
|
|
const char *info = Drives[statusdrive]->GetInfo();
|
|
if (!strncmp(info, "fatDrive ", 9) || !strncmp(info, "isoDrive ", 9)) {
|
|
type=strncmp(info, "isoDrive ", 9)?"fatDrive":"isoDrive";
|
|
path=info+9;
|
|
if (type=="isoDrive")
|
|
readonly=true;
|
|
else {
|
|
readonly=Drives[statusdrive]->readonly;
|
|
if (!path.size()) {
|
|
fatDrive *fdp = dynamic_cast<fatDrive*>(Drives[statusdrive]);
|
|
if (fdp!=NULL&&fdp->opts.mounttype==1)
|
|
path="El Torito floppy drive";
|
|
else if (fdp!=NULL&&fdp->opts.mounttype==2)
|
|
path="RAM drive";
|
|
}
|
|
}
|
|
swappos=DriveManager::GetDrivePosition(statusdrive);
|
|
} else if (!strncmp(info, "PhysFS directory ", 17)) {
|
|
type="PhysFS directory";
|
|
path=info+17;
|
|
readonly=true;
|
|
physfsDrive *pdp = dynamic_cast<physfsDrive*>(Drives[statusdrive]);
|
|
if (pdp!=NULL) {
|
|
const char *wdir = pdp->getOverlaydir();
|
|
if (wdir!=NULL&&strlen(wdir)) {
|
|
readonly=false;
|
|
overlay=std::string(wdir)+(wdir[strlen(wdir)-1]!=CROSS_FILESPLIT?std::string(1, CROSS_FILESPLIT):"")+std::string(1, 'A'+statusdrive)+"_DRIVE";
|
|
}
|
|
}
|
|
} else if (!strncmp(info, "PhysFS CDRom ", 13)) {
|
|
type="PhysFS CDRom";
|
|
path=info+13;
|
|
readonly=true;
|
|
} else if (!strncmp(info, "local directory ", 16)) {
|
|
type="local directory";
|
|
path=info+16;
|
|
readonly=Drives[statusdrive]->readonly;
|
|
Overlay_Drive *ddp = dynamic_cast<Overlay_Drive*>(Drives[statusdrive]);
|
|
if (ddp!=NULL) {
|
|
readonly=ddp->ovlreadonly;
|
|
overlay=ddp->getOverlaydir();
|
|
}
|
|
} else if (!strncmp(info, "CDRom ", 6)) {
|
|
type="CDRom";
|
|
path=info+6;
|
|
readonly=true;
|
|
} else {
|
|
type=info;
|
|
path="";
|
|
readonly=true;
|
|
}
|
|
if (path=="") path="-";
|
|
new GUI::Label(this, 40, 25, "Drive root: "+std::string(root));
|
|
new GUI::Label(this, 40, 50, "Drive type: "+type);
|
|
new GUI::Label(this, 40, 75, "Mounted as: "+path);
|
|
new GUI::Label(this, 40, 100, "Overlay at: "+overlay);
|
|
new GUI::Label(this, 40, 125, "Disk label: "+std::string(name));
|
|
new GUI::Label(this, 40, 150, "Read only : "+std::string(readonly?"Yes":"No"));
|
|
new GUI::Label(this, 40, 175, "Swap slot : "+swappos);
|
|
}
|
|
dos.dta(save_dta);
|
|
(new GUI::Button(this, 165, 205, MSG_Get("CLOSE"), 70))->addActionHandler(this);
|
|
move(parent->getWidth()>this->getWidth()?(parent->getWidth()-this->getWidth())/2:0,parent->getHeight()>this->getHeight()?(parent->getHeight()-this->getHeight())/2:0);
|
|
}
|
|
|
|
void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) override {
|
|
(void)b;//UNUSED
|
|
if (arg == MSG_Get(MSG_Get("CLOSE")))
|
|
close();
|
|
if (shortcut) running = false;
|
|
}
|
|
};
|
|
|
|
std::string GetIDEPosition(unsigned char bios_disk_index);
|
|
class ShowDriveNumber : public GUI::ToplevelWindow {
|
|
protected:
|
|
GUI::Input *name;
|
|
public:
|
|
ShowDriveNumber(GUI::Screen *parent, int x, int y, const char *title) :
|
|
ToplevelWindow(parent, x, y, 480, 260, title) {
|
|
std::string str;
|
|
for (int index = 0; index < MAX_DISK_IMAGES; index++) {
|
|
if (imageDiskList[index]) {
|
|
int swaps=0;
|
|
if (swapInDisksSpecificDrive == index) {
|
|
for (size_t si=0;si < MAX_SWAPPABLE_DISKS;si++)
|
|
if (diskSwap[si] != NULL)
|
|
swaps++;
|
|
}
|
|
if (!swaps) swaps=1;
|
|
if (index<2)
|
|
str = "Swap position: " + std::to_string(swaps==1?1:swapPosition+1) + "/" + std::to_string(swaps) + " - " + (dynamic_cast<imageDiskElToritoFloppy *>(imageDiskList[index])!=NULL?"El Torito floppy drive":imageDiskList[index]->diskname);
|
|
else {
|
|
str = GetIDEPosition(index);
|
|
str = "IDE controller: " + (str.size()?str:"NA") + " - " + imageDiskList[index]->diskname;
|
|
}
|
|
} else
|
|
str = "Not yet mounted";
|
|
new GUI::Label(this, 40, 25*(index+1), std::to_string(index) + " - " + str);
|
|
}
|
|
(new GUI::Button(this, 190, 25*(MAX_DISK_IMAGES+1)+5, MSG_Get("CLOSE"), 70))->addActionHandler(this);
|
|
move(parent->getWidth()>this->getWidth()?(parent->getWidth()-this->getWidth())/2:0,parent->getHeight()>this->getHeight()?(parent->getHeight()-this->getHeight())/2:0);
|
|
}
|
|
|
|
void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) override {
|
|
(void)b;//UNUSED
|
|
if (arg == MSG_Get("CLOSE"))
|
|
close();
|
|
if (shortcut) running = false;
|
|
}
|
|
};
|
|
|
|
class ShowIDEInfo : public GUI::ToplevelWindow {
|
|
protected:
|
|
GUI::Input *name;
|
|
public:
|
|
ShowIDEInfo(GUI::Screen *parent, int x, int y, const char *title) :
|
|
ToplevelWindow(parent, x, y, 300, 210, title) {
|
|
extern std::string GetIDEInfo();
|
|
std::istringstream in(GetIDEInfo().c_str());
|
|
int r=0;
|
|
if (in) for (std::string line; std::getline(in, line); ) {
|
|
r+=25;
|
|
new GUI::Label(this, 40, r, line.c_str());
|
|
}
|
|
(new GUI::Button(this, 110, r+30, MSG_Get("CLOSE"), 70))->addActionHandler(this);
|
|
resize(300, r+110);
|
|
move(parent->getWidth()>this->getWidth()?(parent->getWidth()-this->getWidth())/2:0,parent->getHeight()>this->getHeight()?(parent->getHeight()-this->getHeight())/2:0);
|
|
}
|
|
|
|
void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) override {
|
|
(void)b;//UNUSED
|
|
if (arg == MSG_Get("CLOSE"))
|
|
close();
|
|
if (shortcut) running = false;
|
|
}
|
|
};
|
|
|
|
class ShowLoadWarning : public GUI::ToplevelWindow {
|
|
protected:
|
|
GUI::Input *name;
|
|
public:
|
|
ShowLoadWarning(GUI::Screen *parent, int x, int y, const char *title) :
|
|
ToplevelWindow(parent, x, y, 430, 120, MSG_Get("WARNING")) {
|
|
new GUI::Label(this, strncmp(title, "DOSBox-X ", 9)?30:10, 20, title);
|
|
(new GUI::Button(this, 140, 50, MSG_Get("YES"), 70))->addActionHandler(this);
|
|
(new GUI::Button(this, 230, 50, MSG_Get("NO"), 70))->addActionHandler(this);
|
|
move(parent->getWidth()>this->getWidth()?(parent->getWidth()-this->getWidth())/2:0,parent->getHeight()>this->getHeight()?(parent->getHeight()-this->getHeight())/2:0);
|
|
}
|
|
|
|
void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) override {
|
|
(void)b;//UNUSED
|
|
if (arg == MSG_Get("YES"))
|
|
confres=true;
|
|
if (arg == MSG_Get("NO"))
|
|
confres=false;
|
|
close();
|
|
if (shortcut) running = false;
|
|
}
|
|
};
|
|
|
|
class MakeDiskImage : public GUI::ToplevelWindow {
|
|
protected:
|
|
GUI::Input *name;
|
|
public:
|
|
MakeDiskImage(GUI::Screen *parent, int x, int y, const char *title) :
|
|
ToplevelWindow(parent, x, y, 500, 300, title) {
|
|
new GUI::Label(this, 100, 30, "Select a floppy disk image size:");
|
|
imgfd360 = new GUI::Checkbox(this, 110, 60, "360KB");
|
|
imgfd360->addActionHandler(this);
|
|
imgfd400 = new GUI::Checkbox(this, 210, 60, "400KB");
|
|
imgfd400->addActionHandler(this);
|
|
imgfd720 = new GUI::Checkbox(this, 310, 60, "720KB");
|
|
imgfd720->addActionHandler(this);
|
|
imgfd1200 = new GUI::Checkbox(this, 110, 90, "1.2MB");
|
|
imgfd1200->addActionHandler(this);
|
|
imgfd1440 = new GUI::Checkbox(this, 210, 90, "1.44MB");
|
|
imgfd1440->addActionHandler(this);
|
|
imgfd2880 = new GUI::Checkbox(this, 310, 90, "2.88MB");
|
|
imgfd2880->addActionHandler(this);
|
|
new GUI::Label(this, 100, 120, "Select a hard disk image size:");
|
|
imghd250 = new GUI::Checkbox(this, 110, 150, "250MB");
|
|
imghd250->addActionHandler(this);
|
|
imghd520 = new GUI::Checkbox(this, 210, 150, "520MB");
|
|
imghd520->addActionHandler(this);
|
|
imghd1gig = new GUI::Checkbox(this, 310, 150, "1GB");
|
|
imghd1gig->addActionHandler(this);
|
|
imghd2gig = new GUI::Checkbox(this, 110, 180, "2GB");
|
|
imghd2gig->addActionHandler(this);
|
|
imghd4gig = new GUI::Checkbox(this, 210, 180, "4GB");
|
|
imghd4gig->addActionHandler(this);
|
|
imghd8gig = new GUI::Checkbox(this, 310, 180, "8GB");
|
|
imghd8gig->addActionHandler(this);
|
|
(new GUI::Button(this, 135, 220, MSG_Get("OK"), 90))->addActionHandler(this);
|
|
(new GUI::Button(this, 255, 220, MSG_Get("CANCEL"), 90))->addActionHandler(this);
|
|
move(parent->getWidth()>this->getWidth()?(parent->getWidth()-this->getWidth())/2:0,parent->getHeight()>this->getHeight()?(parent->getHeight()-this->getHeight())/2:0);
|
|
}
|
|
|
|
void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) override {
|
|
(void)b;//UNUSED
|
|
if (arg == "360KB" && imgfd360->isChecked()) {
|
|
imgfd400->setChecked(false);
|
|
imgfd720->setChecked(false);
|
|
imgfd1200->setChecked(false);
|
|
imgfd1440->setChecked(false);
|
|
imgfd2880->setChecked(false);
|
|
imghd250->setChecked(false);
|
|
imghd520->setChecked(false);
|
|
imghd1gig->setChecked(false);
|
|
imghd2gig->setChecked(false);
|
|
imghd4gig->setChecked(false);
|
|
imghd8gig->setChecked(false);
|
|
} else if (arg == "720KB" && imgfd720->isChecked()) {
|
|
imgfd360->setChecked(false);
|
|
imgfd400->setChecked(false);
|
|
imgfd1200->setChecked(false);
|
|
imgfd1440->setChecked(false);
|
|
imgfd2880->setChecked(false);
|
|
imghd250->setChecked(false);
|
|
imghd520->setChecked(false);
|
|
imghd1gig->setChecked(false);
|
|
imghd2gig->setChecked(false);
|
|
imghd4gig->setChecked(false);
|
|
imghd8gig->setChecked(false);
|
|
} else if (arg == "400KB" && imgfd400->isChecked()) {
|
|
imgfd360->setChecked(false);
|
|
imgfd720->setChecked(false);
|
|
imgfd1200->setChecked(false);
|
|
imgfd1440->setChecked(false);
|
|
imgfd2880->setChecked(false);
|
|
imghd250->setChecked(false);
|
|
imghd520->setChecked(false);
|
|
imghd1gig->setChecked(false);
|
|
imghd2gig->setChecked(false);
|
|
imghd4gig->setChecked(false);
|
|
imghd8gig->setChecked(false);
|
|
} else if (arg == "1.2MB" && imgfd1200->isChecked()) {
|
|
imgfd360->setChecked(false);
|
|
imgfd400->setChecked(false);
|
|
imgfd720->setChecked(false);
|
|
imgfd1440->setChecked(false);
|
|
imgfd2880->setChecked(false);
|
|
imghd250->setChecked(false);
|
|
imghd520->setChecked(false);
|
|
imghd1gig->setChecked(false);
|
|
imghd2gig->setChecked(false);
|
|
imghd4gig->setChecked(false);
|
|
imghd8gig->setChecked(false);
|
|
} else if (arg == "1.44MB" && imgfd1440->isChecked()) {
|
|
imgfd360->setChecked(false);
|
|
imgfd400->setChecked(false);
|
|
imgfd720->setChecked(false);
|
|
imgfd1200->setChecked(false);
|
|
imgfd2880->setChecked(false);
|
|
imghd250->setChecked(false);
|
|
imghd520->setChecked(false);
|
|
imghd1gig->setChecked(false);
|
|
imghd2gig->setChecked(false);
|
|
imghd4gig->setChecked(false);
|
|
imghd8gig->setChecked(false);
|
|
} else if (arg == "2.88MB" && imgfd2880->isChecked()) {
|
|
imgfd360->setChecked(false);
|
|
imgfd400->setChecked(false);
|
|
imgfd720->setChecked(false);
|
|
imgfd1200->setChecked(false);
|
|
imgfd1440->setChecked(false);
|
|
imghd250->setChecked(false);
|
|
imghd520->setChecked(false);
|
|
imghd1gig->setChecked(false);
|
|
imghd2gig->setChecked(false);
|
|
imghd4gig->setChecked(false);
|
|
imghd8gig->setChecked(false);
|
|
} else if (arg == "250MB" && imghd250->isChecked()) {
|
|
imgfd360->setChecked(false);
|
|
imgfd400->setChecked(false);
|
|
imgfd720->setChecked(false);
|
|
imgfd1200->setChecked(false);
|
|
imgfd1440->setChecked(false);
|
|
imgfd2880->setChecked(false);
|
|
imghd520->setChecked(false);
|
|
imghd1gig->setChecked(false);
|
|
imghd2gig->setChecked(false);
|
|
imghd4gig->setChecked(false);
|
|
imghd8gig->setChecked(false);
|
|
} else if (arg == "520MB" && imghd520->isChecked()) {
|
|
imgfd360->setChecked(false);
|
|
imgfd400->setChecked(false);
|
|
imgfd720->setChecked(false);
|
|
imgfd1200->setChecked(false);
|
|
imgfd1440->setChecked(false);
|
|
imgfd2880->setChecked(false);
|
|
imghd250->setChecked(false);
|
|
imghd1gig->setChecked(false);
|
|
imghd2gig->setChecked(false);
|
|
imghd4gig->setChecked(false);
|
|
imghd8gig->setChecked(false);
|
|
} else if (arg == "1GB" && imghd1gig->isChecked()) {
|
|
imgfd360->setChecked(false);
|
|
imgfd400->setChecked(false);
|
|
imgfd720->setChecked(false);
|
|
imgfd1200->setChecked(false);
|
|
imgfd1440->setChecked(false);
|
|
imgfd2880->setChecked(false);
|
|
imghd250->setChecked(false);
|
|
imghd520->setChecked(false);
|
|
imghd2gig->setChecked(false);
|
|
imghd4gig->setChecked(false);
|
|
imghd8gig->setChecked(false);
|
|
} else if (arg == "2GB" && imghd2gig->isChecked()) {
|
|
imgfd360->setChecked(false);
|
|
imgfd400->setChecked(false);
|
|
imgfd720->setChecked(false);
|
|
imgfd1200->setChecked(false);
|
|
imgfd1440->setChecked(false);
|
|
imgfd2880->setChecked(false);
|
|
imghd250->setChecked(false);
|
|
imghd520->setChecked(false);
|
|
imghd1gig->setChecked(false);
|
|
imghd4gig->setChecked(false);
|
|
imghd8gig->setChecked(false);
|
|
} else if (arg == "4GB" && imghd4gig->isChecked()) {
|
|
imgfd360->setChecked(false);
|
|
imgfd400->setChecked(false);
|
|
imgfd720->setChecked(false);
|
|
imgfd1200->setChecked(false);
|
|
imgfd1440->setChecked(false);
|
|
imgfd2880->setChecked(false);
|
|
imghd250->setChecked(false);
|
|
imghd520->setChecked(false);
|
|
imghd1gig->setChecked(false);
|
|
imghd2gig->setChecked(false);
|
|
imghd8gig->setChecked(false);
|
|
} else if (arg == "8GB" && imghd8gig->isChecked()) {
|
|
imgfd360->setChecked(false);
|
|
imgfd400->setChecked(false);
|
|
imgfd720->setChecked(false);
|
|
imgfd1200->setChecked(false);
|
|
imgfd1440->setChecked(false);
|
|
imgfd2880->setChecked(false);
|
|
imghd250->setChecked(false);
|
|
imghd520->setChecked(false);
|
|
imghd1gig->setChecked(false);
|
|
imghd2gig->setChecked(false);
|
|
imghd4gig->setChecked(false);
|
|
}
|
|
if (arg == MSG_Get("OK")) {
|
|
std::string temp="";
|
|
if (imgfd360->isChecked())
|
|
temp="fd_360";
|
|
else if (imgfd400->isChecked())
|
|
temp="fd_400";
|
|
else if (imgfd720->isChecked())
|
|
temp="fd_720";
|
|
else if (imgfd1200->isChecked())
|
|
temp="fd_1200";
|
|
else if (imgfd1440->isChecked())
|
|
temp="fd_1440";
|
|
else if (imgfd2880->isChecked())
|
|
temp="fd_2880";
|
|
else if (imghd250->isChecked())
|
|
temp="hd_250";
|
|
else if (imghd520->isChecked())
|
|
temp="hd_520";
|
|
else if (imghd1gig->isChecked())
|
|
temp="hd_1gig";
|
|
else if (imghd2gig->isChecked())
|
|
temp="hd_2gig";
|
|
else if (imghd4gig->isChecked())
|
|
temp="hd_4gig";
|
|
else if (imghd8gig->isChecked())
|
|
temp="hd_8gig";
|
|
if (temp.size()) {
|
|
#if defined(HX_DOS)
|
|
char const * lTheSaveFileName = "IMGMAKE.IMG";
|
|
#else
|
|
char CurrentDir[512];
|
|
char * Temp_CurrentDir = CurrentDir;
|
|
getcwd(Temp_CurrentDir, 512);
|
|
const char *lFilterPatterns[] = {"*.img","*.IMG"};
|
|
const char *lFilterDescription = "Disk image files (*.img)";
|
|
char const * lTheSaveFileName = tinyfd_saveFileDialog("Select a disk image file","IMGMAKE.IMG",2,lFilterPatterns,lFilterDescription);
|
|
#endif
|
|
if (lTheSaveFileName!=NULL) {
|
|
temp="-force -t "+temp+" \""+std::string(lTheSaveFileName)+"\"";
|
|
void runImgmake(const char *str);
|
|
runImgmake(temp.c_str());
|
|
if (!dos_kernel_disabled && strcmp(RunningProgram, "LOADLIN")) {
|
|
DOS_Shell shell;
|
|
shell.ShowPrompt();
|
|
}
|
|
}
|
|
#if !defined(HX_DOS)
|
|
chdir( Temp_CurrentDir );
|
|
#endif
|
|
}
|
|
if (shortcut) running = false;
|
|
}
|
|
else if (arg == MSG_Get("CLOSE") || arg == MSG_Get("CANCEL")) {
|
|
close();
|
|
if (shortcut) running = false;
|
|
}
|
|
}
|
|
};
|
|
|
|
class ShowHelpIntro : public GUI::ToplevelWindow {
|
|
protected:
|
|
GUI::Input *name;
|
|
public:
|
|
ShowHelpIntro(GUI::Screen *parent, int x, int y, const char *title) :
|
|
ToplevelWindow(parent, x, y, 610, 190, title) {
|
|
std::istringstream in(MSG_Get("INTRO_MESSAGE"));
|
|
int r=0;
|
|
if (in) for (std::string line; std::getline(in, line); ) {
|
|
r+=25;
|
|
new GUI::Label(this, 40, r, line.c_str());
|
|
}
|
|
(new GUI::Button(this, 260, 110, MSG_Get("CLOSE"), 70))->addActionHandler(this);
|
|
move(parent->getWidth()>this->getWidth()?(parent->getWidth()-this->getWidth())/2:0,parent->getHeight()>this->getHeight()?(parent->getHeight()-this->getHeight())/2:0);
|
|
}
|
|
|
|
void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) override {
|
|
(void)b;//UNUSED
|
|
if (arg == MSG_Get("CLOSE"))
|
|
close();
|
|
if (shortcut) running = false;
|
|
}
|
|
};
|
|
|
|
std::string prtlist="Printer support is not enabled. Check [printer] section of the configuration.";
|
|
class ShowHelpPRT : public GUI::MessageBox2 {
|
|
public:
|
|
std::vector<GUI::Char> cfg_sname;
|
|
public:
|
|
ShowHelpPRT(GUI::Screen *parent, int x, int y) :
|
|
MessageBox2(parent, x, y, 630, "", "") { // 740
|
|
setTitle(MSG_Get("PRINTER_LIST"));
|
|
setText(prtlist);
|
|
move(parent->getWidth()>this->getWidth()?(parent->getWidth()-this->getWidth())/2:0,parent->getHeight()>this->getHeight()?(parent->getHeight()-this->getHeight())/2:0);
|
|
};
|
|
|
|
void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) override {
|
|
(void)b;//UNUSED
|
|
if (arg == MSG_Get("CLOSE"))
|
|
if(shortcut) running=false;
|
|
}
|
|
|
|
~ShowHelpPRT() {
|
|
if (!cfg_sname.empty()) {
|
|
auto i = cfg_windows_active.find(cfg_sname);
|
|
if (i != cfg_windows_active.end()) cfg_windows_active.erase(i);
|
|
}
|
|
}
|
|
};
|
|
|
|
std::string niclist="The pcap networking for NE2000 Ethernet emulation is not currently active.\nPlease check [ne2000] and [ethernet, pcap] sections of the configuration.";
|
|
class ShowHelpNIC : public GUI::MessageBox2 {
|
|
public:
|
|
std::vector<GUI::Char> cfg_sname;
|
|
public:
|
|
ShowHelpNIC(GUI::Screen *parent, int x, int y) :
|
|
MessageBox2(parent, x, y, 630, "", "") { // 740
|
|
setTitle(MSG_Get("NETWORK_LIST"));
|
|
setText(niclist);
|
|
move(parent->getWidth()>this->getWidth()?(parent->getWidth()-this->getWidth())/2:0,parent->getHeight()>this->getHeight()?(parent->getHeight()-this->getHeight())/2:0);
|
|
};
|
|
|
|
void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) override {
|
|
(void)b;//UNUSED
|
|
if (arg == MSG_Get("CLOSE"))
|
|
if(shortcut) running=false;
|
|
}
|
|
|
|
~ShowHelpNIC() {
|
|
if (!cfg_sname.empty()) {
|
|
auto i = cfg_windows_active.find(cfg_sname);
|
|
if (i != cfg_windows_active.end()) cfg_windows_active.erase(i);
|
|
}
|
|
}
|
|
};
|
|
|
|
class ShowHelpAbout : public GUI::ToplevelWindow {
|
|
protected:
|
|
GUI::Input *name;
|
|
public:
|
|
ShowHelpAbout(GUI::Screen *parent, int x, int y, const char *title) :
|
|
ToplevelWindow(parent, x, y, 420, 230, title) {
|
|
std::istringstream in(aboutmsg);
|
|
int r=0;
|
|
if (in) for (std::string line; std::getline(in, line); ) {
|
|
r+=25;
|
|
new GUI::Label(this, 40, r, line.c_str());
|
|
}
|
|
(new GUI::Button(this, 180, 155, MSG_Get("CLOSE"), 70))->addActionHandler(this);
|
|
move(parent->getWidth()>this->getWidth()?(parent->getWidth()-this->getWidth())/2:0,parent->getHeight()>this->getHeight()?(parent->getHeight()-this->getHeight())/2:0);
|
|
}
|
|
|
|
void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) override {
|
|
(void)b;//UNUSED
|
|
if (arg == MSG_Get("CLOSE"))
|
|
close();
|
|
if (shortcut) running = false;
|
|
}
|
|
};
|
|
|
|
extern std::string helpcmd;
|
|
char *str_replace(const char *orig, const char *rep, const char *with);
|
|
class ShowHelpCommand : public GUI::ToplevelWindow {
|
|
protected:
|
|
GUI::Input *name;
|
|
public:
|
|
ShowHelpCommand(GUI::Screen *parent, int x, int y, const char *title) :
|
|
ToplevelWindow(parent, x, y, 750, 270, title) {
|
|
if (helpcmd=="CD") helpcmd="CHDIR";
|
|
else if (helpcmd=="DEL") helpcmd="DELETE";
|
|
else if (helpcmd=="LH") helpcmd="LOADHIGH";
|
|
else if (helpcmd=="MD") helpcmd="MKDIR";
|
|
else if (helpcmd=="RD") helpcmd="RMDIR";
|
|
else if (helpcmd=="REN") helpcmd="RENAME";
|
|
std::string helpinfo=std::string(MSG_Get(("SHELL_CMD_"+helpcmd+"_HELP").c_str()))+"\n"+std::string(MSG_Get(("SHELL_CMD_"+helpcmd+"_HELP_LONG").c_str()));
|
|
std::istringstream in(str_replace(str_replace(str_replace(str_replace(helpinfo.c_str(), "%%", "%"), "\033[0m", ""), "\033[33;1m", ""), "\033[37;1m", ""));
|
|
int r=0;
|
|
if (in) for (std::string line; std::getline(in, line); ) {
|
|
r+=25;
|
|
new GUI::Label(this, 40, r, line.c_str());
|
|
}
|
|
(new GUI::Button(this, 350, r+40, MSG_Get("CLOSE"), 70))->addActionHandler(this);
|
|
resize(750, r+120);
|
|
move(parent->getWidth()>this->getWidth()?(parent->getWidth()-this->getWidth())/2:0,parent->getHeight()>this->getHeight()?(parent->getHeight()-this->getHeight())/2:0);
|
|
}
|
|
|
|
void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) override {
|
|
(void)b;//UNUSED
|
|
if (arg == MSG_Get("CLOSE"))
|
|
close();
|
|
if (shortcut) running = false;
|
|
}
|
|
};
|
|
|
|
struct ThemePresetEntry {
|
|
ThemePresetEntry(const std::string &_name,const GUI::ThemeWindows31 &&_theme,const unsigned int _special=0) : name(_name), theme(_theme), special(_special) {}
|
|
|
|
std::string name;
|
|
GUI::ThemeWindows31 theme;
|
|
unsigned int special;
|
|
|
|
static constexpr unsigned int PREPEND_HLINE = 1u << 0u;
|
|
static constexpr unsigned int PREPEND_VLINE = 1u << 1u;
|
|
};
|
|
|
|
#define ENTRY(x) ThemePresetEntry( GUI::x::GetName(), GUI::x() )
|
|
#define ENTRYS(x,s) ThemePresetEntry( GUI::x::GetName(), GUI::x(), s )
|
|
static const ThemePresetEntry theme_presets[] = {
|
|
ENTRY( ThemeWindows31WindowsDefault),
|
|
ENTRYS( ThemeWindows31Arizona, ThemePresetEntry::PREPEND_HLINE),
|
|
ENTRY( ThemeWindows31Bordeaux),
|
|
ENTRY( ThemeWindows31Cinnamon),
|
|
ENTRY( ThemeWindows31Designer),
|
|
ENTRY( ThemeWindows31EmeraldCity),
|
|
ENTRY( ThemeWindows31Fluorescent),
|
|
ENTRY( ThemeWindows31HotDogStand),
|
|
ENTRY( ThemeWindows31LCDDefaultScreenSettings),
|
|
ENTRY( ThemeWindows31LCDReversedDark),
|
|
ENTRY( ThemeWindows31LCDReversedLight),
|
|
ENTRY( ThemeWindows31BlackLeatherJacket),
|
|
ENTRYS( ThemeWindows31Mahogany, ThemePresetEntry::PREPEND_VLINE),
|
|
ENTRY( ThemeWindows31Monochrome),
|
|
ENTRY( ThemeWindows31Ocean),
|
|
ENTRY( ThemeWindows31Pastel),
|
|
ENTRY( ThemeWindows31Patchwork),
|
|
ENTRY( ThemeWindows31PlasmaPowerSaver),
|
|
ENTRY( ThemeWindows31Rugby),
|
|
ENTRY( ThemeWindows31TheBlues),
|
|
ENTRY( ThemeWindows31Tweed),
|
|
ENTRY( ThemeWindows31Valentine),
|
|
ENTRY( ThemeWindows31Wingtips)
|
|
};
|
|
|
|
class ConfigurationWindow : public GUI::ToplevelWindow {
|
|
public:
|
|
GUI::Button *saveButton, *closeButton;
|
|
ConfigurationWindow(GUI::Screen *parent, GUI::Size x, GUI::Size y, GUI::String& title) :
|
|
GUI::ToplevelWindow(parent, (int)x, (int)y, 30/*initial*/, 30/*initial*/, title) {
|
|
cfg_windows_active.clear();
|
|
|
|
GUI::Menubar *bar = new GUI::Menubar(this, 0, 0, getWidth()/*initial*/);
|
|
bar->addMenu(MSG_Get("CONFIGURATION"));
|
|
strcpy(tmp1, (MSG_Get("SAVE")+std::string("...")).c_str());
|
|
bar->addItem(0,tmp1);
|
|
strcpy(tmp1, (MSG_Get("SAVE_LANGUAGE")+std::string("...")).c_str());
|
|
bar->addItem(0,tmp1);
|
|
bar->addItem(0,"");
|
|
bar->addItem(0,MSG_Get("CLOSE"));
|
|
bar->addMenu(MSG_Get("SETTINGS"));
|
|
|
|
// theme menu
|
|
bar->addMenu("Theme"); // TODO MSG_Get("THEME")
|
|
for (size_t ti=0;ti < (sizeof(theme_presets)/sizeof(theme_presets[0]));ti++) {
|
|
if (theme_presets[ti].special & ThemePresetEntry::PREPEND_HLINE)
|
|
bar->addItem(2, "");
|
|
if (theme_presets[ti].special & ThemePresetEntry::PREPEND_VLINE)
|
|
bar->addItem(2, "|");
|
|
|
|
bar->addItem(2, theme_presets[ti].name);
|
|
}
|
|
|
|
bar->addMenu(mainMenu.get_item("HelpMenu").get_text().c_str());
|
|
bar->addItem(3,MSG_Get("VISIT_HOMEPAGE"));
|
|
bar->addItem(3,"");
|
|
if (!dos_kernel_disabled) {
|
|
/* these do not work until shell help text is registered */
|
|
bar->addItem(3,MSG_Get("GET_STARTED"));
|
|
bar->addItem(3,MSG_Get("CDROM_SUPPORT"));
|
|
bar->addItem(3,"");
|
|
}
|
|
bar->addItem(3,MSG_Get("INTRODUCTION"));
|
|
bar->addItem(3,mainMenu.get_item("help_about").get_text().c_str());
|
|
bar->addActionHandler(this);
|
|
|
|
int gridbtnwidth = 130;
|
|
int gridbtnheight = GUI::CurrentTheme.ButtonHeight;
|
|
int gridbtnx = 12;
|
|
int gridbtny = 25;
|
|
int btnperrow = 4;
|
|
int i = 0;
|
|
|
|
constexpr auto margin = 3;
|
|
|
|
const auto xSpace = gridbtnwidth + margin;
|
|
const auto ySpace = gridbtnheight + margin;
|
|
|
|
std::function< std::pair<int,int>(const int) > gridfunc = [&/*access to locals here*/](const int i){
|
|
return std::pair<int,int>(gridbtnx+(i%btnperrow)*xSpace, gridbtny+(i/btnperrow)*ySpace);
|
|
};
|
|
|
|
std::vector<Section*> sections; // sorted by relevance
|
|
|
|
// actual sorting
|
|
{
|
|
std::vector<std::string> sectionNames = {
|
|
"log", "dosbox", "render", "sdl",
|
|
"video", "voodoo", "vsync", "ttf",
|
|
"dos", "dosv", "pc98", "4dos",
|
|
"autoexec", "config", "cpu", "speaker",
|
|
"sblaster", "gus", "midi", "mixer",
|
|
"innova", "imfc", "joystick", "mapper",
|
|
"keyboard", "serial", "parallel", "printer",
|
|
"ipx", "ne2000", "ethernet, pcap", "ethernet, slirp",
|
|
"ide, primary", "ide, secondary", "ide, tertiary", "ide, quaternary",
|
|
"ide, quinternary", "ide, sexternary", "ide, septernary", "ide, octernary",
|
|
"fdc, primary",
|
|
};
|
|
|
|
Section* section;
|
|
|
|
auto temp1 = 0;
|
|
|
|
while((section = control->GetSection(temp1++)))
|
|
{
|
|
sections.push_back(section);
|
|
}
|
|
|
|
std::unordered_map<std::string, int> sectionMap;
|
|
|
|
auto temp2 = 0;
|
|
|
|
for(const auto& name : sectionNames)
|
|
{
|
|
sectionMap[name] = temp2++;
|
|
}
|
|
|
|
std::sort(
|
|
sections.begin(), sections.end(),
|
|
[§ionMap](const Section* a, const Section* b)
|
|
{
|
|
const auto itA = sectionMap.find(a->GetName());
|
|
const auto itB = sectionMap.find(b->GetName());
|
|
if(itA != sectionMap.end() && itB != sectionMap.end())
|
|
{
|
|
return itA->second < itB->second;
|
|
}
|
|
if(itA != sectionMap.end())
|
|
{
|
|
return true;
|
|
}
|
|
if(itB != sectionMap.end())
|
|
{
|
|
return false;
|
|
}
|
|
return false;
|
|
});
|
|
}
|
|
|
|
for(const auto & sec : sections)
|
|
{
|
|
if (i != 0 && (i%16) == 0) bar->addItem(1, "|");
|
|
std::string sectionTitle = CapName(std::string(sec->GetName()));
|
|
const auto sz = gridfunc(i);
|
|
GUI::Button *b = new GUI::Button(this, sz.first, sz.second, sectionTitle, gridbtnwidth, gridbtnheight);
|
|
b->addActionHandler(this);
|
|
bar->addItem(1, sectionTitle);
|
|
i++;
|
|
}
|
|
|
|
const auto finalgridpos = gridfunc(i - 1);
|
|
int closerow_y = finalgridpos.second + 5 + ySpace;
|
|
|
|
advopt = new GUI::Checkbox(this, gridbtnx, closerow_y, MSG_Get("SHOW_ADVOPT"));
|
|
Section_prop * section=static_cast<Section_prop *>(control->GetSection("dosbox"));
|
|
advopt->setChecked(section->Get_bool("show advanced options") || advOptUser);
|
|
|
|
// apply theme
|
|
{
|
|
auto theme = std::string(section->Get_string("configuration tool theme"));
|
|
|
|
if(theme.empty())
|
|
{
|
|
bool dark = false;
|
|
|
|
#if defined(WIN32) && !defined(HX_DOS)
|
|
// ReSharper disable once CppDeclaratorDisambiguatedAsFunction
|
|
bool HostDarkMode(); // NOLINT(clang-diagnostic-vexing-parse)
|
|
dark = HostDarkMode();
|
|
#endif
|
|
TryApplyTheme(
|
|
dark
|
|
? GUI::ThemeWindows31LCDReversedDark::GetName()
|
|
: GUI::ThemeWindows31WindowsDefault::GetName());
|
|
}
|
|
else
|
|
{
|
|
TryApplyTheme(theme);
|
|
}
|
|
}
|
|
|
|
strcpy(tmp1, (MSG_Get("SAVE")+std::string("...")).c_str());
|
|
|
|
const auto xSave = gridbtnx + (gridbtnwidth + margin) * 2;
|
|
const auto xExit = gridbtnx + (gridbtnwidth + margin) * 3;
|
|
|
|
(saveButton = new GUI::Button(this, xSave, closerow_y, tmp1, gridbtnwidth, gridbtnheight))->addActionHandler(this);
|
|
(closeButton = new GUI::Button(this, xExit, closerow_y, MSG_Get("CLOSE"), gridbtnwidth, gridbtnheight))->addActionHandler(this);
|
|
|
|
resize(gridbtnx + (xSpace * btnperrow) + gridbtnx + border_left + border_right,
|
|
closerow_y + closeButton->getHeight() + 8 + border_top + border_bottom);
|
|
|
|
bar->resize(getWidth(),bar->getHeight());
|
|
move(parent->getWidth()>this->getWidth()?(parent->getWidth()-this->getWidth())/2:0,parent->getHeight()>this->getHeight()?(parent->getHeight()-this->getHeight())/2:0);
|
|
}
|
|
|
|
~ConfigurationWindow() { running = false; cfg_windows_active.clear(); }
|
|
|
|
bool keyDown(const GUI::Key &key) override {
|
|
if (GUI::ToplevelWindow::keyDown(key)) return true;
|
|
return false;
|
|
}
|
|
|
|
bool keyUp(const GUI::Key &key) override {
|
|
if (GUI::ToplevelWindow::keyUp(key)) return true;
|
|
|
|
if (key.special == GUI::Key::Escape) {
|
|
closeButton->executeAction();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static bool TryApplyTheme(const GUI::String& name)
|
|
{
|
|
for (size_t ti=0;ti < (sizeof(theme_presets)/sizeof(theme_presets[0]));ti++) {
|
|
if (name == theme_presets[ti].name) {
|
|
GUI::DefaultTheme = theme_presets[ti].theme;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) override {
|
|
advOptUser = advopt->isChecked();
|
|
if (TryApplyTheme(arg)) { // TODO MSG_Get("THEME"), save to config
|
|
Section_prop * section=static_cast<Section_prop *>(control->GetSection("dosbox"));
|
|
section->Get_prop("configuration tool theme")->SetValue(arg);
|
|
}
|
|
GUI::String sname = RestoreName(arg);
|
|
sname.at(0) = (unsigned int)std::tolower((int)sname.at(0));
|
|
Section *sec;
|
|
strcpy(tmp1, mainMenu.get_item("help_about").get_text().c_str());
|
|
strcpy(tmp2, (MSG_Get("SAVE")+std::string("...")).c_str());
|
|
if (arg == MSG_Get("OK") || arg == MSG_Get("CANCEL") || arg == MSG_Get("CLOSE")) {
|
|
running = false;
|
|
} else if (sname == "autoexec") {
|
|
auto lookup = cfg_windows_active.find(sname);
|
|
if (lookup == cfg_windows_active.end()) {
|
|
Section_line *section = static_cast<Section_line *>(control->GetSection((const char *)sname));
|
|
auto *np = new AutoexecEditor(getScreen(), 50, 30, section);
|
|
cfg_windows_active[sname] = np;
|
|
np->cfg_sname = sname;
|
|
np->raise();
|
|
}
|
|
else {
|
|
lookup->second->raise();
|
|
}
|
|
} else if (sname == "config" || sname == "4dos") {
|
|
auto lookup = cfg_windows_active.find(sname);
|
|
if (lookup == cfg_windows_active.end()) {
|
|
Section_prop *section = static_cast<Section_prop *>(control->GetSection((const char *)sname));
|
|
auto *np = new ConfigEditor(getScreen(), 50, 30, section);
|
|
cfg_windows_active[sname] = np;
|
|
np->cfg_sname = sname;
|
|
np->raise();
|
|
}
|
|
else {
|
|
lookup->second->raise();
|
|
}
|
|
} else if ((sec = control->GetSection((const char *)sname))) {
|
|
auto lookup = cfg_windows_active.find(sname);
|
|
if (lookup == cfg_windows_active.end()) {
|
|
Section_prop *section = static_cast<Section_prop *>(sec);
|
|
auto *np = new SectionEditor(getScreen(), 50, 30, section);
|
|
cfg_windows_active[sname] = np;
|
|
np->cfg_sname = sname;
|
|
np->raise();
|
|
}
|
|
else {
|
|
lookup->second->raise();
|
|
}
|
|
} else if (arg == MSG_Get("VISIT_HOMEPAGE")) {
|
|
std::string url = "https://dosbox-x.com/";
|
|
#if defined(WIN32)
|
|
ShellExecute(NULL, "open", url.c_str(), NULL, NULL, SW_SHOWNORMAL);
|
|
#elif defined(LINUX)
|
|
system(("xdg-open "+url).c_str());
|
|
#elif defined(MACOSX)
|
|
system(("open "+url).c_str());
|
|
#endif
|
|
} else if (arg == tmp1) {
|
|
//new GUI::MessageBox2(getScreen(), 100, 150, 330, "About DOSBox-X", aboutmsg);
|
|
new GUI::MessageBox2(getScreen(), getScreen()->getWidth()>350?(parent->getWidth()-350)/2:0, 150, 350, mainMenu.get_item("help_about").get_text().c_str(), aboutmsg);
|
|
} else if (arg == MSG_Get("INTRODUCTION")) {
|
|
//new GUI::MessageBox2(getScreen(), 20, 50, 540, "Introduction", intromsg);
|
|
new GUI::MessageBox2(getScreen(), getScreen()->getWidth()>540?(parent->getWidth()-540)/2:0, 150, 540, mainMenu.get_item("help_intro").get_text().c_str(), MSG_Get("INTRO_MESSAGE"));
|
|
} else if (arg == MSG_Get("GET_STARTED")) {
|
|
std::string msg = MSG_Get("PROGRAM_INTRO_MOUNT_START");
|
|
#ifdef WIN32
|
|
msg += MSG_Get("PROGRAM_INTRO_MOUNT_EXST_WINDOWS")+std::string("\n\n")+MSG_Get("PROGRAM_INTRO_MOUNT_EXEN_WINDOWS");
|
|
#else
|
|
msg += MSG_Get("PROGRAM_INTRO_MOUNT_EXST_OTHER")+std::string("\n\n")+MSG_Get("PROGRAM_INTRO_MOUNT_EXEN_OTHER");
|
|
#endif
|
|
msg += std::string("\n\n")+MSG_Get("PROGRAM_INTRO_MOUNT_END");
|
|
|
|
//new GUI::MessageBox2(getScreen(), 0, 50, 680, std::string("Getting Started"), msg);
|
|
new GUI::MessageBox2(getScreen(), getScreen()->getWidth()>680?(parent->getWidth()-680)/2:0, 50, 680, MSG_Get("GET_STARTED"), msg.c_str());
|
|
} else if (arg == MSG_Get("CDROM_SUPPORT")) {
|
|
//new GUI::MessageBox2(getScreen(), 20, 50, 640, "CD-ROM Support", MSG_Get("PROGRAM_INTRO_CDROM"));
|
|
new GUI::MessageBox2(getScreen(), getScreen()->getWidth()>640?(parent->getWidth()-640)/2:0, 50, 640, MSG_Get("CDROM_SUPPORT"), MSG_Get("PROGRAM_INTRO_CDROM"));
|
|
} else if (arg == tmp2) {
|
|
strcpy(tmp1, (MSG_Get("SAVE_CONFIGURATION")+std::string("...")).c_str());
|
|
auto *np = new SaveDialog(getScreen(), 50, 100, tmp1);
|
|
np->raise();
|
|
} else {
|
|
strcpy(tmp2, (MSG_Get("SAVE_LANGUAGE")+std::string("...")).c_str());
|
|
if (arg == tmp2) {
|
|
auto *np = new SaveLangDialog(getScreen(), 90, 100, tmp2);
|
|
np->raise();
|
|
} else
|
|
return ToplevelWindow::actionExecuted(b, arg);
|
|
}
|
|
}
|
|
};
|
|
|
|
/*********************************************************************************************************************/
|
|
/* UI control functions */
|
|
|
|
static void UI_Execute(GUI::ScreenSDL *screen) {
|
|
SDL_Surface *sdlscreen;
|
|
SDL_Event event;
|
|
GUI::String configString = GUI::String(MSG_Get("CONFIG_TOOL"));
|
|
|
|
sdlscreen = screen->getSurface();
|
|
auto *cfg_wnd = new ConfigurationWindow(screen, 40, 10, configString);
|
|
cfg_wnd->raise();
|
|
|
|
// event loop
|
|
while (running) {
|
|
while (SDL_PollEvent(&event)) {
|
|
switch (event.type) {
|
|
#if defined(_WIN32) && !defined(HX_DOS)
|
|
case SDL_SYSWMEVENT : {
|
|
switch ( event.syswm.msg->
|
|
#if defined(C_SDL2)
|
|
msg.win.
|
|
#endif
|
|
msg ) {
|
|
case WM_COMMAND:
|
|
# if DOSBOXMENU_TYPE == DOSBOXMENU_HMENU
|
|
if (GetMenu(GetHWND())) {
|
|
# if defined(C_SDL2)
|
|
if (guiMenu.mainMenuWM_COMMAND((unsigned int)LOWORD(event.syswm.msg->msg.win.wParam)))
|
|
# else
|
|
if (guiMenu.mainMenuWM_COMMAND((unsigned int)LOWORD(event.syswm.msg->wParam)))
|
|
# endif
|
|
return;
|
|
}
|
|
# endif
|
|
break;
|
|
}
|
|
} break;
|
|
#endif
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (!screen->event(event)) {
|
|
if (event.type == SDL_QUIT) running = false;
|
|
}
|
|
}
|
|
|
|
//Selecting keyboard will create a new surface.
|
|
screen->watchTime();
|
|
sdlscreen = screen->getSurface();
|
|
|
|
if (background)
|
|
SDL_BlitSurface(background, NULL, sdlscreen, NULL);
|
|
else
|
|
SDL_FillRect(sdlscreen, nullptr, 0);
|
|
|
|
screen->update(screen->getTime());
|
|
|
|
#if defined(C_SDL2)
|
|
SDL_Window* GFX_GetSDLWindow(void);
|
|
SDL_UpdateWindowSurface(GFX_GetSDLWindow());
|
|
#else
|
|
SDL_UpdateRect(sdlscreen, 0, 0, 0, 0);
|
|
#endif
|
|
|
|
SDL_Delay(40);
|
|
}
|
|
}
|
|
|
|
static void UI_Select(GUI::ScreenSDL *screen, int select) {
|
|
SDL_Surface *sdlscreen = NULL;
|
|
Section_line *section2 = NULL;
|
|
Section_prop *section = NULL;
|
|
Section *sec = NULL;
|
|
SDL_Event event;
|
|
GUI::String configString = GUI::String(MSG_Get("CONFIG_TOOL"));
|
|
|
|
sdlscreen = screen->getSurface();
|
|
switch (select) {
|
|
case 0:
|
|
new GUI::MessageBox2(screen, 200, 150, 280, "", "");
|
|
running=false;
|
|
break;
|
|
case 1: {
|
|
strcpy(tmp1, (MSG_Get("SAVE_CONFIGURATION")+std::string("...")).c_str());
|
|
auto *np = new SaveDialog(screen, 90, 100, tmp1);
|
|
np->raise();
|
|
} break;
|
|
case 2: {
|
|
sec = control->GetSection("sdl");
|
|
section=static_cast<Section_prop *>(sec);
|
|
auto *p = new SectionEditor(screen,50,30,section);
|
|
p->raise();
|
|
} break;
|
|
case 3:
|
|
sec = control->GetSection("dosbox");
|
|
section=static_cast<Section_prop *>(sec);
|
|
new SectionEditor(screen,50,30,section);
|
|
break;
|
|
case 4:
|
|
sec = control->GetSection("mixer");
|
|
section=static_cast<Section_prop *>(sec);
|
|
new SectionEditor(screen,50,30,section);
|
|
break;
|
|
case 5:
|
|
sec = control->GetSection("serial");
|
|
section=static_cast<Section_prop *>(sec);
|
|
new SectionEditor(screen,50,30,section);
|
|
break;
|
|
case 6:
|
|
sec = control->GetSection("ne2000");
|
|
section=static_cast<Section_prop *>(sec);
|
|
new SectionEditor(screen,50,30,section);
|
|
break;
|
|
case 7:
|
|
section2 = static_cast<Section_line *>(control->GetSection("autoexec"));
|
|
new AutoexecEditor(screen, 50, 30, section2);
|
|
break;
|
|
case 8:
|
|
sec = control->GetSection("glide");
|
|
section=static_cast<Section_prop *>(sec);
|
|
new SectionEditor(screen,50,30,section);
|
|
break;
|
|
case 9: {
|
|
strcpy(tmp1, (MSG_Get("SAVE_LANGUAGE")+std::string("...")).c_str());
|
|
auto *np = new SaveLangDialog(screen, 90, 100, tmp1);
|
|
np->raise();
|
|
} break;
|
|
case 10: {
|
|
auto *np = new ConfigurationWindow(screen, 40, 10, configString);
|
|
np->raise();
|
|
} break;
|
|
case 11:
|
|
sec = control->GetSection("parallel");
|
|
section=static_cast<Section_prop *>(sec);
|
|
new SectionEditor(screen,50,30,section);
|
|
break;
|
|
case 12:
|
|
sec = control->GetSection("printer");
|
|
section=static_cast<Section_prop *>(sec);
|
|
new SectionEditor(screen,50,30,section);
|
|
break;
|
|
case 13:
|
|
sec = control->GetSection("cpu");
|
|
section=static_cast<Section_prop *>(sec);
|
|
new SectionEditor(screen,50,30,section);
|
|
break;
|
|
case 14:
|
|
sec = control->GetSection("dos");
|
|
section=static_cast<Section_prop *>(sec);
|
|
new SectionEditor(screen,50,30,section);
|
|
break;
|
|
case 15:
|
|
sec = control->GetSection("midi");
|
|
section=static_cast<Section_prop *>(sec);
|
|
new SectionEditor(screen,50,30,section);
|
|
break;
|
|
case 16: {
|
|
auto *np1 = new SetCycles(screen, 90, 100, "Set CPU Cycles...");
|
|
np1->raise();
|
|
} break;
|
|
case 17: {
|
|
auto *np2 = new SetVsyncrate(screen, 90, 100, "Set vertical syncrate...");
|
|
np2->raise();
|
|
} break;
|
|
case 18: {
|
|
auto *np3 = new SetLocalSize(screen, 90, 100, "Set Default Local Freesize...");
|
|
np3->raise();
|
|
} break;
|
|
case 19: {
|
|
auto *np4 = new SetDOSVersion(screen, 90, 100, "Edit reported DOS version...");
|
|
np4->raise();
|
|
} break;
|
|
case 20: {
|
|
auto *np5 = new SetAspectRatio(screen, 90, 100, "Set aspect ratio...");
|
|
np5->raise();
|
|
} break;
|
|
case 21: {
|
|
auto *np6 = new SetTitleText(screen, 90, 130, mainMenu.get_item("set_titletext").get_text().c_str());
|
|
np6->raise();
|
|
} break;
|
|
case 22: {
|
|
auto *np6 = new SetTransparency(screen, 90, 100, mainMenu.get_item("set_transparency").get_text().c_str());
|
|
np6->raise();
|
|
} break;
|
|
case 23: {
|
|
auto *np7 = new ShowLoadWarning(screen, 150, 120, "DOSBox-X version mismatch. Load the state anyway?");
|
|
np7->raise();
|
|
} break;
|
|
case 24: {
|
|
auto *np7 = new ShowLoadWarning(screen, 150, 120, "Program name mismatch. Load the state anyway?");
|
|
np7->raise();
|
|
} break;
|
|
case 25: {
|
|
auto *np7 = new ShowLoadWarning(screen, 150, 120, "Memory size mismatch. Load the state anyway?");
|
|
np7->raise();
|
|
} break;
|
|
case 26: {
|
|
auto *np7 = new ShowLoadWarning(screen, 150, 120, "Machine type mismatch. Load the state anyway?");
|
|
np7->raise();
|
|
} break;
|
|
case 27: {
|
|
auto *np7 = new ShowLoadWarning(screen, 150, 120, "Are you sure to remove the state in this slot?");
|
|
np7->raise();
|
|
} break;
|
|
case 28: {
|
|
auto *np7 = new SetSensitivity(screen, 90, 100, "Set mouse sensitivity...");
|
|
np7->raise();
|
|
} break;
|
|
case 29: {
|
|
auto *np7 = new SetAutoSave(screen, 0, 0, "Auto-save settings...");
|
|
np7->raise();
|
|
} break;
|
|
case 30: {
|
|
auto *np7 = new SetRefreshRate(screen, 0, 0, mainMenu.get_item("refresh_rate").get_text().c_str());
|
|
np7->raise();
|
|
} break;
|
|
case 31: if (statusdrive>-1 && statusdrive<DOS_DRIVES && Drives[statusdrive]) {
|
|
auto *np8 = new ShowDriveInfo(screen, 120, 50, MSG_Get("DRIVE_INFORMATION"));
|
|
np8->raise();
|
|
} break;
|
|
case 32: {
|
|
auto *np9 = new ShowDriveNumber(screen, 110, 70, MSG_Get("MOUNTED_DRIVE_NUMBER"));
|
|
np9->raise();
|
|
} break;
|
|
case 33: {
|
|
auto *np10 = new ShowIDEInfo(screen, 150, 70, MSG_Get("IDE_CONTROLLER_ASSIGNMENT"));
|
|
np10->raise();
|
|
} break;
|
|
case 34: {
|
|
auto *np11 = new ShowHelpIntro(screen, 70, 70, mainMenu.get_item("help_intro").get_text().c_str());
|
|
np11->raise();
|
|
} break;
|
|
case 35: {
|
|
auto *np12 = new ShowHelpAbout(screen, 110, 70, mainMenu.get_item("help_about").get_text().c_str());
|
|
np12->raise();
|
|
} break;
|
|
case 36: {
|
|
auto *np13 = new ShowHelpCommand(screen, 150, 120, (MSG_Get("HELP_COMMAND")+std::string(": ")+helpcmd).c_str());
|
|
np13->raise();
|
|
} break;
|
|
case 37: {
|
|
auto *np14 = new MakeDiskImage(screen, 110, 70, MSG_Get("CREATE_IMAGE"));
|
|
np14->raise();
|
|
} break;
|
|
case 38: {
|
|
auto *np15 = new ShowHelpNIC(screen, 70, 70);
|
|
np15->raise();
|
|
} break;
|
|
case 39: {
|
|
auto *np15 = new ShowHelpPRT(screen, 70, 70);
|
|
np15->raise();
|
|
} break;
|
|
case 40: {
|
|
auto *np16 = new ShowMixerInfo(screen, 90, 70, MSG_Get("CURRENT_VOLUME"));
|
|
np16->raise();
|
|
} break;
|
|
case 41: {
|
|
auto *np16 = new ShowSBInfo(screen, 150, 100, MSG_Get("CURRENT_SBCONFIG"));
|
|
np16->raise();
|
|
} break;
|
|
case 42: {
|
|
auto *np16 = new ShowMidiDevice(screen, 150, 100, MSG_Get("CURRENT_MIDICONFIG"));
|
|
np16->raise();
|
|
} break;
|
|
#if C_DEBUG
|
|
case 43: {
|
|
npwin = new LogWindow(screen, 70, 70);
|
|
npwin->raise();
|
|
} break;
|
|
case 44: {
|
|
npwin = new CodeWindow(screen, 70, 70);
|
|
npwin->raise();
|
|
} break;
|
|
#endif
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// event loop
|
|
while (running) {
|
|
while (SDL_PollEvent(&event)) {
|
|
switch (event.type) {
|
|
#if defined(_WIN32) && !defined(HX_DOS)
|
|
case SDL_SYSWMEVENT : {
|
|
switch ( event.syswm.msg->
|
|
#if defined(C_SDL2)
|
|
msg.win.
|
|
#endif
|
|
msg ) {
|
|
case WM_COMMAND:
|
|
# if DOSBOXMENU_TYPE == DOSBOXMENU_HMENU
|
|
if (GetMenu(GetHWND())) {
|
|
# if defined(C_SDL2)
|
|
if (guiMenu.mainMenuWM_COMMAND((unsigned int)LOWORD(event.syswm.msg->msg.win.wParam)))
|
|
# else
|
|
if (guiMenu.mainMenuWM_COMMAND((unsigned int)LOWORD(event.syswm.msg->wParam)))
|
|
# endif
|
|
return;
|
|
}
|
|
# endif
|
|
break;
|
|
}
|
|
} break;
|
|
#endif
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (!screen->event(event)) {
|
|
if (event.type == SDL_QUIT) running = false;
|
|
}
|
|
}
|
|
|
|
if (background)
|
|
SDL_BlitSurface(background, NULL, sdlscreen, NULL);
|
|
else
|
|
SDL_FillRect(sdlscreen, nullptr, 0);
|
|
|
|
screen->update(4);
|
|
#if defined(C_SDL2)
|
|
SDL_Window* GFX_GetSDLWindow(void);
|
|
SDL_UpdateWindowSurface(GFX_GetSDLWindow());
|
|
#else
|
|
SDL_UpdateRect(sdlscreen, 0, 0, 0, 0);
|
|
#endif
|
|
SDL_Delay(20);
|
|
}
|
|
}
|
|
|
|
int sel = -1;
|
|
bool switchttf = false, gofs = false;
|
|
void RunCfgTool(Bitu val) {
|
|
(void)val;//unused
|
|
gofs=false;
|
|
#if defined(USE_TTF)
|
|
if (!ttf.inUse && switchttf) {
|
|
ttf_switch_on();
|
|
if (sel==36&&!GFX_IsFullscreen()) {gofs=true;GFX_SwitchFullScreen();}
|
|
}
|
|
switchttf = false;
|
|
#endif
|
|
GUI::ScreenSDL *screen = UI_Startup(NULL);
|
|
if (sel<0)
|
|
UI_Execute(screen);
|
|
else
|
|
UI_Select(screen,sel);
|
|
UI_Shutdown(screen);
|
|
delete screen;
|
|
if (sel>-1) {
|
|
if (gofs&&GFX_IsFullscreen()) GFX_SwitchFullScreen();
|
|
gofs=false;
|
|
toscale=true;
|
|
shortcut=false;
|
|
shortcutid=-1;
|
|
statusdrive=-1;
|
|
helpcmd = "";
|
|
MAPPER_ReleaseAllKeys();
|
|
GFX_LosingFocus();
|
|
sel = -1;
|
|
}
|
|
if (GFX_GetPreventFullscreen()) {
|
|
#if C_OPENGL
|
|
voodoo_ogl_update_dimensions();
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void GUI_Shortcut(int select) {
|
|
if(!select || running) return;
|
|
|
|
MAPPER_ReleaseAllKeys();
|
|
GFX_LosingFocus();
|
|
|
|
shortcutid=select;
|
|
shortcut=true;
|
|
sel = select;
|
|
#if defined(USE_TTF)
|
|
if (ttf.inUse && !confres) {
|
|
ttf_switch_off();
|
|
GFX_EndUpdate(nullptr);
|
|
switchttf = true;
|
|
PIC_AddEvent(RunCfgTool, 100);
|
|
} else
|
|
#endif
|
|
RunCfgTool(0);
|
|
}
|
|
|
|
void GUI_Run(bool pressed) {
|
|
if (pressed || running) return;
|
|
|
|
sel = -1;
|
|
#if defined(USE_TTF)
|
|
if (ttf.inUse) {
|
|
ttf_switch_off();
|
|
GFX_EndUpdate(nullptr);
|
|
switchttf = true;
|
|
PIC_AddEvent(RunCfgTool, 100);
|
|
} else
|
|
#endif
|
|
RunCfgTool(0);
|
|
}
|