1 //
2 // Copyright (c) 2008-2017 the Urho3D project.
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to deal
6 // in the Software without restriction, including without limitation the rights
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 // copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 // THE SOFTWARE.
21 //
22 
23 #pragma once
24 
25 #include "../Core/Object.h"
26 #include "../UI/Cursor.h"
27 #include "../UI/UIBatch.h"
28 
29 namespace Urho3D
30 {
31 
32 /// Font hinting level (only used for FreeType fonts)
33 enum FontHintLevel
34 {
35     /// Completely disable font hinting. Output will be blurrier but more "correct".
36     FONT_HINT_LEVEL_NONE = 0,
37 
38     /// Light hinting. FreeType will pixel-align fonts vertically, but not horizontally.
39     FONT_HINT_LEVEL_LIGHT,
40 
41     /// Full hinting, using either the font's own hinting or FreeType's auto-hinter.
42     FONT_HINT_LEVEL_NORMAL
43 };
44 
45 class Cursor;
46 class Graphics;
47 class ResourceCache;
48 class Timer;
49 class UIBatch;
50 class UIElement;
51 class VertexBuffer;
52 class XMLElement;
53 class XMLFile;
54 
55 /// %UI subsystem. Manages the graphical user interface.
56 class URHO3D_API UI : public Object
57 {
58     URHO3D_OBJECT(UI, Object);
59 
60 public:
61     /// Construct.
62     UI(Context* context);
63     /// Destruct.
64     virtual ~UI();
65 
66     /// Set cursor UI element.
67     void SetCursor(Cursor* cursor);
68     /// Set focused UI element.
69     void SetFocusElement(UIElement* element, bool byKey = false);
70     /// Set modal element. Until all the modal elements are dismissed, all the inputs and events are only sent to them. Return true when successful.
71     /// Only the modal element can clear its modal status or when it is being destructed.
72     bool SetModalElement(UIElement* modalElement, bool enable);
73     /// Clear the UI (excluding the cursor.)
74     void Clear();
75     /// Update the UI logic. Called by HandlePostUpdate().
76     void Update(float timeStep);
77     /// Update the UI for rendering. Called by HandleRenderUpdate().
78     void RenderUpdate();
79     /// Render the UI. If resetRenderTargets is true, is assumed to be the default UI render to backbuffer called by Engine, and will be performed only once. Additional UI renders to a different rendertarget may be triggered from the renderpath.
80     void Render(bool resetRenderTargets = true);
81     /// Debug draw a UI element.
82     void DebugDraw(UIElement* element);
83     /// Load a UI layout from an XML file. Optionally specify another XML file for element style. Return the root element.
84     SharedPtr<UIElement> LoadLayout(Deserializer& source, XMLFile* styleFile = 0);
85     /// Load a UI layout from an XML file. Optionally specify another XML file for element style. Return the root element.
86     SharedPtr<UIElement> LoadLayout(XMLFile* file, XMLFile* styleFile = 0);
87     /// Save a UI layout to an XML file. Return true if successful.
88     bool SaveLayout(Serializer& dest, UIElement* element);
89     /// Set clipboard text.
90     void SetClipboardText(const String& text);
91     /// Set UI element double click interval in seconds.
92     void SetDoubleClickInterval(float interval);
93     /// Set UI drag event start interval in seconds.
94     void SetDragBeginInterval(float interval);
95     /// Set UI drag event start distance threshold in pixels.
96     void SetDragBeginDistance(int pixels);
97     /// Set tooltip default display delay in seconds.
98     void SetDefaultToolTipDelay(float delay);
99     /// Set maximum font face texture size. Must be a power of two. Default is 2048.
100     void SetMaxFontTextureSize(int size);
101     /// Set whether mouse wheel can control also a non-focused element.
102     void SetNonFocusedMouseWheel(bool nonFocusedMouseWheel);
103     /// Set whether to use system clipboard. Default false.
104     void SetUseSystemClipboard(bool enable);
105     /// Set whether to show the on-screen keyboard (if supported) when a %LineEdit is focused. Default true on mobile devices.
106     void SetUseScreenKeyboard(bool enable);
107     /// Set whether to use mutable (eraseable) glyphs to ensure a font face never expands to more than one texture. Default false.
108     void SetUseMutableGlyphs(bool enable);
109     /// Set whether to force font autohinting instead of using FreeType's TTF bytecode interpreter.
110     void SetForceAutoHint(bool enable);
111     /// Set the hinting level used by FreeType fonts.
112     void SetFontHintLevel(FontHintLevel level);
113     /// Set the font subpixel threshold. Below this size, if the hint level is LIGHT or NONE, fonts will use subpixel positioning plus oversampling for higher-quality rendering. Has no effect at hint level NORMAL.
114     void SetFontSubpixelThreshold(float threshold);
115     /// Set the oversampling (horizonal stretching) used to improve subpixel font rendering. Only affects fonts smaller than the subpixel limit.
116     void SetFontOversampling(int oversampling);
117     /// Set %UI scale. 1.0 is default (pixel perfect). Resize the root element to match.
118     void SetScale(float scale);
119     /// Scale %UI to the specified width in pixels.
120     void SetWidth(float width);
121     /// Scale %UI to the specified height in pixels.
122     void SetHeight(float height);
123     /// Set custom size of the root element. This disables automatic resizing of the root element according to window size. Set custom size 0,0 to return to automatic resizing.
124     void SetCustomSize(const IntVector2& size);
125     /// Set custom size of the root element.
126     void SetCustomSize(int width, int height);
127 
128     /// Return root UI element.
GetRoot()129     UIElement* GetRoot() const { return rootElement_; }
130 
131     /// Return root modal element.
GetRootModalElement()132     UIElement* GetRootModalElement() const { return rootModalElement_; }
133 
134     /// Return cursor.
GetCursor()135     Cursor* GetCursor() const { return cursor_; }
136 
137     /// Return cursor position.
138     IntVector2 GetCursorPosition() const;
139     /// Return UI element at screen coordinates. By default returns only input-enabled elements.
140     UIElement* GetElementAt(const IntVector2& position, bool enabledOnly = true);
141     /// Return UI element at screen coordinates. By default returns only input-enabled elements.
142     UIElement* GetElementAt(int x, int y, bool enabledOnly = true);
143 
144     /// Return focused element.
GetFocusElement()145     UIElement* GetFocusElement() const { return focusElement_; }
146 
147     /// Return topmost enabled root-level non-modal element.
148     UIElement* GetFrontElement() const;
149     /// Return currently dragged elements.
150     const Vector<UIElement*> GetDragElements();
151 
152     /// Return the number of currently dragged elements.
GetNumDragElements()153     unsigned GetNumDragElements() const { return (unsigned)dragConfirmedCount_; }
154 
155     /// Return the drag element at index.
156     UIElement* GetDragElement(unsigned index);
157     /// Return clipboard text.
158     const String& GetClipboardText() const;
159 
160     /// Return UI element double click interval in seconds.
GetDoubleClickInterval()161     float GetDoubleClickInterval() const { return doubleClickInterval_; }
162 
163     /// Return UI drag start event interval in seconds.
GetDragBeginInterval()164     float GetDragBeginInterval() const { return dragBeginInterval_; }
165 
166     /// Return UI drag start event distance threshold in pixels.
GetDragBeginDistance()167     int GetDragBeginDistance() const { return dragBeginDistance_; }
168 
169     /// Return tooltip default display delay in seconds.
GetDefaultToolTipDelay()170     float GetDefaultToolTipDelay() const { return defaultToolTipDelay_; }
171 
172     /// Return font texture maximum size.
GetMaxFontTextureSize()173     int GetMaxFontTextureSize() const { return maxFontTextureSize_; }
174 
175     /// Return whether mouse wheel can control also a non-focused element.
IsNonFocusedMouseWheel()176     bool IsNonFocusedMouseWheel() const { return nonFocusedMouseWheel_; }
177 
178     /// Return whether is using the system clipboard.
GetUseSystemClipboard()179     bool GetUseSystemClipboard() const { return useSystemClipboard_; }
180 
181     /// Return whether focusing a %LineEdit will show the on-screen keyboard.
GetUseScreenKeyboard()182     bool GetUseScreenKeyboard() const { return useScreenKeyboard_; }
183 
184     /// Return whether is using mutable (eraseable) glyphs for fonts.
GetUseMutableGlyphs()185     bool GetUseMutableGlyphs() const { return useMutableGlyphs_; }
186 
187     /// Return whether is using forced autohinting.
GetForceAutoHint()188     bool GetForceAutoHint() const { return forceAutoHint_; }
189 
190     /// Return the current FreeType font hinting level.
GetFontHintLevel()191     FontHintLevel GetFontHintLevel() const { return fontHintLevel_; }
192 
193     /// Get the font subpixel threshold. Below this size, if the hint level is LIGHT or NONE, fonts will use subpixel positioning plus oversampling for higher-quality rendering. Has no effect at hint level NORMAL.
GetFontSubpixelThreshold()194     float GetFontSubpixelThreshold() const { return fontSubpixelThreshold_; }
195 
196     /// Get the oversampling (horizonal stretching) used to improve subpixel font rendering. Only affects fonts smaller than the subpixel limit.
GetFontOversampling()197     int GetFontOversampling() const { return fontOversampling_; }
198 
199     /// Return true when UI has modal element(s).
200     bool HasModalElement() const;
201 
202     /// Return whether a drag is in progress.
IsDragging()203     bool IsDragging() const { return dragConfirmedCount_ > 0; };
204 
205     /// Return current UI scale.
GetScale()206     float GetScale() const { return uiScale_; }
207 
208     /// Return root element custom size. Returns 0,0 when custom size is not being used and automatic resizing according to window size is in use instead (default.)
GetCustomSize()209     const IntVector2& GetCustomSize() const { return customSize_; }
210 
211     /// Data structure used to represent the drag data associated to a UIElement.
212     struct DragData
213     {
214         /// Which button combo initiated the drag.
215         int dragButtons;
216         /// How many buttons initiated the drag.
217         int numDragButtons;
218         /// Sum of all touch locations
219         IntVector2 sumPos;
220         /// Flag for a drag start event pending.
221         bool dragBeginPending;
222         /// Timer used to trigger drag begin event.
223         Timer dragBeginTimer;
224         /// Drag start position.
225         IntVector2 dragBeginSumPos;
226     };
227 
228 private:
229     /// Initialize when screen mode initially set.
230     void Initialize();
231     /// Update UI element logic recursively.
232     void Update(float timeStep, UIElement* element);
233     /// Upload UI geometry into a vertex buffer.
234     void SetVertexData(VertexBuffer* dest, const PODVector<float>& vertexData);
235     /// Render UI batches. Geometry must have been uploaded first.
236     void Render
237         (bool resetRenderTargets, VertexBuffer* buffer, const PODVector<UIBatch>& batches, unsigned batchStart, unsigned batchEnd);
238     /// Generate batches from an UI element recursively. Skip the cursor element.
239     void GetBatches(UIElement* element, IntRect currentScissor);
240     /// Return UI element at screen position recursively.
241     void GetElementAt(UIElement*& result, UIElement* current, const IntVector2& position, bool enabledOnly);
242     /// Return the first element in hierarchy that can alter focus.
243     UIElement* GetFocusableElement(UIElement* element);
244     /// Return cursor position and visibility either from the cursor element, or the Input subsystem.
245     void GetCursorPositionAndVisible(IntVector2& pos, bool& visible);
246     /// Set active cursor's shape.
247     void SetCursorShape(CursorShape shape);
248     /// Force release of font faces when global font properties change.
249     void ReleaseFontFaces();
250     /// Handle button or touch hover.
251     void ProcessHover(const IntVector2& cursorPos, int buttons, int qualifiers, Cursor* cursor);
252     /// Handle button or touch begin.
253     void
254         ProcessClickBegin(const IntVector2& cursorPos, int button, int buttons, int qualifiers, Cursor* cursor, bool cursorVisible);
255     /// Handle button or touch end.
256     void ProcessClickEnd(const IntVector2& cursorPos, int button, int buttons, int qualifiers, Cursor* cursor, bool cursorVisible);
257     /// Handle mouse or touch move.
258     void ProcessMove(const IntVector2& cursorPos, const IntVector2& cursorDeltaPos, int buttons, int qualifiers, Cursor* cursor,
259         bool cursorVisible);
260     /// Send a UI element drag or hover begin event.
261     void SendDragOrHoverEvent
262         (StringHash eventType, UIElement* element, const IntVector2& screenPos, const IntVector2& deltaPos, UI::DragData* dragData);
263     /// Send a UI click or double click event.
264     void SendClickEvent
265         (StringHash eventType, UIElement* beginElement, UIElement* endElement, const IntVector2& pos, int button, int buttons,
266             int qualifiers);
267     /// Handle screen mode event.
268     void HandleScreenMode(StringHash eventType, VariantMap& eventData);
269     /// Handle mouse button down event.
270     void HandleMouseButtonDown(StringHash eventType, VariantMap& eventData);
271     /// Handle mouse button up event.
272     void HandleMouseButtonUp(StringHash eventType, VariantMap& eventData);
273     /// Handle mouse move event.
274     void HandleMouseMove(StringHash eventType, VariantMap& eventData);
275     /// Handle mouse wheel event.
276     void HandleMouseWheel(StringHash eventType, VariantMap& eventData);
277     /// Handle touch begin event.
278     void HandleTouchBegin(StringHash eventType, VariantMap& eventData);
279     /// Handle touch end event.
280     void HandleTouchEnd(StringHash eventType, VariantMap& eventData);
281     /// Handle touch move event.
282     void HandleTouchMove(StringHash eventType, VariantMap& eventData);
283     /// Handle keypress event.
284     void HandleKeyDown(StringHash eventType, VariantMap& eventData);
285     /// Handle text input event.
286     void HandleTextInput(StringHash eventType, VariantMap& eventData);
287     /// Handle frame begin event.
288     void HandleBeginFrame(StringHash eventType, VariantMap& eventData);
289     /// Handle logic post-update event.
290     void HandlePostUpdate(StringHash eventType, VariantMap& eventData);
291     /// Handle render update event.
292     void HandleRenderUpdate(StringHash eventType, VariantMap& eventData);
293     /// Handle a file being drag-dropped into the application window.
294     void HandleDropFile(StringHash eventType, VariantMap& eventData);
295     /// Remove drag data and return next iterator.
296     HashMap<WeakPtr<UIElement>, DragData*>::Iterator DragElementErase(HashMap<WeakPtr<UIElement>, DragData*>::Iterator dragElement);
297     /// Handle clean up on a drag cancel.
298     void ProcessDragCancel();
299     /// Sum touch positions and return the begin position ready to send.
300     IntVector2 SumTouchPositions(UI::DragData* dragData, const IntVector2& oldSendPos);
301     /// Resize root element to effective size.
302     void ResizeRootElement();
303     /// Return effective size of the root element, according to UI scale and resolution / custom size.
304     IntVector2 GetEffectiveRootElementSize(bool applyScale = true) const;
305 
306     /// Graphics subsystem.
307     WeakPtr<Graphics> graphics_;
308     /// UI root element.
309     SharedPtr<UIElement> rootElement_;
310     /// UI root modal element.
311     SharedPtr<UIElement> rootModalElement_;
312     /// Cursor.
313     SharedPtr<Cursor> cursor_;
314     /// Currently focused element.
315     WeakPtr<UIElement> focusElement_;
316     /// UI rendering batches.
317     PODVector<UIBatch> batches_;
318     /// UI rendering vertex data.
319     PODVector<float> vertexData_;
320     /// UI rendering batches for debug draw.
321     PODVector<UIBatch> debugDrawBatches_;
322     /// UI rendering vertex data for debug draw.
323     PODVector<float> debugVertexData_;
324     /// UI vertex buffer.
325     SharedPtr<VertexBuffer> vertexBuffer_;
326     /// UI debug geometry vertex buffer.
327     SharedPtr<VertexBuffer> debugVertexBuffer_;
328     /// UI element query vector.
329     PODVector<UIElement*> tempElements_;
330     /// Clipboard text.
331     mutable String clipBoard_;
332     /// Seconds between clicks to register a double click.
333     float doubleClickInterval_;
334     /// Seconds from mouse button down to begin a drag if there has been no movement exceeding pixel threshold.
335     float dragBeginInterval_;
336     /// Tooltip default display delay in seconds.
337     float defaultToolTipDelay_;
338     /// Drag begin event distance threshold in pixels.
339     int dragBeginDistance_;
340     /// Mouse buttons held down.
341     int mouseButtons_;
342     /// Last mouse button pressed.
343     int lastMouseButtons_;
344     /// Qualifier keys held down.
345     int qualifiers_;
346     /// Font texture maximum size.
347     int maxFontTextureSize_;
348     /// Initialized flag.
349     bool initialized_;
350     /// Touch used flag.
351     bool usingTouchInput_;
352     /// Flag to switch mouse wheel event to be sent to non-focused element at cursor.
353     bool nonFocusedMouseWheel_;
354     /// Flag for using operating system clipboard instead of internal.
355     bool useSystemClipboard_;
356     /// Flag for showing the on-screen keyboard on focusing a %LineEdit.
357     bool useScreenKeyboard_;
358     /// Flag for using mutable (erasable) font glyphs.
359     bool useMutableGlyphs_;
360     /// Flag for forcing FreeType auto hinting.
361     bool forceAutoHint_;
362     /// FreeType hinting level (default is FONT_HINT_LEVEL_NORMAL).
363     FontHintLevel fontHintLevel_;
364     /// Maxmimum font size for subpixel glyph positioning and oversampling (default is 12).
365     float fontSubpixelThreshold_;
366     /// Horizontal oversampling for subpixel fonts (default is 2).
367     int fontOversampling_;
368     /// Flag for UI already being rendered this frame.
369     bool uiRendered_;
370     /// Non-modal batch size (used internally for rendering).
371     unsigned nonModalBatchSize_;
372     /// Timer used to trigger double click.
373     Timer clickTimer_;
374     /// UI element last clicked for tracking double clicks.
375     WeakPtr<UIElement> doubleClickElement_;
376     /// Currently hovered elements.
377     HashMap<WeakPtr<UIElement>, bool> hoveredElements_;
378     /// Currently dragged elements.
379     HashMap<WeakPtr<UIElement>, DragData*> dragElements_;
380     /// Number of elements in dragElements_.
381     int dragElementsCount_;
382     /// Number of elements in dragElements_ with dragPending = false.
383     int dragConfirmedCount_;
384     /// UI elements that are being touched with touch input.
385     HashMap<WeakPtr<UIElement>, int> touchDragElements_;
386     /// Confirmed drag elements cache.
387     Vector<UIElement*> dragElementsConfirmed_;
388     /// Current scale of UI.
389     float uiScale_;
390     /// Root element custom size. 0,0 for automatic resizing (default.)
391     IntVector2 customSize_;
392 };
393 
394 /// Register UI library objects.
395 void URHO3D_API RegisterUILibrary(Context* context);
396 
397 }
398