Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <gtk/gtk.h>
- #include <string.h> /* strlen */
- struct _GtkCalendarPrivate
- {
- GtkCalendarDisplayOptions display_flags;
- GdkWindow *main_win;
- GdkWindow *arrow_win[4];
- gchar grow_space [32];
- gint month;
- gint year;
- gint selected_day;
- gint day_month[6][7];
- gint day[6][7];
- gint num_marked_dates;
- gint marked_date[31];
- gint focus_row;
- gint focus_col;
- guint header_h;
- guint day_name_h;
- guint main_h;
- guint arrow_state[4];
- guint arrow_width;
- guint max_month_width;
- guint max_year_width;
- guint day_width;
- guint week_width;
- guint min_day_width;
- guint max_day_char_width;
- guint max_day_char_ascent;
- guint max_day_char_descent;
- guint max_label_char_ascent;
- guint max_label_char_descent;
- guint max_week_char_width;
- /* flags */
- guint year_before : 1;
- guint need_timer : 1;
- guint in_drag : 1;
- guint drag_highlight : 1;
- guint32 timer;
- gint click_child;
- gint week_start;
- gint drag_start_x;
- gint drag_start_y;
- /* Optional callback, used to display extra information for each day. */
- GtkCalendarDetailFunc detail_func;
- gpointer detail_func_user_data;
- GDestroyNotify detail_func_destroy;
- /* Size requistion for details provided by the hook. */
- gint detail_height_rows;
- gint detail_width_chars;
- gint detail_overflow[6];
- };
- typedef struct _GtkCalendarPrivate GtkCalendarPrivate;
- typedef struct _JjkCalendar JjkCalendar;
- typedef struct _JjkCalendarClass JjkCalendarClass;
- struct _JjkCalendar
- {
- GtkCalendar parent;
- GtkCalendarPrivate *gtk_priv;
- };
- struct _JjkCalendarClass
- {
- GtkCalendarClass parent_class;
- /* pointer to original draw function */
- gpointer gtk_calendar_draw;
- };
- G_DEFINE_TYPE (JjkCalendar, jjk_calendar, GTK_TYPE_CALENDAR);
- #define JJK_TYPE_CALENDAR (jjk_calendar_get_type ())
- #define JJK_CALENDAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), JJK_TYPE_CALENDAR, JjkCalendar))
- #define JJK_CALENDAR_CLASS(obj) (G_TYPE_CHECK_CLASS_CAST ((obj), JJK_CALENDAR, JjkCalendarClass))
- #define JJK_IS_CALENDAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), JJK_TYPE_CALENDAR))
- #define JJK_IS_CALENDAR_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE ((obj), JJK_TYPE_CALENDAR))
- #define JJK_CALENDAR_GET_CLASS (G_TYPE_INSTANCE_GET_CLASS ((obj), JJK_TYPE_CALENDAR, JjkCalendarClass))
- typedef gboolean (*draw_cb) (GtkWidget *, cairo_t *);
- static gboolean jjk_calendar_draw (GtkWidget *widget, cairo_t *cr);
- #define GTK_CALENDAR_GET_PRIVATE(widget) (GTK_CALENDAR (widget)->priv)
- static void
- jjk_calendar_class_init (JjkCalendarClass *class)
- {
- GtkWidgetClass *widget_class;
- widget_class = GTK_WIDGET_CLASS (class);
- /* keep a pointer to original draw function, and set our own instead */
- class->gtk_calendar_draw = widget_class->draw;
- widget_class->draw = jjk_calendar_draw;
- }
- static void
- jjk_calendar_init (JjkCalendar *calendar)
- {
- calendar->gtk_priv = G_TYPE_INSTANCE_GET_PRIVATE (calendar,
- GTK_TYPE_CALENDAR,
- GtkCalendarPrivate);
- }
- /**********************************************************/
- /* Spacing around day/week headers and main area, inside those windows */
- #define CALENDAR_MARGIN 0
- #define DAY_XSEP 0 /* not really good for small calendar */
- #define DAY_YSEP 0 /* not really good for small calendar */
- static gint
- calendar_get_xsep (GtkCalendar *calendar)
- {
- gint xsep;
- gtk_widget_style_get (GTK_WIDGET (calendar),
- "horizontal-separation", &xsep,
- NULL);
- return xsep;
- }
- static gint
- calendar_get_ysep (GtkCalendar *calendar)
- {
- gint ysep;
- gtk_widget_style_get (GTK_WIDGET (calendar),
- "vertical-separation", &ysep,
- NULL);
- return ysep;
- }
- static gint
- calendar_get_inner_border (GtkCalendar *calendar)
- {
- gint inner_border;
- gtk_widget_style_get (GTK_WIDGET (calendar),
- "inner-border", &inner_border,
- NULL);
- return inner_border;
- }
- static gint
- calendar_row_height (GtkCalendar *calendar)
- {
- GtkCalendarPrivate *priv = calendar->priv;
- return (GTK_CALENDAR_GET_PRIVATE (calendar)->main_h - CALENDAR_MARGIN
- - ((priv->display_flags & GTK_CALENDAR_SHOW_DAY_NAMES)
- ? calendar_get_ysep (calendar) : CALENDAR_MARGIN)) / 6;
- }
- /* calendar_left_x_for_column: returns the x coordinate
- * for the left of the column */
- static gint
- calendar_left_x_for_column (GtkCalendar *calendar,
- gint column)
- {
- GtkCalendarPrivate *priv = calendar->priv;
- gint width;
- gint x_left;
- gint week_width;
- gint calendar_xsep = calendar_get_xsep (calendar);
- GtkStyleContext *context;
- GtkStateFlags state;
- gint inner_border = calendar_get_inner_border (calendar);
- GtkBorder padding;
- context = gtk_widget_get_style_context (GTK_WIDGET (calendar));
- state = gtk_widget_get_state_flags (GTK_WIDGET (calendar));
- gtk_style_context_get_padding (context, state, &padding);
- week_width = priv->week_width + padding.left + inner_border;
- if (gtk_widget_get_direction (GTK_WIDGET (calendar)) == GTK_TEXT_DIR_RTL)
- {
- column = 6 - column;
- week_width = 0;
- }
- width = GTK_CALENDAR_GET_PRIVATE (calendar)->day_width;
- if (priv->display_flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
- x_left = week_width + calendar_xsep + (width + DAY_XSEP) * column;
- else
- x_left = week_width + CALENDAR_MARGIN + (width + DAY_XSEP) * column;
- return x_left;
- }
- /* calendar_top_y_for_row: returns the y coordinate
- * for the top of the row */
- static gint
- calendar_top_y_for_row (GtkCalendar *calendar,
- gint row)
- {
- GtkStyleContext *context;
- GtkAllocation allocation;
- gint inner_border = calendar_get_inner_border (calendar);
- GtkStateFlags state;
- GtkBorder padding;
- gtk_widget_get_allocation (GTK_WIDGET (calendar), &allocation);
- context = gtk_widget_get_style_context (GTK_WIDGET (calendar));
- state = gtk_widget_get_state_flags (GTK_WIDGET (calendar));
- gtk_style_context_get_padding (context, state, &padding);
- return allocation.height
- - padding.top - inner_border
- - (CALENDAR_MARGIN + (6 - row)
- * calendar_row_height (calendar));
- }
- static void
- calendar_day_rectangle (GtkCalendar *calendar,
- gint row,
- gint col,
- GdkRectangle *rect)
- {
- GtkCalendarPrivate *priv = GTK_CALENDAR_GET_PRIVATE (calendar);
- rect->x = calendar_left_x_for_column (calendar, col);
- rect->y = calendar_top_y_for_row (calendar, row);
- rect->height = calendar_row_height (calendar);
- rect->width = priv->day_width;
- }
- /**********************************************************/
- static gboolean
- jjk_calendar_draw (GtkWidget *widget, cairo_t *cr)
- {
- JjkCalendarClass *class;
- draw_cb cb;
- /* first, call the original function */
- class = G_TYPE_INSTANCE_GET_CLASS (widget, JJK_CALENDAR_CLASS, JjkCalendarClass);
- cb = (draw_cb) class->gtk_calendar_draw;
- cb (widget, cr);
- /* then, our additions */
- GtkCalendar *calendar = GTK_CALENDAR (widget);
- GtkCalendarPrivate *gtk_priv = GTK_CALENDAR_GET_PRIVATE (widget);
- gint r, c, row, col;
- /* first figure out whether we're showing the current month or not */
- GDateTime *datetime;
- gint cur_year, cur_month, cur_day;
- datetime = g_date_time_new_now_local ();
- g_date_time_get_ymd (datetime, &cur_year, &cur_month, &cur_day);
- g_date_time_unref (datetime);
- if (cur_year != gtk_priv->year || cur_month != gtk_priv->month + 1)
- return FALSE;
- /* okay, so then we need to highlight cur_day */
- /* locate day position (row,col) on calendar */
- row = -1;
- col = -1;
- for (r = 0; r < 6; r++)
- for (c = 0; c < 7; c++)
- if (gtk_priv->day_month[r][c] == 1 &&
- gtk_priv->day[r][c] == cur_day)
- {
- row = r;
- col = c;
- }
- if (row == -1 || col == -1)
- return FALSE;
- /* update drawing */
- GdkRectangle day_rect;
- GtkStyleContext *context;
- GtkStateFlags state = 0;
- gchar buffer[32];
- PangoLayout *layout;
- PangoRectangle logical_rect;
- gint x_loc, y_loc;
- calendar_day_rectangle (calendar, row, col, &day_rect);
- cairo_save (cr);
- context = gtk_widget_get_style_context (widget);
- gtk_style_context_save (context);
- if (!gtk_widget_get_sensitive (widget))
- {
- state |= GTK_STATE_FLAG_INSENSITIVE;
- }
- else
- {
- if (gtk_widget_has_focus (widget))
- state |= GTK_STATE_FLAG_FOCUSED;
- if (gtk_priv->marked_date[cur_day-1])
- state |= GTK_STATE_FLAG_ACTIVE;
- if (gtk_priv->selected_day == cur_day)
- {
- state |= GTK_STATE_FLAG_SELECTED;
- }
- /* add our extra class */
- gtk_style_context_add_class (context, "today");
- gtk_style_context_set_state (context, state);
- gtk_render_background (context, cr,
- day_rect.x, day_rect.y,
- day_rect.width, day_rect.height);
- }
- gtk_style_context_set_state (context, state);
- /* load some default styling */
- GtkCssProvider *provider;
- const gchar* css = "JjkCalendar.today { background-color: #c0c0c0; } \
- JjkCalendar.today:selected { background-color: #3a60f9; }";
- gsize css_len = (gsize) strlen(css);
- provider = gtk_css_provider_get_default ();
- gtk_css_provider_load_from_data (provider, css, css_len, NULL);
- gtk_style_context_add_provider (context, (GtkStyleProvider *) provider,
- GTK_STYLE_PROVIDER_PRIORITY_THEME);
- g_snprintf (buffer, sizeof (buffer), "%d", cur_day);
- layout = gtk_widget_create_pango_layout (widget, buffer);
- pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER);
- pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
- x_loc = day_rect.x + (day_rect.width - logical_rect.width) / 2;
- y_loc = day_rect.y;
- gtk_render_layout (context, cr, x_loc, y_loc, layout);
- if (gtk_priv->day_month[row][col] == 1
- && (gtk_priv->marked_date[cur_day-1]))
- {
- gtk_render_layout (context, cr, x_loc - 1, y_loc, layout);
- }
- if (gtk_widget_has_visible_focus (widget) &&
- gtk_priv->focus_row == row && gtk_priv->focus_col == col)
- gtk_render_focus (context, cr,
- day_rect.x, day_rect.y,
- day_rect.width, day_rect.height);
- gtk_style_context_restore (context);
- g_object_unref (layout);
- cairo_restore (cr);
- return FALSE;
- }
- GtkWidget *
- jjk_calendar_new (void)
- {
- return g_object_new (JJK_TYPE_CALENDAR, NULL);
- }
- void
- jjk_calendar_set_first_day (JjkCalendar *calendar, gint day)
- {
- if (day < 0 || day > 6 || day == calendar->gtk_priv->week_start)
- return;
- calendar->gtk_priv->week_start = day;
- /* this will force a refresh of the calendar, making sure internally the
- * calendar_compute_days is called, since we changed things */
- gtk_calendar_select_month (GTK_CALENDAR(calendar),
- calendar->gtk_priv->month,
- calendar->gtk_priv->year);
- }
- int
- main (int argc, char **argv)
- {
- gtk_init (&argc, &argv);
- GtkWidget *window;
- window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
- gtk_window_set_title (GTK_WINDOW (window), "some title");
- gtk_container_set_border_width (GTK_CONTAINER (window), 1);
- gtk_window_set_has_resize_grip (GTK_WINDOW(window), FALSE);
- GtkWidget *cal;
- cal = jjk_calendar_new ();
- jjk_calendar_set_first_day (JJK_CALENDAR (cal), 2);
- gtk_widget_show (cal);
- gtk_container_add (GTK_CONTAINER (window), cal);
- g_signal_connect (window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
- gtk_widget_show (window);
- gtk_main ();
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement