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