1 /* 2 * 3 * This program is free software; you can redistribute it and/or modify it 4 * under the terms of the GNU Lesser General Public License as published by 5 * the Free Software Foundation. 6 * 7 * This program is distributed in the hope that it will be useful, but 8 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 9 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 10 * for more details. 11 * 12 * You should have received a copy of the GNU Lesser General Public License 13 * along with this program; if not, see <http://www.gnu.org/licenses/>. 14 * 15 * 16 * Authors: 17 * Damon Chaplin <damon@ximian.com> 18 * 19 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) 20 * 21 */ 22 23 #ifndef E_DAY_VIEW_H 24 #define E_DAY_VIEW_H 25 26 #include <time.h> 27 #include <gtk/gtk.h> 28 #include <libgnomecanvas/libgnomecanvas.h> 29 30 #include "e-calendar-view.h" 31 32 /* 33 * EDayView - displays the Day & Work-Week views of the calendar. 34 */ 35 36 /* Standard GObject macros */ 37 #define E_TYPE_DAY_VIEW \ 38 (e_day_view_get_type ()) 39 #define E_DAY_VIEW(obj) \ 40 (G_TYPE_CHECK_INSTANCE_CAST \ 41 ((obj), E_TYPE_DAY_VIEW, EDayView)) 42 #define E_DAY_VIEW_CLASS(cls) \ 43 (G_TYPE_CHECK_CLASS_CAST \ 44 ((cls), E_TYPE_DAY_VIEW, EDayViewClass)) 45 #define E_IS_DAY_VIEW(obj) \ 46 (G_TYPE_CHECK_INSTANCE_TYPE \ 47 ((obj), E_TYPE_DAY_VIEW)) 48 #define E_IS_DAY_VIEW_CLASS(cls) \ 49 (G_TYPE_CHECK_CLASS_TYPE \ 50 ((cls), E_TYPE_DAY_VIEW)) 51 #define E_DAY_VIEW_GET_CLASS(obj) \ 52 (G_TYPE_INSTANCE_GET_CLASS \ 53 ((obj), E_TYPE_DAY_VIEW, EDayViewClass)) 54 55 /* The maximum number of days shown. We use the week view for anything more 56 * than about 9 days. */ 57 #define E_DAY_VIEW_MAX_DAYS 10 58 59 /* This is used as a special code to signify a long event instead of the day 60 * of a normal event. */ 61 #define E_DAY_VIEW_LONG_EVENT E_DAY_VIEW_MAX_DAYS 62 63 /* The maximum number of columns of appointments within a day in multi-day 64 * view. */ 65 #define E_DAY_VIEW_MULTI_DAY_MAX_COLUMNS 6 66 67 /* minimum width of the event in one-day view in pixels */ 68 #define E_DAY_VIEW_MIN_DAY_COL_WIDTH 60 69 70 /* The width of the gap between appointments. This should be at least 71 * E_DAY_VIEW_BAR_WIDTH, since in the top canvas we use this space to draw 72 * the triangle to represent continuing events. */ 73 #define E_DAY_VIEW_GAP_WIDTH 7 74 75 /* The width of the bars down the left of each column and appointment. 76 * This includes the borders on each side of it. */ 77 #define E_DAY_VIEW_BAR_WIDTH 7 78 79 /* The height of the horizontal bar above & beneath the selected event. 80 * This includes the borders on the top and bottom. */ 81 #define E_DAY_VIEW_BAR_HEIGHT 6 82 83 /* The size of the reminder & recurrence icons, and padding around them. */ 84 #define E_DAY_VIEW_ICON_WIDTH 16 85 #define E_DAY_VIEW_ICON_HEIGHT 16 86 #define E_DAY_VIEW_ICON_X_PAD 1 87 #define E_DAY_VIEW_ICON_Y_PAD 1 88 89 /* The space between the icons and the long event text. */ 90 #define E_DAY_VIEW_LONG_EVENT_ICON_R_PAD 1 91 92 /* The size of the border around the event. */ 93 #define E_DAY_VIEW_EVENT_BORDER_WIDTH 1 94 #define E_DAY_VIEW_EVENT_BORDER_HEIGHT 1 95 96 /* The padding on each side of the event text. */ 97 #define E_DAY_VIEW_EVENT_X_PAD 2 98 #define E_DAY_VIEW_EVENT_Y_PAD 1 99 100 /* The padding on each side of the event text for events in the top canvas. */ 101 #define E_DAY_VIEW_LONG_EVENT_X_PAD 2 102 #define E_DAY_VIEW_LONG_EVENT_Y_PAD 2 103 104 /* The size of the border around the long events in the top canvas. */ 105 #define E_DAY_VIEW_LONG_EVENT_BORDER_WIDTH 1 106 #define E_DAY_VIEW_LONG_EVENT_BORDER_HEIGHT 1 107 108 /* The space between the time and the icon/text in the top canvas. */ 109 #define E_DAY_VIEW_LONG_EVENT_TIME_X_PAD 2 110 111 /* The gap between rows in the top canvas. */ 112 #define E_DAY_VIEW_TOP_CANVAS_Y_GAP 2 113 114 G_BEGIN_DECLS 115 116 /* These are used to specify the type of an appointment. They match those 117 * used in EMeetingTimeSelector. */ 118 typedef enum { 119 E_DAY_VIEW_BUSY_TENTATIVE = 0, 120 E_DAY_VIEW_BUSY_OUT_OF_OFFICE = 1, 121 E_DAY_VIEW_BUSY_BUSY = 2, 122 123 E_DAY_VIEW_BUSY_LAST = 3 124 } EDayViewBusyType; 125 126 /* This is used to specify the format used when displaying the dates. 127 * The full format is like 'Thursday 12 September'. The abbreviated format is 128 * like 'Thu 12 Sep'. The no weekday format is like '12 Sep'. The short format 129 * is like '12'. The actual format used is determined in 130 * e_day_view_recalc_cell_sizes (), once we know the font being used. */ 131 typedef enum { 132 E_DAY_VIEW_DATE_FULL, 133 E_DAY_VIEW_DATE_ABBREVIATED, 134 E_DAY_VIEW_DATE_NO_WEEKDAY, 135 E_DAY_VIEW_DATE_SHORT 136 } EDayViewDateFormat; 137 138 /* These index our colors array. */ 139 typedef enum { 140 E_DAY_VIEW_COLOR_BG_WORKING, 141 E_DAY_VIEW_COLOR_BG_NOT_WORKING, 142 E_DAY_VIEW_COLOR_BG_SELECTED, 143 E_DAY_VIEW_COLOR_BG_SELECTED_UNFOCUSSED, 144 E_DAY_VIEW_COLOR_BG_GRID, 145 E_DAY_VIEW_COLOR_BG_MULTIDAY_TODAY, 146 147 E_DAY_VIEW_COLOR_BG_TOP_CANVAS, 148 E_DAY_VIEW_COLOR_BG_TOP_CANVAS_SELECTED, 149 E_DAY_VIEW_COLOR_BG_TOP_CANVAS_GRID, 150 151 E_DAY_VIEW_COLOR_EVENT_VBAR, 152 E_DAY_VIEW_COLOR_EVENT_BACKGROUND, 153 E_DAY_VIEW_COLOR_EVENT_BORDER, 154 155 E_DAY_VIEW_COLOR_LONG_EVENT_BACKGROUND, 156 E_DAY_VIEW_COLOR_LONG_EVENT_BORDER, 157 158 E_DAY_VIEW_COLOR_MARCUS_BAINS_LINE, 159 160 E_DAY_VIEW_COLOR_LAST 161 } EDayViewColors; 162 163 /* These specify which part of the selection we are dragging, if any. */ 164 typedef enum { 165 E_DAY_VIEW_DRAG_START, 166 E_DAY_VIEW_DRAG_END 167 } EDayViewDragPosition; 168 169 typedef struct _EDayViewEvent EDayViewEvent; 170 struct _EDayViewEvent { 171 E_CALENDAR_VIEW_EVENT_FIELDS 172 173 /* For events in the main canvas, this contains the start column. 174 * For long events in the top canvas, this is its row. */ 175 guint8 start_row_or_col; 176 177 /* For events in the main canvas, this is the number of columns that 178 * it covers. For long events this is set to 1 if the event is shown. 179 * For both types of events this is set to 0 if the event is not shown, 180 * i.e. it couldn't fit into the display. Currently long events are 181 * always shown as we just increase the height of the top canvas. */ 182 guint8 num_columns; 183 }; 184 185 typedef struct _EDayView EDayView; 186 typedef struct _EDayViewClass EDayViewClass; 187 typedef struct _EDayViewPrivate EDayViewPrivate; 188 189 struct _EDayView { 190 ECalendarView parent; 191 EDayViewPrivate *priv; 192 193 /* The top canvas where the dates are shown. */ 194 GtkWidget *top_dates_canvas; 195 GnomeCanvasItem *top_dates_canvas_item; 196 197 /* The top canvas where the dates and long appointments are shown. */ 198 GtkWidget *top_canvas; 199 GnomeCanvasItem *top_canvas_item; 200 201 /* scrollbar for top_canvas */ 202 GtkWidget *tc_vscrollbar; 203 204 /* horizontal scrollbar for main_canvas */ 205 GtkWidget *mc_hscrollbar; 206 207 /* The main canvas where the rest of the appointments are shown. */ 208 GtkWidget *main_canvas; 209 GnomeCanvasItem *main_canvas_item; 210 211 /* The canvas displaying the times of the day. */ 212 GtkWidget *time_canvas; 213 GnomeCanvasItem *time_canvas_item; 214 215 GtkWidget *vscrollbar; 216 217 /* label showing week number in upper-left corner */ 218 GtkWidget *week_number_label; 219 220 /* The start and end of the days shown. */ 221 time_t lower; 222 time_t upper; 223 224 /* The start of each day & an extra element to hold the last time. */ 225 time_t day_starts[E_DAY_VIEW_MAX_DAYS + 1]; 226 227 /* An array of EDayViewEvent elements for the top view and each day. */ 228 GArray *long_events; 229 GArray *events[E_DAY_VIEW_MAX_DAYS]; 230 231 /* These are set to FALSE whenever an event in the corresponding array 232 * is changed. Any function that needs the events sorted calls 233 * e_day_view_ensure_events_sorted (). */ 234 gboolean long_events_sorted; 235 gboolean events_sorted[E_DAY_VIEW_MAX_DAYS]; 236 237 /* This is TRUE if we need to relayout the events before drawing. */ 238 gboolean long_events_need_layout; 239 gboolean need_layout[E_DAY_VIEW_MAX_DAYS]; 240 241 /* This is TRUE if we need to reshape the canvas items, but a full 242 * layout is not necessary. */ 243 gboolean long_events_need_reshape; 244 gboolean need_reshape[E_DAY_VIEW_MAX_DAYS]; 245 246 /* The ID of the timeout function for doing a new layout. */ 247 gint layout_timeout_id; 248 249 /* The number of rows needed, depending on the times shown and the 250 * minutes per row. */ 251 gint rows; 252 253 /* The height of each row. */ 254 gint row_height; 255 256 /* The number of rows in the top display. */ 257 gint rows_in_top_display; 258 259 /* The height of each row in the top canvas. */ 260 gint top_row_height; 261 262 /* The first and last times shown in the display. The last time isn't 263 * included in the range. Default is 0:00-24:00 */ 264 gint first_hour_shown; 265 gint first_minute_shown; 266 gint last_hour_shown; 267 gint last_minute_shown; 268 269 /* Whether we use show event end times in the main canvas. */ 270 gboolean show_event_end_times; 271 272 /* This is set to TRUE when the widget is created, so it scrolls to 273 * the start of the working day when first shown. */ 274 gboolean scroll_to_work_day; 275 276 /* This is the width & offset of each of the day columns in the 277 * display. */ 278 gint day_widths[E_DAY_VIEW_MAX_DAYS + 1]; 279 gint day_offsets[E_DAY_VIEW_MAX_DAYS + 1]; 280 281 /* An array holding the number of columns in each row, in each day. 282 * Note that there are a maximum of 12 * 24 rows (when a row is 5 mins) 283 * but we don't always have that many rows. */ 284 guint8 cols_per_row[E_DAY_VIEW_MAX_DAYS][12 * 24]; 285 /* The maximum number of columns from all rows in cols_per_row */ 286 gint max_cols; 287 288 /* Sizes of the various time strings. */ 289 gint small_hour_widths[24]; 290 gint max_small_hour_width; 291 gint max_minute_width; 292 gint colon_width; 293 gint digit_width; /* Size of '0' character. */ 294 295 /* This specifies how we are displaying the dates at the top. */ 296 EDayViewDateFormat date_format; 297 298 /* These are the longest month & weekday names in the current font. 299 * Months are 0 to 11. Weekdays are 0 (Sun) to 6 (Sat). */ 300 gint longest_month_name; 301 gint longest_abbreviated_month_name; 302 gint longest_weekday_name; 303 gint longest_abbreviated_weekday_name; 304 305 /* The large font used to display the hours. I don't think we need a 306 * fontset since we only display numbers. */ 307 PangoFontDescription *large_font_desc; 308 PangoFontDescription *small_font_desc; 309 310 /* The icons. */ 311 GdkPixbuf *reminder_icon; 312 GdkPixbuf *recurrence_icon; 313 GdkPixbuf *timezone_icon; 314 GdkPixbuf *meeting_icon; 315 GdkPixbuf *attach_icon; 316 317 /* Colors for drawing. */ 318 GdkColor colors[E_DAY_VIEW_COLOR_LAST]; 319 320 /* The normal & resizing cursors. */ 321 GdkCursor *normal_cursor; 322 GdkCursor *move_cursor; 323 GdkCursor *resize_width_cursor; 324 GdkCursor *resize_height_cursor; 325 326 /* This remembers the last cursor set on the window. */ 327 GdkCursor *last_cursor_set_in_top_canvas; 328 GdkCursor *last_cursor_set_in_main_canvas; 329 330 /* 331 * Editing, Selection & Dragging data 332 */ 333 334 /* The horizontal bars to resize events in the main canvas. */ 335 GnomeCanvasItem *main_canvas_top_resize_bar_item; 336 GnomeCanvasItem *main_canvas_bottom_resize_bar_item; 337 338 /* The event currently being edited. The day is -1 if no event is 339 being edited, or E_DAY_VIEW_LONG_EVENT if a long event is edited. */ 340 gint editing_event_day; 341 gint editing_event_num; 342 343 /* This is a GnomeCanvasRect which is placed around an item while it 344 * is being resized, so we can raise it above all other EText items. */ 345 GnomeCanvasItem *resize_long_event_rect_item; 346 GnomeCanvasItem *resize_rect_item; 347 GnomeCanvasItem *resize_bar_item; 348 349 /* The event for which a popup menu is being displayed, as above. */ 350 gint popup_event_day; 351 gint popup_event_num; 352 353 /* The currently selected region. If selection_start_day is -1 there is 354 * no current selection. If start_row or end_row is -1 then the 355 * selection is in the top canvas. */ 356 gint selection_start_day; 357 gint selection_end_day; 358 gint selection_start_row; 359 gint selection_end_row; 360 361 /* This is TRUE if the selection is currently being dragged using the 362 * mouse. */ 363 gboolean selection_is_being_dragged; 364 365 /* This specifies which end of the selection is being dragged. */ 366 EDayViewDragPosition selection_drag_pos; 367 368 /* This is TRUE if the selection is in the top canvas only (i.e. if the 369 * last motion event was in the top canvas). */ 370 gboolean selection_in_top_canvas; 371 372 /* The last mouse position, relative to the main canvas window. 373 * Used when auto-scrolling to update the selection. */ 374 gint last_mouse_x; 375 gint last_mouse_y; 376 377 /* Auto-scroll info for when selecting an area or dragging an item. */ 378 gint auto_scroll_timeout_id; 379 gint auto_scroll_delay; 380 gboolean auto_scroll_up; 381 382 /* These are used for the resize bars. */ 383 gint resize_bars_event_day; 384 gint resize_bars_event_num; 385 386 /* These are used when resizing events. */ 387 gint resize_event_day; 388 gint resize_event_num; 389 ECalendarViewPosition resize_drag_pos; 390 gint resize_start_row; 391 gint resize_end_row; 392 393 /* This is used to remember the last edited event. */ 394 gchar *last_edited_comp_string; 395 396 /* This is the event the mouse button was pressed on. If the button 397 * is released we start editing it, but if the mouse is dragged we set 398 * this to -1. */ 399 gint pressed_event_day; 400 gint pressed_event_num; 401 402 /* These are used when dragging events. If drag_event_day is not -1 we 403 * know that we are dragging one of the EDayView events around. */ 404 gint drag_event_day; 405 gint drag_event_num; 406 407 /* The last mouse position when dragging, in the entire canvas. */ 408 gint drag_event_x; 409 gint drag_event_y; 410 411 /* The offset of the mouse from the top of the event, in rows. 412 * In the top canvas this is the offset from the left, in days. */ 413 gint drag_event_offset; 414 415 /* The last day & row dragged to, so we know when we need to update 416 * the dragged event's position. */ 417 gint drag_last_day; 418 gint drag_last_row; 419 420 /* This is a GnomeCanvasRect which is placed around an item while it 421 * is being resized, so we can raise it above all other EText items. */ 422 GnomeCanvasItem *drag_long_event_rect_item; 423 GnomeCanvasItem *drag_long_event_item; 424 GnomeCanvasItem *drag_rect_item; 425 GnomeCanvasItem *drag_bar_item; 426 GnomeCanvasItem *drag_item; 427 428 /* Grabbed pointer device while dragging. */ 429 GdkDevice *grabbed_pointer; 430 431 /* "am" and "pm" in the current locale, and their widths. */ 432 gchar *am_string; 433 gchar *pm_string; 434 gint am_string_width; 435 gint pm_string_width; 436 437 /* remember last selected interval when click and restore on double click, 438 * if we double clicked inside that interval. */ 439 guint32 bc_event_time; 440 time_t before_click_dtstart; 441 time_t before_click_dtend; 442 443 gboolean requires_update; 444 }; 445 446 struct _EDayViewClass { 447 ECalendarViewClass parent_class; 448 }; 449 450 GType e_day_view_get_type (void) G_GNUC_CONST; 451 ECalendarView * e_day_view_new (ECalModel *model); 452 453 gboolean e_day_view_get_draw_flat_events (EDayView *day_view); 454 void e_day_view_set_draw_flat_events (EDayView *day_view, 455 gboolean draw_flat_events); 456 457 /* Whether we are displaying a work-week, in which case the display always 458 * starts on the first day of the working week. */ 459 gboolean e_day_view_get_work_week_view (EDayView *day_view); 460 void e_day_view_set_work_week_view (EDayView *day_view, 461 gboolean work_week_view); 462 463 /* The number of days shown in the EDayView, from 1 to 7. This is normally 464 * either 1 or 5 (for the Work-Week view). */ 465 gint e_day_view_get_days_shown (EDayView *day_view); 466 void e_day_view_set_days_shown (EDayView *day_view, 467 gint days_shown); 468 469 /* Whether we display the Marcus Bains Line in the main canvas and time 470 * canvas. */ 471 void e_day_view_marcus_bains_update (EDayView *day_view); 472 gboolean e_day_view_marcus_bains_get_show_line 473 (EDayView *day_view); 474 void e_day_view_marcus_bains_set_show_line 475 (EDayView *day_view, 476 gboolean show_line); 477 const gchar * e_day_view_marcus_bains_get_day_view_color 478 (EDayView *day_view); 479 void e_day_view_marcus_bains_set_day_view_color 480 (EDayView *day_view, 481 const gchar *day_view_color); 482 const gchar * e_day_view_marcus_bains_get_time_bar_color 483 (EDayView *day_view); 484 void e_day_view_marcus_bains_set_time_bar_color 485 (EDayView *day_view, 486 const gchar *time_bar_color); 487 488 /* Whether we display event end times in the main canvas. */ 489 gboolean e_day_view_get_show_event_end_times 490 (EDayView *day_view); 491 void e_day_view_set_show_event_end_times 492 (EDayView *day_view, 493 gboolean show); 494 495 void e_day_view_delete_occurrence (EDayView *day_view); 496 497 /* Returns the number of selected events (0 or 1 at present). */ 498 gint e_day_view_get_num_events_selected 499 (EDayView *day_view); 500 501 /* 502 * Internal functions called by the associated canvas items. 503 */ 504 void e_day_view_check_layout (EDayView *day_view); 505 gint e_day_view_convert_time_to_row (EDayView *day_view, 506 gint hour, 507 gint minute); 508 gint e_day_view_convert_time_to_position 509 (EDayView *day_view, 510 gint hour, 511 gint minute); 512 gboolean e_day_view_get_event_rows (EDayView *day_view, 513 gint day, 514 gint event_num, 515 gint *start_row_out, 516 gint *end_row_out); 517 gboolean e_day_view_get_event_position (EDayView *day_view, 518 gint day, 519 gint event_num, 520 gint *item_x, 521 gint *item_y, 522 gint *item_w, 523 gint *item_h); 524 gboolean e_day_view_get_long_event_position 525 (EDayView *day_view, 526 gint event_num, 527 gint *start_day, 528 gint *end_day, 529 gint *item_x, 530 gint *item_y, 531 gint *item_w, 532 gint *item_h); 533 534 void e_day_view_start_selection (EDayView *day_view, 535 gint day, 536 gint row); 537 void e_day_view_update_selection (EDayView *day_view, 538 gint day, 539 gint row); 540 void e_day_view_finish_selection (EDayView *day_view); 541 542 void e_day_view_check_auto_scroll (EDayView *day_view, 543 gint event_x, 544 gint event_y); 545 void e_day_view_stop_auto_scroll (EDayView *day_view); 546 547 void e_day_view_convert_time_to_display 548 (EDayView *day_view, 549 gint hour, 550 gint *display_hour, 551 const gchar **suffix, 552 gint *suffix_width); 553 gint e_day_view_get_time_string_width 554 (EDayView *day_view); 555 556 gint e_day_view_event_sort_func (gconstpointer arg1, 557 gconstpointer arg2); 558 559 gboolean e_day_view_find_event_from_item (EDayView *day_view, 560 GnomeCanvasItem *item, 561 gint *day_return, 562 gint *event_num_return); 563 void e_day_view_update_calendar_selection_time 564 (EDayView *day_view); 565 void e_day_view_ensure_rows_visible (EDayView *day_view, 566 gint start_row, 567 gint end_row); 568 569 gboolean e_day_view_is_editing (EDayView *day_view); 570 571 void e_day_view_update_timezone_name_labels 572 (EDayView *day_view); 573 574 G_END_DECLS 575 576 #endif /* E_DAY_VIEW_H */ 577