/* * @OPENGROUP_COPYRIGHT@ * COPYRIGHT NOTICE * Copyright (c) 1990, 1991, 1992, 1993 Open Software Foundation, Inc. * Copyright (c) 1996, 1997, 1998, 1999, 2000 The Open Group * ALL RIGHTS RESERVED (MOTIF). See the file named COPYRIGHT.MOTIF for * the full copyright text. * * This software is subject to an open license. It may only be * used on, with or for operating systems which are themselves open * source systems. You must contact The Open Group for a license * allowing distribution and sublicensing of this software on, with, * or for operating systems which are not Open Source programs. * * See http://www.opengroup.org/openmotif/license for full * details of the license agreement. Any use, reproduction, or * distribution of the program constitutes recipient's acceptance of * this agreement. * * EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS * PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY * WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY * OR FITNESS FOR A PARTICULAR PURPOSE * * EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT * NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE * EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. */ /* * HISTORY */ #ifdef REV_INFO #ifndef lint static char rcsid[] = "$XConsortium: ArrowB.c /main/16 1995/10/25 19:50:57 cde-sun $" #endif #endif /* (c) Copyright 1987, 1988, 1989, 1990, 1991, 1992 HEWLETT-PACKARD COMPANY */ #include #include #include #include #include #include #include "PrimitiveI.h" #include "RepTypeI.h" #include "ScreenI.h" #include "TravActI.h" #include "TraversalI.h" #include "XmI.h" #define DELAY_DEFAULT 100 /******** Static Function Declarations ********/ static void ClassPartInitialize( WidgetClass wc); static void Initialize( Widget rw, Widget nw, ArgList args, Cardinal *num_args); static void GetArrowGC( XmArrowButtonWidget aw); static void Redisplay( Widget wid, XEvent *event, Region region); static void Destroy( Widget w); static Boolean SetValues( Widget cw, Widget rw, Widget nw, ArgList args, Cardinal *num_args); static void Arm( Widget wid, XEvent *event, String *params, Cardinal *num_params); static void MultiArm( Widget aw, XEvent *event, String *params, Cardinal *num_params); static void Activate( Widget wid, XEvent *buttonEvent, String *params, Cardinal *num_params); static void MultiActivate( Widget wid, XEvent *buttonEvent, String *params, Cardinal *num_params); static void ActivateCommon( Widget wid, XEvent *buttonEvent); static void ArmAndActivate( Widget wid, XEvent *event, String *params, Cardinal *num_params); static void ArmTimeout( XtPointer closure, XtIntervalId *id); static void Disarm( Widget wid, XEvent *event, String *params, Cardinal *num_params); static void Enter( Widget wid, XEvent *event, String *params, Cardinal *num_params); static void Leave( Widget wid, XEvent *event, String *params, Cardinal *num_params); static void ChangeCB(Widget w, XtCallbackProc activCB, XtPointer closure, Boolean setunset); static void DrawArrow(XmArrowButtonWidget aw, GC top_gc, GC bottom_gc, GC center_gc); /******** End Static Function Declarations ********/ /* Default translation table and action list */ #define defaultTranslations _XmArrowB_defaultTranslations static XtActionsRec actionsList[] = { { "Activate", Activate }, { "MultiActivate", MultiActivate }, { "Arm", Arm }, { "MultiArm", MultiArm }, { "Disarm", Disarm }, { "ArmAndActivate", ArmAndActivate }, { "Enter", Enter }, { "Leave", Leave }, { "ButtonTakeFocus", _XmButtonTakeFocus } }; /* Resource list for ArrowButton */ static XtResource resources[] = { { XmNmultiClick, XmCMultiClick, XmRMultiClick, sizeof(unsigned char), XtOffsetOf( struct _XmArrowButtonRec, arrowbutton.multiClick), XmRImmediate, (XtPointer) XmMULTICLICK_KEEP }, { XmNarrowDirection, XmCArrowDirection, XmRArrowDirection, sizeof(unsigned char), XtOffsetOf( struct _XmArrowButtonRec, arrowbutton.direction), XmRImmediate, (XtPointer) XmARROW_UP }, { XmNactivateCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList), XtOffsetOf( struct _XmArrowButtonRec, arrowbutton.activate_callback), XmRPointer, (XtPointer) NULL }, { XmNarmCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList), XtOffsetOf( struct _XmArrowButtonRec, arrowbutton.arm_callback), XmRPointer, (XtPointer) NULL }, { XmNdisarmCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList), XtOffsetOf( struct _XmArrowButtonRec, arrowbutton.disarm_callback), XmRPointer, (XtPointer) NULL }, { XmNdetailShadowThickness, XmCShadowThickness, XmRHorizontalDimension, sizeof (Dimension), XtOffsetOf(XmArrowButtonRec, arrowbutton.detail_shadow_thickness), XmRCallProc, (XtPointer) _XmSetThickness } }; static XmSyntheticResource syn_resources[] = { { XmNdetailShadowThickness, sizeof(Dimension), XtOffsetOf(XmArrowButtonRec, arrowbutton.detail_shadow_thickness), XmeFromHorizontalPixels,XmeToHorizontalPixels } }; /* The ArrowButton class record definition */ externaldef (xmarrowbuttonclassrec) XmArrowButtonClassRec xmArrowButtonClassRec= { { /* Core fields */ (WidgetClass) &xmPrimitiveClassRec, /* superclass */ "XmArrowButton", /* class_name */ sizeof(XmArrowButtonRec), /* widget_size */ (XtProc)NULL, /* class_initialize */ ClassPartInitialize, /* class_part_initialize */ FALSE, /* class_inited */ Initialize, /* initialize */ (XtArgsProc)NULL, /* initialize_hook */ XtInheritRealize, /* realize */ actionsList, /* actions */ XtNumber(actionsList), /* num_actions */ resources, /* resources */ XtNumber(resources), /* num_resources */ NULLQUARK, /* xrm_class */ TRUE, /* compress_motion */ XtExposeCompressMaximal, /* compress_exposure */ TRUE, /* compress_enterleave */ FALSE, /* visible_interest */ Destroy, /* destroy */ (XtWidgetProc)NULL, /* resize */ Redisplay, /* expose */ SetValues, /* set_values */ (XtArgsFunc)NULL, /* set_values_hook */ XtInheritSetValuesAlmost, /* set_values_almost */ (XtArgsProc)NULL, /* get_values_hook */ (XtAcceptFocusProc)NULL, /* accept_focus */ XtVersion, /* version */ (XtPointer)NULL, /* callback private */ defaultTranslations, /* tm_table */ (XtGeometryHandler)NULL, /* query_geometry */ (XtStringProc)NULL, /* display_accelerator */ (XtPointer)NULL /* extension */ }, { /* XmPrimitive fields */ XmInheritBorderHighlight, /* Primitive border_highlight */ XmInheritBorderUnhighlight, /* Primitive border_unhighlight */ XtInheritTranslations, /* translations */ ArmAndActivate, /* arm_and_activate */ syn_resources, /* syn_resources */ XtNumber(syn_resources), /* num_syn_resources */ (XtPointer) NULL /* extension */ }, { /* XmArrowButtonWidget fields */ (XtPointer) NULL /* extension */ } }; externaldef(xmarrowbuttonwidgetclass) WidgetClass xmArrowButtonWidgetClass = (WidgetClass) &xmArrowButtonClassRec; /* Trait record for arrowButton */ static XmConst XmActivatableTraitRec arrowButtonAT = { 0, /* version */ ChangeCB /* changeCB */ }; /************************************************************************ * * ClassPartInitialize * Set up the fast subclassing for the widget * ************************************************************************/ static void ClassPartInitialize( WidgetClass wc ) { _XmFastSubclassInit (wc, XmARROW_BUTTON_BIT); /* Install the activatable trait for all subclasses */ XmeTraitSet((XtPointer)wc, XmQTactivatable, (XtPointer) &arrowButtonAT); } /************************************************************************ * * Initialize * The main widget instance initialization routine. * ************************************************************************/ /*ARGSUSED*/ static void Initialize( Widget rw, Widget nw, ArgList args, /* unused */ Cardinal *num_args) /* unused */ { XmArrowButtonWidget request = (XmArrowButtonWidget) rw; XmArrowButtonWidget new_w = (XmArrowButtonWidget) nw; /* * Check the data put into the new widget from .Xdefaults * or through the arg list. */ if (!XmRepTypeValidValue(XmRID_ARROW_DIRECTION, new_w->arrowbutton.direction, (Widget) new_w)) { new_w->arrowbutton.direction = XmARROW_UP; } /* Set up a geometry for the widget if it is currently 0. */ if (request->core.width == 0) new_w->core.width += 15; if (request->core.height == 0) new_w->core.height += 15; /* Set the internal arrow variables */ new_w->arrowbutton.timer = 0; new_w->arrowbutton.selected = False; /* Get the drawing graphics contexts. */ GetArrowGC (new_w); } /************************************************************************ * * GetArrowGC * Get the graphics context used for drawing the arrowbutton. * ************************************************************************/ static void GetArrowGC( XmArrowButtonWidget aw ) { XGCValues values; XtGCMask valueMask, unusedMask; valueMask = GCForeground | GCBackground | GCGraphicsExposures; unusedMask = GCClipXOrigin | GCClipYOrigin | GCFont; values.foreground = aw->primitive.foreground; values.background = aw->core.background_pixel; values.graphics_exposures = False; aw->arrowbutton.arrow_GC = XtAllocateGC((Widget) aw, 0, valueMask, &values, GCClipMask, unusedMask); valueMask |= GCFillStyle | GCStipple; values.fill_style = FillOpaqueStippled; values.stipple = _XmGetInsensitiveStippleBitmap((Widget) aw); aw->arrowbutton.insensitive_GC = XtAllocateGC((Widget) aw, 0, valueMask, &values, GCClipMask, unusedMask); } /************************************************************************ * * Redisplay * General redisplay function called on exposure events. * ************************************************************************/ static void Redisplay( Widget wid, XEvent *event, Region region ) { XmArrowButtonWidget aw = (XmArrowButtonWidget) wid; int iwidth, iheight; XtExposeProc expose; iwidth = (int) aw->core.width - 2 * aw->primitive.highlight_thickness; iheight = (int) aw->core.height - 2 * aw->primitive.highlight_thickness; /* Draw the arrow */ if ((iwidth > 0) && (iheight > 0)) { if (aw->primitive.shadow_thickness > 0) XmeDrawShadows(XtDisplay (aw), XtWindow (aw), aw->primitive.top_shadow_GC, aw->primitive.bottom_shadow_GC, aw->primitive.highlight_thickness, aw->primitive.highlight_thickness, aw->core.width - 2 * aw->primitive.highlight_thickness, aw->core.height - 2 * aw->primitive.highlight_thickness, aw->primitive.shadow_thickness, XmSHADOW_OUT); if (aw->arrowbutton.selected && XtIsSensitive(wid)) DrawArrow(aw, aw->primitive.bottom_shadow_GC, aw->primitive.top_shadow_GC, aw->arrowbutton.arrow_GC); else DrawArrow(aw, aw->primitive.top_shadow_GC, aw->primitive.bottom_shadow_GC, (XtIsSensitive(wid) ? aw->arrowbutton.arrow_GC : aw->arrowbutton.insensitive_GC)); } /* Envelop our superclass expose method */ _XmProcessLock(); expose = xmPrimitiveClassRec.core_class.expose; _XmProcessUnlock(); (*(expose)) ((Widget) aw, event, region); } /************************************************************************ * * Destroy * Clean up allocated resources when the widget is destroyed. * ************************************************************************/ static void Destroy( Widget w ) { XmArrowButtonWidget aw = (XmArrowButtonWidget) w; if (aw->arrowbutton.timer) XtRemoveTimeOut(aw->arrowbutton.timer); XtReleaseGC(w, aw->arrowbutton.arrow_GC); XtReleaseGC(w, aw->arrowbutton.insensitive_GC); } /************************************************************************ * * SetValues * ************************************************************************/ /*ARGSUSED*/ static Boolean SetValues( Widget cw, Widget rw, Widget nw, ArgList args, /* unused */ Cardinal *num_args) /* unused */ { XmArrowButtonWidget current = (XmArrowButtonWidget) cw; XmArrowButtonWidget new_w = (XmArrowButtonWidget) nw; Boolean returnFlag = FALSE; /* Check the data put into the new widget. */ if (!XmRepTypeValidValue(XmRID_ARROW_DIRECTION, new_w->arrowbutton.direction, (Widget) new_w)) { new_w->arrowbutton.direction = current->arrowbutton.direction; } /* See if the GC's need to be regenerated and widget redrawn. */ if (new_w->core.background_pixel != current->core.background_pixel || new_w->primitive.foreground != current->primitive.foreground) { returnFlag = TRUE; XtReleaseGC ((Widget) new_w, new_w->arrowbutton.arrow_GC); XtReleaseGC ((Widget) new_w, new_w->arrowbutton.insensitive_GC); GetArrowGC (new_w); } if (new_w->arrowbutton.direction != current->arrowbutton.direction || XtIsSensitive(nw) != XtIsSensitive(cw) || new_w->primitive.highlight_thickness != current->primitive.highlight_thickness || new_w->primitive.shadow_thickness != current->primitive.shadow_thickness) { returnFlag = TRUE; } return (returnFlag); } /************************************************************************ * * Arm * This function processes button 1 down occuring on the arrowButton. * ************************************************************************/ /*ARGSUSED*/ static void Arm( Widget wid, XEvent *event, String *params, /* unused */ Cardinal *num_params) /* unused */ { XmArrowButtonWidget aw = (XmArrowButtonWidget) wid; XmArrowButtonCallbackStruct call_value; (void) XmProcessTraversal((Widget) aw, XmTRAVERSE_CURRENT); aw->arrowbutton.selected = True; aw->arrowbutton.armTimeStamp = event->xbutton.time; /* see MultiActivate */ DrawArrow(aw, aw->primitive.bottom_shadow_GC, aw->primitive.top_shadow_GC, NULL); if (aw->arrowbutton.arm_callback) { XFlush(XtDisplay(aw)); call_value.reason = XmCR_ARM; call_value.event = event; XtCallCallbackList((Widget) aw, aw->arrowbutton.arm_callback, &call_value); } } static void MultiArm( Widget aw, XEvent *event, String *params, Cardinal *num_params) { if (((XmArrowButtonWidget) aw)->arrowbutton.multiClick == XmMULTICLICK_KEEP) Arm(aw, event, params, num_params); } /************************************************************************ * * Activate * This function processes button 1 up occuring on the arrowButton. * If the button 1 up occurred inside the button the activate * callbacks are called. * ************************************************************************/ /*ARGSUSED*/ static void Activate( Widget wid, XEvent *buttonEvent, String *params, /* unused */ Cardinal *num_params) /* unused */ { XmArrowButtonWidget aw = (XmArrowButtonWidget) wid; if (aw->arrowbutton.selected == False) return; aw->arrowbutton.click_count = 1; ActivateCommon((Widget) aw, buttonEvent); } static void MultiActivate( Widget wid, XEvent *buttonEvent, String *params, Cardinal *num_params) { /* When a multi click sequence occurs and the user Button Presses and * holds for a length of time, the final release should look like a * new/separate activate. */ XmArrowButtonWidget aw = (XmArrowButtonWidget) wid; if (aw->arrowbutton.multiClick == XmMULTICLICK_KEEP) { if ((buttonEvent->xbutton.time - aw->arrowbutton.armTimeStamp) > XtGetMultiClickTime(XtDisplay(aw))) aw->arrowbutton.click_count = 1; else aw->arrowbutton.click_count++; ActivateCommon((Widget) aw, buttonEvent); Disarm ((Widget) aw, buttonEvent, params, num_params); } } static void ActivateCommon( Widget wid, XEvent *buttonEvent) { XmArrowButtonWidget aw = (XmArrowButtonWidget) wid; XmArrowButtonCallbackStruct call_value; aw->arrowbutton.selected = False; DrawArrow(aw, aw->primitive.top_shadow_GC, aw->primitive.bottom_shadow_GC, NULL); /* CR 9181: Consider clipping when testing visibility. */ if (((buttonEvent->xany.type == ButtonPress) || (buttonEvent->xany.type == ButtonRelease)) && _XmGetPointVisibility(wid, buttonEvent->xbutton.x_root, buttonEvent->xbutton.y_root) && (aw->arrowbutton.activate_callback)) { XFlush(XtDisplay(aw)); call_value.reason = XmCR_ACTIVATE; call_value.event = buttonEvent; call_value.click_count = aw->arrowbutton.click_count; if ((aw->arrowbutton.multiClick == XmMULTICLICK_DISCARD) && (call_value.click_count > 1)) return; XtCallCallbackList((Widget) aw, aw->arrowbutton.activate_callback, &call_value); } } /************************************************************************ * * ArmAndActivate * ************************************************************************/ /*ARGSUSED*/ static void ArmAndActivate( Widget wid, XEvent *event, String *params, /* unused */ Cardinal *num_params) /* unused */ { XmArrowButtonWidget ab = (XmArrowButtonWidget) wid; XmArrowButtonCallbackStruct call_value; XtExposeProc expose; ab->arrowbutton.selected = TRUE; _XmProcessLock(); expose = ab->core.widget_class->core_class.expose; _XmProcessUnlock(); (*(expose)) ((Widget) ab, event, FALSE); XFlush (XtDisplay (ab)); if (ab->arrowbutton.arm_callback) { call_value.reason = XmCR_ARM; call_value.event = event; XtCallCallbackList((Widget)ab, ab->arrowbutton.arm_callback, &call_value); } call_value.reason = XmCR_ACTIVATE; call_value.event = event; call_value.click_count = 1; /* always 1 in kselect */ if (ab->arrowbutton.activate_callback) { XFlush (XtDisplay (ab)); XtCallCallbackList((Widget)ab,ab->arrowbutton.activate_callback, &call_value); } ab->arrowbutton.selected = FALSE; if (ab->arrowbutton.disarm_callback) { XFlush (XtDisplay (ab)); call_value.reason = XmCR_DISARM; XtCallCallbackList((Widget) ab, ab->arrowbutton.disarm_callback, &call_value); } /* If the button is still around, show it released after a short delay */ if (ab->core.being_destroyed == False) { ab->arrowbutton.timer = XtAppAddTimeOut(XtWidgetToApplicationContext((Widget)ab), (unsigned long) DELAY_DEFAULT, ArmTimeout, (XtPointer)ab); } } /* ARGSUSED */ static void ArmTimeout( XtPointer closure, XtIntervalId *id ) { XmArrowButtonWidget ab = (XmArrowButtonWidget) closure; ab->arrowbutton.timer = 0; if (XtIsRealized((Widget)ab) && XtIsManaged((Widget)ab)) { XtExposeProc expose; _XmProcessLock(); expose = ab->core.widget_class->core_class.expose; _XmProcessUnlock(); (*(expose)) ((Widget) ab, NULL, FALSE); XFlush (XtDisplay (ab)); } } /************************************************************************ * * Disarm * This function processes button 1 up occuring on the arrowButton. * ************************************************************************/ /*ARGSUSED*/ static void Disarm( Widget wid, XEvent *event, String *params, /* unused */ Cardinal *num_params) /* unused */ { XmArrowButtonWidget aw = (XmArrowButtonWidget) wid; XmArrowButtonCallbackStruct call_value; aw->arrowbutton.selected = False; DrawArrow(aw, aw->primitive.top_shadow_GC, aw->primitive.bottom_shadow_GC, NULL); call_value.reason = XmCR_DISARM; call_value.event = event; XtCallCallbackList((Widget) aw, aw->arrowbutton.disarm_callback, &call_value); } /************************************************************************ * * Enter * ************************************************************************/ static void Enter( Widget wid, XEvent *event, String *params, Cardinal *num_params ) { XmArrowButtonWidget aw = (XmArrowButtonWidget) wid; _XmPrimitiveEnter (wid, event, params, num_params); if (aw->arrowbutton.selected && XtIsSensitive(wid)) DrawArrow(aw, aw->primitive.bottom_shadow_GC, aw->primitive.top_shadow_GC, NULL); } /************************************************************************ * * Leave * ************************************************************************/ static void Leave( Widget wid, XEvent *event, String *params, Cardinal *num_params ) { XmArrowButtonWidget aw = (XmArrowButtonWidget) wid; _XmPrimitiveLeave (wid, event, params, num_params); if (aw->arrowbutton.selected && XtIsSensitive(wid)) DrawArrow(aw, aw->primitive.top_shadow_GC, aw->primitive.bottom_shadow_GC, NULL); } /************************************************************************ * * ChangeCB * add or remove the activate callback list. * ************************************************************************/ static void ChangeCB( Widget w, XtCallbackProc activCB, XtPointer closure, Boolean setunset) { if (setunset) XtAddCallback (w, XmNactivateCallback, activCB, closure); else XtRemoveCallback (w, XmNactivateCallback, activCB, closure); } /************************************************************************ * * XmCreateArrowButton * Create an instance of an arrowbutton and return the widget id. * ************************************************************************/ Widget XmCreateArrowButton( Widget parent, char *name, ArgList arglist, Cardinal argcount ) { return XtCreateWidget(name, xmArrowButtonWidgetClass, parent, arglist, argcount); } /* Wrapper around XmeDrawArrow to calculate sizes. */ static void DrawArrow(XmArrowButtonWidget aw, GC top_gc, GC bottom_gc, GC center_gc) { Position x, y; Dimension width, height; Dimension margin = (aw->primitive.highlight_thickness + aw->primitive.shadow_thickness); /* Don't let large margins cause confusion. */ if (margin <= (aw->core.width / 2)) { x = margin; width = aw->core.width - (margin * 2); } else { x = aw->core.width / 2; width = 0; } if (margin <= (aw->core.height / 2)) { y = margin; height = aw->core.height - (margin * 2); } else { y = aw->core.height / 2; height = 0; } /* The way we currently handle 1 shadowThickness in XmeDrawArrow is by drawing the center a little bit bigger, so the center_gc has to be present. Kinda hacky... */ if (!center_gc && aw->arrowbutton.detail_shadow_thickness == 1) center_gc = aw->arrowbutton.arrow_GC ; if (center_gc) XSetClipMask(XtDisplay((Widget)aw), center_gc, None); XmeDrawArrow (XtDisplay ((Widget) aw), XtWindow ((Widget) aw), top_gc, bottom_gc, center_gc, x, y, width, height, aw->arrowbutton.detail_shadow_thickness, aw->arrowbutton.direction); }