Context.h 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. /*
  2. * This source file is part of RmlUi, the HTML/CSS Interface Middleware
  3. *
  4. * For the latest information, see http://github.com/mikke89/RmlUi
  5. *
  6. * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
  7. * Copyright (c) 2019-2023 The RmlUi Team, and contributors
  8. *
  9. * Permission is hereby granted, free of charge, to any person obtaining a copy
  10. * of this software and associated documentation files (the "Software"), to deal
  11. * in the Software without restriction, including without limitation the rights
  12. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  13. * copies of the Software, and to permit persons to whom the Software is
  14. * furnished to do so, subject to the following conditions:
  15. *
  16. * The above copyright notice and this permission notice shall be included in
  17. * all copies or substantial portions of the Software.
  18. *
  19. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  22. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  24. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  25. * THE SOFTWARE.
  26. *
  27. */
  28. #ifndef RMLUI_CORE_CONTEXT_H
  29. #define RMLUI_CORE_CONTEXT_H
  30. #include "Header.h"
  31. #include "Input.h"
  32. #include "ScriptInterface.h"
  33. #include "ScrollTypes.h"
  34. #include "Traits.h"
  35. #include "Types.h"
  36. namespace Rml {
  37. class Stream;
  38. class ContextInstancer;
  39. class ElementDocument;
  40. class EventListener;
  41. class DataModel;
  42. class DataModelConstructor;
  43. class DataTypeRegister;
  44. class ScrollController;
  45. class RenderManager;
  46. enum class EventId : uint16_t;
  47. /**
  48. A context for storing, rendering and processing RML documents. Multiple contexts can exist simultaneously.
  49. @author Peter Curry
  50. */
  51. class RMLUICORE_API Context : public ScriptInterface {
  52. public:
  53. /// Constructs a new, uninitialised context. This should not be called directly, use CreateContext() instead.
  54. /// @param[in] name The name of the context.
  55. /// @param[in] render_manager The render manager used for this context.
  56. Context(const String& name, RenderManager* render_manager);
  57. /// Destroys a context.
  58. virtual ~Context();
  59. /// Returns the name of the context.
  60. /// @return The context's name.
  61. const String& GetName() const;
  62. /// Changes the dimensions of the context.
  63. /// @param[in] dimensions The new dimensions of the context.
  64. void SetDimensions(Vector2i dimensions);
  65. /// Returns the dimensions of the context.
  66. /// @return The current dimensions of the context.
  67. Vector2i GetDimensions() const;
  68. /// Changes the size ratio of 'dp' unit to 'px' unit
  69. /// @param[in] dp_ratio The new density-independent pixel ratio of the context.
  70. void SetDensityIndependentPixelRatio(float density_independent_pixel_ratio);
  71. /// Returns the size ratio of 'dp' unit to 'px' unit
  72. /// @return The current density-independent pixel ratio of the context.
  73. float GetDensityIndependentPixelRatio() const;
  74. /// Updates all elements in the context's documents.
  75. /// This must be called before Context::Render, but after any elements have been changed, added or removed.
  76. bool Update();
  77. /// Renders all visible elements in the context's documents.
  78. bool Render();
  79. /// Creates a new, empty document and places it into this context.
  80. /// @param[in] instancer_name The name of the instancer used to create the document.
  81. /// @return The new document, or nullptr if no document could be created.
  82. ElementDocument* CreateDocument(const String& instancer_name = "body");
  83. /// Load a document into the context.
  84. /// @param[in] document_path The path to the document to load. The path is passed directly to the file interface which is used to load the file.
  85. /// The default file interface accepts both absolute paths and paths relative to the working directory.
  86. /// @return The loaded document, or nullptr if no document was loaded.
  87. ElementDocument* LoadDocument(const String& document_path);
  88. /// Load a document into the context.
  89. /// @param[in] document_stream The opened stream, ready to read.
  90. /// @return The loaded document, or nullptr if no document was loaded.
  91. ElementDocument* LoadDocument(Stream* document_stream);
  92. /// Load a document into the context.
  93. /// @param[in] document_rml The string containing the document RML.
  94. /// @param[in] source_url Optional string used to set the document's source URL, or naming the document for log messages.
  95. /// @return The loaded document, or nullptr if no document was loaded.
  96. ElementDocument* LoadDocumentFromMemory(const String& document_rml, const String& source_url = "[document from memory]");
  97. /// Unload the given document.
  98. /// @param[in] document The document to unload.
  99. /// @note The destruction of the document is deferred until the next call to Context::Update().
  100. void UnloadDocument(ElementDocument* document);
  101. /// Unloads all loaded documents.
  102. /// @note The destruction of the documents is deferred until the next call to Context::Update().
  103. void UnloadAllDocuments();
  104. /// Enable or disable handling of the mouse cursor from this context.
  105. /// When enabled, changes to the cursor name is transmitted through the system interface.
  106. /// @param[in] show True to enable mouse cursor handling, false to disable.
  107. void EnableMouseCursor(bool enable);
  108. /// Activate or deactivate a media theme. Themes can be used in RCSS media queries.
  109. /// @param theme_name[in] The name of the theme to (de)activate.
  110. /// @param activate True to activate the given theme, false to deactivate.
  111. void ActivateTheme(const String& theme_name, bool activate);
  112. /// Check if a given media theme has been activated.
  113. /// @param theme_name The name of the theme.
  114. /// @return True if the theme is activated.
  115. bool IsThemeActive(const String& theme_name) const;
  116. /// Returns the first document in the context with the given id.
  117. /// @param[in] id The id of the desired document.
  118. /// @return The document (if it was found), or nullptr if no document exists with the ID.
  119. ElementDocument* GetDocument(const String& id);
  120. /// Returns a document in the context by index.
  121. /// @param[in] index The index of the desired document.
  122. /// @return The document (if one exists with this index), or nullptr if the index was invalid.
  123. ElementDocument* GetDocument(int index);
  124. /// Returns the number of documents in the context.
  125. int GetNumDocuments() const;
  126. /// Returns the hover element.
  127. /// @return The element the mouse cursor is hovering over.
  128. Element* GetHoverElement();
  129. /// Returns the focus element.
  130. /// @return The element with input focus.
  131. Element* GetFocusElement();
  132. /// Returns the root element that holds all the documents
  133. /// @return The root element.
  134. Element* GetRootElement();
  135. // Returns the youngest descendent of the given element which is under the given point in screen coordinates.
  136. // @param[in] point The point to test.
  137. // @param[in] ignore_element If set, this element and its descendents will be ignored.
  138. // @param[in] element Used internally.
  139. // @return The element under the point, or nullptr if nothing is.
  140. Element* GetElementAtPoint(Vector2f point, const Element* ignore_element = nullptr, Element* element = nullptr) const;
  141. /// Brings the document to the front of the document stack.
  142. /// @param[in] document The document to pull to the front of the stack.
  143. void PullDocumentToFront(ElementDocument* document);
  144. /// Sends the document to the back of the document stack.
  145. /// @param[in] document The document to push to the bottom of the stack.
  146. void PushDocumentToBack(ElementDocument* document);
  147. /// Remove the document from the focus history and focus the previous document.
  148. /// @param[in] document The document to unfocus.
  149. void UnfocusDocument(ElementDocument* document);
  150. /// Adds an event listener to the context's root element.
  151. /// @param[in] event The name of the event to attach to.
  152. /// @param[in] listener Listener object to be attached.
  153. /// @param[in] in_capture_phase True if the listener is to be attached to the capture phase, false for the bubble phase.
  154. void AddEventListener(const String& event, EventListener* listener, bool in_capture_phase = false);
  155. /// Removes an event listener from the context's root element.
  156. /// @param[in] event The name of the event to detach from.
  157. /// @param[in] listener Listener object to be detached.
  158. /// @param[in] in_capture_phase True to detach from the capture phase, false from the bubble phase.
  159. void RemoveEventListener(const String& event, EventListener* listener, bool in_capture_phase = false);
  160. /// Sends a key down event into this context.
  161. /// @param[in] key_identifier The key pressed.
  162. /// @param[in] key_modifier_state The state of key modifiers (shift, control, caps-lock, etc) keys; this should be generated by ORing together
  163. /// members of the Input::KeyModifier enumeration.
  164. /// @return True if the event was not consumed (ie, was prevented from propagating by an element), false if it was.
  165. bool ProcessKeyDown(Input::KeyIdentifier key_identifier, int key_modifier_state);
  166. /// Sends a key up event into this context.
  167. /// @param[in] key_identifier The key released.
  168. /// @param[in] key_modifier_state The state of key modifiers (shift, control, caps-lock, etc) keys; this should be generated by ORing together
  169. /// members of the Input::KeyModifier enumeration.
  170. /// @return True if the event was not consumed (ie, was prevented from propagating by an element), false if it was.
  171. bool ProcessKeyUp(Input::KeyIdentifier key_identifier, int key_modifier_state);
  172. /// Sends a single unicode character as text input into this context.
  173. /// @param[in] character The unicode code point to send into this context.
  174. /// @return True if the event was not consumed (ie, was prevented from propagating by an element), false if it was.
  175. bool ProcessTextInput(Character character);
  176. /// Sends a single ascii character as text input into this context.
  177. bool ProcessTextInput(char character);
  178. /// Sends a string of text as text input into this context.
  179. /// @param[in] string The UTF-8 string to send into this context.
  180. /// @return True if the event was not consumed (ie, was prevented from propagating by an element), false if it was.
  181. bool ProcessTextInput(const String& string);
  182. /// Sends a mouse movement event into this context.
  183. /// @param[in] x The x-coordinate of the mouse cursor, in window-coordinates (ie, 0 should be the left of the client area).
  184. /// @param[in] y The y-coordinate of the mouse cursor, in window-coordinates (ie, 0 should be the top of the client area).
  185. /// @param[in] key_modifier_state The state of key modifiers (shift, control, caps-lock, etc) keys; this should be generated by ORing together
  186. /// members of the Input::KeyModifier enumeration.
  187. /// @return True if the mouse is not interacting with any elements in the context (see 'IsMouseInteracting'), otherwise false.
  188. bool ProcessMouseMove(int x, int y, int key_modifier_state);
  189. /// Sends a mouse-button down event into this context.
  190. /// @param[in] button_index The index of the button that was pressed; 0 for the left button, 1 for right, and 2 for middle button.
  191. /// @param[in] key_modifier_state The state of key modifiers (shift, control, caps-lock, etc) keys; this should be generated by ORing together
  192. /// members of the Input::KeyModifier enumeration.
  193. /// @return True if the mouse is not interacting with any elements in the context (see 'IsMouseInteracting'), otherwise false.
  194. bool ProcessMouseButtonDown(int button_index, int key_modifier_state);
  195. /// Sends a mouse-button up event into this context.
  196. /// @param[in] button_index The index of the button that was release; 0 for the left button, 1 for right, and 2 for middle button.
  197. /// @param[in] key_modifier_state The state of key modifiers (shift, control, caps-lock, etc) keys; this should be generated by ORing together
  198. /// members of the Input::KeyModifier enumeration.
  199. /// @return True if the mouse is not interacting with any elements in the context (see 'IsMouseInteracting'), otherwise false.
  200. bool ProcessMouseButtonUp(int button_index, int key_modifier_state);
  201. /// Sends a mousescroll event into this context.
  202. /// @deprecated Please use the Vector2f version of this function.
  203. bool ProcessMouseWheel(float wheel_delta, int key_modifier_state);
  204. /// Sends a mousescroll event into this context, and scrolls the document unless the event was stopped from propagating.
  205. /// @param[in] wheel_delta The mouse-wheel movement this frame, with positive values being directed right and down.
  206. /// @param[in] key_modifier_state The state of key modifiers (shift, control, caps-lock, etc) keys; this should be generated by ORing together
  207. /// members of the Input::KeyModifier enumeration.
  208. /// @return True if the event was not consumed (ie, was prevented from propagating by an element), false if it was.
  209. bool ProcessMouseWheel(Vector2f wheel_delta, int key_modifier_state);
  210. /// Tells the context the mouse has left the window. This removes any hover state from all elements and prevents 'Update()' from setting the hover
  211. /// state for elements under the mouse.
  212. /// @return True if the mouse is not interacting with any elements in the context (see 'IsMouseInteracting'), otherwise false.
  213. /// @note The mouse is considered activate again after the next call to 'ProcessMouseMove()'.
  214. bool ProcessMouseLeave();
  215. /// Returns a hint on whether the mouse is currently interacting with any elements in this context, based on previously submitted
  216. /// 'ProcessMouse...()' commands.
  217. /// @note Interaction is determined irrespective of background and opacity. See the RCSS property 'pointer-events' to disable interaction for
  218. /// specific elements.
  219. /// @return True if the mouse hovers over or has activated an element in this context, otherwise false.
  220. bool IsMouseInteracting() const;
  221. /// Sets the default scroll behavior, such as for mouse wheel processing and scrollbar interaction.
  222. /// @param[in] scroll_behavior The default smooth scroll behavior, set to instant to disable smooth scrolling.
  223. /// @param[in] speed_factor A factor for adjusting the final smooth scrolling speed, must be strictly positive, defaults to 1.0.
  224. void SetDefaultScrollBehavior(ScrollBehavior scroll_behavior, float speed_factor);
  225. /// Retrieves the render manager which can be used to submit changes to the render state.
  226. RenderManager& GetRenderManager();
  227. /// Sets the instancer to use for releasing this object.
  228. /// @param[in] instancer The context's instancer.
  229. void SetInstancer(ContextInstancer* instancer);
  230. /// Creates a data model.
  231. /// The returned constructor can be used to bind data variables. Elements can bind to the model using the attribute 'data-model="name"'.
  232. /// @param[in] name The name of the data model.
  233. /// @param[in] data_type_register The data type register to use for the data model, or null to use the default register.
  234. /// @return A constructor for the data model, or empty if it could not be created.
  235. DataModelConstructor CreateDataModel(const String& name, DataTypeRegister* data_type_register = nullptr);
  236. /// Retrieves the constructor for an existing data model.
  237. /// The returned constructor can be used to add additional bindings to an existing model.
  238. /// @param[in] name The name of the data model.
  239. /// @return A constructor for the data model, or empty if it could not be found.
  240. DataModelConstructor GetDataModel(const String& name);
  241. /// Removes the given data model.
  242. /// This also removes all data views, controllers and bindings contained by the data model.
  243. /// @warning Invalidates all handles and constructors pointing to the data model.
  244. /// @param[in] name The name of the data model.
  245. /// @return True if succesfully removed, false if no data model was found.
  246. bool RemoveDataModel(const String& name);
  247. /// This will set the documents base <tag> before creation. Default = "body"
  248. /// @param[in] tag The name of the base tag. Example: "html"
  249. void SetDocumentsBaseTag(const String& tag);
  250. /// Gets the name of the documents base tag.
  251. /// @return The current documents base tag name.
  252. const String& GetDocumentsBaseTag();
  253. /// Updates the time until Update should get called again. This can be used by elements
  254. /// and the app to implement on demand rendering and thus drastically save CPU/GPU and
  255. /// reduce power consumption during inactivity. The context stores the lowest requested
  256. /// timestamp, which can later retrieved using GetNextUpdateDelay().
  257. /// @param[in] delay Maximum time until next update
  258. void RequestNextUpdate(double delay);
  259. /// Get the max delay until update and render should get called again. An application can choose
  260. /// to only call update and render once the time has elapsed, but theres no harm in doing so
  261. /// more often. The returned value can be infinity, in which case update should be invoked after
  262. /// user input was received. A value of 0 means "render as fast as possible", for example if
  263. /// an animation is playing.
  264. /// @return Time until next update is expected.
  265. double GetNextUpdateDelay() const;
  266. protected:
  267. void Release() override;
  268. private:
  269. String name;
  270. Vector2i dimensions;
  271. float density_independent_pixel_ratio = 1.f;
  272. String documents_base_tag = "body";
  273. // Wrapper around the render interface for tracking the render state.
  274. RenderManager* render_manager;
  275. SmallUnorderedSet<String> active_themes;
  276. ContextInstancer* instancer;
  277. using ElementSet = SmallOrderedSet<Element*>;
  278. using ElementList = Vector<Element*>;
  279. // Set of elements that are currently in hover state.
  280. ElementSet hover_chain;
  281. // List of elements that are currently in active state.
  282. ElementList active_chain;
  283. // History of windows that have had focus
  284. ElementList document_focus_history;
  285. // Documents that have been unloaded from the context but not yet released.
  286. OwnedElementList unloaded_documents;
  287. // Root of the element tree.
  288. ElementPtr root;
  289. // The element that currently has input focus.
  290. Element* focus;
  291. // The top-most element being hovered over.
  292. Element* hover;
  293. // The element that was being hovered over when the primary mouse button was pressed most recently.
  294. Element* active;
  295. // The element that was clicked on last.
  296. Element* last_click_element;
  297. // The time the last click occurred.
  298. double last_click_time;
  299. // Mouse position during the last mouse_down event.
  300. Vector2i last_click_mouse_position;
  301. // Input state; stored from the most recent input events we receive from the application.
  302. Vector2i mouse_position;
  303. bool mouse_active;
  304. // Controller for various scroll behavior modes.
  305. UniquePtr<ScrollController> scroll_controller; // [not-null]
  306. // Enables cursor handling.
  307. bool enable_cursor;
  308. String cursor_name;
  309. // Document attached to cursor (e.g. while dragging).
  310. ElementPtr cursor_proxy;
  311. // The element that is currently being dragged (or about to be dragged).
  312. Element* drag;
  313. // True if a drag has begun (ie, the ondragstart event has been fired for the drag element), false otherwise.
  314. bool drag_started;
  315. // True if the current drag is a verbose drag (ie, sends ondragover, ondragout, ondragdrop, etc, events).
  316. bool drag_verbose;
  317. // Used when dragging a cloned object.
  318. Element* drag_clone;
  319. // The element currently being dragged over; this is equivalent to hover, but only set while an element is being
  320. // dragged, and excludes the dragged element.
  321. Element* drag_hover;
  322. // Set of elements that are currently being dragged over; this differs from the hover state as the dragged element
  323. // itself can't be part of it.
  324. ElementSet drag_hover_chain;
  325. using DataModels = UnorderedMap<String, UniquePtr<DataModel>>;
  326. DataModels data_models;
  327. UniquePtr<DataTypeRegister> default_data_type_register;
  328. // Time in seconds until Update and Render should be called again. This allows applications to only redraw the ui if needed.
  329. // See RequestNextUpdate() and NextUpdateRequested() for details.
  330. double next_update_timeout = 0;
  331. // Internal callback for when an element is detached or removed from the hierarchy.
  332. void OnElementDetach(Element* element);
  333. // Internal callback for when a new element gains focus.
  334. bool OnFocusChange(Element* element, bool focus_visible);
  335. // Generates an event for faking clicks on an element.
  336. void GenerateClickEvent(Element* element);
  337. // Updates the current hover elements, sending required events.
  338. void UpdateHoverChain(Vector2i old_mouse_position, int key_modifier_state = 0, Dictionary* out_parameters = nullptr,
  339. Dictionary* out_drag_parameters = nullptr);
  340. // Creates the drag clone from the given element. The old drag clone will be released if necessary.
  341. void CreateDragClone(Element* element);
  342. // Releases the drag clone, if one exists.
  343. void ReleaseDragClone();
  344. // Scroll the target by the given amount, using smooth scrolling.
  345. void PerformSmoothscrollOnTarget(Element* target, Vector2f delta_offset, ScrollBehavior scroll_behavior);
  346. // Returns the data model with the provided name, or nullptr if it does not exist.
  347. DataModel* GetDataModelPtr(const String& name) const;
  348. // Builds the parameters for a generic key event.
  349. void GenerateKeyEventParameters(Dictionary& parameters, Input::KeyIdentifier key_identifier);
  350. // Builds the parameters for a generic mouse event.
  351. void GenerateMouseEventParameters(Dictionary& parameters, int button_index = -1);
  352. // Builds the parameters for the key modifier state.
  353. void GenerateKeyModifierEventParameters(Dictionary& parameters, int key_modifier_state);
  354. // Builds the parameters for a drag event.
  355. void GenerateDragEventParameters(Dictionary& parameters);
  356. // Releases all unloaded documents pending destruction.
  357. void ReleaseUnloadedDocuments();
  358. // Sends the specified event to all elements in new_items that don't appear in old_items.
  359. static void SendEvents(const ElementSet& old_items, const ElementSet& new_items, EventId id, const Dictionary& parameters);
  360. friend class Rml::Element;
  361. };
  362. } // namespace Rml
  363. #endif