1//============================================================================
2//
3// SSSS tt lll lll
4// SS SS tt ll ll
5// SS tttttt eeee ll ll aaaa
6// SSSS tt ee ee ll ll aa
7// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
8// SS SS tt ee ll ll aa aa
9// SSSS ttt eeeee llll llll aaaaa
10//
11// Copyright (c) 1995-2019 by Bradford W. Mott, Stephen Anthony
12// and the Stella Team
13//
14// See the file "License.txt" for information on usage and redistribution of
15// this file, and for a DISCLAIMER OF ALL WARRANTIES.
16//============================================================================
17
18#include "OSystem.hxx"
19#include "Dialog.hxx"
20#include "FBSurface.hxx"
21#include "ScrollBarWidget.hxx"
22#include "bspf.hxx"
23
24/*
25 * TODO:
26 * - Allow for a horizontal scrollbar, too?
27 * - If there are less items than fit on one pages, no scrolling can be done
28 * and we thus should not highlight the arrows/slider.
29 */
30
31#define UP_DOWN_BOX_HEIGHT 18
32
33// Up arrow
34static uInt32 up_arrow[8] = {
35 0b00000000,
36 0b00010000,
37 0b00111000,
38 0b01111100,
39 0b11101110,
40 0b11000110,
41 0b10000010,
42 0b00000000
43};
44
45// Down arrow
46static uInt32 down_arrow[8] = {
47 0b00000000,
48 0b10000010,
49 0b11000110,
50 0b11101110,
51 0b01111100,
52 0b00111000,
53 0b00010000,
54 0b00000000
55};
56
57// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
58ScrollBarWidget::ScrollBarWidget(GuiObject* boss, const GUI::Font& font,
59 int x, int y, int w, int h)
60 : Widget(boss, font, x, y, w, h), CommandSender(boss),
61 _numEntries(0),
62 _entriesPerPage(0),
63 _currentPos(0),
64 _wheel_lines(0),
65 _part(kNoPart),
66 _draggingPart(kNoPart),
67 _sliderHeight(0),
68 _sliderPos(0),
69 _sliderDeltaMouseDownPos(0)
70{
71 _flags = Widget::FLAG_ENABLED | Widget::FLAG_TRACK_MOUSE | Widget::FLAG_CLEARBG;
72 _bgcolor = kWidColor;
73 _bgcolorhi = kWidColor;
74}
75
76// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
77void ScrollBarWidget::handleMouseDown(int x, int y, MouseButton b,
78 int clickCount)
79{
80 // Ignore subsequent mouse clicks when the slider is being moved
81 if(_draggingPart == kSliderPart)
82 return;
83
84 int old_pos = _currentPos;
85
86 // Do nothing if there are less items than fit on one page
87 if(_numEntries <= _entriesPerPage)
88 return;
89
90 if (y <= UP_DOWN_BOX_HEIGHT)
91 {
92 // Up arrow
93 _currentPos--;
94 _draggingPart = kUpArrowPart;
95 }
96 else if(y >= _h - UP_DOWN_BOX_HEIGHT)
97 {
98 // Down arrow
99 _currentPos++;
100 _draggingPart = kDownArrowPart;
101 }
102 else if(y < _sliderPos)
103 {
104 _currentPos -= _entriesPerPage - 1;
105 }
106 else if(y >= _sliderPos + _sliderHeight)
107 {
108 _currentPos += _entriesPerPage - 1;
109 }
110 else
111 {
112 _draggingPart = kSliderPart;
113 _sliderDeltaMouseDownPos = y - _sliderPos;
114 }
115
116 // Make sure that _currentPos is still inside the bounds
117 checkBounds(old_pos);
118}
119
120// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
121void ScrollBarWidget::handleMouseUp(int x, int y, MouseButton b,
122 int clickCount)
123{
124 _draggingPart = kNoPart;
125}
126
127// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
128void ScrollBarWidget::handleMouseWheel(int x, int y, int direction)
129{
130 int old_pos = _currentPos;
131
132 if(_numEntries < _entriesPerPage)
133 return;
134
135 if(direction < 0)
136 _currentPos -= _wheel_lines ? _wheel_lines : _WHEEL_LINES;
137 else
138 _currentPos += _wheel_lines ? _wheel_lines : _WHEEL_LINES;
139
140 // Make sure that _currentPos is still inside the bounds
141 checkBounds(old_pos);
142}
143
144// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
145void ScrollBarWidget::handleMouseMoved(int x, int y)
146{
147 // Do nothing if there are less items than fit on one page
148 if(_numEntries <= _entriesPerPage)
149 return;
150
151 if(_draggingPart == kSliderPart)
152 {
153 int old_pos = _currentPos;
154 _sliderPos = y - _sliderDeltaMouseDownPos;
155
156 if(_sliderPos < UP_DOWN_BOX_HEIGHT)
157 _sliderPos = UP_DOWN_BOX_HEIGHT;
158
159 if(_sliderPos > _h - UP_DOWN_BOX_HEIGHT - _sliderHeight)
160 _sliderPos = _h - UP_DOWN_BOX_HEIGHT - _sliderHeight;
161
162 _currentPos = (_sliderPos - UP_DOWN_BOX_HEIGHT) * (_numEntries - _entriesPerPage) /
163 (_h - 2 * UP_DOWN_BOX_HEIGHT - _sliderHeight);
164 checkBounds(old_pos);
165 }
166 else
167 {
168 int old_part = _part;
169
170 if(y <= UP_DOWN_BOX_HEIGHT) // Up arrow
171 _part = kUpArrowPart;
172 else if(y >= _h - UP_DOWN_BOX_HEIGHT) // Down arrow
173 _part = kDownArrowPart;
174 else if(y < _sliderPos)
175 _part = kPageUpPart;
176 else if(y >= _sliderPos + _sliderHeight)
177 _part = kPageDownPart;
178 else
179 _part = kSliderPart;
180
181 if (old_part != _part)
182 setDirty();
183 }
184}
185
186// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
187bool ScrollBarWidget::handleMouseClicks(int x, int y, MouseButton b)
188{
189 // Let continuous mouse clicks come through, as the scroll buttons need them
190 return true;
191}
192
193// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
194void ScrollBarWidget::checkBounds(int old_pos)
195{
196 if(_numEntries <= _entriesPerPage || _currentPos < 0)
197 _currentPos = 0;
198 else if(_currentPos > _numEntries - _entriesPerPage)
199 _currentPos = _numEntries - _entriesPerPage;
200
201 if (old_pos != _currentPos)
202 {
203 recalc();
204 sendCommand(GuiObject::kSetPositionCmd, _currentPos, _id);
205 }
206}
207
208// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
209void ScrollBarWidget::handleMouseEntered()
210{
211 setFlags(Widget::FLAG_HILITED);
212 setDirty();
213}
214
215// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
216void ScrollBarWidget::handleMouseLeft()
217{
218 _part = kNoPart;
219 clearFlags(Widget::FLAG_HILITED);
220 setDirty();
221}
222
223// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
224void ScrollBarWidget::recalc()
225{
226//cerr << "ScrollBarWidget::recalc()\n";
227 if(_numEntries > _entriesPerPage)
228 {
229 _sliderHeight = (_h - 2 * UP_DOWN_BOX_HEIGHT) * _entriesPerPage / _numEntries;
230 if(_sliderHeight < UP_DOWN_BOX_HEIGHT)
231 _sliderHeight = UP_DOWN_BOX_HEIGHT;
232
233 _sliderPos = UP_DOWN_BOX_HEIGHT + (_h - 2 * UP_DOWN_BOX_HEIGHT - _sliderHeight) *
234 _currentPos / (_numEntries - _entriesPerPage);
235 if(_sliderPos < 0)
236 _sliderPos = 0;
237 }
238 else
239 {
240 _sliderHeight = _h - 2 * UP_DOWN_BOX_HEIGHT;
241 _sliderPos = UP_DOWN_BOX_HEIGHT;
242 }
243
244 setDirty();
245}
246
247// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
248void ScrollBarWidget::drawWidget(bool hilite)
249{
250//cerr << "ScrollBarWidget::drawWidget\n";
251 FBSurface& s = _boss->dialog().surface();
252 bool onTop = _boss->dialog().isOnTop();
253 int bottomY = _y + _h;
254 bool isSinglePage = (_numEntries <= _entriesPerPage);
255
256 s.frameRect(_x, _y, _w, _h, hilite ? kWidColorHi : kColor);
257
258 if(_draggingPart != kNoPart)
259 _part = _draggingPart;
260
261 // Up arrow
262 if(hilite && _part == kUpArrowPart)
263 s.fillRect(_x + 1, _y + 1, _w - 2, UP_DOWN_BOX_HEIGHT - 2, kScrollColor);
264 s.drawBitmap(up_arrow, _x+4, _y+5,
265 onTop
266 ? isSinglePage ? kColor : (hilite && _part == kUpArrowPart) ? kWidColor : kTextColor
267 : kColor, 8);
268
269 // Down arrow
270 if(hilite && _part == kDownArrowPart)
271 s.fillRect(_x + 1, bottomY - UP_DOWN_BOX_HEIGHT + 1, _w - 2, UP_DOWN_BOX_HEIGHT - 2, kScrollColor);
272 s.drawBitmap(down_arrow, _x+4, bottomY - UP_DOWN_BOX_HEIGHT + 5,
273 onTop
274 ? isSinglePage ? kColor : (hilite && _part == kDownArrowPart) ? kWidColor : kTextColor
275 : kColor, 8);
276
277 // Slider
278 if(!isSinglePage)
279 {
280 s.fillRect(_x + 1, _y + _sliderPos - 1, _w - 2, _sliderHeight + 2,
281 onTop ? (hilite && _part == kSliderPart) ? kScrollColorHi : kScrollColor : kColor);
282 }
283}
284
285// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
286int ScrollBarWidget::_WHEEL_LINES = 4;
287