gcsx_dialog.h 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588
  1. /* GCSx
  2. ** DIALOG.H
  3. **
  4. ** Dialog boxes, and basic dialog elements
  5. */
  6. /*****************************************************************************
  7. ** Copyright (C) 2003-2006 Janson
  8. **
  9. ** This program is free software; you can redistribute it and/or modify
  10. ** it under the terms of the GNU General Public License as published by
  11. ** the Free Software Foundation; either version 2 of the License, or
  12. ** (at your option) any later version.
  13. **
  14. ** This program is distributed in the hope that it will be useful,
  15. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. ** GNU General Public License for more details.
  18. **
  19. ** You should have received a copy of the GNU General Public License
  20. ** along with this program; if not, write to the Free Software
  21. ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
  22. *****************************************************************************/
  23. #ifndef __GCSx_DIALOG_H_
  24. #define __GCSx_DIALOG_H_
  25. // A dialog Window collects widget Windows and is itself the client area
  26. // of a FrameWindow.
  27. class Widget;
  28. class Dialog : public WindowCollection, public Window {
  29. protected:
  30. std::string title;
  31. int lastButtonId;
  32. int open;
  33. int openModal;
  34. int nextTabId;
  35. class FrameWindow* myFrame;
  36. int autoApply; // If widgets apply on every setting change
  37. int noAutoClose; // Prevent ESC key and Enter key
  38. int inSiblingModify; // Are we in the middle of siblingModified()?
  39. int hasTitlebar;
  40. int isToolPanel;
  41. // For arrangeRow() and makePretty()
  42. int lastWidgetArranged;
  43. int nextWidgetY;
  44. // Apply/save settings
  45. // Don't call this directly- use doAction()
  46. void applySettings();
  47. // Load settings
  48. // Called from runModal and runWindowed
  49. void loadSettings();
  50. // Dialog sizing constants
  51. enum {
  52. // Separation between elements
  53. GUI_DIALOG_SEPHEIGHT = 5,
  54. GUI_DIALOG_SEPWIDTH = 2, // Used by arrangeRow() only
  55. // Separation before button row
  56. GUI_DIALOG_BUTTONSEPHEIGHT = 10,
  57. // Separation between multiple checks or radios
  58. GUI_DIALOG_CHECKSEPHEIGHT = 0, // Used by makePretty() only
  59. // Separation between two columns
  60. GUI_DIALOG_GUTTERWIDTH = 5, // Used by makePretty() only
  61. // Margins on edges- normal dialog
  62. GUI_DIALOG_TOPMARGIN = 5,
  63. GUI_DIALOG_BOTTOMMARGIN = 5,
  64. GUI_DIALOG_LEFTMARGIN = 5,
  65. GUI_DIALOG_RIGHTMARGIN = 5,
  66. // Margins on edges- tool panel dialog
  67. GUI_PANEL_TOPMARGIN = 2,
  68. GUI_PANEL_BOTTOMMARGIN = 2,
  69. GUI_PANEL_LEFTMARGIN = 3,
  70. GUI_PANEL_RIGHTMARGIN = 1,
  71. // Max number of columns/rows we support
  72. GUI_DIALOG_NUMCOL = 10, // Used by makePretty() only
  73. GUI_DIALOG_NUMROW = 20, // Used by makePretty() only
  74. };
  75. // Opens this dialog, but without assigning it as a child window anywhere
  76. void runAsPanel();
  77. public:
  78. enum ButtonAction {
  79. // "DEFAULT" means "whatever the button is set to do" and should only be used
  80. // as a return value for verifyEntry(), not as an actual button action
  81. BUTTON_DEFAULT,
  82. BUTTON_NOTHING,
  83. BUTTON_OK,
  84. BUTTON_APPLY,
  85. BUTTON_CANCEL,
  86. BUTTON_LASTACT = BUTTON_CANCEL,
  87. };
  88. enum DialogAction {
  89. DIALOGACTION_CHECK,
  90. DIALOGACTION_UNCHECK,
  91. DIALOGACTION_RADIO,
  92. DIALOGACTION_TEXTCHANGE,
  93. };
  94. Dialog(const std::string& dTitle, int dAutoApply = 0, int dHasTitlebar = 1, int toolPanel = 0);
  95. virtual ~Dialog();
  96. void setTitle(const std::string& newTitle);
  97. #ifndef NDEBUG
  98. const char* debugDump() const;
  99. #endif
  100. virtual int event(int hasFocus, const SDL_Event* event);
  101. void display(SDL_Surface* destSurface, Rect& toDisplay, const Rect& clipArea, int xOffset, int yOffset);
  102. void resolutionChange(int fromW, int fromH, int fromBpp, int toW, int toH, int toBpp);
  103. const char* tooltip(int xPos, int yPos) const;
  104. WindowType windowType() const;
  105. WindowSort windowSort() const;
  106. CommandSupport supportsCommand(int code) const;
  107. // For outside code to find widgets to edit properties, etc.
  108. // If it finds a container widget, it returns the inner widget
  109. // which = 1 for second widget, etc. May not be in original order added!
  110. Widget* findWidget(int id, int which = 0);
  111. // By default, dialogs do NOT want to be deleted, most are settings dialogs
  112. // you set up once and bring back over and over
  113. virtual int wantsToBeDeleted() const;
  114. // Handles calling verifyEntry(0), etc.
  115. // You shouldn't call this directly, it's used by frame windows only
  116. int attemptClose();
  117. // Validates that all current entry is OK and/or runs custom code for a
  118. // button, return an action. buttonId of 0 for closing
  119. // the dialog via [X]. The default code for this merely runs entryValid() on
  120. // all widgets if buttonType is OK or APPLY.
  121. virtual ButtonAction verifyEntry(int buttonId, ButtonAction buttonType);
  122. // Remove all widgets; allows you to readd widgets
  123. // Must be closed when called!
  124. void clearWidgets();
  125. // Add a widget to this dialog; if fails, widget is not owned by us
  126. // If successful, we will handle deleting widget unless it's not set as wantsToBeDeleted()
  127. // Typically called by widget from addTo()
  128. void addWidget(Widget* newWidget);
  129. // Rearrange size of dialog and all new widgets automatically
  130. // Call this after each chunk or when all done
  131. // If you wish to arrange as a table, increase maxColumns
  132. // Puts static text in column 1 right-aligned, all other widgets in columns 2 onwards
  133. // If you simply want all widgets to flow into all columns, set pureFlow to true
  134. // If you want all static text right-aligned, set staticRight to true
  135. // (this only matters for pureFlow mode)
  136. // ALWAYS centers a final row of buttons, in all circumstances
  137. void makePretty(int maxColumns = 2, int vertCenter = 1, int pureFlow = 0, int staticRight = 0);
  138. // All widgets added since last call to this are arranged in a single row
  139. // Call this after each row
  140. void arrangeRow(int vertCenter = 1, int leftColumnSize = -1, int staticRight = 0);
  141. // Creates a FrameWindow, run this dialog, return the button code pressed
  142. // Returns 0 if ESC/[X] and no CANCEL button
  143. int runModal(int xPos = -1, int yPos = -1);
  144. // Creates a FrameWindow, add dialog to desktop, return with dialog still open
  145. void runWindowed(int xPos = -1, int yPos = -1);
  146. // Actually handles an action- call with a constant other than DEFAULT
  147. // Returns true if this window was closed, possibly deleted
  148. int doAction(ButtonAction buttonType);
  149. // First control- used on dialog init
  150. virtual void firstControl();
  151. // Next and previous control, optionally limited to controls with a given ID
  152. // Can do next from a control other than current if desired
  153. // Returns true if control was switched.
  154. int nextControl(int id = -1, const Widget* from = NULL);
  155. int prevControl(int id = -1);
  156. // Select first button with given action; returns true if found
  157. int buttonControl(ButtonAction action);
  158. void currentFocusDoAction();
  159. // Select control based on hotkey AND ACTIVATE; returns true if found
  160. int hotkeyControl(char keypress);
  161. // Called whenever a child is modified, propogates to all other controls
  162. // (via siblingModified())
  163. // If this causes another widget to modify, it will NOT propogate
  164. // A button press doesn't call this
  165. // focus or other purely-visual or cursor changes don't call this
  166. // load() shouldn't call this
  167. virtual void childModified(Window* modified);
  168. };
  169. class Widget : public Window {
  170. protected:
  171. std::string label;
  172. int underline;
  173. int disabled;
  174. int haveFocus;
  175. int tabId;
  176. char shortcut;
  177. const char* tip;
  178. // Internal ID, internal use includes grouping radio buttons and pass to
  179. // verifyEntry and afterChange in Dialog class. Internal ID should be >= 0
  180. int id;
  181. // (where we store the setting when the dialog closes)
  182. void* setting;
  183. // sets label, underline
  184. void setLabel(const std::string& newLabel);
  185. public:
  186. Widget(int wId, const std::string& wLabel, void* wSetting);
  187. virtual ~Widget();
  188. // (mostly a shortcut)
  189. Dialog* myParent();
  190. void setToolTip(const char* wTip);
  191. virtual const char* tooltip(int xPos, int yPos) const;
  192. // Return true if entry is valid to close
  193. // False if entry is invalid and should be selected and modified (can pop up an error)
  194. virtual int entryValid() const;
  195. // Used by findWidget to make sure it's returning the actual widget
  196. // and not a container widget like WidgetScroll
  197. virtual Widget* returnSelf();
  198. // Changes setting storage (doesn't affect current value if open!)
  199. void changeStorage(void* newSetting);
  200. // Add to a dialog; if fails, widget is not owned by dialog
  201. // If successful, dialog will handle deleting widget unless it's not set as wantsToBeDeleted()
  202. virtual void addTo(Dialog* dialog);
  203. // Set or query tab id
  204. virtual int stateTabId() const;
  205. virtual int stateTabId(int wTabId);
  206. // Selected- perform action
  207. virtual void doAction();
  208. // Tabbed to- perform action
  209. virtual void tabAction();
  210. #ifndef NDEBUG
  211. const char* debugDump() const;
  212. #endif
  213. virtual void disable();
  214. virtual void enable();
  215. // Widgets DO want to be deleted if the dialog is
  216. int wantsToBeDeleted() const;
  217. // If disabled, refuse all
  218. virtual int refuseAll() const;
  219. // Loads setting into our "current" storage
  220. // Also preps anything else necessary before displaying a dialog, such as
  221. // setting graphical states back to normal
  222. virtual void load() = 0;
  223. // Stores our current storage into setting
  224. virtual void apply() = 0;
  225. // Called whenever another widget is modified
  226. // Call AFTER the modification is complete!
  227. // If this causes us to modify, that won't be propogated
  228. // Default action is to do nothing
  229. // A button press doesn't call this
  230. virtual void siblingModified(Widget* modified);
  231. WindowType windowType() const;
  232. virtual int getId() const;
  233. virtual char getShortcut() const;
  234. };
  235. class WButton : public Widget {
  236. protected:
  237. Dialog::ButtonAction action;
  238. int command;
  239. int pressed;
  240. int spacePressed;
  241. int hover;
  242. // Where the icon comes from, if there is one
  243. int isIcon;
  244. SDL_Surface* icon;
  245. int iconX;
  246. int iconY;
  247. int iconW;
  248. int iconH;
  249. enum {
  250. // Margins on edges (includes bevel)
  251. GUI_BUTTON_TOPMARGIN = 6,
  252. GUI_BUTTON_BOTTOMMARGIN = 6,
  253. GUI_BUTTON_LEFTMARGIN = 12,
  254. GUI_BUTTON_RIGHTMARGIN = 12,
  255. // Margin from edge to focus box
  256. GUI_BUTTON_VFOCUSMARGIN = 4,
  257. GUI_BUTTON_HFOCUSMARGIN = 5,
  258. // Margins on edges (includes bevel)
  259. GUI_ICON_MARGIN = 6,
  260. // Margin to focus rectangle
  261. GUI_ICON_FOCUSMARGIN = 4,
  262. };
  263. // Constructor for radio/checkbox
  264. WButton(int bId, const std::string& bLabel, void* bSetting);
  265. WButton(int bId, SDL_Surface* iIconSurface, int iX, int iY, int iW, int iH, void* bSetting);
  266. // Icon display
  267. void constructIcon(SDL_Surface* iIconSurface, int iX, int iY, int iW, int iH);
  268. void iconDisplay(SDL_Surface* destSurface, int atX, int atY, int pressed);
  269. public:
  270. // Buttons do not have a place to store the setting, but instead
  271. // return a value or perform some other operation; action is a
  272. // BUTTON constant from Dialog::ButtonAction; command is sent as
  273. // a message; Buttons with an icon don't currently display a label.
  274. WButton(int bId, const std::string& bLabel, Dialog::ButtonAction bAction = Dialog::BUTTON_NOTHING, int bCommand = NO_COMMAND);
  275. WButton(int bId, SDL_Surface* iIconSurface, int iX, int iY, int iW, int iH, Dialog::ButtonAction bAction = Dialog::BUTTON_NOTHING, int bCommand = NO_COMMAND);
  276. void changeIcon(int iX, int iY);
  277. // (this won't rearrange any elements)
  278. virtual void changeText(const std::string& newLabel);
  279. int event(int hasFocus, const SDL_Event* event);
  280. virtual void load();
  281. virtual void apply();
  282. virtual void display(SDL_Surface* destSurface, Rect& toDisplay, const Rect& clipArea, int xOffset, int yOffset);
  283. // All button presses go through this function
  284. virtual void doAction();
  285. Dialog::ButtonAction getAction() const;
  286. };
  287. class WCheckBox : public WButton {
  288. protected:
  289. // A checkbox is a bit set to on or off in a single location
  290. // Only the noted bit should be affected.
  291. int value;
  292. int currentStatus;
  293. int isRadio;
  294. // Other controls enabled or disabled based on button status
  295. // (control id -> enable or disable)
  296. std::map<int, int> affectControls;
  297. enum {
  298. GUI_CHECKBOX_TOPMARGIN = 1,
  299. GUI_CHECKBOX_BOTTOMMARGIN = 3,
  300. GUI_CHECKBOX_LEFTMARGIN = 1,
  301. GUI_CHECKBOX_RIGHTMARGIN = 4,
  302. // margin before/after checkbox
  303. GUI_CHECKBOX_PRECHECK = 3,
  304. GUI_CHECKBOX_POSTCHECK = 7,
  305. };
  306. static int checkboxSize;
  307. static int checkboxX;
  308. static int checkboxY;
  309. static int checkboxXText;
  310. public:
  311. WCheckBox(int cId, const std::string& cLabel, int* cSetting, int cValue);
  312. WCheckBox(int cId, SDL_Surface* iIconSurface, int iX, int iY, int iW, int iH, int* cSetting, int cValue);
  313. // enable = enable control if checked; otherwise disable if checked
  314. // doesn't take effect until modified or dialog loaded
  315. void affectControl(int cId, int enable);
  316. void changeText(const std::string& newLabel);
  317. virtual void load();
  318. virtual void apply();
  319. void display(SDL_Surface* destSurface, Rect& toDisplay, const Rect& clipArea, int xOffset, int yOffset);
  320. // We can query or set the value of the checkbox with this
  321. // (returns true/false not gaurunteed to be 1/0)
  322. // ALL places checkbox is checked or modified go through this function
  323. virtual int state(int checked = -1, int fromLoad = 0);
  324. virtual void doAction();
  325. int getValue() const { return value; }
  326. };
  327. // Similar to a checkbox, but only one value can be set at once;
  328. // the location is set to exactly the value- no bit operations are done
  329. // Values must be zero or positive! A value that doesn't match any, will have
  330. // NO button selected when the dialog opens, and will not change it if none of
  331. // them end up selected.
  332. // Setting one radio button unsets all other radio buttons with the same id.
  333. class WRadioButton : public WCheckBox {
  334. public:
  335. WRadioButton(int rId, const std::string& rLabel, int* rSetting, int rValue);
  336. WRadioButton(int rId, SDL_Surface* iIconSurface, int iX, int iY, int iW, int iH, int* rSetting, int rValue);
  337. void load();
  338. void apply();
  339. // We can query or set the value of the radio button with this
  340. // If we set it, it will unset any other set buttons with the same id.
  341. // ALL places radio is checked or modified go through this function
  342. virtual int state(int value = -1, int fromLoad = 0);
  343. void doAction();
  344. };
  345. class WTextBox : public Widget {
  346. protected:
  347. enum UndoType {
  348. UNDO_NONE = 0,
  349. UNDO_TYPING,
  350. UNDO_DELETE,
  351. UNDO_OTHER,
  352. };
  353. int maxSize;
  354. std::string currentValue;
  355. std::string undoValue;
  356. int undoPoint;
  357. UndoType undoType;
  358. // Insertion point data- points to the character it is before
  359. int insertPoint;
  360. int insertPointX;
  361. // Selection begin OR end will ALWAYS match insertpoint UNLESS
  362. // there is no selection, in which case both are set to ZERO
  363. int selectionBegin;
  364. int selectionEnd;
  365. // Not gaurunteed to be valid if no selection
  366. int selectionBeginX;
  367. int selectionEndX;
  368. // How far left we have scrolled the text; 0 if text fully fits into textbox
  369. // Never a positive value
  370. int scrollPointX;
  371. // The x/y offset to start display text at normally, accounting for all
  372. // margins and padding
  373. int textX;
  374. int textY;
  375. // Insertion point
  376. int insertY;
  377. int insertHeight;
  378. int insertBlink;
  379. Uint32 insertBlinkMs;
  380. // Characters that make up "words"
  381. static const std::string wordChars;
  382. enum {
  383. GUI_TEXTBOX_INSERTPOINTWIDTH = 2,
  384. GUI_TEXTBOX_BORDERTHICKNESS = 2,
  385. // This is the max (visible) size for a textbox by default
  386. GUI_TEXTBOX_MAXSIZE = 20,
  387. // Margin is blank space inside textbox border
  388. GUI_TEXTBOX_INNERMARGIN = 0,
  389. // Padding is added to edges of text within textbox, but only shows when
  390. // fully scrolled to that end of the text
  391. GUI_TEXTBOX_LEFTPAD = 3,
  392. GUI_TEXTBOX_RIGHTPAD = 3,
  393. // Preferred number of pixels to show in excess on each side when scrolling
  394. GUI_TEXTBOX_SCROLLAHEAD = 10,
  395. // MS to wait between blinks
  396. DELAY_CURSOR_BLINK = 500,
  397. };
  398. // Sets dirty and resets cursor blink
  399. void setDirtyAndBlink();
  400. // Saves an undo point
  401. void saveUndo(UndoType type);
  402. public:
  403. // Text boxes do not have prompts
  404. // Zero max size = no limit
  405. WTextBox(int tId, std::string* tSetting, int tMaxSize, int tDisplayLength = -1);
  406. virtual ~WTextBox();
  407. virtual int event(int hasFocus, const SDL_Event* event);
  408. virtual void load();
  409. virtual void apply();
  410. void display(SDL_Surface* destSurface, Rect& toDisplay, const Rect& clipArea, int xOffset, int yOffset);
  411. void tabAction();
  412. CommandSupport supportsCommand(int code) const;
  413. // We can query or set the current text with this; setting text
  414. // resets selection, insertion, and scroll points; setting text may
  415. // return different text if the text set was not valid
  416. const std::string& state() const;
  417. const std::string& state(const std::string& newValue);
  418. // Returns the insertion position, given a pixel X offset; X offset
  419. // does not need to be within the actual display boundaries (IE you can drag
  420. // past the edges)
  421. int insertWhere(int x) const;
  422. // Handle special keystrokes
  423. void keyBackspace();
  424. void keyDelete();
  425. // Query or set the insertion point, which also clears selection and
  426. // scrolls if needed to view; if drag is true, this drags the current
  427. // insertion point to the given position, modifying the selection as well
  428. int insertionState(int newPos = -1, int drag = 0);
  429. // Selects entire text, scrolls to end
  430. void selectAll();
  431. // Undo
  432. void undo();
  433. // Inserts text at the insertion point, overwriting any selection
  434. // No text = clear selection
  435. // Resets selection and adjusts insertion and scroll points
  436. void pasteText(const std::string& text);
  437. // Copies current selection to buffer
  438. // Copies "" if no selection
  439. void copyText(std::string& buffer) const;
  440. // Validates a change to textbox before it occurs, returns true if change
  441. // is OK; making changes to new text or cursor position is OK; this is only
  442. // called if text changes, not just if cursor position does; you can assume
  443. // new cursor position is right after the added text or where the deleted
  444. // text was. Default version allows all changes. Isn't called just on cursor
  445. // move or load().
  446. virtual int allowChange(const std::string& oldValue, std::string* newValue,
  447. int oldCursorPos, int* newCursorPos) const;
  448. };
  449. class WNumberBox : public WTextBox {
  450. protected:
  451. int min;
  452. int max;
  453. public:
  454. WNumberBox(int tId, int* tSetting, int tMin, int tMax);
  455. ~WNumberBox();
  456. int allowChange(const std::string& oldValue, std::string* newValue,
  457. int oldCursorPos, int* newCursorPos) const;
  458. int event(int hasFocus, const SDL_Event* event);
  459. void load();
  460. void apply();
  461. int entryValid() const;
  462. int state() const;
  463. int state(int newValue);
  464. };
  465. class WStatic : public Widget {
  466. public:
  467. enum {
  468. REFUSE_STATIC = 2,
  469. };
  470. // Static text does not have a place to store any setting
  471. WStatic(int sId, const std::string& sLabel);
  472. void changeText(const std::string& newLabel);
  473. // Refuse all!
  474. // If not disabled, returns WStatic::REFUSE_STATIC to clarify
  475. int refuseAll() const;
  476. int event(int hasFocus, const SDL_Event* event);
  477. void load();
  478. void apply();
  479. void display(SDL_Surface* destSurface, Rect& toDisplay, const Rect& clipArea, int xOffset, int yOffset);
  480. };
  481. #endif