1 // This file contains some FOX functions redefinitions (FOX hacks for the Clearlooks controls)
2 // The Clearlooks controls try to mimic the GTK Clearlooks theme
3 // They are optional and can be set within the Preferences dialog
4 // The hack is done mainly by redefining the onPaint() functions of the various widgets
5
6
7 // Integer scaling factor for check and radio boxes
8 extern FXint scaleint;
9
10
11 //
12 // Some useful functions and macros
13 //
14
15
16 // Draw rectangle with gradient effect
17 // Default is vertical gradient
drawGradientRectangle(FXDC & dc,FXColor upper,FXColor lower,int x,int y,int w,int h,FXbool vert=true)18 static void drawGradientRectangle(FXDC& dc, FXColor upper, FXColor lower, int x, int y, int w, int h, FXbool vert = true)
19 {
20 register int rr, gg, bb, dr, dg, db, r1, g1, b1, r2, g2, b2, yl, yh, yy, dy, n, t, ww;
21 const int MAXSTEPS = 128;
22
23 if ((0 < w) && (0 < h))
24 {
25 // Horizontal gradient : exchange w and h
26 if (!vert)
27 {
28 ww = w;
29 w = h;
30 h = ww;
31 }
32
33 dc.setStipple(STIPPLE_NONE);
34 dc.setFillStyle(FILL_SOLID);
35
36 r1 = FXREDVAL(upper);
37 r2 = FXREDVAL(lower);
38 dr = r2-r1;
39 g1 = FXGREENVAL(upper);
40 g2 = FXGREENVAL(lower);
41 dg = g2-g1;
42 b1 = FXBLUEVAL(upper);
43 b2 = FXBLUEVAL(lower);
44 db = b2-b1;
45
46 n = FXABS(dr);
47 if ((t = FXABS(dg)) > n)
48 {
49 n = t;
50 }
51 if ((t = FXABS(db)) > n)
52 {
53 n = t;
54 }
55 n++;
56 if (n > h)
57 {
58 n = h;
59 }
60 if (n > MAXSTEPS)
61 {
62 n = MAXSTEPS;
63 }
64 rr = (r1<<16)+32767;
65 gg = (g1<<16)+32767;
66 bb = (b1<<16)+32767;
67 yy = 32767;
68
69 dr = (dr<<16)/n;
70 dg = (dg<<16)/n;
71 db = (db<<16)/n;
72 dy = (h<<16)/n;
73
74 do
75 {
76 yl = yy>>16;
77 yy += dy;
78 yh = yy>>16;
79 dc.setForeground(FXRGB(rr>>16, gg>>16, bb>>16));
80
81 // Vertical gradient
82 if (vert)
83 {
84 dc.fillRectangle(x, y+yl, w, yh-yl);
85 }
86
87 // Horizontal gradient
88 else
89 {
90 dc.fillRectangle(x+yl, y, yh-yl, w);
91 }
92
93 rr += dr;
94 gg += dg;
95 bb += db;
96 } while (yh < h);
97 }
98 }
99
100
101 // These macros are used to simplify the code
102 // They draw a button in Standard or Clearlooks mode, in up or down state
103
104 #define DRAW_CLEARLOOKS_BUTTON_UP \
105 dc.setForeground(backColor); \
106 dc.drawPoints(basebackground, 4); \
107 \
108 dc.setForeground(bordercolor); \
109 dc.drawRectangle(2, 0, width-5, 0); \
110 dc.drawRectangle(2, height-1, width-5, height-1); \
111 dc.drawRectangle(0, 2, 0, height-5); \
112 dc.drawRectangle(width-1, 2, 0, height-5); \
113 dc.drawPoints(bordercorners, 4); \
114 dc.setForeground(shadecolor); \
115 dc.drawPoints(bordershade, 16); \
116 \
117 drawGradientRectangle(dc, topcolor, bottomcolor, 2, 1, width-4, height-2); \
118 dc.setForeground(topcolor); \
119 dc.drawRectangle(1, 3, 0, height-7); \
120 dc.setForeground(bottomcolor); \
121 dc.drawRectangle(width-2, 3, 0, height-7);
122
123
124 #define DRAW_CLEARLOOKS_BUTTON_DOWN \
125 dc.setForeground(shadecolor); \
126 dc.fillRectangle(0, 0, width, height); \
127 \
128 dc.setForeground(backColor); \
129 dc.drawPoints(basebackground, 4); \
130 \
131 dc.setForeground(bordercolor); \
132 dc.drawRectangle(2, 0, width-5, 0); \
133 dc.drawRectangle(2, height-1, width-5, height-1); \
134 dc.drawRectangle(0, 2, 0, height-5); \
135 dc.drawRectangle(width-1, 2, 0, height-5); \
136 dc.drawPoints(bordercorners, 4); \
137 dc.setForeground(shadecolor); \
138 dc.drawPoints(bordershade, 16);
139
140
141 #define DRAW_STANDARD_BUTTON_UP \
142 dc.setForeground(backColor); \
143 dc.fillRectangle(border, border, width-border*2, height-border*2); \
144 if (options&FRAME_THICK) { \
145 drawDoubleRaisedRectangle(dc, 0, 0, width, height); } \
146 else{ \
147 drawRaisedRectangle(dc, 0, 0, width, height); }
148
149
150 #define DRAW_STANDARD_BUTTON_DOWN \
151 dc.setForeground(hiliteColor); \
152 dc.fillRectangle(border, border, width-border*2, height-border*2); \
153 if (options&FRAME_THICK) { \
154 drawDoubleSunkenRectangle(dc, 0, 0, width, height); } \
155 else{ \
156 drawSunkenRectangle(dc, 0, 0, width, height); }
157
158
159 #define INIT_CLEARLOOKS \
160 static FXbool init = true; \
161 static FXbool use_clearlooks = true; \
162 static FXColor topcolor, bottomcolor, shadecolor, bordercolor; \
163 \
164 FXPoint basebackground[4] = { FXPoint(0, 0), FXPoint(width-1, 0), FXPoint(0, height-1), \
165 FXPoint(width-1, height-1) }; \
166 FXPoint bordershade[16] = { FXPoint(0, 1), FXPoint(1, 0), FXPoint(1, 2), FXPoint(2, 1), \
167 FXPoint(width-2, 0), FXPoint(width-1, 1), FXPoint(width-3, 1), \
168 FXPoint(width-2, 2), FXPoint(0, height-2), FXPoint(1, height-1), \
169 FXPoint(1, height-3), FXPoint(2, height-2), \
170 FXPoint(width-1, height-2), FXPoint(width-2, height-1), \
171 FXPoint(width-2, height-3), FXPoint(width-3, height-2) \
172 }; \
173 FXPoint bordercorners[4] = { FXPoint(1, 1), FXPoint(1, height-2), FXPoint(width-2, 1), \
174 FXPoint(width-2, height-2) }; \
175 \
176 if (init) \
177 { \
178 use_clearlooks = getApp()->reg().readUnsignedEntry("SETTINGS", "use_clearlooks", true); \
179 \
180 if (use_clearlooks) \
181 { \
182 FXuint r = FXREDVAL(baseColor); \
183 FXuint g = FXGREENVAL(baseColor); \
184 FXuint b = FXBLUEVAL(baseColor); \
185 \
186 topcolor = FXRGB(FXMIN(1.1*r, 255), FXMIN(1.1*g, 255), FXMIN(1.1*b, 255)); \
187 (void)topcolor; /* Hack to avoid unused variable compiler warning */ \
188 bottomcolor = FXRGB(0.9*r, 0.9*g, 0.9*b); \
189 (void)bottomcolor; /* Hack to avoid unused variable compiler warning */ \
190 shadecolor = FXRGB(0.9*r, 0.9*g, 0.9*b); \
191 bordercolor = FXRGB(0.5*r, 0.5*g, 0.5*b); \
192 } \
193 init = false; \
194 }
195
196
197
198 //
199 // Hack of FXButton (button with gradient effect and rounded corners)
200 // Original author : Sander Jansen <sander@knology.net>
201 //
202
203
204 // Handle repaint
onPaint(FXObject *,FXSelector,void * ptr)205 long FXButton::onPaint(FXObject*, FXSelector, void* ptr)
206 {
207 // Initialize Clearlooks
208 INIT_CLEARLOOKS
209
210 FXEvent* ev = (FXEvent*)ptr;
211 FXDCWindow dc(this, ev);
212 int tw = 0, th = 0, iw = 0, ih = 0, tx, ty, ix, iy;
213
214 // Button with nice gradient effect and rounded corners (Clearlooks)
215 if (use_clearlooks)
216 {
217 // Toolbar style
218 if (options&BUTTON_TOOLBAR)
219 {
220 // Enabled and cursor inside, and up
221 if (isEnabled() && underCursor() && (state == STATE_UP))
222 {
223 DRAW_CLEARLOOKS_BUTTON_UP
224 }
225
226 // Enabled and cursor inside and down
227 else if (isEnabled() && underCursor() && (state == STATE_DOWN))
228 {
229 DRAW_CLEARLOOKS_BUTTON_DOWN
230 }
231
232 // Enabled and checked
233 else if (isEnabled() && (state == STATE_ENGAGED))
234 {
235 DRAW_CLEARLOOKS_BUTTON_UP
236 }
237
238 // Disabled or unchecked or not under cursor
239 else
240 {
241 dc.setForeground(backColor);
242 dc.fillRectangle(0, 0, width, height);
243 }
244 }
245
246 // Normal style
247 else
248 {
249 // Draw in up state if disabled or up
250 if (!isEnabled() || (state == STATE_UP))
251 {
252 DRAW_CLEARLOOKS_BUTTON_UP
253 }
254
255 // Draw in down state if enabled and either checked or pressed
256 else
257 {
258 DRAW_CLEARLOOKS_BUTTON_DOWN
259 }
260 }
261 } // End of gradient painting
262
263 // Normal flat rectangular button
264 else
265 {
266 // Got a border at all?
267 if (options&(FRAME_RAISED|FRAME_SUNKEN))
268 {
269 // Toolbar style
270 if (options&BUTTON_TOOLBAR)
271 {
272 // Enabled and cursor inside, and up
273 if (isEnabled() && underCursor() && (state == STATE_UP))
274 {
275 DRAW_STANDARD_BUTTON_UP
276 }
277
278 // Enabled and cursor inside and down
279 else if (isEnabled() && underCursor() && (state == STATE_DOWN))
280 {
281 DRAW_STANDARD_BUTTON_DOWN
282 }
283
284 // Enabled and checked
285 else if (isEnabled() && (state == STATE_ENGAGED))
286 {
287 DRAW_STANDARD_BUTTON_DOWN
288 }
289
290 // Disabled or unchecked or not under cursor
291 else
292 {
293 dc.setForeground(backColor);
294 dc.fillRectangle(0, 0, width, height);
295 }
296 }
297
298 // Normal style
299 else
300 {
301 // Draw in up state if disabled or up
302 if (!isEnabled() || (state == STATE_UP))
303 {
304 DRAW_STANDARD_BUTTON_UP
305 }
306
307 // Draw sunken if enabled and either checked or pressed
308 // Caution! This one is different!
309 else
310 {
311 if (state == STATE_ENGAGED)
312 {
313 dc.setForeground(hiliteColor);
314 }
315 else
316 {
317 dc.setForeground(backColor);
318 }
319 dc.fillRectangle(border, border, width-border*2, height-border*2);
320 if (options&FRAME_THICK)
321 {
322 drawDoubleSunkenRectangle(dc, 0, 0, width, height);
323 }
324 else
325 {
326 drawSunkenRectangle(dc, 0, 0, width, height);
327 }
328 }
329 }
330 }
331
332 // No borders
333 else
334 {
335 if (isEnabled() && (state == STATE_ENGAGED))
336 {
337 dc.setForeground(hiliteColor);
338 dc.fillRectangle(0, 0, width, height);
339 }
340 else
341 {
342 dc.setForeground(backColor);
343 dc.fillRectangle(0, 0, width, height);
344 }
345 }
346 } // End of normal painting
347
348 // Place text & icon
349 if (!label.empty())
350 {
351 tw = labelWidth(label);
352 th = labelHeight(label);
353 }
354 if (icon)
355 {
356 iw = icon->getWidth();
357 ih = icon->getHeight();
358 }
359
360 just_x(tx, ix, tw, iw);
361 just_y(ty, iy, th, ih);
362
363 // Shift a bit when pressed
364 if (state && (options&(FRAME_RAISED|FRAME_SUNKEN)))
365 {
366 ++tx;
367 ++ty;
368 ++ix;
369 ++iy;
370 }
371
372 // Draw enabled state
373 if (isEnabled())
374 {
375 if (icon)
376 {
377 dc.drawIcon(icon, ix, iy);
378 }
379 if (!label.empty())
380 {
381 dc.setFont(font);
382 dc.setForeground(textColor);
383 drawLabel(dc, label, hotoff, tx, ty, tw, th);
384 }
385 if (hasFocus())
386 {
387 dc.drawFocusRectangle(border+1, border+1, width-2*border-2, height-2*border-2);
388 }
389 }
390
391 // Draw grayed-out state
392 else
393 {
394 if (icon)
395 {
396 dc.drawIconSunken(icon, ix, iy);
397 }
398 if (!label.empty())
399 {
400 dc.setFont(font);
401 dc.setForeground(hiliteColor);
402 drawLabel(dc, label, hotoff, tx+1, ty+1, tw, th);
403 dc.setForeground(shadowColor);
404 drawLabel(dc, label, hotoff, tx, ty, tw, th);
405 }
406 }
407
408 return(1);
409 }
410
411
412 //
413 // Hack of FXCheckButton
414 //
415
416 // Includes HiDPI scaling
417
418
419 // Handle repaint
onPaint(FXObject *,FXSelector,void * ptr)420 long FXCheckButton::onPaint(FXObject*, FXSelector, void* ptr)
421 {
422 // Initialize Clearlooks (don't use the macro because here it's different)
423 static FXbool init = true;
424 static FXbool use_clearlooks = true;
425 static FXColor shadecolor, bordercolor;
426
427 if (init)
428 {
429 use_clearlooks = getApp()->reg().readUnsignedEntry("SETTINGS", "use_clearlooks", true);
430
431 if (use_clearlooks)
432 {
433 FXuint r = FXREDVAL(baseColor);
434 FXuint g = FXGREENVAL(baseColor);
435 FXuint b = FXBLUEVAL(baseColor);
436
437 shadecolor = FXRGB(0.9*r, 0.9*g, 0.9*b);
438 bordercolor = FXRGB(0.5*r, 0.5*g, 0.5*b);
439 }
440 init = false;
441 }
442
443 FXEvent* ev = (FXEvent*)ptr;
444 FXint tw = 0, th = 0, tx, ty, ix, iy;
445
446 FXDCWindow dc(this, ev);
447
448 // Figure text size
449 if (!label.empty())
450 {
451 tw = labelWidth(label);
452 th = labelHeight(label);
453 }
454
455 // Placement
456 just_x(tx, ix, tw, scaleint * 13);
457 just_y(ty, iy, th, scaleint * 13);
458 ix = FXMAX(ix, 0);
459 iy = FXMAX(iy, 0);
460
461 // Button with nice gradient effect and rounded corners (Clearlooks)
462 if (use_clearlooks)
463 {
464 // Widget background
465 dc.setForeground(backColor);
466 dc.fillRectangle(ev->rect.x, ev->rect.y, scaleint * ev->rect.w, scaleint * ev->rect.h);
467
468 FXRectangle recs[4];
469
470 // Check background
471 recs[0].x = ix+2*scaleint;
472 recs[0].y = iy+2*scaleint;
473 recs[0].w = 9*scaleint;
474 recs[0].h = 9*scaleint;
475 if ((check == MAYBE) || !isEnabled())
476 {
477 dc.setForeground(baseColor);
478 }
479 else
480 {
481 dc.setForeground(boxColor);
482 }
483 dc.fillRectangles(recs, 1);
484
485 // Check border
486 recs[0].x = ix+2*scaleint;
487 recs[0].y = iy+1*scaleint;
488 recs[0].w = 9*scaleint;
489 recs[0].h = 1*scaleint;
490 recs[1].x = ix+2*scaleint;
491 recs[1].y = iy+11*scaleint;
492 recs[1].w = 9*scaleint;
493 recs[1].h = 1*scaleint;
494 recs[2].x = ix+1*scaleint;
495 recs[2].y = iy+2*scaleint;
496 recs[2].w = 1*scaleint;
497 recs[2].h = 9*scaleint;
498 recs[3].x = ix+11*scaleint;
499 recs[3].y = iy+2*scaleint;
500 recs[3].w = 1*scaleint;
501 recs[3].h = 9*scaleint;
502 dc.setForeground(bordercolor);
503 dc.fillRectangles(recs, 4);
504
505 // Check border corners
506 recs[0].x = ix+1*scaleint;
507 recs[0].y = iy+1*scaleint;
508 recs[0].w = 1*scaleint;
509 recs[0].h = 1*scaleint;
510 recs[1].x = ix+11*scaleint;
511 recs[1].y = iy+1*scaleint;
512 recs[1].w = 1*scaleint;
513 recs[1].h = 1*scaleint;
514 recs[2].x = ix+1*scaleint;
515 recs[2].y = iy+11*scaleint;
516 recs[2].w = 1*scaleint;
517 recs[2].h = 1*scaleint;
518 recs[3].x = ix+11*scaleint;
519 recs[3].y = iy+11*scaleint;
520 recs[3].w = 1*scaleint;
521 recs[3].h = 1*scaleint;
522 dc.setForeground(shadecolor);
523 dc.fillRectangles(recs, 4);
524
525 // Check color
526 if ((check == MAYBE) || !isEnabled())
527 {
528 dc.setForeground(shadowColor);
529 }
530 else
531 {
532 dc.setForeground(checkColor);
533 }
534 }
535
536 // Normal flat rectangular button
537 else
538 {
539 // Widget background
540 dc.setForeground(backColor);
541 dc.fillRectangle(ev->rect.x, ev->rect.y, scaleint * ev->rect.w, scaleint * ev->rect.h);
542
543 FXRectangle recs[2];
544
545 // Check background
546 recs[0].x = ix+2*scaleint;
547 recs[0].y = iy+2*scaleint;
548 recs[0].w = 9*scaleint;
549 recs[0].h = 9*scaleint;
550 if ((check == MAYBE) || !isEnabled())
551 {
552 dc.setForeground(baseColor);
553 }
554 else
555 {
556 dc.setForeground(boxColor);
557 }
558 dc.fillRectangles(recs, 1);
559
560 // Check border for +
561 if (options&CHECKBUTTON_PLUS)
562 {
563 dc.setForeground(textColor);
564 dc.drawRectangle(ix+scaleint*2, iy+scaleint*2, 8*scaleint, 8*scaleint);
565 }
566
567 // Check border for v
568 else
569 {
570 // Check border
571 recs[0].x = ix;
572 recs[0].y = iy;
573 recs[0].w = 12*scaleint;
574 recs[0].h = 1*scaleint;
575 recs[1].x = ix;
576 recs[1].y = iy+1*scaleint;
577 recs[1].w = 1*scaleint;
578 recs[1].h = 11*scaleint;
579 dc.setForeground(shadowColor);
580 dc.fillRectangles(recs, 2);
581
582 recs[0].x = ix+1*scaleint;
583 recs[0].y = iy+1*scaleint;
584 recs[0].w = 10*scaleint;
585 recs[0].h = 1*scaleint;
586 recs[1].x = ix+1*scaleint;
587 recs[1].y = iy+2*scaleint;
588 recs[1].w = 1*scaleint;
589 recs[1].h = 9*scaleint;
590 dc.setForeground(borderColor);
591 dc.fillRectangles(recs, 2);
592
593 recs[0].x = ix;
594 recs[0].y = iy+12*scaleint;
595 recs[0].w = 13*scaleint;
596 recs[0].h = 1*scaleint;
597 recs[1].x = ix+12*scaleint;
598 recs[1].y = iy;
599 recs[1].w = 1*scaleint;
600 recs[1].h = 13*scaleint;
601 dc.setForeground(hiliteColor);
602 dc.fillRectangles(recs, 2);
603 }
604
605 // Check color
606 if ((check == MAYBE) || !isEnabled())
607 {
608 dc.setForeground(shadowColor);
609 }
610 else
611 {
612 dc.setForeground(checkColor);
613 }
614 }
615
616 // Show as +
617 if (options&CHECKBUTTON_PLUS)
618 {
619 if (check != true)
620 {
621 dc.fillRectangle(ix+scaleint*6, iy+scaleint*4, 1*scaleint, 5*scaleint);
622 }
623 dc.fillRectangle(ix+scaleint*4, iy+scaleint*6, 5*scaleint, 1*scaleint);
624 }
625
626 // Show as v
627 else
628 {
629 if (check != false)
630 {
631 FXRectangle recs[7];
632 recs[0].x = ix+3*scaleint;
633 recs[0].y = iy+5*scaleint;
634 recs[0].w = 1*scaleint;
635 recs[0].h = 3*scaleint;
636 recs[1].x = ix+4*scaleint;
637 recs[1].y = iy+6*scaleint;
638 recs[1].w = 1*scaleint;
639 recs[1].h = 3*scaleint;
640 recs[2].x = ix+5*scaleint;
641 recs[2].y = iy+7*scaleint;
642 recs[2].w = 1*scaleint;
643 recs[2].h = 3*scaleint;
644 recs[3].x = ix+6*scaleint;
645 recs[3].y = iy+6*scaleint;
646 recs[3].w = 1*scaleint;
647 recs[3].h = 3*scaleint;
648 recs[4].x = ix+7*scaleint;
649 recs[4].y = iy+5*scaleint;
650 recs[4].w = 1*scaleint;
651 recs[4].h = 3*scaleint;
652 recs[5].x = ix+8*scaleint;
653 recs[5].y = iy+4*scaleint;
654 recs[5].w = 1*scaleint;
655 recs[5].h = 3*scaleint;
656 recs[6].x = ix+9*scaleint;
657 recs[6].y = iy+3*scaleint;
658 recs[6].w = 1*scaleint;
659 recs[6].h = 3*scaleint;
660 dc.fillRectangles(recs, 7);
661 }
662 }
663
664 // Text
665 if (!label.empty() && (label != " ") )
666 {
667 dc.setFont(font);
668 if (isEnabled())
669 {
670 dc.setForeground(textColor);
671 drawLabel(dc, label, hotoff, tx, ty, tw, th);
672 if (hasFocus())
673 {
674 dc.drawFocusRectangle(tx-1, ty-1, tw+2, th+2);
675 }
676 }
677 else
678 {
679 dc.setForeground(hiliteColor);
680 drawLabel(dc, label, hotoff, tx+1, ty+1, tw, th);
681 dc.setForeground(shadowColor);
682 drawLabel(dc, label, hotoff, tx, ty, tw, th);
683 }
684 }
685
686 // Frame
687 drawFrame(dc, 0, 0, width, height);
688
689 return(1);
690 }
691
692
693 //
694 // Hack of FXTextField
695 //
696
697 // Handle repaint
onPaint(FXObject *,FXSelector,void * ptr)698 long FXTextField::onPaint(FXObject*, FXSelector, void* ptr)
699 {
700 // Initialize Clearlooks
701 INIT_CLEARLOOKS
702
703 FXEvent* ev = (FXEvent*)ptr;
704 FXDCWindow dc(this, ev);
705
706 // Draw frame
707 drawFrame(dc, 0, 0, width, height);
708
709 // Draw background
710 dc.setForeground(backColor);
711 dc.fillRectangle(border, border, width-(border<<1), height-(border<<1));
712
713 // !!! Hack to get an optional rounded rectangle shape
714 // only if _TEXTFIELD_NOFRAME is not specified !!!
715 if ( (!(options&_TEXTFIELD_NOFRAME)) & use_clearlooks )
716 {
717 // Outside Background
718 dc.setForeground(baseColor);
719 dc.fillRectangle(0, 0, width, height);
720 dc.drawPoints(basebackground, 4);
721
722 // Border
723 dc.setForeground(bordercolor);
724 dc.drawRectangle(2, 0, width-5, 0);
725 dc.drawRectangle(2, height-1, width-5, height-1);
726 dc.drawRectangle(0, 2, 0, height-5);
727 dc.drawRectangle(width-1, 2, 0, height-5);
728 dc.drawPoints(bordercorners, 4);
729 dc.setForeground(shadecolor);
730 dc.drawPoints(bordershade, 16);
731 dc.setForeground(backColor);
732 dc.fillRectangle(2, 1, width-4, height-2);
733 }
734 // !!! End of hack
735
736 // Draw text, clipped against frame interior
737 dc.setClipRectangle(border, border, width-(border<<1), height-(border<<1));
738 drawTextRange(dc, 0, contents.length());
739
740 // Draw caret
741 if (flags&FLAG_CARET)
742 {
743 int xx = coord(cursor)-1;
744 dc.setForeground(cursorColor);
745 dc.fillRectangle(xx, padtop+border, 1, height-padbottom-padtop-(border<<1));
746 dc.fillRectangle(xx-2, padtop+border, 5, 1);
747 dc.fillRectangle(xx-2, height-border-padbottom-1, 5, 1);
748 }
749
750 return(1);
751 }
752
753
754 //
755 // Hack of FXToggleButton
756 //
757
758 // Handle repaint
onPaint(FXObject *,FXSelector,void * ptr)759 long FXToggleButton::onPaint(FXObject*, FXSelector, void* ptr)
760 {
761 // Initialize Clearlooks
762 INIT_CLEARLOOKS
763
764 int tw = 0, th = 0, iw = 0, ih = 0, tx, ty, ix, iy;
765 FXEvent* ev = (FXEvent*)ptr;
766 FXDCWindow dc(this, ev);
767
768 // Button with nice gradient effect and rounded corners (Clearlooks)
769 if (use_clearlooks)
770 {
771 // Button style is toolbar
772 if (options&TOGGLEBUTTON_TOOLBAR)
773 {
774 // Enabled and cursor inside and button down
775 if (down || ((options&TOGGLEBUTTON_KEEPSTATE) && state))
776 {
777 DRAW_CLEARLOOKS_BUTTON_DOWN
778 }
779 // Enabled and cursor inside but button not down
780 else if (isEnabled() && underCursor())
781 {
782 DRAW_CLEARLOOKS_BUTTON_UP
783 }
784
785 // Disabled or unchecked or not under cursor
786 else
787 {
788 dc.setForeground(backColor);
789 dc.fillRectangle(0, 0, width, height);
790 }
791 }
792
793 // Button style is normal
794 else
795 {
796 // Button down
797 if (down || ((options&TOGGLEBUTTON_KEEPSTATE) && state))
798 {
799 DRAW_CLEARLOOKS_BUTTON_DOWN
800 }
801
802 // Button up
803 else
804 {
805 DRAW_CLEARLOOKS_BUTTON_UP
806 }
807 }
808 } // End of gradient painting
809
810 // Normal flat rectangular button
811 else
812 {
813 // Got a border at all?
814 if (options&(FRAME_RAISED|FRAME_SUNKEN))
815 {
816 // Button style is normal
817 if (options&TOGGLEBUTTON_TOOLBAR)
818 {
819 // Enabled and cursor inside and down
820 if (down || ((options&TOGGLEBUTTON_KEEPSTATE) && state))
821 {
822 DRAW_STANDARD_BUTTON_DOWN
823 }
824
825 // Enabled and cursor inside, and up
826 else if (isEnabled() && underCursor())
827 {
828 DRAW_STANDARD_BUTTON_UP
829 }
830
831 // Disabled or unchecked or not under cursor
832 else
833 {
834 dc.setForeground(backColor);
835 dc.fillRectangle(0, 0, width, height);
836 }
837 }
838
839 // Button style is normal
840 else
841 {
842 // Draw sunken if pressed
843 if (down || ((options&TOGGLEBUTTON_KEEPSTATE) && state))
844 {
845 DRAW_STANDARD_BUTTON_DOWN
846 }
847
848 // Draw raised if not currently pressed down
849 else
850 {
851 DRAW_STANDARD_BUTTON_UP
852 }
853 }
854 }
855
856 // No borders
857 else
858 {
859 dc.setForeground(backColor);
860 dc.fillRectangle(0, 0, width, height);
861 }
862 } // End of normal painting
863
864 // Place text & icon
865 if (state && !altlabel.empty())
866 {
867 tw = labelWidth(altlabel);
868 th = labelHeight(altlabel);
869 }
870 else if (!label.empty())
871 {
872 tw = labelWidth(label);
873 th = labelHeight(label);
874 }
875 if (state && alticon)
876 {
877 iw = alticon->getWidth();
878 ih = alticon->getHeight();
879 }
880 else if (icon)
881 {
882 iw = icon->getWidth();
883 ih = icon->getHeight();
884 }
885
886 just_x(tx, ix, tw, iw);
887 just_y(ty, iy, th, ih);
888
889 // Shift a bit when pressed
890 if ((down || ((options&TOGGLEBUTTON_KEEPSTATE) && state)) && (options&(FRAME_RAISED|FRAME_SUNKEN)))
891 {
892 ++tx;
893 ++ty;
894 ++ix;
895 ++iy;
896 }
897
898 // Draw enabled state
899 if (isEnabled())
900 {
901 if (state && alticon)
902 {
903 dc.drawIcon(alticon, ix, iy);
904 }
905 else if (icon)
906 {
907 dc.drawIcon(icon, ix, iy);
908 }
909 if (state && !altlabel.empty())
910 {
911 dc.setFont(font);
912 dc.setForeground(textColor);
913 drawLabel(dc, altlabel, althotoff, tx, ty, tw, th);
914 }
915 else if (!label.empty())
916 {
917 dc.setFont(font);
918 dc.setForeground(textColor);
919 drawLabel(dc, label, hotoff, tx, ty, tw, th);
920 }
921 if (hasFocus())
922 {
923 dc.drawFocusRectangle(border+1, border+1, width-2*border-2, height-2*border-2);
924 }
925 }
926
927 // Draw grayed-out state
928 else
929 {
930 if (state && alticon)
931 {
932 dc.drawIconSunken(alticon, ix, iy);
933 }
934 else if (icon)
935 {
936 dc.drawIconSunken(icon, ix, iy);
937 }
938 if (state && !altlabel.empty())
939 {
940 dc.setFont(font);
941 dc.setForeground(hiliteColor);
942 drawLabel(dc, altlabel, althotoff, tx+1, ty+1, tw, th);
943 dc.setForeground(shadowColor);
944 drawLabel(dc, altlabel, althotoff, tx, ty, tw, th);
945 }
946 else if (!label.empty())
947 {
948 dc.setFont(font);
949 dc.setForeground(hiliteColor);
950 drawLabel(dc, label, hotoff, tx+1, ty+1, tw, th);
951 dc.setForeground(shadowColor);
952 drawLabel(dc, label, hotoff, tx, ty, tw, th);
953 }
954 }
955
956 return(1);
957 }
958
959
960 //
961 // Hack of FXScrollBar
962 //
963
964
965 // Draw scrollbar button with gradient effect and nice grip
drawGradientScrollButton(FXDCWindow & dc,FXColor topcolor,FXColor bottomcolor,FXColor shadecolor,FXColor lightcolor,FXuint options,int x,int y,int w,int h)966 static void drawGradientScrollButton(FXDCWindow& dc, FXColor topcolor, FXColor bottomcolor, FXColor shadecolor, FXColor lightcolor,
967 FXuint options, int x, int y, int w, int h)
968 {
969 // Fill rectangle with gradient in the right direction (vertical or horizontal)
970 FXbool vertical = ((options&SCROLLBAR_HORIZONTAL) ? true : false);
971
972 drawGradientRectangle(dc, topcolor, bottomcolor, x, y, w, h, vertical);
973
974 // Draw button borders
975 dc.setForeground(lightcolor);
976 dc.fillRectangle(x+1, y+1, w-1, 1);
977 dc.fillRectangle(x+1, y+1, 1, h-2);
978 dc.setForeground(shadecolor);
979 dc.fillRectangle(x, y, w, 1);
980 dc.fillRectangle(x, y, 1, h-1);
981 dc.fillRectangle(x, y+h-1, w, 1);
982 dc.fillRectangle(x+w-1, y, 1, h);
983
984 // Draw grip lines for horizontal scrollbar
985 if ((options&SCROLLBAR_HORIZONTAL))
986 {
987 dc.setForeground(shadecolor);
988 dc.fillRectangle(x+w/2-3, y+4, 1, h-7);
989 dc.fillRectangle(x+w/2, y+4, 1, h-7);
990 dc.fillRectangle(x+w/2+3, y+4, 1, h-7);
991 dc.setForeground(lightcolor);
992 dc.fillRectangle(x+w/2-2, y+4, 1, h-7);
993 dc.fillRectangle(x+w/2+1, y+4, 1, h-7);
994 dc.fillRectangle(x+w/2+4, y+4, 1, h-7);
995 }
996
997 // Draw grip lines for vertical scrollbar
998 else
999 {
1000 dc.setForeground(shadecolor);
1001 dc.fillRectangle(x+4, y+h/2-3, w-7, 1);
1002 dc.fillRectangle(x+4, y+h/2, w-7, 1);
1003 dc.fillRectangle(x+4, y+h/2+3, w-7, 1);
1004 dc.setForeground(lightcolor);
1005 dc.fillRectangle(x+4, y+h/2-2, w-7, 1);
1006 dc.fillRectangle(x+4, y+h/2+1, w-7, 1);
1007 dc.fillRectangle(x+4, y+h/2+4, w-7, 1);
1008 }
1009 }
1010
1011
1012 // Small hack to set the minimum length of the scrollbar button to barsize*2 instead of barsize/2
setPosition(int p)1013 void FXScrollBar::setPosition(int p)
1014 {
1015 int total, travel, lo, hi, l, h;
1016
1017 pos = p;
1018 if (pos < 0)
1019 {
1020 pos = 0;
1021 }
1022 if (pos > (range-page))
1023 {
1024 pos = range-page;
1025 }
1026 lo = thumbpos;
1027 hi = thumbpos+thumbsize;
1028 if (options&SCROLLBAR_HORIZONTAL)
1029 {
1030 total = width-height-height;
1031 thumbsize = (total*page)/range;
1032 // !!! Hack to change the minimum button size !!!
1033 if (thumbsize < (barsize<<1))
1034 {
1035 thumbsize = (barsize<<1);
1036 }
1037 // !!! End of hack !!!
1038 travel = total-thumbsize;
1039 if (range > page)
1040 {
1041 thumbpos = height+(int)((((double)pos)*travel)/(range-page));
1042 }
1043 else
1044 {
1045 thumbpos = height;
1046 }
1047 l = thumbpos;
1048 h = thumbpos+thumbsize;
1049 if ((l != lo) || (h != hi))
1050 {
1051 update(FXMIN(l, lo), 0, FXMAX(h, hi)-FXMIN(l, lo), height);
1052 }
1053 }
1054 else
1055 {
1056 total = height-width-width;
1057 thumbsize = (total*page)/range;
1058 // !!! Hack to change the minimum button size !!!
1059 if (thumbsize < (barsize<<1))
1060 {
1061 thumbsize = (barsize<<1);
1062 }
1063 // !!! End of hack !!!
1064 travel = total-thumbsize;
1065 if (range > page)
1066 {
1067 thumbpos = width+(int)((((double)pos)*travel)/(range-page));
1068 }
1069 else
1070 {
1071 thumbpos = width;
1072 }
1073 l = thumbpos;
1074 h = thumbpos+thumbsize;
1075 if ((l != lo) || (h != hi))
1076 {
1077 update(0, FXMIN(l, lo), width, FXMAX(h, hi)-FXMIN(l, lo));
1078 }
1079 }
1080 }
1081
1082
1083 // Arrow directions
1084 enum
1085 {
1086 _ARROW_LEFT,
1087 _ARROW_RIGHT,
1088 _ARROW_UP,
1089 _ARROW_DOWN
1090 };
1091
1092
1093 // Draw arrow button in scrollbar with gradient effect and rounded corners (Clearlooks)
drawGradientArrowButton(FXDCWindow & dc,FXColor backcolor,FXColor topcolor,FXColor bottomcolor,FXColor shadecolor,FXColor lightcolor,FXColor bordercolor,FXColor arrowcolor,FXuint options,int x,int y,int w,int h,FXbool down,FXuint direction)1094 static void drawGradientArrowButton(FXDCWindow& dc, FXColor backcolor, FXColor topcolor, FXColor bottomcolor, FXColor shadecolor,
1095 FXColor lightcolor, FXColor bordercolor, FXColor arrowcolor,
1096 FXuint options, int x, int y, int w, int h, FXbool down, FXuint direction)
1097 {
1098 FXPoint arrowpoints[3];
1099 int xx, yy, ah, ab;
1100
1101 FXPoint basebackground[2];
1102 FXPoint bordershade[8];
1103 FXPoint bordercorners[2];
1104
1105 // Rounded corner and arrow point coordinates depend on the button direction
1106 if (direction == _ARROW_UP)
1107 {
1108 // Rounded corners
1109 basebackground[0] = FXPoint(0, 0);
1110 basebackground[1] = FXPoint(w-1, 0);
1111 bordercorners[0] = FXPoint(1, 1);
1112 bordercorners[1] = FXPoint(w-2, 1);
1113 bordershade[0] = FXPoint(0, 1);
1114 bordershade[1] = FXPoint(1, 0);
1115 bordershade[2] = FXPoint(1, 2);
1116 bordershade[3] = FXPoint(2, 1);
1117 bordershade[4] = FXPoint(w-2, 0);
1118 bordershade[5] = FXPoint(w-1, 1);
1119 bordershade[6] = FXPoint(w-3, 1);
1120 bordershade[7] = FXPoint(w-2, 2);
1121
1122 // Arrow points
1123 ab = (w-7)|1;
1124 ah = ab>>1;
1125 xx = x+((w-ab)>>1);
1126 yy = y+((h-ah)>>1);
1127 if (down)
1128 {
1129 ++xx;
1130 ++yy;
1131 }
1132 arrowpoints[0] = FXPoint(xx+(ab>>1), yy-1);
1133 arrowpoints[1] = FXPoint(xx, yy+ah);
1134 arrowpoints[2] = FXPoint(xx+ab, yy+ah);
1135 }
1136 else if (direction == _ARROW_DOWN)
1137 {
1138 // Rounded corners
1139 basebackground[0] = FXPoint(x, y+h-1);
1140 basebackground[1] = FXPoint(x+w-1, y+h-1);
1141 bordercorners[0] = FXPoint(x+1, y+h-2);
1142 bordercorners[1] = FXPoint(x+w-2, y+h-2);
1143 bordershade[0] = FXPoint(x, y+h-2);
1144 bordershade[1] = FXPoint(x+1, y+h-1);
1145 bordershade[2] = FXPoint(x+1, y+h-3);
1146 bordershade[3] = FXPoint(x+2, y+h-2);
1147 bordershade[4] = FXPoint(x+w-1, y+h-2);
1148 bordershade[5] = FXPoint(x+w-2, y+h-1);
1149 bordershade[6] = FXPoint(x+w-2, y+h-3);
1150 bordershade[7] = FXPoint(x+w-3, y+h-2);
1151
1152 // Arrow points
1153 ab = (w-7)|1;
1154 ah = ab>>1;
1155 xx = x+((w-ab)>>1);
1156 yy = y+((h-ah)>>1);
1157 if (down)
1158 {
1159 ++xx;
1160 ++yy;
1161 }
1162 arrowpoints[0] = FXPoint(xx+1, yy);
1163 arrowpoints[1] = FXPoint(xx+ab-1, yy);
1164 arrowpoints[2] = FXPoint(xx+(ab>>1), yy+ah);
1165 }
1166 else if (direction == _ARROW_LEFT)
1167 {
1168 // Rounded corners
1169 basebackground[0] = FXPoint(0, 0);
1170 basebackground[1] = FXPoint(0, h-1);
1171 bordercorners[0] = FXPoint(1, 1);
1172 bordercorners[1] = FXPoint(1, h-2);
1173 bordershade[0] = FXPoint(0, 1);
1174 bordershade[1] = FXPoint(1, 0);
1175 bordershade[2] = FXPoint(1, 2);
1176 bordershade[3] = FXPoint(2, 1);
1177 bordershade[4] = FXPoint(0, h-2);
1178 bordershade[5] = FXPoint(1, h-1);
1179 bordershade[6] = FXPoint(1, h-3);
1180 bordershade[7] = FXPoint(2, h-2);
1181
1182 // Arrow points
1183 ab = (h-7)|1;
1184 ah = ab>>1;
1185 xx = x+((w-ah)>>1);
1186 yy = y+((h-ab)>>1);
1187 if (down)
1188 {
1189 ++xx;
1190 ++yy;
1191 }
1192 arrowpoints[0] = FXPoint(xx+ah, yy);
1193 arrowpoints[1] = FXPoint(xx+ah, yy+ab-1);
1194 arrowpoints[2] = FXPoint(xx, yy+(ab>>1));
1195 }
1196 else // _ARROW_RIGHT
1197 {
1198 // Rounded corners
1199 basebackground[0] = FXPoint(x+w-1, y);
1200 basebackground[1] = FXPoint(x+w-1, y+h-1);
1201 bordercorners[0] = FXPoint(x+w-2, y+1);
1202 bordercorners[1] = FXPoint(x+w-2, y+h-2);
1203 bordershade[0] = FXPoint(x+w-2, y);
1204 bordershade[1] = FXPoint(x+w-1, y+1);
1205 bordershade[2] = FXPoint(x+w-3, y+1);
1206 bordershade[3] = FXPoint(x+w-2, y+2);
1207 bordershade[4] = FXPoint(x+w-1, y+h-2);
1208 bordershade[5] = FXPoint(x+w-2, y+h-1);
1209 bordershade[6] = FXPoint(x+w-2, y+h-3);
1210 bordershade[7] = FXPoint(x+w-3, y+h-2);
1211
1212 // Arrow points
1213 ab = (h-7)|1;
1214 ah = ab>>1;
1215 xx = x+((w-ah)>>1);
1216 yy = y+((h-ab)>>1);
1217 if (down)
1218 {
1219 ++xx;
1220 ++yy;
1221 }
1222 arrowpoints[0] = FXPoint(xx, yy);
1223 arrowpoints[1] = FXPoint(xx, yy+ab-1);
1224 arrowpoints[2] = FXPoint(xx+ah, yy+(ab>>1));
1225 }
1226
1227 // Draw button when up
1228 if (!down)
1229 {
1230 // Fill rectangle with gradient in the right direction (vertical or horizontal)
1231 FXbool vertical = ((options&SCROLLBAR_HORIZONTAL) ? true : false);
1232 drawGradientRectangle(dc, topcolor, bottomcolor, x, y, w, h, vertical);
1233
1234 // Button borders
1235 dc.setForeground(lightcolor);
1236 dc.fillRectangle(x+1, y+1, w-1, 1);
1237 dc.fillRectangle(x+1, y+1, 1, h-2);
1238 dc.setForeground(shadecolor);
1239 dc.fillRectangle(x, y, w, 1);
1240 dc.fillRectangle(x, y, 1, h-1);
1241 dc.fillRectangle(x, y+h-1, w, 1);
1242 dc.fillRectangle(x+w-1, y, 1, h);
1243
1244 // Rounded corners
1245 dc.setForeground(backcolor);
1246 dc.drawPoints(basebackground, 2);
1247 dc.setForeground(shadecolor);
1248 dc.drawPoints(bordercorners, 2);
1249 dc.setForeground(bordercolor);
1250 dc.drawPoints(bordershade, 8);
1251
1252 // Arrow
1253 dc.setForeground(arrowcolor);
1254 dc.fillPolygon(arrowpoints, 3);
1255 }
1256
1257 // Draw button when down (pressed)
1258 else
1259 {
1260 // Dark background
1261 dc.setForeground(bordercolor);
1262 dc.fillRectangle(x, y, w, h);
1263
1264 // Button borders
1265 dc.setForeground(lightcolor);
1266 dc.fillRectangle(x+1, y+1, w-1, 1);
1267 dc.fillRectangle(x+1, y+1, 1, h-2);
1268 dc.setForeground(shadecolor);
1269 dc.fillRectangle(x, y, w, 1);
1270 dc.fillRectangle(x, y, 1, h-1);
1271 dc.fillRectangle(x, y+h-1, w, 1);
1272 dc.fillRectangle(x+w-1, y, 1, h);
1273
1274 // Rounded corners
1275 dc.setForeground(backcolor);
1276 dc.drawPoints(basebackground, 2);
1277 dc.setForeground(shadecolor);
1278 dc.drawPoints(bordercorners, 2);
1279 dc.setForeground(bordercolor);
1280 dc.drawPoints(bordershade, 8);
1281
1282 // Arrow
1283 dc.setForeground(arrowcolor);
1284 dc.fillPolygon(arrowpoints, 3);
1285 }
1286 }
1287
1288
1289 // Draw flat scrollbar button with selected colors
drawFlatScrollButton(FXDCWindow & dc,FXint x,FXint y,FXint w,FXint h,FXbool down,FXColor hilitecolor,FXColor shadowcolor,FXColor bordercolor,FXColor scrollbarcolor)1290 static void drawFlatScrollButton(FXDCWindow& dc, FXint x, FXint y, FXint w, FXint h, FXbool down, FXColor hilitecolor, FXColor shadowcolor, FXColor bordercolor, FXColor scrollbarcolor)
1291 {
1292 dc.setForeground(scrollbarcolor);
1293 dc.fillRectangle(x+2, y+2, w-4, h-4);
1294 if (!down)
1295 {
1296 dc.setForeground(scrollbarcolor);
1297 dc.fillRectangle(x, y, w-1, 1);
1298 dc.fillRectangle(x, y, 1, h-1);
1299 dc.setForeground(hilitecolor);
1300 dc.fillRectangle(x+1, y+1, w-2, 1);
1301 dc.fillRectangle(x+1, y+1, 1, h-2);
1302 dc.setForeground(shadowcolor);
1303 dc.fillRectangle(x+1, y+h-2, w-2, 1);
1304 dc.fillRectangle(x+w-2, y+1, 1, h-2);
1305 dc.setForeground(bordercolor);
1306 dc.fillRectangle(x, y+h-1, w, 1);
1307 dc.fillRectangle(x+w-1, y, 1, h);
1308 }
1309 else
1310 {
1311 dc.setForeground(bordercolor);
1312 dc.fillRectangle(x, y, w-2, 1);
1313 dc.fillRectangle(x, y, 1, h-2);
1314 dc.setForeground(shadowcolor);
1315 dc.fillRectangle(x+1, y+1, w-3, 1);
1316 dc.fillRectangle(x+1, y+1, 1, h-3);
1317 dc.setForeground(hilitecolor);
1318 dc.fillRectangle(x, y+h-1, w-1, 1);
1319 dc.fillRectangle(x+w-1, y+1, 1, h-1);
1320 dc.setForeground(scrollbarcolor);
1321 dc.fillRectangle(x+1, y+h-2, w-1, 1);
1322 dc.fillRectangle(x+w-2, y+2, 1, h-2);
1323 }
1324 }
1325
1326
1327 // Handle repaint
onPaint(FXObject *,FXSelector,void * ptr)1328 long FXScrollBar::onPaint(FXObject*, FXSelector, void* ptr)
1329 {
1330 // Caution! Don't use the macro here because it's slightly different
1331
1332 static FXbool init = true;
1333 static FXbool use_clearlooks = true;
1334 static FXColor bg_topcolor, bg_bottomcolor, bg_shadecolor, bg_bordercolor, bg_lightcolor;
1335 static FXColor sb_topcolor, sb_bottomcolor, sb_shadecolor, sb_bordercolor, sb_lightcolor, scrollbarcolor;
1336
1337 register FXEvent* ev = (FXEvent*)ptr;
1338 register int total;
1339 FXDCWindow dc(this, ev);
1340
1341 // At first run, select the scrollbar style and color
1342 if (init)
1343 {
1344 use_clearlooks = getApp()->reg().readUnsignedEntry("SETTINGS", "use_clearlooks", true);
1345 scrollbarcolor = getApp()->reg().readColorEntry("SETTINGS", "scrollbarcolor", FXRGB(237, 233, 227));
1346
1347 // Compute gradient colors from the base color
1348 if (use_clearlooks)
1349 {
1350 // Decompose the base color
1351 FXuint r = FXREDVAL(backColor);
1352 FXuint g = FXGREENVAL(backColor);
1353 FXuint b = FXBLUEVAL(backColor);
1354
1355 // Compute the gradient colors from the base color (background)
1356 bg_topcolor = FXRGB(FXMIN(1.1*r, 255), FXMIN(1.1*g, 255), FXMIN(1.1*b, 255));
1357 bg_bottomcolor = FXRGB(0.9*r, 0.9*g, 0.9*b);
1358 bg_shadecolor = FXRGB(0.8*r, 0.8*g, 0.8*b);
1359 bg_bordercolor = FXRGB(0.9*r, 0.9*g, 0.9*b);
1360 bg_lightcolor = FXRGB(FXMIN(1.3*r, 255), FXMIN(1.3*g, 255), FXMIN(1.3*b, 255));
1361
1362 // Compute the gradient colors from the base color (scrollbar)
1363 r = FXREDVAL(scrollbarcolor);
1364 g = FXGREENVAL(scrollbarcolor);
1365 b = FXBLUEVAL(scrollbarcolor);
1366 sb_topcolor = FXRGB(FXMIN(1.1*r, 255), FXMIN(1.1*g, 255), FXMIN(1.1*b, 255));
1367 sb_bottomcolor = FXRGB(0.9*r, 0.9*g, 0.9*b);
1368 sb_shadecolor = FXRGB(0.8*r, 0.8*g, 0.8*b);
1369 sb_bordercolor = FXRGB(0.9*r, 0.9*g, 0.9*b);
1370 (void)sb_bordercolor; // Hack to avoid unused variable compiler warning
1371 sb_lightcolor = FXRGB(FXMIN(1.3*r, 255), FXMIN(1.3*g, 255), FXMIN(1.3*b, 255));
1372 }
1373 init = false;
1374 }
1375
1376 // Nice scrollbar with gradient and rounded corners
1377 if (use_clearlooks)
1378 {
1379 if (options&SCROLLBAR_HORIZONTAL)
1380 {
1381 total = width-height-height;
1382 if (thumbsize < total) // Scrollable
1383 {
1384 drawGradientScrollButton(dc, sb_topcolor, sb_bottomcolor, sb_shadecolor, sb_lightcolor, options, thumbpos, 0, thumbsize, height);
1385 dc.setForeground(bg_bordercolor);
1386 dc.setBackground(backColor);
1387 dc.fillRectangle(height, 0, thumbpos-height, height);
1388 dc.fillRectangle(thumbpos+thumbsize, 0, width-height-thumbpos-thumbsize, height);
1389 }
1390 else // Non-scrollable
1391 {
1392 dc.setForeground(bg_bordercolor);
1393 dc.setBackground(backColor);
1394 dc.fillRectangle(height, 0, total, height);
1395 }
1396 drawGradientArrowButton(dc, backColor, bg_topcolor, bg_bottomcolor, bg_shadecolor, bg_lightcolor, bg_bordercolor, arrowColor, options, width-height, 0, height, height, (mode == MODE_INC), _ARROW_RIGHT);
1397 drawGradientArrowButton(dc, backColor, bg_topcolor, bg_bottomcolor, bg_shadecolor, bg_lightcolor, bg_bordercolor, arrowColor, options, 0, 0, height, height, (mode == MODE_DEC), _ARROW_LEFT);
1398 }
1399
1400 // Vertical
1401 else
1402 {
1403 total = height-width-width;
1404 if (thumbsize < total) // Scrollable
1405 {
1406 drawGradientScrollButton(dc, sb_topcolor, sb_bottomcolor, sb_shadecolor, sb_lightcolor, options, 0, thumbpos, width, thumbsize);
1407 dc.setForeground(bg_bordercolor);
1408 dc.setBackground(backColor);
1409 dc.fillRectangle(0, width, width, thumbpos-width);
1410 dc.fillRectangle(0, thumbpos+thumbsize, width, height-width-thumbpos-thumbsize);
1411 }
1412 else // Non-scrollable
1413 {
1414 dc.setForeground(bg_bordercolor);
1415 dc.setBackground(backColor);
1416 dc.fillRectangle(0, width, width, total);
1417 }
1418 drawGradientArrowButton(dc, backColor, bg_topcolor, bg_bottomcolor, bg_shadecolor, bg_lightcolor, bg_bordercolor, arrowColor, options, 0, height-width, width, width, (mode == MODE_INC), _ARROW_DOWN);
1419 drawGradientArrowButton(dc, backColor, bg_topcolor, bg_bottomcolor, bg_shadecolor, bg_lightcolor, bg_bordercolor, arrowColor, options, 0, 0, width, width, (mode == MODE_DEC), _ARROW_UP);
1420 }
1421 }
1422
1423 // Standard (flat) scrollbar with selected color
1424 else
1425 {
1426 if (options&SCROLLBAR_HORIZONTAL)
1427 {
1428 total = width-height-height;
1429 if (thumbsize < total) // Scrollable
1430 {
1431 drawFlatScrollButton(dc, thumbpos, 0, thumbsize, height, 0, hiliteColor, shadowColor, borderColor, scrollbarcolor);
1432 dc.setStipple(STIPPLE_GRAY);
1433 dc.setFillStyle(FILL_OPAQUESTIPPLED);
1434 if (mode == MODE_PAGE_DEC)
1435 {
1436 dc.setForeground(backColor);
1437 dc.setBackground(shadowColor);
1438 }
1439 else
1440 {
1441 dc.setForeground(hiliteColor);
1442 dc.setBackground(backColor);
1443 }
1444 dc.fillRectangle(height, 0, thumbpos-height, height);
1445 if (mode == MODE_PAGE_INC)
1446 {
1447 dc.setForeground(backColor);
1448 dc.setBackground(shadowColor);
1449 }
1450 else
1451 {
1452 dc.setForeground(hiliteColor);
1453 dc.setBackground(backColor);
1454 }
1455 dc.fillRectangle(thumbpos+thumbsize, 0, width-height-thumbpos-thumbsize, height);
1456 }
1457 else // Non-scrollable
1458 {
1459 dc.setStipple(STIPPLE_GRAY);
1460 dc.setFillStyle(FILL_OPAQUESTIPPLED);
1461 dc.setForeground(hiliteColor);
1462 dc.setBackground(backColor);
1463 dc.fillRectangle(height, 0, total, height);
1464 }
1465 dc.setFillStyle(FILL_SOLID);
1466 drawButton(dc, width-height, 0, height, height, (mode == MODE_INC));
1467 drawRightArrow(dc, width-height, 0, height, height, (mode == MODE_INC));
1468 drawButton(dc, 0, 0, height, height, (mode == MODE_DEC));
1469 drawLeftArrow(dc, 0, 0, height, height, (mode == MODE_DEC));
1470 }
1471 else
1472 {
1473 total = height-width-width;
1474 if (thumbsize < total) // Scrollable
1475 {
1476 drawFlatScrollButton(dc, 0, thumbpos, width, thumbsize, 0, hiliteColor, shadowColor, borderColor, scrollbarcolor);
1477 dc.setStipple(STIPPLE_GRAY);
1478 dc.setFillStyle(FILL_OPAQUESTIPPLED);
1479 if (mode == MODE_PAGE_DEC)
1480 {
1481 dc.setForeground(backColor);
1482 dc.setBackground(shadowColor);
1483 }
1484 else
1485 {
1486 dc.setForeground(hiliteColor);
1487 dc.setBackground(backColor);
1488 }
1489 dc.fillRectangle(0, width, width, thumbpos-width);
1490 if (mode == MODE_PAGE_INC)
1491 {
1492 dc.setForeground(backColor);
1493 dc.setBackground(shadowColor);
1494 }
1495 else
1496 {
1497 dc.setForeground(hiliteColor);
1498 dc.setBackground(backColor);
1499 }
1500 dc.fillRectangle(0, thumbpos+thumbsize, width, height-width-thumbpos-thumbsize);
1501 }
1502 else // Non-scrollable
1503 {
1504 dc.setStipple(STIPPLE_GRAY);
1505 dc.setFillStyle(FILL_OPAQUESTIPPLED);
1506 dc.setForeground(hiliteColor);
1507 dc.setBackground(backColor);
1508 dc.fillRectangle(0, width, width, total);
1509 }
1510 dc.setFillStyle(FILL_SOLID);
1511 drawButton(dc, 0, height-width, width, width, (mode == MODE_INC));
1512 drawDownArrow(dc, 0, height-width, width, width, (mode == MODE_INC));
1513 drawButton(dc, 0, 0, width, width, (mode == MODE_DEC));
1514 drawUpArrow(dc, 0, 0, width, width, (mode == MODE_DEC));
1515 }
1516 }
1517 return(1);
1518 }
1519
1520
1521 //
1522 // Hack of FXComboBox
1523 //
1524
1525
1526 #define MENUBUTTONARROW_WIDTH 11
1527 #define MENUBUTTONARROW_HEIGHT 5
1528
1529
1530 // Small hack related to the Clearlooks theme
FXComboBox(FXComposite * p,int cols,FXObject * tgt,FXSelector sel,FXuint opts,int x,int y,int w,int h,int pl,int pr,int pt,int pb)1531 FXComboBox::FXComboBox(FXComposite* p, int cols, FXObject* tgt, FXSelector sel, FXuint opts, int x, int y, int w, int h, int pl, int pr, int pt, int pb) :
1532 FXPacker(p, opts, x, y, w, h, 0, 0, 0, 0, 0, 0)
1533 {
1534 flags |= FLAG_ENABLED;
1535 target = tgt;
1536 message = sel;
1537
1538 // !!! Hack to set options to TEXTFIELD_NORMAL instead of 0 (used by the Clearlooks theme)
1539 field = new FXTextField(this, cols, this, FXComboBox::ID_TEXT, TEXTFIELD_NORMAL, 0, 0, 0, 0, pl, pr, pt, pb);
1540 // !!! End of hack
1541
1542 if (options&COMBOBOX_STATIC)
1543 {
1544 field->setEditable(false);
1545 }
1546 pane = new FXPopup(this, FRAME_LINE);
1547 list = new FXList(pane, this, FXComboBox::ID_LIST, LIST_BROWSESELECT|LIST_AUTOSELECT|LAYOUT_FILL_X|LAYOUT_FILL_Y|SCROLLERS_TRACK|HSCROLLER_NEVER);
1548 if (options&COMBOBOX_STATIC)
1549 {
1550 list->setScrollStyle(SCROLLERS_TRACK|HSCROLLING_OFF);
1551 }
1552 button = new FXMenuButton(this, FXString::null, NULL, pane, FRAME_RAISED|FRAME_THICK|MENUBUTTON_DOWN|MENUBUTTON_ATTACH_RIGHT, 0, 0, 0, 0, 0, 0, 0, 0);
1553 button->setXOffset(border);
1554 button->setYOffset(border);
1555
1556 flags &= ~FLAG_UPDATE; // Never GUI update
1557 }
1558
1559
1560 //
1561 // Hack of FXMenuTitle
1562 //
1563
1564 // This hack adds an optional gradient with rounded corner theme to the menu title (Clearlooks)
1565
1566 // Handle repaint
onPaint(FXObject *,FXSelector,void * ptr)1567 long FXMenuTitle::onPaint(FXObject*, FXSelector, void* ptr)
1568 {
1569 // Initialize Clearlooks
1570 FXColor baseColor = backColor;
1571 INIT_CLEARLOOKS
1572
1573 FXEvent* ev = (FXEvent*)ptr;
1574 FXDCWindow dc(this, ev);
1575 FXint xx, yy;
1576
1577 dc.setFont(font);
1578 xx = 6;
1579 yy = 0;
1580
1581 if (isEnabled())
1582 {
1583 if (isActive())
1584 {
1585 // Button with nice gradient effect and rounded corners (Clearlooks)
1586 if (use_clearlooks)
1587 {
1588 dc.setForeground(selbackColor);
1589 dc.fillRectangle(0, 0, width, height);
1590 dc.setForeground(backColor);
1591 dc.drawPoints(basebackground, 4);
1592 dc.setForeground(bordercolor);
1593 dc.drawRectangle(2, 0, width-5, 0);
1594 dc.drawRectangle(2, height-1, width-5, height-1);
1595 dc.drawRectangle(0, 2, 0, height-5);
1596 dc.drawRectangle(width-1, 2, 0, height-5);
1597 dc.drawPoints(bordercorners, 4);
1598 dc.setForeground(selbackColor);
1599 dc.drawPoints(bordershade, 16);
1600 }
1601
1602 // Normal flat rectangular button
1603 else
1604 {
1605 dc.setForeground(selbackColor);
1606 dc.fillRectangle(1, 1, width-2, height-2);
1607 dc.setForeground(shadowColor);
1608 dc.fillRectangle(0, 0, width, 1);
1609 dc.fillRectangle(0, 0, 1, height);
1610 dc.setForeground(hiliteColor);
1611 dc.fillRectangle(0, height-1, width, 1);
1612 dc.fillRectangle(width-1, 0, 1, height);
1613 }
1614 xx++;
1615 yy++;
1616 }
1617 else if (underCursor())
1618 {
1619 // Button with nice gradient effect and rounded corners (Clearlooks)
1620 if (use_clearlooks)
1621 {
1622 DRAW_CLEARLOOKS_BUTTON_UP
1623 }
1624
1625 // Normal flat rectangular button
1626 else
1627 {
1628 dc.setForeground(backColor);
1629 dc.fillRectangle(1, 1, width-2, height-2);
1630 dc.setForeground(shadowColor);
1631 dc.fillRectangle(0, height-1, width, 1);
1632 dc.fillRectangle(width-1, 0, 1, height);
1633 dc.setForeground(hiliteColor);
1634 dc.fillRectangle(0, 0, width, 1);
1635 dc.fillRectangle(0, 0, 1, height);
1636 }
1637 }
1638
1639 else
1640 {
1641 dc.setForeground(backColor);
1642 dc.fillRectangle(0, 0, width, height);
1643 }
1644
1645 if (icon)
1646 {
1647 dc.drawIcon(icon, xx, yy+(height-icon->getHeight())/2);
1648 xx += 5+icon->getWidth();
1649 }
1650
1651 if (!label.empty())
1652 {
1653 yy += font->getFontAscent()+(height-font->getFontHeight())/2;
1654 dc.setForeground(isActive() ? seltextColor : textColor);
1655 dc.drawText(xx, yy, label);
1656 if (0 <= hotoff)
1657 {
1658 dc.fillRectangle(xx+font->getTextWidth(&label[0], hotoff), yy+1, font->getTextWidth(&label[hotoff], wclen(&label[hotoff])), 1);
1659 }
1660 }
1661 }
1662
1663 else
1664 {
1665 dc.setForeground(backColor);
1666 dc.fillRectangle(0, 0, width, height);
1667 if (icon)
1668 {
1669 dc.drawIconSunken(icon, xx, yy+(height-icon->getHeight())/2);
1670 xx += 5+icon->getWidth();
1671 }
1672 if (!label.empty())
1673 {
1674 yy += font->getFontAscent()+(height-font->getFontHeight())/2;
1675 dc.setForeground(hiliteColor);
1676 dc.drawText(xx+1, yy+1, label);
1677 if (0 <= hotoff)
1678 {
1679 dc.fillRectangle(xx+font->getTextWidth(&label[0], hotoff), yy+1, font->getTextWidth(&label[hotoff], wclen(&label[hotoff])), 1);
1680 }
1681 dc.setForeground(shadowColor);
1682 dc.drawText(xx, yy, label);
1683 if (0 <= hotoff)
1684 {
1685 dc.fillRectangle(xx+font->getTextWidth(&label[0], hotoff), yy+1, font->getTextWidth(&label[hotoff], wclen(&label[hotoff])), 1);
1686 }
1687 }
1688 }
1689
1690 return(1);
1691 }
1692
1693
1694 //
1695 // Hack of FXRadioButton
1696 //
1697
1698 // Includes HiDPI scaling
1699
1700
1701 // Handle repaint
onPaint(FXObject *,FXSelector,void * ptr)1702 long FXRadioButton::onPaint(FXObject*, FXSelector, void* ptr)
1703 {
1704 // Initialize Clearlooks (don't use the macro because here it's different)
1705 static FXbool init = true;
1706 static FXbool use_clearlooks = true;
1707 static FXColor bordercolor;
1708
1709 if (init)
1710 {
1711 use_clearlooks = getApp()->reg().readUnsignedEntry("SETTINGS", "use_clearlooks", true);
1712
1713 if (use_clearlooks)
1714 {
1715 FXuint r = FXREDVAL(baseColor);
1716 FXuint g = FXGREENVAL(baseColor);
1717 FXuint b = FXBLUEVAL(baseColor);
1718
1719 bordercolor = FXRGB(0.5*r, 0.5*g, 0.5*b);
1720 }
1721 init = false;
1722 }
1723
1724 FXEvent* ev = (FXEvent*)ptr;
1725 FXint tw = 0, th = 0, tx, ty, ix, iy;
1726 FXRectangle recs[6];
1727 FXDCWindow dc(this, ev);
1728
1729 dc.setForeground(backColor);
1730 dc.fillRectangle(ev->rect.x, ev->rect.y, ev->rect.w, ev->rect.h);
1731
1732 if (!label.empty())
1733 {
1734 tw = labelWidth(label);
1735 th = labelHeight(label);
1736 }
1737
1738 // Placement
1739 just_x(tx, ix, tw, scaleint * 13);
1740 just_y(ty, iy, th, scaleint * 13);
1741 ix = FXMAX(ix, 0);
1742 iy = FXMAX(iy, 0);
1743
1744 // Inside
1745 recs[0].x = ix+4*scaleint;
1746 recs[0].y = iy+2*scaleint;
1747 recs[0].w = 4*scaleint;
1748 recs[0].h = 1*scaleint;
1749 recs[1].x = ix+3*scaleint;
1750 recs[1].y = iy+3*scaleint;
1751 recs[1].w = 6*scaleint;
1752 recs[1].h = 1*scaleint;
1753 recs[2].x = ix+2*scaleint;
1754 recs[2].y = iy+4*scaleint;
1755 recs[2].w = 8*scaleint;
1756 recs[2].h = 4*scaleint;
1757 recs[3].x = ix+3*scaleint;
1758 recs[3].y = iy+8*scaleint;
1759 recs[3].w = 6*scaleint;
1760 recs[3].h = 1*scaleint;
1761 recs[4].x = ix+4*scaleint;
1762 recs[4].y = iy+9*scaleint;
1763 recs[4].w = 4*scaleint;
1764 recs[4].h = 1*scaleint;
1765
1766 if (!isEnabled()) // fix by Daniel Gehriger (gehriger@linkcad.com)
1767 {
1768 dc.setForeground(baseColor);
1769 }
1770 else
1771 {
1772 dc.setForeground(diskColor);
1773 }
1774 dc.fillRectangles(recs, 5);
1775
1776 // Radio button with Clearlooks appearance
1777 if (use_clearlooks)
1778 {
1779 // Top left inside
1780 recs[0].x = ix+4*scaleint;
1781 recs[0].y = iy+1*scaleint;
1782 recs[0].w = 4*scaleint;
1783 recs[0].h = 1*scaleint;
1784 recs[1].x = ix+2*scaleint;
1785 recs[1].y = iy+2*scaleint;
1786 recs[1].w = 2*scaleint;
1787 recs[1].h = 1*scaleint;
1788 recs[2].x = ix+8*scaleint;
1789 recs[2].y = iy+2*scaleint;
1790 recs[2].w = 2*scaleint;
1791 recs[2].h = 1*scaleint;
1792 recs[3].x = ix+2*scaleint;
1793 recs[3].y = iy+3*scaleint;
1794 recs[3].w = 1*scaleint;
1795 recs[3].h = 1*scaleint;
1796 recs[4].x = ix+1*scaleint;
1797 recs[4].y = iy+4*scaleint;
1798 recs[4].w = 1*scaleint;
1799 recs[4].h = 4*scaleint;
1800 recs[5].x = ix+2*scaleint;
1801 recs[5].y = iy+8*scaleint;
1802 recs[5].w = 1*scaleint;
1803 recs[5].h = 2*scaleint;
1804 dc.setForeground(bordercolor);
1805 dc.fillRectangles(recs, 6);
1806
1807 // Bottom right inside
1808 recs[0].x = ix+9*scaleint;
1809 recs[0].y = iy+3*scaleint;
1810 recs[0].w = 1*scaleint;
1811 recs[0].h = 1*scaleint;
1812 recs[1].x = ix+10*scaleint;
1813 recs[1].y = iy+4*scaleint;
1814 recs[1].w = 1*scaleint;
1815 recs[1].h = 4*scaleint;
1816 recs[2].x = ix+9*scaleint;
1817 recs[2].y = iy+8*scaleint;
1818 recs[2].w = 1*scaleint;
1819 recs[2].h = 1*scaleint;
1820 recs[3].x = ix+8*scaleint;
1821 recs[3].y = iy+9*scaleint;
1822 recs[3].w = 2*scaleint;
1823 recs[3].h = 1*scaleint;
1824 recs[4].x = ix+3*scaleint;
1825 recs[4].y = iy+9*scaleint;
1826 recs[4].w = 1*scaleint;
1827 recs[4].h = 1*scaleint;
1828 recs[5].x = ix+4*scaleint;
1829 recs[5].y = iy+10*scaleint;
1830 recs[5].w = 4*scaleint;
1831 recs[5].h = 1*scaleint;
1832 dc.setForeground(bordercolor);
1833 dc.fillRectangles(recs, 6);
1834 }
1835
1836 // Standard radio button
1837 else
1838 {
1839 // Top left outside
1840 recs[0].x = ix+4*scaleint;
1841 recs[0].y = iy+0*scaleint;
1842 recs[0].w = 4*scaleint;
1843 recs[0].h = 1*scaleint;
1844 recs[1].x = ix+2*scaleint;
1845 recs[1].y = iy+1*scaleint;
1846 recs[1].w = 2*scaleint;
1847 recs[1].h = 1*scaleint;
1848 recs[2].x = ix+8*scaleint;
1849 recs[2].y = iy+1*scaleint;
1850 recs[2].w = 2*scaleint;
1851 recs[2].h = 1*scaleint;
1852 recs[3].x = ix+1*scaleint;
1853 recs[3].y = iy+2*scaleint;
1854 recs[3].w = 1*scaleint;
1855 recs[3].h = 2*scaleint;
1856 recs[4].x = ix+0*scaleint;
1857 recs[4].y = iy+4*scaleint;
1858 recs[4].w = 1*scaleint;
1859 recs[4].h = 4*scaleint;
1860 recs[5].x = ix+1*scaleint;
1861 recs[5].y = iy+8*scaleint;
1862 recs[5].w = 1*scaleint;
1863 recs[5].h = 2*scaleint;
1864 dc.setForeground(shadowColor);
1865 dc.fillRectangles(recs, 6);
1866
1867 // Top left inside
1868 recs[0].x = ix+4*scaleint;
1869 recs[0].y = iy+1*scaleint;
1870 recs[0].w = 4*scaleint;
1871 recs[0].h = 1*scaleint;
1872 recs[1].x = ix+2*scaleint;
1873 recs[1].y = iy+2*scaleint;
1874 recs[1].w = 2*scaleint;
1875 recs[1].h = 1*scaleint;
1876 recs[2].x = ix+8*scaleint;
1877 recs[2].y = iy+2*scaleint;
1878 recs[2].w = 2*scaleint;
1879 recs[2].h = 1*scaleint;
1880 recs[3].x = ix+2*scaleint;
1881 recs[3].y = iy+3*scaleint;
1882 recs[3].w = 1*scaleint;
1883 recs[3].h = 1*scaleint;
1884 recs[4].x = ix+1*scaleint;
1885 recs[4].y = iy+4*scaleint;
1886 recs[4].w = 1*scaleint;
1887 recs[4].h = 4*scaleint;
1888 recs[5].x = ix+2*scaleint;
1889 recs[5].y = iy+8*scaleint;
1890 recs[5].w = 1*scaleint;
1891 recs[5].h = 2*scaleint;
1892 dc.setForeground(borderColor);
1893 dc.fillRectangles(recs, 6);
1894
1895 // Bottom right outside
1896 recs[0].x = ix+10*scaleint;
1897 recs[0].y = iy+2*scaleint;
1898 recs[0].w = 1*scaleint;
1899 recs[0].h = 2*scaleint;
1900 recs[1].x = ix+11*scaleint;
1901 recs[1].y = iy+4*scaleint;
1902 recs[1].w = 1*scaleint;
1903 recs[1].h = 4*scaleint;
1904 recs[2].x = ix+10*scaleint;
1905 recs[2].y = iy+8*scaleint;
1906 recs[2].w = 1*scaleint;
1907 recs[2].h = 2*scaleint;
1908 recs[3].x = ix+8*scaleint;
1909 recs[3].y = iy+10*scaleint;
1910 recs[3].w = 2*scaleint;
1911 recs[3].h = 1*scaleint;
1912 recs[4].x = ix+2*scaleint;
1913 recs[4].y = iy+10*scaleint;
1914 recs[4].w = 2*scaleint;
1915 recs[4].h = 1*scaleint;
1916 recs[5].x = ix+4*scaleint;
1917 recs[5].y = iy+11*scaleint;
1918 recs[5].w = 4*scaleint;
1919 recs[5].h = 1*scaleint;
1920 dc.setForeground(hiliteColor);
1921 dc.fillRectangles(recs, 6);
1922
1923 // Bottom right inside
1924 recs[0].x = ix+9*scaleint;
1925 recs[0].y = iy+3*scaleint;
1926 recs[0].w = 1*scaleint;
1927 recs[0].h = 1*scaleint;
1928 recs[1].x = ix+10*scaleint;
1929 recs[1].y = iy+4*scaleint;
1930 recs[1].w = 1*scaleint;
1931 recs[1].h = 4*scaleint;
1932 recs[2].x = ix+9*scaleint;
1933 recs[2].y = iy+8*scaleint;
1934 recs[2].w = 1*scaleint;
1935 recs[2].h = 1*scaleint;
1936 recs[3].x = ix+8*scaleint;
1937 recs[3].y = iy+9*scaleint;
1938 recs[3].w = 2*scaleint;
1939 recs[3].h = 1*scaleint;
1940 recs[4].x = ix+3*scaleint;
1941 recs[4].y = iy+9*scaleint;
1942 recs[4].w = 1*scaleint;
1943 recs[4].h = 1*scaleint;
1944 recs[5].x = ix+4*scaleint;
1945 recs[5].y = iy+10*scaleint;
1946 recs[5].w = 4*scaleint;
1947 recs[5].h = 1*scaleint;
1948 dc.setForeground(baseColor);
1949 dc.fillRectangles(recs, 6);
1950 }
1951
1952 // Ball inside
1953 if (check != false)
1954 {
1955 recs[0].x = ix+5*scaleint;
1956 recs[0].y = iy+4*scaleint;
1957 recs[0].w = 2*scaleint;
1958 recs[0].h = 1*scaleint;
1959 recs[1].x = ix+4*scaleint;
1960 recs[1].y = iy+5*scaleint;
1961 recs[1].w = 4*scaleint;
1962 recs[1].h = 2*scaleint;
1963 recs[2].x = ix+5*scaleint;
1964 recs[2].y = iy+7*scaleint;
1965 recs[2].w = 2*scaleint;
1966 recs[2].h = 1*scaleint;
1967 if (isEnabled())
1968 {
1969 dc.setForeground(radioColor);
1970 }
1971 else
1972 {
1973 dc.setForeground(shadowColor);
1974 }
1975 dc.fillRectangles(recs, 3);
1976 }
1977
1978 // Label
1979 if (!label.empty())
1980 {
1981 dc.setFont(font);
1982 if (isEnabled())
1983 {
1984 dc.setForeground(textColor);
1985 drawLabel(dc, label, hotoff, tx, ty, tw, th);
1986 if (hasFocus())
1987 {
1988 dc.drawFocusRectangle(tx-1, ty-1, tw+2*scaleint, th+2);
1989 }
1990 }
1991 else
1992 {
1993 dc.setForeground(hiliteColor);
1994 drawLabel(dc, label, hotoff, tx+1, ty+1, tw, th);
1995 dc.setForeground(shadowColor);
1996 drawLabel(dc, label, hotoff, tx, ty, tw, th);
1997 }
1998 }
1999 drawFrame(dc, 0, 0, width, height);
2000 return(1);
2001 }
2002
2003
2004 //
2005 // Hack of FXMenuButton
2006 //
2007
2008
2009
2010 // Handle repaint
onPaint(FXObject *,FXSelector,void * ptr)2011 long FXMenuButton::onPaint(FXObject*, FXSelector, void* ptr)
2012 {
2013 // Initialize Clearlooks
2014 INIT_CLEARLOOKS
2015
2016 int tw = 0, th = 0, iw = 0, ih = 0, tx, ty, ix, iy;
2017 FXEvent* ev = (FXEvent*)ptr;
2018 FXPoint points[3];
2019 FXDCWindow dc(this, ev);
2020
2021 // Button with nice gradient effect and rounded corners (Clearlooks)
2022 if (use_clearlooks)
2023 {
2024 // Toolbar style
2025 if (options&MENUBUTTON_TOOLBAR)
2026 {
2027 // Enabled and cursor inside, and not popped up
2028 if (isEnabled() && underCursor() && !state)
2029 {
2030 DRAW_CLEARLOOKS_BUTTON_DOWN
2031 }
2032
2033 // Enabled and popped up
2034 else if (isEnabled() && state)
2035 {
2036 DRAW_CLEARLOOKS_BUTTON_UP
2037 }
2038
2039 // Disabled or unchecked or not under cursor
2040 else
2041 {
2042 dc.setForeground(backColor);
2043 dc.fillRectangle(0, 0, width, height);
2044 }
2045 }
2046
2047 // Normal style
2048 else
2049 {
2050 // Draw in up state if disabled or up
2051 if (!isEnabled() || !state)
2052 {
2053 DRAW_CLEARLOOKS_BUTTON_UP
2054 }
2055
2056 // If enabled and either checked or pressed
2057 else
2058 {
2059 DRAW_CLEARLOOKS_BUTTON_DOWN
2060 }
2061 }
2062 } // End of gradient painting
2063
2064
2065 // Normal flat rectangular button
2066 else
2067 {
2068 // Got a border at all?
2069 if (options&(FRAME_RAISED|FRAME_SUNKEN))
2070 {
2071 // Toolbar style
2072 if (options&MENUBUTTON_TOOLBAR)
2073 {
2074 // Enabled and cursor inside, and not popped up
2075 if (isEnabled() && underCursor() && !state)
2076 {
2077 DRAW_STANDARD_BUTTON_DOWN
2078 }
2079
2080 // Enabled and popped up
2081 else if (isEnabled() && state)
2082 {
2083 DRAW_STANDARD_BUTTON_UP
2084 }
2085
2086 // Disabled or unchecked or not under cursor
2087 else
2088 {
2089 dc.setForeground(backColor);
2090 dc.fillRectangle(0, 0, width, height);
2091 }
2092 }
2093
2094 // Normal style
2095 else
2096 {
2097 // Draw in up state if disabled or up
2098 if (!isEnabled() || !state)
2099 {
2100 DRAW_STANDARD_BUTTON_UP
2101 }
2102
2103 // Draw sunken if enabled and either checked or pressed
2104 else
2105 {
2106 DRAW_STANDARD_BUTTON_DOWN
2107 }
2108 }
2109 }
2110
2111 // No borders
2112 else
2113 {
2114 if (isEnabled() && state)
2115 {
2116 dc.setForeground(hiliteColor);
2117 dc.fillRectangle(0, 0, width, height);
2118 }
2119 else
2120 {
2121 dc.setForeground(backColor);
2122 dc.fillRectangle(0, 0, width, height);
2123 }
2124 }
2125 } // End of normal painting
2126
2127 // Position text & icon
2128 if (!label.empty())
2129 {
2130 tw = labelWidth(label);
2131 th = labelHeight(label);
2132 }
2133
2134 // Icon?
2135 if (icon)
2136 {
2137 iw = icon->getWidth();
2138 ih = icon->getHeight();
2139 }
2140
2141 // Arrows?
2142 else if (!(options&MENUBUTTON_NOARROWS))
2143 {
2144 if (options&MENUBUTTON_LEFT)
2145 {
2146 ih = MENUBUTTONARROW_WIDTH;
2147 iw = MENUBUTTONARROW_HEIGHT;
2148 }
2149 else
2150 {
2151 iw = MENUBUTTONARROW_WIDTH;
2152 ih = MENUBUTTONARROW_HEIGHT;
2153 }
2154 }
2155
2156 // Keep some room for the arrow!
2157 just_x(tx, ix, tw, iw);
2158 just_y(ty, iy, th, ih);
2159
2160 // Move a bit when pressed
2161 if (state)
2162 {
2163 ++tx;
2164 ++ty;
2165 ++ix;
2166 ++iy;
2167 }
2168
2169 // Draw icon
2170 if (icon)
2171 {
2172 if (isEnabled())
2173 {
2174 dc.drawIcon(icon, ix, iy);
2175 }
2176 else
2177 {
2178 dc.drawIconSunken(icon, ix, iy);
2179 }
2180 }
2181
2182 // Draw arrows
2183 else if (!(options&MENUBUTTON_NOARROWS))
2184 {
2185 // Right arrow
2186 if ((options&MENUBUTTON_RIGHT) == MENUBUTTON_RIGHT)
2187 {
2188 if (isEnabled())
2189 {
2190 dc.setForeground(textColor);
2191 }
2192 else
2193 {
2194 dc.setForeground(shadowColor);
2195 }
2196 points[0].x = ix;
2197 points[0].y = iy;
2198 points[1].x = ix;
2199 points[1].y = iy+MENUBUTTONARROW_WIDTH-1;
2200 points[2].x = ix+MENUBUTTONARROW_HEIGHT;
2201 points[2].y = (short)(iy+(MENUBUTTONARROW_WIDTH>>1));
2202 dc.fillPolygon(points, 3);
2203 }
2204
2205 // Left arrow
2206 else if (options&MENUBUTTON_LEFT)
2207 {
2208 if (isEnabled())
2209 {
2210 dc.setForeground(textColor);
2211 }
2212 else
2213 {
2214 dc.setForeground(shadowColor);
2215 }
2216 points[0].x = ix+MENUBUTTONARROW_HEIGHT;
2217 points[0].y = iy;
2218 points[1].x = ix+MENUBUTTONARROW_HEIGHT;
2219 points[1].y = iy+MENUBUTTONARROW_WIDTH-1;
2220 points[2].x = ix;
2221 points[2].y = (short)(iy+(MENUBUTTONARROW_WIDTH>>1));
2222 dc.fillPolygon(points, 3);
2223 }
2224
2225 // Up arrow
2226 else if (options&MENUBUTTON_UP)
2227 {
2228 if (isEnabled())
2229 {
2230 dc.setForeground(textColor);
2231 }
2232 else
2233 {
2234 dc.setForeground(shadowColor);
2235 }
2236 points[0].x = (short)(ix+(MENUBUTTONARROW_WIDTH>>1));
2237 points[0].y = iy-1;
2238 points[1].x = ix;
2239 points[1].y = iy+MENUBUTTONARROW_HEIGHT;
2240 points[2].x = ix+MENUBUTTONARROW_WIDTH;
2241 points[2].y = iy+MENUBUTTONARROW_HEIGHT;
2242 dc.fillPolygon(points, 3);
2243 }
2244
2245 // Down arrow
2246 else
2247 {
2248 if (isEnabled())
2249 {
2250 dc.setForeground(textColor);
2251 }
2252 else
2253 {
2254 dc.setForeground(shadowColor);
2255 }
2256 points[0].x = ix+1;
2257 points[0].y = iy;
2258 points[2].x = ix+MENUBUTTONARROW_WIDTH-1;
2259 points[2].y = iy;
2260 points[1].x = (short)(ix+(MENUBUTTONARROW_WIDTH>>1));
2261 points[1].y = iy+MENUBUTTONARROW_HEIGHT;
2262 dc.fillPolygon(points, 3);
2263 }
2264 }
2265
2266 // Draw text
2267 if (!label.empty())
2268 {
2269 dc.setFont(font);
2270 if (isEnabled())
2271 {
2272 dc.setForeground(textColor);
2273 drawLabel(dc, label, hotoff, tx, ty, tw, th);
2274 }
2275 else
2276 {
2277 dc.setForeground(hiliteColor);
2278 drawLabel(dc, label, hotoff, tx+1, ty+1, tw, th);
2279 dc.setForeground(shadowColor);
2280 drawLabel(dc, label, hotoff, tx, ty, tw, th);
2281 }
2282 }
2283
2284 // Draw focus
2285 if (hasFocus())
2286 {
2287 if (isEnabled())
2288 {
2289 dc.drawFocusRectangle(border+1, border+1, width-2*border-2, height-2*border-2);
2290 }
2291 }
2292 return(1);
2293 }
2294
2295
2296 //
2297 // Hack of FXArrowButton
2298 //
2299
2300
2301 // Handle repaint
onPaint(FXObject *,FXSelector,void * ptr)2302 long FXArrowButton::onPaint(FXObject*, FXSelector, void* ptr)
2303 {
2304 // Initialize Clearlooks
2305 INIT_CLEARLOOKS
2306
2307 FXEvent* ev = (FXEvent*)ptr;
2308 FXDCWindow dc(this, ev);
2309 FXPoint points[3];
2310 int xx, yy, ww, hh, q;
2311
2312 // Button with nice gradient effect and rounded corners (Clearlooks)
2313 if (use_clearlooks)
2314 {
2315 // Toolbar style
2316 if (options&ARROW_TOOLBAR)
2317 {
2318 // Enabled and cursor inside, and up
2319 if (isEnabled() && underCursor() && !state)
2320 {
2321 DRAW_CLEARLOOKS_BUTTON_UP
2322 }
2323
2324 // Enabled and cursor inside and down
2325 else if (isEnabled() && state)
2326 {
2327 DRAW_CLEARLOOKS_BUTTON_DOWN
2328 }
2329
2330 // Disabled or unchecked or not under cursor
2331 else
2332 {
2333 dc.setForeground(backColor);
2334 dc.fillRectangle(0, 0, width, height);
2335 }
2336 }
2337
2338 // Normal style
2339 else
2340 {
2341 // Draw sunken if enabled and pressed
2342 if (isEnabled() && state)
2343 {
2344 DRAW_CLEARLOOKS_BUTTON_DOWN
2345 }
2346
2347 // Draw in up state if disabled or up
2348 else
2349 {
2350 DRAW_CLEARLOOKS_BUTTON_UP
2351 }
2352 }
2353 } // End of gradient painting
2354
2355 // Normal flat rectangular button
2356 else
2357 {
2358 // With borders
2359 if (options&(FRAME_RAISED|FRAME_SUNKEN))
2360 {
2361 // Toolbar style
2362 if (options&ARROW_TOOLBAR)
2363 {
2364 // Enabled and cursor inside, and up
2365 if (isEnabled() && underCursor() && !state)
2366 {
2367 DRAW_STANDARD_BUTTON_UP
2368 }
2369
2370 // Enabled and cursor inside and down
2371 else if (isEnabled() && state)
2372 {
2373 DRAW_STANDARD_BUTTON_DOWN
2374 }
2375
2376 // Disabled or unchecked or not under cursor
2377 else
2378 {
2379 dc.setForeground(backColor);
2380 dc.fillRectangle(0, 0, width, height);
2381 }
2382 }
2383
2384 // Normal style
2385 else
2386 {
2387 // Draw sunken if enabled and pressed
2388 if (isEnabled() && state)
2389 {
2390 DRAW_STANDARD_BUTTON_DOWN
2391 }
2392
2393 // Draw in up state if disabled or up
2394 else
2395 {
2396 DRAW_STANDARD_BUTTON_UP
2397 }
2398 }
2399 }
2400
2401 // No borders
2402 else
2403 {
2404 if (isEnabled() && state)
2405 {
2406 dc.setForeground(hiliteColor);
2407 dc.fillRectangle(0, 0, width, height);
2408 }
2409 else
2410 {
2411 dc.setForeground(backColor);
2412 dc.fillRectangle(0, 0, width, height);
2413 }
2414 }
2415 } // End of normal painting
2416
2417 // Compute size of the arrows....
2418 ww = width-padleft-padright-(border<<1);
2419 hh = height-padtop-padbottom-(border<<1);
2420 if (options&(ARROW_UP|ARROW_DOWN))
2421 {
2422 q = ww|1;
2423 if (q > (hh<<1))
2424 {
2425 q = (hh<<1)-1;
2426 }
2427 ww = q;
2428 hh = q>>1;
2429 }
2430 else
2431 {
2432 q = hh|1;
2433 if (q > (ww<<1))
2434 {
2435 q = (ww<<1)-1;
2436 }
2437 ww = q>>1;
2438 hh = q;
2439 }
2440
2441 if (options&JUSTIFY_LEFT)
2442 {
2443 xx = padleft+border;
2444 }
2445 else if (options&JUSTIFY_RIGHT)
2446 {
2447 xx = width-ww-padright-border;
2448 }
2449 else
2450 {
2451 xx = (width-ww)/2;
2452 }
2453
2454 if (options&JUSTIFY_TOP)
2455 {
2456 yy = padtop+border;
2457 }
2458 else if (options&JUSTIFY_BOTTOM)
2459 {
2460 yy = height-hh-padbottom-border;
2461 }
2462 else
2463 {
2464 yy = (height-hh)/2;
2465 }
2466
2467 if (state)
2468 {
2469 ++xx;
2470 ++yy;
2471 }
2472
2473 if (isEnabled())
2474 {
2475 dc.setForeground(arrowColor);
2476 }
2477 else
2478 {
2479 dc.setForeground(shadowColor);
2480 }
2481
2482 // NB Size of arrow should stretch
2483 if (options&ARROW_UP)
2484 {
2485 points[0].x = xx+(ww>>1);
2486 points[0].y = yy-1;
2487 points[1].x = xx;
2488 points[1].y = yy+hh;
2489 points[2].x = xx+ww;
2490 points[2].y = yy+hh;
2491 dc.fillPolygon(points, 3);
2492 }
2493 else if (options&ARROW_DOWN)
2494 {
2495 points[0].x = xx+1;
2496 points[0].y = yy;
2497 points[1].x = xx+ww-1;
2498 points[1].y = yy;
2499 points[2].x = xx+(ww>>1);
2500 points[2].y = yy+hh;
2501 dc.fillPolygon(points, 3);
2502 }
2503 else if (options&ARROW_LEFT)
2504 {
2505 points[0].x = xx+ww;
2506 points[0].y = yy;
2507 points[1].x = xx+ww;
2508 points[1].y = yy+hh-1;
2509 points[2].x = xx;
2510 points[2].y = yy+(hh>>1);
2511 dc.fillPolygon(points, 3);
2512 }
2513 else if (options&ARROW_RIGHT)
2514 {
2515 points[0].x = xx;
2516 points[0].y = yy;
2517 points[1].x = xx;
2518 points[1].y = yy+hh-1;
2519 points[2].x = xx+ww;
2520 points[2].y = yy+(hh>>1);
2521 dc.fillPolygon(points, 3);
2522 }
2523 return(1);
2524 }
2525
2526
2527 //
2528 // Hack of FXProgressBar
2529 //
2530
2531 // Note : Not implemented for the dial and vertical progress bar!
2532 // This hacks assumes that border = 2
2533
2534
2535 // Draw only the interior, i.e. the part that changes
drawInterior(FXDCWindow & dc)2536 void FXProgressBar::drawInterior(FXDCWindow& dc)
2537 {
2538 static FXbool init = true;
2539 static FXbool use_clearlooks = true;
2540 static FXColor topcolor, bottomcolor, bordercolor;
2541
2542 FXPoint bordercorners[4] = { FXPoint(1, 1), FXPoint(1, height-2), FXPoint(width-2, 1),
2543 FXPoint(width-2, height-2) };
2544
2545 // Init Clearlooks (don't use the macro because here it's different)
2546 if (init)
2547 {
2548 use_clearlooks = getApp()->reg().readUnsignedEntry("SETTINGS", "use_clearlooks", true);
2549
2550 if (use_clearlooks)
2551 {
2552 FXuint r = FXREDVAL(barColor);
2553 FXuint g = FXGREENVAL(barColor);
2554 FXuint b = FXBLUEVAL(barColor);
2555
2556 topcolor = FXRGB(FXMIN(1.2*r, 255), FXMIN(1.2*g, 255), FXMIN(1.2*b, 255));
2557 bottomcolor = FXRGB(0.9*r, 0.9*g, 0.9*b);
2558
2559 r = FXREDVAL(baseColor);
2560 g = FXGREENVAL(baseColor);
2561 b = FXBLUEVAL(baseColor);
2562
2563 bordercolor = FXRGB(0.5*r, 0.5*g, 0.5*b);
2564 }
2565 init = false;
2566 }
2567
2568 int percent, barlength, barfilled, tx, ty, tw, th, n, d;
2569 char numtext[6];
2570
2571 if (options&PROGRESSBAR_DIAL)
2572 {
2573 // If total is 0, it's 100%
2574 barfilled = 23040;
2575 percent = 100;
2576 if (total != 0)
2577 {
2578 barfilled = (FXuint)(((double)progress * (double)23040) / (double)total);
2579 percent = (FXuint)(((double)progress * 100.0) / (double)total);
2580 }
2581
2582 tw = width-(border<<1)-padleft-padright;
2583 th = height-(border<<1)-padtop-padbottom;
2584 d = FXMIN(tw, th)-1;
2585
2586 tx = border+padleft+((tw-d)/2);
2587 ty = border+padtop+((th-d)/2);
2588
2589 if (barfilled != 23040)
2590 {
2591 dc.setForeground(barBGColor);
2592 dc.fillArc(tx, ty, d, d, 5760, 23040-barfilled);
2593 }
2594 if (barfilled != 0)
2595 {
2596 dc.setForeground(barColor);
2597 dc.fillArc(tx, ty, d, d, 5760, -barfilled);
2598 }
2599
2600 // Draw outside circle
2601 dc.setForeground(borderColor);
2602 dc.drawArc(tx+1, ty, d, d, 90*64, 45*64);
2603 dc.drawArc(tx, ty+1, d, d, 135*64, 45*64);
2604 dc.setForeground(baseColor);
2605 dc.drawArc(tx-1, ty, d, d, 270*64, 45*64);
2606 dc.drawArc(tx, ty-1, d, d, 315*64, 45*64);
2607
2608 dc.setForeground(shadowColor);
2609 dc.drawArc(tx, ty, d, d, 45*64, 180*64);
2610 dc.setForeground(hiliteColor);
2611 dc.drawArc(tx, ty, d, d, 225*64, 180*64);
2612
2613 // Draw text
2614 if (options&PROGRESSBAR_PERCENTAGE)
2615 {
2616 dc.setFont(font);
2617 tw = font->getTextWidth("100%", 4);
2618 if (tw > (10*d)/16)
2619 {
2620 return;
2621 }
2622 th = font->getFontHeight();
2623 if (th > d/2)
2624 {
2625 return;
2626 }
2627 snprintf(numtext, sizeof(numtext)-1, "%d%%", percent);
2628 n = strlen(numtext);
2629 tw = font->getTextWidth(numtext, n);
2630 th = font->getFontHeight();
2631 tx = tx+d/2-tw/2;
2632 ty = ty+d/2+font->getFontAscent()+5;
2633 //dc.setForeground(textNumColor);
2634 #ifdef HAVE_XFT_H
2635 dc.setForeground(barBGColor); // Code for XFT until XFT can use BLT_SRC_XOR_DST
2636 dc.drawText(tx-1, ty, numtext, n);
2637 dc.drawText(tx+1, ty, numtext, n);
2638 dc.drawText(tx, ty-1, numtext, n);
2639 dc.drawText(tx, ty+1, numtext, n);
2640 dc.setForeground(textNumColor);
2641 dc.drawText(tx, ty, numtext, n);
2642 #else
2643 dc.setForeground(FXRGB(255, 255, 255)); // Original code
2644 dc.setFunction(BLT_SRC_XOR_DST);
2645 dc.drawText(tx, ty, numtext, n);
2646 #endif
2647 }
2648 }
2649
2650 // Vertical bar
2651 else if (options&PROGRESSBAR_VERTICAL)
2652 {
2653 // If total is 0, it's 100%
2654 barlength = height-border-border;
2655 barfilled = barlength;
2656 percent = 100;
2657
2658 if (total != 0)
2659 {
2660 barfilled = (FXuint)(((double)progress * (double)barlength) / (double)total);
2661 percent = (FXuint)(((double)progress * 100.0) / (double)total);
2662 }
2663
2664 // Draw completed bar
2665 if (0 < barfilled)
2666 {
2667 dc.setForeground(barColor);
2668 dc.fillRectangle(border, height-border-barfilled, width-(border<<1), barfilled);
2669 }
2670
2671 // Draw uncompleted bar
2672 if (barfilled < barlength)
2673 {
2674 dc.setForeground(barBGColor);
2675 dc.fillRectangle(border, border, width-(border<<1), barlength-barfilled);
2676 }
2677
2678 // Draw text
2679 if (options&PROGRESSBAR_PERCENTAGE)
2680 {
2681 dc.setFont(font);
2682 snprintf(numtext, sizeof(numtext)-1, "%d%%", percent);
2683 n = strlen(numtext);
2684 tw = font->getTextWidth(numtext, n);
2685 th = font->getFontHeight();
2686 ty = (height-th)/2+font->getFontAscent();
2687 tx = (width-tw)/2;
2688 if (height-border-barfilled > ty) // In upper side
2689 {
2690 dc.setForeground(textNumColor);
2691 dc.setClipRectangle(border, border, width-(border<<1), height-(border<<1));
2692 dc.drawText(tx, ty, numtext, n);
2693 }
2694 else if (ty-th > height-border-barfilled) // In lower side
2695 {
2696 dc.setForeground(textAltColor);
2697 dc.setClipRectangle(border, border, width-(border<<1), height-(border<<1));
2698 dc.drawText(tx, ty, numtext, n);
2699 }
2700 else // In between!
2701 {
2702 dc.setForeground(textAltColor);
2703 dc.setClipRectangle(border, height-border-barfilled, width-(border<<1), barfilled);
2704 dc.drawText(tx, ty, numtext, n);
2705 dc.setForeground(textNumColor);
2706 dc.setClipRectangle(border, border, width-(border<<1), barlength-barfilled);
2707 dc.drawText(tx, ty, numtext, n);
2708 dc.clearClipRectangle();
2709 }
2710 }
2711 }
2712
2713 // Horizontal bar
2714 else
2715 {
2716 // If total is 0, it's 100%
2717 barlength = width-border-border;
2718 barfilled = barlength;
2719 percent = 100;
2720 if (total != 0)
2721 {
2722 barfilled = (FXuint)(((double)progress * (double)barlength) / (double)total);
2723 percent = (FXuint)(((double)progress * 100.0) / (double)total);
2724 }
2725
2726 // Draw uncompleted bar
2727 if (barfilled < barlength)
2728 {
2729 // Clearlooks (gradient with rounded corners)
2730 if (use_clearlooks)
2731 {
2732 dc.setForeground(barBGColor);
2733 dc.fillRectangle(border+barfilled+(border>>1), border>>1, barlength-barfilled, height-border);
2734 }
2735 // Standard (flat)
2736 else
2737 {
2738 dc.setForeground(barBGColor);
2739 dc.fillRectangle(border+barfilled, border, barlength-barfilled, height-(border<<1));
2740 }
2741 }
2742
2743 // Draw completed bar
2744 if (0 < barfilled)
2745 {
2746 // Clearlooks (gradient with rounded corners)
2747 if (use_clearlooks)
2748 {
2749 drawGradientRectangle(dc, topcolor, bottomcolor, border-1, border-1, barfilled+2, height-border, true);
2750
2751 dc.setForeground(bordercolor);
2752 dc.fillRectangle(barfilled+3, 2, 1, height-(border<<1));
2753 dc.drawPoints(bordercorners, 4);
2754
2755 FXPoint barcorners[2] = { FXPoint(barfilled+2, 1), FXPoint(barfilled+2, height-border) };
2756 dc.drawPoints(barcorners, 2);
2757 }
2758 // Standard (flat)
2759 else
2760 {
2761 dc.setForeground(barColor);
2762 dc.fillRectangle(border, border, barfilled, height-(border<<1));
2763 }
2764 }
2765 // Draw text
2766 if (options&PROGRESSBAR_PERCENTAGE)
2767 {
2768 dc.setFont(font);
2769 snprintf(numtext, sizeof(numtext)-1, "%d%%", percent);
2770 n = strlen(numtext);
2771 tw = font->getTextWidth(numtext, n);
2772 th = font->getFontHeight();
2773 ty = (height-th)/2+font->getFontAscent();
2774 tx = (width-tw)/2;
2775 if (border+barfilled <= tx) // In right side
2776 {
2777 dc.setForeground(textNumColor);
2778 dc.setClipRectangle(border, border, width-(border<<1), height-(border<<1));
2779 dc.drawText(tx, ty, numtext, n);
2780 }
2781 else if (tx+tw <= border+barfilled) // In left side
2782 {
2783 dc.setForeground(textAltColor);
2784 dc.setClipRectangle(border, border, width-(border<<1), height-(border<<1));
2785 dc.drawText(tx, ty, numtext, n);
2786 }
2787 else // In between!
2788 {
2789 dc.setForeground(textAltColor);
2790 dc.setClipRectangle(border, border, barfilled, height);
2791 dc.drawText(tx, ty, numtext, n);
2792 dc.setForeground(textNumColor);
2793 dc.setClipRectangle(border+barfilled, border, barlength-barfilled, height);
2794 dc.drawText(tx, ty, numtext, n);
2795 dc.clearClipRectangle();
2796 }
2797 }
2798 }
2799 }
2800
2801
2802 // Draw the progress bar
onPaint(FXObject *,FXSelector,void * ptr)2803 long FXProgressBar::onPaint(FXObject*,FXSelector,void *ptr)
2804 {
2805 // Initialize Clearlooks
2806 INIT_CLEARLOOKS
2807
2808 FXEvent *event=(FXEvent*)ptr;
2809 FXDCWindow dc(this,event);
2810
2811 // Draw borders if any
2812 drawFrame(dc,0,0,width,height);
2813
2814 // Background
2815 dc.setForeground(getBaseColor());
2816 dc.fillRectangle(border,border,width-(border<<1),height-(border<<1));
2817
2818 // !!! Hack to get an optional rounded rectangle shape
2819 // only if _TEXTFIELD_NOFRAME is not specified !!!
2820 if ( (!(options&_TEXTFIELD_NOFRAME)) & use_clearlooks )
2821 {
2822 // Outside Background
2823 dc.setForeground(baseColor);
2824 dc.fillRectangle(0, 0, width, height);
2825 dc.drawPoints(basebackground, 4);
2826
2827 // Border
2828 dc.setForeground(bordercolor);
2829 dc.drawRectangle(2, 0, width-5, 0);
2830 dc.drawRectangle(2, height-1, width-5, height-1);
2831 dc.drawRectangle(0, 2, 0, height-5);
2832 dc.drawRectangle(width-1, 2, 0, height-5);
2833 dc.drawPoints(bordercorners, 4);
2834 dc.setForeground(shadecolor);
2835 dc.drawPoints(bordershade, 16);
2836 dc.setForeground(backColor);
2837 dc.fillRectangle(2, 1, width-4, height-2);
2838 }
2839 // !!! End of hack
2840
2841 // Interior
2842 drawInterior(dc);
2843 return 1;
2844 }
2845
2846
2847 //
2848 // Hack of FXPacker
2849 //
2850
2851 // This hack optionally draws a rectangle with rounded corners (Clearlooks)
drawGrooveRectangle(FXDCWindow & dc,FXint x,FXint y,FXint w,FXint h)2852 void FXPacker::drawGrooveRectangle(FXDCWindow& dc, FXint x, FXint y, FXint w, FXint h)
2853 {
2854 static FXbool init = true;
2855 static FXbool use_clearlooks = true;
2856 static FXColor shadecolor, bordercolor;
2857
2858 FXPoint bordershade[16] =
2859 {
2860 FXPoint(x, y+1), FXPoint(x+1, y), FXPoint(x+1, y+2), FXPoint(x+2, y+1),
2861 FXPoint(x+w-2, y), FXPoint(x+w-1, y+1), FXPoint(x+w-3, y+1),
2862 FXPoint(x+w-2, y+2), FXPoint(x, y+h-2), FXPoint(x+1, y+h-1),
2863 FXPoint(x+1, y+h-3), FXPoint(x+2, y+h-2),
2864 FXPoint(x+w-1, y+h-2), FXPoint(x+w-2, y+h-1),
2865 FXPoint(x+w-2, y+h-3), FXPoint(x+w-3, y+h-2)
2866 };
2867 FXPoint bordercorners[4] =
2868 {
2869 FXPoint(x+1, y+1), FXPoint(x+1, y+h-2), FXPoint(x+w-2, y+1),
2870 FXPoint(x+w-2, y+h-2)
2871 };
2872
2873 if (init)
2874 {
2875 use_clearlooks = getApp()->reg().readUnsignedEntry("SETTINGS", "use_clearlooks", true);
2876
2877 if (use_clearlooks)
2878 {
2879 FXuint r = FXREDVAL(backColor);
2880 FXuint g = FXGREENVAL(backColor);
2881 FXuint b = FXBLUEVAL(backColor);
2882
2883 shadecolor = FXRGB(0.9*r, 0.9*g, 0.9*b);
2884 bordercolor = FXRGB(0.5*r, 0.5*g, 0.5*b);
2885 (void)bordercolor; // Hack to avoid unused variable compiler warning
2886 }
2887 init = false;
2888 }
2889
2890 if ((0 < w) && (0 < h))
2891 {
2892 // Rectangle with rounded corners (Clearlooks)
2893 if (use_clearlooks)
2894 {
2895 // Draw the 4 edges
2896 dc.setForeground(shadowColor);
2897 dc.drawRectangle(x+w-1, y+2, 0, h-5); // right
2898 dc.drawRectangle(x, y+2, 0, h-5); // left
2899 dc.drawRectangle(x+2, y, w-5, 0); // up
2900 dc.drawRectangle(x+2, y+h-1, w-5, 0); // down
2901
2902 // Draw the 4 rounded corners (with shade)
2903 dc.setForeground(shadowColor);
2904 dc.drawPoints(bordercorners, 4);
2905 dc.setForeground(shadecolor);
2906 dc.drawPoints(bordershade, 16);
2907 }
2908
2909 // Standard rectangle
2910 else
2911 {
2912 dc.setForeground(shadowColor);
2913 dc.fillRectangle(x, y, w, 1);
2914 dc.fillRectangle(x, y, 1, h);
2915 dc.setForeground(hiliteColor);
2916 dc.fillRectangle(x, y+h-1, w, 1);
2917 dc.fillRectangle(x+w-1, y, 1, h);
2918 if ((1 < w) && (1 < h))
2919 {
2920 dc.setForeground(shadowColor);
2921 dc.fillRectangle(x+1, y+h-2, w-2, 1);
2922 dc.fillRectangle(x+w-2, y+1, 1, h-2);
2923 dc.setForeground(hiliteColor);
2924 dc.fillRectangle(x+1, y+1, w-3, 1);
2925 dc.fillRectangle(x+1, y+1, 1, h-3);
2926 }
2927 }
2928 }
2929 }
2930
2931
2932 //
2933 // Hack of FXMenuRadio
2934 //
2935
2936 // For HiDPI scaling
2937
2938 #define LEADSPACE 22
2939 #define TRAILSPACE 16
2940
2941
2942 // Handle repaint
onPaint(FXObject *,FXSelector,void * ptr)2943 long FXMenuRadio::onPaint(FXObject*,FXSelector,void* ptr)
2944 {
2945 FXEvent *ev=(FXEvent*)ptr;
2946 FXDCWindow dc(this,ev);
2947 FXint xx,yy;
2948
2949 xx=LEADSPACE;
2950
2951 // Grayed out
2952 if(!isEnabled())
2953 {
2954 dc.setForeground(backColor);
2955 dc.fillRectangle(0,0,width,height);
2956 if(!label.empty())
2957 {
2958 yy=font->getFontAscent()+(height-font->getFontHeight())/2;
2959 dc.setFont(font);
2960 dc.setForeground(hiliteColor);
2961 dc.drawText(xx+1,yy+1,label);
2962 if(!accel.empty()) dc.drawText(width-TRAILSPACE-font->getTextWidth(accel)+1,yy+1,accel);
2963 if(0<=hotoff) dc.fillRectangle(xx+font->getTextWidth(&label[0],hotoff)+1,yy+2,font->getTextWidth(&label[hotoff],wclen(&label[hotoff])),1);
2964 dc.setForeground(shadowColor);
2965 dc.drawText(xx,yy,label);
2966 if(!accel.empty()) dc.drawText(width-TRAILSPACE-font->getTextWidth(accel),yy,accel);
2967 if(0<=hotoff) dc.fillRectangle(xx+font->getTextWidth(&label[0],hotoff),yy+1,font->getTextWidth(&label[hotoff],wclen(&label[hotoff])),1);
2968 }
2969 }
2970
2971 // Active
2972 else if(isActive())
2973 {
2974 dc.setForeground(selbackColor);
2975 dc.fillRectangle(0,0,width,height);
2976 if(!label.empty())
2977 {
2978 yy=font->getFontAscent()+(height-font->getFontHeight())/2;
2979 dc.setFont(font);
2980 dc.setForeground(isEnabled() ? seltextColor : shadowColor);
2981 dc.drawText(xx,yy,label);
2982 if(!accel.empty()) dc.drawText(width-TRAILSPACE-font->getTextWidth(accel),yy,accel);
2983 if(0<=hotoff) dc.fillRectangle(xx+font->getTextWidth(&label[0],hotoff),yy+1,font->getTextWidth(&label[hotoff],wclen(&label[hotoff])),1);
2984 }
2985 }
2986
2987 // Normal
2988 else
2989 {
2990 dc.setForeground(backColor);
2991 dc.fillRectangle(0,0,width,height);
2992 if(!label.empty())
2993 {
2994 yy=font->getFontAscent()+(height-font->getFontHeight())/2;
2995 dc.setFont(font);
2996 dc.setForeground(textColor);
2997 dc.drawText(xx,yy,label);
2998 if(!accel.empty()) dc.drawText(width-TRAILSPACE-font->getTextWidth(accel),yy,accel);
2999 if(0<=hotoff) dc.fillRectangle(xx+font->getTextWidth(&label[0],hotoff),yy+1,font->getTextWidth(&label[hotoff],wclen(&label[hotoff])),1);
3000 }
3001 }
3002
3003 // Draw the radio
3004 xx=5/scaleint;
3005 yy=(height-9*scaleint)/2;
3006
3007 if(!isEnabled())
3008 dc.setForeground(backColor);
3009 else
3010 dc.setForeground(radioColor);
3011 dc.fillArc(xx,yy,9*scaleint,9*scaleint,0,360*64);
3012 dc.setForeground(shadowColor);
3013 dc.drawArc(xx,yy,9*scaleint,9*scaleint,0,360*64);
3014
3015 // Draw the bullit
3016 if(check!=FALSE)
3017 {
3018 FXRectangle recs[3];
3019 recs[0].x=xx+4*scaleint;
3020 recs[0].y=yy+3*scaleint;
3021 recs[0].w=2*scaleint;
3022 recs[0].h=1*scaleint;
3023 recs[1].x=xx+3*scaleint;
3024 recs[1].y=yy+4*scaleint;
3025 recs[1].w=4*scaleint;
3026 recs[1].h=2*scaleint;
3027 recs[2].x=xx+4*scaleint;
3028 recs[2].y=yy+6*scaleint;
3029 recs[2].w=2*scaleint;
3030 recs[2].h=1*scaleint;
3031 if(isEnabled())
3032 {
3033 if(check==MAYBE)
3034 dc.setForeground(shadowColor);
3035 else
3036 dc.setForeground(textColor);
3037 }
3038 else
3039 {
3040 dc.setForeground(shadowColor);
3041 }
3042 dc.fillRectangles(recs,3);
3043 }
3044
3045 return 1;
3046 }
3047
3048
3049 //
3050 // Hack of FXMenuCheck
3051 //
3052
3053 // For HiDPI scaling
3054
3055 // Handle repaint
onPaint(FXObject *,FXSelector,void * ptr)3056 long FXMenuCheck::onPaint(FXObject*,FXSelector,void* ptr)
3057 {
3058 FXEvent *ev=(FXEvent*)ptr;
3059 FXDCWindow dc(this,ev);
3060 FXint xx,yy;
3061
3062 xx=LEADSPACE;
3063
3064 // Grayed out
3065 if(!isEnabled())
3066 {
3067 dc.setForeground(backColor);
3068 dc.fillRectangle(0,0,width,height);
3069 if(!label.empty())
3070 {
3071 yy=font->getFontAscent()+(height-font->getFontHeight())/2;
3072 dc.setFont(font);
3073 dc.setForeground(hiliteColor);
3074 dc.drawText(xx+1,yy+1,label);
3075 if(!accel.empty()) dc.drawText(width-TRAILSPACE-font->getTextWidth(accel)+1,yy+1,accel);
3076 if(0<=hotoff) dc.fillRectangle(xx+font->getTextWidth(&label[0],hotoff)+1,yy+2,font->getTextWidth(&label[hotoff],wclen(&label[hotoff])),1);
3077 dc.setForeground(shadowColor);
3078 dc.drawText(xx,yy,label);
3079 if(!accel.empty()) dc.drawText(width-TRAILSPACE-font->getTextWidth(accel),yy,accel);
3080 if(0<=hotoff) dc.fillRectangle(xx+font->getTextWidth(&label[0],hotoff),yy+1,font->getTextWidth(&label[hotoff],wclen(&label[hotoff])),1);
3081 }
3082 }
3083
3084 // Active
3085 else if(isActive())
3086 {
3087 dc.setForeground(selbackColor);
3088 dc.fillRectangle(0,0,width,height);
3089 if(!label.empty())
3090 {
3091 yy=font->getFontAscent()+(height-font->getFontHeight())/2;
3092 dc.setFont(font);
3093 dc.setForeground(isEnabled() ? seltextColor : shadowColor);
3094 dc.drawText(xx,yy,label);
3095 if(!accel.empty()) dc.drawText(width-TRAILSPACE-font->getTextWidth(accel),yy,accel);
3096 if(0<=hotoff) dc.fillRectangle(xx+font->getTextWidth(&label[0],hotoff),yy+1,font->getTextWidth(&label[hotoff],wclen(&label[hotoff])),1);
3097 }
3098 }
3099
3100 // Normal
3101 else
3102 {
3103 dc.setForeground(backColor);
3104 dc.fillRectangle(0,0,width,height);
3105 if(!label.empty())
3106 {
3107 yy=font->getFontAscent()+(height-font->getFontHeight())/2;
3108 dc.setFont(font);
3109 dc.setForeground(textColor);
3110 dc.drawText(xx,yy,label);
3111 if(!accel.empty()) dc.drawText(width-TRAILSPACE-font->getTextWidth(accel),yy,accel);
3112 if(0<=hotoff) dc.fillRectangle(xx+font->getTextWidth(&label[0],hotoff),yy+1,font->getTextWidth(&label[hotoff],wclen(&label[hotoff])),1);
3113 }
3114 }
3115
3116 // Draw the box
3117 xx=5/scaleint;
3118 yy=(height-9*scaleint)/2;
3119 if(!isEnabled())
3120 dc.setForeground(backColor);
3121 else
3122 dc.setForeground(boxColor);
3123 dc.fillRectangle(xx+1,yy+1,8*scaleint,8*scaleint);
3124 dc.setForeground(shadowColor);
3125 dc.drawRectangle(xx,yy,9*scaleint,9*scaleint);
3126
3127 // Draw the check
3128 if(check!=FALSE)
3129 {
3130 FXRectangle recs[7];
3131 recs[0].x = xx+2*scaleint;
3132 recs[0].y = yy+4*scaleint;
3133 recs[0].w = 1*scaleint;
3134 recs[0].h = 3*scaleint;
3135 recs[1].x = xx+3*scaleint;
3136 recs[1].y = yy+5*scaleint;
3137 recs[1].w = 1*scaleint;
3138 recs[1].h = 3*scaleint;
3139 recs[2].x = xx+4*scaleint;
3140 recs[2].y = yy+6*scaleint;
3141 recs[2].w = 1*scaleint;
3142 recs[2].h = 3*scaleint;
3143 recs[3].x = xx+5*scaleint;
3144 recs[3].y = yy+5*scaleint;
3145 recs[3].w = 1*scaleint;
3146 recs[3].h = 3*scaleint;
3147 recs[4].x = xx+6*scaleint;
3148 recs[4].y = yy+4*scaleint;
3149 recs[4].w = 1*scaleint;
3150 recs[4].h = 3*scaleint;
3151 recs[5].x = xx+7*scaleint;
3152 recs[5].y = yy+3*scaleint;
3153 recs[5].w = 1*scaleint;
3154 recs[5].h = 3*scaleint;
3155 recs[6].x = xx+8*scaleint;
3156 recs[6].y = yy+2*scaleint;
3157 recs[6].w = 1*scaleint;
3158 recs[6].h = 3*scaleint;
3159
3160 if(isEnabled())
3161 {
3162 if(check==MAYBE)
3163 dc.setForeground(shadowColor);
3164 else
3165 dc.setForeground(textColor);
3166 }
3167 else
3168 {
3169 dc.setForeground(shadowColor);
3170 }
3171 dc.fillRectangles(recs, 7);
3172 }
3173
3174 return 1;
3175 }
3176
3177
3178 //
3179 // Hack of FXTreeList
3180 //
3181
3182 // For HiDPI scaling
3183
3184
3185 #define SIDE_SPACING 4 // Spacing between side and item
3186 #define HALFBOX_SIZE 4 // Half box size
3187
3188 // Draw item list
onPaint(FXObject *,FXSelector,void * ptr)3189 long FXTreeList::onPaint(FXObject*,FXSelector,void* ptr)
3190 {
3191 FXEvent* event=(FXEvent*)ptr;
3192 FXTreeItem* item=firstitem;
3193 FXTreeItem* p;
3194 FXint yh,xh,x,y,w,h,xp,hh;
3195 FXDCWindow dc(this,event);
3196 dc.setFont(font);
3197 x=pos_x;
3198 y=pos_y;
3199 if(options&TREELIST_ROOT_BOXES) x+=(4+indent);
3200 while(item && y<event->rect.y+event->rect.h)
3201 {
3202 w=item->getWidth(this);
3203 h=item->getHeight(this);
3204 if(event->rect.y<=y+h)
3205 {
3206 // Draw item
3207 dc.setForeground(backColor);
3208 dc.fillRectangle(0,y,width,h);
3209 item->draw(this,dc,x,y,w,h);
3210
3211 // Show other paraphernalia such as dotted lines and expand-boxes
3212 if((options&(TREELIST_SHOWS_LINES|TREELIST_SHOWS_BOXES)) && (item->parent || (options&TREELIST_ROOT_BOXES)))
3213 {
3214 hh=h/2;
3215 yh=y+hh;
3216 xh=x-indent+(SIDE_SPACING/2) - (scaleint - 1) * SIDE_SPACING;
3217 dc.setForeground(lineColor);
3218 dc.setBackground(backColor);
3219 dc.setStipple(STIPPLE_GRAY,pos_x&1,pos_y&1);
3220 if(options&TREELIST_SHOWS_LINES) // Connect items with lines
3221 {
3222 p=item->parent;
3223 xp=xh;
3224 dc.setFillStyle(FILL_OPAQUESTIPPLED);
3225 while(p)
3226 {
3227 xp-=(indent+p->getHeight(this)/2);
3228 if(p->next) dc.fillRectangle(xp,y,1,h);
3229 p=p->parent;
3230 }
3231 if((options&TREELIST_SHOWS_BOXES) && (item->hasItems() || item->getFirst()))
3232 {
3233 if(item->prev || item->parent) dc.fillRectangle(xh,y,1,yh-y-scaleint*HALFBOX_SIZE);
3234 if(item->next) dc.fillRectangle(xh,yh+scaleint*HALFBOX_SIZE,1,(y+h-yh-scaleint*HALFBOX_SIZE));
3235 }
3236 else
3237 {
3238 if(item->prev || item->parent) dc.fillRectangle(xh,y,1,hh);
3239 if(item->next) dc.fillRectangle(xh,yh,1,h);
3240 dc.fillRectangle(xh,yh,x+(SIDE_SPACING/2)-scaleint*2-xh,1);
3241 }
3242 dc.setFillStyle(FILL_SOLID);
3243 }
3244
3245 // Boxes before items for expand/collapse of item
3246 if((options&TREELIST_SHOWS_BOXES) && (item->hasItems() || item->getFirst()))
3247 {
3248 dc.setFillStyle(FILL_OPAQUESTIPPLED);
3249 dc.fillRectangle((xh+scaleint*4),yh,scaleint*( (SIDE_SPACING/2)-2 ),scaleint*1);
3250 dc.setFillStyle(FILL_SOLID);
3251 dc.drawRectangle(xh-scaleint*HALFBOX_SIZE,yh-scaleint*HALFBOX_SIZE, scaleint*(HALFBOX_SIZE+HALFBOX_SIZE),scaleint*(HALFBOX_SIZE+HALFBOX_SIZE));
3252 dc.setForeground(textColor);
3253 dc.fillRectangle(xh-scaleint*(HALFBOX_SIZE-2),yh,scaleint*(HALFBOX_SIZE+HALFBOX_SIZE-3),scaleint*1);
3254 if(!(options&TREELIST_AUTOSELECT) && !item->isExpanded())
3255 {
3256 dc.fillRectangle(xh,yh-scaleint*(HALFBOX_SIZE-2),scaleint*1,scaleint*(HALFBOX_SIZE+HALFBOX_SIZE-3));
3257 }
3258 }
3259 }
3260 }
3261
3262 y+=h;
3263
3264 // Move on to the next item
3265 if(item->first && ((options&TREELIST_AUTOSELECT) || item->isExpanded()))
3266 {
3267 x+=(indent+h/2);
3268 item=item->first;
3269 continue;
3270 }
3271 while(!item->next && item->parent)
3272 {
3273 item=item->parent;
3274 x-=(indent+item->getHeight(this)/2);
3275 }
3276 item=item->next;
3277 }
3278 if(y<event->rect.y+event->rect.h)
3279 {
3280 dc.setForeground(backColor);
3281 dc.fillRectangle(event->rect.x,y,event->rect.w,event->rect.y+event->rect.h-y);
3282 }
3283 return 1;
3284 }
3285
3286