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