1 /* vi:set ts=8 sts=4 sw=4:
3 * VIM - Vi IMproved by Bram Moolenaar
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
11 * (C) 2002,2005 by Marcin Dalecki <martin@dalecki.de>
13 * MARCIN DALECKI ASSUMES NO RESPONSIBILITY FOR THE USE OR INABILITY TO USE ANY
14 * OF THIS SOFTWARE . THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
15 * KIND, AND MARCIN DALECKI EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES,
16 * INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 * FITNESS FOR A PARTICULAR PURPOSE.
21 * Enhanced Motif PushButton widget with move over behavior.
30 #if defined(HAVE_XM_TRAITP_H) && defined(HAVE_XM_MANAGER_H) \
31 && defined(HAVE_XM_UNHIGHLIGHTT_H) && defined(HAVE_XM_XPMP_H)
32 # include <Xm/TraitP.h>
33 # include <Xm/Manager.h>
34 # include <Xm/UnhighlightT.h>
40 #include <Xm/ManagerP.h>
41 #include <Xm/Display.h>
42 #include <Xm/DisplayP.h>
44 #include <X11/Shell.h>
45 #include <X11/ShellP.h>
47 #include "gui_xmebwp.h"
49 /* Provide some missing wrappers, which are missed from the LessTif
50 * implementation. Also missing in Motif 1.2 and earlier.
52 * We neither use XmeGetPixmapData or _XmGetPixmapData, since with LessTif the
53 * pixmap will not appear in it's caches properly. We cache the interesting
54 * values in XmEnhancedButtonPart instead ourself.
56 #if defined(LESSTIF_VERSION) || (XmVersion <= 1002)
57 # ifndef Lab_IsMenupane
58 # define Lab_IsMenupane(w) (Lab_MenuType(w) == (int)XmMENU_POPUP || \
59 Lab_MenuType(w) == (int)XmMENU_PULLDOWN)
61 # define XmeClearBorder _XmClearBorder
62 # define XmeDrawShadows _XmDrawShadows
63 # define XmeDrawHighlight(a, b, c, d, e, f, g, h) \
64 _XmDrawHighlight(a, b, c, d, e, f, g, h, LineSolid)
68 * Motif internals we have to cheat around with.
71 /* Hopefully this will never change... */
72 #ifndef XmFOCUS_IGNORE
73 # define XmFOCUS_IGNORE 1<<1
76 extern Boolean
_XmGetInDragMode(Widget widget
);
77 extern void _XmPrimitiveEnter(Widget wid
,
79 String
* params
, Cardinal
* num_params
);
80 extern void _XmPrimitiveLeave(Widget wid
,
82 String
* params
, Cardinal
* num_params
);
83 extern void _XmSetFocusFlag(Widget w
, unsigned int mask
, Boolean value
);
84 extern void _XmCalcLabelDimensions(Widget wid
);
87 * Declaration of class methods.
89 static void Destroy(Widget w
);
90 static void Initialize(Widget rq
, Widget eb
, ArgList args
, Cardinal
*n
);
91 static Boolean
SetValues(Widget current
, Widget request
, Widget
new, ArgList args
, Cardinal
*n
);
92 static void Redisplay(Widget
, XEvent
*, Region
);
95 * Declaration of action methods.
97 static void Enter(Widget
, XEvent
*, String
*, Cardinal
*);
98 static void Leave(Widget
, XEvent
*, String
*, Cardinal
*);
99 static void BorderHighlight(Widget
);
100 static void BorderUnhighlight(Widget
);
103 * 4 x 4 stipple for desensitized widgets
105 #define stipple_width 4
106 #define stipple_height 4
107 static char stipple_bits
[] = { 0x0a, 0x05, 0x0a, 0x05 };
108 #define STIPPLE_BITMAP xmEnhancedButtonClassRec.enhancedbutton_class.stipple_bitmap
113 static XtActionsRec actionsList
[] =
119 static XtResource resources
[] =
122 XmNpixmapData
, XmCPixmap
, XmRString
, sizeof(String
),
123 XtOffsetOf(XmEnhancedButtonRec
, enhancedbutton
.pixmap_data
),
124 XmRImmediate
, (XtPointer
) NULL
126 XmNpixmapFile
, XmCPixmap
, XmRString
, sizeof(String
),
127 XtOffsetOf(XmEnhancedButtonRec
, enhancedbutton
.pixmap_file
),
128 XmRImmediate
, (XtPointer
) NULL
130 XmNspacing
, XmCSpacing
, XmRHorizontalDimension
, sizeof(Dimension
),
131 XtOffsetOf(XmEnhancedButtonRec
, enhancedbutton
.spacing
),
132 XmRImmediate
, (XtPointer
) 2
135 XmNlabelLocation
, XmCLocation
, XmRInt
, sizeof(int),
136 XtOffsetOf(XmEnhancedButtonRec
, enhancedbutton
.label_location
),
137 XtRImmediate
, (XtPointer
) XmRIGHT
141 /* This is needed to work around a bug in Lesstif 2, leaving the extension
142 * NULL somehow results in getting it set to an invalid pointer. */
143 XmPrimitiveClassExtRec xmEnhancedButtonPrimClassExtRec
=
145 /* next_extension */ NULL
,
146 /* record_type */ NULLQUARK
,
147 /* version */ XmPrimitiveClassExtVersion
,
148 /* record_size */ sizeof(XmPrimitiveClassExtRec
),
149 /* widget_baseline */ XmInheritBaselineProc
,
150 /* widget_display_rect */ XmInheritDisplayRectProc
,
151 /* widget_margins */ NULL
154 XmEnhancedButtonClassRec xmEnhancedButtonClassRec
=
157 /* core_class fields */
158 /* superclass */ (WidgetClass
) & xmPushButtonClassRec
,
159 /* class_name */ "XmEnhancedButton",
160 /* widget_size */ sizeof(XmEnhancedButtonRec
),
161 /* class_initialize */ NULL
,
162 /* class_part_initialize */ NULL
,
163 /* class_inited */ False
,
164 /* initialize */ Initialize
,
165 /* initialize_hook */ NULL
,
166 /* realize */ XtInheritRealize
,
167 /* actions */ actionsList
,
168 /* num_actions */ XtNumber(actionsList
),
169 /* resources */ resources
,
170 /* num_resources */ XtNumber(resources
),
171 /* xrm_class */ NULLQUARK
,
172 /* compress_motion */ True
,
173 /* compress_exposure */ XtExposeCompressMaximal
,
174 /* compress_enterleave */ True
,
175 /* visible_interest */ False
,
176 /* destroy */ Destroy
,
177 /* resize */ XtInheritResize
,
178 /* expose */ Redisplay
,
179 /* set_values */ SetValues
,
180 /* set_values_hook */ NULL
,
181 /* set_values_almost */ XtInheritSetValuesAlmost
,
182 /* get_values_hook */ NULL
,
183 /* accept_focus */ XtInheritAcceptFocus
,
184 /* version */ XtVersion
,
185 /* callback_private */ NULL
,
187 /* query_geometry */ NULL
,
188 /* display_accelerator */ XtInheritDisplayAccelerator
,
192 /* primitive_class fields */
194 /* border highlight */ BorderHighlight
,
195 /* border_unhighlight */ BorderUnhighlight
,
196 /* translations */ XtInheritTranslations
,
197 /* arm and activate */ XmInheritArmAndActivate
,
198 /* synthetic resources */ NULL
,
199 /* number of syn res */ 0,
200 /* extension */ (XtPointer
)&xmEnhancedButtonPrimClassExtRec
,
203 /* label_class fields */
205 /* setOverrideCallback */ XmInheritSetOverrideCallback
,
206 /* menuProcs */ XmInheritMenuProc
,
207 /* translations */ XtInheritTranslations
,
208 /* extension */ NULL
,
211 /* pushbutton_class record */
213 /* extension */ (XtPointer
) NULL
,
216 /* enhancedbutton_class fields */
218 /* stipple_bitmap */ None
223 WidgetClass xmEnhancedButtonWidgetClass
=
224 (WidgetClass
)&xmEnhancedButtonClassRec
;
228 * Create a slightly fainter pixmap to be shown on button entry.
230 static unsigned short
231 bump_color(unsigned short value
)
233 int tmp
= 2 * (((int) value
- 65535) / 3) + 65535;
239 alloc_color(Display
*display
,
243 void *closure UNUSED
)
248 if (!XParseColor(display
, colormap
, colorname
, xcolor
))
251 xcolor
->red
= bump_color(xcolor
->red
);
252 xcolor
->green
= bump_color(xcolor
->green
);
253 xcolor
->blue
= bump_color(xcolor
->blue
);
255 status
= XAllocColor(display
, colormap
, xcolor
);
256 return status
!= 0 ? 1 : 0;
260 static char * blank_xpm
[] =
262 /* width height ncolors cpp [x_hot y_hot] */
265 " s iconColor1 m black c #000000",
266 ". s none m none c none",
267 "X s topShadowColor m none c #DCDEE5",
268 "o s bottomShadowColor m black c #5D6069",
287 set_pixmap(XmEnhancedButtonWidget eb
)
289 /* Configure defines XPMATTRIBUTES_TYPE as XpmAttributes or as
290 * XpmAttributes_21, depending on what is in Xm/XpmP.h. */
291 XPMATTRIBUTES_TYPE attr
;
294 static XpmColorSymbol color
[8] = {
297 {"background", NULL
, 0},
298 {"foreground", NULL
, 0},
299 {"bottomShadowColor", NULL
, 0},
300 {"topShadowColor", NULL
, 0},
301 {"highlightColor", NULL
, 0},
302 {"armColor", NULL
, 0}
305 Display
*dpy
= XtDisplay(eb
);
308 unsigned int height
, width
, border
, depth
;
312 Pixmap arm_pix
= None
;
313 Pixmap ins_pix
= None
;
314 Pixmap high_pix
= None
;
315 char **data
= (char **) eb
->enhancedbutton
.pixmap_data
;
316 char *fname
= (char *) eb
->enhancedbutton
.pixmap_file
;
320 /* Make sure there is a default value for the pixmap.
325 gc
= XtGetGC((Widget
)eb
, (XtGCMask
)0, NULL
);
327 scr
= DefaultScreen(dpy
);
328 root
= RootWindow(dpy
, scr
);
330 eb
->label
.pixmap
= None
;
332 eb
->enhancedbutton
.pixmap_depth
= 0;
333 eb
->enhancedbutton
.pixmap_width
= 0;
334 eb
->enhancedbutton
.pixmap_height
= 0;
335 eb
->enhancedbutton
.normal_pixmap
= None
;
336 eb
->enhancedbutton
.armed_pixmap
= None
;
337 eb
->enhancedbutton
.highlight_pixmap
= None
;
338 eb
->enhancedbutton
.insensitive_pixmap
= None
;
340 /* We use dynamic colors, get them now. */
341 motif_get_toolbar_colors(
342 &eb
->core
.background_pixel
,
343 &eb
->primitive
.foreground
,
344 &eb
->primitive
.bottom_shadow_color
,
345 &eb
->primitive
.top_shadow_color
,
346 &eb
->primitive
.highlight_color
);
348 /* Setup color subsititution table. */
349 color
[0].pixel
= eb
->core
.background_pixel
;
350 color
[1].pixel
= eb
->core
.background_pixel
;
351 color
[2].pixel
= eb
->core
.background_pixel
;
352 color
[3].pixel
= eb
->primitive
.foreground
;
353 color
[4].pixel
= eb
->core
.background_pixel
;
354 color
[5].pixel
= eb
->primitive
.top_shadow_color
;
355 color
[6].pixel
= eb
->primitive
.highlight_color
;
356 color
[7].pixel
= eb
->pushbutton
.arm_color
;
358 /* Create the "sensitive" pixmap. */
359 attr
.valuemask
= XpmColorSymbols
| XpmCloseness
;
360 attr
.closeness
= 65535; /* accuracy isn't crucial */
361 attr
.colorsymbols
= color
;
362 attr
.numsymbols
= XtNumber(color
);
365 status
= XpmReadFileToPixmap(dpy
, root
, fname
, &pix
, &mask
, &attr
);
366 if (!fname
|| status
!= XpmSuccess
)
367 status
= XpmCreatePixmapFromData(dpy
, root
, data
, &pix
, &mask
, &attr
);
369 /* If something failed, we will fill in the default pixmap. */
370 if (status
!= XpmSuccess
)
371 status
= XpmCreatePixmapFromData(dpy
, root
, blank_xpm
, &pix
,
374 XpmFreeAttributes(&attr
);
376 XGetGeometry(dpy
, pix
, &root
, &x
, &y
, &width
, &height
, &border
, &depth
);
378 if (eb
->enhancedbutton
.label_location
== (int)XmTOP
379 || eb
->enhancedbutton
.label_location
== (int)XmBOTTOM
)
380 shift
= eb
->primitive
.shadow_thickness
/ 2;
382 shift
= eb
->primitive
.shadow_thickness
/ 2;
387 sen_pix
= XCreatePixmap(dpy
, root
, width
+ shift
, height
+ shift
, depth
);
389 XSetForeground(dpy
, gc
, eb
->core
.background_pixel
);
390 XFillRectangle(dpy
, sen_pix
, gc
, 0, 0, width
+ shift
, height
+ shift
);
391 XSetClipMask(dpy
, gc
, mask
);
392 XSetClipOrigin(dpy
, gc
, shift
, shift
);
393 XCopyArea(dpy
, pix
, sen_pix
, gc
, 0, 0, width
, height
, shift
, shift
);
395 /* Create the "highlight" pixmap. */
396 color
[4].pixel
= eb
->primitive
.bottom_shadow_color
;
397 #ifdef XpmAllocColor /* SGI doesn't have it */
398 attr
.valuemask
= XpmColorSymbols
| XpmCloseness
| XpmAllocColor
;
399 attr
.alloc_color
= alloc_color
;
401 attr
.valuemask
= XpmColorSymbols
| XpmCloseness
;
403 attr
.closeness
= 65535; /* accuracy isn't crucial */
404 attr
.colorsymbols
= color
;
405 attr
.numsymbols
= XtNumber(color
);
407 status
= XpmCreatePixmapFromData(dpy
, root
, data
, &pix
, NULL
, &attr
);
408 XpmFreeAttributes(&attr
);
410 high_pix
= XCreatePixmap(dpy
, root
, width
+ shift
, height
+ shift
, depth
);
413 XSetForeground(dpy
, gc
, eb
->core
.background_pixel
);
415 XSetForeground(dpy
, gc
, eb
->primitive
.top_shadow_color
);
417 XSetClipMask(dpy
, gc
, None
);
418 XFillRectangle(dpy
, high_pix
, gc
, 0, 0, width
+ shift
, height
+ shift
);
419 XSetClipMask(dpy
, gc
, mask
);
420 XSetClipOrigin(dpy
, gc
, 0, 0);
421 XCopyArea(dpy
, pix
, high_pix
, gc
, 0, 0, width
, height
, 0, 0);
423 arm_pix
= XCreatePixmap(dpy
, pix
, width
+ shift
, height
+ shift
, depth
);
425 if (eb
->pushbutton
.fill_on_arm
)
426 XSetForeground(dpy
, gc
, eb
->pushbutton
.arm_color
);
428 XSetForeground(dpy
, gc
, eb
->core
.background_pixel
);
429 XSetClipOrigin(dpy
, gc
, shift
, shift
);
430 XSetClipMask(dpy
, gc
, None
);
431 XFillRectangle(dpy
, arm_pix
, gc
, 0, 0, width
+ shift
, height
+ shift
);
432 XSetClipMask(dpy
, gc
, mask
);
433 XSetClipOrigin(dpy
, gc
, 2 * shift
, 2 * shift
);
434 XCopyArea(dpy
, pix
, arm_pix
, gc
, 0, 0, width
, height
, 2 * shift
, 2 * shift
);
436 XFreePixmap(dpy
, pix
);
437 XFreePixmap(dpy
, mask
);
439 /* Create the "insensitive" pixmap. */
440 attr
.valuemask
= XpmColorSymbols
| XpmCloseness
| XpmColorKey
;
441 attr
.closeness
= 65535; /* accuracy isn't crucial */
442 attr
.colorsymbols
= color
;
443 attr
.numsymbols
= sizeof(color
) / sizeof(color
[0]);
444 attr
.color_key
= XPM_MONO
;
445 status
= XpmCreatePixmapFromData(dpy
, root
, data
, &pix
, &mask
, &attr
);
447 /* Need to create new Pixmaps with the mask applied. */
449 ins_pix
= XCreatePixmap(dpy
, root
, width
+ shift
, height
+ shift
, depth
);
451 XSetForeground(dpy
, gc
, eb
->core
.background_pixel
);
452 XSetClipOrigin(dpy
, gc
, 0, 0);
453 XSetClipMask(dpy
, gc
, None
);
454 XFillRectangle(dpy
, ins_pix
, gc
, 0, 0, width
+ shift
, height
+ shift
);
455 XSetClipMask(dpy
, gc
, mask
);
456 XSetForeground(dpy
, gc
, eb
->primitive
.top_shadow_color
);
457 XSetClipOrigin(dpy
, gc
, 2 * shift
, 2 * shift
);
458 XFillRectangle(dpy
, ins_pix
, gc
, 2 * shift
, 2 * shift
, width
, height
);
459 XSetForeground(dpy
, gc
, eb
->primitive
.bottom_shadow_color
);
460 XSetClipOrigin(dpy
, gc
, shift
, shift
);
461 XFillRectangle(dpy
, ins_pix
, gc
, 0, 0, width
+ shift
, height
+ shift
);
462 XtReleaseGC((Widget
) eb
, gc
);
464 XpmFreeAttributes(&attr
);
466 eb
->enhancedbutton
.pixmap_depth
= depth
;
467 eb
->enhancedbutton
.pixmap_width
= width
;
468 eb
->enhancedbutton
.pixmap_height
= height
;
469 eb
->enhancedbutton
.normal_pixmap
= sen_pix
;
470 eb
->enhancedbutton
.highlight_pixmap
= high_pix
;
471 eb
->enhancedbutton
.insensitive_pixmap
= ins_pix
;
472 eb
->enhancedbutton
.armed_pixmap
= arm_pix
;
474 eb
->enhancedbutton
.doing_setvalues
= True
;
475 eb
->enhancedbutton
.doing_setvalues
= False
;
477 XFreePixmap(dpy
, pix
);
478 XFreePixmap(dpy
, mask
);
481 #define BUTTON_MASK ( \
482 Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask \
486 draw_shadows(XmEnhancedButtonWidget eb
)
492 if (!eb
->primitive
.shadow_thickness
)
495 if ((eb
->core
.width
<= 2 * eb
->primitive
.highlight_thickness
)
496 || (eb
->core
.height
<= 2 * eb
->primitive
.highlight_thickness
))
499 #if !defined(LESSTIF_VERSION) && (XmVersion > 1002)
503 dpy
= (XmDisplay
) XmGetXmDisplay(XtDisplay(eb
));
504 etched_in
= dpy
->display
.enable_etched_in_menu
;
509 if (!etched_in
^ eb
->pushbutton
.armed
)
511 top_gc
= eb
->primitive
.top_shadow_GC
;
512 bottom_gc
= eb
->primitive
.bottom_shadow_GC
;
516 top_gc
= eb
->primitive
.bottom_shadow_GC
;
517 bottom_gc
= eb
->primitive
.top_shadow_GC
;
520 XmeDrawShadows(XtDisplay(eb
), XtWindow(eb
),
523 eb
->primitive
.highlight_thickness
,
524 eb
->primitive
.highlight_thickness
,
525 eb
->core
.width
- 2 * eb
->primitive
.highlight_thickness
,
526 eb
->core
.height
- 2 * eb
->primitive
.highlight_thickness
,
527 eb
->primitive
.shadow_thickness
,
528 (unsigned)(etched_in
? XmSHADOW_IN
: XmSHADOW_OUT
));
532 draw_highlight(XmEnhancedButtonWidget eb
)
534 eb
->primitive
.highlighted
= True
;
535 eb
->primitive
.highlight_drawn
= True
;
537 if (!XtWidth(eb
) || !XtHeight(eb
) || !eb
->primitive
.highlight_thickness
)
540 XmeDrawHighlight(XtDisplay(eb
), XtWindow(eb
),
541 eb
->primitive
.highlight_GC
, 0, 0,
542 XtWidth(eb
), XtHeight(eb
),
543 eb
->primitive
.highlight_thickness
);
547 draw_unhighlight(XmEnhancedButtonWidget eb
)
549 GC manager_background_GC
;
551 eb
->primitive
.highlighted
= False
;
552 eb
->primitive
.highlight_drawn
= False
;
554 if (!XtWidth(eb
) || !XtHeight(eb
) || !eb
->primitive
.highlight_thickness
)
557 if (XmIsManager(eb
->core
.parent
))
560 XmSpecifyUnhighlightTrait UnhighlightT
;
562 if (((UnhighlightT
= (XmSpecifyUnhighlightTrait
) XmeTraitGet((XtPointer
)
563 XtClass(eb
->core
.parent
), XmQTspecifyUnhighlight
))
564 != NULL
) && (UnhighlightT
->getUnhighlightGC
!= NULL
))
566 /* if unhighlight trait in parent use specified GC... */
567 manager_background_GC
=
568 UnhighlightT
->getUnhighlightGC(eb
->core
.parent
, (Widget
) eb
);
572 /* ...otherwise, use parent's background GC */
573 manager_background_GC
= ((XmManagerWidget
)
574 (eb
->core
.parent
))->manager
.background_GC
;
577 manager_background_GC
= ((XmManagerWidget
)
578 (eb
->core
.parent
))->manager
.background_GC
;
580 XmeDrawHighlight(XtDisplay(eb
), XtWindow(eb
),
581 manager_background_GC
,
582 0, 0, XtWidth(eb
), XtHeight(eb
),
583 eb
->primitive
.highlight_thickness
);
584 if (!eb
->pushbutton
.armed
&& eb
->primitive
.shadow_thickness
)
585 XmeClearBorder(XtDisplay(eb
), XtWindow(eb
),
586 eb
->primitive
.highlight_thickness
,
587 eb
->primitive
.highlight_thickness
,
588 eb
->core
.width
- 2 * eb
->primitive
.highlight_thickness
,
589 eb
->core
.height
- 2 * eb
->primitive
.highlight_thickness
,
590 eb
->primitive
.shadow_thickness
);
593 XmeClearBorder(XtDisplay(eb
), XtWindow(eb
), 0, 0, XtWidth(eb
),
594 XtHeight(eb
), eb
->primitive
.highlight_thickness
);
598 draw_pixmap(XmEnhancedButtonWidget eb
,
599 XEvent
*event UNUSED
,
600 Region region UNUSED
)
603 GC gc
= eb
->label
.normal_GC
;
612 if (!XtIsSensitive((Widget
) eb
))
613 pix
= eb
->enhancedbutton
.insensitive_pixmap
;
616 if (eb
->primitive
.highlighted
&& !eb
->pushbutton
.armed
)
617 pix
= eb
->enhancedbutton
.highlight_pixmap
;
618 else if (eb
->pushbutton
.armed
)
619 pix
= eb
->enhancedbutton
.armed_pixmap
;
621 pix
= eb
->enhancedbutton
.normal_pixmap
;
624 if (pix
== None
|| !eb
->enhancedbutton
.pixmap_data
)
627 depth
= eb
->enhancedbutton
.pixmap_depth
;
628 w
= eb
->enhancedbutton
.pixmap_width
;
629 h
= eb
->enhancedbutton
.pixmap_height
;
631 gc
= eb
->label
.normal_GC
;
632 x
= eb
->primitive
.highlight_thickness
633 + eb
->primitive
.shadow_thickness
634 + eb
->label
.margin_width
;
635 y
= eb
->primitive
.highlight_thickness
636 + eb
->primitive
.shadow_thickness
637 + eb
->label
.margin_height
;
638 width
= eb
->core
.width
- 2 * x
;
641 height
= eb
->core
.height
- 2 * y
;
644 if (depth
== (int)eb
->core
.depth
)
645 XCopyArea(XtDisplay(eb
), pix
, XtWindow(eb
), gc
, 0, 0,
646 width
, height
, x
, y
);
648 XCopyPlane(XtDisplay(eb
), pix
, XtWindow(eb
), gc
, 0, 0,
649 width
, height
, x
, y
, (unsigned long)1);
653 * Draw the label contained in the pushbutton.
656 draw_label(XmEnhancedButtonWidget eb
, XEvent
*event
, Region region
)
659 Boolean replaceGC
= False
;
660 Boolean deadjusted
= False
;
661 #if !defined(LESSTIF_VERSION) && (XmVersion > 1002)
662 XmDisplay dpy
= (XmDisplay
)XmGetXmDisplay(XtDisplay(eb
));
663 Boolean etched_in
= dpy
->display
.enable_etched_in_menu
;
665 Boolean etched_in
= False
;
668 if (eb
->pushbutton
.armed
669 && ((!Lab_IsMenupane(eb
) && eb
->pushbutton
.fill_on_arm
)
670 || (Lab_IsMenupane(eb
) && etched_in
)))
672 if (eb
->label
.label_type
== (int)XmSTRING
673 && eb
->pushbutton
.arm_color
== eb
->primitive
.foreground
)
675 tmp_gc
= eb
->label
.normal_GC
;
676 eb
->label
.normal_GC
= eb
->pushbutton
.background_gc
;
682 * If the button contains a labeled pixmap, we will take it instead of our
686 if (eb
->label
.label_type
== (int)XmPIXMAP
)
688 if (eb
->pushbutton
.armed
)
690 if (eb
->pushbutton
.arm_pixmap
!= XmUNSPECIFIED_PIXMAP
)
691 eb
->label
.pixmap
= eb
->pushbutton
.arm_pixmap
;
693 eb
->label
.pixmap
= eb
->pushbutton
.unarm_pixmap
;
696 /* pushbutton is not armed */
697 eb
->label
.pixmap
= eb
->pushbutton
.unarm_pixmap
;
701 * Temporarily remove the Xm3D_ENHANCE_PIXEL hack ("adjustment") from the
702 * margin values, so we don't confuse Label.
704 if (eb
->pushbutton
.default_button_shadow_thickness
> 0)
707 Lab_MarginLeft(eb
) -= Xm3D_ENHANCE_PIXEL
;
708 Lab_MarginRight(eb
) -= Xm3D_ENHANCE_PIXEL
;
709 Lab_MarginTop(eb
) -= Xm3D_ENHANCE_PIXEL
;
710 Lab_MarginBottom(eb
) -= Xm3D_ENHANCE_PIXEL
;
717 expose
= xmLabelClassRec
.core_class
.expose
;
719 (*expose
)((Widget
) eb
, event
, region
);
724 Lab_MarginLeft(eb
) += Xm3D_ENHANCE_PIXEL
;
725 Lab_MarginRight(eb
) += Xm3D_ENHANCE_PIXEL
;
726 Lab_MarginTop(eb
) += Xm3D_ENHANCE_PIXEL
;
727 Lab_MarginBottom(eb
) += Xm3D_ENHANCE_PIXEL
;
731 eb
->label
.normal_GC
= tmp_gc
;
737 String
*params UNUSED
,
738 Cardinal
*num_params UNUSED
)
740 XmEnhancedButtonWidget eb
= (XmEnhancedButtonWidget
) wid
;
741 XmPushButtonCallbackStruct call_value
;
743 if (Lab_IsMenupane(eb
))
745 if ((((ShellWidget
) XtParent(XtParent(eb
)))->shell
.popped_up
)
746 && _XmGetInDragMode((Widget
) eb
))
748 #if !defined(LESSTIF_VERSION) && (XmVersion > 1002)
749 XmDisplay dpy
= (XmDisplay
) XmGetXmDisplay(XtDisplay(wid
));
750 Boolean etched_in
= dpy
->display
.enable_etched_in_menu
;
752 Boolean etched_in
= False
;
755 if (eb
->pushbutton
.armed
)
758 /* ...so KHelp event is delivered correctly. */
759 _XmSetFocusFlag(XtParent(XtParent(eb
)), XmFOCUS_IGNORE
, TRUE
);
760 XtSetKeyboardFocus(XtParent(XtParent(eb
)), (Widget
) eb
);
761 _XmSetFocusFlag(XtParent(XtParent(eb
)), XmFOCUS_IGNORE
, FALSE
);
763 eb
->pushbutton
.armed
= TRUE
;
765 ((XmManagerWidget
) XtParent(wid
))->manager
.active_child
= wid
;
767 /* etched in menu button */
768 if (etched_in
&& !XmIsTearOffButton(eb
))
770 XFillRectangle(XtDisplay(eb
), XtWindow(eb
),
771 eb
->pushbutton
.fill_gc
,
772 0, 0, eb
->core
.width
, eb
->core
.height
);
773 draw_label(eb
, event
, NULL
);
774 draw_pixmap(eb
, event
, NULL
);
777 if ((eb
->core
.width
> 2 * eb
->primitive
.highlight_thickness
)
778 && (eb
->core
.height
>
779 2 * eb
->primitive
.highlight_thickness
))
781 XmeDrawShadows(XtDisplay(eb
), XtWindow(eb
),
782 eb
->primitive
.top_shadow_GC
,
783 eb
->primitive
.bottom_shadow_GC
,
784 eb
->primitive
.highlight_thickness
,
785 eb
->primitive
.highlight_thickness
,
786 eb
->core
.width
- 2 * eb
->primitive
.highlight_thickness
,
787 eb
->core
.height
- 2 * eb
->primitive
.highlight_thickness
,
788 eb
->primitive
.shadow_thickness
,
789 (unsigned)(etched_in
? XmSHADOW_IN
: XmSHADOW_OUT
));
792 if (eb
->pushbutton
.arm_callback
)
794 XFlush(XtDisplay(eb
));
796 call_value
.reason
= (int)XmCR_ARM
;
797 call_value
.event
= event
;
798 XtCallCallbackList((Widget
) eb
,
799 eb
->pushbutton
.arm_callback
,
808 _XmPrimitiveEnter((Widget
) eb
, event
, NULL
, NULL
);
809 if (eb
->pushbutton
.armed
== TRUE
)
812 expose
= XtClass(eb
)->core_class
.expose
;
814 (*expose
) (wid
, event
, (Region
) NULL
);
819 draw_pixmap(eb
, event
, NULL
);
826 String
*params UNUSED
,
827 Cardinal
*num_params UNUSED
)
829 XmEnhancedButtonWidget eb
= (XmEnhancedButtonWidget
)wid
;
830 XmPushButtonCallbackStruct call_value
;
832 if (Lab_IsMenupane(eb
))
834 #if !defined(LESSTIF_VERSION) && (XmVersion > 1002)
835 XmDisplay dpy
= (XmDisplay
) XmGetXmDisplay(XtDisplay(wid
));
836 Boolean etched_in
= dpy
->display
.enable_etched_in_menu
;
838 Boolean etched_in
= False
;
841 if (_XmGetInDragMode((Widget
)eb
)
842 && eb
->pushbutton
.armed
843 && ( /* !ActiveTearOff || */
844 event
->xcrossing
.mode
== NotifyNormal
))
846 eb
->pushbutton
.armed
= FALSE
;
848 ((XmManagerWidget
) XtParent(wid
))->manager
.active_child
= NULL
;
850 if (etched_in
&& !XmIsTearOffButton(eb
))
852 XFillRectangle(XtDisplay(eb
), XtWindow(eb
),
853 eb
->pushbutton
.background_gc
,
854 0, 0, eb
->core
.width
, eb
->core
.height
);
855 draw_label(eb
, event
, NULL
);
856 draw_pixmap(eb
, event
, NULL
);
860 (XtDisplay(eb
), XtWindow(eb
),
861 eb
->primitive
.highlight_thickness
,
862 eb
->primitive
.highlight_thickness
,
864 2 * eb
->primitive
.highlight_thickness
,
866 2 * eb
->primitive
.highlight_thickness
,
867 eb
->primitive
.shadow_thickness
);
869 if (eb
->pushbutton
.disarm_callback
)
871 XFlush(XtDisplay(eb
));
873 call_value
.reason
= (int)XmCR_DISARM
;
874 call_value
.event
= event
;
875 XtCallCallbackList((Widget
) eb
,
876 eb
->pushbutton
.disarm_callback
,
883 _XmPrimitiveLeave((Widget
) eb
, event
, NULL
, NULL
);
885 if (eb
->pushbutton
.armed
== TRUE
)
888 eb
->pushbutton
.armed
= FALSE
;
890 expose
= XtClass(eb
)->core_class
.expose
;
892 (*expose
) (wid
, event
, (Region
)NULL
);
893 draw_unhighlight(eb
);
894 draw_pixmap(eb
, event
, NULL
);
895 eb
->pushbutton
.armed
= TRUE
;
899 draw_unhighlight(eb
);
900 draw_pixmap(eb
, event
, NULL
);
905 #define IsNull(p) ((p) == XmUNSPECIFIED_PIXMAP)
908 set_size(XmEnhancedButtonWidget newtb
)
913 _XmCalcLabelDimensions((Widget
) newtb
);
915 /* Find out how big the pixmap is */
916 if (newtb
->enhancedbutton
.pixmap_data
917 && !IsNull(newtb
->label
.pixmap
)
918 && !IsNull(newtb
->enhancedbutton
.normal_pixmap
))
920 w
= newtb
->enhancedbutton
.pixmap_width
;
921 h
= newtb
->enhancedbutton
.pixmap_height
;
925 * Plase note that we manipulate the width only in case of push buttons not
926 * used in the context of a menu pane.
928 if (Lab_IsMenupane(newtb
))
930 newtb
->label
.margin_left
= w
+ 2 * (newtb
->primitive
.shadow_thickness
931 + newtb
->primitive
.highlight_thickness
)
932 + newtb
->label
.margin_width
;
936 newtb
->label
.margin_left
= w
;
937 newtb
->core
.width
= w
+ 2 * (newtb
->primitive
.shadow_thickness
938 + newtb
->primitive
.highlight_thickness
939 + newtb
->label
.margin_width
)
940 + newtb
->label
.TextRect
.width
;
942 if (newtb
->label
.TextRect
.width
> 0)
944 newtb
->label
.margin_left
+= newtb
->label
.margin_width
945 + newtb
->primitive
.shadow_thickness
;
946 newtb
->core
.width
+= newtb
->label
.margin_width
947 + newtb
->primitive
.shadow_thickness
;
950 if (newtb
->label
.TextRect
.height
< h
)
952 newtb
->core
.height
= h
+ 2 * (newtb
->primitive
.shadow_thickness
953 + newtb
->primitive
.highlight_thickness
954 + newtb
->label
.margin_height
);
958 /* FIXME: We should calculate an drawing offset for the pixmap here to
963 printf("%d %d %d %d %d %d - %d %d\n", newtb
->enhancedbutton
.normal_pixmap
,
964 h
, newtb
->core
.height
,
965 newtb
->primitive
.shadow_thickness
,
966 newtb
->primitive
.highlight_thickness
,
967 newtb
->label
.margin_height
,
972 /* Invoke Label's Resize procedure. */
976 resize
= xmLabelClassRec
.core_class
.resize
;
979 (* resize
) ((Widget
) newtb
);
984 Initialize(Widget rq
, Widget ebw
, ArgList args UNUSED
, Cardinal
*n UNUSED
)
986 XmEnhancedButtonWidget request
= (XmEnhancedButtonWidget
)rq
;
987 XmEnhancedButtonWidget eb
= (XmEnhancedButtonWidget
)ebw
;
991 resize
= xmLabelClassRec
.core_class
.resize
;
994 /* Create a bitmap for stippling (Drawable resources are cheap). */
995 if (STIPPLE_BITMAP
== None
)
997 Display
*dpy
= XtDisplay((Widget
) request
);
998 Window rootW
= DefaultRootWindow(dpy
);
1000 STIPPLE_BITMAP
= XCreateBitmapFromData(dpy
, rootW
, stipple_bits
,
1001 stipple_width
, stipple_height
);
1003 eb
->enhancedbutton
.doing_setvalues
= False
;
1005 /* First see what type of extended label this is.
1007 if (eb
->enhancedbutton
.pixmap_data
)
1012 /* FIXME: this is not the perfect way to deal with menues, which do not
1013 * have any string set right now. */
1014 str
= XmStringCreateLocalized("");
1015 XtVaSetValues((Widget
) eb
, XmNlabelString
, str
, NULL
);
1018 eb
->label
.pixmap
= eb
->enhancedbutton
.normal_pixmap
;
1020 if (request
->core
.width
== 0)
1022 if (request
->core
.height
== 0)
1023 eb
->core
.height
= 0;
1026 (* resize
)((Widget
)eb
);
1030 free_pixmaps(XmEnhancedButtonWidget eb
)
1033 * Clear the old pixmaps.
1035 Pixmap norm_pix
= eb
->enhancedbutton
.normal_pixmap
;
1036 Pixmap arm_pix
= eb
->enhancedbutton
.armed_pixmap
;
1037 Pixmap insen_pix
= eb
->enhancedbutton
.insensitive_pixmap
;
1038 Pixmap high_pix
= eb
->enhancedbutton
.highlight_pixmap
;
1040 if (norm_pix
!= None
&& norm_pix
!= XmUNSPECIFIED_PIXMAP
)
1041 XFreePixmap(XtDisplay(eb
), norm_pix
);
1043 if (arm_pix
!= None
&& arm_pix
!= XmUNSPECIFIED_PIXMAP
)
1044 XFreePixmap(XtDisplay(eb
), arm_pix
);
1046 if (insen_pix
!= None
&& insen_pix
!= XmUNSPECIFIED_PIXMAP
)
1047 XFreePixmap(XtDisplay(eb
), insen_pix
);
1049 if (high_pix
!= None
&& high_pix
!= XmUNSPECIFIED_PIXMAP
)
1050 XFreePixmap(XtDisplay(eb
), high_pix
);
1056 if (!XmIsEnhancedButton(w
))
1059 free_pixmaps((XmEnhancedButtonWidget
)w
);
1063 SetValues(Widget current
,
1064 Widget request UNUSED
,
1066 ArgList args UNUSED
,
1069 XmEnhancedButtonWidget cur
= (XmEnhancedButtonWidget
) current
;
1070 XmEnhancedButtonWidget eb
= (XmEnhancedButtonWidget
) new;
1071 Boolean redraw
= False
;
1072 Boolean change
= True
;
1073 Display
*dpy
= XtDisplay(current
);
1075 #define NOT_EQUAL(field) (cur->field != eb->field)
1078 * Make sure that lost sensitivity is causing the border to vanish as well.
1080 if (NOT_EQUAL(core
.sensitive
) && !Lab_IsMenupane(current
))
1082 if (cur
->core
.sensitive
== True
)
1084 draw_unhighlight(eb
);
1090 unsigned int r_height
;
1091 unsigned int r_width
;
1092 unsigned int r_border
;
1093 unsigned int r_depth
;
1104 * Artificially let the highlight appear if the mouse is over us.
1106 /* Best way to get the root window of object: */
1107 XGetGeometry(dpy
, XtWindow(cur
), &root
, &r_x
, &r_y
, &r_width
,
1108 &r_height
, &r_border
, &r_depth
);
1109 XQueryPointer(XtDisplay(cur
), XtWindow(cur
), &root_q
, &child
,
1110 &root_x
, &root_y
, &win_x
, &win_y
, &mask
);
1114 if ((win_x
< 0) || (win_y
< 0))
1117 if ((win_x
> (int)r_width
) || (win_y
> (int)r_height
))
1128 * Check for changed ExtLabelString.
1130 if (NOT_EQUAL(primitive
.shadow_thickness
))
1133 /* Don't change the pixmaps */
1137 if (NOT_EQUAL(primitive
.foreground
))
1139 if (NOT_EQUAL(core
.background_pixel
))
1141 if (NOT_EQUAL(pushbutton
.fill_on_arm
))
1143 if (NOT_EQUAL(enhancedbutton
.spacing
))
1145 if (NOT_EQUAL(enhancedbutton
.label_location
))
1150 if (NOT_EQUAL(label
._label
))
1160 if (eb
->primitive
.highlighted
)
1161 eb
->label
.pixmap
= eb
->enhancedbutton
.highlight_pixmap
;
1163 eb
->label
.pixmap
= eb
->enhancedbutton
.normal_pixmap
;
1173 Redisplay(Widget w
, XEvent
*event
, Region region
)
1175 XmEnhancedButtonWidget eb
= (XmEnhancedButtonWidget
) w
;
1176 #if !defined(LESSTIF_VERSION) && (XmVersion > 1002)
1178 XtEnum default_button_emphasis
;
1185 if (!XtIsRealized((Widget
)eb
))
1188 #if !defined(LESSTIF_VERSION) && (XmVersion > 1002)
1189 dpy
= (XmDisplay
)XmGetXmDisplay(XtDisplay(eb
));
1190 default_button_emphasis
= dpy
->display
.default_button_emphasis
;
1194 * Compute the area allocated to the label of the pushbutton; fill in the
1195 * dimensions in the box.
1198 if ((eb
->pushbutton
.arm_color
== eb
->primitive
.top_shadow_color
)
1199 || (eb
->pushbutton
.arm_color
== eb
->primitive
.bottom_shadow_color
))
1202 if (eb
->pushbutton
.compatible
)
1203 adjust
= eb
->pushbutton
.show_as_default
;
1205 adjust
= eb
->pushbutton
.default_button_shadow_thickness
;
1209 adjust
= adjust
+ eb
->primitive
.shadow_thickness
;
1210 adjust
= (adjust
<< 1);
1211 dx
= eb
->primitive
.highlight_thickness
+ adjust
+ fill
;
1214 dx
= (eb
->primitive
.highlight_thickness
1215 + eb
->primitive
.shadow_thickness
+ fill
);
1220 box
.width
= eb
->core
.width
- adjust
;
1221 box
.height
= eb
->core
.height
- adjust
;
1224 * Redraw the background.
1226 if (!Lab_IsMenupane(eb
))
1230 /* Don't shade if the button contains a label with a pixmap, since
1231 * there is no variant of the label available with the needed
1234 if (eb
->pushbutton
.armed
&& eb
->pushbutton
.fill_on_arm
)
1236 if (eb
->label
.label_type
== (int)XmPIXMAP
)
1238 if (eb
->pushbutton
.arm_pixmap
!= XmUNSPECIFIED_PIXMAP
)
1239 gc
= eb
->pushbutton
.fill_gc
;
1241 gc
= eb
->pushbutton
.background_gc
;
1244 gc
= eb
->pushbutton
.fill_gc
;
1247 gc
= eb
->pushbutton
.background_gc
;
1248 /* really need to fill with background if not armed ? */
1250 XFillRectangle(XtDisplay(eb
), XtWindow(eb
), gc
,
1251 box
.x
, box
.y
, box
.width
, box
.height
);
1254 draw_label(eb
, event
, region
);
1256 if (Lab_IsMenupane(eb
))
1258 if (eb
->pushbutton
.armed
)
1259 (*(((XmPushButtonWidgetClass
)XtClass(eb
))
1260 ->primitive_class
.border_highlight
))(w
);
1261 draw_pixmap(eb
, event
, region
);
1267 #if !defined(LESSTIF_VERSION) && (XmVersion > 1002)
1269 * NOTE: PushButton has two types of shadows: primitive-shadow and
1270 * default-button-shadow. If pushbutton is in a menu only primitive
1271 * shadows are drawn.
1273 switch (default_button_emphasis
)
1275 case XmEXTERNAL_HIGHLIGHT
:
1276 adjust
= (eb
->primitive
.highlight_thickness
-
1277 (eb
->pushbutton
.default_button_shadow_thickness
1278 ? Xm3D_ENHANCE_PIXEL
: 0));
1281 case XmINTERNAL_HIGHLIGHT
:
1291 * Clear the area not occupied by label with parents background color.
1292 * Label will invoke BorderUnhighlight() on the highlight_thickness
1293 * area, which is redundant when XmEXTERNAL_HIGHLIGHT default button
1294 * shadow emphasis is used.
1298 int borderwidth
=box
.x
- adjust
;
1299 int rectwidth
= eb
->core
.width
- 2 * adjust
;
1300 int rectheight
= eb
->core
.height
- 2 * adjust
;
1302 if (XmIsManager(XtParent(eb
)))
1304 XmeDrawHighlight(XtDisplay(eb
), XtWindow(eb
),
1305 XmParentBackgroundGC(eb
),
1306 adjust
, adjust
, rectwidth
, rectheight
, borderwidth
);
1310 XmeClearBorder(XtDisplay(eb
), XtWindow(eb
),
1311 adjust
, adjust
, rectwidth
, rectheight
, borderwidth
);
1314 #if !defined(LESSTIF_VERSION) && (XmVersion > 1002)
1315 switch (default_button_emphasis
)
1317 case XmINTERNAL_HIGHLIGHT
:
1318 /* The call above erases the border highlighting. */
1319 if (eb
->primitive
.highlight_drawn
)
1320 (*(((XmPushButtonWidgetClass
) XtClass (eb
))
1321 ->primitive_class
.border_highlight
)) ((Widget
) eb
) ;
1330 if (eb
->pushbutton
.default_button_shadow_thickness
)
1332 if (eb
->pushbutton
.show_as_default
)
1335 * - get the topShadowColor and bottomShadowColor from the
1336 * parent; use those colors to construct top and bottom gc;
1337 * use these GCs to draw the shadows of the button.
1339 * - Should not be called if pushbutton is in a row column or
1342 * - Should be called only if a defaultbuttonshadow is to be
1347 int default_button_shadow_thickness
;
1348 int x
, y
, width
, height
, delta
;
1351 if (eb
->pushbutton
.compatible
1352 && (eb
->pushbutton
.show_as_default
== 0))
1355 if (!eb
->pushbutton
.compatible
1356 && (eb
->pushbutton
.default_button_shadow_thickness
1360 delta
= eb
->primitive
.highlight_thickness
;
1363 * May need more complex computation for getting the GCs.
1365 parent
= XtParent(eb
);
1366 if (XmIsManager(parent
))
1368 /* Use the parent's GC so monochrome works. */
1369 bottom_gc
= XmParentTopShadowGC(eb
);
1370 top_gc
= XmParentBottomShadowGC(eb
);
1374 /* Use your own pixel for drawing. */
1375 bottom_gc
= eb
->primitive
.top_shadow_GC
;
1376 top_gc
= eb
->primitive
.bottom_shadow_GC
;
1379 if ((bottom_gc
== None
) || (top_gc
== None
))
1383 if (eb
->pushbutton
.compatible
)
1384 default_button_shadow_thickness
=
1385 eb
->pushbutton
.show_as_default
;
1387 default_button_shadow_thickness
=
1388 eb
->pushbutton
.default_button_shadow_thickness
;
1390 #if !defined(LESSTIF_VERSION) && (XmVersion > 1002)
1392 * Compute location of bounding box to contain the
1393 * defaultButtonShadow.
1395 switch (default_button_emphasis
)
1397 case XmEXTERNAL_HIGHLIGHT
:
1398 delta
= eb
->primitive
.highlight_thickness
;
1401 case XmINTERNAL_HIGHLIGHT
:
1402 delta
= Xm3D_ENHANCE_PIXEL
;
1412 width
= eb
->core
.width
- 2 * delta
;
1413 height
= eb
->core
.height
- 2 * delta
;
1415 if ((width
> 0) && (height
> 0))
1416 XmeDrawShadows(XtDisplay(eb
), XtWindow(eb
),
1417 top_gc
, bottom_gc
, x
, y
, width
, height
,
1418 default_button_shadow_thickness
,
1419 (unsigned)XmSHADOW_OUT
);
1423 if (eb
->primitive
.highlight_drawn
)
1425 draw_pixmap(eb
, event
, region
);
1430 BorderHighlight(Widget w
)
1432 XmEnhancedButtonWidget eb
= (XmEnhancedButtonWidget
)w
;
1434 (*(xmPushButtonClassRec
.primitive_class
.border_highlight
))(w
);
1435 draw_pixmap(eb
, NULL
, NULL
);
1439 BorderUnhighlight(Widget w
)
1441 XmEnhancedButtonWidget eb
= (XmEnhancedButtonWidget
)w
;
1443 (*(xmPushButtonClassRec
.primitive_class
.border_unhighlight
))(w
);
1444 draw_pixmap(eb
, NULL
, NULL
);
1447 #endif /* FEAT_TOOLBAR */