1 /*
2 This file is part of Warzone 2100.
3 Copyright (C) 1999-2004 Eidos Interactive
4 Copyright (C) 2005-2020 Warzone 2100 Project
5
6 Warzone 2100 is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 Warzone 2100 is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with Warzone 2100; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20 /** @file
21 * Slide bar widget definitions.
22 */
23
24 #include "widget.h"
25 #include "widgint.h"
26 #include "slider.h"
27 #include "lib/ivis_opengl/pieblitfunc.h"
28
29 static bool DragEnabled = true;
30
31 enum SliderState
32 {
33 // Slider is being dragged
34 SLD_DRAG = 1 << 0,
35
36 // Slider is hilited
37 SLD_HILITE = 1 << 1,
38
39 // Slider is disabled
40 SLD_DISABLED = 1 << 2
41 };
42
sliderEnableDrag(bool Enable)43 void sliderEnableDrag(bool Enable)
44 {
45 DragEnabled = Enable;
46 }
47
W_SLDINIT()48 W_SLDINIT::W_SLDINIT()
49 : orientation(WSLD_LEFT)
50 , numStops(0)
51 , barSize(0)
52 , pos(0)
53 {}
54
W_SLIDER(W_SLDINIT const * init)55 W_SLIDER::W_SLIDER(W_SLDINIT const *init)
56 : WIDGET(init, WIDG_SLIDER)
57 , orientation(init->orientation)
58 , numStops(init->numStops)
59 , barSize(init->barSize)
60 , pos(init->pos)
61 , state(0)
62 , pTip(init->pTip)
63 {
64 ASSERT((init->style & ~(WBAR_PLAIN | WIDG_HIDDEN)) == 0, "Unknown style");
65 ASSERT(init->orientation >= WSLD_LEFT || init->orientation <= WSLD_BOTTOM, "Unknown orientation");
66 bool horizontal = init->orientation == WSLD_LEFT || init->orientation == WSLD_RIGHT;
67 bool vertical = init->orientation == WSLD_TOP || init->orientation == WSLD_BOTTOM;
68 ASSERT((!horizontal || init->numStops <= init->width - init->barSize) &&
69 (!vertical || init->numStops <= init->height - init->barSize), "Too many stops for slider length");
70 ASSERT(init->pos <= init->numStops, "Slider position greater than stops (%d/%d)", init->pos, init->numStops);
71 ASSERT((!horizontal || init->barSize <= init->width) &&
72 (!vertical || init->barSize <= init->height), "Slider bar is larger than slider width");
73 }
74
75 /* Get the current position of a slider bar */
widgGetSliderPos(const std::shared_ptr<W_SCREEN> & psScreen,UDWORD id)76 UDWORD widgGetSliderPos(const std::shared_ptr<W_SCREEN> &psScreen, UDWORD id)
77 {
78 ASSERT_OR_RETURN(0, psScreen != nullptr, "Invalid screen pointer");
79 WIDGET *psWidget;
80
81 psWidget = widgGetFromID(psScreen, id);
82 ASSERT(psWidget != nullptr, "Could not find widget from id %u", id);
83 if (psWidget)
84 {
85 return ((W_SLIDER *)psWidget)->pos;
86 }
87 return 0;
88 }
89
90 /* Run a slider widget */
run(W_CONTEXT * psContext)91 void W_SLIDER::run(W_CONTEXT *psContext)
92 {
93 if ((state & SLD_DRAG) && !mouseDown(MOUSE_LMB))
94 {
95 state &= ~SLD_DRAG;
96 if (auto lockedScreen = screenPointer.lock())
97 {
98 lockedScreen->setReturn(shared_from_this());
99 }
100 dirty = true;
101 }
102 else if (!(state & SLD_DRAG) && mouseDown(MOUSE_LMB))
103 {
104 clicked(psContext, WKEY_NONE);
105 }
106 if (state & SLD_DRAG)
107 {
108 /* Figure out where the drag box should be */
109 int mx = psContext->mx - x();
110 int my = psContext->my - y();
111 int stopSize;
112 switch (orientation)
113 {
114 case WSLD_LEFT:
115 if (mx <= barSize / 2)
116 {
117 pos = 0;
118 }
119 else if (mx >= width() - barSize / 2)
120 {
121 pos = numStops;
122 }
123 else
124 {
125 /* Mouse is in the middle of the slider, calculate which stop */
126 stopSize = (width() - barSize) / numStops;
127 pos = (mx + stopSize / 2 - barSize / 2)
128 * numStops
129 / (width() - barSize);
130 }
131 break;
132 case WSLD_RIGHT:
133 if (mx <= barSize / 2)
134 {
135 pos = numStops;
136 }
137 else if (mx >= width() - barSize / 2)
138 {
139 pos = 0;
140 }
141 else
142 {
143 /* Mouse is in the middle of the slider, calculate which stop */
144 stopSize = (width() - barSize) / numStops;
145 pos = numStops
146 - (mx + stopSize / 2 - barSize / 2)
147 * numStops
148 / (width() - barSize);
149 }
150 break;
151 case WSLD_TOP:
152 if (my <= barSize / 2)
153 {
154 pos = 0;
155 }
156 else if (my >= height() - barSize / 2)
157 {
158 pos = numStops;
159 }
160 else
161 {
162 /* Mouse is in the middle of the slider, calculate which stop */
163 stopSize = (height() - barSize) / numStops;
164 pos = (my + stopSize / 2 - barSize / 2)
165 * numStops
166 / (height() - barSize);
167 }
168 break;
169 case WSLD_BOTTOM:
170 if (my <= barSize / 2)
171 {
172 pos = numStops;
173 }
174 else if (my >= height() - barSize / 2)
175 {
176 pos = 0;
177 }
178 else
179 {
180 /* Mouse is in the middle of the slider, calculate which stop */
181 stopSize = (height() - barSize) / numStops;
182 pos = numStops
183 - (my + stopSize / 2 - barSize / 2)
184 * numStops
185 / (height() - barSize);
186 }
187 break;
188 }
189 }
190 }
191
clicked(W_CONTEXT * psContext,WIDGET_KEY)192 void W_SLIDER::clicked(W_CONTEXT *psContext, WIDGET_KEY)
193 {
194 if (isEnabled() && DragEnabled && geometry().contains(psContext->mx, psContext->my))
195 {
196 dirty = true;
197 state |= SLD_DRAG;
198 }
199 }
200
highlight(W_CONTEXT *)201 void W_SLIDER::highlight(W_CONTEXT *)
202 {
203 state |= SLD_HILITE;
204 dirty = true;
205 }
206
207
208 /* Respond to the mouse moving off a slider */
highlightLost()209 void W_SLIDER::highlightLost()
210 {
211 state &= ~SLD_HILITE;
212 dirty = true;
213 }
214
setTip(std::string string)215 void W_SLIDER::setTip(std::string string)
216 {
217 pTip = string;
218 }
219
display(int xOffset,int yOffset)220 void W_SLIDER::display(int xOffset, int yOffset)
221 {
222 ASSERT(false, "No default implementation exists for sliders");
223 }
224
enable()225 void W_SLIDER::enable()
226 {
227 state &= ~SLD_DISABLED;
228 }
229
disable()230 void W_SLIDER::disable()
231 {
232 state |= SLD_DISABLED;
233 }
234
isHighlighted() const235 bool W_SLIDER::isHighlighted() const
236 {
237 return (state & SLD_HILITE) != 0;
238 }
239
isEnabled() const240 bool W_SLIDER::isEnabled() const
241 {
242 return (state & SLD_DISABLED) == 0;
243 }
244