1 /*
2 scroll.cc Scroll Bar
3 Copyright (c) 1997-8,2000,2002,2004,2007 Kriang Lerdsuwanakij
4 email: lerdsuwa@users.sourceforge.net
5
6 This program 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 This program 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 this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "scroll.h"
22 #include "strmisc.h"
23
24 /*************************************************************************
25 Scroll bar base class
26 *************************************************************************/
27
CalcSize()28 void ScrollBarBase::CalcSize()
29 {
30 // Min value = 0 when curPos = 0,
31 // No max limit (to be recalc
32 // in the if block below.)
33 beforeThumb = (curPos*barSize+totalSize/2)/totalSize;
34 // Min value = 1, max = barSize
35 thumb = Min(Max((visualSize*barSize+totalSize/2)/totalSize, 1),
36 barSize);
37 afterThumb = barSize-beforeThumb-thumb;
38
39 if (afterThumb < 0) {
40 afterThumb = 0;
41 beforeThumb = barSize-thumb;
42 }
43 }
44
ScrollBarBase(NCScreenManager & scrnMan_,int id_)45 ScrollBarBase::ScrollBarBase(NCScreenManager &scrnMan_, int id_)
46 : NCWindowBase(scrnMan_, id_)
47 {
48 controlledWin = NULL;
49 lastScrollDirection = 0;
50 lastScrollPosition = 0;
51
52 barSize = visualSize = totalSize = 1;
53 curPos = 0;
54 CalcSize();
55 }
56
SetVisualSize(int visualSize_)57 void ScrollBarBase::SetVisualSize(int visualSize_)
58 {
59 visualSize = visualSize_;
60 if (visualSize > totalSize)
61 totalSize = visualSize;
62 CalcSize();
63 DrawScrollBar();
64 }
65
SetTotalSize(int totalSize_)66 void ScrollBarBase::SetTotalSize(int totalSize_)
67 {
68 totalSize = totalSize_;
69 if (totalSize < visualSize)
70 visualSize = totalSize;
71 CalcSize();
72 DrawScrollBar();
73 }
74
SetPosition(int curPos_)75 void ScrollBarBase::SetPosition(int curPos_)
76 {
77 curPos = curPos_;
78 if (curPos < 0) // Position beyond lower limit
79 curPos = 0;
80 // Position beyond upper limit
81 else if (curPos > totalSize-visualSize)
82 curPos = totalSize-visualSize;
83 CalcSize();
84 DrawScrollBar();
85 }
86
87 /*************************************************************************
88 Scroll bar with left/right or up/down arrows at the ends
89 of the bar
90 *************************************************************************/
91
92 extern entity_id scrollBarID, scrollBlockID;
93 extern attr_t scrollArrowA, scrollBarA, scrollBlockA;
94
Init()95 void HScrollBar::Init()
96 {
97 NCWindowBase::Init();
98
99 if (GetRow() && GetCol()) {
100 win = newwin(GetRow(), GetCol(), GetY(), GetX());
101 if (win == NULL) { // Error
102 throw bad_alloc();
103 }
104 }
105 else
106 win = NULL;
107
108 barSize = GetCol()-2;
109 CalcSize();
110
111 DrawScrollBar();
112 }
113
DrawScrollBar()114 void HScrollBar::DrawScrollBar()
115 {
116 int i;
117
118 if (!win)
119 return;
120
121 wmove(win, 0, 0);
122 wattrset(win, scrollArrowA);
123 draw_entity(win, EID_LARR);
124
125 wattrset(win, scrollBarA);
126 for (i = 0; i < BeforeThumb(); i++)
127 draw_entity(win, scrollBarID);
128
129 wattrset(win, scrollBlockA);
130 for (i = 0; i < Thumb(); i++)
131 draw_entity(win, scrollBlockID);
132
133 wattrset(win, scrollBarA);
134 for (i = 0; i < AfterThumb(); i++)
135 draw_entity(win, scrollBarID);
136
137 wattrset(win, scrollArrowA);
138 draw_entity(win, EID_RARR);
139 wnoutrefresh(win);
140 }
141
DoResize()142 void HScrollBar::DoResize()
143 {
144 if (win)
145 delwin(win);
146 win = NULL;
147 Init();
148 }
149
DoUpdate()150 void HScrollBar::DoUpdate()
151 {
152 if (win)
153 wnoutrefresh(win);
154 }
155
HScrollBar(NCScreenManager & scrnMan_,int id_)156 HScrollBar::HScrollBar(NCScreenManager &scrnMan_, int id_)
157 : ScrollBarBase(scrnMan_, id_)
158 {
159 }
160
Init()161 void VScrollBar::Init()
162 {
163 NCWindowBase::Init();
164
165 if (GetRow() && GetCol()) {
166 win = newwin(GetRow(), GetCol(), GetY(), GetX());
167 if (win == NULL) { // Error
168 throw bad_alloc();
169 }
170 }
171 else
172 win = NULL;
173
174 barSize = GetRow()-2;
175 CalcSize();
176
177 DrawScrollBar();
178 }
179
DrawScrollBar()180 void VScrollBar::DrawScrollBar()
181 {
182 int i;
183 int j = 0;
184
185 if (!win)
186 return;
187
188 wmove(win, 0, 0);
189 wattrset(win, scrollArrowA);
190 draw_entity(win, EID_UARR);
191 j++;
192
193 wattrset(win, scrollBarA);
194 for (i = 0; i < BeforeThumb(); i++) {
195 wmove(win, j, 0);
196 draw_entity(win, scrollBarID);
197 j++;
198 }
199
200 wattrset(win, scrollBlockA);
201 for (i = 0; i < Thumb(); i++) {
202 wmove(win, j, 0);
203 draw_entity(win, scrollBlockID);
204 j++;
205 }
206
207 wattrset(win, scrollBarA);
208 for (i = 0; i < AfterThumb(); i++) {
209 wmove(win, j, 0);
210 draw_entity(win, scrollBarID);
211 j++;
212 }
213
214 wmove(win, j, 0);
215 wattrset(win, scrollArrowA);
216 draw_entity(win, EID_DARR);
217 wnoutrefresh(win);
218 }
219
DoResize()220 void VScrollBar::DoResize()
221 {
222 if (win)
223 delwin(win);
224 win = NULL;
225 Init();
226 }
227
DoUpdate()228 void VScrollBar::DoUpdate()
229 {
230 if (win)
231 wnoutrefresh(win);
232 }
233
VScrollBar(NCScreenManager & scrnMan_,int id_)234 VScrollBar::VScrollBar(NCScreenManager &scrnMan_, int id_)
235 : ScrollBarBase(scrnMan_, id_)
236 {
237 }
238
239 /*************************************************************************
240 Our own scroll bar
241 *************************************************************************/
242
243 #ifdef NCURSES_MOUSE_VERSION
ProcessMouse(MEVENT & event)244 void khHScrollBar::ProcessMouse(MEVENT &event)
245 {
246 if (!win) // Window hiden
247 return;
248
249 // Only accepts mouse button 1
250 if (!(event.bstate & (BUTTON1_CLICKED | BUTTON1_DOUBLE_CLICKED
251 | BUTTON1_TRIPLE_CLICKED | BUTTON1_PRESSED)))
252 return;
253
254 if (event.bstate & BUTTON1_TRIPLE_CLICKED) {
255 // Convert triple click to 3 separate clicks.
256 event.bstate ^= BUTTON1_TRIPLE_CLICKED;
257 event.bstate |= BUTTON1_CLICKED;
258 ProcessMouse(event);
259 scrnMan.RequestUpdate();
260 ProcessMouse(event);
261 scrnMan.RequestUpdate();
262 ProcessMouse(event);
263 scrnMan.RequestUpdate();
264 return;
265 }
266 if (event.bstate & BUTTON1_DOUBLE_CLICKED) {
267 // Convert double click to 2 separate clicks.
268 event.bstate ^= BUTTON1_DOUBLE_CLICKED;
269 event.bstate |= BUTTON1_CLICKED;
270 ProcessMouse(event);
271 scrnMan.RequestUpdate();
272 ProcessMouse(event);
273 scrnMan.RequestUpdate();
274 return;
275 }
276
277 if (controlledWin) {
278 if (event.x == GetX1()) {
279 controlledWin->ProcessKey(KEY_SLEFT);
280 lastScrollDirection = 0;
281 }
282 else if (event.x == GetX2()) {
283 controlledWin->ProcessKey(KEY_SRIGHT);
284 lastScrollDirection = 0;
285 }
286 else {
287 if (event.x < GetX1()+1+BeforeThumb()) {
288 controlledWin->ProcessKey(KEY_SLEFT);
289 lastScrollPosition = event.x;
290 lastScrollDirection = -1;
291 }
292 else if (event.x >= GetX1()+1+BeforeThumb()+Thumb()) {
293 controlledWin->ProcessKey(KEY_SRIGHT);
294 lastScrollPosition = event.x;
295 lastScrollDirection = 1;
296 }
297 else if (lastScrollPosition == event.x) {
298 if (lastScrollDirection == -1) {
299 controlledWin->ProcessKey(KEY_SLEFT);
300 }
301 else if (lastScrollDirection == 1) {
302 controlledWin->ProcessKey(KEY_SRIGHT);
303 }
304 }
305 }
306 }
307 }
308 #endif
309
khHScrollBar(NCScreenManager & scrnMan_,int id_)310 khHScrollBar::khHScrollBar(NCScreenManager &scrnMan_, int id_)
311 : HScrollBar(scrnMan_, id_)
312 {
313 Init();
314 }
315
316 #ifdef NCURSES_MOUSE_VERSION
ProcessMouse(MEVENT & event)317 void khVScrollBar::ProcessMouse(MEVENT &event)
318 {
319 if (!win) // Window hiden
320 return;
321
322 // Only accepts mouse button 1
323 if (!(event.bstate & (BUTTON1_CLICKED | BUTTON1_DOUBLE_CLICKED
324 | BUTTON1_TRIPLE_CLICKED | BUTTON1_PRESSED)))
325 return;
326
327 if (event.bstate & BUTTON1_TRIPLE_CLICKED) {
328 // Convert triple click to 3 separate clicks.
329 event.bstate ^= BUTTON1_TRIPLE_CLICKED;
330 event.bstate |= BUTTON1_CLICKED;
331 ProcessMouse(event);
332 scrnMan.RequestUpdate();
333 ProcessMouse(event);
334 scrnMan.RequestUpdate();
335 ProcessMouse(event);
336 scrnMan.RequestUpdate();
337 return;
338 }
339 if (event.bstate & BUTTON1_DOUBLE_CLICKED) {
340 // Convert double click to 2 separate clicks.
341 event.bstate ^= BUTTON1_DOUBLE_CLICKED;
342 event.bstate |= BUTTON1_CLICKED;
343 ProcessMouse(event);
344 scrnMan.RequestUpdate();
345 ProcessMouse(event);
346 scrnMan.RequestUpdate();
347 return;
348 }
349
350 if (controlledWin) {
351 if (event.y == GetY1()) { // Scroll reverse
352 controlledWin->ProcessKey(KEY_SR);
353 lastScrollDirection = 0;
354 }
355 else if (event.y == GetY2()) { // Scroll forward
356 controlledWin->ProcessKey(KEY_SF);
357 lastScrollDirection = 0;
358 }
359 else {
360 if (event.y < GetY1()+1+BeforeThumb()) {
361 controlledWin->ProcessKey(KEY_PPAGE);
362 lastScrollPosition = event.y;
363 lastScrollDirection = -1;
364 }
365 else if (event.y >= GetY1()+1+BeforeThumb()+Thumb()) {
366 controlledWin->ProcessKey(KEY_NPAGE);
367 lastScrollPosition = event.y;
368 lastScrollDirection = 1;
369 }
370 else if (lastScrollPosition == event.y) {
371 if (lastScrollDirection == -1) {
372 controlledWin->ProcessKey(KEY_PPAGE);
373 }
374 else if (lastScrollDirection == 1) {
375 controlledWin->ProcessKey(KEY_NPAGE);
376 }
377 }
378 }
379 }
380 }
381 #endif
382
khVScrollBar(NCScreenManager & scrnMan_,int id_)383 khVScrollBar::khVScrollBar(NCScreenManager &scrnMan_, int id_)
384 : VScrollBar(scrnMan_, id_)
385 {
386 Init();
387 }
388
389 /*************************************************************************
390 Our tiny box between horizontal and vertical scroll bar
391 *************************************************************************/
392
Init()393 void khScrollBox::Init()
394 {
395 NCWindowBase::Init();
396
397 if (GetRow() && GetCol()) {
398 win = newwin(GetRow(), GetCol(), GetY(), GetX());
399 if (win == NULL) { // Error
400 throw bad_alloc();
401 }
402 }
403 else
404 win = NULL;
405
406 NCurses::InitMore(win); // Set keyboard mode
407 // Required since this is the
408 // only window that stays
409 // permanently even when screen
410 // size changes
411
412 DrawBox();
413 }
414
DrawBox()415 void khScrollBox::DrawBox()
416 {
417 if (win) {
418 wattrset(win, scrollArrowA);
419 waddch(win, ' ');
420 }
421 }
422
DoResize()423 void khScrollBox::DoResize()
424 {
425 InitGeometry(); // Compute new location
426 if (win)
427 mvwin(win, GetY(), GetX()); // Move there
428 }
429
DoUpdate()430 void khScrollBox::DoUpdate()
431 {
432 if (win)
433 wnoutrefresh(win);
434 }
435
DoRestCursor()436 void khScrollBox::DoRestCursor()
437 {
438 if (win) {
439 wmove(win, 0, 0);
440 wnoutrefresh(win);
441 }
442 }
443
khScrollBox(NCScreenManager & scrnMan_,int id_)444 khScrollBox::khScrollBox(NCScreenManager &scrnMan_, int id_)
445 : NCWindowBase(scrnMan_, id_)
446 {
447 Init();
448 }
449
450