123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577 |
- /* GCSx
- ** GUI.H
- **
- ** Base gui classes and code
- */
- /*****************************************************************************
- ** Copyright (C) 2003-2006 Janson
- **
- ** 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., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
- *****************************************************************************/
- #ifndef __GCSx_GUI_H_
- #define __GCSx_GUI_H_
- // Virtual base class for Window and Desktop
- class WindowParent {
- public:
- virtual int getScreenX() const = 0;
- virtual int getScreenY() const = 0;
- virtual void setChildDirty() = 0;
- virtual void childMoved(int fromX, int fromY, int toX, int toY, class Window* child) = 0;
- virtual void childResized(int fromW, int fromH, int toW, int toH, class Window* child) = 0;
- virtual void childDeleted(Window* child) = 0;
- virtual void childModified(Window* child) = 0; // Usage varies by child window type
- virtual void siblingModified(Window* sibling) = 0; // Usage varies by window type
- virtual ~WindowParent() = 0;
- };
- class Window : public virtual WindowParent {
- protected:
- int x, y, width, height;
- WindowParent* parent; // Could be a Window, or desktop, or NULL
- WindowParent* parentNotify; // We notify this window if we are deleted- nothing more!
- // (how much of us is viewable based on parent window telling us- -1 if unknown)
- int viewWidth, viewHeight;
-
- // Unique ID across all windows
- int id;
- static int nextId;
-
- // Are we visible, and therefore need to update/redraw?
- // This is true if width and height are >0 and parent is non-NULL
- // and viewWidth/Height are non-zero
- int visible;
-
- int dirty; // If we need to redraw ourselves
- int childDirty; // If a child of ours needs to redraw
- // If we need to redraw entirely from scratch (only set by ::resize normally)
- // If a window doesn't check this (ie, if it normally repaints totally anyways)
- // you don't need to zero it out. Many windows repaint totally, so this is
- // usually ignored, but you can create a window that tracks partial repaints
- // and this should then trigger a full repaint.
- int totalDirty;
- // Default GUI routines only call this with total=1; your routines, if they
- // set partial dirties, need to track the partialness in your own variables
- void setDirty(int total = 0);
- public:
- enum WindowType {
- // Window types- client windows are windows within a frame window
- // Widget windows are subwindows within a client window
- WINDOW_UNKNOWN,
- WINDOW_POPUPMENU,
- WINDOW_MENUBAR,
- WINDOW_FRAME,
- WINDOW_DIALOG,
- WINDOW_CLIENT,
- WINDOW_WIDGET,
- WINDOW_TOOLTIP,
- WINDOW_LASTTYPE = WINDOW_WIDGET,
- };
- enum WindowSort {
- // Window sort priorities
- WINDOWSORT_DESKTOP,
- WINDOWSORT_NORMAL,
- WINDOWSORT_ONTOP,
- WINDOWSORT_DOCKED,
- WINDOWSORT_MODAL,
- WINDOWSORT_POPUP,
- };
-
- // Whether to hide, disable, or enable a command in a popup menu
- enum CommandSupport {
- COMMAND_HIDE = 0,
- COMMAND_DISABLE = 1,
- COMMAND_ENABLE = 2,
- COMMAND_CHECKBOX = 4,
- COMMAND_RADIO = 8,
- COMMAND_SELECTED = 16,
- };
- Window();
- virtual ~Window();
- void setParent(WindowParent* wParent);
- void setParentNotify(WindowParent* wParentNotify);
- WindowParent* getParent() const { return parent; }
-
- void setChildDirty();
- // When a child resizes or moves, it calls one of these to tell us to
- // set appropriate dirtiness; the default versions of these do NOTHING
- virtual void childMoved(int fromX, int fromY, int toX, int toY, Window* child);
- virtual void childResized(int fromW, int fromH, int toW, int toH, Window* child);
- // Called when we are the parent or parentnotify of a child that is just about to be deleted
- virtual void childDeleted(Window* child);
- // Called by child windows when they "modify"- usage is up to the child windows
- // i.e. dialog widgets use this commonly; other windows may never use it
- // Default behavior propogates upward without modifying pointer (i.e. passes up
- // a grandchild pointer)
- virtual void childModified(Window* child);
- // Called by parent windows when a sibling was modified- usage is up to the
- // windows in question- mostly used by dialogs and frame wiondows
- // Default behavior is to do nothing
- virtual void siblingModified(Window* sibling);
- // Called when resolution changes; 0 for from if first resolution set
- virtual void resolutionChange(int fromW, int fromH, int fromBpp, int toW, int toH, int toBpp);
-
- #ifndef NDEBUG
- virtual const char* debugDump() const;
- #endif
- // x/y position includes any scrollbar-induced offset
- virtual void move(int xPos, int yPos);
- // (this function accepts zero/negative values as "hidden"- minimized- which
- // unsets visible member))
- // fromParent is true if parent is telling us to resize and we don't need to
- // propogate it back (normally we'll tell our parent if we resize and our parent
- // is a container such as a frame window)
- // 'view' size is the amount of us that we can see, may be larger or smaller
- // than our actual width or height; -1 means unchanged; this is
- // used by frame windows and other containers to tell us that, if we want,
- // we can optimize our displays, resizes, and storage to this amount of surface
- virtual void resize(int newWidth, int newHeight, int newViewWidth = -1, int newViewHeight = -1, int fromParent = 0);
- // Returns true if closing is ok; false if close should abort (save dialog, for example)
- // This doesn't actually close the window- use an SDL_CLOSE event for that
- virtual int attemptClose();
-
- // Return true if event was used
- // Note that keyboard events typically -only- go to the window with focus
- // Mouse events typically -only- go to the window with mousefocus, and coordinates are adjusted
- // This function is NOT allowed to modify the event
- // Only SDL_CLOSE events are allowed to delete windows, and only children
- // (parent always deletes a window)
- // If you wish to close otherwise, issue an appropriate SDL_CLOSE event
- // Focus events should be careful if they also trigger focus changes, to prevent infinite loops
- // This function must not open a modal dialog or new event loop due to any of these events-
- // SDL_QUIT, SDL_ACTIVEEVENT, SDL_VIDEORESIZE, SDL_VIDEOEXPOSE, SDL_IDLE
- // Any event that opens a modal dialog or event loop must be on an object that is thread-
- // safe for these events- (it will still receive these events while it's waiting on modal)
- // SDL_ACTIVEEVENT, SDL_VIDEORESIZE, SDL_VIDEOEXPOSE, SDL_IDLE
- virtual int event(int hasFocus, const SDL_Event* event) = 0;
-
- // Do we need to be redrawn, or one of our children?
- int isDirty() const;
-
- // Return true if this paints using an alpha blend, IE windows below must be repainted first
- /* Not currently used or supported
- virtual int usesAlpha() const;
- */
-
- // Return true if this window wants to be deleted by it's parent when closed
- // If false, code elsewhere handles it's deletion (for example, config dialogs
- // are static and global, and only deleted on exit)
- // This is used by Frame windows, Dialog windows, and the desktop, etc.
- // This defaults to TRUE
- virtual int wantsToBeDeleted() const;
-
- // Return true if this window is currently a docked part of the user interface
- // (such as a menu) This affects where other windows can move/resize to
- virtual int isDocked() const;
-
- // Return true if this window, when active, doesn't prevent the previous window
- // from appearing active; when inactive, returns to that previous window. (used
- // for popups and menus)
- virtual int tempFocus() const;
-
- // Return true if this window doesn't want any focus or events at all
- virtual int refuseAll() const;
-
- // Return whether this window supports the given SDL_COMMAND- used to disable
- // or hide menu options that aren't appropriate for the current menu
- virtual CommandSupport supportsCommand(int code) const;
-
- // Return type and sort of window
- // MUST return WINDOWSORT_MODAL if a modal window!
- // This can't be done via RTTI as there is not a one-to-one relationship to
- // classes (for example, menu class returns both memubar and popup types)
- virtual WindowType windowType() const;
- virtual WindowSort windowSort() const;
-
- // Display to surface (don't flip/update screen)
- // toDisplay is the rectangle that MUST be updated per parent/desktop request
- // and is gaurunteed to be within your x/w/size; clipArea is your clipping area
- // and may extend further than your size and will always contain toDisplay
- // Always set a clip rectangle on destSurface before drawing- either clipArea
- // or a subrectangle of clipArea
- // offset tells you what coordinate is your 0/0
- // toDisplay and clipArea are fully x/y based (not 0-based)
- // If no required update, toDisplay will have width of zero
- // display() must store the actual updated area back into toDisplay, which
- // should have been clipped by clipArea
- virtual void display(SDL_Surface* destSurface, Rect& toDisplay, const Rect& clipArea, int xOffset, int yOffset) = 0;
-
- // Return true if this window or it's parent is currently part of the desktop
- int isOnDesktop() const;
-
- // Closes this window or it's parent via an SDL_CLOSE event
- // Does NOT call attemptClose() if you set skipAttempt true
- void closeWindow(int skipAttempt = 0);
-
- // Returns pointer to tooltip to display; x/y relative to window
- // Return NULL for none
- virtual const char* tooltip(int xPos, int yPos) const;
-
- // Are coordinates within our boundaries?
- int isCoords(int xPos, int yPos) const;
- int getX() const;
- int getY() const;
- int getWidth() const;
- int getHeight() const;
- int getId() const;
- void getRect(Rect& rect) const;
-
- // Gets actual on-screen position
- int getScreenX() const;
- int getScreenY() const;
-
- // Receives undo/redo notifications, if appropriate
- virtual void undoNotify(int undoType, int undoItemId, int undoItemSubId, int uX, int uY, int uW, int uH);
- };
- // Used to hold and organize windows, for a desktop, or within another window
- // Doesn't contain any actual code to display the windows to screen
- class WindowCollection : public virtual WindowParent {
- protected:
- // (internal gui data regarding windows and focus)
- // List so that iterators work even if elements change
- std::list<Window*> windowDataDisplay; // Windows in display order
- std::list<Window*> windowDataFocus; // Windows in focus order
- Window* currentFocus;
- Window* previousFocus; // (last window with focus when a tempFocus window is active)
- Window* lastFocus; // (window with input focus when we lost our own focus, ie app change)
- Window* currentMouseFocus;
- int lastMouseX;
- int lastMouseY;
-
- // Allow clicking outside any windows?
- int allowDesktopClick;
-
- // (if a modal window is defined, no window below it can accept events or focus)
- Window* modalPos;
- // What we need to update next refresh
- Rect updateRect;
-
- // How large our "canvas" is for windows- after subtracting docked windows and
- // menus. This is only used by child classes that care, such as Desktop.
- int overallWidth;
- int overallHeight;
- int canvasX;
- int canvasY;
- int canvasWidth;
- int canvasHeight;
- int windowRunEvent(Window* target, const SDL_Event* event);
- const Window* findWindowByCoords(int x, int y) const;
- Window* findWindowByCoords(int x, int y);
- // (sendMoveEvent sends a custom-generated mouse movement event to
- // reconfirm mouse position if focus has changed)
- Window* recheckMouseFocus(int sendMoveEvent = 0);
- // (toTop should always be true except when called from bringToTop)
- // Returns true if a focus change was made
- int changeInputFocus(Window* window, int toTop = 1);
-
- // Scans all windows for docked windows and adjusts our canvas, if we're
- // using that feature
- void adjustCanvas();
-
- // Used to handle broadcast-type events, mostly SDL_COMMAND, SDL_IDLE
- int (*handleEvents)(const SDL_Event* event);
- // Add something to our refresh rect
- void addToUpdateRect(const Rect& add);
- public:
- WindowCollection();
- virtual ~WindowCollection();
- // Called when resolution changes; 0 for from if first resolution set
- void resolutionChange(int fromW, int fromH, int fromBpp, int toW, int toH, int toBpp);
- // Sets the function to catch SDL_COMMAND, SDL_IDLE, and other broadcast events
- // Not called on SDL_COMMAND if another window uses it
- void setEventHandler(int (*eventHandler)(const SDL_Event* event));
- // Add or remove Window from the collection (adds to top of z-order for the window's sort type)
- // Note that if addWindow fails, window will not be added, so it won't ever be closed and delete itself
- void addWindow(Window* item, int giveFocus = 1);
- // (this MUST BE CALLED to remove a window that's been deleted)
- void removeWindow(Window* item);
- // pos = 0 for first, 1 for second, etc.
- // Scans in focus order, returning lowest window first
- Window* findWindow(Window::WindowType type, int pos);
- // Verifies that a specific window is on desktop
- int verifyWindow(const Window* target) const;
- Window* verifyWindow(int targetId);
-
- // returns window with input focus
- Window* findFocusWindow();
- // returns window with previous input focus, or current if no previous
- Window* findPreviousFocusWindow();
- // Bring to top or bottom (item must already be part of collection)
- void bringToTop(Window* item, int giveFocus = 1);
- void sendToBottom(Window* item); // Loses focus unless only window
-
- // Handles an untouched event and propogates it to the proper
- // window or windows. Returns true if event was used. After this function,
- // any window pointers could poitn to closed windows.
- int handleEvent(const SDL_Event* event);
- };
- class Desktop : public WindowCollection {
- protected:
- // Quit state is global to all event loops- once a quit is requested, all
- // loops above and below will quit.
- int quit; // Any non-zero value is a quit, and can represent a "quit type"
- int preQuit;
- int cancelPreQuit;
- int eventLoopCount;
- int modalReturn;
- int eventCleanup; // Ignore mouse/keyboard events until queue is clean
-
- // If a child of ours needs redrawing
- int childDirty;
-
- // Location and time of last left mouse click, to check for double-click
- int dclickX;
- int dclickY;
- int dclickTicks;
-
- enum {
- // Double-click sensitivity, in time (ms) and distance (max pixels)
- DOUBLECLICK_TIME = 1000,
- DOUBLECLICK_DIST = 2,
-
- // Phase rotation schedule
- DELAY_PHASE_ROTATE = 60,
- // Tooltip delay
- DELAY_TOOLTIP_SHOW = 1000,
- // Short and long timeouts (long repeats)
- DELAY_IDLE_SHORT = 3000,
- DELAY_IDLE_LONG = 60000,
- };
-
- // Global phase for selection rectangles and glowing cursors
- int cursorPhase;
- int cursorAlpha;
- int selectionPhase;
- Uint32 selectionPhaseMs;
-
- // Idle timeout
- Uint32 idleTimeout;
- int didShortTimeout;
- int didLongTimeout;
-
- // Current tooltip, time until tooltip should show
- class ToolTip* tooltip;
- Uint32 tooltipMs;
-
- // Keypad-to-regular sym conversion
- static SDLKey keypadConvert[10];
-
- // Background
- SDL_Surface* backgroundImage;
- int bkSrcX;
- int bkSrcY;
- int bkSrcW;
- int bkSrcH;
- int bkDestX;
- int bkDestY;
- int backgroundColorIndex;
- int backgroundAlpha;
-
- // Game loop (optional)
- void (*gameLoopH)(int);
- // Global function for dynamic popups
- Window::CommandSupport (*supportsCommandH)(int code);
- public:
- int lastShortcutKey;
- Desktop();
- virtual ~Desktop();
-
- void setBackground(SDL_Surface* image, int colorIndex);
- void setBackgroundAlpha(int alpha); // openGL only, 0-256
- // (also enables desktop clicking)
- void setGameLoop(void (*gameLoop)(int));
- int currentSelectionPhase() const { return selectionPhase; }
- int currentCursorAlpha() const { return cursorAlpha; }
- void setChildDirty();
- void childMoved(int fromX, int fromY, int toX, int toY, Window* child);
- void childResized(int fromW, int fromH, int toW, int toH, Window* child);
- void childDeleted(Window* child);
- void childModified(Window* child);
- void siblingModified(Window* sibling);
- // Broadcast a custom event
- // For example, broadcastEvent(SDL_COMMAND, command_code);
- // Can pass a single exempt window which will NOT receive the event
- // runImmediate recurses it to event loop immediately, and returns result-
- // intended for use by desktop event handler only
- // Otherwise returns 0
- int broadcastEvent(int type, int code, void* data = NULL, Window* exempt = NULL, int runImmediate = 0);
- // SDL_OBJECTCHANGE events always go out *IMMEDIATELY* (interrupting current work)
- // @TODO: all uses of this should pass (and expect) the base (OR EDIT?) form of the object
- // for exampe, Scene and Layer, not SceneEdit or LayerEdit
- void broadcastObjChange(int code, void* object, int data1, int data2, Window* exempt = NULL);
- // Send a focus or close event to a specific window
- // Cancels sending anything if window is NULL
- // For example, focusEvent(SDL_MOUSEFOCUS, 1, window);
- // Only intended for focus/close events
- // This is the correct and ONLY way for a window to request a window,
- // including itself, to close (use SDL_CLOSE)
- // Note that SDL_CLOSE events always go to the very front of the queue, so
- // no other events will process first, for safety
- void focusEvent(int type, int code, Window* window);
- // Main draw/event loop; also used for modal dialogs
- // Returns value returned by a modal dialog, 0 if none was returned (closed by mistake?)
- // Main event loop always returns 0
- int eventLoop();
-
- // Updates screen (use during loops to modify onscreen without using threads)
- void updateScreen();
-
- // Ignore all keyboard/mouse events (ie user interaction) until event queue clears
- // Good if you lock things up for a short period, to prevent invalid clicks
- void initEventCleanup();
-
- // Closes and clears all windows off the desktop immediately
- void closeAllWindows();
- // Deletes all windows off the desktop, no user prompts, no events
- void deleteAllWindows();
-
- // Call during a modal dialog upon closing to tell inner event loop what value to return
- void setModalReturn(int returnValue);
-
- // Call during a SDL_PREQUIT event to cancel the quit
- void cancelQuit();
-
- // Call to find out if we're cancelling a quit; use this so that you
- // stop propogating a SDL_PREQUIT event once it's been cancelled
- int cancelQuitState();
-
- // Sets the function to check global support for a popup command
- // Presumably, if this function returns "supported", the global event handler will handle it
- void setSupportsHandler(Window::CommandSupport (*supportsHandler)(int code));
-
- // Call global support handler; pass prior response, this will combine them
- Window::CommandSupport supportsCommand(int code, Window::CommandSupport prior) const;
- // Desktop size relative to entire screen, MINUS docked windows
- int desktopX() const;
- int desktopY() const;
- int desktopWidth() const;
- int desktopHeight() const;
- int getScreenX() const;
- int getScreenY() const;
-
- // Called when resolution changes; 0 for from if first resolution set
- void resolutionChange(int fromW, int fromH, int fromBpp, int toW, int toH, int toBpp);
-
- // Cancels any possibility of a double click- use when initiating
- // "fake" clicks or other situations where double clicks are not desired
- void preventDoubleClick();
- };
- // Used for SDL_OBJECTCHANGE events
- struct ObjChange {
- const void* obj;
- int info1;
- int info2;
- };
- // Custom event types
- enum {
- // Lose or gain mouse focus- code 0 lose 1 gain, data1 window
- // code &2 if parent FRAME window still has focus, just on another child
- // (may later expand &2 functionality to dialogs)
- SDL_MOUSEFOCUS = SDL_USEREVENT,
- // Lose or gain input focus- code 0 lose 1 gain, data1 window
- // code &2 if parent FRAME window still has focus, just on another child
- // (may later expand &2 functionality to dialogs)
- SDL_INPUTFOCUS,
- // Command (from a menu or accelerator) code in 'code' member
- SDL_COMMAND,
- // Close window, data1 window
- // (not a request, but a demand- any pre-close should have already ran)
- SDL_CLOSE,
- // Pre-quit, idle, etc- sub event in 'code'
- SDL_SPECIAL,
- // Broadcast/system key
- SDL_SYSKEY,
- // Double-click left mouse button- otherwise same as SDL_MOUSEBUTTONDOWN
- SDL_MOUSEBUTTONDBL,
- // Called when various game objects update, to tell needed windows to update
- // code contains one OBJ_ and one or more OBJMOD_ constants OR'd together
- // data1 points to a ObjChange structure
- SDL_OBJECTCHANGE,
- // Sub events for SDL_SPECIAL- stored in 'code'
- // Pre-quit, can be cancelled (prompt for saving, etc.)
- SDL_PREQUIT = 1,
- // Close game
- SDL_CLOSEGAME = 2,
- // Desktop now 'active' or not 'active' window (if enabled during gameplay mode)
- SDL_DESKTOPACTIVE = 3,
- SDL_DESKTOPINACTIVE = 4,
- // Special types of quits
- SDL_SPECIALQUIT = 64, // Set at 64 so you can go & SDL_SPECIALQUIT
- SDL_QUITTOEDITOR = 65,
- SDL_QUITTOFRONT = 66,
- SDL_QUITTOGAME = 67,
- // Idle- set at 128 so you can go & SDL_IDLE to check for this or any
- // idle-derived event like IDLEPHASE
- SDL_IDLE = 128,
- // Idle with cursor glow and selection phase change
- SDL_IDLEPHASE = 129,
- // Idle with cursor glow
- SDL_IDLECURSOR = 130,
- // Idle short timeout (no activity for 3 sec, as defined in enum)
- SDL_IDLETIMEOUTSHORT = 131,
- // Idle long timeout (no activity every 60 sec, as defined in enum)
- SDL_IDLETIMEOUTLONG = 132,
- };
- // The main desktop
- extern Desktop* desktop;
- // Combines an SDLKey and either KMOD_CTRL, KMOD_SHIFT, KMOD_ALT, or a combo
- // to a single value
- #define combineKey(sym, mod) (((mod) << 16) | (sym))
- #endif
|