1 /*
2  *  The ManaPlus Client
3  *  Copyright (C) 2004-2009  The Mana World Development Team
4  *  Copyright (C) 2009-2010  The Mana Developers
5  *  Copyright (C) 2011-2019  The ManaPlus Developers
6  *  Copyright (C) 2019-2021  Andrei Karas
7  *
8  *  This file is part of The ManaPlus Client.
9  *
10  *  This program is free software; you can redistribute it and/or modify
11  *  it under the terms of the GNU General Public License as published by
12  *  the Free Software Foundation; either version 2 of the License, or
13  *  any later version.
14  *
15  *  This program is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *  GNU General Public License for more details.
19  *
20  *  You should have received a copy of the GNU General Public License
21  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
22  */
23 
24 /*      _______   __   __   __   ______   __   __   _______   __   __
25  *     / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___  /\ /  |\/ /\
26  *    / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / /
27  *   / / /__   / / // / // / // / /    / ___  / // ___  / // /| ' / /
28  *  / /_// /\ / /_// / // / // /_/_   / / // / // /\_/ / // / |  / /
29  * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ /
30  * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/
31  *
32  * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson
33  *
34  *
35  * Per Larsson a.k.a finalman
36  * Olof Naessén a.k.a jansem/yakslem
37  *
38  * Visit: http://guichan.sourceforge.net
39  *
40  * License: (BSD)
41  * Redistribution and use in source and binary forms, with or without
42  * modification, are permitted provided that the following conditions
43  * are met:
44  * 1. Redistributions of source code must retain the above copyright
45  *    notice, this list of conditions and the following disclaimer.
46  * 2. Redistributions in binary form must reproduce the above copyright
47  *    notice, this list of conditions and the following disclaimer in
48  *    the documentation and/or other materials provided with the
49  *    distribution.
50  * 3. Neither the name of Guichan nor the names of its contributors may
51  *    be used to endorse or promote products derived from this software
52  *    without specific prior written permission.
53  *
54  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
55  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
56  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
57  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
58  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
59  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
60  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
61  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
62  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
63  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
64  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
65  */
66 
67 #ifndef GUI_GUI_H
68 #define GUI_GUI_H
69 
70 #include "gui/color.h"
71 
72 #include "enums/events/mousebutton.h"
73 #include "enums/events/mouseeventtype.h"
74 
75 #include "enums/resources/cursor.h"
76 
77 #include <deque>
78 #include <list>
79 
80 #include "localconsts.h"
81 
82 class Event;
83 class FocusHandler;
84 class FocusListener;
85 class Graphics;
86 class GuiConfigListener;
87 class ImageSet;
88 class KeyEvent;
89 class KeyListener;
90 class MouseEvent;
91 class MouseInput;
92 class Font;
93 class SDLInput;
94 class Widget;
95 class Window;
96 
97 #ifdef USE_SDL2
98 #define MouseStateType uint32_t
99 #else  // USE_SDL2
100 #define MouseStateType uint8_t
101 #endif  // USE_SDL2
102 
103 /**
104  * \defgroup GUI Core GUI related classes (widgets)
105  */
106 
107 /**
108  * \defgroup Interface User interface related classes (windows, dialogs)
109  */
110 
111 /**
112  * Main GUI class.
113  *
114  * \ingroup GUI
115  */
116 class Gui final
117 {
118     public:
119         /**
120          * Constructor.
121          */
122         Gui();
123 
124         A_DELETE_COPY(Gui)
125 
126         /**
127          * Destructor.
128          */
129         ~Gui();
130 
131         void postInit(Graphics *const graphics) A_NONNULL(2);
132 
133         /**
134          * Performs logic of the GUI. Overridden to track mouse pointer
135          * activity.
136          */
137         void logic();
138 
139         void slowLogic();
140 
141         void clearFonts();
142 
143         /**
144          * Draws the whole Gui by calling draw functions down in the
145          * Gui hierarchy. It also draws the mouse pointer.
146          */
147         void draw();
148 
149         /**
150          * Called when the application window has been resized.
151          */
152         void videoResized() const;
153 
getFocusHandler()154         FocusHandler *getFocusHandler() const noexcept2 A_WARN_UNUSED
155         { return mFocusHandler; }
156 
157         /**
158          * Return game font.
159          */
getFont()160         Font *getFont() const RETURNS_NONNULL A_WARN_UNUSED
161         { return mGuiFont; }
162 
163         /**
164          * Return help font.
165          */
getHelpFont()166         Font *getHelpFont() const RETURNS_NONNULL A_WARN_UNUSED
167         { return mHelpFont; }
168 
169         /**
170          * Return secure font.
171          */
getSecureFont()172         Font *getSecureFont() const RETURNS_NONNULL A_WARN_UNUSED
173         { return mSecureFont; }
174 
175         /**
176          * Return npc font.
177          */
getNpcFont()178         Font *getNpcFont() const RETURNS_NONNULL A_WARN_UNUSED
179         { return mNpcFont; }
180 
181         /**
182          * Return the Font used for "Info Particles", i.e. ones showing, what
183          * you picked up, etc.
184          */
getInfoParticleFont()185         Font *getInfoParticleFont() const RETURNS_NONNULL A_WARN_UNUSED
186         { return mInfoParticleFont; }
187 
188         /**
189          * Sets whether a custom cursor should be rendered.
190          */
191         void setUseCustomCursor(const bool customCursor);
192 
193         /**
194          * Sets which cursor should be used.
195          */
setCursorType(const CursorT index)196         void setCursorType(const CursorT index)
197         { mCursorType = index; }
198 
setDoubleClick(const bool b)199         void setDoubleClick(const bool b)
200         { mDoubleClick = b; }
201 
202         void updateFonts();
203 
204         bool handleInput();
205 
206         bool handleKeyInput();
207 
208         void resetClickCount();
209 
210         MouseEvent *createMouseEvent(Window *const widget) A_WARN_UNUSED;
211 
212         static void getAbsolutePosition(Widget *restrict widget,
213                                         int &restrict x,
214                                         int &restrict y);
215 
216         void addGlobalFocusListener(FocusListener* focusListener);
217 
218         void removeGlobalFocusListener(FocusListener* focusListener);
219 
220         void distributeGlobalFocusGainedEvent(const Event &focusEvent);
221 
222         void removeDragged(const Widget *const widget);
223 
getLastMouseX()224         int getLastMouseX() const
225         { return mLastMouseX; }
226 
getLastMouseY()227         int getLastMouseY() const
228         { return mLastMouseY; }
229 
230         static MouseStateType getMouseState(int &x, int &y);
231 
232         /**
233          * Sets the top widget. The top widget is the root widget
234          * of the GUI. If you want a GUI to be able to contain more
235          * than one widget the top widget should be a container.
236          *
237          * @param top The top widget.
238          * @see Container
239          */
240         void setTop(Widget *const top);
241 
242         /**
243          * Gets the top widget. The top widget is the root widget
244          * of the GUI.
245          *
246          * @return The top widget. NULL if no top widget has been set.
247          */
getTop()248         Widget* getTop() const noexcept2 A_WARN_UNUSED
249         { return mTop; }
250 
251         /**
252          * Sets the graphics object to use for drawing.
253          *
254          * @param graphics The graphics object to use for drawing.
255          * @see getGraphics, AllegroGraphics, HGEGraphics,
256          *      OpenLayerGraphics, OpenGLGraphics, SDLGraphics
257          */
258         void setGraphics(Graphics *const graphics) A_NONNULL(2);
259 
260         /**
261          * Gets the graphics object used for drawing.
262          *
263          *  @return The graphics object used for drawing. NULL if no
264          *          graphics object has been set.
265          * @see setGraphics, AllegroGraphics, HGEGraphics,
266          *      OpenLayerGraphics, OpenGLGraphics, SDLGraphics
267          */
268         Graphics* getGraphics() const RETURNS_NONNULL A_WARN_UNUSED;
269 
270         /**
271          * Sets the input object to use for input handling.
272          *
273          * @param input The input object to use for input handling.
274          * @see getInput, AllegroInput, HGEInput, OpenLayerInput,
275          *      SDLInput
276          */
277         void setInput(SDLInput *const input) A_NONNULL(2);
278 
279         /**
280          * Gets the input object being used for input handling.
281          *
282          *  @return The input object used for handling input. NULL if no
283          *          input object has been set.
284          * @see setInput, AllegroInput, HGEInput, OpenLayerInput,
285          *      SDLInput
286          */
287         SDLInput* getInput() const A_WARN_UNUSED;
288 
289         /**
290          * Adds a global key listener to the Gui. A global key listener
291          * will receive all key events generated from the GUI and global
292          * key listeners will receive the events before key listeners
293          * of widgets.
294          *
295          * @param keyListener The key listener to add.
296          * @see removeGlobalKeyListener
297          */
298         void addGlobalKeyListener(KeyListener *const keyListener);
299 
300         /**
301          * Removes global key listener from the Gui.
302          *
303          * @param keyListener The key listener to remove.
304          * @throws Exception if the key listener hasn't been added.
305          * @see addGlobalKeyListener
306          */
307         void removeGlobalKeyListener(KeyListener *const keyListener);
308 
isLongPress()309         bool isLongPress() const
310         { return getMousePressLength() > 250; }
311 
312         int getMousePressLength() const;
313 
314     protected:
315         void handleMouseMoved(const MouseInput &mouseInput);
316 
317         void handleMouseReleased(const MouseInput &mouseInput);
318 
319         void handleMousePressed(const MouseInput &mouseInput);
320 
321         void handleMouseInput();
322 
323         void distributeMouseEvent(Widget *const source,
324                                   const MouseEventTypeT type,
325                                   const MouseButtonT button,
326                                   const int x, const int y,
327                                   const bool force,
328                                   const bool toSourceOnly);
329 
330         /**
331          *
332          * Handles mouse wheel moved down input.
333          *
334          * @param mouseInput The mouse input to handle.
335          */
336         void handleMouseWheelMovedDown(const MouseInput& mouseInput);
337 
338         /**
339          * Handles mouse wheel moved up input.
340          *
341          * @param mouseInput The mouse input to handle.
342          */
343         void handleMouseWheelMovedUp(const MouseInput& mouseInput);
344 
345         /**
346          * Gets the widget at a certain position.
347          *
348          * @return The widget at a certain position.
349          */
350         Widget* getWidgetAt(const int x, const int y) const A_WARN_UNUSED;
351 
352         /**
353          * Gets the source of the mouse event.
354          *
355          * @return The source widget of the mouse event.
356          */
357         Widget* getMouseEventSource(const int x,
358                                     const int y) const A_WARN_UNUSED;
359 
360         /**
361          * Gets the source of the key event.
362          *
363          * @return The source widget of the key event.
364          */
365         Widget* getKeyEventSource() const A_WARN_UNUSED;
366 
367         /**
368          * Distributes a key event.
369          *
370          * @param event The key event to distribute.
371 
372          */
373         void distributeKeyEvent(KeyEvent &event) const;
374 
375         /**
376          * Distributes a key event to the global key listeners.
377          *
378          * @param event The key event to distribute.
379          *
380          */
381         void distributeKeyEventToGlobalKeyListeners(KeyEvent& event);
382 
383         /**
384          * Handles modal mouse input focus. Modal mouse input focus needs
385          * to be checked at each logic iteration as it might be necessary to
386          * distribute mouse entered or mouse exited events.
387          *
388          */
389         void handleModalMouseInputFocus();
390 
391         /**
392          * Handles modal focus. Modal focus needs to be checked at
393          * each logic iteration as it might be necessary to distribute
394          * mouse entered or mouse exited events.
395          *
396          */
397         void handleModalFocus();
398 
399         /**
400          * Handles modal focus gained. If modal focus has been gained it might
401          * be necessary to distribute mouse entered or mouse exited events.
402          *
403          */
404         void handleModalFocusGained();
405 
406         /**
407          * Handles modal mouse input focus gained. If modal focus has been
408          * gained it might be necessary to distribute mouse entered or mouse
409          * exited events.
410          *
411          */
412         void handleModalFocusReleased();
413 
414     private:
415         /**
416          * Holds the top widget.
417          */
418         Widget* mTop;
419 
420         /**
421          * Holds the graphics implementation used.
422          */
423         Graphics* mGraphics A_NONNULLPOINTER;
424 
425         /**
426          * Holds the input implementation used.
427          */
428         SDLInput* mInput A_NONNULLPOINTER;
429 
430         /**
431          * Holds the focus handler for the Gui.
432          */
433         FocusHandler* mFocusHandler A_NONNULLPOINTER;
434 
435         /**
436          * Typedef.
437          */
438         typedef std::list<KeyListener*> KeyListenerList;
439 
440         /**
441          * Typedef.
442          */
443         typedef KeyListenerList::iterator KeyListenerListIterator;
444 
445         /**
446          * Holds the global key listeners of the Gui.
447          */
448         KeyListenerList mKeyListeners;
449 
450         /**
451          * Holds the last mouse button pressed.
452          */
453         MouseButtonT mLastMousePressButton;
454 
455         /**
456          * Holds the last mouse press time stamp.
457          */
458         unsigned int mLastMousePressTimeStamp;
459 
460         /**
461          * Holds the last mouse x coordinate.
462          */
463         int mLastMouseX;
464 
465         /**
466          * Holds the last mouse y coordinate.
467          */
468         int mLastMouseY;
469 
470         /**
471          * Holds the current click count. Used to keep track
472          * of clicks for a the last pressed button.
473          */
474         int mClickCount;
475 
476         /**
477          * Holds the last button used when a drag of a widget
478          * was initiated. Used to be able to release a drag
479          * when the same button is released.
480          */
481         MouseButtonT mLastMouseDragButton;
482 
483         /**
484          * Holds a stack with all the widgets with the mouse.
485          * Used to properly distribute mouse events.
486          */
487         std::deque<Widget*> mWidgetWithMouseQueue;
488 
489         GuiConfigListener *mConfigListener;
490         /** The global GUI font */
491         Font *mGuiFont A_NONNULLPOINTER;
492         /** Font for Info Particles */
493         Font *mInfoParticleFont A_NONNULLPOINTER;
494         /** Font for Help Window */
495         Font *mHelpFont A_NONNULLPOINTER;
496         /** Font for secure labels */
497         Font *mSecureFont A_NONNULLPOINTER;
498         /** Font for npc text */
499         Font *mNpcFont A_NONNULLPOINTER;
500         /** Mouse cursor images */
501         ImageSet *mMouseCursors;
502         float mMouseCursorAlpha;
503         int mMouseInactivityTimer;
504         CursorT mCursorType;
505 #ifdef ANDROID
506         uint16_t mLastMouseRealX;
507         uint16_t mLastMouseRealY;
508 #endif  // ANDROID
509 
510         typedef std::list<FocusListener*> FocusListenerList;
511         typedef FocusListenerList::iterator FocusListenerIterator;
512         FocusListenerList mFocusListeners;
513         Color mForegroundColor;
514         Color mForegroundColor2;
515         time_t mTime;
516         time_t mTime10;
517         bool mCustomCursor;                 /**< Show custom cursor */
518         bool mDoubleClick;
519 };
520 
521 extern Gui *gui;                            /**< The GUI system */
522 
523 /**
524  * Bolded text font
525  */
526 extern Font *boldFont A_NONNULLPOINTER;
527 
528 #endif  // GUI_GUI_H
529