DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
include/menu.h
00001 /*
00002  *  Copyright (C) 2002-2020  The DOSBox Team
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License along
00015  *  with this program; if not, write to the Free Software Foundation, Inc.,
00016  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  */
00018 
00019 #include <string>
00020 #include "config.h"
00021 #include "menudef.h"
00022 void SetVal(const std::string& secname, const std::string& preval, const std::string& val);
00023 
00024 #include <SDL_video.h>
00025 
00026 #ifdef __WIN32__
00027 #include "programs.h"
00028 
00029 void ToggleMenu(bool pressed);
00030 void mem_conf(std::string memtype, int option);
00031 void UnMount(int i_drive);
00032 void BrowseFolder( char drive , std::string drive_type );
00033 void Mount_Img(char drive, std::string realpath);
00034 void Mount_Img_Floppy(char drive, std::string realpath);
00035 void Mount_Img_HDD(char drive, std::string realpath);
00036 void DOSBox_SetMenu(void);
00037 void DOSBox_NoMenu(void);
00038 void DOSBox_RefreshMenu(void);
00039 void ToggleMenu(bool pressed);
00040 void DOSBox_CheckOS(int &id, int &major, int &minor);
00041 void MountDrive(char drive, const char drive2[DOS_PATHLENGTH]);
00042 void MountDrive_2(char drive, const char drive2[DOS_PATHLENGTH], std::string drive_type);
00043 void MENU_Check_Drive(HMENU handle, int cdrom, int floppy, int local, int image, int automount, int umount, char drive);
00044 bool MENU_SetBool(std::string secname, std::string value);
00045 void MENU_swapstereo(bool enabled);
00046 void* GetSetSDLValue(int isget, std::string& target, void* setval);
00047 void GFX_SetTitle(Bit32s cycles, Bits frameskip, Bits timing, bool paused);
00048 void change_output(int output);
00049 void res_input(bool type, const char * res);
00050 void res_init(void);
00051 int Reflect_Menu(void);
00052 extern bool DOSBox_Kor(void);
00053 
00054 extern unsigned int hdd_defsize;
00055 extern char hdd_size[20];
00056 extern HWND GetHWND(void);
00057 extern HWND GetSurfaceHWND(void);
00058 extern void GetDefaultSize(void);
00059 #define SCALER(opscaler,opsize) \
00060         if ((render.scale.op==opscaler) && (render.scale.size==opsize))
00061 
00062 #define SCALER_SW(opscaler,opsize) \
00063         if ((render.scale.op==opscaler) && (render.scale.size==opsize) && (!render.scale.hardware))
00064 
00065 #define SCALER_HW(opscaler,opsize) \
00066         if ((render.scale.op==opscaler) && (render.scale.size==opsize) && (render.scale.hardware))
00067 
00068 #define SCALER_2(opscaler,opsize) \
00069         ((render.scale.op==opscaler) && (render.scale.size==opsize))
00070 
00071 #define SCALER_SW_2(opscaler,opsize) \
00072         ((render.scale.op==opscaler) && (render.scale.size==opsize) && (!render.scale.hardware))
00073 
00074 #define SCALER_HW_2(opscaler,opsize) \
00075         ((render.scale.op==opscaler) && (render.scale.size==opsize) && (render.scale.hardware))
00076 
00077 #define AUTOMOUNT(name,name2) \
00078         (((GetDriveType(name) == 2) || (GetDriveType(name) == 3) || (GetDriveType(name) == 4) || (GetDriveType(name) == 5) || (GetDriveType(name) == 6)))&&(!Drives[name2-'A'])
00079 
00080 #else
00081 
00082 void DOSBox_CheckOS(int &id, int &major, int &minor);
00083 void DOSBox_RefreshMenu(void);
00084 void DOSBox_SetMenu(void);
00085 void DOSBox_NoMenu(void);
00086 
00087 // dummy Win32 functions for less #ifdefs
00088 #define GetHWND() (0)
00089 #define SetMenu(a,b)
00090 #define DragAcceptFiles(a,b)
00091 #define GetMenu(a) (0)
00092 
00093 // menu.cpp replacements; the optimizer will completely remove code based on these
00094 #define VER_PLATFORM_WIN32_NT (1)
00095 #define DOSBox_Kor() !strncmp("ko", getenv("LANG"), 2) // dirty hack.
00096 
00097 #endif
00098 
00099 /* menu interface mode */
00100 #define DOSBOXMENU_NULL     (0)     /* nothing */
00101 #define DOSBOXMENU_HMENU    (1)     /* Windows HMENU resources */
00102 #define DOSBOXMENU_NSMENU   (2)     /* Mac OS X NSMenu / NSMenuItem resources */
00103 #define DOSBOXMENU_SDLDRAW  (3)     /* menus that WE draw on the SDL surface */
00104 
00105 #if C_FORCE_MENU_SDLDRAW /* Programmer/Dev wants to compile with SDL drawn menus even if host OS offers menus (shrug) Ok */
00106 # define DOSBOXMENU_TYPE    DOSBOXMENU_SDLDRAW
00107 #elif defined(WIN32) && !defined(C_SDL2) && !defined(HX_DOS)
00108 # define DOSBOXMENU_TYPE    DOSBOXMENU_HMENU
00109 #elif defined(MACOSX)
00110 # define DOSBOXMENU_TYPE    DOSBOXMENU_NSMENU
00111 #elif defined(C_SDL2) /* SDL 2.x only */
00112 # define DOSBOXMENU_TYPE    DOSBOXMENU_SDLDRAW
00113 #elif !defined(C_SDL2) /* SDL 1.x only */
00114 # define DOSBOXMENU_TYPE    DOSBOXMENU_SDLDRAW
00115 #else
00116 # define DOSBOXMENU_TYPE    DOSBOXMENU_NULL
00117 #endif
00118 
00119 /* Whether or not the menu exists, and is NOT drawn by ourself (Windows and Mac OS X) */
00120 #if DOSBOXMENU_TYPE == DOSBOXMENU_HMENU || DOSBOXMENU_TYPE == DOSBOXMENU_NSMENU
00121 # define DOSBOXMENU_EXTERNALLY_MANAGED
00122 #endif
00123 
00124 void GUI_Shortcut(int select);
00125 
00126 #define DOSBOXMENU_ACCELMARK_STR        "\x01"
00127 #define DOSBOXMENU_ACCELMARK_CHAR       '\x01'
00128 
00129 #include <map>
00130 #include <vector>
00131 
00132 #ifndef MENU_DOSBOXMENU_H
00133 #define MENU_DOSBOXMENU_H
00134 
00135 class DOSBoxMenu {
00136     public:
00137         DOSBoxMenu(const DOSBoxMenu &src) = delete;             /* don't copy me */
00138         DOSBoxMenu(const DOSBoxMenu &&src) = delete;            /* don't move me */
00139     public:
00140         class item;
00141     public:
00142         enum item_type_t {
00143             item_type_id=0,
00144             submenu_type_id,
00145             separator_type_id,
00146             vseparator_type_id,
00147 
00148             MAX_id
00149         };
00150     public:
00151         typedef uint16_t                item_handle_t;
00152         typedef bool                  (*callback_t)(DOSBoxMenu * const,item * const);
00153         typedef std::string             mapper_event_t;     /* event name */
00154     public:
00155         class displaylist {
00156             friend DOSBoxMenu;
00157 
00158             public:
00159                                         displaylist();
00160                                         ~displaylist();
00161 #if DOSBOXMENU_TYPE == DOSBOXMENU_SDLDRAW
00162             public:
00163                 void                    DrawDisplayList(DOSBoxMenu &menu,bool updateScreen=true);
00164                 item_handle_t           itemFromPoint(DOSBoxMenu &menu,int x,int y);
00165 #endif
00166             protected:
00167                 bool                    items_changed = false;
00168                 bool                    order_changed = false;
00169                 std::vector<item_handle_t> disp_list;
00170             public:
00171                 const std::vector<item_handle_t> &get_disp_list(void) const {
00172                     return disp_list;
00173                 }
00174         };
00175     public:
00176         static constexpr item_handle_t  unassigned_item_handle = ((item_handle_t)(0xFFFFU)); 
00177         static constexpr callback_t     unassigned_callback = NULL;
00178         static const mapper_event_t     unassigned_mapper_event; /* empty std::string */
00179     public:
00180         struct accelerator {
00181                                         accelerator() { }
00182                                         accelerator(char _key,unsigned char _instance=0) : key(_key), key_instance(_instance) { }
00183 
00184             char                        key = 0;            /* ascii code i.e. 'g' */
00185             unsigned char               key_instance = 0;   /* which occurrence of the letter in the text */
00186         };
00187     public:
00188         class item {
00189             friend DOSBoxMenu;
00190 
00191             public:
00192                                         item();
00193                                         ~item();
00194             protected:
00195                 std::string             name;               /* item name */
00196                 std::string             text;               /* item text */
00197                 std::string             shortcut_text;      /* shortcut text on the right */
00198                 std::string             description;        /* description text */
00199                 struct accelerator      accelerator;        /* menu accelerator */
00200             protected:
00201                 item_handle_t           parent_id = unassigned_item_handle;
00202                 item_handle_t           master_id = unassigned_item_handle;
00203                 enum item_type_t        type = item_type_id;
00204             protected:
00205                 struct status {
00206                                         status() : changed(false), allocated(false),
00207                                                    enabled(true), checked(false),
00208                                                    in_use(false) { };
00209 
00210                     unsigned int        changed:1;
00211                     unsigned int        allocated:1;
00212                     unsigned int        enabled:1;
00213                     unsigned int        checked:1;
00214                     unsigned int        in_use:1;
00215                 } status = {};
00216             protected:
00217                 callback_t              callback_func = unassigned_callback;
00218                 mapper_event_t          mapper_event = unassigned_mapper_event;
00219             public:
00220                 displaylist             display_list;
00221             public:
00222                 uint64_t                user_defined = 0;
00223 #if DOSBOXMENU_TYPE == DOSBOXMENU_HMENU /* Windows menu handle */
00224             protected:
00225                 HMENU                   winMenu = NULL;
00226             protected:
00227                 void                    winAppendMenu(HMENU handle);
00228                 std::string             winConstructMenuText(void);
00229 #endif
00230 #if DOSBOXMENU_TYPE == DOSBOXMENU_NSMENU /* Mac OS X menu handle */
00231             protected:
00232                 void*                   nsMenuItem = NULL;
00233                 void*                   nsMenu = NULL;
00234             protected:
00235                 void                    nsAppendMenu(void *nsMenu);
00236 #endif
00237 #if DOSBOXMENU_TYPE == DOSBOXMENU_SDLDRAW
00238             protected:
00239                 SDL_Rect                screenBox = {0,0,0,0};      /* absolute screen coords */
00240                 SDL_Rect                checkBox = {0,0,0,0};       /* relative to screenbox */
00241                 SDL_Rect                textBox = {0,0,0,0};        /* relative to screenbox */
00242                 SDL_Rect                shortBox = {0,0,0,0};       /* relative to screenbox */
00243                 SDL_Rect                popupBox = {0,0,0,0};       /* absolute screen coords */
00244                 bool                    boxInit = false;
00245                 bool                    itemHover = false;
00246                 bool                    needRedraw = false;
00247                 bool                    itemHilight = false;
00248                 bool                    itemVisible = false;
00249                 bool                    itemHoverDrawn = false;
00250                 bool                    itemHilightDrawn = false;
00251                 bool                    borderTop = false;
00252             public:
00253                 void                    removeFocus(DOSBoxMenu &menu);
00254                 void                    removeHover(DOSBoxMenu &menu);
00255                 void                    drawMenuItem(DOSBoxMenu &menu);
00256                 void                    showItem(DOSBoxMenu &menu,bool show=true);
00257                 item&                   setHover(DOSBoxMenu &menu,bool ho=true);
00258                 item&                   setHilight(DOSBoxMenu &menu,bool hi=true);
00259                 void                    placeItem(DOSBoxMenu &menu,int x,int y,bool isTopLevel=false);
00260                 void                    placeItemFinal(DOSBoxMenu &menu,int finalwidth,bool isTopLevel=false);
00261                 void                    layoutSubmenu(DOSBoxMenu &menu, bool isTopLevel=false);
00262                 void                    updateScreenFromPopup(DOSBoxMenu &menu);
00263                 void                    updateScreenFromItem(DOSBoxMenu &menu);
00264                 void                    drawBackground(DOSBoxMenu &menu);
00265             public:
00266                 inline bool isHilight(void) const {
00267                     return itemHilight;
00268                 }
00269 #endif
00270             protected:
00271                 item&                   allocate(const DOSBoxMenu::item_handle_t id, const enum item_type_t new_type, const std::string& new_name);
00272                 void                    deallocate(void);
00273             public:
00274                 inline bool checkResetRedraw(void) {
00275 #if DOSBOXMENU_TYPE == DOSBOXMENU_SDLDRAW
00276                                         bool r = needRedraw || (itemHilight != itemHilightDrawn) || (itemHover != itemHoverDrawn);
00277                     needRedraw = false;
00278                     return r;
00279 #else
00280                                         return false;
00281 #endif
00282                 }
00283                 inline const std::string &get_name(void) const {
00284                     return name;
00285                 }
00286                 inline item_handle_t get_master_id(void) const {
00287                     return master_id;
00288                 }
00289                 inline bool is_allocated(void) const {
00290                     return master_id != unassigned_item_handle;
00291                 }
00292                 inline bool has_vis_text(void) const {
00293                     return type <= submenu_type_id;
00294                 }
00295                 inline bool has_vis_shortcut_text(void) const {
00296                     return type <= item_type_id;
00297                 }
00298                 inline bool has_vis_description(void) const {
00299                     return false;
00300                 }
00301                 inline bool has_vis_accelerator(void) const {
00302                     return type <= item_type_id;
00303                 }
00304                 inline bool has_vis_enabled(void) const {
00305                     return type <= submenu_type_id;
00306                 }
00307                 inline bool can_enable(void) const {
00308                     return type <= submenu_type_id;
00309                 }
00310                 inline bool has_vis_checked(void) const {
00311                     return type <= item_type_id;
00312                 }
00313                 inline bool can_check(void) const {
00314                     return type <= item_type_id;
00315                 }
00316             public:
00317                 void refresh_item(DOSBoxMenu &menu);
00318                 inline bool has_changed(void) const {
00319                     return status.changed;
00320                 }
00321                 void clear_changed(void) {
00322                     status.changed = false;
00323                 }
00324             public:
00325                 inline item &check(const bool f=true) {
00326                     if (status.checked != f) {
00327                         status.checked  = f;
00328                         if (can_check() && has_vis_checked())
00329                             status.changed = 1;
00330                     }
00331 
00332                     return *this;
00333                 }
00334                 inline bool is_checked(void) const {
00335                     return status.checked;
00336                 }
00337             public:
00338                 inline item &enable(const bool f=true) {
00339                     if (status.enabled != f) {
00340                         status.enabled  = f;
00341                         if (can_enable() && has_vis_enabled())
00342                             status.changed = 1;
00343                     }
00344 
00345                     return *this;
00346                 }
00347                 inline bool is_enabled(void) const {
00348                     return status.enabled;
00349                 }
00350             public:
00351                 inline item_type_t get_type(void) const {
00352                     return type;
00353                 }
00354                 void set_type(const item_type_t t) {
00355                     if (type >= separator_type_id && t >= separator_type_id)
00356                         type = t;
00357                 }
00358             public:
00359                 inline callback_t get_callback_function(void) const {
00360                     return callback_func;
00361                 }
00362                 inline item &set_callback_function(const callback_t f) {
00363                     callback_func = f;
00364                     return *this;
00365                 }
00366             public:
00367                 inline mapper_event_t get_mapper_event(void) const {
00368                     return mapper_event;
00369                 }
00370                 inline item& set_mapper_event(const mapper_event_t& e) {
00371                     mapper_event = e;
00372                     return *this;
00373                 }
00374             public:
00375                 inline const std::string &get_text(void) const {
00376                     return text;
00377                 }
00378                 inline item &set_text(const std::string &str) {
00379                     if (has_vis_text() && text != str)
00380                         status.changed = 1;
00381 
00382                     text = str;
00383                     return *this;
00384                 }
00385             public:
00386                 inline const std::string &get_shortcut_text(void) const {
00387                     return shortcut_text;
00388                 }
00389                 inline item &set_shortcut_text(const std::string &str) {
00390                     if (has_vis_shortcut_text() && shortcut_text != str)
00391                         status.changed = 1;
00392 
00393                     shortcut_text = str;
00394                     return *this;
00395                 }
00396             public:
00397                 inline const std::string &get_description(void) const {
00398                     return description;
00399                 }
00400                 inline item &set_description(const std::string &str) {
00401                     if (has_vis_description() && description != str)
00402                         status.changed = 1;
00403 
00404                     description = str;
00405                     return *this;
00406                 }
00407             public:
00408                 inline const struct accelerator &get_accelerator(void) const {
00409                     return accelerator;
00410                 }
00411                 inline item &set_accelerator(const struct accelerator &str) {
00412                     if (has_vis_accelerator()/* && accelerator != str*//*TODO*/)
00413                         status.changed = 1;
00414 
00415                     accelerator = str;
00416                     return *this;
00417                 }
00418         };
00419     public:
00420                                         DOSBoxMenu();
00421                                         ~DOSBoxMenu();
00422     public:
00423         bool                            item_exists(const item_handle_t i);
00424         bool                            item_exists(const std::string &name);
00425         item&                           get_item(const item_handle_t i);
00426         item&                           get_item(const std::string &name);
00427         item_handle_t                   get_item_id_by_name(const std::string &name);
00428         item&                           alloc_item(const enum item_type_t type,const std::string &name);
00429         void                            delete_item(const item_handle_t i);
00430         void                            clear_all_menu_items(void);
00431         void                            dump_log_debug(void);
00432         void                            dump_log_displaylist(DOSBoxMenu::displaylist &ls, unsigned int indent);
00433         const char*                     TypeToString(const enum item_type_t type);
00434         void                            rebuild(void);
00435         void                            unbuild(void);
00436     public:
00437         displaylist                     display_list;
00438     protected:
00439         std::vector<item>               master_list;
00440         std::map<std::string,item_handle_t> name_map;
00441         item_handle_t                   master_list_alloc = 0;
00442 #if DOSBOXMENU_TYPE == DOSBOXMENU_HMENU /* Windows menu handle */
00443     protected:
00444         HMENU                           winMenu = NULL;
00445         bool                            winMenuInit(void);
00446         void                            winMenuDestroy(void);
00447         bool                            winMenuSubInit(DOSBoxMenu::item &item);
00448     public:
00449         HMENU                           getWinMenu(void) const;
00450         bool                            mainMenuWM_COMMAND(unsigned int id);
00451     public:
00452         static constexpr unsigned int   winMenuMinimumID = 0x1000;
00453 #endif
00454 #if DOSBOXMENU_TYPE == DOSBOXMENU_NSMENU /* Mac OS X NSMenu / NSMenuItem handle */
00455     protected:
00456         void*                           nsMenu = NULL;
00457         bool                            nsMenuInit(void);
00458         void                            nsMenuDestroy(void);
00459         bool                            nsMenuSubInit(DOSBoxMenu::item &item);
00460     public:
00461         void*                           getNsMenu(void) const;
00462         bool                            mainMenuAction(unsigned int id);
00463     public:
00464         static constexpr unsigned int   nsMenuMinimumID = 0x1000;
00465 #endif
00466 #if DOSBOXMENU_TYPE == DOSBOXMENU_SDLDRAW
00467     public:
00468         bool                            needRedraw = false;
00469         bool                            menuVisible = false;
00470         item_handle_t                   menuUserAttentionAt = unassigned_item_handle;
00471         item_handle_t                   menuUserHoverAt = unassigned_item_handle;
00472     public:
00473         SDL_Rect                        menuBox = {0,0,0,0};
00474     public:
00475         inline bool isVisible(void) const {
00476             return menuVisible;
00477         }
00478         inline bool needsRedraw(void) const {
00479             return needRedraw;
00480         }
00481         inline void setRedraw(void) {
00482             needRedraw = true;
00483         }
00484         inline void clearRedraw(void) {
00485             needRedraw = false;
00486         }
00487     public:
00488         void                            showMenu(bool show=true);
00489         void                            setScale(size_t s);
00490         void                            removeHover(void);
00491         void                            removeFocus(void);
00492         void                            updateRect(void);
00493         void                            layoutMenu(void);
00494     public:
00495         static constexpr size_t         menuBarHeightBase = (16 + 1);
00496         size_t                          menuBarHeight = menuBarHeightBase;
00497     public:
00498         size_t                          screenWidth = 640;
00499         size_t                          screenHeight = 400;
00500     public:
00501         static constexpr size_t         fontCharWidthBase = 8;
00502         static constexpr size_t         fontCharHeightBase = 16;
00503         static constexpr size_t         dropshadowX = 8;
00504         static constexpr size_t         dropshadowY = 8;
00505     public:
00506         size_t                          fontCharScale = 1;
00507         size_t                          fontCharWidth = fontCharWidthBase;
00508         size_t                          fontCharHeight = fontCharHeightBase;
00509 #endif
00510     public:
00511         void                            dispatchItemCommand(item &item);
00512     public:
00513         static constexpr size_t         master_list_limit = 4096;
00514     public:
00515         void                            displaylist_append(displaylist &ls,const DOSBoxMenu::item_handle_t item_id);
00516         void                            displaylist_clear(displaylist &ls);
00517 };
00518 
00519 extern DOSBoxMenu mainMenu;
00520 
00521 void DOSBox_SetMenu(DOSBoxMenu &altMenu);
00522 
00523 #endif /* MENU_DOSBOXMENU_H */
00524