Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
help.c
Go to the documentation of this file.
1/*
2 This file is part of the Ansel project.
3 Copyright (C) 2023, 2025-2026 Aurélien PIERRE.
4 Copyright (C) 2023 Luca Zulberti.
5
6 Ansel is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 Ansel is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with Ansel. If not, see <http://www.gnu.org/licenses/>.
18*/
19#include "common/darktable.h"
20#include "gui/actions/menu.h"
22#include "common/l10n.h"
23#include "control/control.h"
24
25
26static gboolean show_about_dialog(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
27{
28 GtkWidget *dialog = gtk_about_dialog_new();
29 gtk_widget_set_name (dialog, "about-dialog");
30#ifdef GDK_WINDOWING_QUARTZ
32#endif
33 gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(dialog), PACKAGE_NAME);
34 gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(dialog), darktable_package_version);
35 char *copyright = g_strdup_printf(_("Copyright \302\251 darktable authors 2009-2022\nCopyright \302\251 Aur\303\251lien Pierre 2022-%s"), darktable_last_commit_year);
36 gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(dialog), copyright);
37 dt_free(copyright);
38 gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(dialog),
39 _("Organize and develop images from digital cameras"));
40 gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(dialog), "https://ansel.photos");
41 gtk_about_dialog_set_website_label(GTK_ABOUT_DIALOG(dialog), _("Website"));
42 char *icon = g_strdup("ansel");
43 gtk_about_dialog_set_logo_icon_name(GTK_ABOUT_DIALOG(dialog), icon);
44 dt_free(icon);
45
46 const char *str = _("all those of you that made previous releases possible");
47
48#include "tools/darktable_authors.h"
49
50 const char *final[] = {str, NULL };
51 gtk_about_dialog_add_credit_section (GTK_ABOUT_DIALOG(dialog), _("and..."), final);
52 gtk_about_dialog_set_translator_credits(GTK_ABOUT_DIALOG(dialog), _("translator-credits"));
53
54 gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(dt_ui_main_window(darktable.gui->ui)));
55 gtk_dialog_run(GTK_DIALOG(dialog));
56 gtk_widget_destroy(dialog);
57
58 return TRUE;
59}
60
61static gboolean open_doc_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
62{
63 // TODO: use translated URL when doc gets translated
64 gtk_show_uri_on_window(GTK_WINDOW(dt_ui_main_window(darktable.gui->ui)), "https://ansel.photos/en/doc", GDK_CURRENT_TIME, NULL);
65 return TRUE;
66}
67
68static gboolean open_chat_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
69{
70 gtk_show_uri_on_window(GTK_WINDOW(dt_ui_main_window(darktable.gui->ui)),
71 "https://app.element.io/#/room/#ansel:matrix.org", GDK_CURRENT_TIME, NULL);
72 return TRUE;
73}
74
75static gboolean open_search_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
76{
77 gtk_show_uri_on_window(GTK_WINDOW(dt_ui_main_window(darktable.gui->ui)),
78 "https://chantal.aurelienpierre.com", GDK_CURRENT_TIME, NULL);
79 return TRUE;
80}
81
82static gboolean open_forum_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
83{
84 gtk_show_uri_on_window(GTK_WINDOW(dt_ui_main_window(darktable.gui->ui)),
85 "https://community.ansel.photos", GDK_CURRENT_TIME, NULL);
86 return TRUE;
87}
88
89// TODO: this doesn't work for all widgets. the reason being that the GtkEventBox we put libs/iops into catches events.
90static char *get_help_url(GtkWidget *widget)
91{
92 while(widget)
93 {
94 // if the widget doesn't have a help url set go up the widget hierarchy to find a parent that has an url
95 gchar *help_url = g_object_get_data(G_OBJECT(widget), "dt-help-url");
96 if(help_url) return help_url;
97 widget = gtk_widget_get_parent(widget);
98 }
99
100 return NULL;
101}
102
104{
106 dt_control_change_cursor(GDK_LEFT_PTR);
107 gdk_event_handler_set((GdkEventFunc)gtk_main_do_event, NULL, NULL);
108}
109
110static void _main_do_event_help(GdkEvent *event, gpointer data)
111{
112 gboolean handled = FALSE;
113
114 switch(event->type)
115 {
116 case GDK_BUTTON_PRESS:
117 {
118 if(event->button.button == GDK_BUTTON_SECONDARY)
119 {
120 // On right-click : abort and reset
122 handled = TRUE;
123 break;
124 }
125
126 GtkWidget *event_widget = gtk_get_event_widget(event);
127 if(event_widget)
128 {
129 // Note : help url contains the fully-formed URL adapted to current language
130 gchar *help_url = get_help_url(event_widget);
131 if(help_url && *help_url)
132 {
134
136 dt_print(DT_DEBUG_CONTROL, "[context help] opening '%s'\n", help_url);
137
138 // ask the user if the website may be accessed
139 GtkWidget *dialog = gtk_message_dialog_new
140 (GTK_WINDOW(win), GTK_DIALOG_DESTROY_WITH_PARENT,
141 GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
142 _("do you want to access ansel.photos ?"));
143#ifdef GDK_WINDOWING_QUARTZ
145#endif
146
147 gtk_window_set_title(GTK_WINDOW(dialog), _("access the online usermanual?"));
148 const gint res = gtk_dialog_run(GTK_DIALOG(dialog));
149 const gboolean open = (res == GTK_RESPONSE_YES) || !(res == GTK_RESPONSE_NO);
150 gtk_widget_destroy(dialog);
151
152 if(open)
153 {
154 GError *error = NULL;
155 const gboolean uri_success = gtk_show_uri_on_window(GTK_WINDOW(win), help_url, gtk_get_current_event_time(), &error);
156
157 if(uri_success)
158 {
159 dt_control_log(_("help url opened in web browser"));
160 }
161 else
162 {
163 dt_control_log(_("error while opening help url in web browser"));
164 if (!IS_NULL_PTR(error)) // uri_success being FALSE should guarantee that
165 {
166 fprintf (stderr, "unable to read file: %s\n", error->message);
167 g_error_free(error);
168 }
169 }
170 }
171 }
172 else
173 {
174 dt_control_log(_("there is no help available for this element"));
175 }
176 }
177 handled = TRUE;
178 break;
179 }
180
181 case GDK_ENTER_NOTIFY:
182 case GDK_LEAVE_NOTIFY:
183 {
184 GtkWidget *event_widget = gtk_get_event_widget(event);
185 if(event_widget)
186 {
187 gchar *help_url = get_help_url(event_widget);
188 if(help_url)
189 {
190 // TODO: find a better way to tell the user that the hovered widget has a help link
191 dt_cursor_t cursor = event->type == GDK_ENTER_NOTIFY ? GDK_QUESTION_ARROW : GDK_X_CURSOR;
195 }
196 }
197 break;
198 }
199 default:
200 break;
201 }
202
203 if(!handled) gtk_main_do_event(event);
204}
205
206static gboolean contextual_help_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
207{
208 dt_control_change_cursor(GDK_X_CURSOR);
210 gdk_event_handler_set(_main_do_event_help, NULL, NULL);
211 return TRUE;
212}
213
214static gboolean search_accels_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
215{
218 return TRUE;
219}
220
221static gboolean supervisor_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
222{
224 return TRUE;
225}
226
227void append_help(GtkWidget **menus, GList **lists, const dt_menus_t index)
228{
229 add_sub_menu_entry(menus, lists, _("Online documentation"), index, NULL, open_doc_callback, NULL, NULL, NULL, 0, 0);
230 add_sub_menu_entry(menus, lists, _("Ask a question"), index, NULL, open_search_callback, NULL, NULL, NULL, 0, 0);
231 add_sub_menu_entry(menus, lists, _("Join the support chat"), index, NULL, open_chat_callback, NULL, NULL, NULL, 0, 0);
232 add_sub_menu_entry(menus, lists, _("Join the support forum"), index, NULL, open_forum_callback, NULL, NULL, NULL, 0, 0);
233 add_menu_separator(menus[index]);
234 add_sub_menu_entry(menus, lists, _("Open contextual help"), index, NULL, contextual_help_callback, NULL, NULL, NULL, 0, 0);
235 add_sub_menu_entry(menus, lists, _("Search actions..."), index, NULL, search_accels_callback, NULL, NULL,
236 NULL, GDK_KEY_p, GDK_CONTROL_MASK);
237 add_menu_separator(menus[index]);
238 add_sub_menu_entry(menus, lists, _("Event supervisor..."), index, NULL, supervisor_callback, NULL, NULL, NULL, 0, 0);
239 add_menu_separator(menus[index]);
240 add_sub_menu_entry(menus, lists, _("About"), index, NULL, show_about_dialog, NULL, NULL, NULL, 0, 0);
241}
void dt_accels_search(dt_accels_t *accels, GtkWindow *main_window, GtkWidget *anchor)
static void error(char *msg)
Definition ashift_lsd.c:202
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
#define PACKAGE_NAME
const char darktable_package_version[]
const char darktable_last_commit_year[]
void dt_control_forbid_change_cursor()
Definition control.c:224
void dt_control_log(const char *msg,...)
Definition control.c:777
void dt_control_allow_change_cursor()
Definition control.c:229
#define dt_control_change_cursor(cursor)
Definition control.h:116
GdkCursorType dt_cursor_t
Definition control.h:70
darktable_t darktable
Definition darktable.c:183
void dt_print(dt_debug_thread_t thread, const char *msg,...)
Definition darktable.c:1600
@ DT_DEBUG_CONTROL
Definition darktable.h:738
#define dt_free(ptr)
Definition darktable.h:478
#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:293
GtkWidget * dt_ui_main_window(dt_ui_t *ui)
get the main window widget
static gboolean show_about_dialog(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
Definition help.c:26
static gboolean supervisor_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
Definition help.c:221
static void _restore_default_cursor()
Definition help.c:103
void append_help(GtkWidget **menus, GList **lists, const dt_menus_t index)
Definition help.c:227
static void _main_do_event_help(GdkEvent *event, gpointer data)
Definition help.c:110
static gboolean open_chat_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
Definition help.c:68
static gboolean search_accels_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
Definition help.c:214
static gboolean open_search_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
Definition help.c:75
static gboolean open_doc_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
Definition help.c:61
static char * get_help_url(GtkWidget *widget)
Definition help.c:90
static gboolean contextual_help_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
Definition help.c:206
static gboolean open_forum_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
Definition help.c:82
void add_sub_menu_entry(GtkWidget **menus, GList **lists, const gchar *label, const dt_menus_t index, void *data, gboolean(*action_callback)(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data), gboolean(*checked_callback)(GtkWidget *widget), gboolean(*active_callback)(GtkWidget *widget), gboolean(*sensitive_callback)(GtkWidget *widget), guint key_val, GdkModifierType mods)
Definition menu.c:541
void add_menu_separator(GtkWidget *menu)
Definition menu.c:597
dt_menus_t
Definition menu.h:42
void dt_osx_disallow_fullscreen(GtkWidget *widget)
Definition osx.mm:104
int main()
Definition prova.c:47
struct _GtkWidget GtkWidget
Definition splash.h:29
struct dt_gui_gtk_t * gui
Definition darktable.h:803
dt_accels_t * accels
Definition gtk.h:199
dt_ui_t * ui
Definition gtk.h:165
void dt_gui_supervisor_window_show(void)