home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / x / volume10 / xt-examples / part04 / Label.c < prev   
Encoding:
C/C++ Source or Header  |  1990-11-04  |  15.7 KB  |  579 lines

  1. /***********************************************************
  2. Copyright 1990 by Digital Equipment Corporation, Maynard, Massachusetts.
  3.  
  4.                         All Rights Reserved
  5.  
  6. Permission to use, copy, modify, and distribute these examples for any
  7. purpose and without fee is hereby granted, provided that the above
  8. copyright notice appear in all copies and that both that copyright
  9. notice and this permission notice appear in supporting documentation,
  10. and that the name of Digital not be used in advertising or publicity
  11. pertaining to distribution of the software without specific, written
  12. prior permission.
  13.  
  14. DIGITAL AND THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
  15. SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
  16. FITNESS, IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT
  17. OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
  18. OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  19. OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
  20. OR PERFORMANCE OF THIS SOFTWARE.
  21.  
  22. ******************************************************************/
  23.  
  24. #include <X11/Xos.h>        /* Needed for string manipulation */
  25. #include <X11/IntrinsicP.h>    /* Intrinsics header file */
  26. #include <X11/StringDefs.h>    /* Resource string definitions */
  27. #include <X11/Xatom.h>        /* For selection atoms */
  28. #include "LabelP.h"        /* Label private header file */
  29.  
  30. #define Offset(field) XtOffsetOf(LabelRec, label.field)
  31.  
  32. static XtResource resources[] = {
  33.     {XtNlabel, XtCLabel, XtRString, sizeof(String),
  34.     Offset(label), XtRString, (XtPointer) NULL},
  35.     {XtNfont,  XtCFont, XtRFontStruct, sizeof(XFontStruct *),
  36.     Offset(font), XtRString, (XtPointer) XtDefaultFont},
  37.     {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
  38.     Offset(foreground), XtRString,
  39.     (XtPointer) XtDefaultForeground},
  40.     {XtNjustify, XtCJustify, XtRJustify, sizeof(Justify),
  41.     Offset(justify), XtRImmediate, (XtPointer) Left},
  42.     {XtNspace, XtCSpace, XtRDimension, sizeof(Dimension),
  43.     Offset(space), XtRImmediate, (XtPointer) 2},
  44.     {XtNloseSelection, XtCLoseSelection, XtRCallback, 
  45.     sizeof(XtCallbackList), Offset(lose_selection),
  46.     XtRCallback, (XtPointer) NULL},
  47.     {XtNborderWidth, XtCBorderWidth, XtRDimension, sizeof(Dimension),
  48.         XtOffsetOf(LabelRec, core.border_width),
  49.     XtRImmediate, (XtPointer) 0},
  50. };
  51. #undef Offset
  52.  
  53. /* Forward declarations */
  54.  
  55. static void ClassInitialize(), ClassPartInitialize(), Initialize(),
  56.     Redisplay(), Destroy(), Resize(), LoseSelection();
  57. static Boolean SetValues(), SelectText();
  58. static XtGeometryResult QueryGeometry();
  59.  
  60. /* Class record declaration */
  61.  
  62. LabelClassRec labelClassRec = {
  63.     /* Core class part */
  64.   {
  65.     /* superclass         */    (WidgetClass) &widgetClassRec,
  66.     /* class_name         */    "Label",
  67.     /* widget_size         */    sizeof(LabelRec),
  68.     /* class_initialize      */ ClassInitialize,
  69.     /* class_part_initialize */    ClassPartInitialize,
  70.     /* class_inited          */    FALSE,
  71.     /* initialize         */    Initialize,
  72.     /* initialize_hook       */    NULL,        
  73.     /* realize             */    XtInheritRealize,
  74.     /* actions             */    NULL,
  75.     /* num_actions         */    0,
  76.     /* resources         */    resources,
  77.     /* num_resources         */    XtNumber(resources),
  78.     /* xrm_class         */    NULLQUARK,
  79.     /* compress_motion         */    TRUE,
  80.     /* compress_exposure     */    XtExposeCompressMultiple,
  81.     /* compress_enterleave   */    TRUE,
  82.     /* visible_interest         */    FALSE,
  83.     /* destroy             */    Destroy,
  84.     /* resize             */    Resize,
  85.     /* expose             */    Redisplay,
  86.     /* set_values         */    SetValues,
  87.     /* set_values_hook       */    NULL,            
  88.     /* set_values_almost     */    XtInheritSetValuesAlmost,  
  89.     /* get_values_hook       */    NULL,            
  90.     /* accept_focus         */    NULL,
  91.     /* version             */    XtVersion,
  92.     /* callback offsets      */ NULL,
  93.     /* tm_table              */ NULL,
  94.     /* query_geometry         */    QueryGeometry,
  95.     /* display_accelerator   */ NULL,
  96.     /* extension             */ NULL
  97.   },
  98.     /* Label class part    */
  99.   {
  100.     /* select             */ SelectText,
  101.     /* extension             */ NULL
  102.   }
  103. };
  104.  
  105. /* Class record pointer */
  106.  
  107. WidgetClass labelWidgetClass = (WidgetClass) &labelClassRec;
  108.  
  109. static Boolean LowerCase(from, to, size)
  110.     register String from, to;
  111.     int size;
  112. {
  113.     register char ch;
  114.     register int i;
  115.  
  116.     for (i = 0; i < size; i++) {
  117.     ch = from[i];
  118.     if (ch >= 'A' && ch <= 'Z') to[i] = ch - 'A' + 'a';
  119.     else to[i] = ch;
  120.     if (ch == '\0') return FALSE;
  121.     }
  122.     return TRUE;
  123. }
  124.  
  125. Boolean CvtStringToJustify(dpy, args, num_args, from, to, data)
  126.     Display *dpy;
  127.     XrmValuePtr args;
  128.     Cardinal *num_args;
  129.     XrmValuePtr from, to;
  130.     XtPointer *data;
  131. {
  132. #define LOWER_SIZE 10
  133.     char lower[LOWER_SIZE];    /* Lower cased string value */
  134.     register int i;
  135.     Boolean badConvert;
  136.     static Justify j;
  137.  
  138.     if (*num_args != 0) {    /* Check for correct number */
  139.     XtAppErrorMsg(XtDisplayToApplicationContext(dpy),
  140.            "cvtStringToJustify", "wrongParameters",
  141.            "XtToolkitError",
  142.            "String to justify conversion needs no extra arguments",
  143.            (String *) NULL, (Cardinal *) NULL);
  144.     }
  145.  
  146.     /* Lower case the value */
  147.     badConvert = LowerCase(from->addr, lower, LOWER_SIZE);
  148.  
  149.     /* Try to convert if a short enough string specified */
  150.     if (!badConvert) {
  151.     if (strcmp(lower, "left") == 0) j = Left;
  152.     else if (strcmp(lower, "center") == 0) j = Center;
  153.     else if (strcmp(lower, "right") == 0) j = Right;
  154.     else badConvert = TRUE;
  155.     }
  156.  
  157.     /* String too long or unknown value -- issue warning */
  158.     if (badConvert) {
  159.     XtDisplayStringConversionWarning(dpy, from->addr, "Justify");
  160.     } else {
  161.     if (to->addr == NULL) to->addr = (caddr_t) &j;
  162.     else if (to->size < sizeof(Justify)) badConvert = TRUE;
  163.     else *(Justify *) to->addr = j;
  164.  
  165.     to->size = sizeof(Justify);
  166.     }
  167.     return !badConvert;
  168. #undef LOWER_SIZE
  169. }
  170.  
  171. #if 0
  172. Boolean CvtStringToJustify(dpy, args, num_args, from, to, data)
  173.     Display *dpy;
  174.     XrmValuePtr args;
  175.     Cardinal *num_args;
  176.     XrmValuePtr from, to;
  177.     XtPointer *data;
  178. {
  179. #define LOWER_SIZE 10
  180.     char lower[LOWER_SIZE];    /* Lower cased string value */
  181.     register int i;
  182.     Boolean badConvert;
  183.     XrmQuark q;
  184.     static Justify j;
  185.     static XrmQuark Qleft, Qcenter, Qright;
  186.     static Boolean haveQuarks = FALSE;
  187.  
  188.     if (*num_args != 0) {    /* Check for correct number */
  189.     XtAppErrorMsg(XtDisplayToApplicationContext(dpy),
  190.            "cvtStringToJustify", "wrongParameters",
  191.            "XtToolkitError",
  192.            "String to justify conversion needs no extra arguments",
  193.            (String *) NULL, (Cardinal *) NULL);
  194.     }
  195.  
  196.     if (!haveQuarks) {
  197.     Qleft   = XrmStringToQuark("left");
  198.     Qcenter = XrmStringToQuark("center");
  199.     Qright  = XrmStringToQuark("right");
  200.     haveQuarks = TRUE;
  201.     }
  202.  
  203.     badConvert = LowerCase(from->addr, lower, LOWER_SIZE);
  204.  
  205.     /* Try to convert if a short enough string specified */
  206.  
  207.     if (!badConvert) {
  208.     q = XrmStringToQuark(lower);
  209.     if (q == Qleft) j = Left;
  210.     else if (q == Qcenter) j = Center;
  211.     else if (q == Qright) j = Right;
  212.     else badConvert = TRUE;
  213.     }
  214.  
  215.     /* String too long or unknown value -- issue warning */
  216.  
  217.     if (badConvert) {
  218.     XtDisplayStringConversionWarning(dpy, from->addr, "Justify");
  219.     } else {
  220.     if (to->addr == NULL) to->addr = (caddr_t) &j;
  221.     else if (to->size < sizeof(Justify)) badConvert = TRUE;
  222.     else *(Justify *) to->addr = j;
  223.  
  224.     to->size = sizeof(Justify);
  225.     }
  226.     return !badConvert;
  227. #undef LOWER_SIZE
  228. }
  229. #endif
  230.  
  231. static Atom FetchAtom(w, name)
  232.     Widget w;
  233.     String name;
  234. {
  235.     Atom a;
  236.     XrmValue source, dest;
  237.  
  238.     source.size = strlen(name)+1;
  239.     source.addr = name;
  240.     dest.size = sizeof(Atom);
  241.     dest.addr = (caddr_t) &a;
  242.     
  243.     (void) XtConvertAndStore(w, XtRString, &source, XtRAtom, &dest);
  244.     return a;
  245. }
  246.     
  247. static Boolean DeliverSelection(w, selection, target,
  248.     type, value, length, format)
  249.     Widget w;
  250.     Atom *selection, *target, *type;
  251.     XtPointer *value;
  252.     unsigned long *length;
  253.     int *format;
  254. {
  255.     LabelWidget lw = (LabelWidget) w;
  256.     static Atom targets = 0;
  257.  
  258.     if (targets == 0) {
  259.     targets = FetchAtom(w, "TARGETS");
  260.     }
  261.  
  262.     if (*target == targets) {
  263.     *type = XA_ATOM;
  264.     *value = (XtPointer) XtNew(Atom);
  265.     *(Atom *) *value = XA_STRING;
  266.     *length = 1;
  267.     *format = 32;
  268.     return TRUE;
  269.     }
  270.  
  271.     if (*target == XA_STRING) {
  272.     *type = XA_STRING;
  273.     *value = (XtPointer) XtNewString(lw->label.label);
  274.     *length = lw->label.label_len;
  275.     *format = 8;
  276.     return TRUE;
  277.     }
  278.  
  279.     return FALSE;    
  280. }
  281.  
  282. static void LoseSelection(w, selection)
  283.     Widget w;
  284.     Atom *selection;
  285. {
  286.     LabelWidget lw = (LabelWidget) w;
  287.  
  288.     XtCallCallbackList(lw, lw->label.lose_selection,
  289.         (XtPointer) selection);
  290. }
  291.  
  292. /* Label's select implementation */
  293.  
  294. static Boolean SelectText(w, selection, own)
  295.     Widget w;
  296.     Atom selection;
  297.     Boolean own;
  298. {
  299.     LabelWidget lw = (LabelWidget) w;
  300.  
  301.     if (own) {
  302.     return XtOwnSelection(w, selection,
  303.         XtLastTimestampProcessed(XtDisplay(w)),
  304.         DeliverSelection, LoseSelection,
  305.         (XtSelectionDoneProc) NULL);
  306.     } else {
  307.     XtDisownSelection(w, selection,
  308.         XtLastTimestampProcessed(XtDisplay(w)));
  309.     return TRUE;
  310.     }
  311. }
  312.  
  313. Boolean LabelSelectText(w, selection, own)
  314.     Widget w;
  315.     Atom selection;
  316.     Boolean own;
  317. {
  318.     /* Check that we're in Label or a subclass */
  319.  
  320.     XtCheckSubclass(w, labelWidgetClass, NULL);
  321.  
  322.     /* Call the class method */
  323.  
  324.     return (*((LabelWidgetClass) XtClass(w))->label_class.select)
  325.         (w, selection, own);
  326. }
  327.  
  328. static void ClassInitialize()
  329. {
  330.     /* Register a converter for string to justification */
  331.  
  332.     XtSetTypeConverter(XtRString, XtRJustify, CvtStringToJustify,
  333.         (XtConvertArgList) NULL, 0,
  334.         XtCacheAll, (XtDestructor) NULL);
  335. }
  336.  
  337. static void ClassPartInitialize(widget_class)
  338.     WidgetClass widget_class;
  339. {
  340.     register LabelWidgetClass wc = (LabelWidgetClass) widget_class;
  341.     LabelWidgetClass super =
  342.         (LabelWidgetClass) wc->core_class.superclass;
  343.  
  344.     if (wc->label_class.select == InheritSelectText) {
  345.     wc->label_class.select = super->label_class.select;
  346.     }
  347. }
  348.  
  349. static void SetTextWidthAndHeight(lw)
  350.     register LabelWidget lw;
  351. {
  352.     register XFontStruct *fs = lw->label.font;
  353.     int accel_len;
  354.  
  355.     lw->label.label_len = strlen(lw->label.label);
  356.     lw->label.label_width =
  357.         XTextWidth(fs, lw->label.label, lw->label.label_len);
  358.     lw->label.label_height =
  359.         fs->max_bounds.ascent + fs->max_bounds.descent;
  360.  
  361.     if (lw->label.accel_string != NULL) {
  362.     accel_len = strlen(lw->label.accel_string);
  363.     lw->label.label_len += accel_len;
  364.     lw->label.label_width +=
  365.         XTextWidth(fs, lw->label.accel_string, accel_len);
  366.     }
  367. }
  368.  
  369. static GC GetNormalGC(lw)
  370.     LabelWidget lw;
  371. {
  372.     XGCValues    values;
  373.  
  374.     /* Allocate a graphics context with the foreground and font */
  375.  
  376.     values.foreground = lw->label.foreground;
  377.     values.font = lw->label.font->fid;
  378.     return XtGetGC((Widget) lw, GCForeground | GCFont, &values);
  379. }
  380.  
  381. static void Initialize(request, new, args, num_args)
  382.     Widget request, new;
  383.     ArgList args;
  384.     Cardinal *num_args;
  385. {
  386.     LabelWidget lw = (LabelWidget) new;
  387.  
  388.     /* If no label is specified, use the name */
  389.     if (lw->label.label == NULL) lw->label.label = lw->core.name;
  390.  
  391.     /* Copy the label */
  392.     lw->label.label = XtNewString(lw->label.label);
  393.  
  394.     /* Clear accelerator string */
  395.     lw->label.accel_string = NULL;
  396.  
  397.     /* Compute the text dimensions and get a graphics context. */
  398.     SetTextWidthAndHeight(lw);
  399.     lw->label.gc = lw->label.current_gc = GetNormalGC(lw);
  400.  
  401.     /* If no size specified, compute one */
  402.     lw->label.size_computed =
  403.         (lw->core.width == 0) && (lw->core.height == 0);
  404.  
  405.     if (lw->core.width == 0) {
  406.     lw->core.width = lw->label.label_width + 2 * lw->label.space;
  407.     }
  408.     if (lw->core.height == 0) {
  409.     lw->core.height = lw->label.label_height + 2 * lw->label.space;
  410.     }
  411.  
  412.     lw->label.desired_width = lw->core.width;
  413.     lw->label.desired_height = lw->core.height;
  414. }
  415.  
  416. static Boolean SetValues(old, request, new, args, num_args)
  417.     Widget  old, request, new;
  418.     ArgList args;
  419.     Cardinal *num_args;
  420. {
  421.     LabelWidget oldlw = (LabelWidget) old;
  422.     LabelWidget newlw = (LabelWidget) new;
  423.     Boolean redisplay = FALSE;
  424.  
  425. #define NE(field) (oldlw->field != newlw->field)
  426.  
  427.     /* If the label has been reset to NULL, change to the name */
  428.  
  429.     if (newlw->label.label == NULL) {
  430.     newlw->label.label = newlw->core.name;
  431.     }
  432.  
  433.     /* Decide whether to compute the size */
  434.  
  435.     if (newlw->core.width == 0 && newlw->core.height == 0) {
  436.     newlw->label.size_computed = TRUE;
  437.     } else if (NE(core.width) || NE(core.height)) {
  438.     newlw->label.size_computed = FALSE;
  439.     if (NE(core.width)) {
  440.         newlw->label.desired_width = newlw->core.width;
  441.     }
  442.     if (NE(core.height)) {
  443.         newlw->label.desired_height = newlw->core.height;
  444.     }
  445.     } /* else leave the same */
  446.  
  447.     /* If label, font, or accelerator string has changed, 
  448.        compute size and recopy */
  449.  
  450.     if (NE(label.label) || NE(label.font) || NE(label.accel_string)) {
  451.     SetTextWidthAndHeight(newlw);
  452.     redisplay = TRUE;
  453.  
  454.     if (NE(label.label)) {
  455.         XtFree((char *) oldlw->label.label);
  456.         newlw->label.label = XtNewString(newlw->label.label);
  457.     }
  458.  
  459.     if (NE(label.accel_string)) {
  460.         XtFree((char *) oldlw->label.accel_string);
  461.         newlw->label.accel_string =
  462.             XtNewString(newlw->label.accel_string);
  463.     }
  464.     }
  465.  
  466.     /* Compute the size if necessary */
  467.  
  468.     if ((newlw->label.size_computed && redisplay) ||
  469.         newlw->core.width == 0) {
  470.     newlw->label.desired_width = newlw->core.width =
  471.         newlw->label.label_width + 2 * newlw->label.space;
  472.     }
  473.     if ((newlw->label.size_computed && redisplay) ||
  474.         newlw->core.height == 0) {
  475.     newlw->label.desired_height = newlw->core.height =
  476.         newlw->label.label_height + 2 * newlw->label.space;
  477.     }
  478.     
  479.     /* If foreground or font has changed, update GC */
  480.  
  481.     if (NE(label.foreground) || NE(label.font->fid)) {
  482.     XtReleaseGC(newlw, oldlw->label.gc);
  483.     newlw->label.gc = GetNormalGC(newlw);
  484.  
  485.     if (newlw->label.current_gc == oldlw->label.gc) {
  486.         newlw->label.current_gc = newlw->label.gc;
  487.         redisplay = TRUE;
  488.     }
  489.     }
  490.  
  491.     return redisplay || NE(label.space) || NE(label.justify);
  492. #undef NE
  493. }
  494.  
  495. static void Destroy(w)
  496.     Widget w;
  497. {
  498.     LabelWidget lw = (LabelWidget) w;
  499.  
  500.     XtFree((char *) lw->label.label);
  501.     XtReleaseGC(w, lw->label.gc);
  502. }
  503.  
  504. static void Redisplay(w, event, region)
  505.     Widget w;
  506.     XEvent *event;
  507.     Region region;
  508. {
  509.     LabelWidget lw = (LabelWidget) w;
  510.     char *string;
  511.     Boolean allocated = FALSE;
  512.     int x;
  513.  
  514.     if (lw->label.accel_string == NULL) {
  515.     string = lw->label.label;
  516.     } else {
  517.     string = XtMalloc(lw->label.label_len + 1);
  518.     (void) strcpy(string, lw->label.label);
  519.     (void) strcat(string, lw->label.accel_string);
  520.     allocated = TRUE;
  521.     }
  522.  
  523.     switch (lw->label.justify) {
  524.     case Left:
  525.         x = lw->label.space;    
  526.         break;
  527.     case Right:
  528.         x = (int) lw->core.width - (int) lw->label.space -
  529.             (int) lw->label.label_width;
  530.         break;
  531.     case Center:
  532.         x = ((int) lw->core.width -
  533.             (int) lw->label.label_width) / 2;
  534.         break;
  535.     }
  536.  
  537.     XDrawString(XtDisplay(w), XtWindow(w), lw->label.current_gc,
  538.         x, lw->label.space + lw->label.font->max_bounds.ascent,
  539.         string, lw->label.label_len);
  540.  
  541.     if (allocated) XtFree(string);
  542. }
  543.  
  544. static void Resize(w)
  545.     Widget w;
  546. {
  547.     /* If widget is realized, clear and redisplay */
  548.  
  549.     if (XtIsRealized(w)) {
  550.     XClearWindow(XtDisplay(w), XtWindow(w));
  551.     (*(XtClass(w)->core_class.expose))(w,
  552.         (XEvent *) NULL, (Region) NULL);
  553.     }
  554. }   
  555.  
  556. static XtGeometryResult QueryGeometry(w, proposed, desired)
  557.     Widget w;
  558.     XtWidgetGeometry *proposed, *desired;
  559. {
  560.     LabelWidget lw = (LabelWidget) w;
  561. #define Set(bit) (proposed->request_mode & bit)
  562.  
  563.     desired->width = lw->label.desired_width;
  564.     desired->height = lw->label.desired_height;
  565.     desired->request_mode = CWWidth | CWHeight;
  566.  
  567.     if (Set(CWWidth) && proposed->width == desired->width &&
  568.         Set(CWHeight) && proposed->height == desired->height) {
  569.     return XtGeometryYes;
  570.     }
  571.  
  572.     if (desired->width == lw->core.width &&
  573.         desired->height == lw->core.height) {
  574.     return XtGeometryNo;
  575.     }
  576.     return XtGeometryAlmost;
  577. #undef Set
  578. }
  579.