1 #include "rxvtlib.h"
2
3 /*--------------------------------*-C-*---------------------------------*
4 * File: scrollbar.c
5 *----------------------------------------------------------------------*
6 * $Id: scrollbar.c,v 1.19.2.1 1999/07/17 09:47:26 mason Exp $
7 *
8 * Copyright (C) 1997,1998 mj olesen <olesen@me.QueensU.CA>
9 * Copyright (C) 1998 Alfredo K. Kojima <kojima@windowmaker.org>
10 * - N*XTstep like scrollbars
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *----------------------------------------------------------------------*/
26
27 /*----------------------------------------------------------------------*
28 */
29 #ifndef NEXT_SCROLLBAR
30
31 #ifdef XTERM_SCROLLBAR /* bitmap scrollbar */
32
33 /* 12x2 bitmap */
34
35 #if (SB_WIDTH != 15)
36 #error Error, check scrollbar width (SB_WIDTH).It must be 15 for XTERM_SCROLLBAR
37 #endif
38
39 #else /* XTERM_SCROLLBAR */
40
41 /* draw triangular button with a shadow of SHADOW (1 or 2) pixels */
42 /* INTPROTO */
rxvtlib_Draw_button(rxvtlib * o,int x,int y,int state,int dirn)43 void rxvtlib_Draw_button (rxvtlib *o, int x, int y, int state, int dirn)
44 {
45 const unsigned int sz = (SB_WIDTH), sz2 = (SB_WIDTH / 2);
46 XPoint pt[3];
47 GC top, bot;
48
49 switch (state) {
50 case +1:
51 top = o->topShadowGC;
52 bot = o->botShadowGC;
53 break;
54 case -1:
55 top = o->botShadowGC;
56 bot = o->topShadowGC;
57 break;
58 default:
59 top = bot = o->scrollbarGC;
60 break;
61 }
62
63 /* fill triangle */
64 pt[0].x = x;
65 pt[1].x = x + sz - 1;
66 pt[2].x = x + sz2;
67 if (dirn == UP) {
68 pt[0].y = pt[1].y = y + sz - 1;
69 pt[2].y = y;
70 } else {
71 pt[0].y = pt[1].y = y;
72 pt[2].y = y + sz - 1;
73 }
74 XFillPolygon (o->Xdisplay, o->scrollBar.win, o->scrollbarGC,
75 pt, 3, Convex, CoordModeOrigin);
76
77 /* draw base */
78 XDrawLine (o->Xdisplay, o->scrollBar.win, (dirn == UP ? bot : top),
79 pt[0].x, pt[0].y, pt[1].x, pt[1].y);
80
81 /* draw shadow on left */
82 pt[1].x = x + sz2 - 1;
83 pt[1].y = y + (dirn == UP ? 0 : sz - 1);
84 XDrawLine (o->Xdisplay, o->scrollBar.win, top,
85 pt[0].x, pt[0].y, pt[1].x, pt[1].y);
86
87 #if (SHADOW > 1)
88 /* doubled */
89 pt[0].x++;
90 if (dirn == UP) {
91 pt[0].y--;
92 pt[1].y++;
93 } else {
94 pt[0].y++;
95 pt[1].y--;
96 }
97 XDrawLine (o->Xdisplay, o->scrollBar.win, top,
98 pt[0].x, pt[0].y, pt[1].x, pt[1].y);
99 #endif
100 /* draw shadow on right */
101 pt[1].x = x + sz - 1;
102 /* pt[2].x = x + sz2; */
103 pt[1].y = y + (dirn == UP ? sz - 1 : 0);
104 pt[2].y = y + (dirn == UP ? 0 : sz - 1);
105 XDrawLine (o->Xdisplay, o->scrollBar.win, bot,
106 pt[2].x, pt[2].y, pt[1].x, pt[1].y);
107 #if (SHADOW > 1)
108 /* doubled */
109 pt[1].x--;
110 if (dirn == UP) {
111 pt[2].y++;
112 pt[1].y--;
113 } else {
114 pt[2].y--;
115 pt[1].y++;
116 }
117 XDrawLine (o->Xdisplay, o->scrollBar.win, bot,
118 pt[2].x, pt[2].y, pt[1].x, pt[1].y);
119 #endif
120 }
121 #endif /* ! XTERM_SCROLLBAR */
122
123 #else /* ! NEXT_SCROLLBAR */
124 /*
125 * N*XTSTEP like scrollbar - written by Alfredo K. Kojima
126 */
127
128 /* INTPROTO */
rxvtlib_renderPixmap(rxvtlib * o,char ** data,int width,int height)129 Pixmap rxvtlib_renderPixmap (rxvtlib *o, char **data, int width, int height)
130 {
131 int x, y;
132 Pixmap d;
133
134 d = XCreatePixmap (o->Xdisplay, o->scrollBar.win, width, height, o->Xdepth);
135
136 for (y = 0; y < height; y++) {
137 for (x = 0; x < width; x++) {
138 switch (data[y][x]) {
139 case ' ':
140 case 'w':
141 XDrawPoint (o->Xdisplay, d, o->whiteGC, x, y);
142 break;
143 case '.':
144 case 'l':
145 XDrawPoint (o->Xdisplay, d, o->grayGC, x, y);
146 break;
147 case '%':
148 case 'd':
149 XDrawPoint (o->Xdisplay, d, o->darkGC, x, y);
150 break;
151 case '#':
152 case 'b':
153 default:
154 XDrawPoint (o->Xdisplay, d, o->blackGC, x, y);
155 break;
156 }
157 }
158 }
159 return d;
160 }
161
162 /* INTPROTO */
rxvtlib_init_scrollbar_stuff(rxvtlib * o)163 void rxvtlib_init_scrollbar_stuff (rxvtlib *o)
164 {
165 XGCValues gcvalue;
166 XColor xcol;
167 Pixmap stipple;
168 unsigned long light, dark;
169
170 gcvalue.graphics_exposures = False;
171
172 gcvalue.foreground =
173 BlackPixelOfScreen (DefaultScreenOfDisplay (o->Xdisplay));
174 o->blackGC =
175 XCreateGC (o->Xdisplay, o->scrollBar.win, GCForeground | GCGraphicsExposures,
176 &gcvalue);
177
178 gcvalue.foreground =
179 WhitePixelOfScreen (DefaultScreenOfDisplay (o->Xdisplay));
180 o->whiteGC =
181 XCreateGC (o->Xdisplay, o->scrollBar.win, GCForeground | GCGraphicsExposures,
182 &gcvalue);
183
184 xcol.red = 0xaeba;
185 xcol.green = 0xaaaa;
186 xcol.blue = 0xaeba;
187 if (!XAllocColor (o->Xdisplay, o->Xcmap, &xcol)) {
188 print_error ("can't allocate %s", "light gray");
189 xcol.pixel = o->PixColors[Color_AntiqueWhite];
190 }
191 light = gcvalue.foreground = xcol.pixel;
192 o->grayGC =
193 XCreateGC (o->Xdisplay, o->scrollBar.win, GCForeground | GCGraphicsExposures,
194 &gcvalue);
195
196 xcol.red = 0x51aa;
197 xcol.green = 0x5555;
198 xcol.blue = 0x5144;
199 if (!XAllocColor (o->Xdisplay, o->Xcmap, &xcol)) {
200 print_error ("can't allocate %s", "dark gray");
201 xcol.pixel = o->PixColors[Color_Grey25];
202 }
203 dark = gcvalue.foreground = xcol.pixel;
204 o->darkGC =
205 XCreateGC (o->Xdisplay, o->scrollBar.win, GCForeground | GCGraphicsExposures,
206 &gcvalue);
207
208 stipple = XCreateBitmapFromData (o->Xdisplay, o->scrollBar.win,
209 (char *) o->stp_bits, stp_width, stp_height);
210
211 gcvalue.foreground = dark;
212 gcvalue.background = light;
213 gcvalue.fill_style = FillStippled;
214 gcvalue.stipple = stipple;
215
216 /* XSetWindowBackground(Xdisplay, scrollBar.win, PixColors[Color_Red]); */
217
218 o->stippleGC = XCreateGC (o->Xdisplay, o->scrollBar.win, GCForeground | GCBackground
219 | GCStipple | GCFillStyle | GCGraphicsExposures,
220 &gcvalue);
221
222 o->dimple = rxvtlib_renderPixmap (o, o->SCROLLER_DIMPLE, SCROLLER_DIMPLE_WIDTH,
223 SCROLLER_DIMPLE_HEIGHT);
224
225 o->upArrow = rxvtlib_renderPixmap (o, o->SCROLLER_ARROW_UP, ARROW_WIDTH, ARROW_HEIGHT);
226 o->downArrow = rxvtlib_renderPixmap (o, o->SCROLLER_ARROW_DOWN, ARROW_WIDTH, ARROW_HEIGHT);
227 o->upArrowHi = rxvtlib_renderPixmap (o, o->HI_SCROLLER_ARROW_UP, ARROW_WIDTH, ARROW_HEIGHT);
228 o->downArrowHi =
229 rxvtlib_renderPixmap (o, o->HI_SCROLLER_ARROW_DOWN, ARROW_WIDTH, ARROW_HEIGHT);
230
231 rxvtlib_scrollbar_show (o, 1);
232 }
233
234 /* Draw bevel & arrows */
235 /* INTPROTO */
rxvtlib_drawBevel(rxvtlib * o,Drawable d,int x,int y,int w,int h)236 void rxvtlib_drawBevel (rxvtlib *o, Drawable d, int x, int y, int w, int h)
237 {
238 XDrawLine (o->Xdisplay, d, o->whiteGC, x, y, x + w - 1, y);
239 XDrawLine (o->Xdisplay, d, o->whiteGC, x, y, x, y + h - 1);
240
241 XDrawLine (o->Xdisplay, d, o->blackGC, x + w - 1, y, x + w - 1, y + h - 1);
242 XDrawLine (o->Xdisplay, d, o->blackGC, x, y + h - 1, x + w - 1, y + h - 1);
243
244 XDrawLine (o->Xdisplay, d, o->darkGC, x + 1, y + h - 2, x + w - 2, y + h - 2);
245 XDrawLine (o->Xdisplay, d, o->darkGC, x + w - 2, y + 1, x + w - 2, y + h - 2);
246 }
247
248 #endif /* ! NEXT_SCROLLBAR */
249
250 /* EXTPROTO */
rxvtlib_scrollbar_show(rxvtlib * o,int update)251 int rxvtlib_scrollbar_show (rxvtlib *o, int update)
252 {
253 static int scrollbar_len; /* length of slider */
254 static int last_top, last_bot, last_state;
255 #ifndef NEXT_SCROLLBAR
256 static short sb_width; /* old (drawn) values */
257 int xsb = 0;
258
259 if (!scrollbar_visible ())
260 return 0;
261
262 if (o->scrollbarGC == None) {
263 XGCValues gcvalue;
264
265 #ifdef XTERM_SCROLLBAR
266 sb_width = SB_WIDTH - 1;
267 gcvalue.stipple = XCreateBitmapFromData (o->Xdisplay, o->scrollBar.win,
268 o->sb_bits, 12, 2);
269 if (!gcvalue.stipple) {
270 print_error ("can't create bitmap");
271 o->killed = EXIT_FAILURE | DO_EXIT;
272 return 0;
273 }
274 gcvalue.fill_style = FillOpaqueStippled;
275 gcvalue.foreground = o->PixColors[Color_fg];
276 gcvalue.background = o->PixColors[Color_bg];
277
278 o->scrollbarGC = XCreateGC (o->Xdisplay, o->scrollBar.win,
279 GCForeground | GCBackground |
280 GCFillStyle | GCStipple, &gcvalue);
281 gcvalue.foreground = o->PixColors[Color_border];
282 o->ShadowGC = XCreateGC (o->Xdisplay, o->scrollBar.win, GCForeground, &gcvalue);
283 #else /* XTERM_SCROLLBAR */
284 sb_width = SB_WIDTH;
285
286 gcvalue.foreground = o->PixColors[Color_trough];
287 if (o->sb_shadow) {
288 XSetWindowBackground (o->Xdisplay, o->scrollBar.win, gcvalue.foreground);
289 XClearWindow (o->Xdisplay, o->scrollBar.win);
290 }
291 gcvalue.foreground = (o->Xdepth <= 2 ? o->PixColors[Color_fg]
292 : o->PixColors[Color_scroll]);
293 o->scrollbarGC = XCreateGC (o->Xdisplay, o->scrollBar.win, GCForeground,
294 &gcvalue);
295
296 gcvalue.foreground = o->PixColors[Color_topShadow];
297 o->topShadowGC = XCreateGC (o->Xdisplay, o->scrollBar.win,
298 GCForeground, &gcvalue);
299
300 gcvalue.foreground = o->PixColors[Color_bottomShadow];
301 o->botShadowGC = XCreateGC (o->Xdisplay, o->scrollBar.win,
302 GCForeground, &gcvalue);
303 #endif /* XTERM_SCROLLBAR */
304 }
305 if (update) {
306 int top = (o->TermWin.nscrolled - o->TermWin.view_start);
307 int bot = top + (o->TermWin.nrow - 1);
308 int len =
309
310 max ((o->TermWin.nscrolled + (o->TermWin.nrow - 1)), 1);
311 int adj = ((bot - top) * scrollbar_size()) % len;
312
313 o->scrollBar.top = (o->scrollBar.beg + (top * scrollbar_size ()) / len);
314 scrollbar_len = (((bot - top) * scrollbar_size()) / len +
315 SCROLL_MINHEIGHT + ((adj > 0) ? 1 : 0));
316 o->scrollBar.bot = (o->scrollBar.top + scrollbar_len);
317 /* no change */
318 if ((o->scrollBar.top == last_top) && (o->scrollBar.bot == last_bot)
319 && ((o->scrollBar.state == last_state) || (!scrollbar_isUpDn())))
320 return 0;
321 }
322 /* instead of XClearWindow (Xdisplay, scrollBar.win); */
323 #ifdef XTERM_SCROLLBAR
324 xsb = (o->Options & Opt_scrollBar_right) ? 1 : 0;
325 #endif
326 if (last_top < o->scrollBar.top)
327 XClearArea (o->Xdisplay, o->scrollBar.win,
328 o->sb_shadow + xsb, last_top,
329 sb_width, (o->scrollBar.top - last_top), False);
330
331 if (o->scrollBar.bot < last_bot)
332 XClearArea (o->Xdisplay, o->scrollBar.win,
333 o->sb_shadow + xsb, o->scrollBar.bot,
334 sb_width, (last_bot - o->scrollBar.bot), False);
335
336 last_top = o->scrollBar.top;
337 last_bot = o->scrollBar.bot;
338
339 /* scrollbar slider */
340 #ifdef XTERM_SCROLLBAR
341 XFillRectangle (o->Xdisplay, o->scrollBar.win, o->scrollbarGC,
342 xsb + 1, o->scrollBar.top,
343 sb_width - 2, scrollbar_len);
344
345 XDrawLine (o->Xdisplay, o->scrollBar.win, o->ShadowGC,
346 xsb ? 0 : o->sb_width, o->scrollBar.beg, xsb ? 0 : sb_width,
347 o->scrollBar.end);
348
349 #else
350 #ifdef SB_BORDER
351 {
352 int xofs;
353
354 if (o->Options & Opt_scrollBar_right)
355 xofs = 0;
356 else
357 xofs = (o->sb_shadow) ? SB_WIDTH : SB_WIDTH - 1;
358
359 XDrawLine (o->Xdisplay, o->scrollBar.win, o->botShadowGC,
360 xofs, 0, xofs, o->scrollBar.end + SB_WIDTH);
361 }
362 #endif
363 XFillRectangle (o->Xdisplay, o->scrollBar.win, o->scrollbarGC,
364 o->sb_shadow, o->scrollBar.top,
365 sb_width, scrollbar_len);
366
367 if (o->sb_shadow)
368 /* trough shadow */
369 rxvtlib_Draw_Shadow (o, o->scrollBar.win,
370 o->botShadowGC, o->topShadowGC,
371 0, 0,
372 (sb_width + 2 * o->sb_shadow),
373 (o->scrollBar.end + (sb_width + 1) + o->sb_shadow));
374 /* shadow for scrollbar slider */
375 rxvtlib_Draw_Shadow (o, o->scrollBar.win,
376 o->topShadowGC, o->botShadowGC,
377 o->sb_shadow, o->scrollBar.top, sb_width,
378 scrollbar_len);
379
380 /*
381 * Redraw scrollbar arrows
382 */
383 rxvtlib_Draw_button (o, o->sb_shadow, o->sb_shadow, (scrollbar_isUp ()? -1 : +1), UP);
384 rxvtlib_Draw_button (o, o->sb_shadow, (o->scrollBar.end + 1),
385 (scrollbar_isDn ()? -1 : +1), DN);
386 #endif /* XTERM_SCROLLBAR */
387 last_top = o->scrollBar.top;
388 last_bot = o->scrollBar.bot;
389 last_state = o->scrollBar.state;
390
391 #else /* NEXT_SCROLLBAR */
392 Pixmap buffer;
393 int height = o->scrollBar.end + SB_BUTTON_TOTAL_HEIGHT + SB_PADDING;
394
395 if (o->blackGC == NULL)
396 rxvtlib_init_scrollbar_stuff (o);
397 if (o->killed)
398 return 0;
399
400 if (update) {
401 int top = (o->TermWin.nscrolled - o->TermWin.view_start);
402 int bot = top + (o->TermWin.nrow - 1);
403 int len =
404
405 max ((o->TermWin.nscrolled + (o->TermWin.nrow - 1)), 1);
406 int adj = ((bot - top) * scrollbar_size()) % len;
407
408 o->scrollBar.top = (o->scrollBar.beg + (top * scrollbar_size ()) / len);
409 scrollbar_len = (((bot - top) * scrollbar_size()) / len +
410 SCROLL_MINHEIGHT + ((adj > 0) ? 1 : 0));
411 o->scrollBar.bot = (o->scrollBar.top + scrollbar_len);
412 /* no change */
413 if ((o->scrollBar.top == last_top) && (o->scrollBar.bot == last_bot)
414 && ((o->scrollBar.state == last_state) || (!scrollbar_isUpDn())))
415 return 0;
416 }
417 /* create double buffer */
418 buffer =
419 XCreatePixmap (o->Xdisplay, o->scrollBar.win, SB_WIDTH + 1, height, o->Xdepth);
420
421 last_top = o->scrollBar.top;
422 last_bot = o->scrollBar.bot;
423 last_state = o->scrollBar.state;
424
425 /* draw the background */
426 XFillRectangle (o->Xdisplay, buffer, o->grayGC, 0, 0, SB_WIDTH + 1, height);
427 XDrawRectangle(o->Xdisplay, buffer, o->blackGC, 0, -SB_BORDER_WIDTH,
428 SB_WIDTH, height + SB_BORDER_WIDTH);
429
430 if (o->TermWin.nscrolled > 0) {
431 XFillRectangle(o->Xdisplay, buffer, o->stippleGC,
432 SB_LEFT_PADDING, SB_PADDING,
433 SB_BUTTON_WIDTH,
434 height - SB_BUTTON_TOTAL_HEIGHT - SB_PADDING);
435 XFillRectangle(o->Xdisplay, buffer, o->grayGC,
436 SB_LEFT_PADDING, o->scrollBar.top + SB_PADDING,
437 SB_BUTTON_WIDTH, scrollbar_len);
438 rxvtlib_drawBevel(o, buffer, SB_BUTTON_BEVEL_X, o->scrollBar.top + SB_PADDING,
439 SB_BUTTON_WIDTH, scrollbar_len);
440 rxvtlib_drawBevel(o, buffer, SB_BUTTON_BEVEL_X, height - SB_BUTTON_BOTH_HEIGHT,
441 SB_BUTTON_WIDTH, SB_BUTTON_HEIGHT);
442 rxvtlib_drawBevel(o, buffer, SB_BUTTON_BEVEL_X, height - SB_BUTTON_SINGLE_HEIGHT,
443 SB_BUTTON_WIDTH, SB_BUTTON_HEIGHT);
444
445 XCopyArea (o->Xdisplay, o->dimple, buffer, o->whiteGC, 0, 0,
446 SCROLLER_DIMPLE_WIDTH, SCROLLER_DIMPLE_HEIGHT,
447 (SB_WIDTH - SCROLLER_DIMPLE_WIDTH) / 2,
448 o->scrollBar.top + SB_BEVEL_WIDTH_UPPER_LEFT +
449 (scrollbar_len - SCROLLER_DIMPLE_HEIGHT) / 2);
450
451 if (scrollbar_isUp ())
452 XCopyArea(o->Xdisplay, o->upArrowHi, buffer, o->whiteGC, 0, 0,
453 ARROW_WIDTH, ARROW_HEIGHT,
454 SB_BUTTON_FACE_X,
455 height - (SB_BUTTON_BOTH_HEIGHT - SB_BEVEL_WIDTH_UPPER_LEFT));
456 else
457 XCopyArea(o->Xdisplay, o->upArrow, buffer, o->whiteGC, 0, 0,
458 ARROW_WIDTH, ARROW_HEIGHT,
459 SB_BUTTON_FACE_X,
460 height - (SB_BUTTON_BOTH_HEIGHT - SB_BEVEL_WIDTH_UPPER_LEFT));
461
462 if (scrollbar_isDn ())
463 XCopyArea(o->Xdisplay, o->downArrowHi, buffer, o->whiteGC, 0, 0,
464 ARROW_WIDTH, ARROW_HEIGHT,
465 SB_BUTTON_FACE_X,
466 height - (SB_BUTTON_SINGLE_HEIGHT - SB_BEVEL_WIDTH_UPPER_LEFT));
467 else
468 XCopyArea(o->Xdisplay, o->downArrow, buffer, o->whiteGC, 0, 0,
469 ARROW_WIDTH, ARROW_HEIGHT,
470 SB_BUTTON_FACE_X,
471 height - (SB_BUTTON_SINGLE_HEIGHT - SB_BEVEL_WIDTH_UPPER_LEFT));
472 } else {
473 XFillRectangle(o->Xdisplay, buffer, o->stippleGC,
474 SB_LEFT_PADDING, SB_PADDING,
475 SB_BUTTON_WIDTH, height - SB_MARGIN_SPACE);
476 }
477
478 if (o->Options & Opt_scrollBar_right)
479 XCopyArea (o->Xdisplay, buffer, o->scrollBar.win, o->grayGC, 0, 0,
480 SB_WIDTH + SB_BORDER_WIDTH, height, 0, 0);
481 else
482 XCopyArea (o->Xdisplay, buffer, o->scrollBar.win, o->grayGC, 0, 0,
483 SB_WIDTH + SB_BORDER_WIDTH, height, -SB_BORDER_WIDTH, 0);
484
485 XFreePixmap (o->Xdisplay, buffer);
486 #endif /* ! NEXT_SCROLLBAR */
487 return 1;
488 }
489
490 /* EXTPROTO */
rxvtlib_scrollbar_mapping(rxvtlib * o,int map)491 int rxvtlib_scrollbar_mapping (rxvtlib *o, int map)
492 {
493 int change = 0;
494
495 if (map && !scrollbar_visible ()) {
496 o->scrollBar.state = 1;
497 if (o->scrollBar.win == 0)
498 return 0;
499 XMapWindow (o->Xdisplay, o->scrollBar.win);
500 change = 1;
501 } else if (!map && scrollbar_visible ()) {
502 o->scrollBar.state = 0;
503 XUnmapWindow (o->Xdisplay, o->scrollBar.win);
504 change = 1;
505 }
506 return change;
507 }
508
509 /* EXTPROTO */
rxvtlib_map_scrollBar(rxvtlib * o,int map)510 void rxvtlib_map_scrollBar (rxvtlib *o, int map)
511 {
512 if (rxvtlib_scrollbar_mapping (o, map)) {
513 rxvtlib_resize_all_windows (o);
514 rxvtlib_scr_touch (o);
515 }
516 }
517
518 /*----------------------- end-of-file (C source) -----------------------*/
519