2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these libraries and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /* $XConsortium: weekglance.c /main/13 1996/11/21 19:43:24 drk $ */
25 * (c) Copyright 1993, 1994 Hewlett-Packard Company
26 * (c) Copyright 1993, 1994 International Business Machines Corp.
27 * (c) Copyright 1993, 1994 Novell, Inc.
28 * (c) Copyright 1993, 1994 Sun Microsystems, Inc.
31 #include <EUSCompat.h>
37 #include <sys/param.h> /* MAXPATHLEN defined here */
39 #include <sys/utsname.h> /* SYS_NMLN */
45 #if defined(sun) && defined(_XOPEN_SOURCE)
49 #include <sys/resource.h>
51 #include <netinet/in.h>
56 #include <Xm/ToggleBG.h>
57 #include <Dt/HourGlass.h>
62 #include "datefield.h"
63 #include "x_graphics.h"
67 #include "group_editor.h"
70 #include "dayglance.h"
71 #include "monthglance.h"
72 #include "yearglance.h"
73 #include "weekglance.h"
79 #define XOS_USE_XT_LOCKING
80 #define X_INCLUDE_TIME_H
81 #if defined(__linux__)
84 #include <X11/Xos_r.h>
86 static int week_xytoclock(Week *w, int x, int y);
87 static int week_xytohour(Week *w, int x, int y);
88 static void fill_day();
89 static void draw_week();
90 static void draw_chart();
91 static void quick_button_cb(Widget, XtPointer, XtPointer);
92 static void display_hot_btn(Calendar *, int, int);
93 static void clear_hot_btn(Calendar *, int);
94 static void allocator(Calendar *);
95 static void deallocator(Calendar *);
96 static Boolean print_week (Calendar *c,
104 #define inchart(w, x, y) \
105 ((x >= w->chart_x && x <= (w->chart_x + w->chart_width) && \
106 y >= w->chart_y - w->label_height && \
107 y <= (w->chart_y + w->chart_height-1)))
109 #define inweek(w, x, y) \
110 ((x >= w->x && x <= w->x + w->width && \
111 y >= w->y && y <= w->y + w->day_height) || \
112 (x >= w->x + 3 * w->day_width && x <= w->x + w->width && \
113 y >= w->y + w->day_height && y <= w->y + w->height))
116 format_week_header(Tick date, OrderingType order, char *buf)
118 Calendar *c = calendar;
120 _Xltimeparams localtime_buf;
122 tm = _XLocaltime(&date, localtime_buf);
125 Attention Translator:
127 This string is used in the calendar week view. In the C locale
130 Monday, January 16, 1995
132 strftime conversion string: "%A, %B %e, %Y" is used. The string
133 will be used in a label that looks like this:
135 Week Starting Monday, January 16, 1995
137 Use the appropriate strftime conversion for your locale.
140 catgets(c->DT_catd, 1, 993, "Week Starting %A, %B %e, %Y"), tm);
144 count_week_pages (Calendar *c, int lines_per_page, Tick start_date)
147 CSA_return_code stat;
148 CSA_entry_handle *list;
149 CSA_attribute *range_attrs;
152 int num_appts, i, j, max = 0, pages;
154 /* count the times and text of appts */
155 for (i = 1; i <= 7; i++)
157 /* setup a time limit for appts searched */
158 start = (time_t) lowerbound (start_date);
159 stop = (time_t) next_ndays(start_date, 1) - 1;
160 setup_range(&range_attrs, &ops, &j, start, stop,
161 CSA_TYPE_EVENT, 0, B_FALSE, c->general->version);
162 csa_list_entries(c->cal_handle, j, range_attrs, ops, &a_total, &list, NULL);
163 free_range(&range_attrs, &ops, j);
165 num_appts = count_multi_appts(list, a_total, c);
169 start_date = nextday(start_date);
173 pages = max / lines_per_page;
174 if ((max % lines_per_page) > 0)
181 print_week (Calendar *c,
188 Boolean more, done = False, all_done = True;
189 int num_appts, day_of_week;
192 OrderingType ot = get_int_prop(p, CP_DATEORDERING);
194 CSA_return_code stat;
195 CSA_entry_handle *list;
196 CSA_attribute *range_attrs;
200 static Tick start_date = 0;
201 static int total_pages;
203 static char *days[] = {
204 (char *)NULL, (char *)NULL, (char *)NULL,
205 (char *)NULL, (char *)NULL, (char *)NULL, (char *)NULL
208 if (days[0] == (char *)NULL)
210 days[0] = XtNewString(catgets(c->DT_catd, 1, 596, "Monday %d"));
211 days[1] = XtNewString(catgets(c->DT_catd, 1, 597, "Tuesday %d"));
212 days[2] = XtNewString(catgets(c->DT_catd, 1, 598, "Wednesday %d"));
213 days[3] = XtNewString(catgets(c->DT_catd, 1, 599, "Thursday %d"));
214 days[4] = XtNewString(catgets(c->DT_catd, 1, 600, "Friday %d"));
215 days[5] = XtNewString(catgets(c->DT_catd, 1, 601, "Saturday %d"));
216 days[6] = XtNewString(catgets(c->DT_catd, 1, 602, "Sunday %d"));
219 x_init_printer(xp, LANDSCAPE);
221 lines_per_page = x_get_week_lines_per_page(xp);
224 start_date = first_date;
228 start_date = prevweek(start_date);
229 if (!timeok(start_date))
230 start_date = get_bot();
233 total_pages = (lines_per_page > 0) ?
234 count_week_pages(c, lines_per_page, start_date) : 1;
236 format_week_header(start_date, ot, buf);
238 x_print_header(xp, buf, num_page, total_pages);
239 x_week_appt_boxes(xp);
240 x_week_sched_boxes(xp);
242 /* print the times and text of appts */
243 for (i = (dow(start_date) + 6) % 7; i < 7; i++)
245 /* print <Weekday DD> centered at top of appt box */
246 x_week_sched_init(xp);
248 sprintf(buf, days[i], dom(start_date));
250 /* setup a time limit for appts searched */
251 start = (time_t) lowerbound (start_date);
252 stop = (time_t) next_ndays(start_date, 1) - 1;
253 setup_range(&range_attrs, &ops, &j, start, stop,
254 CSA_TYPE_EVENT, 0, B_FALSE, c->general->version);
255 csa_list_entries(c->cal_handle, j, range_attrs,
256 ops, &a_total, &list, NULL);
257 free_range(&range_attrs, &ops, j);
259 num_appts = count_multi_appts(list, a_total, c);
261 if ((lines_per_page > 0) &&
262 (num_appts > (lines_per_page * num_page)))
267 x_week_daynames(xp, buf, i, more);
269 /* print out times and appts */
270 if (lines_per_page > 0)
271 done = x_print_multi_appts(xp, list, a_total,
272 num_page, weekGlance);
278 x_week_sched_draw(xp, i);
280 start_date = nextday(start_date);
284 x_finish_printer(xp);
290 print_week_range(Calendar * c, Tick start_tick, Tick end_tick)
293 Props *p = (Props *)c->properties;
294 Tick first_date = start_tick;
296 Boolean done = False, first = True;
298 void *xp = (void *)NULL;
300 /* get number of weeks needed to print */
302 num_weeks = ((end_tick - start_tick)/wksec) + 1;
307 first_date = first_dow(first_date);
308 if (!timeok(first_date))
309 first_date = get_bot();
311 if ((xp = x_open_file(c)) == (void *)NULL)
314 for (; num_weeks > 0; num_weeks--) {
316 done = print_week(c, num_page, xp, first_date, p, first);
328 count_multi_appts(CSA_entry_handle *list, int num_entries, Calendar *c)
330 CSA_return_code stat;
331 Dtcm_appointment *appt;
332 int count = 0, i, meoval;
333 Props *pr = (Props*)c->properties;
334 Lines *lines, *l_ptr;
336 meoval = get_int_prop(pr, CP_PRINTPRIVACY);
338 appt = allocate_appt_struct(appt_read,
340 CSA_ENTRY_ATTR_CLASSIFICATION_I,
341 CSA_X_DT_ENTRY_ATTR_SHOWTIME_I,
342 CSA_ENTRY_ATTR_SUMMARY_I,
344 for (i = 0; i < num_entries; i++) {
346 stat = query_appt_struct(c->cal_handle, list[i], appt);
348 if (stat != CSA_SUCCESS) {
349 free_appt_struct(&appt);
353 if ((privacy_set(appt) == CSA_CLASS_PUBLIC) && !(meoval & PRINT_PUBLIC))
355 else if ((privacy_set(appt) == CSA_CLASS_CONFIDENTIAL) &&
356 !(meoval & PRINT_SEMIPRIVATE))
358 else if ((privacy_set(appt) == CSA_CLASS_PRIVATE) &&
359 !(meoval & PRINT_PRIVATE))
362 if (showtime_set(appt)) {
365 l_ptr = lines = text_to_lines(appt->what->value->item.string_value, 10);
366 while (lines != NULL) {
370 destroy_lines(l_ptr);
372 free_appt_struct(&appt);
377 * handler for week view menu item.
380 week_button (Widget widget, XtPointer data, XtPointer cbs)
382 Calendar *c = calendar;
384 if (c->view->glance == weekGlance)
387 switch (c->view->glance) {
389 c->view->glance = weekGlance;
390 cleanup_after_dayview(c);
391 paint_weekview(c, NULL);
394 c->view->glance = weekGlance;
395 cleanup_after_yearview(c);
396 XtMapWidget(c->canvas);
399 c->view->glance = weekGlance;
400 cleanup_after_monthview(c);
408 * Clean up anything left around that won't be removed on
409 * switching to another view, such as the hot buttons for
410 * navigation to day view.
413 cleanup_after_weekview(Calendar *c)
416 Week *w = (Week *)c->view->week_info;
419 set_message(c->message_text, "");
421 XtUnmanageChildren(w->hot_button, 7);
423 XmToggleButtonGadgetSetState(c->week_scope, False, False);
426 * Deallocating everything causes all this view's memory to be
427 * freed (at least all we have allocated in this application)
428 * at the expense of rebuilding the view next time it is used.
429 * Commenting it out improves usability and avoids any risk
430 * of memory leakage from Xt and Motif.
438 * allocate storage & subwidgets used by week view
441 allocator(Calendar *c)
447 /* main storage for other week data */
448 calendar->view->week_info = (caddr_t) ckalloc(sizeof(Week));
449 w = (Week *)c->view->week_info;
451 /* navigation buttons to day view */
452 w->hot_button = (Widget *) ckalloc(7 * sizeof(Widget));
454 /* Set the recomputeSize of the PushButtons to False, to prevent a loop
455 where a SetValues is done on the PushButton's width from the
456 exposeCallback of the DrawingArea */
457 XtSetArg(args[0], XmNrecomputeSize, False);
459 for (n=0; n<7; n++) {
461 XmCreatePushButton(c->canvas, "week2day", args, 1);
462 XtAddCallback(w->hot_button[n],XmNactivateCallback,
463 quick_button_cb, (XtPointer) (intptr_t) n);
466 /* selection info (and init its permanent attributes) */
467 w->current_selection = ckalloc(sizeof(Selection));
468 ((Selection*)w->current_selection)->row = 0;
469 ((Selection*)w->current_selection)->nunits = 1;
473 * allocate storage & subwidgets used by week view
476 deallocator(Calendar *c)
478 Week *w = (Week *)c->view->week_info;
483 XtDestroyWidget(w->hot_button[n]);
485 /* array that held navigation buttons */
489 free(w->current_selection);
491 /* allocated in init_week */
492 if (w->time_array != NULL)
495 /* structure holding week information */
497 c->view->week_info = NULL;
501 * Set up data needed to draw this particular week
504 init_week(Calendar *c, Boundary *boundary)
506 Week *w = (Week *)c->view->week_info;
507 int char_width, char_height;
509 int num_hrs, day_of_week;
510 int empty_space, day_box;
512 XFontSetExtents regfontextents, boldfontextents;
517 * The week view starts on Monday. Map Sunday to the last day of the
520 if ((day_of_week = dow(c->view->date)) == 0)
525 ((Selection*)w->current_selection)->col = day_of_week;
527 w->start_date = lowerbound(c->view->date - (day_of_week * daysec));
528 /* make sure date is within bounds */
529 if (w->start_date == -1) {
530 if (year(c->view->date) == year(get_bot())) {
531 w->start_date = get_bot();
535 else if (year(next_ndays(w->start_date, 7)) > year(get_eot())) {
540 * Set up a bunch of variables which are needed to draw and fill
541 * the week at a glance screen
543 XtVaGetValues(c->canvas,
544 XmNwidth, &w->canvas_w,
545 XmNheight, &w->canvas_h,
548 w->font = c->fonts->labelfont;
549 w->small_font = c->fonts->viewfont;
550 w->small_bold_font = c->fonts->boldfont;
551 CalFontExtents(w->font, ®fontextents);
552 CalFontExtents(w->small_bold_font, &boldfontextents);
554 w->x = c->view->outside_margin;
555 w->y = 2 * (int) boldfontextents.max_logical_extent.height;
557 char_height = regfontextents.max_logical_extent.height;
558 char_width = regfontextents.max_logical_extent.width;
559 w->label_height = char_height * 2;
560 w->day_width = ((int) (w->canvas_w - 2 * w->x)) / 5;
561 /* height of box with label */
562 w->day_height = ((int) (w->canvas_h - 2 * w->y)) / 2;
564 * We compute week dimensions from day dimensions to remove rounding
567 w->width = w->day_width * 5;
568 /* height from top of box to bottom of weekend boxes */
569 w->height = w->day_height * 2;
571 p = (Props *)c->properties;
572 w->begin_hour = get_int_prop(p, CP_DAYBEGIN);
573 w->end_hour = get_int_prop(p, CP_DAYEND);
575 /* width of a column in chart */
576 w->chart_day_width = (3 * w->day_width - 3 * char_width) / 7;
578 w->chart_width = w->chart_day_width * 7;
579 num_hrs = w->end_hour - w->begin_hour;
581 /* height of box without label */
582 day_box = w->day_height - w->label_height;
584 /* height of an hour in chart */
585 w->chart_hour_height = day_box / num_hrs;
586 /* chart_hour_height must be evenly divisble by BOX_SEG */
587 w->chart_hour_height -= (w->chart_hour_height % BOX_SEG);
588 w->chart_height = w->chart_hour_height * num_hrs;
590 /* x point of upper left corner of chart */
591 w->chart_x = w->x + 2 * boldfontextents.max_logical_extent.width;
592 /* y point of upper left corner of chart */
593 w->chart_y = w->y + w->height - w->chart_height;
595 /* left over empty space above chart after round off error */
596 empty_space = day_box - w->chart_height;
597 /* add pixels to the height of each hour box in chart to fill gap*/
598 if (w->add_pixels = ((double)empty_space / (double)num_hrs)) {
599 w->chart_y -= w->add_pixels * num_hrs;
600 w->chart_height += w->add_pixels * num_hrs;
603 w->segs_in_array = BOX_SEG * num_hrs * 7;
604 if (w->time_array != NULL)
606 w->time_array = (char*)ckalloc(w->segs_in_array);
608 c->view->outside_margin = w->x;
609 c->view->topoffset = w->y;
619 XmToggleButtonGadgetSetState(c->week_scope, True, False);
620 c->view->glance = weekGlance;
622 /* allocate weekview storage if it's never been used before */
623 if (c->view->week_info == NULL) {
625 resize_weekview(c, &boundary);
627 init_week(c, &boundary);
629 draw_week(c, rect, boundary);
630 calendar_select(c, weekdaySelect, NULL);
634 cm_update_segs(Week *w,
641 int num_segs, i, start, start_hour, duration, nday;
643 start_hour = hour(tick);
645 if (start_hour >= w->end_hour) {
651 if (start_hour < w->begin_hour) {
653 duration = dur - ((w->begin_hour -
654 (start_hour + (double)minute(tick)/(double)60))
657 start = ((start_hour - w->begin_hour) * 60 + minute(tick));
667 nday = (nday=dow(tick))==0? 6: nday-1;
668 num_segs = (double)start / (double)MINS_IN_SEG;
669 *start_index = (double)start / (double)MINS_IN_SEG + (nday * (w->segs_in_array/7));
670 if (start - (num_segs * MINS_IN_SEG) > 7)
672 num_segs = ((double)duration / (double)60 / (double)MINS_IN_SEG);
673 *end_index = num_segs + *start_index;
674 if (((double)duration/(double)60-MINS_IN_SEG*num_segs) > 7)
677 if (*end_index > (i = ((nday + 1) * (w->segs_in_array / 7))) )
680 for (i = *start_index; i < *end_index; i++)
688 add_extra_pixels(int i, int num_pixels, int *h)
690 if (((i+1) % BOX_SEG) == 0)
695 chart_draw_appts(Week *w, int start, int end)
697 int x, y, h, i, segs_in_col, no_boxes;
698 Calendar *c = calendar;
699 int col_remainder, boxseg_h;
702 XtVaGetValues(c->canvas, XmNcolormap, &cms, NULL);
703 h = boxseg_h = (double)w->chart_hour_height / (double)BOX_SEG;
704 segs_in_col = (w->segs_in_array / 7);
705 /* find starting segment in column */
706 col_remainder = (start % segs_in_col);
708 no_boxes = (double)(col_remainder+1) / (double)BOX_SEG;
709 y = w->chart_y + ((double)col_remainder * (double)boxseg_h) +
710 ((double)w->add_pixels * (double)no_boxes) + 1;
711 x = w->chart_x + ((double)start / (double)segs_in_col *
712 (double)w->chart_day_width);
714 for (i = start; i < end; i++) {
715 if (w->time_array[i] == 0) {
716 /* batch up repaints */
717 if ( (i+1) < w->segs_in_array &&
718 w->time_array[i+1] == 0 &&
719 ((i+1) % segs_in_col) != 0 ) {
721 add_extra_pixels(i, w->add_pixels, &h);
724 add_extra_pixels(i, w->add_pixels, &h);
725 gr_clear_area(c->xcontext, x, y, w->chart_day_width, h);
727 else if (w->time_array[i] == 1) {
728 /* batch up for one repaint */
729 if ( (i+1) < w->segs_in_array
730 && w->time_array[i+1] == 1 &&
731 ((i+1) % segs_in_col) != 0 ) {
733 add_extra_pixels(i, w->add_pixels, &h);
736 add_extra_pixels(i, w->add_pixels, &h);
737 if ((c->xcontext->screen_depth < 8) || FAKE_MONOCHROME)
738 gr_make_gray(c->xcontext, x, y,
739 w->chart_day_width, h, 25);
741 gr_make_grayshade(c->xcontext, x, y,
742 w->chart_day_width, h, LIGHTGREY);
744 else if (w->time_array[i] == 2) {
745 /* batch up for one repaint */
746 if ( (i+1) < w->segs_in_array
747 && w->time_array[i+1] == 2 &&
748 ((i+1) % segs_in_col) != 0 ) {
750 add_extra_pixels(i, w->add_pixels, &h);
753 add_extra_pixels(i, w->add_pixels, &h);
754 if ((c->xcontext->screen_depth < 8) || FAKE_MONOCHROME)
755 gr_make_gray(c->xcontext, x, y,
756 w->chart_day_width, h, 50);
758 gr_make_rgbcolor(c->xcontext, cms, x, y,
759 w->chart_day_width, h,
760 MIDGREY, MIDGREY, MIDGREY);
762 else if (w->time_array[i] >= 3) {
763 /* batch up for one repaint */
764 if ( (i+1) < w->segs_in_array
765 && w->time_array[i+1] >= 3 &&
766 ((i+1) % segs_in_col) != 0 ) {
768 add_extra_pixels(i, w->add_pixels, &h);
771 add_extra_pixels(i, w->add_pixels, &h);
772 if ((c->xcontext->screen_depth < 8) || FAKE_MONOCHROME)
773 gr_make_gray(c->xcontext, x, y,
774 w->chart_day_width, h, 75);
776 gr_make_grayshade(c->xcontext, x, y,
777 w->chart_day_width, h, DIMGREY);
779 if (i != 0 && (((i+1) % segs_in_col) == 0)) {
780 x += w->chart_day_width;
782 h = ((double)w->chart_hour_height/(double)BOX_SEG);
798 Week *w = (Week *)c->view->week_info;
800 /* allocate weekview storage if it's never been used before */
801 if (c->view->week_info == NULL) {
803 w = (Week *)c->view->week_info;
806 init_week(c, boundary);
811 for (n = 0; n < 7; n++) {
814 y += w->day_height + 1;
815 x = w->x + 3 * w->day_width;
818 XtVaSetValues(w->hot_button[n],
821 XmNwidth, w->day_width - 3,
822 XmNheight, w->label_height - 2,
829 draw_week(Calendar *c, XRectangle *rect, Boundary boundary)
831 Week *w = (Week *)c->view->week_info;
839 char buf[MAXNAMELEN];
840 char *footer_message = NULL;
841 int start_ind, end_ind;
842 int today_dom, day_om;
844 Props *p = (Props*)c->properties;
845 XRectangle chartrect;
846 OrderingType ot = get_int_prop(p, CP_DATEORDERING);
847 Tick start_tick, end_tick;
849 CSA_return_code stat;
850 CSA_entry_handle *list;
851 CSA_attribute *range_attrs;
854 int i, lower_bound = 0, upper_bound = 0;
855 XFontSetExtents regfontextents, boldfontextents;
856 int notused, width1, width2, width3;
858 CalFontExtents(w->font, ®fontextents);
859 char_height = regfontextents.max_logical_extent.height;
860 start_date = w->start_date;
863 start = (time_t) lowerbound(start_date);
864 stop = (time_t) next_ndays(start, 7) - 1;
866 if (c->paint_cache == NULL) {
867 setup_range(&range_attrs, &ops, &i, start, stop, CSA_TYPE_EVENT,
868 0, B_FALSE, c->general->version);
869 csa_list_entries(c->cal_handle, i, range_attrs, ops,
870 &a_total, &list, NULL);
871 free_range(&range_attrs, &ops, i);
872 allocate_paint_cache(list, a_total, &c->paint_cache);
873 c->paint_cache_size = a_total;
878 gr_clear_box(xc, 0, 0, w->canvas_w, w->canvas_h);
880 CalTextExtents(w->font, days2[3], cm_strlen(days2[3]),
881 ¬used, ¬used, &width1, ¬used);
882 CalTextExtents(w->font, " 00", cm_strlen(" 00"),
883 ¬used, ¬used, &width2, ¬used);
884 CalTextExtents(w->font, "Wed 00", cm_strlen("Wed 00"),
885 ¬used, ¬used, &width3, ¬used);
886 if (width1 + width2 <= w->day_width - 2)
888 else if (width3 <= w->day_width - 2)
895 format_week_header(start_date, ot, label);
896 gr_text(xc, x, y - char_height / 2, w->font, label, rect);
899 * Draw bold box around first 5 days
901 gr_draw_box(xc, x, y, w->width, w->day_height, rect);
902 gr_draw_box(xc, x - 1, y - 1, w->width + 2, w->day_height + 2, rect);
903 gr_draw_line(xc, x, y + w->label_height, x + w->width,
904 y + w->label_height, gr_solid, rect);
907 * Draw bold box around last 2 days
909 x += 3 * w->day_width;
912 gr_draw_box(xc, x, y, 2 * w->day_width, w->day_height, rect);
913 gr_draw_box(xc, x - 1, y, 2 * w->day_width + 2, w->day_height + 1,rect);
914 gr_draw_line(xc, x, y + w->label_height, x + 2 * w->day_width,
915 y + w->label_height, gr_solid, rect);
917 x = w->x + w->day_width;
918 for (n = 0; n < 4; n++) {
920 gr_draw_line(xc, x, y, x, y + w->day_height,
923 gr_draw_line(xc, x, y, x, y + 2 * w->day_height,
929 * Fill in week with appointments
933 current_day = start_date;
934 today_dom = dom(time(0));
936 /* Crock alert!!!! The obscure code below is doing something
937 really nasty. The variable boundary indicates whether the
938 week being displayed falls across a boundary with the
939 beginning or the end of time. In the case of the beginning
940 of time, the code then assumes that the first 2 days in the
941 week need to be unbuttoned, and the rest buttoned and painted.
942 Likewise, with the end of time case, the code assumes the last
943 3 days of the week need similar treatment. */
945 for (n = 0; n < 7; n++) {
949 x = w->x + 3 * w->day_width;
952 if (boundary == okay) {
953 day_om = dom(current_day);
954 display_hot_btn(c, n, day_om);
955 fill_day(c, w, x, y, current_day,
956 c->paint_cache, c->paint_cache_size, rect);
957 current_day += daysec;
958 if (lower_bound > 0) {
959 sprintf(buf, "%s", catgets(c->DT_catd, 1, 623, "Calendar does not display dates prior to January 1, 1970"));
960 footer_message = buf;
963 footer_message = NULL;
965 else if (boundary == lower) {
966 /* skip days before Jan 1, 1970 */
968 if (lower_bound++ == 2)
971 else if (boundary == upper) {
972 day_om = dom(current_day);
973 if (++upper_bound <= 4)
974 display_hot_btn(c, n, day_om);
975 fill_day(c, w, x, y, current_day,
976 c->paint_cache, c->paint_cache_size, rect);
977 current_day += daysec;
978 sprintf(buf, "%s", catgets(c->DT_catd, 1, 624, "Calendar does not display dates after December 31, 2037"));
979 footer_message = buf;
986 CalFontExtents(w->small_bold_font, &boldfontextents);
989 chartrect.y = w->chart_y - w->label_height;
990 chartrect.width = w->chart_width +
991 3*boldfontextents.max_logical_extent.width;
992 chartrect.height = w->chart_height + 2*w->label_height;
995 if (rect == NULL || myrect_intersectsrect(rect, &chartrect)) {
996 for (i = 0; i < c->paint_cache_size; i++) {
997 start_tick = (c->paint_cache)[i].start_time;
998 end_tick = (c->paint_cache)[i].end_time;
999 cm_update_segs(w, start_tick,
1000 (end_tick ? (end_tick - start_tick) : 0),
1001 &start_ind, &end_ind, True);
1003 chart_draw_appts(w, 0, w->segs_in_array);
1004 draw_chart(c, w, NULL);
1007 /* do not repaint the footer message in a damage display.
1008 For some reason this causes the damage routine to get called
1009 again, resulting in a recursive dsaster. */
1011 if (footer_message && !rect)
1012 set_message(c->message_text, footer_message);
1015 * Format 2 lines of appt data
1018 format_entry(Paint_cache *cache_entry, char *buf1, char *buf2,
1019 DisplayType display) {
1020 Tick tick, end_tick = 0;
1021 int hour1, min1, hour2, min2;
1025 _Xltimeparams localtime_buf;
1028 tick = cache_entry->start_time;
1029 end_tick = cache_entry->end_time;
1032 * Extract an appointment and format it into 2 lines of no more
1035 *buf1 = *buf2 = '\0';
1036 if (cache_entry == NULL || cache_entry->summary == NULL) return;
1037 tm = _XLocaltime(&tick, localtime_buf);
1038 hour1 = tm->tm_hour;
1041 if (!cache_entry->show_time || magic_time(tick)) {
1042 lines = (Lines *) text_to_lines(cache_entry->summary, 1);
1043 if (lines==NULL) return;
1044 strncpy(buf2, lines->s, 256);
1045 destroy_lines(lines);
1050 if (display == HOUR12 && !adjust_hour(&hour1))
1053 hour2 = hour(end_tick);
1054 min2 = minute(end_tick);
1055 if (display == HOUR12 && !adjust_hour(&hour2))
1059 if (end_tick == 0 ||
1060 (hour1 == hour2 && min1 == min2 && (strcmp(s1, s2) == 0))) {
1061 if (display == HOUR24)
1062 sprintf(buf1, "%02d%.2d", hour1, min1);
1064 sprintf(buf1, "%d:%.2d%s", hour1, min1, s1);
1067 if (display == HOUR12)
1068 sprintf(buf1, "%d:%.2d%s-%d:%.2d%s", hour1, min1, s1,
1071 sprintf(buf1, "%02d%02d-%02d%02d", hour1, min1,
1076 lines = (Lines *) text_to_lines(cache_entry->summary, 1);
1078 if (lines == NULL || lines->s == NULL ||
1079 (cm_strlen(lines->s) == 1 && lines->s[0] == ' '))
1082 sprintf(buf2, " %s", lines->s);
1083 destroy_lines(lines);
1087 paint_entry(Calendar *c, int x, int y, int maxchars, Paint_cache *cache_entry, XRectangle *rect)
1089 XFontSetExtents fontextents;
1090 Props *p = (Props*)c->properties;
1091 int nlines = 0, dt = get_int_prop(p, CP_DEFAULTDISP);
1092 new_XContext *xc = c->xcontext;
1093 char buf1[50], buf2[WHAT_LEN+1];
1094 Week *w = (Week *)c->view->week_info;
1098 * Write an appointment entry into a day
1101 if (maxchars >= 40) /* maxed out possible=40 */
1104 buf1[0] = '\0'; buf2[0] = '\0';
1106 format_entry(cache_entry, buf1, buf2, dt);
1108 tick = cache_entry->start_time;
1110 if (cache_entry->show_time && !magic_time(tick) && (buf1[0] != '\0')) {
1111 maxchars = gr_nchars(w->day_width - 5, buf1,c->fonts->boldfont);
1112 buf1[min(cm_strlen(buf1), maxchars)] = '\0';
1113 gr_text(xc, x, y, c->fonts->boldfont, buf1, rect);
1115 CalFontExtents(c->fonts->boldfont, &fontextents);
1116 y += fontextents.max_logical_extent.height;;
1118 if (buf2[0] != '\0') {
1119 maxchars = gr_nchars(w->day_width - 5, buf2,
1120 c->fonts->viewfont);
1121 buf2[min(cm_strlen(buf2), maxchars)] = '\0';
1122 gr_text(xc, x, y, c->fonts->viewfont, buf2, rect);
1130 fill_day(Calendar *c, Week *w, int x, int y, int day,
1131 Paint_cache *cache, int a_total, XRectangle *rect)
1133 CSA_return_code stat;
1134 Dtcm_appointment *appt;
1135 int lower = (int)lowerbound(day);
1136 int upper = (int)next_ndays(day, 1);
1139 XFontSetExtents fontextents;
1146 CalFontExtents(w->small_font, &fontextents);
1147 char_width = fontextents.max_logical_extent.width;
1148 char_height = fontextents.max_logical_extent.height;
1149 maxlines = ((w->day_height - w->label_height) / char_height)- 1;
1150 maxchars = (w->day_width / char_width);
1155 y += (w->label_height + char_height);
1158 * Fill in a day with appointments
1161 /* loop thru twice, first displaying "no time" appointments,
1162 and then the others. */
1164 for (loop = 0; loop < 2; loop++) {
1165 for (i = 0; i < a_total; i++) {
1167 if ((cache[i].start_time < lower) || (cache[i].start_time >= upper))
1170 if (cache[i].show_time != loop)
1173 if (nlines < maxlines) {
1174 n = paint_entry(c, x, y, maxchars, &cache[i], rect);
1175 y += n * char_height;
1183 draw_chart(Calendar *c, Week *w, XRectangle *rect)
1187 XFontSetExtents fontextents;
1190 new_XContext *xc = c->xcontext;
1191 Props *p = (Props*)c->properties;
1192 DisplayType dt = get_int_prop(p, CP_DEFAULTDISP);
1194 CalFontExtents(w->font, &fontextents);
1195 char_height = fontextents.max_logical_extent.height;
1198 * Draw chart. We first draw all the lines, then the labels
1199 * so that Xlib can batch the lines into 1 X request
1202 /* Draw horizontal lines for time */
1205 for (n = w->begin_hour; n <= w->end_hour; n++) {
1206 gr_draw_line(xc, x, y, x + w->chart_width, y, gr_solid, rect); y += w->chart_hour_height + w->add_pixels;
1209 /* Draw vertical lines for days */
1211 for (n = 0; n < 7; n++) {
1212 gr_draw_line(xc, w->chart_x + (w->chart_day_width * n),
1213 y, w->chart_x + (w->chart_day_width * n),
1214 y + w->chart_height, gr_solid, rect);
1218 * Draw box around the whole thing.
1220 gr_draw_box(xc, w->chart_x, w->chart_y, w->chart_width,
1221 w->chart_height, rect);
1222 gr_draw_box(xc, w->chart_x - 1, w->chart_y - 1,
1223 w->chart_width + 2, w->chart_height + 2, rect);
1224 /* Label horizontal lines with time of day */
1227 for (n = w->begin_hour; n <= w->end_hour; n++) {
1229 sprintf(label, "%2d", n > 12 ? n - 12 : n);
1231 sprintf(label, "%2d", n);
1232 gr_text(xc, w->x - 8, y+3,
1233 w->small_bold_font, label, rect);
1234 y += w->chart_hour_height + w->add_pixels;
1237 /* Label vertical lines with day labels */
1239 for (n = 0; n < 7; n++) {
1240 x = gr_center(w->chart_day_width, days3[n+1], w->font);
1241 gr_text(xc, w->chart_x + (w->chart_day_width * n) + x,
1242 y - char_height / 2, w->font, days3[n+1], rect);
1248 week_event(XEvent *event)
1250 Calendar *c = calendar;
1251 Props *p = (Props*)c->properties;
1252 static int lastdate;
1253 static XEvent lastevent;
1254 int x, y, i, j, hr, id;
1255 Week *w = (Week *)c->view->week_info;
1257 Editor *e = (Editor *)c->editor;
1258 ToDo *t = (ToDo*)c->todo;
1259 GEditor *ge = (GEditor*)c->geditor;
1260 static int lastrow, lastcol;
1263 x = event->xbutton.x;
1264 y = event->xbutton.y;
1265 wsel = (Selection *)w->current_selection;
1267 switch(event->type) {
1269 j = week_xytoclock(w, x, y);
1270 (col = dow(j)) == 0 ? col = 6 : col--;
1271 if (inchart(w, x, y))
1272 row = (double)(y - w->chart_y) /
1273 (double)(w->chart_hour_height+ w->add_pixels);
1276 if (j != lastdate || lastcol != col || lastrow != row) {
1277 calendar_deselect(c);
1281 c->view->olddate = c->view->date;
1283 calendar_select(c, weekdaySelect, NULL);
1286 lastcol = wsel->col;
1287 lastrow = wsel->row;
1288 lastdate = c->view->date;
1291 j = week_xytoclock(w, x, y);
1294 hr = (inchart(w, x, y)) ? week_xytohour(w, x, y) : (wsel->row + w->begin_hour);
1296 if (ds_is_double_click(&lastevent, event)) {
1297 _DtTurnOnHourGlass(c->frame);
1298 if (j == lastdate) {
1299 show_editor(c, next_nhours(j, hr), next_nhours(j, hr + 1), False);
1301 else if (editor_showing(e)) {
1302 set_editor_defaults(e, next_nhours(j, hr), next_nhours(j, hr + 1), False);
1305 _DtTurnOffHourGlass(c->frame);
1308 calendar_deselect(c);
1309 (wsel->col = dow(j)) == 0 ?
1310 wsel->col = 6 : wsel->col--;
1311 if (inchart(w, x, y))
1312 wsel->row = (double)(y - w->chart_y) /
1313 (double)(w->chart_hour_height + w->add_pixels);
1315 c->view->olddate = c->view->date;
1317 calendar_select(c, weekdaySelect, NULL);
1319 if (editor_showing(e)) {
1320 set_editor_defaults(e, next_nhours(j, hr), next_nhours(j, hr + 1), False);
1323 if (todo_showing(t)) {
1324 set_todo_defaults(t);
1327 if (geditor_showing(ge)) {
1328 set_geditor_defaults(ge, 0, 0);
1332 lastdate = c->view->date;
1333 lastcol = wsel->col;
1334 lastrow = wsel->row;
1343 week_xytohour(Week *w, int x, int y)
1345 if (!inchart(w, x, y))
1348 return(w->begin_hour + ((double)y /
1349 (double)(w->chart_hour_height + w->add_pixels)));
1353 week_xytoclock(Week *w, int x, int y)
1358 * Convert the x and y location on the week view to a date
1360 if (inchart(w, x, y)) {
1361 dow = (double)(x - w->chart_x)/(double)w->chart_day_width;
1362 } else if (inweek(w, x, y)) {
1363 if (y < w->y + w->day_height)
1364 dow = (x - w->x)/w->day_width;
1366 dow = (x - w->x - 3 * w->day_width)/w->day_width
1371 if (w->start_date == get_bot()) {
1377 else if (w->start_date == (time_t)last_ndays(get_eot(), 3)) {
1383 return(w->start_date + dow * daysec);
1388 * Handler for "hot" buttons to navigate to day view
1391 quick_button_cb(Widget widget, XtPointer client, XtPointer call)
1393 Calendar *c = calendar;
1394 Week *w = (Week *)c->view->week_info;
1395 int dow = (int) (intptr_t) client;
1398 if (c->view->date != get_bot()) {
1399 c->view->olddate = c->view->date;
1400 c->view->date = w->start_date + dow * daysec;
1402 calendar_select(c, weekhotboxSelect, NULL);
1404 cleanup_after_weekview(c);
1406 c->view->glance = dayGlance;
1408 (void)init_dayview(c);
1415 * Handle labeling, positioning and managing of a given hotbutton
1420 int n, /* which button (0..6) */
1421 int date) /* what day in month */
1423 Week *w = (Week *)c->view->week_info;
1424 Widget btn = w->hot_button[n];
1428 /* REVISIT: I18N wrap the string for day name */
1429 sprintf(buf, "%s %d", n == 6 ? days[0] : days[n + 1], date);
1431 str = XmStringCreateLocalized(buf);
1432 XtVaSetValues(btn, XmNlabelString, str, NULL);
1435 if (!XtIsManaged(btn)) {
1441 * Clear previous hot buttons because we can't display dates
1442 * prior to Jan 1, 1970
1445 clear_hot_btn(Calendar *c,
1446 int n) /* which button (0..6) */
1448 Week *w = (Week *)c->view->week_info;
1449 Widget btn = w->hot_button[n];
1451 if (XtIsManaged(btn)) {
1452 XtUnmanageChild(btn);