1 /*
2     This file is part of darktable,
3     Copyright (C) 2019-2020 darktable developers.
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 
19 #include "common/darktable.h"
20 #include "common/debug.h"
21 #include "control/signal.h"
22 #include "bauhaus/bauhaus.h"
23 #include "gui/gtk.h"
24 #include "libs/lib.h"
25 #include <gtk/gtk.h>
26 #include <stdlib.h>
27 
28 DT_MODULE(1)
29 
30 typedef struct dt_lib_ioporder_t
31 {
32   int current_mode;
33   GList *last_custom_iop_order;
34   GtkWidget *widget;
35 } dt_lib_ioporder_t;
36 
name(dt_lib_module_t * self)37 const char *name(dt_lib_module_t *self)
38 {
39   return _("module order");
40 }
41 
views(dt_lib_module_t * self)42 const char **views(dt_lib_module_t *self)
43 {
44   static const char *v[] = {"darkroom", NULL};
45   return v;
46 }
47 
container(dt_lib_module_t * self)48 uint32_t container(dt_lib_module_t *self)
49 {
50   return DT_UI_CONTAINER_PANEL_RIGHT_BOTTOM;
51 }
52 
position()53 int position()
54 {
55   return 880;
56 }
57 
update(dt_lib_module_t * self)58 void update(dt_lib_module_t *self)
59 {
60   dt_lib_ioporder_t *d = (dt_lib_ioporder_t *)self->data;
61 
62   const dt_iop_order_t kind = dt_ioppr_get_iop_order_list_kind(darktable.develop->iop_order_list);
63 
64   if(kind == DT_IOP_ORDER_CUSTOM)
65   {
66     gchar *iop_order_list = dt_ioppr_serialize_text_iop_order_list(darktable.develop->iop_order_list);
67     gboolean found = FALSE;
68     int index = 0;
69 
70     sqlite3_stmt *stmt;
71 
72     DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db),
73                                 "SELECT op_params, name"
74                                 " FROM data.presets"
75                                 " WHERE operation='ioporder'"
76                                 " ORDER BY writeprotect DESC", -1, &stmt, NULL);
77 
78     while(sqlite3_step(stmt) == SQLITE_ROW)
79     {
80       const char *params = (char *)sqlite3_column_blob(stmt, 0);
81       const int32_t params_len = sqlite3_column_bytes(stmt, 0);
82       const char *name = (const char *)sqlite3_column_text(stmt, 1);
83       GList *iop_list = dt_ioppr_deserialize_iop_order_list(params, params_len);
84       gchar *iop_list_text = dt_ioppr_serialize_text_iop_order_list(iop_list);
85       g_list_free(iop_list);
86       index++;
87 
88       if(!strcmp(iop_order_list, iop_list_text))
89       {
90         gtk_label_set_text(GTK_LABEL(d->widget), name);
91         d->current_mode = index;
92         found = TRUE;
93         g_free(iop_list_text);
94         break;
95     }
96 
97       g_free(iop_list_text);
98     }
99 
100     sqlite3_finalize(stmt);
101 
102     g_free(iop_order_list);
103 
104     if(!found)
105     {
106       d->current_mode = DT_IOP_ORDER_CUSTOM;
107       gtk_label_set_text(GTK_LABEL(d->widget), _(dt_iop_order_string(DT_IOP_ORDER_CUSTOM)));
108     }
109   }
110   else if(kind == DT_IOP_ORDER_LEGACY)
111   {
112     d->current_mode = kind;
113     gtk_label_set_text(GTK_LABEL(d->widget), _(dt_iop_order_string(DT_IOP_ORDER_LEGACY)));
114   }
115   else if(kind == DT_IOP_ORDER_V30)
116   {
117     d->current_mode = kind;
118     gtk_label_set_text(GTK_LABEL(d->widget), _(dt_iop_order_string(DT_IOP_ORDER_V30)));
119   }
120 }
121 
_invalidate_pipe(dt_develop_t * dev)122 static void _invalidate_pipe(dt_develop_t *dev)
123 {
124   // we rebuild the pipe
125   dev->pipe->changed |= DT_DEV_PIPE_REMOVE;
126   dev->preview_pipe->changed |= DT_DEV_PIPE_REMOVE;
127   dev->preview2_pipe->changed |= DT_DEV_PIPE_REMOVE;
128   dev->pipe->cache_obsolete = 1;
129   dev->preview_pipe->cache_obsolete = 1;
130   dev->preview2_pipe->cache_obsolete = 1;
131 
132   // invalidate buffers and force redraw of darkroom
133   dt_dev_invalidate_all(dev);
134 }
135 
_image_loaded_callback(gpointer instance,gpointer user_data)136 static void _image_loaded_callback(gpointer instance, gpointer user_data)
137 {
138   dt_lib_module_t *self = (dt_lib_module_t *)user_data;
139   update(self);
140 }
141 
gui_init(dt_lib_module_t * self)142 void gui_init(dt_lib_module_t *self)
143 {
144   dt_lib_ioporder_t *d = (dt_lib_ioporder_t *)malloc(sizeof(dt_lib_ioporder_t));
145 
146   self->data = (void *)d;
147   self->widget = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
148 
149   GtkWidget *label = gtk_label_new(_("current order"));
150 
151   d->widget = gtk_label_new("");
152   d->current_mode = -1;
153   d->last_custom_iop_order = NULL;
154 
155   gtk_box_pack_start(GTK_BOX(self->widget), label, TRUE, TRUE, 0);
156   gtk_box_pack_start(GTK_BOX(self->widget), d->widget, TRUE, TRUE, 0);
157 
158   DT_DEBUG_CONTROL_SIGNAL_CONNECT(darktable.signals, DT_SIGNAL_DEVELOP_IMAGE_CHANGED,
159                             G_CALLBACK(_image_loaded_callback), self);
160   DT_DEBUG_CONTROL_SIGNAL_CONNECT(darktable.signals, DT_SIGNAL_DEVELOP_INITIALIZE,
161                             G_CALLBACK(_image_loaded_callback), self);
162   DT_DEBUG_CONTROL_SIGNAL_CONNECT(darktable.signals, DT_SIGNAL_DEVELOP_HISTORY_CHANGE,
163                             G_CALLBACK(_image_loaded_callback), self);
164 }
165 
gui_cleanup(dt_lib_module_t * self)166 void gui_cleanup(dt_lib_module_t *self)
167 {
168   free(self->data);
169   self->data = NULL;
170 }
171 
gui_reset(dt_lib_module_t * self)172 void gui_reset (dt_lib_module_t *self)
173 {
174   dt_lib_ioporder_t *d = (dt_lib_ioporder_t *)self->data;
175 
176   // the module reset is use to select the v3.0 iop-order
177 
178   GList *iop_order_list = dt_ioppr_get_iop_order_list_version(DT_IOP_ORDER_V30);
179 
180   if(iop_order_list)
181   {
182     const int32_t imgid = darktable.develop->image_storage.id;
183 
184     dt_ioppr_change_iop_order(darktable.develop, imgid, iop_order_list);
185 
186     _invalidate_pipe(darktable.develop);
187 
188     d->current_mode = DT_IOP_ORDER_V30;
189     gtk_label_set_text(GTK_LABEL(d->widget), _("v3.0"));
190     g_list_free_full(iop_order_list, free);
191   }
192 }
193 
init_presets(dt_lib_module_t * self)194 void init_presets(dt_lib_module_t *self)
195 {
196   size_t size = 0;
197   char *params = NULL;
198   GList *list;
199 
200   list = dt_ioppr_get_iop_order_list_version(DT_IOP_ORDER_LEGACY);
201   params = dt_ioppr_serialize_iop_order_list(list, &size);
202   dt_lib_presets_add(_("legacy"), self->plugin_name, self->version(), (const char *)params, (int32_t)size, TRUE);
203   free(params);
204 
205   list = dt_ioppr_get_iop_order_list_version(DT_IOP_ORDER_V30);
206   params = dt_ioppr_serialize_iop_order_list(list, &size);
207   dt_lib_presets_add(_("v3.0 (default)"), self->plugin_name, self->version(), (const char *)params, (int32_t)size,
208                      TRUE);
209   free(params);
210 }
211 
set_params(dt_lib_module_t * self,const void * params,int size)212 int set_params(dt_lib_module_t *self, const void *params, int size)
213 {
214   if(!params) return 1;
215 
216   GList *iop_order_list = dt_ioppr_deserialize_iop_order_list(params, (size_t)size);
217 
218   if(iop_order_list)
219   {
220     const int32_t imgid = darktable.develop->image_storage.id;
221 
222     dt_ioppr_change_iop_order(darktable.develop, imgid, iop_order_list);
223 
224     _invalidate_pipe(darktable.develop);
225 
226     update(self);
227 
228     g_list_free_full(iop_order_list, free);
229     return 0;
230   }
231   else
232   {
233     return 1;
234   }
235 }
236 
get_params(dt_lib_module_t * self,int * size)237 void *get_params(dt_lib_module_t *self, int *size)
238 {
239   size_t p_size = 0;
240   void *params = dt_ioppr_serialize_iop_order_list(darktable.develop->iop_order_list, &p_size);
241   *size = (int)p_size;
242 
243   return params;
244 }
245 
246 // modelines: These editor modelines have been set for all relevant files by tools/update_modelines.sh
247 // vim: shiftwidth=2 expandtab tabstop=2 cindent
248 // kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
249