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 librararies 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>
36 #include <sys/param.h> /* MAXPATHLEN defined here */
38 #include <sys/utsname.h> /* SYS_NMLN */
44 #if defined(sun) && defined(_XOPEN_SOURCE)
48 #include <sys/resource.h>
50 #include <netinet/in.h>
55 #include <Xm/ToggleBG.h>
56 #include <Dt/HourGlass.h>
61 #include "datefield.h"
62 #include "x_graphics.h"
66 #include "group_editor.h"
69 #include "dayglance.h"
70 #include "monthglance.h"
71 #include "yearglance.h"
72 #include "weekglance.h"
78 #define XOS_USE_XT_LOCKING
79 #define X_INCLUDE_TIME_H
83 #include <X11/Xos_r.h>
85 static int week_xytoclock(Week *w, int x, int y);
86 static int week_xytohour(Week *w, int x, int y);
87 static void fill_day();
88 static void draw_week();
89 static void draw_chart();
90 static void quick_button_cb(Widget, XtPointer, XtPointer);
91 static void display_hot_btn(Calendar *, int, int);
92 static void clear_hot_btn(Calendar *, int);
93 static void allocator(Calendar *);
94 static void deallocator(Calendar *);
95 static Boolean print_week (Calendar *c,
103 #define inchart(w, x, y) \
104 ((x >= w->chart_x && x <= (w->chart_x + w->chart_width) && \
105 y >= w->chart_y - w->label_height && \
106 y <= (w->chart_y + w->chart_height-1)))
108 #define inweek(w, x, y) \
109 ((x >= w->x && x <= w->x + w->width && \
110 y >= w->y && y <= w->y + w->day_height) || \
111 (x >= w->x + 3 * w->day_width && x <= w->x + w->width && \
112 y >= w->y + w->day_height && y <= w->y + w->height))
115 format_week_header(Tick date, OrderingType order, char *buf)
117 Calendar *c = calendar;
119 _Xltimeparams localtime_buf;
121 tm = _XLocaltime(&date, localtime_buf);
124 Attention Translator:
126 This string is used in the calendar week view. In the C locale
129 Monday, January 16, 1995
131 strftime conversion string: "%A, %B %e, %Y" is used. The string
132 will be used in a label that looks like this:
134 Week Starting Monday, January 16, 1995
136 Use the appropriate strftime conversion for your locale.
139 catgets(c->DT_catd, 1, 993, "Week Starting %A, %B %e, %Y"), tm);
143 count_week_pages (Calendar *c, int lines_per_page, Tick start_date)
146 CSA_return_code stat;
147 CSA_entry_handle *list;
148 CSA_attribute *range_attrs;
151 int num_appts, i, j, max = 0, pages;
153 /* count the times and text of appts */
154 for (i = 1; i <= 7; i++)
156 /* setup a time limit for appts searched */
157 start = (time_t) lowerbound (start_date);
158 stop = (time_t) next_ndays(start_date, 1) - 1;
159 setup_range(&range_attrs, &ops, &j, start, stop,
160 CSA_TYPE_EVENT, 0, B_FALSE, c->general->version);
161 csa_list_entries(c->cal_handle, j, range_attrs, ops, &a_total, &list, NULL);
162 free_range(&range_attrs, &ops, j);
164 num_appts = count_multi_appts(list, a_total, c);
168 start_date = nextday(start_date);
172 pages = max / lines_per_page;
173 if ((max % lines_per_page) > 0)
180 print_week (Calendar *c,
187 Boolean more, done = False, all_done = True;
188 int num_appts, day_of_week;
191 OrderingType ot = get_int_prop(p, CP_DATEORDERING);
193 CSA_return_code stat;
194 CSA_entry_handle *list;
195 CSA_attribute *range_attrs;
199 static Tick start_date = 0;
200 static int total_pages;
202 static char *days[] = {
203 (char *)NULL, (char *)NULL, (char *)NULL,
204 (char *)NULL, (char *)NULL, (char *)NULL, (char *)NULL
207 if (days[0] == (char *)NULL)
209 days[0] = XtNewString(catgets(c->DT_catd, 1, 596, "Monday %d"));
210 days[1] = XtNewString(catgets(c->DT_catd, 1, 597, "Tuesday %d"));
211 days[2] = XtNewString(catgets(c->DT_catd, 1, 598, "Wednesday %d"));
212 days[3] = XtNewString(catgets(c->DT_catd, 1, 599, "Thursday %d"));
213 days[4] = XtNewString(catgets(c->DT_catd, 1, 600, "Friday %d"));
214 days[5] = XtNewString(catgets(c->DT_catd, 1, 601, "Saturday %d"));
215 days[6] = XtNewString(catgets(c->DT_catd, 1, 602, "Sunday %d"));
218 x_init_printer(xp, LANDSCAPE);
220 lines_per_page = x_get_week_lines_per_page(xp);
223 start_date = first_date;
227 start_date = prevweek(start_date);
228 if (!timeok(start_date))
229 start_date = get_bot();
232 total_pages = (lines_per_page > 0) ?
233 count_week_pages(c, lines_per_page, start_date) : 1;
235 format_week_header(start_date, ot, buf);
237 x_print_header(xp, buf, num_page, total_pages);
238 x_week_appt_boxes(xp);
239 x_week_sched_boxes(xp);
241 /* print the times and text of appts */
242 for (i = (dow(start_date) + 6) % 7; i < 7; i++)
244 /* print <Weekday DD> centered at top of appt box */
245 x_week_sched_init(xp);
247 sprintf(buf, days[i], dom(start_date));
249 /* setup a time limit for appts searched */
250 start = (time_t) lowerbound (start_date);
251 stop = (time_t) next_ndays(start_date, 1) - 1;
252 setup_range(&range_attrs, &ops, &j, start, stop,
253 CSA_TYPE_EVENT, 0, B_FALSE, c->general->version);
254 csa_list_entries(c->cal_handle, j, range_attrs,
255 ops, &a_total, &list, NULL);
256 free_range(&range_attrs, &ops, j);
258 num_appts = count_multi_appts(list, a_total, c);
260 if ((lines_per_page > 0) &&
261 (num_appts > (lines_per_page * num_page)))
266 x_week_daynames(xp, buf, i, more);
268 /* print out times and appts */
269 if (lines_per_page > 0)
270 done = x_print_multi_appts(xp, list, a_total,
271 num_page, weekGlance);
277 x_week_sched_draw(xp, i);
279 start_date = nextday(start_date);
283 x_finish_printer(xp);
289 print_week_range(Calendar * c, Tick start_tick, Tick end_tick)
292 Props *p = (Props *)c->properties;
293 register Tick first_date = start_tick;
295 Boolean done = False, first = True;
297 void *xp = (void *)NULL;
299 /* get number of weeks needed to print */
301 num_weeks = ((end_tick - start_tick)/wksec) + 1;
306 first_date = first_dow(first_date);
307 if (!timeok(first_date))
308 first_date = get_bot();
310 if ((xp = x_open_file(c)) == (void *)NULL)
313 for (; num_weeks > 0; num_weeks--) {
315 done = print_week(c, num_page, xp, first_date, p, first);
327 count_multi_appts(CSA_entry_handle *list, int num_entries, Calendar *c)
329 CSA_return_code stat;
330 Dtcm_appointment *appt;
331 int count = 0, i, meoval;
332 Props *pr = (Props*)c->properties;
333 Lines *lines, *l_ptr;
335 meoval = get_int_prop(pr, CP_PRINTPRIVACY);
337 appt = allocate_appt_struct(appt_read,
339 CSA_ENTRY_ATTR_CLASSIFICATION_I,
340 CSA_X_DT_ENTRY_ATTR_SHOWTIME_I,
341 CSA_ENTRY_ATTR_SUMMARY_I,
343 for (i = 0; i < num_entries; i++) {
345 stat = query_appt_struct(c->cal_handle, list[i], appt);
347 if (stat != CSA_SUCCESS) {
348 free_appt_struct(&appt);
352 if ((privacy_set(appt) == CSA_CLASS_PUBLIC) && !(meoval & PRINT_PUBLIC))
354 else if ((privacy_set(appt) == CSA_CLASS_CONFIDENTIAL) &&
355 !(meoval & PRINT_SEMIPRIVATE))
357 else if ((privacy_set(appt) == CSA_CLASS_PRIVATE) &&
358 !(meoval & PRINT_PRIVATE))
361 if (showtime_set(appt)) {
364 l_ptr = lines = text_to_lines(appt->what->value->item.string_value, 10);
365 while (lines != NULL) {
369 destroy_lines(l_ptr);
371 free_appt_struct(&appt);
376 * handler for week view menu item.
379 week_button (Widget widget, XtPointer data, XtPointer cbs)
381 Calendar *c = calendar;
383 if (c->view->glance == weekGlance)
386 switch (c->view->glance) {
388 c->view->glance = weekGlance;
389 cleanup_after_dayview(c);
390 paint_weekview(c, NULL);
393 c->view->glance = weekGlance;
394 cleanup_after_yearview(c);
395 XtMapWidget(c->canvas);
398 c->view->glance = weekGlance;
399 cleanup_after_monthview(c);
407 * Clean up anything left around that won't be removed on
408 * switching to another view, such as the hot buttons for
409 * navigation to day view.
412 cleanup_after_weekview(Calendar *c)
415 Week *w = (Week *)c->view->week_info;
418 set_message(c->message_text, "");
420 XtUnmanageChildren(w->hot_button, 7);
422 XmToggleButtonGadgetSetState(c->week_scope, False, False);
425 * Deallocating everything causes all this view's memory to be
426 * freed (at least all we have allocated in this application)
427 * at the expense of rebuilding the view next time it is used.
428 * Commenting it out improves usability and avoids any risk
429 * of memory leakage from Xt and Motif.
437 * allocate storage & subwidgets used by week view
440 allocator(Calendar *c)
446 /* main storage for other week data */
447 calendar->view->week_info = (caddr_t) ckalloc(sizeof(Week));
448 w = (Week *)c->view->week_info;
450 /* navigation buttons to day view */
451 w->hot_button = (Widget *) ckalloc(7 * sizeof(Widget));
453 /* Set the recomputeSize of the PushButtons to False, to prevent a loop
454 where a SetValues is done on the PushButton's width from the
455 exposeCallback of the DrawingArea */
456 XtSetArg(args[0], XmNrecomputeSize, False);
458 for (n=0; n<7; n++) {
460 XmCreatePushButton(c->canvas, "week2day", args, 1);
461 XtAddCallback(w->hot_button[n],XmNactivateCallback,
462 quick_button_cb, (XtPointer) (intptr_t) n);
465 /* selection info (and init its permanent attributes) */
466 w->current_selection = ckalloc(sizeof(Selection));
467 ((Selection*)w->current_selection)->row = 0;
468 ((Selection*)w->current_selection)->nunits = 1;
472 * allocate storage & subwidgets used by week view
475 deallocator(Calendar *c)
477 Week *w = (Week *)c->view->week_info;
482 XtDestroyWidget(w->hot_button[n]);
484 /* array that held navigation buttons */
488 free(w->current_selection);
490 /* allocated in init_week */
491 if (w->time_array != NULL)
494 /* structure holding week information */
496 c->view->week_info = NULL;
500 * Set up data needed to draw this particular week
503 init_week(Calendar *c, Boundary *boundary)
505 Week *w = (Week *)c->view->week_info;
506 int char_width, char_height;
508 int num_hrs, day_of_week;
509 int empty_space, day_box;
511 XFontSetExtents regfontextents, boldfontextents;
516 * The week view starts on Monday. Map Sunday to the last day of the
519 if ((day_of_week = dow(c->view->date)) == 0)
524 ((Selection*)w->current_selection)->col = day_of_week;
526 w->start_date = lowerbound(c->view->date - (day_of_week * daysec));
527 /* make sure date is within bounds */
528 if (w->start_date == -1) {
529 if (year(c->view->date) == year(get_bot())) {
530 w->start_date = get_bot();
534 else if (year(next_ndays(w->start_date, 7)) > year(get_eot())) {
539 * Set up a bunch of variables which are needed to draw and fill
540 * the week at a glance screen
542 XtVaGetValues(c->canvas,
543 XmNwidth, &w->canvas_w,
544 XmNheight, &w->canvas_h,
547 w->font = c->fonts->labelfont;
548 w->small_font = c->fonts->viewfont;
549 w->small_bold_font = c->fonts->boldfont;
550 CalFontExtents(w->font, ®fontextents);
551 CalFontExtents(w->small_bold_font, &boldfontextents);
553 w->x = c->view->outside_margin;
554 w->y = 2 * (int) boldfontextents.max_logical_extent.height;
556 char_height = regfontextents.max_logical_extent.height;
557 char_width = regfontextents.max_logical_extent.width;
558 w->label_height = char_height * 2;
559 w->day_width = ((int) (w->canvas_w - 2 * w->x)) / 5;
560 /* height of box with label */
561 w->day_height = ((int) (w->canvas_h - 2 * w->y)) / 2;
563 * We compute week dimensions from day dimensions to remove rounding
566 w->width = w->day_width * 5;
567 /* height from top of box to bottom of weekend boxes */
568 w->height = w->day_height * 2;
570 p = (Props *)c->properties;
571 w->begin_hour = get_int_prop(p, CP_DAYBEGIN);
572 w->end_hour = get_int_prop(p, CP_DAYEND);
574 /* width of a column in chart */
575 w->chart_day_width = (3 * w->day_width - 3 * char_width) / 7;
577 w->chart_width = w->chart_day_width * 7;
578 num_hrs = w->end_hour - w->begin_hour;
580 /* height of box without label */
581 day_box = w->day_height - w->label_height;
583 /* height of an hour in chart */
584 w->chart_hour_height = day_box / num_hrs;
585 /* chart_hour_height must be evenly divisble by BOX_SEG */
586 w->chart_hour_height -= (w->chart_hour_height % BOX_SEG);
587 w->chart_height = w->chart_hour_height * num_hrs;
589 /* x point of upper left corner of chart */
590 w->chart_x = w->x + 2 * boldfontextents.max_logical_extent.width;
591 /* y point of upper left corner of chart */
592 w->chart_y = w->y + w->height - w->chart_height;
594 /* left over empty space above chart after round off error */
595 empty_space = day_box - w->chart_height;
596 /* add pixels to the height of each hour box in chart to fill gap*/
597 if (w->add_pixels = ((double)empty_space / (double)num_hrs)) {
598 w->chart_y -= w->add_pixels * num_hrs;
599 w->chart_height += w->add_pixels * num_hrs;
602 w->segs_in_array = BOX_SEG * num_hrs * 7;
603 if (w->time_array != NULL)
605 w->time_array = (char*)ckalloc(w->segs_in_array);
607 c->view->outside_margin = w->x;
608 c->view->topoffset = w->y;
618 XmToggleButtonGadgetSetState(c->week_scope, True, False);
619 c->view->glance = weekGlance;
621 /* allocate weekview storage if it's never been used before */
622 if (c->view->week_info == NULL) {
624 resize_weekview(c, &boundary);
626 init_week(c, &boundary);
628 draw_week(c, rect, boundary);
629 calendar_select(c, weekdaySelect, NULL);
633 cm_update_segs(Week *w,
640 int num_segs, i, start, start_hour, duration, nday;
642 start_hour = hour(tick);
644 if (start_hour >= w->end_hour) {
650 if (start_hour < w->begin_hour) {
652 duration = dur - ((w->begin_hour -
653 (start_hour + (double)minute(tick)/(double)60))
656 start = ((start_hour - w->begin_hour) * 60 + minute(tick));
666 nday = (nday=dow(tick))==0? 6: nday-1;
667 num_segs = (double)start / (double)MINS_IN_SEG;
668 *start_index = (double)start / (double)MINS_IN_SEG + (nday * (w->segs_in_array/7));
669 if (start - (num_segs * MINS_IN_SEG) > 7)
671 num_segs = ((double)duration / (double)60 / (double)MINS_IN_SEG);
672 *end_index = num_segs + *start_index;
673 if (((double)duration/(double)60-MINS_IN_SEG*num_segs) > 7)
676 if (*end_index > (i = ((nday + 1) * (w->segs_in_array / 7))) )
679 for (i = *start_index; i < *end_index; i++)
687 add_extra_pixels(int i, int num_pixels, int *h)
689 if (((i+1) % BOX_SEG) == 0)
694 chart_draw_appts(Week *w, int start, int end)
696 int x, y, h, i, segs_in_col, no_boxes;
697 Calendar *c = calendar;
698 int col_remainder, boxseg_h;
701 XtVaGetValues(c->canvas, XmNcolormap, &cms, NULL);
702 h = boxseg_h = (double)w->chart_hour_height / (double)BOX_SEG;
703 segs_in_col = (w->segs_in_array / 7);
704 /* find starting segment in column */
705 col_remainder = (start % segs_in_col);
707 no_boxes = (double)(col_remainder+1) / (double)BOX_SEG;
708 y = w->chart_y + ((double)col_remainder * (double)boxseg_h) +
709 ((double)w->add_pixels * (double)no_boxes) + 1;
710 x = w->chart_x + ((double)start / (double)segs_in_col *
711 (double)w->chart_day_width);
713 for (i = start; i < end; i++) {
714 if (w->time_array[i] == 0) {
715 /* batch up repaints */
716 if ( (i+1) < w->segs_in_array &&
717 w->time_array[i+1] == 0 &&
718 ((i+1) % segs_in_col) != 0 ) {
720 add_extra_pixels(i, w->add_pixels, &h);
723 add_extra_pixels(i, w->add_pixels, &h);
724 gr_clear_area(c->xcontext, x, y, w->chart_day_width, h);
726 else if (w->time_array[i] == 1) {
727 /* batch up for one repaint */
728 if ( (i+1) < w->segs_in_array
729 && w->time_array[i+1] == 1 &&
730 ((i+1) % segs_in_col) != 0 ) {
732 add_extra_pixels(i, w->add_pixels, &h);
735 add_extra_pixels(i, w->add_pixels, &h);
736 if ((c->xcontext->screen_depth < 8) || FAKE_MONOCHROME)
737 gr_make_gray(c->xcontext, x, y,
738 w->chart_day_width, h, 25);
740 gr_make_grayshade(c->xcontext, x, y,
741 w->chart_day_width, h, LIGHTGREY);
743 else if (w->time_array[i] == 2) {
744 /* batch up for one repaint */
745 if ( (i+1) < w->segs_in_array
746 && w->time_array[i+1] == 2 &&
747 ((i+1) % segs_in_col) != 0 ) {
749 add_extra_pixels(i, w->add_pixels, &h);
752 add_extra_pixels(i, w->add_pixels, &h);
753 if ((c->xcontext->screen_depth < 8) || FAKE_MONOCHROME)
754 gr_make_gray(c->xcontext, x, y,
755 w->chart_day_width, h, 50);
757 gr_make_rgbcolor(c->xcontext, cms, x, y,
758 w->chart_day_width, h,
759 MIDGREY, MIDGREY, MIDGREY);
761 else if (w->time_array[i] >= 3) {
762 /* batch up for one repaint */
763 if ( (i+1) < w->segs_in_array
764 && w->time_array[i+1] >= 3 &&
765 ((i+1) % segs_in_col) != 0 ) {
767 add_extra_pixels(i, w->add_pixels, &h);
770 add_extra_pixels(i, w->add_pixels, &h);
771 if ((c->xcontext->screen_depth < 8) || FAKE_MONOCHROME)
772 gr_make_gray(c->xcontext, x, y,
773 w->chart_day_width, h, 75);
775 gr_make_grayshade(c->xcontext, x, y,
776 w->chart_day_width, h, DIMGREY);
778 if (i != 0 && (((i+1) % segs_in_col) == 0)) {
779 x += w->chart_day_width;
781 h = ((double)w->chart_hour_height/(double)BOX_SEG);
797 Week *w = (Week *)c->view->week_info;
799 /* allocate weekview storage if it's never been used before */
800 if (c->view->week_info == NULL) {
802 w = (Week *)c->view->week_info;
805 init_week(c, boundary);
810 for (n = 0; n < 7; n++) {
813 y += w->day_height + 1;
814 x = w->x + 3 * w->day_width;
817 XtVaSetValues(w->hot_button[n],
820 XmNwidth, w->day_width - 3,
821 XmNheight, w->label_height - 2,
828 draw_week(Calendar *c, XRectangle *rect, Boundary boundary)
830 Week *w = (Week *)c->view->week_info;
831 register int current_day;
838 char buf[MAXNAMELEN];
839 char *footer_message = NULL;
840 int start_ind, end_ind;
841 int today_dom, day_om;
843 Props *p = (Props*)c->properties;
844 XRectangle chartrect;
845 OrderingType ot = get_int_prop(p, CP_DATEORDERING);
846 Tick start_tick, end_tick;
848 CSA_return_code stat;
849 CSA_entry_handle *list;
850 CSA_attribute *range_attrs;
853 int i, lower_bound = 0, upper_bound = 0;
854 XFontSetExtents regfontextents, boldfontextents;
855 int notused, width1, width2, width3;
857 CalFontExtents(w->font, ®fontextents);
858 char_height = regfontextents.max_logical_extent.height;
859 start_date = w->start_date;
862 start = (time_t) lowerbound(start_date);
863 stop = (time_t) next_ndays(start, 7) - 1;
865 if (c->paint_cache == NULL) {
866 setup_range(&range_attrs, &ops, &i, start, stop, CSA_TYPE_EVENT,
867 0, B_FALSE, c->general->version);
868 csa_list_entries(c->cal_handle, i, range_attrs, ops,
869 &a_total, &list, NULL);
870 free_range(&range_attrs, &ops, i);
871 allocate_paint_cache(list, a_total, &c->paint_cache);
872 c->paint_cache_size = a_total;
877 gr_clear_box(xc, 0, 0, w->canvas_w, w->canvas_h);
879 CalTextExtents(w->font, days2[3], cm_strlen(days2[3]),
880 ¬used, ¬used, &width1, ¬used);
881 CalTextExtents(w->font, " 00", cm_strlen(" 00"),
882 ¬used, ¬used, &width2, ¬used);
883 CalTextExtents(w->font, "Wed 00", cm_strlen("Wed 00"),
884 ¬used, ¬used, &width3, ¬used);
885 if (width1 + width2 <= w->day_width - 2)
887 else if (width3 <= w->day_width - 2)
894 format_week_header(start_date, ot, label);
895 gr_text(xc, x, y - char_height / 2, w->font, label, rect);
898 * Draw bold box around first 5 days
900 gr_draw_box(xc, x, y, w->width, w->day_height, rect);
901 gr_draw_box(xc, x - 1, y - 1, w->width + 2, w->day_height + 2, rect);
902 gr_draw_line(xc, x, y + w->label_height, x + w->width,
903 y + w->label_height, gr_solid, rect);
906 * Draw bold box around last 2 days
908 x += 3 * w->day_width;
911 gr_draw_box(xc, x, y, 2 * w->day_width, w->day_height, rect);
912 gr_draw_box(xc, x - 1, y, 2 * w->day_width + 2, w->day_height + 1,rect);
913 gr_draw_line(xc, x, y + w->label_height, x + 2 * w->day_width,
914 y + w->label_height, gr_solid, rect);
916 x = w->x + w->day_width;
917 for (n = 0; n < 4; n++) {
919 gr_draw_line(xc, x, y, x, y + w->day_height,
922 gr_draw_line(xc, x, y, x, y + 2 * w->day_height,
928 * Fill in week with appointments
932 current_day = start_date;
933 today_dom = dom(time(0));
935 /* Crock alert!!!! The obscure code below is doing something
936 really nasty. The variable boundary indicates whether the
937 week being displayed falls across a boundary with the
938 beginning or the end of time. In the case of the beginning
939 of time, the code then assumes that the first 2 days in the
940 week need to be unbuttoned, and the rest buttoned and painted.
941 Likewise, with the end of time case, the code assumes the last
942 3 days of the week need similar treatment. */
944 for (n = 0; n < 7; n++) {
948 x = w->x + 3 * w->day_width;
951 if (boundary == okay) {
952 day_om = dom(current_day);
953 display_hot_btn(c, n, day_om);
954 fill_day(c, w, x, y, current_day,
955 c->paint_cache, c->paint_cache_size, rect);
956 current_day += daysec;
957 if (lower_bound > 0) {
958 sprintf(buf, "%s", catgets(c->DT_catd, 1, 623, "Calendar does not display dates prior to January 1, 1970"));
959 footer_message = buf;
962 footer_message = NULL;
964 else if (boundary == lower) {
965 /* skip days before Jan 1, 1970 */
967 if (lower_bound++ == 2)
970 else if (boundary == upper) {
971 day_om = dom(current_day);
972 if (++upper_bound <= 4)
973 display_hot_btn(c, n, day_om);
974 fill_day(c, w, x, y, current_day,
975 c->paint_cache, c->paint_cache_size, rect);
976 current_day += daysec;
977 sprintf(buf, "%s", catgets(c->DT_catd, 1, 624, "Calendar does not display dates after December 31, 2037"));
978 footer_message = buf;
985 CalFontExtents(w->small_bold_font, &boldfontextents);
988 chartrect.y = w->chart_y - w->label_height;
989 chartrect.width = w->chart_width +
990 3*boldfontextents.max_logical_extent.width;
991 chartrect.height = w->chart_height + 2*w->label_height;
994 if (rect == NULL || myrect_intersectsrect(rect, &chartrect)) {
995 for (i = 0; i < c->paint_cache_size; i++) {
996 start_tick = (c->paint_cache)[i].start_time;
997 end_tick = (c->paint_cache)[i].end_time;
998 cm_update_segs(w, start_tick,
999 (end_tick ? (end_tick - start_tick) : 0),
1000 &start_ind, &end_ind, True);
1002 chart_draw_appts(w, 0, w->segs_in_array);
1003 draw_chart(c, w, NULL);
1006 /* do not repaint the footer message in a damage display.
1007 For some reason this causes the damage routine to get called
1008 again, resulting in a recursive dsaster. */
1010 if (footer_message && !rect)
1011 set_message(c->message_text, footer_message);
1014 * Format 2 lines of appt data
1017 format_entry(Paint_cache *cache_entry, char *buf1, char *buf2,
1018 DisplayType display) {
1019 Tick tick, end_tick = 0;
1020 int hour1, min1, hour2, min2;
1024 _Xltimeparams localtime_buf;
1027 tick = cache_entry->start_time;
1028 end_tick = cache_entry->end_time;
1031 * Extract an appointment and format it into 2 lines of no more
1034 *buf1 = *buf2 = '\0';
1035 if (cache_entry == NULL || cache_entry->summary == NULL) return;
1036 tm = _XLocaltime(&tick, localtime_buf);
1037 hour1 = tm->tm_hour;
1040 if (!cache_entry->show_time || magic_time(tick)) {
1041 lines = (Lines *) text_to_lines(cache_entry->summary, 1);
1042 if (lines==NULL) return;
1043 strncpy(buf2, lines->s, 256);
1044 destroy_lines(lines);
1049 if (display == HOUR12 && !adjust_hour(&hour1))
1052 hour2 = hour(end_tick);
1053 min2 = minute(end_tick);
1054 if (display == HOUR12 && !adjust_hour(&hour2))
1058 if (end_tick == 0 ||
1059 (hour1 == hour2 && min1 == min2 && (strcmp(s1, s2) == 0))) {
1060 if (display == HOUR24)
1061 sprintf(buf1, "%02d%.2d", hour1, min1);
1063 sprintf(buf1, "%d:%.2d%s", hour1, min1, s1);
1066 if (display == HOUR12)
1067 sprintf(buf1, "%d:%.2d%s-%d:%.2d%s", hour1, min1, s1,
1070 sprintf(buf1, "%02d%02d-%02d%02d", hour1, min1,
1075 lines = (Lines *) text_to_lines(cache_entry->summary, 1);
1077 if (lines == NULL || lines->s == NULL ||
1078 (cm_strlen(lines->s) == 1 && lines->s[0] == ' '))
1081 sprintf(buf2, " %s", lines->s);
1082 destroy_lines(lines);
1086 paint_entry(Calendar *c, int x, int y, int maxchars, Paint_cache *cache_entry, XRectangle *rect)
1088 XFontSetExtents fontextents;
1089 Props *p = (Props*)c->properties;
1090 int nlines = 0, dt = get_int_prop(p, CP_DEFAULTDISP);
1091 new_XContext *xc = c->xcontext;
1092 char buf1[50], buf2[WHAT_LEN+1];
1093 Week *w = (Week *)c->view->week_info;
1097 * Write an appointment entry into a day
1100 if (maxchars >= 40) /* maxed out possible=40 */
1103 buf1[0] = '\0'; buf2[0] = '\0';
1105 format_entry(cache_entry, buf1, buf2, dt);
1107 tick = cache_entry->start_time;
1109 if (cache_entry->show_time && !magic_time(tick) && (buf1[0] != '\0')) {
1110 maxchars = gr_nchars(w->day_width - 5, buf1,c->fonts->boldfont);
1111 buf1[min(cm_strlen(buf1), maxchars)] = '\0';
1112 gr_text(xc, x, y, c->fonts->boldfont, buf1, rect);
1114 CalFontExtents(c->fonts->boldfont, &fontextents);
1115 y += fontextents.max_logical_extent.height;;
1117 if (buf2[0] != '\0') {
1118 maxchars = gr_nchars(w->day_width - 5, buf2,
1119 c->fonts->viewfont);
1120 buf2[min(cm_strlen(buf2), maxchars)] = '\0';
1121 gr_text(xc, x, y, c->fonts->viewfont, buf2, rect);
1129 fill_day(Calendar *c, Week *w, int x, int y, int day,
1130 Paint_cache *cache, int a_total, XRectangle *rect)
1132 CSA_return_code stat;
1133 Dtcm_appointment *appt;
1134 register int lower = (int)lowerbound(day);
1135 register int upper = (int)next_ndays(day, 1);
1136 register int i, loop, n;
1137 register int nlines = 0;
1138 XFontSetExtents fontextents;
1145 CalFontExtents(w->small_font, &fontextents);
1146 char_width = fontextents.max_logical_extent.width;
1147 char_height = fontextents.max_logical_extent.height;
1148 maxlines = ((w->day_height - w->label_height) / char_height)- 1;
1149 maxchars = (w->day_width / char_width);
1154 y += (w->label_height + char_height);
1157 * Fill in a day with appointments
1160 /* loop thru twice, first displaying "no time" appointments,
1161 and then the others. */
1163 for (loop = 0; loop < 2; loop++) {
1164 for (i = 0; i < a_total; i++) {
1166 if ((cache[i].start_time < lower) || (cache[i].start_time >= upper))
1169 if (cache[i].show_time != loop)
1172 if (nlines < maxlines) {
1173 n = paint_entry(c, x, y, maxchars, &cache[i], rect);
1174 y += n * char_height;
1182 draw_chart(Calendar *c, register Week *w, XRectangle *rect)
1186 XFontSetExtents fontextents;
1189 new_XContext *xc = c->xcontext;
1190 Props *p = (Props*)c->properties;
1191 DisplayType dt = get_int_prop(p, CP_DEFAULTDISP);
1193 CalFontExtents(w->font, &fontextents);
1194 char_height = fontextents.max_logical_extent.height;
1197 * Draw chart. We first draw all the lines, then the labels
1198 * so that Xlib can batch the lines into 1 X request
1201 /* Draw horizontal lines for time */
1204 for (n = w->begin_hour; n <= w->end_hour; n++) {
1205 gr_draw_line(xc, x, y, x + w->chart_width, y, gr_solid, rect); y += w->chart_hour_height + w->add_pixels;
1208 /* Draw vertical lines for days */
1210 for (n = 0; n < 7; n++) {
1211 gr_draw_line(xc, w->chart_x + (w->chart_day_width * n),
1212 y, w->chart_x + (w->chart_day_width * n),
1213 y + w->chart_height, gr_solid, rect);
1217 * Draw box around the whole thing.
1219 gr_draw_box(xc, w->chart_x, w->chart_y, w->chart_width,
1220 w->chart_height, rect);
1221 gr_draw_box(xc, w->chart_x - 1, w->chart_y - 1,
1222 w->chart_width + 2, w->chart_height + 2, rect);
1223 /* Label horizontal lines with time of day */
1226 for (n = w->begin_hour; n <= w->end_hour; n++) {
1228 sprintf(label, "%2d", n > 12 ? n - 12 : n);
1230 sprintf(label, "%2d", n);
1231 gr_text(xc, w->x - 8, y+3,
1232 w->small_bold_font, label, rect);
1233 y += w->chart_hour_height + w->add_pixels;
1236 /* Label vertical lines with day labels */
1238 for (n = 0; n < 7; n++) {
1239 x = gr_center(w->chart_day_width, days3[n+1], w->font);
1240 gr_text(xc, w->chart_x + (w->chart_day_width * n) + x,
1241 y - char_height / 2, w->font, days3[n+1], rect);
1247 week_event(XEvent *event)
1249 Calendar *c = calendar;
1250 Props *p = (Props*)c->properties;
1251 static int lastdate;
1252 static XEvent lastevent;
1253 int x, y, i, j, hr, id;
1254 Week *w = (Week *)c->view->week_info;
1256 Editor *e = (Editor *)c->editor;
1257 ToDo *t = (ToDo*)c->todo;
1258 GEditor *ge = (GEditor*)c->geditor;
1259 static int lastrow, lastcol;
1262 x = event->xbutton.x;
1263 y = event->xbutton.y;
1264 wsel = (Selection *)w->current_selection;
1266 switch(event->type) {
1268 j = week_xytoclock(w, x, y);
1269 (col = dow(j)) == 0 ? col = 6 : col--;
1270 if (inchart(w, x, y))
1271 row = (double)(y - w->chart_y) /
1272 (double)(w->chart_hour_height+ w->add_pixels);
1275 if (j != lastdate || lastcol != col || lastrow != row) {
1276 calendar_deselect(c);
1280 c->view->olddate = c->view->date;
1282 calendar_select(c, weekdaySelect, NULL);
1285 lastcol = wsel->col;
1286 lastrow = wsel->row;
1287 lastdate = c->view->date;
1290 j = week_xytoclock(w, x, y);
1293 hr = (inchart(w, x, y)) ? week_xytohour(w, x, y) : (wsel->row + w->begin_hour);
1295 if (ds_is_double_click(&lastevent, event)) {
1296 _DtTurnOnHourGlass(c->frame);
1297 if (j == lastdate) {
1298 show_editor(c, next_nhours(j, hr), next_nhours(j, hr + 1), False);
1300 else if (editor_showing(e)) {
1301 set_editor_defaults(e, next_nhours(j, hr), next_nhours(j, hr + 1), False);
1304 _DtTurnOffHourGlass(c->frame);
1307 calendar_deselect(c);
1308 (wsel->col = dow(j)) == 0 ?
1309 wsel->col = 6 : wsel->col--;
1310 if (inchart(w, x, y))
1311 wsel->row = (double)(y - w->chart_y) /
1312 (double)(w->chart_hour_height + w->add_pixels);
1314 c->view->olddate = c->view->date;
1316 calendar_select(c, weekdaySelect, NULL);
1318 if (editor_showing(e)) {
1319 set_editor_defaults(e, next_nhours(j, hr), next_nhours(j, hr + 1), False);
1322 if (todo_showing(t)) {
1323 set_todo_defaults(t);
1326 if (geditor_showing(ge)) {
1327 set_geditor_defaults(ge, 0, 0);
1331 lastdate = c->view->date;
1332 lastcol = wsel->col;
1333 lastrow = wsel->row;
1342 week_xytohour(Week *w, int x, int y)
1344 if (!inchart(w, x, y))
1347 return(w->begin_hour + ((double)y /
1348 (double)(w->chart_hour_height + w->add_pixels)));
1352 week_xytoclock(Week *w, int x, int y)
1357 * Convert the x and y location on the week view to a date
1359 if (inchart(w, x, y)) {
1360 dow = (double)(x - w->chart_x)/(double)w->chart_day_width;
1361 } else if (inweek(w, x, y)) {
1362 if (y < w->y + w->day_height)
1363 dow = (x - w->x)/w->day_width;
1365 dow = (x - w->x - 3 * w->day_width)/w->day_width
1370 if (w->start_date == get_bot()) {
1376 else if (w->start_date == (time_t)last_ndays(get_eot(), 3)) {
1382 return(w->start_date + dow * daysec);
1387 * Handler for "hot" buttons to navigate to day view
1390 quick_button_cb(Widget widget, XtPointer client, XtPointer call)
1392 Calendar *c = calendar;
1393 Week *w = (Week *)c->view->week_info;
1394 int dow = (int) (intptr_t) client;
1397 if (c->view->date != get_bot()) {
1398 c->view->olddate = c->view->date;
1399 c->view->date = w->start_date + dow * daysec;
1401 calendar_select(c, weekhotboxSelect, NULL);
1403 cleanup_after_weekview(c);
1405 c->view->glance = dayGlance;
1407 (void)init_dayview(c);
1414 * Handle labeling, positioning and managing of a given hotbutton
1419 int n, /* which button (0..6) */
1420 int date) /* what day in month */
1422 Week *w = (Week *)c->view->week_info;
1423 Widget btn = w->hot_button[n];
1427 /* REVISIT: I18N wrap the string for day name */
1428 sprintf(buf, "%s %d", n == 6 ? days[0] : days[n + 1], date);
1430 str = XmStringCreateLocalized(buf);
1431 XtVaSetValues(btn, XmNlabelString, str, NULL);
1434 if (!XtIsManaged(btn)) {
1440 * Clear previous hot buttons because we can't display dates
1441 * prior to Jan 1, 1970
1444 clear_hot_btn(Calendar *c,
1445 int n) /* which button (0..6) */
1447 Week *w = (Week *)c->view->week_info;
1448 Widget btn = w->hot_button[n];
1450 if (XtIsManaged(btn)) {
1451 XtUnmanageChild(btn);