Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
thumbnail_btn.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2020, 2022 Aldric Renaudin.
4 Copyright (C) 2021 Dan Torop.
5 Copyright (C) 2021 Heiko Bauke.
6 Copyright (C) 2021 Hubert Kowalski.
7 Copyright (C) 2022, 2025 Aurélien PIERRE.
8 Copyright (C) 2022 Diederik Ter Rahe.
9 Copyright (C) 2022 Martin Bařinka.
10 Copyright (C) 2022 Nicolas Auffray.
11
12 darktable is free software: you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation, either version 3 of the License, or
15 (at your option) any later version.
16
17 darktable is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with darktable. If not, see <http://www.gnu.org/licenses/>.
24*/
25#include "thumbnail_btn.h"
26#include "gui/gtk.h"
27#include <string.h>
28
31static gboolean _thumbnail_btn_draw(GtkWidget *widget, cairo_t *cr);
32static gboolean _thumbnail_btn_enter_leave_notify_callback(GtkWidget *widget, GdkEventCrossing *event);
33
35{
36 GtkWidgetClass *widget_class = (GtkWidgetClass *)klass;
37
38 widget_class->draw = _thumbnail_btn_draw;
39 widget_class->enter_notify_event = _thumbnail_btn_enter_leave_notify_callback;
40 widget_class->leave_notify_event = _thumbnail_btn_enter_leave_notify_callback;
41}
42
44{
45}
46
47static gboolean _thumbnail_btn_draw(GtkWidget *widget, cairo_t *cr)
48{
49 g_return_val_if_fail(DTGTK_IS_THUMBNAIL_BTN(widget), FALSE);
50
51 if(gtk_widget_get_allocated_height(widget) < 2 || gtk_widget_get_allocated_width(widget) < 2) return TRUE;
52
53 GtkStateFlags state = gtk_widget_get_state_flags(widget);
54
55 GdkRGBA *fg_color, *bg_color;
56 GtkStyleContext *context = gtk_widget_get_style_context(widget);
57 gtk_style_context_get(context, state, GTK_STYLE_PROPERTY_COLOR, &fg_color, GTK_STYLE_PROPERTY_BACKGROUND_COLOR,
58 &bg_color, NULL);
59
60 GtkBorder margin;
61 gtk_style_context_get_margin(context, state, &margin);
62 gtk_widget_set_margin_bottom(widget, margin.bottom);
63 gtk_widget_set_margin_top(widget, margin.top);
64 gtk_widget_set_margin_start(widget, margin.left);
65 gtk_widget_set_margin_end(widget, margin.right);
66
67 if(fg_color->alpha == 0 && bg_color->alpha == 0)
68 {
69 DTGTK_THUMBNAIL_BTN(widget)->hidden = TRUE;
70 gdk_rgba_free(fg_color);
71 gdk_rgba_free(bg_color);
72 return TRUE;
73 }
74 DTGTK_THUMBNAIL_BTN(widget)->hidden = FALSE;
75
76 cairo_save(cr);
77 gdk_cairo_set_source_rgba(cr, fg_color);
78
79 /* draw icon */
80 if(DTGTK_THUMBNAIL_BTN(widget)->icon)
81 {
82 GtkAllocation allocation;
83 gtk_widget_get_allocation(widget, &allocation);
84
85 int flags = DTGTK_THUMBNAIL_BTN(widget)->icon_flags;
86 if(state & GTK_STATE_FLAG_PRELIGHT)
88 else
89 flags &= ~CPF_PRELIGHT;
90
91 if(state & GTK_STATE_FLAG_ACTIVE)
93 else
94 flags &= ~CPF_ACTIVE;
95
96 GtkBorder padding;
97 gtk_style_context_get_padding(context, state, &padding);
98 // padding is a percent of the full size
99 const float icon_x = padding.left;
100 const float icon_y = padding.top;
101 const float icon_w = allocation.width - (padding.left + padding.right);
102 const float icon_h = allocation.height - (padding.top + padding.bottom);
103 DTGTK_THUMBNAIL_BTN(widget)->icon(
104 cr, icon_x, icon_y, icon_w, icon_h, flags,
105 DTGTK_THUMBNAIL_BTN(widget)->icon_data ? DTGTK_THUMBNAIL_BTN(widget)->icon_data : bg_color);
106 }
107 // and eventually the image border
108 cairo_restore(cr);
109 gtk_render_frame(context, cr, 0, 0, gtk_widget_get_allocated_width(widget),
110 gtk_widget_get_allocated_height(widget));
111
112 gdk_rgba_free(fg_color);
113 gdk_rgba_free(bg_color);
114 return TRUE;
115}
116
117static gboolean _thumbnail_btn_enter_leave_notify_callback(GtkWidget *widget, GdkEventCrossing *event)
118{
119 g_return_val_if_fail(!IS_NULL_PTR(widget), FALSE);
120
121 if(event->type == GDK_ENTER_NOTIFY)
122 gtk_widget_set_state_flags(widget, GTK_STATE_FLAG_PRELIGHT, FALSE);
123 else
124 gtk_widget_unset_state_flags(widget, GTK_STATE_FLAG_PRELIGHT);
125
126 gtk_widget_queue_draw(widget);
127 return FALSE;
128}
129
130// Public functions
131GtkWidget *dtgtk_thumbnail_btn_new(DTGTKCairoPaintIconFunc paint, gint paintflags, void *paintdata)
132{
134 button = g_object_new(dtgtk_thumbnail_btn_get_type(), NULL);
135 dt_gui_add_class(GTK_WIDGET(button), "dt_thumb_btn");
136 button->icon = paint;
137 button->icon_flags = paintflags;
138 button->icon_data = paintdata;
139 gtk_widget_set_events(GTK_WIDGET(button), GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK
140 | GDK_LEAVE_NOTIFY_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
147{
148 static GType dtgtk_thumbnail_btn_type = 0;
149 if(!dtgtk_thumbnail_btn_type)
150 {
151 static const GTypeInfo dtgtk_thumbnail_btn_info = {
153 (GBaseInitFunc)NULL,
154 (GBaseFinalizeFunc)NULL,
155 (GClassInitFunc)_thumbnail_btn_class_init,
156 NULL, /* class_finalize */
157 NULL, /* class_data */
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
169{
170 g_return_val_if_fail(DTGTK_IS_THUMBNAIL_BTN(widget), TRUE);
171
172 return DTGTK_THUMBNAIL_BTN(widget)->hidden;
173}
174// clang-format off
175// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
176// vim: shiftwidth=2 expandtab tabstop=2 cindent
177// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
178// clang-format on
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
Definition darktable.h:281
@ CPF_PRELIGHT
Definition dtgtk/paint.h:68
@ CPF_ACTIVE
Definition dtgtk/paint.h:67
void(* DTGTKCairoPaintIconFunc)(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
Definition dtgtk/paint.h:75
void dt_gui_add_class(GtkWidget *widget, const gchar *class_name)
Definition gtk.c:133
dt_mipmap_buffer_dsc_flags flags
Definition mipmap_cache.c:4
struct _GtkWidget GtkWidget
Definition splash.h:29
const float uint32_t state[4]
DTGTKCairoPaintIconFunc icon
static gboolean _thumbnail_btn_enter_leave_notify_callback(GtkWidget *widget, GdkEventCrossing *event)
static void _thumbnail_btn_init(GtkDarktableThumbnailBtn *button)
static void _thumbnail_btn_class_init(GtkDarktableThumbnailBtnClass *klass)
GtkWidget * dtgtk_thumbnail_btn_new(DTGTKCairoPaintIconFunc paint, gint paintflags, void *paintdata)
GType dtgtk_thumbnail_btn_get_type()
static gboolean _thumbnail_btn_draw(GtkWidget *widget, cairo_t *cr)
gboolean dtgtk_thumbnail_btn_is_hidden(GtkWidget *widget)
struct _GtkDarktableThumbnailBtnClass GtkDarktableThumbnailBtnClass
struct _GtkDarktableThumbnailBtn GtkDarktableThumbnailBtn
#define DTGTK_IS_THUMBNAIL_BTN(obj)
#define DTGTK_THUMBNAIL_BTN(obj)