.\"remove .ig hn for full docs .de hi .ig eh .. .de eh .. .TH "" 3 "" "Version 3.0" "Free Widget Foundation" .SH NAME XfwfArrow .SH DESCRIPTION The Arrow widget is usually part of a composite scrollbar widget. It draws a triangle pointing up, down, left or right, depending on the \fIdirection\fP resource. It has a single callback, that is repeatedly called as long as a mouse button -- button 1 by default -- is pressed. The triangle has a 3D shadow, the size of which can be controlled with a resource. The shadow is either stippled or colored, depending on the \fIshadowScheme\fP and associated resources (see the XfwfFrame widget). .SS "Public variables" .ps-2 .TS center box; cBsss lB|lB|lB|lB l|l|l|l. XfwfArrow Name Class Type Default XtNdirection XtCDirection Alignment XfwfTop XtNforeground XtCForeground Pixel XtDefaultBackground XtNarrowShadow XtCArrowShadow Dimension 2 XtNinitialDelay XtCInitialDelay Cardinal 500 XtNrepeatDelay XtCRepeatDelay Cardinal 200 XtNcallback XtCCallback Callback NULL .TE .ps .TP .I "XtNdirection" The direction of the arrow (triangle) is given by the \fIdirection\fP resource, which is of type \fIAlignment\fP. Only \fI"top"\fP (\fIXfwfTop\fP), \fI"bottom"\fP (\fIXfwfBottom\fP), \fI"left"\fP (\fIXfwfLeft\fP) and \fI"right"\fP (\fIXfwfRight\fP) are valid directions. Other directions result in a warning. .hi .nf Alignment direction = XfwfTop .fi .eh .TP .I "XtNforeground" The color of the arrow also determines the color of the 3D shadow, at least if \fIshadowScheme\fP is set to \fIXfwfAuto\fP, as it is by default. .hi .nf Pixel foreground = XtDefaultBackground .fi .eh .TP .I "XtNarrowShadow" The width of the arrow's shadow is by default 2 pixels. .hi .nf Dimension arrowShadow = 2 .fi .eh .TP .I "XtNinitialDelay" When the user presses and then holds the mouse button, the action function waits some milliseconds before it starts repeating the callbacks. .hi .nf Cardinal initialDelay = 500 .fi .eh .TP .I "XtNrepeatDelay" Between repeated calls to the callback routines, the arrow widget will wait a few milliseconds. .hi .nf Cardinal repeatDelay = 200 .fi .eh .TP .I "XtNcallback" The \fIcallback\fP function is called by the \fIactivate\fP action. It is called repeatedly until the mouse button that triggered the action is released again. .hi .nf XtCallbackList callback = NULL .fi .eh .ps-2 .TS center box; cBsss lB|lB|lB|lB l|l|l|l. XfwfBoard Name Class Type Default XtNabs_x XtCAbs_x Position 0 XtNrel_x XtCRel_x Float "0.0" XtNabs_y XtCAbs_y Position 0 XtNrel_y XtCRel_y Float "0.0" XtNabs_width XtCAbs_width Position 0 XtNrel_width XtCRel_width Float "1.0" XtNabs_height XtCAbs_height Position 0 XtNrel_height XtCRel_height Float "1.0" XtNhunit XtCHunit Float "1.0" XtNvunit XtCVunit Float "1.0" XtNlocation XtCLocation String NULL .TE .ps .ps-2 .TS center box; cBsss lB|lB|lB|lB l|l|l|l. XfwfFrame Name Class Type Default XtNcursor XtCCursor Cursor None XtNframeType XtCFrameType FrameType XfwfRaised XtNframeWidth XtCFrameWidth Dimension 0 XtNouterOffset XtCOuterOffset Dimension 0 XtNinnerOffset XtCInnerOffset Dimension 0 XtNshadowScheme XtCShadowScheme ShadowScheme XfwfAuto XtNtopShadowColor XtCTopShadowColor Pixel compute_topcolor XtNbottomShadowColor XtCBottomShadowColor Pixel compute_bottomcolor XtNtopShadowStipple XtCTopShadowStipple Bitmap NULL XtNbottomShadowStipple XtCBottomShadowStipple Bitmap NULL .TE .ps .ps-2 .TS center box; cBsss lB|lB|lB|lB l|l|l|l. XfwfCommon Name Class Type Default XtNtraversalOn XtCTraversalOn Boolean True XtNhighlightThickness XtCHighlightThickness Dimension 2 XtNhighlightColor XtCHighlightColor Pixel XtDefaultForeground XtNhighlightPixmap XtCHighlightPixmap Pixmap None XtNnextTop XtCNextTop Callback NULL XtNuserData XtCUserData Pointer NULL .TE .ps .ps-2 .TS center box; cBsss lB|lB|lB|lB l|l|l|l. Composite Name Class Type Default XtNchildren XtCChildren WidgetList NULL insertPosition XtCInsertPosition XTOrderProc NULL numChildren XtCNumChildren Cardinal 0 .TE .ps .ps-2 .TS center box; cBsss lB|lB|lB|lB l|l|l|l. Core Name Class Type Default XtNx XtCX Position 0 XtNy XtCY Position 0 XtNwidth XtCWidth Dimension 0 XtNheight XtCHeight Dimension 0 borderWidth XtCBorderWidth Dimension 0 XtNcolormap XtCColormap Colormap NULL XtNdepth XtCDepth Int 0 destroyCallback XtCDestroyCallback XTCallbackList NULL XtNsensitive XtCSensitive Boolean True XtNtm XtCTm XTTMRec NULL ancestorSensitive XtCAncestorSensitive Boolean False accelerators XtCAccelerators XTTranslations NULL borderColor XtCBorderColor Pixel 0 borderPixmap XtCBorderPixmap Pixmap NULL background XtCBackground Pixel 0 backgroundPixmap XtCBackgroundPixmap Pixmap NULL mappedWhenManaged XtCMappedWhenManaged Boolean True XtNscreen XtCScreen Screen * NULL .TE .ps .SS "Translations" .nf : activate_and_start_timer() .fi .nf : stop_timer() .fi .hi .SS "Actions" .TP .I "activate_and_start_timer The \fIactivate\fP action calls the \fIcallback\fP routine once and installs a timeout routine. .hi .nf void activate_and_start_timer($, XEvent* event, String* params, Cardinal* num_params) { if (event->type != ButtonPress) { XtWarning("The Arrow activate action isn't bound to a BtnDown event"); return; } XtCallCallbackList($, $callback, NULL); $timer = XtAppAddTimeOut(XtWidgetToApplicationContext($), $initialDelay, timer_callback, $); } .fi .eh .TP .I "stop_timer .hi .nf void stop_timer($, XEvent* event, String* params, Cardinal* num_params) { XtRemoveTimeOut($timer); } .fi .eh .hi .hi .SH "Importss" The stipple for the shadows are loaded from a bitmap file. .nf .B incl "stip4.bm" .fi .nf .B incl .fi .nf .B incl .fi .hi .hi .SS "Private variables" The three GC's are used for drawing the arrow and its shadows. .nf GC arrowgc .fi .nf GC arrowlightgc .fi .nf GC arrowdarkgc .fi The repeating callback is implemented with a time out routine. The timer is a private variable of the widget. .nf XtIntervalId timer .fi .hi .hi .SS "Methods" The \fIinitialize\fP method sets initial values for the three GC's and checks the \fIdirection\fP resource. .nf initialize(Widget request, $, ArgList args, Cardinal * num_args) { if ($direction != XfwfTop $direction != XfwfLeft $direction != XfwfRight $direction != XfwfBottom) { XtWarning("direction of Arrow widget incorrect; set to `top'"); $direction = XfwfTop; } $arrowgc = NULL; create_arrowgc($); $arrowlightgc = NULL; create_arrowlightgc($); $arrowdarkgc = NULL; create_arrowdarkgc($); } .fi When the \fIforeground\fP, \fIarrowShadow\fP or \fIdirection\fP resource changes, the widget has to be redrawn. Like in the \fIinitialize\fP method, the \fIdirection\fP resource needs to be checked for valid values. If the inherited resource \fIshadowScheme\fP or one of its family changes, new GC's need to be created. .nf Boolean set_values(Widget old, Widget request, $, ArgList args, Cardinal * num_args) { Boolean need_redisplay = False; if ($direction != XfwfTop $direction != XfwfLeft $direction != XfwfRight $direction != XfwfBottom) { XtWarning("direction of Arrow widget incorrect; set to `top'"); $direction = XfwfTop; } if ($old$direction != $direction) need_redisplay = True; if ($old$foreground != $foreground) { create_arrowgc($); need_redisplay = True; } if ($old$arrowShadow != $arrowShadow) need_redisplay = True; if ($shadowScheme != $old$shadowScheme) { create_arrowdarkgc($); create_arrowlightgc($); need_redisplay = True; } else if ($shadowScheme == XfwfColor) { if ($topShadowColor != $old$topShadowColor) { create_arrowlightgc($); need_redisplay = True; } if ($bottomShadowColor != $old$bottomShadowColor) { create_arrowdarkgc($); need_redisplay = True; } } else if ($shadowScheme = XfwfStipple) { if ($topShadowStipple != $old$topShadowStipple) { create_arrowlightgc($); need_redisplay = True; } if ($bottomShadowStipple != $old$bottomShadowStipple) { create_arrowdarkgc($); need_redisplay = True; } } return need_redisplay; } .fi The arrow is drawn as large as possible. The arrow is actually a triangle with 3D shadows. \fIp1\fP is the triangle itself, \fIp2\fP, \fIp3\fP and \fIp4\fP are the shadows. \fBdef\fP point(p, i, xx, yy) = (p[i ].x =xx ),(p[i ].y =yy ) .nf expose($, XEvent * event, Region region) { XPoint p1[3], p2[4], p3[4], p4[4]; Position x, y; Dimension width, height, a, a2, a3; assert($direction == XfwfTop || $direction == XfwfLeft || $direction == XfwfRight || $direction == XfwfBottom); if (! XtIsRealized($)) return; if (region != NULL) { XSetRegion(XtDisplay($), $arrowgc, region); XSetRegion(XtDisplay($), $arrowlightgc, region); XSetRegion(XtDisplay($), $arrowdarkgc, region); } $compute_inside($, x, y, width, height); a = $arrowShadow; switch ($direction) { case XfwfTop: a2 = (1.0 + 0.71*width/height) * a; a3 = (1.0 + 0.83*height/width) * a; point(p1, 0, x + width/2, y + a3); point(p1, 1, x + a2, y + height - a); point(p1, 2, x + width - a2, y + height - a); XFillPolygon(XtDisplay($), $window, $arrowgc, p1, 3, Convex, CoordModeOrigin); if (a == 0) break; point(p2, 0, x + width/2, y); point(p2, 1, x + width/2, y + a3); point(p2, 2, x + width - a2, y + height - a); point(p2, 3, x + width, y + height); point(p3, 0, x + a2, y + height - a); point(p3, 1, x, y + height); point(p3, 2, x + width, y + height); point(p3, 3, x + width - a2, y + height - a); point(p4, 0, x + width/2, y); point(p4, 1, x, y + height); point(p4, 2, x + a2, y + height - a); point(p4, 3, x + width/2, y + a3); XFillPolygon(XtDisplay($), $window, $arrowdarkgc, p2, 4, Convex, CoordModeOrigin); XFillPolygon(XtDisplay($), $window, $arrowdarkgc, p3, 4, Convex, CoordModeOrigin); XFillPolygon(XtDisplay($), $window, $arrowlightgc, p4, 4, Convex, CoordModeOrigin); break; case XfwfLeft: a2 = (1.0 + 0.83*width/height) * a; a3 = (1.0 + 0.71*height/width) * a; point(p1, 0, x + a2, y + height/2); point(p1, 1, x + width - a, y + a3); point(p1, 2, x + width - a, y + height - a3); XFillPolygon(XtDisplay($), $window, $arrowgc, p1, 3, Convex, CoordModeOrigin); if ($arrowShadow == 0) break; point(p2, 0, x + width, y); point(p2, 1, x, y + height/2); point(p2, 2, x + a2, y + height/2); point(p2, 3, x + width - a, y + a3); point(p3, 0, x, y + height/2); point(p3, 1, x + width, y + height); point(p3, 2, x + width - a, y + height - a3); point(p3, 3, x + a2, y + height/2); point(p4, 0, x + width, y); point(p4, 1, x + width - a, y + a3); point(p4, 2, x + width - a, y + height - a3); point(p4, 3, x + width, y + height); XFillPolygon(XtDisplay($), $window, $arrowlightgc, p2, 4, Convex, CoordModeOrigin); XFillPolygon(XtDisplay($), $window, $arrowdarkgc, p3, 4, Convex, CoordModeOrigin); XFillPolygon(XtDisplay($), $window, $arrowdarkgc, p4, 4, Convex, CoordModeOrigin); break; case XfwfBottom: a2 = (1.0 + 0.71*width/height) * a; a3 = (1.0 + 0.83*height/width) * a; point(p1, 0, x + width/2, y + height - a3); point(p1, 1, x + a2, y + a); point(p1, 2, x + width - a2, y + a); XFillPolygon(XtDisplay($), $window, $arrowgc, p1, 3, Convex, CoordModeOrigin); if ($arrowShadow == 0) break; point(p2, 0, x, y); point(p2, 1, x + width/2, y + height); point(p2, 2, x + width/2, y + height - a3); point(p2, 3, x + a2, y + a); point(p3, 0, x + width, y); point(p3, 1, x + width - a2, y + a); point(p3, 2, x + width/2, y + height - a3); point(p3, 3, x + width/2, y + height); point(p4, 0, x, y); point(p4, 1, x + a2, y + a); point(p4, 2, x + width - a2, y + a); point(p4, 3, x + width, y); XFillPolygon(XtDisplay($), $window, $arrowlightgc, p2, 4, Convex, CoordModeOrigin); XFillPolygon(XtDisplay($), $window, $arrowdarkgc, p3, 4, Convex, CoordModeOrigin); XFillPolygon(XtDisplay($), $window, $arrowlightgc, p4, 4, Convex, CoordModeOrigin); break; case XfwfRight: a2 = (1.0 + 0.83*width/height) * a; a3 = (1.0 + 0.71*height/width) * a; point(p1, 0, x + width - $arrowShadow, y + height/2); point(p1, 1, x + $arrowShadow, y + $arrowShadow); point(p1, 2, x + $arrowShadow, y + height - $arrowShadow); XFillPolygon(XtDisplay($), $window, $arrowgc, p1, 3, Convex, CoordModeOrigin); if ($arrowShadow == 0) break; point(p2, 0, x, y + height); point(p2, 1, x + width, y + height/2); point(p2, 2, x + width - a2, y + height/2); point(p2, 3, x + a, y + height - a3); point(p3, 0, x, y); point(p3, 1, x + a, y + a3); point(p3, 2, x + width - a2, y + height/2); point(p3, 3, x + width, y + height/2); point(p4, 0, x, y); point(p4, 1, x, y + height); point(p4, 2, x + a, y + height - a3); point(p4, 3, x + a, y + a3); XFillPolygon(XtDisplay($), $window, $arrowdarkgc, p2, 4, Convex, CoordModeOrigin); XFillPolygon(XtDisplay($), $window, $arrowlightgc, p3, 4, Convex, CoordModeOrigin); XFillPolygon(XtDisplay($), $window, $arrowlightgc, p4, 4, Convex, CoordModeOrigin); break; } if (region != NULL) { XSetClipMask(XtDisplay($), $arrowgc, None); XSetClipMask(XtDisplay($), $arrowlightgc, None); XSetClipMask(XtDisplay($), $arrowdarkgc, None); } } .fi .hi .hi .SH "Utilities" The time-out calls the \fItimer_callback\fP routine. The routine re-installs the time-out and calls the \fIcallback\fP function (but in the reverse order, because we do not want time-outs to overtake each other). The delay is now \fIrepeatDelay\fP instead of \fIinitialDelay\fP. .nf timer_callback(XtPointer client_data, XtIntervalId * timer) { Widget $ = (Widget) client_data; XtCallCallbackList($, $callback, NULL); $timer = XtAppAddTimeOut(XtWidgetToApplicationContext($), $repeatDelay, timer_callback, $); } .fi The GC for the triangle is created by a utility function. It destroys the old GC and then creates a new one, based on the \fIforeground\fP resource. .nf create_arrowgc($) { XtGCMask mask; XGCValues values; if ($arrowgc != NULL) XtReleaseGC($, $arrowgc); mask = GCForeground; values.foreground = $foreground; $arrowgc = XtGetGC($, mask, values); } .fi The GC for the light shadow is dependent on the inherited \fIshadowScheme\fP resource. It is the same routine as for the shadows in the XfwfFrame widget. .nf create_arrowlightgc($) { XtGCMask mask; XGCValues values; if ($arrowlightgc != NULL) XtReleaseGC($, $arrowlightgc); switch ($shadowScheme) { case XfwfColor: mask = GCForeground; values.foreground = $topShadowColor; break; case XfwfStipple: mask = GCFillStyle | GCStipple | GCForeground | GCBackground; values.fill_style = FillOpaqueStippled; values.background = $background_pixel; values.stipple = $topShadowStipple; values.foreground = WhitePixelOfScreen(XtScreen($)); break; case XfwfAuto: if (DefaultDepthOfScreen(XtScreen($)) > 4 $lighter_color($, $foreground, values.foreground)) { mask = GCForeground; } else { mask = GCFillStyle | GCBackground | GCForeground | GCStipple; values.fill_style = FillOpaqueStippled; values.background = $foreground; values.foreground = WhitePixelOfScreen(XtScreen($)); values.stipple = XCreateBitmapFromData(XtDisplay($), RootWindowOfScreen(XtScreen($)), stip4_bits, stip4_width, stip4_height); } break; } $arrowlightgc = XtGetGC($, mask, values); } .fi The routine for the dark part of the shadow is analogous. .nf create_arrowdarkgc($) { XtGCMask mask; XGCValues values; if ($arrowdarkgc != NULL) XtReleaseGC($, $arrowdarkgc); switch ($shadowScheme) { case XfwfColor: mask = GCForeground; values.foreground = $bottomShadowColor; break; case XfwfStipple: mask = GCFillStyle | GCStipple | GCForeground | GCBackground; values.fill_style = FillOpaqueStippled; values.stipple = $bottomShadowStipple; values.foreground = BlackPixelOfScreen(XtScreen($)); values.background = $background_pixel; break; case XfwfAuto: if (DefaultDepthOfScreen(XtScreen($)) > 4 $darker_color($, $foreground, values.foreground)) { mask = GCForeground; } else { mask = GCFillStyle | GCBackground | GCForeground | GCStipple; values.fill_style = FillOpaqueStippled; values.background = $foreground; values.foreground = WhitePixelOfScreen(XtScreen($)); values.stipple = XCreateBitmapFromData(XtDisplay($), RootWindowOfScreen(XtScreen($)), stip4_bits, stip4_width, stip4_height); } break; } $arrowdarkgc = XtGetGC($, mask, values); } .fi .hi