1 /** 2 Gui Overlay 3 4 Copyright: (c) Enalye 2017 5 License: Zlib 6 Authors: Enalye 7 */ 8 9 module atelier.ui.gui_overlay; 10 11 import std.algorithm.comparison : max; 12 import atelier.core, atelier.render, atelier.common; 13 import atelier.ui.gui_element, atelier.ui.label, atelier.ui.text, atelier.ui.gui_manager; 14 15 private { 16 HintWindow _hintWindow; 17 Hint _displayedHint; 18 GuiElement[] _backupGuis; 19 GuiElement[] _overlayGuiElements; 20 bool _isOverlay = false; 21 } 22 23 /// Create a Hint for a gui element. 24 Hint makeHint(string text) { 25 return new Hint(text); 26 } 27 28 /// Displays text next to the cursor when hovering over a gui. 29 class Hint { 30 /// The title is rendered above the text. 31 string text; 32 33 /// Ctor 34 this(string text_) { 35 text = text_; 36 } 37 } 38 39 /// Create the hint gui. 40 package void openHintWindow(Hint hint) { 41 _hintWindow = new HintWindow; 42 _displayedHint = hint; 43 } 44 45 /// Is there a gui running as an overlay ? 46 bool isOverlay() { 47 return _isOverlay; 48 } 49 50 /// Add the gui as an overlay (rendered above all other guis). \ 51 /// Doesn't take away events from the other guis (unlike modal). 52 void setOverlay(GuiElement gui) { 53 if (!_isOverlay) { 54 _isOverlay = true; 55 _backupGuis = getRoots(); 56 removeRoots(); 57 } 58 59 _overlayGuiElements ~= gui; 60 appendRoot(gui); 61 } 62 63 /// Remove the current overlay gui. 64 void stopOverlay() { 65 if (!_isOverlay) 66 return; 67 _isOverlay = false; 68 setRoots(_backupGuis); 69 _backupGuis.length = 0L; 70 _overlayGuiElements.length = 0L; 71 } 72 73 /// Process events from the guis that aren't overlay. 74 package void processOverlayEvent(Event event) { 75 switch (event.type) with (Event.Type) { 76 case quit: 77 foreach (gui; _backupGuis) { 78 gui.onQuit(); 79 gui.onEvent(event); 80 } 81 stopOverlay(); 82 break; 83 case resize: 84 case custom: 85 foreach (gui; _backupGuis) { 86 gui.onEvent(event); 87 } 88 break; 89 default: 90 break; 91 } 92 } 93 94 /// Updates and renders guis that are behind. 95 package(atelier) void processOverlayBack() { 96 foreach (gui; _backupGuis) { 97 updateRoots(gui, null); 98 drawRoots(gui); 99 } 100 } 101 102 /// Updates and renders guis that are in front (like the hint). 103 package(atelier) void processOverlayFront(float deltaTime) { 104 if (_hintWindow is null) 105 return; 106 _hintWindow.hint = _displayedHint; 107 _hintWindow.update(deltaTime); 108 _hintWindow.draw(); 109 } 110 111 /// Stops overlay gui. 112 void endOverlay() { 113 _displayedHint = null; 114 } 115 116 /// The gui that renders the hint. 117 private final class HintWindow : GuiElement { 118 private { 119 bool _isRendered; 120 } 121 Label text; 122 123 @property void hint(Hint hint) { 124 _isRendered = hint !is null; 125 if (_isRendered) { 126 text.text = hint.text; 127 } 128 } 129 130 this() { 131 text = new Label; 132 } 133 134 override void update(float deltaTime) { 135 if (!_isRendered) 136 return; 137 size = Vec2f(text.size.x + 25f, text.size.y); 138 139 //They aren't processed by the gui manager, so we use setScreenCoords directly. 140 setScreenCoords(getMousePos() + size / 2f + Vec2f(20f, 10f)); 141 text.setScreenCoords(center + Vec2f(0f, (text.size.y - size.y) / 2f)); 142 } 143 144 override void draw() { 145 if (!_isRendered) 146 return; 147 drawFilledRect(origin, size, Color.white * .11f); 148 text.draw(); 149 } 150 }