Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
button.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2010-2012 Henrik Andersson.
4 Copyright (C) 2010-2011 johannes hanika.
5 Copyright (C) 2011 Antony Dovgal.
6 Copyright (C) 2011 Jérémy Rosen.
7 Copyright (C) 2011 Robert Bieber.
8 Copyright (C) 2011, 2014, 2016, 2018 Tobias Ellinghaus.
9 Copyright (C) 2012 Richard Wonka.
10 Copyright (C) 2013-2016 Roman Lebedev.
11 Copyright (C) 2017 Ulrich Pegelow.
12 Copyright (C) 2018, 2020-2021 Pascal Obry.
13 Copyright (C) 2019, 2025 Aurélien PIERRE.
14 Copyright (C) 2020 Marco.
15 Copyright (C) 2020 Mark-64.
16 Copyright (C) 2020 U-DESKTOP-HQME86J\marco.
17 Copyright (C) 2021 Hubert Kowalski.
18 Copyright (C) 2022 Aldric Renaudin.
19 Copyright (C) 2022 Martin Bařinka.
20 Copyright (C) 2022 Nicolas Auffray.
21
22 darktable is free software: you can redistribute it and/or modify
23 it under the terms of the GNU General Public License as published by
24 the Free Software Foundation, either version 3 of the License, or
25 (at your option) any later version.
26
27 darktable is distributed in the hope that it will be useful,
28 but WITHOUT ANY WARRANTY; without even the implied warranty of
29 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 GNU General Public License for more details.
31
32 You should have received a copy of the GNU General Public License
33 along with darktable. If not, see <http://www.gnu.org/licenses/>.
34*/
35#include "button.h"
36#include "system/macros.h" // IS_NULL_PTR -- a pure macro header, no state
37#include <math.h>
39#include <string.h>
40
42static void _button_init(GtkDarktableButton *button);
43static gboolean _button_draw(GtkWidget *widget, cairo_t *cr);
44
46{
47 GtkWidgetClass *widget_class = (GtkWidgetClass *)klass;
48
49 widget_class->draw = _button_draw;
50}
51
52static void _button_init(GtkDarktableButton *button)
53{
54}
55
56static gboolean _button_draw(GtkWidget *widget, cairo_t *cr)
57{
58 g_return_val_if_fail(!IS_NULL_PTR(widget), FALSE);
59 g_return_val_if_fail(DTGTK_IS_BUTTON(widget), FALSE);
60
61 GtkStateFlags state = gtk_widget_get_state_flags(widget);
62
63 GdkRGBA fg_color;
64 GtkStyleContext *context = gtk_widget_get_style_context(widget);
65 gtk_style_context_get_color(context, state, &fg_color);
66
67 /* update paint flags depending of states */
68 int flags = DTGTK_BUTTON(widget)->icon_flags;
69
70 /* prelight */
71 if(state & GTK_STATE_FLAG_PRELIGHT)
73 else
74 flags &= ~CPF_PRELIGHT;
75
76 /* begin cairo drawing */
77 /* get button total allocation */
78 GtkAllocation allocation;
79 gtk_widget_get_allocation(widget, &allocation);
80 const int width = allocation.width;
81 const int height = allocation.height;
82
83 /* get the css geometry properties of the button */
84 GtkBorder margin, border, padding;
85 gtk_style_context_get_margin(context, state, &margin);
86 gtk_style_context_get_border(context, state, &border);
87 gtk_style_context_get_padding(context, state, &padding);
88
89 /* for button frame and background, we remove css margin from allocation */
90 int startx = margin.left;
91 int starty = margin.top;
92 int cwidth = width - margin.left - margin.right;
93 int cheight = height - margin.top - margin.bottom;
94
95 /* draw standard button background and borders */
96 gtk_render_background(context, cr, startx, starty, cwidth, cheight);
97 gtk_render_frame(context, cr, startx, starty, cwidth, cheight);
98 gdk_cairo_set_source_rgba(cr, &fg_color);
99
100 /* draw icon */
101 if(DTGTK_BUTTON(widget)->icon)
102 {
103 /* calculate the button content allocation */
104 startx += border.left + padding.left;
105 starty += border.top + padding.top;
106 cwidth -= border.left + border.right + padding.left + padding.right;
107 cheight -= border.top + border.bottom + padding.top + padding.bottom;
108
109 /* The icon margin is read from our drawing-area child only while GTK still owns it.
110 gtk_button_set_label() can replace the child with a label, which destroys the
111 canvas and leaves our stored pointer stale. In that case, we keep drawing the
112 icon with no extra margin instead of dereferencing an invalid child pointer. */
113 GtkBorder cmargin = { 0 };
114 GtkWidget *canvas = gtk_bin_get_child(GTK_BIN(widget));
115 if(!IS_NULL_PTR(canvas) && canvas == DTGTK_BUTTON(widget)->canvas)
116 {
117 GtkStyleContext *ccontext = gtk_widget_get_style_context(canvas);
118 gtk_style_context_get_margin(ccontext, state, &cmargin);
119 }
120
121 startx += round(cmargin.left * cwidth / 100.0f);
122 starty += round(cmargin.top * cheight / 100.0f);
123 cwidth = round((float)cwidth * (1.0 - (cmargin.left + cmargin.right) / 100.0f));
124 cheight = round((float)cheight * (1.0 - (cmargin.top + cmargin.bottom) / 100.0f));
125
126 void *icon_data = DTGTK_BUTTON(widget)->icon_data;
127 if(cwidth > 0 && cheight > 0)
128 DTGTK_BUTTON(widget)->icon(cr, startx, starty, cwidth, cheight, flags, icon_data);
129 }
130
131 return FALSE;
132}
133
134// Public functions
135GtkWidget *dtgtk_button_new(DTGTKCairoPaintIconFunc paint, gint paintflags, void *paintdata)
136{
137 GtkDarktableButton *button;
138 button = g_object_new(dtgtk_button_get_type(), NULL);
139 button->icon = paint;
140 button->icon_flags = paintflags;
141 button->icon_data = paintdata;
142 button->canvas = gtk_drawing_area_new();
143 gtk_container_add(GTK_CONTAINER(button), button->canvas);
144 dt_gui_add_class(GTK_WIDGET(button), "dt_module_btn");
145 gtk_widget_set_valign(GTK_WIDGET(button), GTK_ALIGN_CENTER);
146 gtk_widget_set_halign(GTK_WIDGET(button), GTK_ALIGN_CENTER);
147 gtk_widget_set_vexpand(GTK_WIDGET(button), FALSE);
148 gtk_widget_set_hexpand(GTK_WIDGET(button), FALSE);
149 return (GtkWidget *)button;
150}
151
153{
154 static GType dtgtk_button_type = 0;
155 if(!dtgtk_button_type)
156 {
157 static const GTypeInfo dtgtk_button_info = {
158 sizeof(GtkDarktableButtonClass), (GBaseInitFunc)NULL, (GBaseFinalizeFunc)NULL,
159 (GClassInitFunc)_button_class_init, NULL, /* class_finalize */
160 NULL, /* class_data */
161 sizeof(GtkDarktableButton), 0, /* n_preallocs */
162 (GInstanceInitFunc)_button_init,
163 };
164 dtgtk_button_type = g_type_register_static(GTK_TYPE_BUTTON, "GtkDarktableButton", &dtgtk_button_info, 0);
165 }
166 return dtgtk_button_type;
167}
168
169void dtgtk_button_set_paint(GtkDarktableButton *button, DTGTKCairoPaintIconFunc paint, gint paintflags, void *paintdata)
170{
171 g_return_if_fail(!IS_NULL_PTR(button));
172 button->icon = paint;
173 button->icon_flags = paintflags;
174 button->icon_data = paintdata;
175}
176
177void dtgtk_button_set_active(GtkDarktableButton *button, gboolean active)
178{
179 g_return_if_fail(!IS_NULL_PTR(button));
180 if(active)
181 button->icon_flags |= CPF_ACTIVE;
182 else
183 button->icon_flags &= ~CPF_ACTIVE;
184}
185
187{
188 g_return_val_if_fail(!IS_NULL_PTR(button), FALSE);
189 return button->icon_flags & CPF_ACTIVE;
190}
191
192// clang-format off
193// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
194// vim: shiftwidth=2 expandtab tabstop=2 cindent
195// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
196// clang-format on
#define FALSE
Definition ashift_lsd.c:158
static void _button_class_init(GtkDarktableButtonClass *klass)
Definition button.c:45
static void _button_init(GtkDarktableButton *button)
Definition button.c:52
void dtgtk_button_set_paint(GtkDarktableButton *button, DTGTKCairoPaintIconFunc paint, gint paintflags, void *paintdata)
Definition button.c:169
void dtgtk_button_set_active(GtkDarktableButton *button, gboolean active)
Definition button.c:177
static gboolean _button_draw(GtkWidget *widget, cairo_t *cr)
Definition button.c:56
GtkWidget * dtgtk_button_new(DTGTKCairoPaintIconFunc paint, gint paintflags, void *paintdata)
Definition button.c:135
gboolean dtgtk_button_get_active(GtkDarktableButton *button)
Definition button.c:186
GType dtgtk_button_get_type()
Definition button.c:152
#define DTGTK_IS_BUTTON(obj)
Definition button.h:43
struct _GtkDarktableButtonClass GtkDarktableButtonClass
#define DTGTK_BUTTON(obj)
Definition button.h:40
struct _GtkDarktableButton GtkDarktableButton
struct _GtkWidget GtkWidget
GtkWidget, opaque, spelled exactly as GTK spells it.
Definition colorspaces.h:98
#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 macros.h:96
uint32_t width
Definition mipmap_cache.c:0
uint32_t height
Definition mipmap_cache.c:1
dt_mipmap_buffer_dsc_flags flags
Definition mipmap_cache.c:4
const float uint32_t state[4]
DTGTKCairoPaintIconFunc icon
Definition button.h:54
GtkWidget * canvas
Definition button.h:58
void dt_gui_add_class(GtkWidget *widget, const gchar *class_name)
@ CPF_PRELIGHT
@ CPF_ACTIVE
void(* DTGTKCairoPaintIconFunc)(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)