Initial import of the CDE 2.1.30 sources from the Open Group.
[oweals/cde.git] / cde / programs / dtcm / dtcm / MonthPanel.c
1 /*********************************************************************************
2 **  MonthPanel.c
3 **
4 **  $XConsortium: MonthPanel.c /main/7 1996/11/21 19:41:55 drk $
5 **
6 **  RESTRICTED CONFIDENTIAL INFORMATION:
7 **
8 **  The information in this document is subject to special
9 **  restrictions in a confidential disclosure agreement between
10 **  HP, IBM, Sun, USL, SCO and Univel.  Do not distribute this
11 **  document outside HP, IBM, Sun, USL, SCO, or Univel without
12 **  Sun's specific written approval.  This document and all copies
13 **  and derivative works thereof must be returned or destroyed at
14 **  Sun's request.
15 **
16 **  Copyright 1993 Sun Microsystems, Inc.  All rights reserved.
17 **
18 *******************************************************************************/
19
20 /*                                                                      *
21  * (c) Copyright 1993, 1994 Hewlett-Packard Company                     *
22  * (c) Copyright 1993, 1994 International Business Machines Corp.       *
23  * (c) Copyright 1993, 1994 Sun Microsystems, Inc.                      *
24  * (c) Copyright 1993, 1994 Novell, Inc.                                *
25  */
26
27 /*
28  * Month Panel widget implementation (class XmMonthPanel)
29  *
30  * The XmMonthPanel widget is rigged with the Motif widget binary
31  * compatibility mechanism.  All Motif-specific changes for this mechanism
32  * are preceded by a comment including the string "MotifBc"
33  *
34  * For a description of the Motif widget binary compatibility mechanism
35  * see the reference manual entry on XmResolvePartOffsets().
36  *
37  */
38 #include <EUSCompat.h>
39 #include <stdio.h>
40 #include <Xm/ManagerP.h>
41 #include <Xm/PushBG.h>
42 #include <Xm/SeparatoG.h>
43 #include <Xm/LabelG.h>
44 #include "MonthPanelP.h"
45 #include "timeops.h"
46 #include "misc.h"
47
48 #define XOS_USE_XT_LOCKING
49 #define X_INCLUDE_TIME_H
50 #include <X11/Xos_r.h>
51
52 /*
53  * MotifBc - index value for this class is superclass' value + 1
54  */
55 #ifdef MOTIF_BC
56 #define XmMonthPanelIndex (XmManagerIndex + 1)
57 #endif /* MOTIF_BC */
58
59 /*
60  * MotifBc - dynamic offset tables
61  */
62 #ifdef MOTIF_BC
63 static XmOffsetPtr ipot;        /* Instance part offset table */
64 static XmOffsetPtr cpot;        /* Constraint part offset table */
65 #endif /* MOTIF_BC */
66
67 /*
68  * MotifBc - macros for accessing instance and constraint fields
69  */
70 #ifdef MOTIF_BC
71 #define Year(w)         XmField(w, ipot, XmMonthPanel, year, int)
72 #define Month(w)        XmField(w, ipot, XmMonthPanel, month, int)
73 #define Callback(w)     XmField(w, ipot, XmMonthPanel, callback, XtCallbackList)
74 #define TitleFormat(w)  XmField(w, ipot, XmMonthPanel, title_format, String)
75 #define Header(w)       XmField(w, ipot, XmMonthPanel, header, Widget)
76 #define DayLabels(w)    XmField(w, ipot, XmMonthPanel, day_labels, Widget *)
77 #define Days(w)         XmField(w, ipot, XmMonthPanel, days, Widget *)
78 #endif /* MOTIF_BC */
79
80
81 /********    Static Function Declarations    ********/
82 static void scale_components(XmMonthPanelWidget);
83
84 static void ClassPartInitialize(WidgetClass) ;
85 static void Initialize(Widget, Widget, ArgList, Cardinal *) ;
86 static void Redisplay(Widget, XEvent *, Region);
87 static void DoLayout(XmMonthPanelWidget) ;
88 static void Resize(Widget) ;
89 static Boolean SetValues(Widget, Widget, Widget, ArgList, Cardinal *) ;
90 static XtGeometryResult QueryProc(Widget, XtWidgetGeometry*, XtWidgetGeometry*);
91 static XtGeometryResult GeometryManager( Widget, XtWidgetGeometry *, XtWidgetGeometry *);
92 static void DayCallback(Widget, XtPointer, XtPointer);
93 static void MonthCallback(Widget, XtPointer, XtPointer);
94 static void set_header_string(XmMonthPanelWidget);
95 static Boolean clipped(Widget);
96 /********    End Static Function Declarations    ********/
97
98
99 /*
100  * These arrays are implemented in calendarA.c.  They are arrays
101  * of the local strings for day names and month names.  The day
102  * arrays start from 0, the month array starts from 1; no particular
103  * reason for this difference that I can see.
104  */
105 extern char *days3[];           /* eg: "S"   */
106 extern char *months[];          /* eg: "January" */
107
108 /*
109  * widget instance names for column header labels in panel
110  */
111 static char *col_hdr[] = { "sunday", "monday", "tuesday", "wednesday",
112                            "thursday", "friday", "saturday" };
113
114 \f
115 /************************************************************************
116  *                                                                      *
117  * Month Panel Resources                                                *
118  *                                                                      *
119  ************************************************************************/
120
121 static XtResource resources[] = 
122 {
123     { XmNyear, XmCYear, XmRInt, sizeof(int),
124         XtOffsetOf( struct _XmMonthPanelRec, month_panel.year),
125         XmRImmediate, (XtPointer)NULL },
126     { XmNmonth, XmCMonth, XmRInt, sizeof(int),
127         XtOffsetOf( struct _XmMonthPanelRec, month_panel.month),
128         XmRImmediate, (XtPointer)NULL },
129     { XmNactivateCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList),
130         XtOffsetOf( struct _XmMonthPanelRec, month_panel.callback),
131         XmRImmediate, (XtPointer)NULL },
132     { XmNtitleFormat, XmCTitleFormat, XmRString, sizeof(char *),
133         XtOffsetOf( struct _XmMonthPanelRec, month_panel.title_format),
134         XtRString, (XtPointer)"%B %Y" },
135     { XmNactiveHeader, XmCActiveHeader, XmRBoolean, sizeof(Boolean),
136         XtOffsetOf( struct _XmMonthPanelRec, month_panel.active_header),
137         XtRImmediate, (XtPointer)False },
138     { XmNactiveDays, XmCActiveDays, XmRBoolean, sizeof(Boolean),
139         XtOffsetOf( struct _XmMonthPanelRec, month_panel.active_days),
140         XtRImmediate, (XtPointer)False },
141     { XmNshowPanelHeader, XmCShowPanelHeader, XmRBoolean, sizeof(Boolean),
142         XtOffsetOf( struct _XmMonthPanelRec, month_panel.show_panel_header),
143         XtRImmediate, (XtPointer)True },
144     { XmNshowColumnHeaders, XmCShowColumnHeaders, XmRBoolean, sizeof(Boolean),
145         XtOffsetOf( struct _XmMonthPanelRec, month_panel.show_column_headers),
146         XtRImmediate, (XtPointer)True },
147     { XmNshowSeparator, XmCShowSeparator, XmRBoolean, sizeof(Boolean),
148         XtOffsetOf( struct _XmMonthPanelRec, month_panel.show_separator),
149         XtRImmediate, (XtPointer)True }
150 };
151
152
153 \f
154 /****************************************************************
155  *
156  * Full class record constant
157  *
158  ****************************************************************/
159
160 externaldef(xmmonthpanelclassrec) XmMonthPanelClassRec
161              xmMonthPanelClassRec = {
162   {
163 /* core_class fields      */
164     /* superclass         */    (WidgetClass) &xmManagerClassRec,
165     /* class_name         */    "XmMonthPanel",
166     /* widget_size        */    sizeof(XmMonthPanelRec),
167     /* class_initialize   */    NULL,
168     /* class_partinit     */    ClassPartInitialize,
169     /* class_inited       */    FALSE,
170     /* initialize         */    Initialize,
171     /* Init hook          */    NULL,
172     /* realize            */    XtInheritRealize,
173     /* actions            */    NULL,
174     /* num_actions        */    0,
175     /* resources          */    resources,
176     /* num_resources      */    XtNumber(resources),
177     /* xrm_class          */    NULLQUARK,
178     /* compress_motion    */    TRUE,
179     /* compress_exposure  */    XtExposeCompressMaximal,
180     /* compress_enterleave*/    TRUE,
181     /* visible_interest   */    FALSE,
182     /* destroy            */    NULL,
183     /* resize             */    Resize,
184     /* expose             */    Redisplay,
185     /* set_values         */    SetValues,
186     /* set values hook    */    NULL,
187     /* set values almost  */    XtInheritSetValuesAlmost,
188     /* get values hook    */    NULL,
189     /* accept_focus       */    NULL,
190     /* Version            */    XtVersion,
191     /* PRIVATE cb list    */    NULL,
192     /* tm_table           */    XtInheritTranslations,
193     /* query_geometry     */    XtInheritQueryGeometry,
194     /* display_accelerator*/    NULL,
195     /* extension          */    NULL,
196   },
197   {
198 /* composite_class fields */
199     /* geometry_manager   */    GeometryManager,
200     /* change_managed     */    XtInheritChangeManaged,
201     /* insert_child       */    XtInheritInsertChild,
202     /* delete_child       */    XtInheritDeleteChild,   /* Inherit from superclass */
203     /* Extension          */    NULL,
204   },{
205 /* Constraint class Init */
206     NULL,
207     0,
208     0,
209     NULL,
210     NULL,
211     NULL,
212     NULL
213       
214   },
215 /* Manager Class */
216    {            
217       XtInheritTranslations,                    /* translations        */    
218       NULL,                                     /* get resources          */
219       0,                                        /* num get_resources      */
220       NULL,                                     /* get_cont_resources     */
221       0,                                        /* num_get_cont_resources */
222       XmInheritParentProcess,                   /* parent_process         */
223       NULL,                                     /* extension           */    
224    },
225
226  {
227 /* Month Panel class - none */     
228      /* mumble */               0
229  }      
230 };
231
232 externaldef(xmmonthpanelwidgetclass) WidgetClass
233              xmMonthPanelWidgetClass = (WidgetClass)&xmMonthPanelClassRec;
234
235
236 \f
237
238 /************************************************************************
239  *                                                                      *
240  *  ClassPartInitialize - Set up the fast subclassing.                  *
241  *                                                                      *
242  ************************************************************************/
243 static void 
244 ClassPartInitialize( WidgetClass wc )
245 {
246 /*
247    _XmFastSubclassInit (wc, XmMONTH_PANEL_BIT);
248 */
249 }
250
251 \f
252 /************************************************************************
253  *                                                                      *
254  *  Initialize                                                          *
255  *                                                                      *
256  ************************************************************************/
257 /* ARGSUSED */
258 static void 
259 Initialize( Widget rw, Widget nw, ArgList args, Cardinal *num_args )
260 {
261         int i=0;
262         Arg wargs[5];
263         Widget header;
264         XmString str;
265         struct tm *tm_ret;
266         time_t timer;
267         Tick tmptick;
268         _Xltimeparams localtime_buf;
269         
270         XmMonthPanelWidget request = (XmMonthPanelWidget) rw ;
271         XmMonthPanelWidget new_w = (XmMonthPanelWidget) nw ;
272
273         char buf[BUFSIZ];
274
275         new_w->month_panel.display_rows = 6;  /* minimum to show all days */
276
277 /*
278  * create and cache panel header ( eg. "January") (depends on format resource)
279  *
280  * Whether XmLabels or XmPushButton gadgets are used is selectable via
281  * the boolean "activeDays" and "activeHeader" resource. True gets you buttons.
282  */
283
284         if (new_w->month_panel.active_header) {
285            new_w->month_panel.header =
286                 XmCreatePushButtonGadget((Widget)new_w, "header", NULL, 0);
287            XtAddCallback(new_w->month_panel.header, XmNactivateCallback,
288                 MonthCallback, NULL);
289            new_w->month_panel.separator = (Widget) NULL;
290         }
291         else {
292            new_w->month_panel.header =
293                 XmCreateLabelGadget((Widget)new_w, "header", NULL, 0);
294            new_w->month_panel.separator =
295                 XmCreateSeparatorGadget((Widget)new_w, "separator", NULL, 0); 
296            /* Managing of separator is switchable */
297            if (new_w->month_panel.show_separator) {
298               XtManageChild(new_w->month_panel.separator);
299               /* separator takes another row to display */
300               (new_w->month_panel.display_rows)++;
301            }
302         }
303
304         /* set header label */
305
306 /*
307 **  Problem in set_header_string.  It references month_panel.month
308 ** and month_panel.year, which aren't initialized in when it is called
309 ** in the Initialize function.  Set them to today.
310 */
311         time (&timer);
312         tm_ret = _XLocaltime(&timer, localtime_buf);
313         new_w->month_panel.month = tm_ret->tm_mon + 1;
314         new_w->month_panel.year = 1900 + tm_ret->tm_year;
315
316         set_header_string(new_w);
317
318         /* Managing of header is switchable */
319         if (new_w->month_panel.show_panel_header) {
320            XtManageChild(new_w->month_panel.header);
321            /* header takes another row to display */
322            (new_w->month_panel.display_rows)++;
323         }
324
325 /*
326  * create and cache id's of, column header day names
327  */
328         new_w->month_panel.day_labels =
329                 (Widget *) XtMalloc( 7 * sizeof(Widget) );
330         for (i=0; i < 7; i++) {
331            XmString str;
332            Widget label;
333
334            /* I18N:next line: wrap the string & fetch from catalog */
335            str = XmStringCreateLocalized(days3[i]);
336            XtSetArg(wargs[0], XmNlabelString, str);
337            label = XmCreateLabelGadget((Widget) new_w, col_hdr[i], wargs, 1);
338            /* Managing of column headers is switchable */
339            if (new_w->month_panel.show_column_headers)
340               XtManageChild(label);
341            new_w->month_panel.day_labels[i] = label; /* cache in panel inst. */
342            XmStringFree(str);
343         }
344
345         /* column headers take another row to display */
346         if (new_w->month_panel.show_column_headers)
347            (new_w->month_panel.display_rows)++;
348
349 /*
350  * create and cache id's of, 31 buttons for days
351  */
352         new_w->month_panel.days = (Widget *) XtMalloc( 31 * sizeof(Widget) );
353         for (i=0; i < 31; i++) {
354            char buf[BUFSIZ];
355            XmString str;
356            Widget btn;
357
358            sprintf(buf, "%d", i+1);
359            str = XmStringCreateLocalized(buf);
360            XtSetArg(wargs[0], XmNlabelString, str);
361            sprintf(buf, "day%d", i+1);
362
363 /* choose between buttons or labels for day objects */
364            if (new_w->month_panel.active_days) {
365                 btn = XmCreatePushButtonGadget((Widget)new_w, buf, wargs, 1);
366                 XtAddCallback(btn, XmNactivateCallback, DayCallback,
367                         (XtPointer)(i+1));
368            }
369            else {
370                 btn = XmCreateLabelGadget((Widget) new_w, buf, wargs, 1);
371            }
372            new_w->month_panel.days[i] = btn;/* cache id in panel instance */
373            XmStringFree(str);
374         }
375         XtManageChildren((WidgetList)new_w->month_panel.days, 31);
376
377 /*
378  * Set all these components to the appropriate size for the container
379  * Then position them correctly.
380  */
381         scale_components(new_w);
382
383         DoLayout(new_w);
384 }
385
386 static void
387 Redisplay(Widget w, XEvent *ev, Region region)
388 {
389         XmMonthPanelWidget panel = (XmMonthPanelWidget) w;
390
391         XmeRedisplayGadgets( w, ev, region) ;
392 }
393
394 \f
395 /************************************************************************
396  *                                                                      *
397  * DoLayout - Layout the month panel.                                   *
398  *                                                                      *
399  ************************************************************************/
400 static void 
401 DoLayout( XmMonthPanelWidget mw )
402 {
403         XmMonthPanelPart *mpp = &(mw->month_panel);
404         Dimension w = mw->core.width;
405         Dimension h = mw->core.height;
406         int col_w = (int) w/7;
407         int row_h;
408         Boolean tall_header;
409         Position x=0;
410         Position y=0;
411         int days_in_month = monthlength(monthdayyear(mpp->month,1,mpp->year));
412         int first = fdom(monthdayyear(mpp->month,1,mpp->year));
413         Widget this_widget;
414         int i=0;
415
416         if (!mw->month_panel.active_days && mw->month_panel.active_header) {
417                 tall_header = True;
418                 row_h = (int) h/(mpp->display_rows + 1);
419         }
420         else {
421                 tall_header = False;
422                 row_h = (int) h/(mpp->display_rows);
423         }
424
425 /* 
426  * Make sure the variable buttons are correctly [un]managed.
427  * (the "variable" buttons are those for 29th, 30th and 31st)
428  */
429         for (i=28; i < 31; i++) {
430                 Widget this_widget = (mpp->days)[i];
431                 if (days_in_month > i) {
432                         if (!XtIsManaged(this_widget))
433                                 XtManageChild(this_widget);
434                 }
435                 else {
436                         if (XtIsManaged(this_widget))
437                                 XtUnmanageChild(this_widget);
438                 }
439         }
440
441 /*
442  * position the panel header
443  */
444         XtMoveWidget(mpp->header, 0, 0);
445
446 /*
447  * position the separator, if any
448  */
449         if (mpp->separator != NULL) {
450                 if (tall_header)
451                         XtMoveWidget(mpp->separator,
452                                 (Position) w/8, (Position) 2 * row_h);
453                 else
454                         XtMoveWidget(mpp->separator,
455                                 (Position) w/8, (Position)  row_h);
456         }
457
458 /*
459  * position the day labels
460  */
461         x = (Position) 0;
462         y = (Position) (mw->month_panel.display_rows -
463                         (tall_header ? 6 : 7)) * row_h;
464
465         i=0;
466         while (i < 7) {
467                 this_widget = mw->month_panel.day_labels[i];
468                 XtMoveWidget(this_widget, x, y);
469                 x += col_w;
470                 i++;
471         }
472
473 /*
474  * position the day buttons
475  */
476         x = (Position) first * col_w;
477         y = (Position) (mw->month_panel.display_rows -
478                         (tall_header ? 5 : 6)) * row_h;
479
480         i=0;
481         while (i < 31){
482                 this_widget = mw->month_panel.days[i];
483
484                 /* don't bother with unmanaged buttons */
485                 if (XtIsManaged(this_widget))
486                         XtMoveWidget(this_widget, x, y);
487                 i++;
488
489                 /* take new row after each 7 buttons */
490                 if ( ( (i+first) % 7 ) == 0 ) {
491                         x = 0;
492                         y += row_h;
493                 }
494                 else
495                         x += col_w;
496         }
497
498 }
499 \f
500
501 /************************************************************************
502  *
503  * scale_components - Make all the labels, buttons correct size for this
504  *                    size space.
505  *
506  *                    [4/12/94] - Check whether new size causes labels
507  *                                to be clipped.  If it does, set labelType
508  *                                to PIXMAP.  A suitable labelPixmap should be
509  *                                set to indicate "label too small".
510  ************************************************************************/
511
512 static void
513 scale_components(XmMonthPanelWidget mw) {
514
515         XmMonthPanelPart *mpp = &(mw->month_panel);
516         Dimension w=mw->core.width;
517         Dimension h=mw->core.height;
518         int row_h;
519         Boolean tall_header;
520         int col_w = (int) w/7;
521         int i=0;
522         Widget this_widget;
523         unsigned char ltype;
524         Pixel fg, bg;
525         Pixmap head_pm, col_head_pm, btn_pm;
526
527         if (!mw->month_panel.active_days && mw->month_panel.active_header) {
528                 tall_header = True;
529                 row_h = (int) h/(mpp->display_rows + 1);
530         }
531         else {
532                 tall_header = False;
533                 row_h = (int) h/(mpp->display_rows);
534         }
535
536         /******************************************************************
537          * get pixmap in colors needed - used to replace text when clipped.
538          *
539          * NOTE1: Don't need to release the pixmaps, because they come from
540          * the Motif-owned image cache.
541          * 
542          * NOTE2: setting the pixmaps should be in redisplay rather than
543          * here - only done here because this is where labelType is toggled.
544          ******************************************************************/
545         XtVaGetValues(XtParent(mw), XmNforeground, &fg, XmNbackground, &bg, NULL);
546         head_pm = XmGetPixmap(XtScreen(mw), "slant_right", fg, bg);
547         col_head_pm = XmGetPixmap(XtScreen(mw), "slant_left", fg, bg);
548         btn_pm = XmGetPixmap(XtScreen(mw), "50_foreground", fg, bg);
549
550
551         /*********************************************************************
552          * This algorithm allocates equal header, label and button heights;
553          * equal label and button widths; header spans container width.
554          *********************************************************************/
555
556         /**************************
557          * set panel header size
558          **************************/
559         
560         if (tall_header)
561                 XtResizeWidget(mpp->header, w, 2 * row_h, mpp->header->core.border_width);
562         else
563                 XtResizeWidget(mpp->header, w, row_h, mpp->header->core.border_width);
564
565         if (clipped(mpp->header)) {
566                 XtVaSetValues(mpp->header,
567                         XmNlabelType, XmPIXMAP,
568                         XmNlabelPixmap, head_pm,
569                         NULL);
570         }
571         else
572                 XtVaSetValues(mpp->header,
573                         XmNlabelType, XmSTRING,
574                         NULL);
575
576         /**************************
577          * separator
578          **************************/
579         if (mpp->separator != NULL) {
580                 XtResizeWidget(mpp->separator, 3*(int)w/4, row_h, 0);
581         }
582         
583         /**************************
584          * set column-heading label sizes
585          **************************/
586         for (i=0; i<7; i++) {
587                 this_widget = (mpp->day_labels)[i];
588                 XtResizeWidget(this_widget, col_w, row_h, 0);
589         }       
590         /* display pixmap if clipped, string otherwise */
591         this_widget = (mpp->day_labels)[6];
592         XtVaGetValues(this_widget, XmNlabelType, &ltype, NULL);
593         if (clipped(this_widget)) {
594            if (ltype == XmSTRING) {
595                 for (i=0; i<7; i++) {
596                    XtVaSetValues((mpp->day_labels)[i],
597                         XmNlabelType, XmPIXMAP,
598                         XmNlabelPixmap, col_head_pm,
599                         NULL);
600                 }       
601            }
602         }
603         else {
604            if (ltype == XmPIXMAP) {
605                 for (i=0; i<7; i++) {
606                    XtVaSetValues((mpp->day_labels)[i], XmNlabelType, XmSTRING, NULL);
607                 }       
608            }
609         }
610
611         /**************************
612          * Day buttons
613          **************************/
614         for (i=0; i<31; i++) {
615                 this_widget = (mpp->days)[i];
616                 XtResizeWidget(this_widget, col_w, row_h, 0);
617         }       
618
619         /*************************************************************
620          * If any of the button labels are clipped, replace the
621          * entire set with their pixmap equivalents.  The labelPixmap
622          * resource should be set to something that means "not big enough"
623          * (like a dot!)
624          *   This check should really be done in above loop, but it
625          * slows things down to catch the edge case (different fonts
626          * in different labels, so this is thought "good enough".
627          *   28th button picked at random for test - at least it's always a
628          * 2-digit label.
629          *************************************************************/
630         this_widget = (mpp->days)[27];
631         XtVaGetValues(this_widget, XmNlabelType, &ltype, NULL);
632         if (clipped(this_widget)) {
633            if (ltype == XmSTRING) {
634                 for (i=0; i<31; i++) {
635                    XtVaSetValues((mpp->days)[i],
636                         XmNlabelType, XmPIXMAP,
637                         XmNlabelPixmap, btn_pm,
638                         NULL);
639                 }       
640            }
641         }
642         else {
643            if (ltype == XmPIXMAP) {
644                 for (i=0; i<31; i++) {
645                    XtVaSetValues((mpp->days)[i], XmNlabelType, XmSTRING, NULL);
646                 }       
647            }
648         }
649 }
650
651 /*
652  * Determine whether labelString requires more space
653  * than its widget currently has.  This information
654  * can be used to display clipped information differently
655  */
656 static Boolean
657 clipped(Widget w) 
658 {
659         XmString str;
660         XmFontList fl;
661         Dimension req_w, req_h, act_w, act_h, shd_w, hlt_w;
662
663         return(False);
664
665         XtVaGetValues(w,
666                 XmNlabelString, &str,
667                 XmNfontList, &fl,
668                 XmNhighlightThickness, &hlt_w,
669                 XmNshadowThickness, &shd_w,
670                 XmNwidth, &act_w,
671                 XmNheight, &act_h,
672                 NULL);
673
674         XmStringExtent(fl, str, &req_w, &req_h);
675
676         /* adjust actual width/height available for shadow and highlight */
677         act_w -= ( (2*hlt_w) + (2*shd_w) );
678         act_h -= ( (2*hlt_w) + (2*shd_w) );
679
680         if ((req_w > act_w) || (req_h > act_h))
681                 return (True);
682         else
683                 return(False);
684 }
685
686 /************************************************************************
687  *                                                                      *
688  *  Recompute the size of the month panel.                              * 
689  *                                                                      *
690  ************************************************************************/
691 static void 
692 Resize( Widget wid )
693 {
694     XmMonthPanelWidget mw = (XmMonthPanelWidget) wid ;
695     XmManagerWidgetClass super = (XmManagerWidgetClass) xmManagerWidgetClass;
696
697     scale_components(mw);
698     DoLayout(mw);
699     (*super->core_class.resize)((Widget) mw);
700 }
701 \f
702 /***************************************************************************
703  *                                                                         *
704  *  Geometry Manager
705  *                                                                         *
706  ***************************************************************************/
707 static XtGeometryResult
708 GeometryManager( Widget w, XtWidgetGeometry *request, XtWidgetGeometry *reply )
709 {
710         return (XtGeometryYes);
711 }
712 \f
713 /***************************************************************************
714  *                                                                         *
715  *  QueryProc (stub for now)                                               *
716  *                                                                         *
717  ***************************************************************************/
718 static XtGeometryResult 
719 QueryProc( Widget w, XtWidgetGeometry *request, XtWidgetGeometry *reply )
720 {
721 /*    XmMonthPanelWidget mw = (XmMonthPanelWidget) w;*/
722     return(XtGeometryYes);
723 }
724 \f
725
726 #if 0
727 /***************************************************************************
728  *                                                                         *
729  *  CalcSize (stub for now- to be called by QueryProc)                     *
730  *                                                                         *
731  ***************************************************************************/
732 static void
733 CalcSize(XmMonthPanelWidget mw, Dimension *replyWidth , Dimension *replyHeight)
734 {
735     *replyWidth = mw->core.width;
736     *replyHeight = mw->core.height;
737
738 }
739 #endif
740 \f
741 /************************************************************************
742  *                                                                      *
743  *  SetValues                                                           *
744  *                                                                      *
745  ************************************************************************/
746 static Boolean 
747 SetValues( Widget cw, Widget rw, Widget nw, ArgList args, Cardinal *num_args )
748 {
749         XmMonthPanelWidget current = (XmMonthPanelWidget) cw ;
750         XmMonthPanelWidget request = (XmMonthPanelWidget) rw ;
751         XmMonthPanelWidget new_w = (XmMonthPanelWidget) nw ;
752     Boolean relayout = FALSE;
753     Boolean new_date = FALSE;
754
755     if (request->month_panel.show_panel_header != current->month_panel.show_panel_header) {
756        if (request->month_panel.show_panel_header) {
757           XtManageChild(request->month_panel.header);
758           (request->month_panel.display_rows)++;
759        }
760        else {
761           XtUnmanageChild(request->month_panel.header);
762           (request->month_panel.display_rows)--;
763        }
764        relayout = TRUE;
765     }
766
767     if (request->month_panel.show_column_headers != current->month_panel.show_column_headers) {
768        if (request->month_panel.show_column_headers) {
769           int col=0;
770           while (col < 7) {
771              XtManageChild(request->month_panel.day_labels[col]);
772              col++;
773           }
774           (request->month_panel.display_rows)++;
775        }
776        else {
777           int col=0;
778           while (col < 7) {
779              XtUnmanageChild(request->month_panel.day_labels[col]);
780              col++;
781           }
782           (request->month_panel.display_rows)--;
783        }
784        relayout = TRUE;
785     }
786        
787     if (request->month_panel.show_separator != current->month_panel.show_separator) {
788        if (request->month_panel.show_separator) {
789           XtManageChild(request->month_panel.separator);
790           (request->month_panel.display_rows)++;
791        }
792        else {
793           XtUnmanageChild(request->month_panel.separator);
794           (request->month_panel.display_rows)--;
795        }
796        relayout = TRUE;
797     }
798
799     if (request->month_panel.month != current->month_panel.month) {
800
801         /* range check - quietly force to nearest valid value */
802         if (request->month_panel.month < 1)
803                 new_w->month_panel.month = 1;
804         else if (request->month_panel.month > 12)
805                 new_w->month_panel.month = 12;
806
807         new_date = TRUE;
808     }
809
810     if (request->month_panel.year != current->month_panel.year) {
811
812         /* range check - quietly force to nearest valid value */
813         if (request->month_panel.year < 1)
814                 new_w->month_panel.year = 1970;
815         else if (request->month_panel.year > 2037)
816                 new_w->month_panel.year = 2037;
817  
818         new_date = TRUE;
819     }
820
821     if ((request->core.width != current->core.width) ||
822         (request->core.height != current->core.height)) {
823                 relayout = TRUE;
824     }
825
826     if (strcmp(request->month_panel.title_format,
827                 new_w->month_panel.title_format) != 0) {
828         set_header_string(new_w);
829     }
830
831     if (new_date) {
832         set_header_string(new_w);
833         relayout = TRUE;
834     }
835
836     if (relayout)
837         DoLayout(new_w);
838
839     return (relayout);
840 }
841
842 /*
843  * set_header_string
844  *
845  * Sets label in month button of panel, according to the
846  * setting of the titleFormat resource, which is assumed to
847  * be a valid format string for stftime(3)
848  */
849 static void
850 set_header_string(XmMonthPanelWidget mw)
851 {
852         XmString str;
853         struct tm *tm_ret;
854         Tick tmptick;
855         Arg wargs[3];
856         char buf[BUFSIZ];
857         _Xltimeparams localtime_buf;
858
859         tmptick =
860            monthdayyear(mw->month_panel.month, 1 ,mw->month_panel.year);
861         tm_ret = _XLocaltime(&tmptick, localtime_buf);
862         (void) strftime(buf, BUFSIZ, mw->month_panel.title_format, tm_ret);
863
864         str = XmStringCreateLocalized(buf);
865         XtSetArg(wargs[0], XmNlabelString, str);
866         XtSetValues(mw->month_panel.header, wargs, 1);
867         XmStringFree(str);
868 }
869
870 \f
871 /************************************************************************
872  * DayCallback is invoked from day button children.
873  * It invokes MonthPanel's own callbac list, setting the type in the
874  * callback struct to DAY_SELECTION, and the day field to the index of the
875  * button that was pressed.
876  *
877  ************************************************************************/
878 static void DayCallback(Widget w, XtPointer client, XtPointer call)
879 {
880    XmMonthPanelWidget mp = (XmMonthPanelWidget) XtParent(w);
881    XmMonthPanelCallbackStruct data;
882
883    data.type = DAY_SELECTION;
884    data.day = (int) client;
885
886    XtCallCallbackList((Widget) mp, mp->month_panel.callback, &data);
887 }
888
889 /************************************************************************
890  * MonthCallback is invoked from the header button.
891  * It invokes MonthPanel's own callback list, setting the type in the
892  * callback struct to MONTH_SELECTION, and zeroing out the day field.
893  ************************************************************************/
894 static void MonthCallback(Widget w, XtPointer client, XtPointer call)
895 {
896    XmMonthPanelWidget mp = (XmMonthPanelWidget) XtParent(w);
897    XmMonthPanelCallbackStruct data;
898
899    data.type = MONTH_SELECTION;
900    data.day = 0;
901
902    XtCallCallbackList((Widget) mp, mp->month_panel.callback, &data);
903 }
904
905 /************************************************************************
906  *                                                                      *
907  * XmCreateMonthPanel - convenience interface to XtCreateWidget.        *
908  *                                                                      *
909  ************************************************************************/
910 Widget 
911 XmCreateMonthPanel( Widget parent, char *name, ArgList args, Cardinal argCount )
912 {
913
914     return ( XtCreateWidget( name, 
915                              xmMonthPanelWidgetClass, 
916                              parent, 
917                              args, 
918                              argCount ) );
919 }