Advertisement
Guest User

Untitled

a guest
Dec 16th, 2011
45
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 12.36 KB | None | 0 0
  1.  
  2. #include <gtk/gtk.h>
  3. #include <string.h>     /* strlen */
  4.  
  5. struct _GtkCalendarPrivate
  6. {
  7.   GtkCalendarDisplayOptions display_flags;
  8.  
  9.   GdkWindow *main_win;
  10.   GdkWindow *arrow_win[4];
  11.  
  12.   gchar grow_space [32];
  13.  
  14.   gint  month;
  15.   gint  year;
  16.   gint  selected_day;
  17.  
  18.   gint  day_month[6][7];
  19.   gint  day[6][7];
  20.  
  21.   gint  num_marked_dates;
  22.   gint  marked_date[31];
  23.  
  24.   gint  focus_row;
  25.   gint  focus_col;
  26.  
  27.   guint header_h;
  28.   guint day_name_h;
  29.   guint main_h;
  30.  
  31.   guint arrow_state[4];
  32.   guint arrow_width;
  33.   guint max_month_width;
  34.   guint max_year_width;
  35.  
  36.   guint day_width;
  37.   guint week_width;
  38.  
  39.   guint min_day_width;
  40.   guint max_day_char_width;
  41.   guint max_day_char_ascent;
  42.   guint max_day_char_descent;
  43.   guint max_label_char_ascent;
  44.   guint max_label_char_descent;
  45.   guint max_week_char_width;
  46.  
  47.   /* flags */
  48.   guint year_before : 1;
  49.  
  50.   guint need_timer  : 1;
  51.  
  52.   guint in_drag : 1;
  53.   guint drag_highlight : 1;
  54.  
  55.   guint32 timer;
  56.   gint click_child;
  57.  
  58.   gint week_start;
  59.  
  60.   gint drag_start_x;
  61.   gint drag_start_y;
  62.  
  63.   /* Optional callback, used to display extra information for each day. */
  64.   GtkCalendarDetailFunc detail_func;
  65.   gpointer              detail_func_user_data;
  66.   GDestroyNotify        detail_func_destroy;
  67.  
  68.   /* Size requistion for details provided by the hook. */
  69.   gint detail_height_rows;
  70.   gint detail_width_chars;
  71.   gint detail_overflow[6];
  72. };
  73.  
  74. typedef struct _GtkCalendarPrivate  GtkCalendarPrivate;
  75.  
  76.  
  77.  
  78. typedef struct _JjkCalendar         JjkCalendar;
  79. typedef struct _JjkCalendarClass    JjkCalendarClass;
  80.  
  81. struct _JjkCalendar
  82. {
  83.     GtkCalendar parent;
  84.    
  85.     GtkCalendarPrivate *gtk_priv;
  86. };
  87.  
  88. struct _JjkCalendarClass
  89. {
  90.     GtkCalendarClass parent_class;
  91.    
  92.     /* pointer to original draw function */
  93.     gpointer gtk_calendar_draw;
  94. };
  95.  
  96. G_DEFINE_TYPE (JjkCalendar, jjk_calendar, GTK_TYPE_CALENDAR);
  97.  
  98. #define JJK_TYPE_CALENDAR               (jjk_calendar_get_type ())
  99. #define JJK_CALENDAR(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), JJK_TYPE_CALENDAR, JjkCalendar))
  100. #define JJK_CALENDAR_CLASS(obj)         (G_TYPE_CHECK_CLASS_CAST ((obj), JJK_CALENDAR,  JjkCalendarClass))
  101. #define JJK_IS_CALENDAR(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), JJK_TYPE_CALENDAR))
  102. #define JJK_IS_CALENDAR_CLASS(obj)      (G_TYPE_CHECK_CLASS_TYPE ((obj), JJK_TYPE_CALENDAR))
  103. #define JJK_CALENDAR_GET_CLASS          (G_TYPE_INSTANCE_GET_CLASS ((obj), JJK_TYPE_CALENDAR, JjkCalendarClass))
  104.  
  105. typedef gboolean (*draw_cb) (GtkWidget *, cairo_t *);
  106. static gboolean jjk_calendar_draw (GtkWidget *widget, cairo_t *cr);
  107. #define GTK_CALENDAR_GET_PRIVATE(widget)  (GTK_CALENDAR (widget)->priv)
  108.  
  109. static void
  110. jjk_calendar_class_init (JjkCalendarClass *class)
  111. {
  112.     GtkWidgetClass *widget_class;
  113.    
  114.     widget_class = GTK_WIDGET_CLASS (class);
  115.    
  116.     /* keep a pointer to original draw function, and set our own instead */
  117.     class->gtk_calendar_draw = widget_class->draw;
  118.     widget_class->draw = jjk_calendar_draw;
  119. }
  120.  
  121. static void
  122. jjk_calendar_init (JjkCalendar *calendar)
  123. {
  124.     calendar->gtk_priv = G_TYPE_INSTANCE_GET_PRIVATE (calendar,
  125.                                                       GTK_TYPE_CALENDAR,
  126.                                                       GtkCalendarPrivate);
  127. }
  128.  
  129. /**********************************************************/
  130.  
  131. /* Spacing around day/week headers and main area, inside those windows */
  132. #define CALENDAR_MARGIN          0
  133.  
  134. #define DAY_XSEP                 0 /* not really good for small calendar */
  135. #define DAY_YSEP                 0 /* not really good for small calendar */
  136.  
  137. static gint
  138. calendar_get_xsep (GtkCalendar *calendar)
  139. {
  140.   gint xsep;
  141.  
  142.   gtk_widget_style_get (GTK_WIDGET (calendar),
  143.                         "horizontal-separation", &xsep,
  144.                         NULL);
  145.  
  146.   return xsep;
  147. }
  148.  
  149. static gint
  150. calendar_get_ysep (GtkCalendar *calendar)
  151. {
  152.   gint ysep;
  153.  
  154.   gtk_widget_style_get (GTK_WIDGET (calendar),
  155.                         "vertical-separation", &ysep,
  156.                         NULL);
  157.  
  158.   return ysep;
  159. }
  160.  
  161. static gint
  162. calendar_get_inner_border (GtkCalendar *calendar)
  163. {
  164.   gint inner_border;
  165.  
  166.   gtk_widget_style_get (GTK_WIDGET (calendar),
  167.                         "inner-border", &inner_border,
  168.                         NULL);
  169.  
  170.   return inner_border;
  171. }
  172.  
  173. static gint
  174. calendar_row_height (GtkCalendar *calendar)
  175. {
  176.   GtkCalendarPrivate *priv = calendar->priv;
  177.  
  178.   return (GTK_CALENDAR_GET_PRIVATE (calendar)->main_h - CALENDAR_MARGIN
  179.           - ((priv->display_flags & GTK_CALENDAR_SHOW_DAY_NAMES)
  180.              ? calendar_get_ysep (calendar) : CALENDAR_MARGIN)) / 6;
  181. }
  182.  
  183.  
  184. /* calendar_left_x_for_column: returns the x coordinate
  185.  * for the left of the column */
  186. static gint
  187. calendar_left_x_for_column (GtkCalendar *calendar,
  188.                             gint         column)
  189. {
  190.   GtkCalendarPrivate *priv = calendar->priv;
  191.   gint width;
  192.   gint x_left;
  193.   gint week_width;
  194.   gint calendar_xsep = calendar_get_xsep (calendar);
  195.   GtkStyleContext *context;
  196.   GtkStateFlags state;
  197.   gint inner_border = calendar_get_inner_border (calendar);
  198.   GtkBorder padding;
  199.  
  200.   context = gtk_widget_get_style_context (GTK_WIDGET (calendar));
  201.   state = gtk_widget_get_state_flags (GTK_WIDGET (calendar));
  202.   gtk_style_context_get_padding (context, state, &padding);
  203.  
  204.   week_width = priv->week_width + padding.left + inner_border;
  205.  
  206.   if (gtk_widget_get_direction (GTK_WIDGET (calendar)) == GTK_TEXT_DIR_RTL)
  207.     {
  208.       column = 6 - column;
  209.       week_width = 0;
  210.     }
  211.  
  212.   width = GTK_CALENDAR_GET_PRIVATE (calendar)->day_width;
  213.   if (priv->display_flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
  214.     x_left = week_width + calendar_xsep + (width + DAY_XSEP) * column;
  215.   else
  216.     x_left = week_width + CALENDAR_MARGIN + (width + DAY_XSEP) * column;
  217.  
  218.   return x_left;
  219. }
  220.  
  221. /* calendar_top_y_for_row: returns the y coordinate
  222.  * for the top of the row */
  223. static gint
  224. calendar_top_y_for_row (GtkCalendar *calendar,
  225.                         gint         row)
  226. {
  227.   GtkStyleContext *context;
  228.   GtkAllocation allocation;
  229.   gint inner_border = calendar_get_inner_border (calendar);
  230.   GtkStateFlags state;
  231.   GtkBorder padding;
  232.  
  233.   gtk_widget_get_allocation (GTK_WIDGET (calendar), &allocation);
  234.   context = gtk_widget_get_style_context (GTK_WIDGET (calendar));
  235.   state = gtk_widget_get_state_flags (GTK_WIDGET (calendar));
  236.  
  237.   gtk_style_context_get_padding (context, state, &padding);
  238.  
  239.   return  allocation.height
  240.           - padding.top - inner_border
  241.           - (CALENDAR_MARGIN + (6 - row)
  242.              * calendar_row_height (calendar));
  243. }
  244.  
  245. static void
  246. calendar_day_rectangle (GtkCalendar  *calendar,
  247.                         gint          row,
  248.                         gint          col,
  249.                         GdkRectangle *rect)
  250. {
  251.   GtkCalendarPrivate *priv = GTK_CALENDAR_GET_PRIVATE (calendar);
  252.  
  253.   rect->x = calendar_left_x_for_column (calendar, col);
  254.   rect->y = calendar_top_y_for_row (calendar, row);
  255.   rect->height = calendar_row_height (calendar);
  256.   rect->width = priv->day_width;
  257. }
  258.  
  259. /**********************************************************/
  260.  
  261. static gboolean
  262. jjk_calendar_draw (GtkWidget *widget, cairo_t *cr)
  263. {
  264.     JjkCalendarClass *class;
  265.     draw_cb cb;
  266.    
  267.     /* first, call the original function */
  268.     class = G_TYPE_INSTANCE_GET_CLASS (widget, JJK_CALENDAR_CLASS, JjkCalendarClass);
  269.     cb = (draw_cb) class->gtk_calendar_draw;
  270.     cb (widget, cr);
  271.    
  272.     /* then, our additions */
  273.  
  274.     GtkCalendar *calendar = GTK_CALENDAR (widget);
  275.     GtkCalendarPrivate *gtk_priv = GTK_CALENDAR_GET_PRIVATE (widget);
  276.     gint r, c, row, col;
  277.    
  278.     /* first figure out whether we're showing the current month or not */
  279.     GDateTime *datetime;
  280.     gint cur_year, cur_month, cur_day;
  281.    
  282.     datetime = g_date_time_new_now_local ();
  283.     g_date_time_get_ymd (datetime, &cur_year, &cur_month, &cur_day);
  284.     g_date_time_unref (datetime);
  285.    
  286.     if (cur_year != gtk_priv->year || cur_month != gtk_priv->month + 1)
  287.         return FALSE;
  288.     /* okay, so then we need to highlight cur_day */
  289.    
  290.     /* locate day position (row,col) on calendar */
  291.     row = -1;
  292.     col = -1;
  293.     for (r = 0; r < 6; r++)
  294.         for (c = 0; c < 7; c++)
  295.             if (gtk_priv->day_month[r][c] == 1 &&
  296.                 gtk_priv->day[r][c] == cur_day)
  297.             {
  298.                 row = r;
  299.                 col = c;
  300.             }
  301.     if (row == -1 || col == -1)
  302.         return FALSE;
  303.    
  304.     /* update drawing */
  305.     GdkRectangle day_rect;
  306.     GtkStyleContext *context;
  307.     GtkStateFlags state = 0;
  308.     gchar buffer[32];
  309.    
  310.     PangoLayout *layout;
  311.     PangoRectangle logical_rect;
  312.     gint x_loc, y_loc;
  313.    
  314.     calendar_day_rectangle (calendar, row, col, &day_rect);
  315.     cairo_save (cr);
  316.     context = gtk_widget_get_style_context (widget);
  317.     gtk_style_context_save (context);
  318.  
  319.     if (!gtk_widget_get_sensitive (widget))
  320.     {
  321.         state |= GTK_STATE_FLAG_INSENSITIVE;
  322.     }
  323.     else
  324.     {
  325.         if (gtk_widget_has_focus (widget))
  326.             state |= GTK_STATE_FLAG_FOCUSED;
  327.  
  328.         if (gtk_priv->marked_date[cur_day-1])
  329.             state |= GTK_STATE_FLAG_ACTIVE;
  330.  
  331.         if (gtk_priv->selected_day == cur_day)
  332.         {
  333.             state |= GTK_STATE_FLAG_SELECTED;
  334.         }
  335.        
  336.         /* add our extra class */
  337.         gtk_style_context_add_class (context, "today");
  338.        
  339.         gtk_style_context_set_state (context, state);
  340.         gtk_render_background (context, cr,
  341.                                day_rect.x, day_rect.y,
  342.                                day_rect.width, day_rect.height);
  343.     }
  344.  
  345.     gtk_style_context_set_state (context, state);
  346.  
  347.     /* load some default styling */
  348.     GtkCssProvider *provider;
  349.     const gchar* css = "JjkCalendar.today { background-color: #c0c0c0; } \
  350.        JjkCalendar.today:selected { background-color: #3a60f9; }";
  351.     gsize css_len = (gsize) strlen(css);
  352.     provider = gtk_css_provider_get_default ();
  353.     gtk_css_provider_load_from_data (provider, css, css_len, NULL);
  354.     gtk_style_context_add_provider (context, (GtkStyleProvider *) provider,
  355.                                     GTK_STYLE_PROVIDER_PRIORITY_THEME);
  356.    
  357.     g_snprintf (buffer, sizeof (buffer), "%d", cur_day);
  358.    
  359.     layout = gtk_widget_create_pango_layout (widget, buffer);
  360.     pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER);
  361.     pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
  362.  
  363.     x_loc = day_rect.x + (day_rect.width - logical_rect.width) / 2;
  364.     y_loc = day_rect.y;
  365.  
  366.     gtk_render_layout (context, cr, x_loc, y_loc, layout);
  367.    
  368.     if (gtk_priv->day_month[row][col] == 1
  369.         && (gtk_priv->marked_date[cur_day-1]))
  370.     {
  371.         gtk_render_layout (context, cr, x_loc - 1, y_loc, layout);
  372.     }
  373.    
  374.     if (gtk_widget_has_visible_focus (widget) &&
  375.         gtk_priv->focus_row == row && gtk_priv->focus_col == col)
  376.     gtk_render_focus (context, cr,
  377.                       day_rect.x, day_rect.y,
  378.                       day_rect.width, day_rect.height);
  379.    
  380.     gtk_style_context_restore (context);
  381.     g_object_unref (layout);
  382.     cairo_restore (cr);
  383.    
  384.     return FALSE;
  385. }
  386.  
  387.  
  388. GtkWidget *
  389. jjk_calendar_new (void)
  390. {
  391.     return g_object_new (JJK_TYPE_CALENDAR, NULL);
  392. }
  393.  
  394. void
  395. jjk_calendar_set_first_day (JjkCalendar *calendar, gint day)
  396. {
  397.     if (day < 0 || day > 6 || day == calendar->gtk_priv->week_start)
  398.         return;
  399.    
  400.     calendar->gtk_priv->week_start = day;
  401.     /* this will force a refresh of the calendar, making sure internally the
  402.      * calendar_compute_days is called, since we changed things */
  403.     gtk_calendar_select_month (GTK_CALENDAR(calendar),
  404.                                calendar->gtk_priv->month,
  405.                                calendar->gtk_priv->year);
  406. }
  407.  
  408.  
  409. int
  410. main (int argc, char **argv)
  411. {
  412.     gtk_init (&argc, &argv);
  413.  
  414.     GtkWidget *window;
  415.     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  416.     gtk_window_set_title (GTK_WINDOW (window), "some title");
  417.     gtk_container_set_border_width (GTK_CONTAINER (window), 1);
  418.     gtk_window_set_has_resize_grip (GTK_WINDOW(window), FALSE);
  419.    
  420.     GtkWidget *cal;
  421.     cal = jjk_calendar_new ();
  422.     jjk_calendar_set_first_day (JJK_CALENDAR (cal), 2);
  423.     gtk_widget_show (cal);
  424.     gtk_container_add (GTK_CONTAINER (window), cal);
  425.  
  426.     g_signal_connect (window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
  427.     gtk_widget_show (window);
  428.     gtk_main ();
  429.     return 0;
  430. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement