2
* Copyright(c) 1992 Bell Communications Research, Inc. (Bellcore)
3
* Copyright(c) 1999 Andrew Lister
6
* Permission to use, copy, modify and distribute this material for
7
* any purpose and without fee is hereby granted, provided that the
8
* above copyright notice and this permission notice appear in all
9
* copies, and that the name of Bellcore not be used in advertising
10
* or publicity pertaining to this material without the specific,
11
* prior written permission of an authorized representative of
14
* BELLCORE MAKES NO REPRESENTATIONS AND EXTENDS NO WARRANTIES, EX-
15
* PRESS OR IMPLIED, WITH RESPECT TO THE SOFTWARE, INCLUDING, BUT
16
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
17
* FITNESS FOR ANY PARTICULAR PURPOSE, AND THE WARRANTY AGAINST IN-
18
* FRINGEMENT OF PATENTS OR OTHER INTELLECTUAL PROPERTY RIGHTS. THE
19
* SOFTWARE IS PROVIDED "AS IS", AND IN NO EVENT SHALL BELLCORE OR
20
* ANY OF ITS AFFILIATES BE LIABLE FOR ANY DAMAGES, INCLUDING ANY
21
* LOST PROFITS OR OTHER INCIDENTAL OR CONSEQUENTIAL DAMAGES RELAT-
22
* ING TO THE SOFTWARE.
24
* CaptionWidget Author: Andrew Wason, Bellcore, aw@bae.bellcore.com
30
* Caption.c - displays a caption label next to it's child.
38
#include <X11/StringDefs.h>
45
#define tolower(c) ((c) - 'A' + 'a')
48
#define OffsetOf(field) XtOffsetOf(XbaeCaptionRec, field)
50
static XtResource resources[] = {
51
{ XmNfontList, XmCFontList, XmRFontList, sizeof(XmFontList),
52
OffsetOf(caption.font_list), XmRImmediate, (XtPointer) NULL },
53
{ XmNlabelAlignment, XmCLabelAlignment, XmRLabelAlignment,
54
sizeof(XbaeLabelAlignment), OffsetOf(caption.label_alignment),
55
XmRImmediate, (XtPointer) XbaeAlignmentCenter },
56
{ XmNlabelOffset, XmCLabelOffset, XmRInt, sizeof(int),
57
OffsetOf(caption.label_offset), XmRImmediate, (XtPointer) 0 },
58
{ XmNlabelPixmap, XmCLabelPixmap, XmRManForegroundPixmap, sizeof(Pixmap),
59
OffsetOf(caption.label_pixmap),
60
XmRImmediate, (XtPointer) XmUNSPECIFIED_PIXMAP },
61
{ XmNlabelPosition, XmCLabelPosition, XmRLabelPosition,
62
sizeof(XbaeLabelPosition), OffsetOf(caption.label_position),
63
XmRImmediate, (XtPointer) XbaePositionLeft },
64
{ XmNlabelString, XmCXmString, XmRXmString, sizeof(XmString),
65
OffsetOf(caption.label_string), XmRImmediate, (XtPointer) NULL },
66
{ XmNlabelTextAlignment, XmCAlignment, XmRAlignment, sizeof(unsigned char),
67
OffsetOf(caption.label_text_alignment),
68
XmRImmediate, (XtPointer) XmALIGNMENT_CENTER },
69
{ XmNlabelType, XmCLabelType, XmRLabelType, sizeof(unsigned char),
70
OffsetOf(caption.label_type), XmRImmediate, (XtPointer) XmSTRING },
76
* Macro to retrieve our label and the user's child.
78
#define LabelChild(w) (((CompositeWidget)w)->composite.children[0])
79
#define UserChild(w) (((CompositeWidget)w)->composite.children[1])
81
#define HaveUserChild(w) (((CompositeWidget)w)->composite.num_children > 1 \
82
&& XtIsManaged(UserChild(w)))
86
* Declaration of methods
88
static void ClassInitialize P((void));
89
static void Initialize P((Widget, Widget, ArgList, Cardinal *));
90
static void InsertChild P((Widget));
91
static Boolean SetValues P((Widget, Widget, Widget, ArgList, Cardinal *));
92
static void SetValuesAlmost P((Widget, Widget, XtWidgetGeometry *,
94
static void GetValuesHook P((Widget, ArgList, Cardinal *));
95
static void Resize P((Widget));
96
static void ChangeManaged P((Widget));
97
static XtGeometryResult GeometryManager P((Widget, XtWidgetGeometry *,
99
static XtGeometryResult QueryGeometry P((Widget, XtWidgetGeometry *,
100
XtWidgetGeometry *));
105
static void ComputeSize P((XbaeCaptionWidget, Dimension *, Dimension *,
106
Dimension, Dimension, Dimension));
107
static void ComputeUserChildSize P((XbaeCaptionWidget, Dimension, Dimension,
108
Dimension *, Dimension *, Dimension));
110
static void Layout P((XbaeCaptionWidget, Boolean));
111
static Boolean CompareStrings P((String, String));
116
static Boolean CvtStringToLabelPosition P((Display *, XrmValuePtr, Cardinal *,
117
XrmValuePtr, XrmValuePtr,
119
static Boolean CvtStringToLabelAlignment P((Display *, XrmValuePtr,
120
Cardinal *, XrmValuePtr,
121
XrmValuePtr, XtPointer *));
124
XbaeCaptionClassRec xbaeCaptionClassRec = {
126
/* core_class fields */
127
/* superclass */ (WidgetClass) &xmManagerClassRec,
128
/* class_name */ "XbaeCaption",
129
/* widget_size */ sizeof(XbaeCaptionRec),
130
/* class_initialize */ ClassInitialize,
131
/* class_part_initialize */ NULL,
132
/* class_inited */ False,
133
/* initialize */ (XtInitProc)Initialize,
134
/* initialize_hook */ NULL,
135
/* realize */ XtInheritRealize,
138
/* resources */ resources,
139
/* num_resources */ XtNumber(resources),
140
/* xrm_class */ NULLQUARK,
141
/* compress_motion */ True,
142
/* compress_exposure */ XtExposeCompressMaximal,
143
/* compress_enterleave */ True,
144
/* visible_interest */ False,
146
/* resize */ (XtWidgetProc)Resize,
147
/* expose */ _XmRedisplayGadgets,
148
/* set_values */ (XtSetValuesFunc)SetValues,
149
/* set_values_hook */ NULL,
150
/* set_values_almost */ (XtAlmostProc)SetValuesAlmost,
151
/* get_values_hook */ (XtArgsProc)GetValuesHook,
152
/* accept_focus */ NULL,
153
/* version */ XtVersion,
154
/* callback_private */ NULL,
155
/* tm_table */ XtInheritTranslations,
156
/* query_geometry */ (XtGeometryHandler)QueryGeometry,
157
/* display_accelerator */ NULL,
161
/* composite_class fields */
162
/* geometry_manager */ GeometryManager,
163
/* change_managed */ (XtWidgetProc)ChangeManaged,
164
/* insert_child */ InsertChild,
165
/* delete_child */ XtInheritDeleteChild,
166
/* extension */ NULL,
169
/* constraint_class fields */
170
/* resources */ NULL,
171
/* num_resources */ 0,
172
/* constraint_size */ 0,
173
/* initialize */ NULL,
175
/* set_values */ NULL,
179
/* manager_class fields */
180
/* translations */ XtInheritTranslations,
181
/* syn_resources */ NULL,
182
/* num_syn_resources */ 0,
183
/* syn_constraint_resources */ NULL,
184
/* num_syn_constraint_resources */ 0,
185
/* parent_process */ XmInheritParentProcess,
189
/* caption_class fields */
190
/* extension */ NULL,
194
WidgetClass xbaeCaptionWidgetClass = (WidgetClass)&xbaeCaptionClassRec;
200
XtSetTypeConverter(XmRString, XmRLabelAlignment,
201
CvtStringToLabelAlignment, NULL, 0,
204
XtSetTypeConverter(XmRString, XmRLabelPosition,
205
CvtStringToLabelPosition, NULL, 0,
211
Initialize(req, n, args, num_args)
216
XbaeCaptionWidget new = (XbaeCaptionWidget)n;
218
* Validate our labelPosition
220
switch (new->caption.label_position) {
221
case XbaePositionLeft:
222
case XbaePositionRight:
223
case XbaePositionTop:
224
case XbaePositionBottom:
228
XtWidgetToApplicationContext((Widget)new),
229
"initialize", "badLabelPosition", "XbaeCaption",
230
"XbaeCaption: Invalid label position.",
231
(String *) NULL, (Cardinal *) NULL);
232
new->caption.label_position = XbaePositionLeft;
237
* Validate our labelAlignment
239
switch (new->caption.label_alignment) {
240
case XbaeAlignmentTopOrLeft:
241
case XbaeAlignmentCenter:
242
case XbaeAlignmentBottomOrRight:
246
XtWidgetToApplicationContext((Widget)new),
247
"initialize", "badLabelAlignment", "XbaeCaption",
248
"XbaeCaption: Invalid label alignment.",
249
(String *) NULL, (Cardinal *) NULL);
250
new->caption.label_alignment = XbaeAlignmentCenter;
255
* Create the label with our name, so if no labelString is specified,
256
* it will use our name as it's label.
259
XtVaCreateManagedWidget(XtName((Widget)new),
260
xmLabelWidgetClass, (Widget)new,
261
XmNbackground, new->core.background_pixel,
262
XmNforeground, new->manager.foreground,
263
XmNfontList, new->caption.font_list,
264
XmNlabelType, new->caption.label_type,
266
new->caption.label_text_alignment,
267
XmNlabelString, new->caption.label_string,
268
XmNlabelPixmap, new->caption.label_pixmap,
273
* The label makes a copy of these, so NULL them out
274
* (we don't want to point to the user's data).
275
* get_values_hook will handle a get_values on these.
277
new->caption.label_string = NULL;
278
new->caption.font_list = NULL;
281
* We are the same size as our label. We ignore user specified
284
new->core.width = LabelChild(new)->core.width;
285
new->core.height = LabelChild(new)->core.height;
292
if (((CompositeWidget)XtParent(w))->composite.num_children > 1) {
294
XtWidgetToApplicationContext(w),
295
"insertChild", "badChild", "XbaeCaption",
296
"XbaeCaption: Cannot add more than one child.",
297
(String *)NULL, (Cardinal *)NULL);
301
(*((CompositeWidgetClass)
302
(xbaeCaptionWidgetClass->core_class.superclass))->composite_class.
309
SetValues(cur, req, nw, args, num_args)
314
XbaeCaptionWidget current = (XbaeCaptionWidget)cur;
315
XbaeCaptionWidget new = (XbaeCaptionWidget)nw;
316
Dimension old_label_width, old_label_height;
317
Boolean layout = False;
321
#define NE(field) (current->field != new->field)
322
#define EQ(field) (current->field == new->field)
325
* Validate our labelPosition
327
if (NE(caption.label_position)) {
328
switch (new->caption.label_position) {
329
case XbaePositionLeft:
330
case XbaePositionRight:
331
case XbaePositionTop:
332
case XbaePositionBottom:
336
XtWidgetToApplicationContext((Widget)new),
337
"setValues", "badLabelPosition", "XbaeCaption",
338
"XbaeCaption: Invalid label position.",
339
(String *) NULL, (Cardinal *) NULL);
340
new->caption.label_position = current->caption.label_position;
345
* Validate our labelAlignment
347
if (NE(caption.label_alignment)) {
348
switch (new->caption.label_alignment) {
349
case XbaeAlignmentTopOrLeft:
350
case XbaeAlignmentCenter:
351
case XbaeAlignmentBottomOrRight:
355
XtWidgetToApplicationContext((Widget)new),
356
"setValues", "badLabelAlignment", "XbaeCaption",
357
"XbaeCaption: Invalid label alignment.",
358
(String *) NULL, (Cardinal *) NULL);
359
new->caption.label_alignment = current->caption.label_alignment;
364
* Save labels size in case XtSetValues changes it below.
366
old_label_width = LabelChild(new)->core.width;
367
old_label_height = LabelChild(new)->core.height;
370
* Pass through resources to our label. Our geometry_manager
371
* will let it change size if it needs to.
374
if (NE(caption.label_type)) {
375
XtSetArg(largs[n], XmNlabelType,new->caption.label_type); n++;
377
if (NE(caption.label_text_alignment)) {
378
XtSetArg(largs[n], XmNalignment,
379
new->caption.label_text_alignment); n++;
381
if (NE(caption.label_string)) {
382
XtSetArg(largs[n], XmNlabelString, new->caption.label_string); n++;
384
if (NE(caption.label_pixmap)) {
385
XtSetArg(largs[n], XmNlabelPixmap, new->caption.label_pixmap); n++;
387
if (NE(caption.font_list)) {
388
XtSetArg(largs[n], XmNfontList, new->caption.font_list); n++;
390
if (NE(core.background_pixel)) {
391
XtSetArg(largs[n], XmNbackground, new->core.background_pixel); n++;
393
if (NE(manager.foreground)) {
394
XtSetArg(largs[n], XmNforeground, new->manager.foreground); n++;
397
XtSetValues(LabelChild(new), largs, n);
400
* The label makes a copy of these, so NULL them out
401
* (we don't want to point to the user's data).
402
* get_values_hook will handle a get_values on these.
404
new->caption.label_string = NULL;
405
new->caption.font_list = NULL;
409
* Calculate a new size if the label changed size, or if offset changed,
410
* or if alignment or position changed in a way which requires a new
411
* size. Our resize or set_values_almost methods will lay things out.
413
if (old_label_width != LabelChild(new)->core.width ||
414
old_label_height != LabelChild(new)->core.height ||
415
NE(caption.label_offset) || NE(caption.label_position)) {
417
if (!HaveUserChild(new)) {
418
new->core.width = LabelChild(new)->core.width;
419
new->core.height = LabelChild(new)->core.height;
422
ComputeSize(new, &new->core.width, &new->core.height,
423
UserChild(new)->core.width,
424
UserChild(new)->core.height,
425
UserChild(new)->core.border_width);
428
* If, after all that, our size didn't change, then we need
429
* to layout (since resize and set_values_almost won't be called).
431
if (EQ(core.width) && EQ(core.height))
436
* If label alignment changed, but our size didn't, then we need to layout
437
* (since resize and set_values_almost won't be called).
439
if (NE(caption.label_alignment) && EQ(core.width) && EQ(core.height))
453
SetValuesAlmost(o, n, request, reply)
456
XtWidgetGeometry *request;
457
XtWidgetGeometry *reply;
459
XbaeCaptionWidget new = (XbaeCaptionWidget)n;
461
* If XtGeometryAlmost, accept compromize - our resize method
462
* will take care of it.
464
if (reply->request_mode)
468
* If XtGeometryNo, then layout if it was a size change that was denied,
469
* and accept the original geometry.
472
if (request->request_mode & CWWidth ||
473
request->request_mode & CWHeight)
476
request->request_mode = 0;
481
GetValuesHook(w, args, num_args)
486
XbaeCaptionWidget cw = (XbaeCaptionWidget)w;
490
* We don't save a copy of the label_string or font_list.
491
* If the user wants these, we get them from the label widget.
493
for (i = 0; i < *num_args; i++)
494
if (strcmp(args[i].name, XmNlabelString) == 0)
495
XtGetValues(LabelChild(cw), &args[i], 1);
496
else if (strcmp(args[i].name, XmNfontList) == 0)
497
XtGetValues(LabelChild(cw), &args[i], 1);
501
* Do not configure the user's child if configure is False.
502
* This is for when we are laying out from within our GeometryManager.
503
* Since we are following a XtGeometryYes policy, we shouldn't config
504
* the initiating child (the label never initiates)
507
#if NeedFunctionPrototypes
508
Layout(XbaeCaptionWidget cw, Boolean configure)
510
Layout(cw, configure)
511
XbaeCaptionWidget cw;
515
Position label_x = 0, label_y = 0;
516
Position user_x = 0, user_y = 0;
517
Dimension user_width, user_height;
520
* If we only have the label, position it at 0,0.
522
if (!HaveUserChild(cw)) {
523
XtMoveWidget(LabelChild(cw), 0, 0);
528
* Calculate the positions of our label and user's children.
530
switch (cw->caption.label_position) {
532
case XbaePositionLeft:
533
case XbaePositionRight:
534
switch (cw->caption.label_alignment) {
535
case XbaeAlignmentTopOrLeft:
538
case XbaeAlignmentCenter:
539
label_y = (int) (cw->core.height / 2) -
540
(int) (LabelChild(cw)->core.height / 2);
542
case XbaeAlignmentBottomOrRight:
543
label_y = (int)cw->core.height - (int)LabelChild(cw)->core.height;
549
case XbaePositionTop:
550
case XbaePositionBottom:
551
switch (cw->caption.label_alignment) {
552
case XbaeAlignmentTopOrLeft:
555
case XbaeAlignmentCenter:
556
label_x = (int) (cw->core.width / 2) -
557
(int) (LabelChild(cw)->core.width / 2);
559
case XbaeAlignmentBottomOrRight:
560
label_x = (int)cw->core.width - (int)LabelChild(cw)->core.width;
569
* Calculate the positions of our label and user's children.
571
switch (cw->caption.label_position) {
573
case XbaePositionLeft:
574
if ((int)LabelChild(cw)->core.width + cw->caption.label_offset > 0) {
576
user_x = (int)LabelChild(cw)->core.width +
577
cw->caption.label_offset;
580
label_x = -cw->caption.label_offset;
585
case XbaePositionRight:
586
if ((int)LabelChild(cw)->core.width + cw->caption.label_offset > 0)
587
label_x = (int)cw->core.width - (int)LabelChild(cw)->core.width;
589
label_x = (int)cw->core.width - ((int)LabelChild(cw)->core.width -
590
cw->caption.label_offset);
594
case XbaePositionTop:
595
if ((int)LabelChild(cw)->core.height + cw->caption.label_offset > 0) {
597
user_y = (int)LabelChild(cw)->core.height +
598
cw->caption.label_offset;
601
label_y = -cw->caption.label_offset;
606
case XbaePositionBottom:
608
label_y = cw->core.height - LabelChild(cw)->core.height;
610
if ((int)LabelChild(cw)->core.height + cw->caption.label_offset > 0)
611
label_y = (int)cw->core.height - (int)LabelChild(cw)->core.height;
613
label_y = (int)cw->core.height -
614
((int)LabelChild(cw)->core.height - cw->caption.label_offset);
620
* Position our label widget.
622
XtMoveWidget(LabelChild(cw), label_x, label_y);
627
* Calculate the size of the user's child widget.
629
ComputeUserChildSize(cw, cw->core.width, cw->core.height,
630
&user_width, &user_height,
631
UserChild(cw)->core.border_width);
633
_XmConfigureObject((Widget)UserChild(cw),
634
(int)user_x, (int)user_y,
635
(int)user_width, (int)user_height,
636
(int)UserChild(cw)->core.border_width);
644
Layout((XbaeCaptionWidget)w, True);
648
* Given a width/height for the caption widget and the border width
649
* of the user's child, compute the width and height of the user's child.
652
#if NeedFunctionPrototypes
653
ComputeUserChildSize(XbaeCaptionWidget cw, Dimension cwWidth,
654
Dimension cwHeight, Dimension *childWidth,
655
Dimension *childHeight, Dimension childBorderWidth)
657
ComputeUserChildSize(cw, cwWidth, cwHeight, childWidth, childHeight,
659
XbaeCaptionWidget cw;
662
Dimension *childWidth;
663
Dimension *childHeight;
664
Dimension childBorderWidth;
667
int width = cwWidth - 2 * childBorderWidth;
668
int height = cwHeight - 2 * childBorderWidth;
671
* Remember, cw->caption.label_offset can be negative.
672
* If the label width plus the offset is positive, then the label
673
* is off the edge of the user's child, so we subtract that space
674
* from the user's child space. Otherwise the label is offset into
675
* the space of the user's child widget, so the user's child gets
676
* the full space and the label will be on top of it (or off the opposite
680
switch (cw->caption.label_position) {
681
case XbaePositionLeft:
682
case XbaePositionRight:
683
if ((int)LabelChild(cw)->core.width + cw->caption.label_offset > 0)
684
width -= (int)LabelChild(cw)->core.width +
685
cw->caption.label_offset;
687
case XbaePositionTop:
688
case XbaePositionBottom:
689
if ((int)LabelChild(cw)->core.height + cw->caption.label_offset > 0)
690
height -= (int)LabelChild(cw)->core.height +
691
cw->caption.label_offset;
703
*childHeight = height;
707
* Compute our size, taking into account the sizes of
708
* both of our children (the user's child size is passed in; we use the
709
* current size of the label child)
712
#if NeedFunctionPrototypes
713
ComputeSize(XbaeCaptionWidget cw, Dimension *cwWidth, Dimension *cwHeight,
714
Dimension childWidth, Dimension childHeight,
715
Dimension childBorderWidth)
717
ComputeSize(cw, cwWidth, cwHeight, childWidth, childHeight, childBorderWidth)
718
XbaeCaptionWidget cw;
721
Dimension childWidth;
722
Dimension childHeight;
723
Dimension childBorderWidth;
726
childWidth += 2 * childBorderWidth;
727
childHeight += 2 * childBorderWidth;
730
* Remember, cw->caption.label_offset can be negative.
733
switch (cw->caption.label_position) {
734
case XbaePositionRight:
735
case XbaePositionLeft:
736
if ((int)LabelChild(cw)->core.width + cw->caption.label_offset > 0)
737
*cwWidth = childWidth + LabelChild(cw)->core.width +
738
cw->caption.label_offset;
740
*cwWidth = childWidth;
742
*cwHeight = childHeight > LabelChild(cw)->core.height
744
: LabelChild(cw)->core.height;
747
case XbaePositionTop:
748
case XbaePositionBottom:
749
if ((int)LabelChild(cw)->core.height + cw->caption.label_offset > 0)
750
*cwHeight = childHeight + LabelChild(cw)->core.height +
751
cw->caption.label_offset;
753
*cwHeight = childHeight;
755
*cwWidth = childWidth > LabelChild(cw)->core.width
757
: LabelChild(cw)->core.width;
766
XbaeCaptionWidget cw = (XbaeCaptionWidget)w;
767
Dimension width, height;
768
XtGeometryResult result;
771
* Figure out what size we want to be. If we don't have a user child,
772
* we just want to be as big as the label. Otherwise we must
773
* take the label and user child into account.
775
if (!HaveUserChild(cw)) {
776
width = LabelChild(cw)->core.width;
777
height = LabelChild(cw)->core.height;
780
ComputeSize(cw, &width, &height,
781
UserChild(cw)->core.width, UserChild(cw)->core.height,
782
UserChild(cw)->core.border_width);
786
* If our calculated size is not our current size,
787
* then request our calculated size.
789
if (width != cw->core.width || height != cw->core.height) {
791
result = XtMakeResizeRequest((Widget)cw, width, height,
793
} while (result == XtGeometryAlmost);
797
* Layout for the new configuration
803
static XtGeometryResult
804
GeometryManager(w, desired, allowed)
806
XtWidgetGeometry *desired, *allowed;
808
XbaeCaptionWidget cw = (XbaeCaptionWidget) XtParent(w);
809
Dimension save_width, save_height, save_border_width;
811
#define Wants(flag) (desired->request_mode & flag)
814
* If this is our label widget child, and it is querying, then return
815
* Yes since we always grant the labels requests.
817
if (w == LabelChild(cw) && Wants(XtCWQueryOnly))
818
return XtGeometryYes;
821
* Disallow position-only changes for the user's child.
823
if (w == UserChild(cw) &&
824
!Wants(CWWidth) && !Wants(CWHeight) && !Wants(CWBorderWidth))
828
* Save the childs current geometry in case we have to back it out.
830
save_width = w->core.width;
831
save_height = w->core.height;
832
save_border_width = w->core.border_width;
835
* Store the childs desired geometry into it's widget record.
838
w->core.width = desired->width;
840
w->core.height = desired->height;
841
if (Wants(CWBorderWidth))
842
w->core.border_width = desired->border_width;
845
* If this is our label widget child, then return Yes. We stored the
846
* changes into the widget above (except for position which we do now),
847
* so Xt will reconfigure the label.
848
* We let our label widget do whatever it wants since we control
849
* when it requests a new size in our set_values.
851
if (w == LabelChild(cw)) {
853
w->core.x = desired->x;
855
w->core.y = desired->y;
856
return XtGeometryYes;
860
* Otherwise this must be our user's child widget.
861
* We will attempt to resize to accomodate it.
864
XtWidgetGeometry request;
865
XtGeometryResult result;
868
* Compute the size we want to be based on the new geometry
869
* stored in the user's child above.
871
ComputeSize(cw, &request.width, &request.height,
872
w->core.width, w->core.height, w->core.border_width);
875
* If our calculated size is not our current size,
876
* then request our calculated size.
878
if (request.width != cw->core.width ||
879
request.height != cw->core.height) {
880
request.request_mode = 0;
881
if (request.width != cw->core.width)
882
request.request_mode |= CWWidth;
883
if (request.height != cw->core.height)
884
request.request_mode |= CWHeight;
885
if (Wants(XtCWQueryOnly))
886
request.request_mode |= XtCWQueryOnly;
888
result = XtMakeGeometryRequest((Widget)cw, &request, &request);
889
} while (result == XtGeometryAlmost);
892
* If our request was granted, we need to layout (we are assuming
893
* our parent implements an XtGeometryYes policy and not
896
if (result == XtGeometryYes && !Wants(XtCWQueryOnly))
900
result = XtGeometryYes;
903
* A Yes result means we either got the size we wanted, or we agreed
906
if (result == XtGeometryYes) {
907
Dimension childWidth, childHeight;
910
* Compute the size of the user's child given the size
911
* we got from our geometry negotiations above.
913
ComputeUserChildSize(cw, request.width, request.height,
914
&childWidth, &childHeight,
915
w->core.border_width);
918
* If the child wants to change it's position, or it wants
919
* to change it's size but our compromize size is not an
920
* exact fit, then we need to return Almost and the new geometry.
922
if (((Wants(CWX) || Wants(CWY)) ||
923
(Wants(CWWidth) && childWidth != w->core.width) ||
924
(Wants(CWHeight) && childHeight != w->core.height))) {
925
result = XtGeometryAlmost;
926
allowed->request_mode = desired->request_mode & ~(CWX | CWY);
927
allowed->width = childWidth;
928
allowed->height = childHeight;
929
allowed->border_width = w->core.border_width;
934
* Restore the childs geometry for No or Almost or QueryOnly.
936
if (result == XtGeometryNo || result == XtGeometryAlmost ||
937
Wants(XtCWQueryOnly)) {
938
w->core.width = save_width;
939
w->core.height = save_height;
940
w->core.border_width = save_border_width;
949
static XtGeometryResult
950
QueryGeometry(w, proposed, desired)
952
XtWidgetGeometry *proposed, *desired;
954
XbaeCaptionWidget cw = (XbaeCaptionWidget)w;
955
#define Set(bit) (proposed->request_mode & bit)
958
* If we don't have a user child, we want to be the size of the label.
960
if (!HaveUserChild(cw)) {
961
desired->width = LabelChild(cw)->core.width;
962
desired->height = LabelChild(cw)->core.height;
963
desired->request_mode = CWWidth | CWHeight;
965
if (Set(CWWidth) && proposed->width == desired->width &&
966
Set(CWHeight) && proposed->height == desired->height)
967
return XtGeometryYes;
969
if (desired->width == cw->core.width &&
970
desired->height == cw->core.height)
973
return XtGeometryAlmost;
977
* Otherwise we must take into account what size the user child wants to be
980
XtWidgetGeometry childProposed, childDesired;
981
Dimension childWidth, childHeight, childBorderWidth = 0;
982
Dimension cwWidth, cwHeight;
983
XtGeometryResult result;
986
* Get our size based on the proposed size for use in computing
987
* the user's child size.
990
cwWidth = proposed->width;
992
cwWidth = cw->core.width;
994
cwHeight = proposed->height;
996
cwHeight = cw->core.height;
999
* Compute the size of the user's child based on our proposed new size.
1001
ComputeUserChildSize(cw, cwWidth, cwHeight,
1002
&childWidth, &childHeight,
1003
UserChild(cw)->core.border_width);
1006
* Build a geometry request to query the user's child with.
1008
childProposed.request_mode = 0;
1010
childProposed.width = childWidth;
1011
childProposed.request_mode |= CWWidth;
1013
if (Set(CWHeight)) {
1014
childProposed.height = childHeight;
1015
childProposed.request_mode |= CWHeight;
1021
result = XtQueryGeometry(UserChild(cw), &childProposed, &childDesired);
1024
* Save the childs desired geometry.
1029
/* use our computed childWidth and childHeight */
1030
childBorderWidth = UserChild(cw)->core.border_width;
1032
case XtGeometryAlmost:
1033
childWidth = childDesired.width;
1034
childHeight = childDesired.height;
1035
childBorderWidth = childDesired.border_width;
1038
childWidth = UserChild(cw)->core.width;
1039
childHeight = UserChild(cw)->core.height;
1040
childBorderWidth = UserChild(cw)->core.border_width;
1047
* Calculate what size we need to be to handle the childs
1048
* desired geometry and store it in our own desired record.
1050
ComputeSize(cw, &desired->width, &desired->height,
1051
childWidth, childHeight, childBorderWidth);
1054
* If the proposed geometry changed, or if the child cares about
1055
* it's geometry, then set the flag in desired
1057
desired->request_mode = 0;
1058
if ((Set(CWWidth) && proposed->width != desired->width) ||
1059
childDesired.request_mode & CWWidth)
1060
desired->request_mode |= CWWidth;
1061
if ((Set(CWHeight) && proposed->height != desired->height) ||
1062
childDesired.request_mode & CWHeight)
1063
desired->request_mode |= CWHeight;
1066
* If our desired geometry differs from the proposed one, or if
1067
* we care about a geometry which was not proposed, we return
1068
* Almost. Otherwise we return whatever our child returned.
1070
if ((Set(CWWidth) && proposed->width != desired->width) ||
1071
(!Set(CWWidth) && desired->request_mode & CWWidth) ||
1072
(Set(CWHeight) && proposed->height != desired->height) ||
1073
(!Set(CWHeight) && desired->request_mode & CWHeight))
1074
return XtGeometryAlmost;
1084
* Compare two strings. The test string must be lower case
1085
* and NULL terminated. Leading and trailing whitespace in the in
1086
* string is ignored.
1089
CompareStrings(in, test)
1093
* Strip leading whitespace off the in string.
1095
while (isspace(*in))
1098
for (; *test != '\0' && !isspace(*in); test++, in++) {
1108
if (*test == '\0' && (*in == '\0' || isspace(*in)))
1116
CvtStringToLabelPosition(dpy, args, num_args, from, to, data)
1120
XrmValuePtr from, to;
1123
static XbaeLabelPosition position;
1127
XtDisplayToApplicationContext(dpy),
1128
"cvtStringToLabelPosition", "wrongParameters",
1130
"String to LabelPosition conversion needs no extra arguments",
1134
* User didn't provide enough space
1136
if (to->addr != NULL && to->size < sizeof(XbaeLabelPosition)) {
1137
to->size = sizeof(XbaeLabelPosition);
1141
if (CompareStrings(from->addr, "left"))
1142
position = XbaePositionLeft;
1143
else if (CompareStrings(from->addr, "right"))
1144
position = XbaePositionRight;
1145
else if (CompareStrings(from->addr, "top"))
1146
position = XbaePositionTop;
1147
else if (CompareStrings(from->addr, "bottom"))
1148
position = XbaePositionBottom;
1150
XtDisplayStringConversionWarning(dpy, from->addr, XmRLabelPosition);
1155
* Store our return value
1157
if (to->addr == NULL)
1158
to->addr = (XtPointer) &position;
1160
*(XbaeLabelPosition *) to->addr = position;
1161
to->size = sizeof(XbaeLabelPosition);
1168
CvtStringToLabelAlignment(dpy, args, num_args, from, to, data)
1172
XrmValuePtr from, to;
1175
static XbaeLabelAlignment alignment;
1179
XtDisplayToApplicationContext(dpy),
1180
"cvtStringToLabelAlignment", "wrongParameters",
1182
"String to LabelAlignment conversion needs no extra arguments",
1186
* User didn't provide enough space
1188
if (to->addr != NULL && to->size < sizeof(XbaeLabelAlignment)) {
1189
to->size = sizeof(XbaeLabelAlignment);
1193
if (CompareStrings(from->addr, "toporleft") ||
1194
CompareStrings(from->addr, "top") ||
1195
CompareStrings(from->addr, "left"))
1196
alignment = XbaeAlignmentTopOrLeft;
1197
else if (CompareStrings(from->addr, "center"))
1198
alignment = XbaeAlignmentCenter;
1199
else if (CompareStrings(from->addr, "bottomorright") ||
1200
CompareStrings(from->addr, "bottom") ||
1201
CompareStrings(from->addr, "right"))
1202
alignment = XbaeAlignmentBottomOrRight;
1204
XtDisplayStringConversionWarning(dpy, from->addr, XmRLabelAlignment);
1209
* Store our return value
1211
if (to->addr == NULL)
1212
to->addr = (XtPointer) &alignment;
1214
*(XbaeLabelAlignment *) to->addr = alignment;
1215
to->size = sizeof(XbaeLabelAlignment);
1221
XbaeCreateCaption(parent, name, args, ac)
1227
return XtCreateWidget(name, xbaeCaptionWidgetClass, parent, args, ac);