1 /* Copyright (C) 2000-2012 by George Williams */
2 /*
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are met:
5
6 * Redistributions of source code must retain the above copyright notice, this
7 * list of conditions and the following disclaimer.
8
9 * Redistributions in binary form must reproduce the above copyright notice,
10 * this list of conditions and the following disclaimer in the documentation
11 * and/or other materials provided with the distribution.
12
13 * The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include <fontforge-config.h>
29
30 #include "gdraw.h"
31 #include "ggadgetP.h"
32 #include "gresource.h"
33 #include "ustring.h"
34
35 static GBox scrollbar_box = GBOX_EMPTY; /* Don't initialize here */
36 static GBox thumb_box = GBOX_EMPTY; /* Don't initialize here */
37 int _GScrollBar_Width = 13; /* in points */
38 int _GScrollBar_StartTime=300, _GScrollBar_RepeatTime=200;
39 static int gscrollbar_inited = false;
40
41 static GGadget *GScrollBarCreateInitialized(struct gwindow *base, GGadgetData *gd,void *data);
42 static struct scrollbarinit sbinit = { 0, 40, 20, 10 };
43 static GGadgetCreateData scrollbar_gcd[] = {
44 { GScrollBarCreateInitialized, { { 0, 0, 100, 13 }, NULL, 0, 0, 0, 0, 0, NULL, { (GTextInfo *) &sbinit }, gg_visible, NULL, NULL }, NULL, NULL },
45 { GScrollBarCreateInitialized, { { 0, 0, 100, 13 }, NULL, 0, 0, 0, 0, 0, NULL, { (GTextInfo *) &sbinit }, gg_visible|gg_enabled, NULL, NULL }, NULL, NULL }
46 };
47 static GGadgetCreateData *sarray[] = { GCD_Glue, &scrollbar_gcd[0], GCD_Glue, &scrollbar_gcd[1], GCD_Glue, NULL, NULL };
48 static GGadgetCreateData scrollbarbox =
49 { GHVGroupCreate, { { 2, 2, 0, 0 }, NULL, 0, 0, 0, 0, 0, NULL, { (GTextInfo *) sarray }, gg_visible|gg_enabled, NULL, NULL }, NULL, NULL };
50 static GResInfo gthumb_ri;
51 static GResInfo gscrollbar_ri = {
52 >humb_ri, &ggadget_ri,>humb_ri, NULL,
53 &scrollbar_box,
54 NULL,
55 &scrollbarbox,
56 NULL,
57 N_("ScrollBar"),
58 N_("Scroll Bar"),
59 "GScrollBar",
60 "Gdraw",
61 false,
62 box_foreground_border_outer|omf_border_type|omf_border_width|
63 omf_padding|omf_main_background,
64 NULL,
65 GBOX_EMPTY,
66 NULL,
67 NULL,
68 NULL
69 };
70 static GResInfo gthumb_ri = {
71 NULL, &ggadget_ri,&gscrollbar_ri, NULL,
72 &thumb_box,
73 NULL,
74 &scrollbarbox,
75 NULL,
76 N_("SB Thumb"),
77 N_("Scroll Bar Thumb"),
78 "GScrollBarThumb",
79 "Gdraw",
80 true,
81 omf_main_background|omf_border_width|omf_padding,
82 NULL,
83 GBOX_EMPTY,
84 NULL,
85 NULL,
86 NULL
87 };
88
GScrollBarChanged(GScrollBar * gsb,enum sb sbtype,int32 pos)89 static void GScrollBarChanged(GScrollBar *gsb, enum sb sbtype, int32 pos) {
90 GEvent e;
91 int active_len;
92
93 if ( gsb->g.vert ) {
94 active_len = gsb->g.inner.height;
95 } else {
96 active_len = gsb->g.inner.width;
97 }
98 if ( active_len<=0 )
99 active_len = 1;
100
101 e.type = et_controlevent;
102 e.w = gsb->g.base;
103 e.u.control.subtype = et_scrollbarchange;
104 e.u.control.g = &gsb->g;
105 e.u.control.u.sb.type = sbtype;
106 e.u.control.u.sb.pos = (pos-gsb->thumboff)*(gsb->sb_max-gsb->sb_min)/active_len +
107 gsb->sb_min;
108 if ( e.u.control.u.sb.pos > gsb->sb_max-gsb->sb_mustshow )
109 e.u.control.u.sb.pos = gsb->sb_max-gsb->sb_mustshow;
110 if ( e.u.control.u.sb.pos < gsb->sb_min )
111 e.u.control.u.sb.pos = gsb->sb_min;
112
113 if ( gsb->g.handle_controlevent!=NULL )
114 (gsb->g.handle_controlevent)(&gsb->g,&e);
115 else
116 GDrawPostEvent(&e);
117 }
118
draw_thumb(GWindow pixmap,GScrollBar * gsb)119 static void draw_thumb(GWindow pixmap, GScrollBar *gsb) {
120 GRect thumbrect, thumbinner, old;
121 int lw, skip, i;
122
123 GDrawPushClip(pixmap,&gsb->g.inner,&old);
124 thumbrect = gsb->g.inner;
125 if ( gsb->g.vert ) {
126 thumbrect.y = gsb->g.inner.y+gsb->thumbpos;
127 thumbrect.height = gsb->thumbsize;
128 } else {
129 thumbrect.x = gsb->g.inner.x+gsb->thumbpos;
130 thumbrect.width = gsb->thumbsize;
131 }
132 thumbinner.x = thumbrect.x+gsb->thumbborder;
133 thumbinner.y = thumbrect.y+gsb->thumbborder;
134 thumbinner.width = thumbrect.width-2*gsb->thumbborder;
135 thumbinner.height = thumbrect.height-2*gsb->thumbborder;
136
137 GBoxDrawBackground(pixmap,&thumbrect,gsb->thumbbox, gsb->g.state,false);
138 GBoxDrawBorder(pixmap,&thumbrect,gsb->thumbbox,gsb->g.state,false);
139
140 lw = GDrawPointsToPixels(gsb->g.base,1);
141 skip = GDrawPointsToPixels(gsb->g.base,3);
142 GDrawSetLineWidth(pixmap,lw);
143 if ( gsb->g.vert ) {
144 for ( i = thumbinner.y + skip; i<thumbinner.y+thumbinner.height-skip;
145 i += skip+2*lw ) {
146 GDrawDrawLine(pixmap,thumbinner.x+lw, i, thumbinner.x+thumbinner.width-2*lw, i,
147 gsb->thumbbox->border_brightest );
148 GDrawDrawLine(pixmap,thumbinner.x+lw, i+lw, thumbinner.x+thumbinner.width-2*lw, i+lw,
149 gsb->thumbbox->border_darkest );
150 }
151 } else {
152 for ( i = thumbinner.x + skip; i<thumbinner.x+thumbinner.width-skip;
153 i += skip+2*lw ) {
154 GDrawDrawLine(pixmap,i, thumbinner.y+lw, i, thumbinner.y+thumbinner.height-2*lw,
155 gsb->thumbbox->border_brightest );
156 GDrawDrawLine(pixmap,i+lw, thumbinner.y+lw, i+lw, thumbinner.y+thumbinner.height-2*lw,
157 gsb->thumbbox->border_darkest );
158 }
159 }
160 GDrawPopClip(pixmap,&old);
161 }
162
draw_arrow(GWindow pixmap,GScrollBar * gsb,int which)163 static void draw_arrow(GWindow pixmap, GScrollBar *gsb, int which) {
164 GPoint pts[5];
165 int point = GDrawPointsToPixels(gsb->g.base,1);
166 int cnt = 4;
167 Color fill = gsb->thumbbox->main_foreground;
168
169 if ( fill == COLOR_DEFAULT )
170 fill = GDrawGetDefaultForeground(GDrawGetDisplayOfWindow(pixmap));
171
172 switch ( which ) {
173 case 0: /* Horizontal left arrow */
174 pts[0].y = (gsb->g.r.y+(gsb->g.r.height-1)/2);
175 pts[0].x = gsb->g.r.x + 2*point;
176 pts[1].y = gsb->g.r.y + point;
177 pts[1].x = pts[0].x + (gsb->g.r.height-1)/2-point ;
178 pts[2].y = gsb->g.r.y+gsb->g.r.height-1 - point;
179 pts[2].x = pts[1].x;
180 pts[3] = pts[0];
181 if ( !(gsb->g.inner.height&1 )) {
182 ++pts[3].y;
183 pts[4] = pts[0];
184 cnt = 5;
185 }
186 GDrawFillPoly(pixmap,pts,cnt,fill);
187 GDrawDrawLine(pixmap,pts[0].x,pts[0].y,pts[1].x,pts[1].y,
188 gsb->thumbbox->border_brightest);
189 GDrawDrawLine(pixmap,pts[2].x,pts[2].y,pts[3].x,pts[3].y,
190 gsb->thumbbox->border_darker);
191 GDrawDrawLine(pixmap,pts[1].x,pts[1].y,pts[2].x,pts[2].y,
192 gsb->thumbbox->border_darkest);
193 break;
194 case 1: /* Vertical up arrow */
195 pts[0].x = (gsb->g.r.x+(gsb->g.r.width-1)/2);
196 pts[0].y = gsb->g.r.y + 2*point;
197 pts[1].x = gsb->g.r.x + point;
198 pts[1].y = pts[0].y + (gsb->g.r.width-1)/2-point ;
199 pts[2].x = gsb->g.r.x+gsb->g.r.width-1 - point;
200 pts[2].y = pts[1].y;
201 pts[3] = pts[0];
202 if ( !(gsb->g.inner.width&1 )) {
203 ++pts[3].x;
204 pts[4] = pts[0];
205 cnt = 5;
206 }
207 GDrawFillPoly(pixmap,pts,cnt,fill);
208 GDrawDrawLine(pixmap,pts[0].x,pts[0].y,pts[1].x,pts[1].y,
209 gsb->thumbbox->border_brightest);
210 GDrawDrawLine(pixmap,pts[2].x,pts[2].y,pts[3].x,pts[3].y,
211 gsb->thumbbox->border_darker);
212 GDrawDrawLine(pixmap,pts[1].x,pts[1].y,pts[2].x,pts[2].y,
213 gsb->thumbbox->border_darkest);
214 break;
215 case 2: /* Horizontal right arrow */
216 pts[0].y = (gsb->g.r.y+(gsb->g.r.height-1)/2);
217 pts[0].x = gsb->g.r.x + gsb->g.r.width-1 - 2*point;
218 pts[1].y = gsb->g.r.y + point;
219 pts[1].x = pts[0].x - ((gsb->g.r.height-1)/2-point);
220 pts[2].y = gsb->g.r.y+gsb->g.r.height-1 - point;
221 pts[2].x = pts[1].x;
222 pts[3] = pts[0];
223 if ( !(gsb->g.inner.height&1 )) {
224 ++pts[3].y;
225 pts[4] = pts[0];
226 cnt = 5;
227 }
228 GDrawFillPoly(pixmap,pts,cnt,fill);
229 GDrawDrawLine(pixmap,pts[0].x,pts[0].y,pts[1].x,pts[1].y,
230 gsb->thumbbox->border_darkest);
231 GDrawDrawLine(pixmap,pts[2].x,pts[2].y,pts[3].x,pts[3].y,
232 gsb->thumbbox->border_darker);
233 GDrawDrawLine(pixmap,pts[1].x,pts[1].y,pts[2].x,pts[2].y,
234 gsb->thumbbox->border_brightest);
235 break;
236 case 3: /* Vertical down arrow */
237 pts[0].x = (gsb->g.r.x+(gsb->g.r.width-1)/2);
238 pts[0].y = gsb->g.r.y + gsb->g.r.height-1 - 2*point;
239 pts[1].x = gsb->g.r.x + point;
240 pts[1].y = pts[0].y - ((gsb->g.r.width-1)/2-point);
241 pts[2].x = gsb->g.r.x+gsb->g.r.width-1 - point;
242 pts[2].y = pts[1].y;
243 pts[3] = pts[0];
244 if ( !(gsb->g.inner.width&1 )) {
245 ++pts[3].x;
246 pts[4] = pts[0];
247 cnt = 5;
248 }
249 GDrawFillPoly(pixmap,pts,cnt,fill);
250 GDrawDrawLine(pixmap,pts[0].x,pts[0].y,pts[1].x,pts[1].y,
251 gsb->thumbbox->border_darkest);
252 GDrawDrawLine(pixmap,pts[2].x,pts[2].y,pts[3].x,pts[3].y,
253 gsb->thumbbox->border_darker);
254 GDrawDrawLine(pixmap,pts[1].x,pts[1].y,pts[2].x,pts[2].y,
255 gsb->thumbbox->border_brightest);
256 break;
257 }
258 }
259
260 static void GScrollBarFit(GScrollBar *gsb);
261
gscrollbar_expose(GWindow pixmap,GGadget * g,GEvent * event)262 static int gscrollbar_expose(GWindow pixmap, GGadget *g, GEvent *event) {
263 GScrollBar *gsb = (GScrollBar *) g;
264 GBox box = *(g->box);
265 GRect old1;
266 GRect r;
267 int ar;
268
269 if ( g->state == gs_invisible )
270 return( false );
271
272 /* In case border was changed in resource editor, */
273 /* the scrollbar thumb inside must be refitted. */
274 GScrollBarFit(gsb);
275
276 GDrawPushClip(pixmap,&g->r,&old1);
277
278 r = g->r;
279 ar = gsb->arrowsize - gsb->sbborder;
280 if ( gsb->g.vert ) { r.y += ar ; r.height -= 2*ar; }
281 else { r.x += ar; r.width -= 2*ar; }
282
283 /* Mimick old border behavior to retain compatibility with older themes, */
284 /* but match border shape with that of background. */
285 box.flags = box_foreground_border_outer;
286 box.border_width = 0;
287 GBoxDrawBackground(pixmap,&g->r,g->box,g->state,false);
288 GBoxDrawBackground(pixmap,&r,g->box,gs_pressedactive,false);
289 GBoxDrawBorder(pixmap,&g->r,&box,g->state,false);
290 GBoxDrawBorder(pixmap,&r,g->box,g->state,false);
291
292 draw_thumb(pixmap,gsb); /* sets line width for arrows too */
293 draw_arrow(pixmap,gsb,gsb->g.vert);
294 draw_arrow(pixmap,gsb,gsb->g.vert|2);
295
296 GDrawPopClip(pixmap,&old1);
297 return( true );
298 }
299
gscrollbar_mouse(GGadget * g,GEvent * event)300 static int gscrollbar_mouse(GGadget *g, GEvent *event) {
301 GScrollBar *gsb = (GScrollBar *) g;
302 int active_pos, active_len;
303
304 if ( !g->takes_input || (g->state!=gs_enabled && g->state!=gs_active && g->state!=gs_focused ))
305 return( false );
306 if ( event->type == et_crossing )
307 return( false );
308
309 if ( gsb->g.vert ) {
310 active_pos = event->u.mouse.y-g->inner.y;
311 active_len = g->inner.height;
312 } else {
313 active_pos = event->u.mouse.x-g->inner.x;
314 active_len = g->inner.width;
315 }
316
317 if ( (event->type==et_mouseup || event->type==et_mousedown) &&
318 (event->u.mouse.button>=4 && event->u.mouse.button<=7) ) {
319 /* X treats scroll wheels as though they send events from buttons 4 and 5 */
320 /* Badly configured wacom mice send "p5 r5 p4 r4" or "p4 r4 p5 r5" */
321 /* properly configured mice just send "p4 r4" or "p5 r5" */
322 /* And apple's mouse with a scrollwheel sends buttons 6&7 for horizontal*/
323 /* scrolling */
324 /* Convention is that shift-vertical scroll=horizontal scroll */
325 /* control-vertical scroll=minimize/maximize */
326 if ( event->type==et_mousedown ) {
327 GDrawCancelTimer(gsb->pressed); gsb->pressed = NULL;
328 int isv = event->u.mouse.button<=5;
329 if ( event->u.mouse.state&ksm_shift ) isv = !isv;
330 if ( !isv && g->vert )
331 return( false ); /* Allow horizontal scrolling with normal scroll but not vice versa */
332 else if ( event->u.mouse.state&ksm_control )
333 return( false );
334 if ( event->u.mouse.button==5 || event->u.mouse.button==7 ) {
335 GScrollBarChanged(gsb,et_sb_down,0);
336 } else if ( event->u.mouse.button==4 || event->u.mouse.button==6 ) {
337 GScrollBarChanged(gsb,et_sb_up,0);
338 }
339 }
340 return( true );
341 }
342
343 if ( event->type == et_mousedown && GGadgetWithin(g,event->u.mouse.x,event->u.mouse.y)) {
344 GDrawCancelTimer(gsb->pressed); gsb->pressed = NULL;
345 if ( event->u.mouse.button!=1 ) {
346 gsb->thumbpressed = true;
347 gsb->thumboff = 0;
348 active_pos = event->u.mouse.y-g->inner.y;
349 GScrollBarChanged(gsb,et_sb_thumb,active_pos);
350 } else if ( active_pos >= gsb->thumbpos &&
351 active_pos < gsb->thumbpos+gsb->thumbsize ) {
352 gsb->thumbpressed = true;
353 gsb->thumboff = active_pos-gsb->thumbpos;
354 } else if ( active_pos < gsb->thumbpos &&
355 (event->u.mouse.state&(ksm_control|ksm_meta)) ) {
356 gsb->thumbpressed = true;
357 gsb->thumboff = active_pos;
358 GScrollBarChanged(gsb,et_sb_top,0);
359 } else if ( active_pos >= gsb->thumbpos+gsb->thumbsize &&
360 (event->u.mouse.state&(ksm_control|ksm_meta)) ) {
361 gsb->thumbpressed = true;
362 gsb->thumboff = active_pos-active_len+gsb->thumbsize;
363 GScrollBarChanged(gsb,et_sb_bottom,0);
364 } else {
365 if ( active_pos<0 )
366 gsb->repeatcmd = et_sb_up;
367 else if ( active_pos >= active_len )
368 gsb->repeatcmd = et_sb_down;
369 else if ( active_pos < gsb->thumbpos )
370 gsb->repeatcmd = et_sb_uppage;
371 else /* if ( active_pos > gsb->thumbpos+gsb->thumbsize )*/
372 gsb->repeatcmd = et_sb_downpage;
373 GScrollBarChanged(gsb,gsb->repeatcmd,0);
374 gsb->pressed = GDrawRequestTimer(g->base,_GScrollBar_StartTime,_GScrollBar_RepeatTime,NULL);
375 }
376 } else if ( event->type == et_mousemove && gsb->thumbpressed ) {
377 GDrawSkipMouseMoveEvents(gsb->g.base,event);
378 if ( gsb->g.vert ) {
379 active_pos = event->u.mouse.y-g->inner.y;
380 } else {
381 active_pos = event->u.mouse.x-g->inner.x;
382 }
383 GScrollBarChanged(gsb,et_sb_thumb,active_pos);
384 } else if ( event->type == et_mouseup && (gsb->thumbpressed || gsb->pressed)) {
385 if ( gsb->thumbpressed )
386 GScrollBarChanged(gsb,et_sb_thumbrelease,active_pos);
387 GDrawCancelTimer(gsb->pressed); gsb->pressed = NULL;
388 gsb->thumbpressed = false;
389 } else if ( event->type == et_mousemove && !gsb->pressed &&
390 g->popup_msg!=NULL && GGadgetWithin(g,event->u.mouse.x,event->u.mouse.y)) {
391 GGadgetPreparePopup(g->base,g->popup_msg);
392 return( true );
393 } else
394 return( false );
395
396 return( true );
397 }
398
gscrollbar_timer(GGadget * g,GEvent * event)399 static int gscrollbar_timer(GGadget *g, GEvent *event) {
400 GScrollBar *gsb = (GScrollBar *) g;
401
402 if ( event->u.timer.timer == gsb->pressed ) {
403 GScrollBarChanged(gsb,gsb->repeatcmd,0);
404 return( true );
405 }
406 return( false );
407 }
408
gscrollbar_destroy(GGadget * g)409 static void gscrollbar_destroy(GGadget *g) {
410 GScrollBar *gsb = (GScrollBar *) g;
411
412 if ( gsb==NULL )
413 return;
414 GDrawCancelTimer(gsb->pressed);
415 _ggadget_destroy(g);
416 }
417
gscrollbar_get_desired_size(GGadget * g,GRect * outer,GRect * inner)418 static void gscrollbar_get_desired_size(GGadget *g, GRect *outer, GRect *inner) {
419 int bp = GBoxBorderWidth(g->base,g->box);
420 GScrollBar *gsb = (GScrollBar *) g;
421 int width, height;
422 int minheight, sbw;
423
424 sbw = GDrawPointsToPixels(gsb->g.base,_GScrollBar_Width);
425 minheight = 2*(gsb->thumbborder+gsb->arrowsize) + GDrawPointsToPixels(gsb->g.base,2);
426 if ( g->vert ) {
427 width = sbw;
428 height = minheight;
429 } else {
430 width = minheight;
431 height = sbw;
432 }
433
434 if ( inner!=NULL ) {
435 inner->x = inner->y = 0;
436 inner->width = width; inner->height = height;
437 }
438 if ( outer!=NULL ) {
439 outer->x = outer->y = 0;
440 outer->width = width+2*bp; outer->height = height+2*bp;
441 }
442 }
443
444 struct gfuncs gscrollbar_funcs = {
445 0,
446 sizeof(struct gfuncs),
447
448 gscrollbar_expose,
449 gscrollbar_mouse,
450 NULL,
451 NULL,
452 NULL,
453 gscrollbar_timer,
454 NULL,
455
456 _ggadget_redraw,
457 _ggadget_move,
458 _ggadget_resize,
459 _ggadget_setvisible,
460 _ggadget_setenabled,
461 _ggadget_getsize,
462 _ggadget_getinnersize,
463
464 gscrollbar_destroy,
465
466 NULL,
467 NULL,
468 NULL,
469 NULL,
470 NULL,
471
472 NULL,
473 NULL,
474
475 NULL,
476 NULL,
477 NULL,
478 NULL,
479 NULL,
480 NULL,
481 NULL,
482 NULL,
483 NULL,
484 NULL,
485 NULL,
486
487 gscrollbar_get_desired_size,
488 NULL,
489 NULL,
490 NULL
491 };
492
GScrollBarInit()493 static void GScrollBarInit() {
494 _GGadgetCopyDefaultBox(&scrollbar_box);
495 _GGadgetCopyDefaultBox(&thumb_box);
496 scrollbar_box.border_type = bt_lowered;
497 scrollbar_box.border_width = 1;
498 scrollbar_box.padding = 0;
499 scrollbar_box.flags |= box_foreground_border_outer;
500 scrollbar_box.main_background = GDrawColorBrighten(scrollbar_box.main_background, 0x10);
501 thumb_box.main_background = GDrawColorDarken(thumb_box.main_background,0x8);
502 thumb_box.border_width = 1;
503 thumb_box.padding = 0;
504 _GGadgetInitDefaultBox("GScrollBar.",&scrollbar_box,NULL);
505 _GGadgetInitDefaultBox("GScrollBarThumb.",&thumb_box,NULL);
506 _GScrollBar_Width = GResourceFindInt("GScrollBar.Width",_GScrollBar_Width);
507 _GScrollBar_StartTime = GResourceFindInt("GScrollBar.StartupTime",_GScrollBar_StartTime);
508 _GScrollBar_RepeatTime = GResourceFindInt("GScrollBar.RepeatTime",_GScrollBar_RepeatTime);
509 gscrollbar_inited = true;
510 }
511
GScrollBarFit(GScrollBar * gsb)512 static void GScrollBarFit(GScrollBar *gsb) {
513 int minheight;
514
515 gsb->sbborder = GBoxBorderWidth(gsb->g.base,gsb->g.box);
516 gsb->thumbborder = GBoxBorderWidth(gsb->g.base,gsb->thumbbox);
517 /* FIXME: workaround for incorrect calculation. */
518 if ( gsb->thumbborder > 5 ) gsb->thumbborder = 5;
519 gsb->arrowsize = gsb->sbborder +
520 2*GDrawPointsToPixels(gsb->g.base,2) +
521 GDrawPointsToPixels(gsb->g.base,_GScrollBar_Width)/2-
522 2*GDrawPointsToPixels(gsb->g.base,1);
523 minheight = 2*(gsb->thumbborder+gsb->arrowsize) + GDrawPointsToPixels(gsb->g.base,2);
524
525 if ( gsb->g.vert ) {
526 gsb->g.r.width = GDrawPointsToPixels(gsb->g.base,_GScrollBar_Width);
527 if ( gsb->g.r.height< minheight )
528 gsb->g.r.height = minheight;
529 gsb->g.inner.x = gsb->g.r.x+gsb->sbborder;
530 gsb->g.inner.width = gsb->g.r.width - 2*gsb->sbborder;
531 gsb->g.inner.y = gsb->g.r.y+gsb->arrowsize;
532 gsb->g.inner.height = gsb->g.r.height - 2*gsb->arrowsize;
533 } else {
534 gsb->g.r.height = GDrawPointsToPixels(gsb->g.base,_GScrollBar_Width);
535 if ( gsb->g.r.width< minheight )
536 gsb->g.r.width = minheight;
537 gsb->g.inner.x = gsb->g.r.x+gsb->arrowsize;
538 gsb->g.inner.width = gsb->g.r.width - 2*gsb->arrowsize;
539 gsb->g.inner.y = gsb->g.r.y+gsb->sbborder;
540 gsb->g.inner.height = gsb->g.r.height - 2*gsb->sbborder;
541 }
542 }
543
_GScrollBarCreate(GScrollBar * gsb,struct gwindow * base,GGadgetData * gd,void * data,GBox * def)544 static GScrollBar *_GScrollBarCreate(GScrollBar *gsb, struct gwindow *base, GGadgetData *gd,void *data, GBox *def) {
545
546 if ( !gscrollbar_inited )
547 GScrollBarInit();
548 gsb->g.funcs = &gscrollbar_funcs;
549 gd->flags |= gg_pos_use0;
550 _GGadget_Create(&gsb->g,base,gd,data,def);
551
552 gsb->g.takes_input = true;
553 if ( gd->flags & gg_sb_vert )
554 gsb->g.vert = true;
555 gsb->thumbbox = &thumb_box;
556
557 GScrollBarFit(gsb);
558 if ( gd->u.sbinit!=NULL )
559 GScrollBarSetMustShow(&gsb->g,
560 gd->u.sbinit->sb_min,
561 gd->u.sbinit->sb_max,
562 gd->u.sbinit->sb_pagesize,
563 gd->u.sbinit->sb_pos);
564
565 if ( gd->flags & gg_group_end )
566 _GGadgetCloseGroup(&gsb->g);
567 return( gsb );
568 }
569
GScrollBarCreateInitialized(struct gwindow * base,GGadgetData * gd,void * data)570 static GGadget *GScrollBarCreateInitialized(struct gwindow *base, GGadgetData *gd,void *data) {
571 GScrollBar *gsb = _GScrollBarCreate(calloc(1,sizeof(GScrollBar)),base,gd,data,&scrollbar_box);
572
573 return( &gsb->g );
574 }
575
GScrollBarCreate(struct gwindow * base,GGadgetData * gd,void * data)576 GGadget *GScrollBarCreate(struct gwindow *base, GGadgetData *gd,void *data) {
577 GScrollBar *gsb;
578 struct scrollbarinit *hold = gd->u.sbinit;
579
580 gd->u.sbinit = NULL;
581 gsb = _GScrollBarCreate(calloc(1,sizeof(GScrollBar)),base,gd,data,&scrollbar_box);
582 gd->u.sbinit = hold;
583
584 return( &gsb->g );
585 }
586
GScrollBarGetPos(GGadget * g)587 int32 GScrollBarGetPos(GGadget *g) {
588 return( ((GScrollBar *) g)->sb_pos );
589 }
590
GScrollBarAddToPos(GGadget * g,int32 pos)591 int32 GScrollBarAddToPos(GGadget *g,int32 pos) {
592 return GScrollBarSetPos( g, GScrollBarGetPos(g) + pos );
593 }
594
595
GScrollBarSetPos(GGadget * g,int32 pos)596 int32 GScrollBarSetPos(GGadget *g,int32 pos) {
597 GScrollBar *gsb = (GScrollBar *) g;
598
599 if ( pos>gsb->sb_max-gsb->sb_mustshow )
600 pos = gsb->sb_max-gsb->sb_mustshow;
601 if ( pos<gsb->sb_min )
602 pos = gsb->sb_min;
603 gsb->sb_pos = pos;
604
605 if ( pos==gsb->sb_min || gsb->sb_min==gsb->sb_max )
606 gsb->thumbpos = 0;
607 else
608 gsb->thumbpos =
609 ((gsb->g.vert?gsb->g.inner.height:gsb->g.inner.width)-gsb->size_offset)
610 *(pos-gsb->sb_min)/(gsb->sb_max-gsb->sb_min);
611 _ggadget_redraw(g);
612 return( pos );
613 }
614
GScrollBarSetMustShow(GGadget * g,int32 sb_min,int32 sb_max,int32 sb_pagesize,int32 sb_mustshow)615 void GScrollBarSetMustShow(GGadget *g, int32 sb_min, int32 sb_max, int32 sb_pagesize,
616 int32 sb_mustshow ) {
617 GScrollBar *gsb = (GScrollBar *) g;
618
619 if ( sb_min>sb_max || sb_pagesize<=0 ) {
620 GDrawIError("Invalid scrollbar bounds min=%d max=%d, pagesize=%d",
621 sb_min, sb_max, sb_pagesize );
622 return;
623 }
624 gsb->sb_min = sb_min;
625 gsb->sb_max = sb_max;
626 gsb->sb_pagesize = sb_pagesize;
627 gsb->sb_mustshow = sb_mustshow;
628 gsb->size_offset = 0;
629 gsb->thumbsize = (gsb->g.vert?gsb->g.inner.height:gsb->g.inner.width);
630 if ( sb_max-sb_min > sb_pagesize )
631 gsb->thumbsize = (gsb->thumbsize*gsb->sb_pagesize)/(sb_max-sb_min);
632 if ( gsb->thumbsize<2*gsb->thumbborder+10 ) {
633 gsb->size_offset = 2*gsb->thumbborder+10 - gsb->thumbsize;
634 gsb->thumbsize = 2*gsb->thumbborder+10;
635 if ( gsb->thumbsize>(gsb->g.vert?gsb->g.inner.height:gsb->g.inner.width) ) {
636 gsb->size_offset = 0;
637 gsb->thumbsize = (gsb->g.vert?gsb->g.inner.height:gsb->g.inner.width);
638 }
639 }
640 GScrollBarSetPos(g,gsb->sb_pos);
641 }
642
GScrollBarSetBounds(GGadget * g,int32 sb_min,int32 sb_max,int32 sb_pagesize)643 void GScrollBarSetBounds(GGadget *g, int32 sb_min, int32 sb_max, int32 sb_pagesize ) {
644 GScrollBarSetMustShow(g,sb_min,sb_max,sb_pagesize,sb_pagesize);
645 }
646
GScrollBarGetBounds(GGadget * g,int32 * sb_min,int32 * sb_max,int32 * sb_pagesize)647 void GScrollBarGetBounds(GGadget *g, int32 *sb_min, int32 *sb_max, int32 *sb_pagesize ) {
648 GScrollBar *gsb = (GScrollBar *) g;
649 *sb_min = gsb->sb_min;
650 *sb_max = gsb->sb_max;
651 *sb_pagesize = gsb->sb_pagesize;
652 }
653
_GScrollBarRIHead(void)654 GResInfo *_GScrollBarRIHead(void) {
655 if ( !gscrollbar_inited )
656 GScrollBarInit();
657 return( &gscrollbar_ri );
658 }
659