1-- @docclass
2UIScrollBar = extends(UIWidget, "UIScrollBar")
3
4-- private functions
5local function calcValues(self)
6 local slider = self:getChildById('sliderButton')
7 local decrementButton = self:getChildById('decrementButton')
8 local incrementButton = self:getChildById('incrementButton')
9
10 local pxrange, center
11 if self.orientation == 'vertical' then
12 pxrange = (self:getHeight() - decrementButton:getHeight() - decrementButton:getMarginTop() - decrementButton:getMarginBottom()
13 - incrementButton:getHeight() - incrementButton:getMarginTop() - incrementButton:getMarginBottom())
14 center = self:getY() + math.floor(self:getHeight() / 2)
15 else -- horizontal
16 pxrange = (self:getWidth() - decrementButton:getWidth() - decrementButton:getMarginLeft() - decrementButton:getMarginRight()
17 - incrementButton:getWidth() - incrementButton:getMarginLeft() - incrementButton:getMarginRight())
18 center = self:getX() + math.floor(self:getWidth() / 2)
19 end
20
21 local range = self.maximum - self.minimum + 1
22
23 local proportion
24
25 if self.pixelsScroll then
26 proportion = pxrange/(range+pxrange)
27 else
28 proportion = math.min(math.max(self.step, 1), range)/range
29 end
30
31 local px = math.max(proportion * pxrange, 6)
32 if g_app.isMobile() then
33 px = math.max(proportion * pxrange, 24)
34 end
35 px = px - px % 2 + 1
36
37 local offset = 0
38 if range == 0 or self.value == self.minimum then
39 if self.orientation == 'vertical' then
40 offset = -math.floor((self:getHeight() - px) / 2) + decrementButton:getMarginRect().height
41 else
42 offset = -math.floor((self:getWidth() - px) / 2) + decrementButton:getMarginRect().width
43 end
44 elseif range > 1 and self.value == self.maximum then
45 if self.orientation == 'vertical' then
46 offset = math.ceil((self:getHeight() - px) / 2) - incrementButton:getMarginRect().height
47 else
48 offset = math.ceil((self:getWidth() - px) / 2) - incrementButton:getMarginRect().width
49 end
50 elseif range > 1 then
51 offset = (((self.value - self.minimum) / (range - 1)) - 0.5) * (pxrange - px)
52 end
53
54 return range, pxrange, px, offset, center
55end
56
57local function updateValueDisplay(widget)
58 if widget == nil then return end
59
60 if widget:getShowValue() then
61 widget:setText(widget:getValue() .. (widget:getSymbol() or ''))
62 end
63end
64
65local function updateSlider(self)
66 local slider = self:getChildById('sliderButton')
67 if slider == nil then return end
68
69 local range, pxrange, px, offset, center = calcValues(self)
70 if self.orientation == 'vertical' then
71 slider:setHeight(px)
72 slider:setMarginTop(offset)
73 else -- horizontal
74 slider:setWidth(px)
75 slider:setMarginLeft(offset)
76 end
77 updateValueDisplay(self)
78
79 local status = (self.maximum ~= self.minimum)
80
81 self:setOn(status)
82 for _i,child in pairs(self:getChildren()) do
83 child:setEnabled(status)
84 end
85end
86
87local function parseSliderPos(self, slider, pos, move)
88 local delta, hotDistance
89 if self.orientation == 'vertical' then
90 delta = move.y
91 hotDistance = pos.y - slider:getY()
92 else
93 delta = move.x
94 hotDistance = pos.x - slider:getX()
95 end
96
97 if (delta > 0 and hotDistance + delta > self.hotDistance) or
98 (delta < 0 and hotDistance + delta < self.hotDistance) then
99 local range, pxrange, px, offset, center = calcValues(self)
100 local newvalue = self.value + delta * (range / (pxrange - px))
101 self:setValue(newvalue)
102 end
103end
104
105local function parseSliderPress(self, slider, pos, button)
106 if self.orientation == 'vertical' then
107 self.hotDistance = pos.y - slider:getY()
108 else
109 self.hotDistance = pos.x - slider:getX()
110 end
111end
112
113-- public functions
114function UIScrollBar.create()
115 local scrollbar = UIScrollBar.internalCreate()
116 scrollbar:setFocusable(false)
117 scrollbar.value = 0
118 scrollbar.minimum = -999999
119 scrollbar.maximum = 999999
120 scrollbar.step = 1
121 scrollbar.orientation = 'vertical'
122 scrollbar.pixelsScroll = false
123 scrollbar.showValue = false
124 scrollbar.symbol = nil
125 scrollbar.mouseScroll = true
126 return scrollbar
127end
128
129function UIScrollBar:onSetup()
130 self.setupDone = true
131 local sliderButton = self:getChildById('sliderButton')
132 g_mouse.bindAutoPress(self:getChildById('decrementButton'), function() self:onDecrement() end, 300)
133 g_mouse.bindAutoPress(self:getChildById('incrementButton'), function() self:onIncrement() end, 300)
134 g_mouse.bindPressMove(sliderButton, function(mousePos, mouseMoved) parseSliderPos(self, sliderButton, mousePos, mouseMoved) end)
135 g_mouse.bindPress(sliderButton, function(mousePos, mouseButton) parseSliderPress(self, sliderButton, mousePos, mouseButton) end)
136
137 updateSlider(self)
138end
139
140function UIScrollBar:onStyleApply(styleName, styleNode)
141 for name,value in pairs(styleNode) do
142 if name == 'maximum' then
143 self:setMaximum(tonumber(value))
144 elseif name == 'minimum' then
145 self:setMinimum(tonumber(value))
146 elseif name == 'step' then
147 self:setStep(tonumber(value))
148 elseif name == 'orientation' then
149 self:setOrientation(value)
150 elseif name == 'value' then
151 self:setValue(value)
152 elseif name == 'pixels-scroll' then
153 self.pixelsScroll = true
154 elseif name == 'show-value' then
155 self.showValue = true
156 elseif name == 'symbol' then
157 self.symbol = value
158 elseif name == 'mouse-scroll' then
159 self.mouseScroll = value
160 end
161 end
162end
163
164function UIScrollBar:onDecrement()
165 if g_keyboard.isCtrlPressed() then
166 self:decrement(self.value)
167 elseif g_keyboard.isShiftPressed() then
168 self:decrement(10)
169 else
170 self:decrement()
171 end
172end
173
174function UIScrollBar:onIncrement()
175 if g_keyboard.isCtrlPressed() then
176 self:increment(self.maximum)
177 elseif g_keyboard.isShiftPressed() then
178 self:increment(10)
179 else
180 self:increment()
181 end
182end
183
184function UIScrollBar:decrement(count)
185 count = count or self.step
186 self:setValue(self.value - count)
187end
188
189function UIScrollBar:increment(count)
190 count = count or self.step
191 self:setValue(self.value + count)
192end
193
194function UIScrollBar:setMaximum(maximum)
195 if maximum == self.maximum then return end
196 self.maximum = maximum
197 if self.minimum > maximum then
198 self:setMinimum(maximum)
199 end
200 if self.value > maximum then
201 self:setValue(maximum)
202 else
203 updateSlider(self)
204 end
205end
206
207function UIScrollBar:setMinimum(minimum)
208 if minimum == self.minimum then return end
209 self.minimum = minimum
210 if self.maximum < minimum then
211 self:setMaximum(minimum)
212 end
213 if self.value < minimum then
214 self:setValue(minimum)
215 else
216 updateSlider(self)
217 end
218end
219
220function UIScrollBar:setRange(minimum, maximum)
221 self:setMinimum(minimum)
222 self:setMaximum(maximum)
223end
224
225function UIScrollBar:setValue(value)
226 value = math.max(math.min(value, self.maximum), self.minimum)
227 if self.value == value then return end
228 local delta = value - self.value
229 self.value = value
230 updateSlider(self)
231 if self.setupDone then
232 signalcall(self.onValueChange, self, math.round(value), delta)
233 end
234end
235
236function UIScrollBar:setMouseScroll(scroll)
237 self.mouseScroll = scroll
238end
239
240function UIScrollBar:setStep(step)
241 self.step = step
242end
243
244function UIScrollBar:setOrientation(orientation)
245 self.orientation = orientation
246end
247
248function UIScrollBar:setText(text)
249 local valueLabel = self:getChildById('valueLabel')
250 if valueLabel then
251 valueLabel:setText(text)
252 end
253end
254
255function UIScrollBar:onGeometryChange()
256 updateSlider(self)
257end
258
259function UIScrollBar:onMouseWheel(mousePos, mouseWheel)
260 if not self.mouseScroll or not self:isOn() or self.disableScroll then
261 return false
262 end
263 if mouseWheel == MouseWheelUp then
264 if self.orientation == 'vertical' then
265 if self.value <= self.minimum then return false end
266 self:decrement()
267 else
268 if self.value >= self.maximum then return false end
269 self:increment()
270 end
271 else
272 if self.orientation == 'vertical' then
273 if self.value >= self.maximum then return false end
274 self:increment()
275 else
276 if self.value <= self.minimum then return false end
277 self:decrement()
278 end
279 end
280 return true
281end
282
283function UIScrollBar:getMaximum() return self.maximum end
284function UIScrollBar:getMinimum() return self.minimum end
285function UIScrollBar:getValue() return math.round(self.value) end
286function UIScrollBar:getStep() return self.step end
287function UIScrollBar:getOrientation() return self.orientation end
288function UIScrollBar:getShowValue() return self.showValue end
289function UIScrollBar:getSymbol() return self.symbol end
290function UIScrollBar:getMouseScroll() return self.mouseScroll end
291