1 /*
2     This file is part of darktable,
3     copyright (c)2020 Aldric Renaudin.
4 
5     darktable is free software: you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation, either version 3 of the License, or
8     (at your option) any later version.
9 
10     darktable is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14 
15     You should have received a copy of the GNU General Public License
16     along with darktable.  If not, see <http://www.gnu.org/licenses/>.
17 */
18 #include "thumbnail_btn.h"
19 #include "gui/gtk.h"
20 #include <string.h>
21 
22 static void _thumbnail_btn_class_init(GtkDarktableThumbnailBtnClass *klass);
23 static void _thumbnail_btn_init(GtkDarktableThumbnailBtn *button);
24 static gboolean _thumbnail_btn_draw(GtkWidget *widget, cairo_t *cr);
25 static gboolean _thumbnail_btn_enter_notify_callback(GtkWidget *widget, GdkEventCrossing *event);
26 static gboolean _thumbnail_btn_leave_notify_callback(GtkWidget *widget, GdkEventCrossing *event);
27 
_thumbnail_btn_class_init(GtkDarktableThumbnailBtnClass * klass)28 static void _thumbnail_btn_class_init(GtkDarktableThumbnailBtnClass *klass)
29 {
30   GtkWidgetClass *widget_class = (GtkWidgetClass *)klass;
31 
32   widget_class->draw = _thumbnail_btn_draw;
33   widget_class->enter_notify_event = _thumbnail_btn_enter_notify_callback;
34   widget_class->leave_notify_event = _thumbnail_btn_leave_notify_callback;
35 }
36 
_thumbnail_btn_init(GtkDarktableThumbnailBtn * button)37 static void _thumbnail_btn_init(GtkDarktableThumbnailBtn *button)
38 {
39 }
40 
_thumbnail_btn_draw(GtkWidget * widget,cairo_t * cr)41 static gboolean _thumbnail_btn_draw(GtkWidget *widget, cairo_t *cr)
42 {
43   g_return_val_if_fail(DTGTK_IS_THUMBNAIL_BTN(widget), FALSE);
44 
45   if(gtk_widget_get_allocated_height(widget) < 2 || gtk_widget_get_allocated_width(widget) < 2) return TRUE;
46 
47   GtkStateFlags state = gtk_widget_get_state_flags(widget);
48 
49   GdkRGBA *fg_color, *bg_color;
50   GtkStyleContext *context = gtk_widget_get_style_context(widget);
51   gtk_style_context_get(context, state, GTK_STYLE_PROPERTY_COLOR, &fg_color, GTK_STYLE_PROPERTY_BACKGROUND_COLOR,
52                         &bg_color, NULL);
53   if(fg_color->alpha == 0 && bg_color->alpha == 0)
54   {
55     DTGTK_THUMBNAIL_BTN(widget)->hidden = TRUE;
56     gdk_rgba_free(fg_color);
57     gdk_rgba_free(bg_color);
58     return TRUE;
59   }
60   DTGTK_THUMBNAIL_BTN(widget)->hidden = FALSE;
61 
62   cairo_save(cr);
63   gdk_cairo_set_source_rgba(cr, fg_color);
64 
65   /* draw icon */
66   if(DTGTK_THUMBNAIL_BTN(widget)->icon)
67   {
68     GtkAllocation allocation;
69     gtk_widget_get_allocation(widget, &allocation);
70 
71     int flags = DTGTK_THUMBNAIL_BTN(widget)->icon_flags;
72     if(state & GTK_STATE_FLAG_PRELIGHT)
73       flags |= CPF_PRELIGHT;
74     else
75       flags &= ~CPF_PRELIGHT;
76 
77     if(state & GTK_STATE_FLAG_ACTIVE)
78       flags |= CPF_ACTIVE;
79     else
80       flags &= ~CPF_ACTIVE;
81 
82     if(flags & CPF_DO_NOT_USE_BORDER)
83     {
84       DTGTK_THUMBNAIL_BTN(widget)->icon(cr, 0, 0, allocation.width, allocation.height, flags,
85                                         DTGTK_THUMBNAIL_BTN(widget)->icon_data ? DTGTK_THUMBNAIL_BTN(widget)->icon_data : bg_color);
86     }
87     else
88     {
89       DTGTK_THUMBNAIL_BTN(widget)->icon(cr, 0.125 * allocation.width, 0.125 * allocation.height,
90                                         0.75 * allocation.width, 0.75 * allocation.height, flags,
91                                         DTGTK_THUMBNAIL_BTN(widget)->icon_data ? DTGTK_THUMBNAIL_BTN(widget)->icon_data : bg_color);
92     }
93   }
94   // and eventually the image border
95   cairo_restore(cr);
96   gtk_render_frame(context, cr, 0, 0, gtk_widget_get_allocated_width(widget),
97                    gtk_widget_get_allocated_height(widget));
98 
99   gdk_rgba_free(fg_color);
100   gdk_rgba_free(bg_color);
101   return TRUE;
102 }
103 
_thumbnail_btn_enter_notify_callback(GtkWidget * widget,GdkEventCrossing * event)104 static gboolean _thumbnail_btn_enter_notify_callback(GtkWidget *widget, GdkEventCrossing *event)
105 {
106   g_return_val_if_fail(widget != NULL, FALSE);
107 
108   int flags = gtk_widget_get_state_flags(widget);
109   flags |= GTK_STATE_FLAG_PRELIGHT;
110 
111   gtk_widget_set_state_flags(widget, flags, TRUE);
112   gtk_widget_queue_draw(widget);
113   return FALSE;
114 }
_thumbnail_btn_leave_notify_callback(GtkWidget * widget,GdkEventCrossing * event)115 static gboolean _thumbnail_btn_leave_notify_callback(GtkWidget *widget, GdkEventCrossing *event)
116 {
117   g_return_val_if_fail(widget != NULL, FALSE);
118 
119   int flags = gtk_widget_get_state_flags(widget);
120   flags &= ~GTK_STATE_FLAG_PRELIGHT;
121 
122   gtk_widget_set_state_flags(widget, flags, TRUE);
123   gtk_widget_queue_draw(widget);
124   return FALSE;
125 }
126 
127 // Public functions
dtgtk_thumbnail_btn_new(DTGTKCairoPaintIconFunc paint,gint paintflags,void * paintdata)128 GtkWidget *dtgtk_thumbnail_btn_new(DTGTKCairoPaintIconFunc paint, gint paintflags, void *paintdata)
129 {
130   GtkDarktableThumbnailBtn *button;
131   button = g_object_new(dtgtk_thumbnail_btn_get_type(), NULL);
132   GtkStyleContext *context = gtk_widget_get_style_context(GTK_WIDGET(button));
133   gtk_style_context_add_class(context, "dt_thumb_btn");
134   button->icon = paint;
135   button->icon_flags = paintflags;
136   button->icon_data = paintdata;
137   gtk_widget_set_events(GTK_WIDGET(button), GDK_EXPOSURE_MASK
138                                                 | GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK
139                                                 | GDK_BUTTON_RELEASE_MASK | GDK_STRUCTURE_MASK
140                                                 | GDK_ENTER_NOTIFY_MASK | GDK_ALL_EVENTS_MASK);
141   gtk_widget_set_app_paintable(GTK_WIDGET(button), TRUE);
142   gtk_widget_set_name(GTK_WIDGET(button), "thumbnail_btn");
143   return (GtkWidget *)button;
144 }
145 
dtgtk_thumbnail_btn_get_type()146 GType dtgtk_thumbnail_btn_get_type()
147 {
148   static GType dtgtk_thumbnail_btn_type = 0;
149   if(!dtgtk_thumbnail_btn_type)
150   {
151     static const GTypeInfo dtgtk_thumbnail_btn_info = {
152       sizeof(GtkDarktableThumbnailBtnClass),
153       (GBaseInitFunc)NULL,
154       (GBaseFinalizeFunc)NULL,
155       (GClassInitFunc)_thumbnail_btn_class_init,
156       NULL, /* class_finalize */
157       NULL, /* class_data */
158       sizeof(GtkDarktableThumbnailBtn),
159       0, /* n_preallocs */
160       (GInstanceInitFunc)_thumbnail_btn_init,
161     };
162     dtgtk_thumbnail_btn_type
163         = g_type_register_static(GTK_TYPE_DRAWING_AREA, "GtkDarktableThumbnailBtn", &dtgtk_thumbnail_btn_info, 0);
164   }
165   return dtgtk_thumbnail_btn_type;
166 }
167 
dtgtk_thumbnail_btn_is_hidden(GtkWidget * widget)168 gboolean dtgtk_thumbnail_btn_is_hidden(GtkWidget *widget)
169 {
170   g_return_val_if_fail(DTGTK_IS_THUMBNAIL_BTN(widget), TRUE);
171 
172   return DTGTK_THUMBNAIL_BTN(widget)->hidden;
173 }
174 // modelines: These editor modelines have been set for all relevant files by tools/update_modelines.sh
175 // vim: shiftwidth=2 expandtab tabstop=2 cindent
176 // kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
177