1 ///A collection of immediate-mode UI widgets
2 module dgt.ui;
3 
4 import dgt.geom : Rectangle, Vector;
5 import dgt.texture : Texture;
6 import dgt.window : Window;
7 
8 ///A clickable button
9 struct Button
10 {
11     @disable this();
12 
13     public @nogc nothrow:
14 
15     Rectangle area;
16     Vector position;
17     Texture tex, hover, press;
18 
19     /**
20     Defines a button
21 
22     Params:
23     area = The clickable region of the button
24     position = The spot to draw the button
25     tex = The default texture of the button
26     hover = The texture when the button is hovered over
27     press = The texture when the button is pressed down
28     */
29     this(in Rectangle area, in Vector position, in Texture tex, in Texture hover, in Texture press)
30     {
31         this.area = area;
32         this.position = position;
33         this.tex = tex;
34         this.hover = hover;
35         this.press = press;
36     }
37 
38     ///Draw a button and return if it is pressed
39     bool draw(ref scope Window window) const
40     {
41         bool mouseContained = area.contains(window.mouse);
42         window.draw(mouseContained ? (window.mouseLeftPressed ? press : hover) : tex,
43                 position.x, position.y);
44         return mouseContained && window.mouseLeftReleased;
45     }
46 }
47 
48 ///A slider that can be moved along a horizontal axis
49 struct Slider
50 {
51     public @nogc nothrow:
52     Rectangle area;
53     Texture slider;
54 
55     @disable this();
56 
57     /**
58     Create a slider
59 
60     Params:
61     area = The region the slider can move around in
62     sliderHead = The image to draw where the slider is currently pointing
63     */
64     this(in Rectangle area, in Texture sliderHead)
65     {
66         this.area = area;
67         this.slider = sliderHead;
68     }
69 
70     ///Draw a slider with a given normalized value and return its new value
71     float draw(ref scope Window window, in float current) const
72     {
73         window.draw(slider, -slider.size.width / 2 + area.x + current * area.width,
74                 -slider.size.height / 2 + area.y + area.height / 2);
75         if (window.mouseLeftPressed && area.contains(window.mouse))
76             return (window.mouse.x - area.x) / cast(float)(area.width);
77         else
78             return current;
79     }
80 
81 }
82 
83 ///A rotating selection of options
84 struct Carousel
85 {
86     @disable this();
87     public @nogc nothrow:
88     Button left, right;
89     Vector position;
90     const(Texture[]) textures;
91 
92     ///Create a carousel with a given set of options 
93     this(in Button left, in Button right, in Vector currentItemPosition, in Texture[] textures)
94     {
95         this.left = left;
96         this.right = right;
97         this.position = currentItemPosition;
98         this.textures = textures;
99     }
100 
101     ///Draw a carousel with a given current index and return the new index
102     int draw(ref scope Window window, in int current) const
103     {
104         int next = current;
105         if (left.draw(window))
106             next --;
107         if (right.draw(window))
108             next ++;
109         next = cast(int)((next + textures.length) % textures.length);
110         window.draw(textures[next], position.x, position.y);
111         return next;
112     }
113 }