~ubuntu-branches/ubuntu/saucy/darktable/saucy

« back to all changes in this revision

Viewing changes to src/views/darkroom.c

  • Committer: Bazaar Package Importer
  • Author(s): David Bremner
  • Date: 2011-04-14 23:42:12 UTC
  • Revision ID: james.westby@ubuntu.com-20110414234212-kuffcz5wiu18v6ra
Tags: upstream-0.8
ImportĀ upstreamĀ versionĀ 0.8

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
    This file is part of darktable,
 
3
    copyright (c) 2009--2010 johannes hanika.
 
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
/** this is the view for the darkroom module.  */
 
19
#include "views/view.h"
 
20
#include "develop/develop.h"
 
21
#include "control/jobs.h"
 
22
#include "control/control.h"
 
23
#include "control/conf.h"
 
24
#include "develop/imageop.h"
 
25
#include "common/image_cache.h"
 
26
#include "common/imageio.h"
 
27
#include "common/debug.h"
 
28
#include "gui/gtk.h"
 
29
#include "gui/metadata.h"
 
30
#include "gui/iop_modulegroups.h"
 
31
 
 
32
#include <stdlib.h>
 
33
#include <string.h>
 
34
#include <math.h>
 
35
#include <glade/glade.h>
 
36
#include <gdk/gdkkeysyms.h>
 
37
 
 
38
DT_MODULE(1)
 
39
 
 
40
const char
 
41
*name(dt_view_t *self)
 
42
{
 
43
  return _("darkroom");
 
44
}
 
45
 
 
46
 
 
47
void
 
48
init(dt_view_t *self)
 
49
{
 
50
  self->data = malloc(sizeof(dt_develop_t));
 
51
  dt_dev_init((dt_develop_t *)self->data, 1);
 
52
 
 
53
}
 
54
 
 
55
 
 
56
void cleanup(dt_view_t *self)
 
57
{
 
58
  dt_develop_t *dev = (dt_develop_t *)self->data;
 
59
  dt_dev_cleanup(dev);
 
60
  free(dev);
 
61
}
 
62
 
 
63
 
 
64
void expose(dt_view_t *self, cairo_t *cri, int32_t width_i, int32_t height_i, int32_t pointerx, int32_t pointery)
 
65
{
 
66
  // if width or height > max pipeline pixels: center the view and clamp.
 
67
  int32_t width  = MIN(width_i,  DT_IMAGE_WINDOW_SIZE);
 
68
  int32_t height = MIN(height_i, DT_IMAGE_WINDOW_SIZE);
 
69
 
 
70
  cairo_set_source_rgb (cri, .2, .2, .2);
 
71
  cairo_rectangle(cri, 0, 0, fmaxf(0, width_i-DT_IMAGE_WINDOW_SIZE) *.5f, height);
 
72
  cairo_fill (cri);
 
73
  cairo_rectangle(cri, fmaxf(0.0, width_i-DT_IMAGE_WINDOW_SIZE) *.5f + width, 0, width_i, height);
 
74
  cairo_fill (cri);
 
75
 
 
76
  if(width_i  > DT_IMAGE_WINDOW_SIZE) cairo_translate(cri, -(DT_IMAGE_WINDOW_SIZE-width_i) *.5f, 0.0f);
 
77
  if(height_i > DT_IMAGE_WINDOW_SIZE) cairo_translate(cri, 0.0f, -(DT_IMAGE_WINDOW_SIZE-height_i)*.5f);
 
78
  cairo_save(cri);
 
79
 
 
80
  dt_develop_t *dev = (dt_develop_t *)self->data;
 
81
 
 
82
  if(dev->gui_synch)
 
83
  {
 
84
    // synch module guis from gtk thread:
 
85
    darktable.gui->reset = 1;
 
86
    GList *modules = dev->iop;
 
87
    while(modules)
 
88
    {
 
89
      dt_iop_module_t *module = (dt_iop_module_t *)(modules->data);
 
90
      dt_iop_gui_update(module);
 
91
      modules = g_list_next(modules);
 
92
    }
 
93
    darktable.gui->reset = 0;
 
94
    dev->gui_synch = 0;
 
95
  }
 
96
 
 
97
  if(dev->image_dirty || dev->pipe->input_timestamp < dev->preview_pipe->input_timestamp) dt_dev_process_image(dev);
 
98
  if(dev->preview_dirty) dt_dev_process_preview(dev);
 
99
 
 
100
  dt_pthread_mutex_t *mutex = NULL;
 
101
  int wd, ht, stride, closeup;
 
102
  int32_t zoom;
 
103
  float zoom_x, zoom_y;
 
104
  DT_CTL_GET_GLOBAL(zoom_y, dev_zoom_y);
 
105
  DT_CTL_GET_GLOBAL(zoom_x, dev_zoom_x);
 
106
  DT_CTL_GET_GLOBAL(zoom, dev_zoom);
 
107
  DT_CTL_GET_GLOBAL(closeup, dev_closeup);
 
108
  static cairo_surface_t *image_surface = NULL;
 
109
  static int image_surface_width = 0, image_surface_height = 0, image_surface_imgid = -1;
 
110
 
 
111
  if(image_surface_width != width || image_surface_height != height || image_surface == NULL)
 
112
  {
 
113
    // create double-buffered image to draw on, to make modules draw more fluently.
 
114
    image_surface_width = width;
 
115
    image_surface_height = height;
 
116
    if(image_surface) cairo_surface_destroy(image_surface);
 
117
    image_surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, width, height);
 
118
  }
 
119
  cairo_surface_t *surface;
 
120
  cairo_t *cr = cairo_create(image_surface);
 
121
 
 
122
  // adjust scroll bars
 
123
  {
 
124
    float zx = zoom_x, zy = zoom_y, boxw = 1., boxh = 1.;
 
125
    dt_dev_check_zoom_bounds(dev, &zx, &zy, zoom, closeup, &boxw, &boxh);
 
126
    dt_view_set_scrollbar(self, zx+.5-boxw*.5, 1.0, boxw, zy+.5-boxh*.5, 1.0, boxh);
 
127
  }
 
128
 
 
129
  if(!dev->image_dirty && dev->pipe->input_timestamp >= dev->preview_pipe->input_timestamp)
 
130
  {
 
131
    // draw image
 
132
    mutex = &dev->pipe->backbuf_mutex;
 
133
    dt_pthread_mutex_lock(mutex);
 
134
    wd = dev->pipe->backbuf_width;
 
135
    ht = dev->pipe->backbuf_height;
 
136
    stride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, wd);
 
137
    surface = cairo_image_surface_create_for_data (dev->pipe->backbuf, CAIRO_FORMAT_RGB24, wd, ht, stride);
 
138
    cairo_set_source_rgb (cr, .2, .2, .2);
 
139
    cairo_paint(cr);
 
140
    cairo_translate(cr, .5f*(width-wd), .5f*(height-ht));
 
141
    if(closeup)
 
142
    {
 
143
      const float closeup_scale = 2.0;
 
144
      cairo_scale(cr, closeup_scale, closeup_scale);
 
145
      float boxw = 1, boxh = 1, zx0 = zoom_x, zy0 = zoom_y, zx1 = zoom_x, zy1 = zoom_y, zxm = -1.0, zym = -1.0;
 
146
      dt_dev_check_zoom_bounds(dev, &zx0, &zy0, zoom, 0, &boxw, &boxh);
 
147
      dt_dev_check_zoom_bounds(dev, &zx1, &zy1, zoom, 1, &boxw, &boxh);
 
148
      dt_dev_check_zoom_bounds(dev, &zxm, &zym, zoom, 1, &boxw, &boxh);
 
149
      const float fx = 1.0 - fmaxf(0.0, (zx0 - zx1)/(zx0 - zxm)), fy = 1.0 - fmaxf(0.0, (zy0 - zy1)/(zy0 - zym));
 
150
      cairo_translate(cr, -wd/(2.0*closeup_scale) * fx, -ht/(2.0*closeup_scale) * fy);
 
151
    }
 
152
    cairo_rectangle(cr, 0, 0, wd, ht);
 
153
    cairo_set_source_surface (cr, surface, 0, 0);
 
154
    cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_FAST);
 
155
    cairo_fill_preserve(cr);
 
156
    cairo_set_line_width(cr, 1.0);
 
157
    cairo_set_source_rgb (cr, .3, .3, .3);
 
158
    cairo_stroke(cr);
 
159
    cairo_surface_destroy (surface);
 
160
    dt_pthread_mutex_unlock(mutex);
 
161
    image_surface_imgid = dev->image->id;
 
162
  }
 
163
  else if(!dev->preview_dirty)
 
164
    // else if(!dev->preview_loading)
 
165
  {
 
166
    // draw preview
 
167
    mutex = &dev->preview_pipe->backbuf_mutex;
 
168
    dt_pthread_mutex_lock(mutex);
 
169
 
 
170
    wd = dev->preview_pipe->backbuf_width;
 
171
    ht = dev->preview_pipe->backbuf_height;
 
172
    float zoom_scale = dt_dev_get_zoom_scale(dev, zoom, closeup ? 2 : 1, 1);
 
173
    cairo_set_source_rgb (cr, .2, .2, .2);
 
174
    cairo_paint(cr);
 
175
    cairo_rectangle(cr, 0, 0, width, height);
 
176
    cairo_clip(cr);
 
177
    stride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, wd);
 
178
    surface = cairo_image_surface_create_for_data (dev->preview_pipe->backbuf, CAIRO_FORMAT_RGB24, wd, ht, stride);
 
179
    cairo_translate(cr, width/2.0, height/2.0f);
 
180
    cairo_scale(cr, zoom_scale, zoom_scale);
 
181
    cairo_translate(cr, -.5f*wd-zoom_x*wd, -.5f*ht-zoom_y*ht);
 
182
    // avoid to draw the 1px garbage that sometimes shows up in the preview :(
 
183
    cairo_rectangle(cr, 0, 0, wd-1, ht-1);
 
184
    cairo_set_source_surface (cr, surface, 0, 0);
 
185
    cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_FAST);
 
186
    cairo_fill(cr);
 
187
    cairo_surface_destroy (surface);
 
188
    dt_pthread_mutex_unlock(mutex);
 
189
    image_surface_imgid = dev->image->id;
 
190
  }
 
191
  cairo_restore(cri);
 
192
 
 
193
  if(image_surface_imgid == dev->image->id)
 
194
  {
 
195
    cairo_destroy(cr);
 
196
    cairo_set_source_surface(cri, image_surface, 0, 0);
 
197
    cairo_paint(cri);
 
198
  }
 
199
 
 
200
  if(darktable.gui->request_snapshot)
 
201
  {
 
202
    cairo_surface_write_to_png(image_surface, darktable.gui->snapshot[0].filename);
 
203
    darktable.gui->request_snapshot = 0;
 
204
  }
 
205
  // and if a snapshot is currently selected, draw it on top!
 
206
  if(darktable.gui->snapshot_image)
 
207
  {
 
208
    cairo_set_source_surface(cri, darktable.gui->snapshot_image, 0, 0);
 
209
    cairo_rectangle(cri, 0, 0, width*.5f, height);
 
210
    cairo_fill(cri);
 
211
    cairo_set_source_rgb(cri, .7, .7, .7);
 
212
    cairo_set_line_width(cri, 1.0);
 
213
    cairo_move_to(cri, width*.5f, 0.0f);
 
214
    cairo_line_to(cri, width*.5f, height);
 
215
    cairo_stroke(cri);
 
216
  }
 
217
 
 
218
  // execute module callback hook.
 
219
  if(dev->gui_module && dev->gui_module->request_color_pick)
 
220
  {
 
221
    int32_t zoom, closeup;
 
222
    float zoom_x, zoom_y;
 
223
    float wd = dev->preview_pipe->backbuf_width;
 
224
    float ht = dev->preview_pipe->backbuf_height;
 
225
    DT_CTL_GET_GLOBAL(zoom_y, dev_zoom_y);
 
226
    DT_CTL_GET_GLOBAL(zoom_x, dev_zoom_x);
 
227
    DT_CTL_GET_GLOBAL(zoom, dev_zoom);
 
228
    DT_CTL_GET_GLOBAL(closeup, dev_closeup);
 
229
    float zoom_scale = dt_dev_get_zoom_scale(dev, zoom, closeup ? 2 : 1, 1);
 
230
 
 
231
    cairo_translate(cri, width/2.0, height/2.0f);
 
232
    cairo_scale(cri, zoom_scale, zoom_scale);
 
233
    cairo_translate(cri, -.5f*wd-zoom_x*wd, -.5f*ht-zoom_y*ht);
 
234
 
 
235
    // cairo_set_operator(cri, CAIRO_OPERATOR_XOR);
 
236
    cairo_set_line_width(cri, 1.0/zoom_scale);
 
237
    cairo_set_source_rgb(cri, .2, .2, .2);
 
238
 
 
239
    float *box = dev->gui_module->color_picker_box;
 
240
    cairo_rectangle(cri, box[0]*wd, box[1]*ht, (box[2] - box[0])*wd, (box[3] - box[1])*ht);
 
241
    cairo_stroke(cri);
 
242
    cairo_translate(cri, 1.0/zoom_scale, 1.0/zoom_scale);
 
243
    cairo_set_source_rgb(cri, .8, .8, .8);
 
244
    cairo_rectangle(cri, box[0]*wd, box[1]*ht, (box[2] - box[0])*wd, (box[3] - box[1])*ht);
 
245
    cairo_stroke(cri);
 
246
  }
 
247
  else if(dev->gui_module && dev->gui_module->gui_post_expose)
 
248
  {
 
249
    if(width_i  > DT_IMAGE_WINDOW_SIZE) pointerx += (DT_IMAGE_WINDOW_SIZE-width_i) *.5f;
 
250
    if(height_i > DT_IMAGE_WINDOW_SIZE) pointery += (DT_IMAGE_WINDOW_SIZE-height_i)*.5f;
 
251
    dev->gui_module->gui_post_expose(dev->gui_module, cri, width, height, pointerx, pointery);
 
252
  }
 
253
}
 
254
 
 
255
 
 
256
void reset(dt_view_t *self)
 
257
{
 
258
  DT_CTL_SET_GLOBAL(dev_zoom, DT_ZOOM_FIT);
 
259
  DT_CTL_SET_GLOBAL(dev_zoom_x, 0);
 
260
  DT_CTL_SET_GLOBAL(dev_zoom_y, 0);
 
261
  DT_CTL_SET_GLOBAL(dev_closeup, 0);
 
262
}
 
263
 
 
264
 
 
265
static void module_show_callback(GtkToggleButton *togglebutton, gpointer user_data)
 
266
{
 
267
  dt_iop_module_t *module = (dt_iop_module_t *)user_data;
 
268
  char option[512];
 
269
  snprintf(option, 512, "plugins/darkroom/%s/visible", module->op);
 
270
  if(gtk_toggle_button_get_active(togglebutton))
 
271
  {
 
272
    dt_gui_iop_modulegroups_switch(module->groups());
 
273
    gtk_widget_show(GTK_WIDGET(module->topwidget));
 
274
    dt_conf_set_bool (option, TRUE);
 
275
    gtk_expander_set_expanded(module->expander, TRUE);
 
276
    snprintf(option, 512, _("hide %s"), module->name());
 
277
  }
 
278
  else
 
279
  {
 
280
    gtk_widget_hide(GTK_WIDGET(module->topwidget));
 
281
    dt_conf_set_bool (option, FALSE);
 
282
    gtk_expander_set_expanded(module->expander, FALSE);
 
283
    snprintf(option, 512, _("show %s"), module->name());
 
284
  }
 
285
  gtk_object_set(GTK_OBJECT(module->showhide), "tooltip-text", option, (char *)NULL);
 
286
}
 
287
 
 
288
 
 
289
int try_enter(dt_view_t *self)
 
290
{
 
291
  dt_develop_t *dev = (dt_develop_t *)self->data;
 
292
  int selected;
 
293
  DT_CTL_GET_GLOBAL(selected, lib_image_mouse_over_id);
 
294
  if(selected < 0)
 
295
  {
 
296
    // try last selected
 
297
    sqlite3_stmt *stmt;
 
298
    DT_DEBUG_SQLITE3_PREPARE_V2(darktable.db, "select * from selected_images", -1, &stmt, NULL);
 
299
    if(sqlite3_step(stmt) == SQLITE_ROW)
 
300
      selected = sqlite3_column_int(stmt, 0);
 
301
    sqlite3_finalize(stmt);
 
302
  }
 
303
 
 
304
  if(selected < 0)
 
305
  {
 
306
    // fail :(
 
307
    dt_control_log(_("no image selected!"));
 
308
    return 1;
 
309
  }
 
310
 
 
311
  // this loads the image from db if needed:
 
312
  dev->image = dt_image_cache_get(selected, 'r');
 
313
  // get image and check if it has been deleted from disk first!
 
314
  char imgfilename[1024];
 
315
  dt_image_full_path(dev->image->id, imgfilename, 1024);
 
316
  if(!g_file_test(imgfilename, G_FILE_TEST_IS_REGULAR))
 
317
  {
 
318
    dt_control_log(_("image `%s' is currently unavailable"), dev->image->filename);
 
319
    // dt_image_remove(selected);
 
320
    dt_image_cache_release(dev->image, 'r');
 
321
    dev->image = NULL;
 
322
    return 1;
 
323
  }
 
324
  return 0;
 
325
}
 
326
 
 
327
 
 
328
 
 
329
static void
 
330
select_this_image(const int imgid)
 
331
{
 
332
  // select this image, if no multiple selection:
 
333
  int count = 0;
 
334
  sqlite3_stmt *stmt;
 
335
  DT_DEBUG_SQLITE3_PREPARE_V2(darktable.db, "select count(imgid) from selected_images", -1, &stmt, NULL);
 
336
  if(sqlite3_step(stmt) == SQLITE_ROW)
 
337
    count = sqlite3_column_int(stmt, 0);
 
338
  sqlite3_finalize(stmt);
 
339
  if(count < 2)
 
340
  {
 
341
    DT_DEBUG_SQLITE3_EXEC(darktable.db, "delete from selected_images", NULL, NULL, NULL);
 
342
    DT_DEBUG_SQLITE3_PREPARE_V2(darktable.db, "insert into selected_images values (?1)", -1, &stmt, NULL);
 
343
    DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid);
 
344
    sqlite3_step(stmt);
 
345
    sqlite3_finalize(stmt);
 
346
  }
 
347
}
 
348
 
 
349
static void
 
350
dt_dev_change_image(dt_develop_t *dev, dt_image_t *image)
 
351
{
 
352
  // stare last active group
 
353
  dt_conf_set_int("plugins/darkroom/groups", dt_gui_iop_modulegroups_get());
 
354
  // store last active plugin:
 
355
  if(darktable.develop->gui_module)
 
356
    dt_conf_set_string("plugins/darkroom/active", darktable.develop->gui_module->op);
 
357
  else
 
358
    dt_conf_set_string("plugins/darkroom/active", "");
 
359
  g_assert(dev->gui_attached);
 
360
  // commit image ops to db
 
361
  dt_dev_write_history(dev);
 
362
  // write .xmp file
 
363
  dt_image_write_sidecar_file(dev->image->id);
 
364
 
 
365
  // commit updated mipmaps to db
 
366
  // TODO: bg process?
 
367
  dt_dev_process_to_mip(dev);
 
368
  // release full buffer
 
369
  if(dev->image && dev->image->pixels)
 
370
    dt_image_release(dev->image, DT_IMAGE_FULL, 'r');
 
371
 
 
372
  dt_image_cache_flush(dev->image);
 
373
 
 
374
  dev->image = image;
 
375
  while(dev->history)
 
376
  {
 
377
    // clear history of old image
 
378
    free(((dt_dev_history_item_t *)dev->history->data)->params);
 
379
    free( (dt_dev_history_item_t *)dev->history->data);
 
380
    dev->history = g_list_delete_link(dev->history, dev->history);
 
381
  }
 
382
  GList *modules = g_list_last(dev->iop);
 
383
  while(modules)
 
384
  {
 
385
    dt_iop_module_t *module = (dt_iop_module_t *)(modules->data);
 
386
    if(strcmp(module->op, "gamma"))
 
387
    {
 
388
      char var[1024];
 
389
      snprintf(var, 1024, "plugins/darkroom/%s/expanded", module->op);
 
390
      dt_conf_set_bool(var, gtk_expander_get_expanded (module->expander));
 
391
      // remove widget:
 
392
      GtkWidget *top = GTK_WIDGET(module->topwidget);
 
393
      GtkWidget *exp = GTK_WIDGET(module->expander);
 
394
      GtkWidget *shh = GTK_WIDGET(module->showhide);
 
395
      GtkWidget *parent = NULL;
 
396
      g_object_get(G_OBJECT(module->widget), "parent", &parent, (char *)NULL);
 
397
      // re-init and re-gui_init
 
398
      module->gui_cleanup(module);
 
399
      gtk_widget_destroy(GTK_WIDGET(module->widget));
 
400
      dt_iop_reload_defaults(module);
 
401
      module->gui_init(module);
 
402
      // copy over already inited stuff:
 
403
      module->topwidget = top;
 
404
      module->expander = GTK_EXPANDER(exp);
 
405
      module->showhide = shh;
 
406
      // reparent
 
407
      gtk_container_add(GTK_CONTAINER(parent), module->widget);
 
408
      gtk_widget_show_all(module->topwidget);
 
409
      // all the signal handlers get passed module*, which is still valid.
 
410
    }
 
411
    modules = g_list_previous(modules);
 
412
  }
 
413
  // hack: now hide all custom expander widgets again.
 
414
  modules = dev->iop;
 
415
  while(modules)
 
416
  {
 
417
    dt_iop_module_t *module = (dt_iop_module_t *)(modules->data);
 
418
    if(strcmp(module->op, "gamma"))
 
419
    {
 
420
      char option[1024];
 
421
      snprintf(option, 1024, "plugins/darkroom/%s/visible", module->op);
 
422
      gboolean active = dt_conf_get_bool (option);
 
423
      gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(module->showhide), !active);
 
424
      gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(module->showhide), active);
 
425
 
 
426
      snprintf(option, 1024, "plugins/darkroom/%s/expanded", module->op);
 
427
      active = dt_conf_get_bool (option);
 
428
      gtk_expander_set_expanded (module->expander, active);
 
429
    }
 
430
    else
 
431
    {
 
432
      gtk_widget_hide_all(GTK_WIDGET(module->topwidget));
 
433
    }
 
434
    modules = g_list_next(modules);
 
435
  }
 
436
  dt_gui_iop_modulegroups_switch(dt_conf_get_int("plugins/darkroom/groups"));
 
437
  dt_dev_read_history(dev);
 
438
  dt_dev_pop_history_items(dev, dev->history_end);
 
439
  dt_dev_raw_reload(dev);
 
440
 
 
441
  // get last active plugin:
 
442
  gchar *active_plugin = dt_conf_get_string("plugins/darkroom/active");
 
443
  if(active_plugin)
 
444
  {
 
445
    modules = dev->iop;
 
446
    while(modules)
 
447
    {
 
448
      dt_iop_module_t *module = (dt_iop_module_t *)(modules->data);
 
449
      if(!strcmp(module->op, active_plugin))
 
450
        dt_iop_request_focus(module);
 
451
      modules = g_list_next(modules);
 
452
    }
 
453
    g_free(active_plugin);
 
454
  }
 
455
}
 
456
 
 
457
static void
 
458
film_strip_activated(const int imgid, void *data)
 
459
{
 
460
  // switch images in darkroom mode:
 
461
  dt_view_t *self = (dt_view_t *)data;
 
462
  dt_develop_t *dev = (dt_develop_t *)self->data;
 
463
  dt_image_t *image = dt_image_cache_get(imgid, 'r');
 
464
  dt_dev_change_image(dev, image);
 
465
  // release image struct with metadata.
 
466
  dt_image_cache_release(dev->image, 'r');
 
467
  // select newly loaded image
 
468
  select_this_image(dev->image->id);
 
469
  // force redraw
 
470
  dt_control_queue_draw_all();
 
471
  // prefetch next few from first selected image on.
 
472
  dt_view_film_strip_prefetch();
 
473
}
 
474
 
 
475
static void
 
476
zoom_key_accel(void *data)
 
477
{
 
478
  dt_develop_t *dev = darktable.develop;
 
479
  int zoom, closeup;
 
480
  float zoom_x, zoom_y;
 
481
  switch ((long int)data)
 
482
  {
 
483
    case 1:
 
484
      DT_CTL_GET_GLOBAL(zoom, dev_zoom);
 
485
      DT_CTL_GET_GLOBAL(closeup, dev_closeup);
 
486
      if(zoom == DT_ZOOM_1) closeup ^= 1;
 
487
      DT_CTL_SET_GLOBAL(dev_closeup, closeup);
 
488
      DT_CTL_SET_GLOBAL(dev_zoom, DT_ZOOM_1);
 
489
      dt_dev_invalidate(dev);
 
490
      break;
 
491
    case 2:
 
492
      DT_CTL_SET_GLOBAL(dev_zoom, DT_ZOOM_FILL);
 
493
      dt_dev_check_zoom_bounds(dev, &zoom_x, &zoom_y, DT_ZOOM_FILL, 0, NULL, NULL);
 
494
      DT_CTL_SET_GLOBAL(dev_zoom_x, zoom_x);
 
495
      DT_CTL_SET_GLOBAL(dev_zoom_y, zoom_y);
 
496
      DT_CTL_SET_GLOBAL(dev_closeup, 0);
 
497
      dt_dev_invalidate(dev);
 
498
      break;
 
499
    case 3:
 
500
      DT_CTL_SET_GLOBAL(dev_zoom, DT_ZOOM_FIT);
 
501
      DT_CTL_SET_GLOBAL(dev_zoom_x, 0);
 
502
      DT_CTL_SET_GLOBAL(dev_zoom_y, 0);
 
503
      DT_CTL_SET_GLOBAL(dev_closeup, 0);
 
504
      dt_dev_invalidate(dev);
 
505
      break;
 
506
    default:
 
507
      break;
 
508
  }
 
509
}
 
510
 
 
511
static void
 
512
film_strip_key_accel(void *data)
 
513
{
 
514
  dt_view_film_strip_toggle(darktable.view_manager, film_strip_activated, data);
 
515
  dt_control_queue_draw_all();
 
516
}
 
517
 
 
518
void enter(dt_view_t *self)
 
519
{
 
520
  dt_print(DT_DEBUG_CONTROL, "[run_job+] 11 %f in darkroom mode\n", dt_get_wtime());
 
521
  dt_develop_t *dev = (dt_develop_t *)self->data;
 
522
 
 
523
  select_this_image(dev->image->id);
 
524
 
 
525
  DT_CTL_SET_GLOBAL(dev_zoom, DT_ZOOM_FIT);
 
526
  DT_CTL_SET_GLOBAL(dev_zoom_x, 0);
 
527
  DT_CTL_SET_GLOBAL(dev_zoom_y, 0);
 
528
  DT_CTL_SET_GLOBAL(dev_closeup, 0);
 
529
 
 
530
  dev->gui_leaving = 0;
 
531
  dev->gui_module = NULL;
 
532
  dt_dev_load_image(dev, dev->image);
 
533
 
 
534
  // adjust gui:
 
535
  GtkWidget *widget;
 
536
  gtk_widget_set_visible (glade_xml_get_widget (darktable.gui->main_window, "modulegroups_eventbox"), TRUE);
 
537
 
 
538
  widget = glade_xml_get_widget (darktable.gui->main_window, "navigation_expander");
 
539
  gtk_widget_set_visible(widget, TRUE);
 
540
  widget = glade_xml_get_widget (darktable.gui->main_window, "histogram_expander");
 
541
  gtk_widget_set_visible(widget, TRUE);
 
542
  widget = glade_xml_get_widget (darktable.gui->main_window, "snapshots_eventbox");
 
543
  gtk_widget_set_visible(widget, TRUE);
 
544
  widget = glade_xml_get_widget (darktable.gui->main_window, "history_eventbox");
 
545
  gtk_widget_set_visible(widget, TRUE);
 
546
  widget = glade_xml_get_widget (darktable.gui->main_window, "bottom_darkroom_box");
 
547
  gtk_widget_set_visible(widget, TRUE);
 
548
  widget = glade_xml_get_widget (darktable.gui->main_window, "bottom_lighttable_box");
 
549
  gtk_widget_set_visible(widget, FALSE);
 
550
  widget = glade_xml_get_widget (darktable.gui->main_window, "plugins_vbox_left");
 
551
  gtk_widget_set_visible(widget, FALSE);
 
552
  widget = glade_xml_get_widget (darktable.gui->main_window, "import_eventbox");
 
553
  gtk_widget_set_visible(widget, FALSE);
 
554
  widget = glade_xml_get_widget (darktable.gui->main_window, "module_list_eventbox");
 
555
  gtk_widget_set_visible(widget, TRUE);
 
556
 
 
557
  // get top level vbox containing all expanders, plugins_vbox:
 
558
  GtkBox *box = GTK_BOX(glade_xml_get_widget (darktable.gui->main_window, "plugins_vbox"));
 
559
  GtkTable *module_list = GTK_TABLE(glade_xml_get_widget (darktable.gui->main_window, "module_list"));
 
560
  GList *modules = g_list_last(dev->iop);
 
561
  int ti = 0, tj = 0;
 
562
  while(modules)
 
563
  {
 
564
    dt_iop_module_t *module = (dt_iop_module_t *)(modules->data);
 
565
    module->gui_init(module);
 
566
    // add the widget created by gui_init to an expander and both to list.
 
567
    GtkWidget *expander = dt_iop_gui_get_expander(module);
 
568
    module->topwidget = GTK_WIDGET(expander);
 
569
    gtk_box_pack_start(box, expander, FALSE, FALSE, 0);
 
570
    if(strcmp(module->op, "gamma"))
 
571
    {
 
572
      module->showhide = gtk_toggle_button_new();
 
573
      char filename[1024], datadir[1024];
 
574
      dt_get_datadir(datadir, 1024);
 
575
      snprintf(filename, 1024, "%s/pixmaps/plugins/darkroom/%s.png", datadir, module->op);
 
576
      if(!g_file_test(filename, G_FILE_TEST_IS_REGULAR))
 
577
        snprintf(filename, 1024, "%s/pixmaps/plugins/darkroom/template.png", datadir);
 
578
      GtkWidget *image = gtk_image_new_from_file(filename);
 
579
      gtk_button_set_image(GTK_BUTTON(module->showhide), image);
 
580
      g_signal_connect(G_OBJECT(module->showhide), "toggled",
 
581
                       G_CALLBACK(module_show_callback), module);
 
582
      gtk_table_attach(module_list, module->showhide, ti, ti+1, tj, tj+1,
 
583
                       GTK_FILL | GTK_EXPAND | GTK_SHRINK,
 
584
                       GTK_SHRINK,
 
585
                       0, 0);
 
586
      if(ti < 5) ti++;
 
587
      else
 
588
      {
 
589
        ti = 0;
 
590
        tj ++;
 
591
      }
 
592
    }
 
593
    modules = g_list_previous(modules);
 
594
  }
 
595
  // end marker widget:
 
596
  GtkWidget *endmarker = gtk_drawing_area_new();
 
597
 
 
598
  gtk_box_pack_start(box, endmarker, FALSE, FALSE, 0);
 
599
  g_signal_connect (G_OBJECT (endmarker), "expose-event",
 
600
                    G_CALLBACK (dt_control_expose_endmarker), 0);
 
601
  gtk_widget_set_size_request(endmarker, -1, 50);
 
602
 
 
603
  gtk_widget_show_all(GTK_WIDGET(box));
 
604
  gtk_widget_show_all(GTK_WIDGET(module_list));
 
605
 
 
606
 
 
607
  /* set list of modules to modulegroups */
 
608
  dt_gui_iop_modulegroups_set_list (dev->iop);
 
609
 
 
610
  // hack: now hide all custom expander widgets again.
 
611
  modules = dev->iop;
 
612
  while(modules)
 
613
  {
 
614
    dt_iop_module_t *module = (dt_iop_module_t *)(modules->data);
 
615
    if(strcmp(module->op, "gamma"))
 
616
    {
 
617
      char option[1024];
 
618
      snprintf(option, 1024, "plugins/darkroom/%s/visible", module->op);
 
619
      gboolean active = dt_conf_get_bool (option);
 
620
      gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(module->showhide), !active);
 
621
      gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(module->showhide), active);
 
622
 
 
623
      snprintf(option, 1024, "plugins/darkroom/%s/expanded", module->op);
 
624
      active = dt_conf_get_bool (option);
 
625
      gtk_expander_set_expanded (module->expander, active);
 
626
    }
 
627
    else
 
628
    {
 
629
      gtk_widget_hide_all(GTK_WIDGET(module->topwidget));
 
630
    }
 
631
    modules = g_list_next(modules);
 
632
  }
 
633
 
 
634
 
 
635
  // synch gui and flag gegl pipe as dirty
 
636
  // FIXME: this assumes static pipeline as well
 
637
  // this is done here and not in dt_read_history, as it would else be triggered before module->gui_init.
 
638
  dt_dev_pop_history_items(dev, dev->history_end);
 
639
 
 
640
  if(dt_conf_get_bool("plugins/filmstrip/on"))
 
641
  {
 
642
    // double click callback:
 
643
    dt_view_film_strip_scroll_to(darktable.view_manager, dev->image->id);
 
644
    dt_view_film_strip_open(darktable.view_manager, film_strip_activated, self);
 
645
    dt_view_film_strip_prefetch();
 
646
  }
 
647
  dt_gui_key_accel_register(GDK_CONTROL_MASK, GDK_f, film_strip_key_accel, self);
 
648
  dt_gui_key_accel_register(GDK_MOD1_MASK, GDK_1, zoom_key_accel, (void *)1);
 
649
  dt_gui_key_accel_register(GDK_MOD1_MASK, GDK_2, zoom_key_accel, (void *)2);
 
650
  dt_gui_key_accel_register(GDK_MOD1_MASK, GDK_3, zoom_key_accel, (void *)3);
 
651
 
 
652
  // switch on groups as they where last time:
 
653
  dt_gui_iop_modulegroups_switch(dt_conf_get_int("plugins/darkroom/groups"));
 
654
 
 
655
  // get last active plugin:
 
656
  gchar *active_plugin = dt_conf_get_string("plugins/darkroom/active");
 
657
  if(active_plugin)
 
658
  {
 
659
    modules = dev->iop;
 
660
    while(modules)
 
661
    {
 
662
      dt_iop_module_t *module = (dt_iop_module_t *)(modules->data);
 
663
      if(!strcmp(module->op, active_plugin))
 
664
        dt_iop_request_focus(module);
 
665
      modules = g_list_next(modules);
 
666
    }
 
667
    g_free(active_plugin);
 
668
  }
 
669
 
 
670
  // image should be there now.
 
671
  float zoom_x, zoom_y;
 
672
  dt_dev_check_zoom_bounds(dev, &zoom_x, &zoom_y, DT_ZOOM_FIT, 0, NULL, NULL);
 
673
  DT_CTL_SET_GLOBAL(dev_zoom_x, zoom_x);
 
674
  DT_CTL_SET_GLOBAL(dev_zoom_y, zoom_y);
 
675
}
 
676
 
 
677
 
 
678
static void
 
679
dt_dev_remove_child(GtkWidget *widget, gpointer data)
 
680
{
 
681
  gtk_container_remove(GTK_CONTAINER(data), widget);
 
682
}
 
683
 
 
684
void leave(dt_view_t *self)
 
685
{
 
686
  // store groups for next time:
 
687
  dt_conf_set_int("plugins/darkroom/groups", dt_gui_iop_modulegroups_get());
 
688
 
 
689
  // store last active plugin:
 
690
  if(darktable.develop->gui_module)
 
691
    dt_conf_set_string("plugins/darkroom/active", darktable.develop->gui_module->op);
 
692
  else
 
693
    dt_conf_set_string("plugins/darkroom/active", "");
 
694
 
 
695
  if(dt_conf_get_bool("plugins/filmstrip/on"))
 
696
    dt_view_film_strip_close(darktable.view_manager);
 
697
  dt_gui_key_accel_unregister(film_strip_key_accel);
 
698
  dt_gui_key_accel_unregister(zoom_key_accel);
 
699
 
 
700
  GList *childs = gtk_container_get_children (
 
701
                    GTK_CONTAINER (glade_xml_get_widget (darktable.gui->main_window, "bottom_left_toolbox")));
 
702
  while(childs)
 
703
  {
 
704
    gtk_widget_destroy ( GTK_WIDGET (childs->data));
 
705
    childs=g_list_next(childs);
 
706
  }
 
707
 
 
708
  GtkWidget *widget;
 
709
  widget = glade_xml_get_widget (darktable.gui->main_window, "navigation_expander");
 
710
  gtk_widget_set_visible(widget, FALSE);
 
711
  widget = glade_xml_get_widget (darktable.gui->main_window, "histogram_expander");
 
712
  gtk_widget_set_visible(widget, FALSE);
 
713
  widget = glade_xml_get_widget (darktable.gui->main_window, "snapshots_eventbox");
 
714
  gtk_widget_set_visible(widget, FALSE);
 
715
  widget = glade_xml_get_widget (darktable.gui->main_window, "history_eventbox");
 
716
  gtk_widget_set_visible(widget, FALSE);
 
717
  widget = glade_xml_get_widget (darktable.gui->main_window, "bottom_darkroom_box");
 
718
  gtk_widget_set_visible(widget, FALSE);
 
719
  widget = glade_xml_get_widget (darktable.gui->main_window, "bottom_lighttable_box");
 
720
  gtk_widget_set_visible(widget, TRUE);
 
721
  widget = glade_xml_get_widget (darktable.gui->main_window, "plugins_vbox_left");
 
722
  gtk_widget_set_visible(widget, TRUE);
 
723
  widget = glade_xml_get_widget (darktable.gui->main_window, "module_list_eventbox");
 
724
  gtk_widget_set_visible(widget, FALSE);
 
725
 
 
726
  dt_develop_t *dev = (dt_develop_t *)self->data;
 
727
  // commit image ops to db
 
728
  dt_dev_write_history(dev);
 
729
  // write .xmp file
 
730
  dt_image_write_sidecar_file(dev->image->id);
 
731
 
 
732
  // commit updated mipmaps to db
 
733
  dt_dev_process_to_mip(dev);
 
734
 
 
735
  // clear gui.
 
736
  dev->gui_leaving = 1;
 
737
  dt_pthread_mutex_lock(&dev->history_mutex);
 
738
  dt_dev_pixelpipe_cleanup_nodes(dev->pipe);
 
739
  dt_dev_pixelpipe_cleanup_nodes(dev->preview_pipe);
 
740
  GtkBox *box = GTK_BOX(glade_xml_get_widget (darktable.gui->main_window, "plugins_vbox"));
 
741
  while(dev->history)
 
742
  {
 
743
    dt_dev_history_item_t *hist = (dt_dev_history_item_t *)(dev->history->data);
 
744
    // printf("removing history item %d - %s, data %f %f\n", hist->module->instance, hist->module->op, *(float *)hist->params, *((float *)hist->params+1));
 
745
    free(hist->params);
 
746
    hist->params = NULL;
 
747
    free(hist);
 
748
    dev->history = g_list_delete_link(dev->history, dev->history);
 
749
  }
 
750
  while(dev->iop)
 
751
  {
 
752
    dt_iop_module_t *module = (dt_iop_module_t *)(dev->iop->data);
 
753
    // printf("removing module %d - %s\n", module->instance, module->op);
 
754
    char var[1024];
 
755
    snprintf(var, 1024, "plugins/darkroom/%s/expanded", module->op);
 
756
    dt_conf_set_bool(var, gtk_expander_get_expanded (module->expander));
 
757
 
 
758
    module->gui_cleanup(module);
 
759
    module->cleanup(module);
 
760
    free(module);
 
761
    dev->iop = g_list_delete_link(dev->iop, dev->iop);
 
762
  }
 
763
  gtk_container_foreach(GTK_CONTAINER(box), (GtkCallback)dt_dev_remove_child, (gpointer)box);
 
764
  dt_pthread_mutex_unlock(&dev->history_mutex);
 
765
 
 
766
  // release full buffer
 
767
  if(dev->image->pixels)
 
768
    dt_image_release(dev->image, DT_IMAGE_FULL, 'r');
 
769
 
 
770
  // release image struct with metadata as well.
 
771
  dt_image_cache_flush(dev->image);
 
772
  dt_image_cache_release(dev->image, 'r');
 
773
  dt_print(DT_DEBUG_CONTROL, "[run_job-] 11 %f in darkroom mode\n", dt_get_wtime());
 
774
}
 
775
 
 
776
void mouse_leave(dt_view_t *self)
 
777
{
 
778
  // if we are not hovering over a thumbnail in the filmstrip -> show metadata of opened image.
 
779
  dt_develop_t *dev = (dt_develop_t *)self->data;
 
780
  int32_t mouse_over_id = dev->image->id;
 
781
  DT_CTL_SET_GLOBAL(lib_image_mouse_over_id, mouse_over_id);
 
782
  dt_gui_metadata_update();
 
783
 
 
784
  // reset any changes the selected plugin might have made.
 
785
  dt_control_change_cursor(GDK_LEFT_PTR);
 
786
}
 
787
 
 
788
void mouse_moved(dt_view_t *self, double x, double y, int which)
 
789
{
 
790
  dt_develop_t *dev = (dt_develop_t *)self->data;
 
791
 
 
792
  // if we are not hovering over a thumbnail in the filmstrip -> show metadata of opened image.
 
793
  int32_t mouse_over_id = -1;
 
794
  DT_CTL_GET_GLOBAL(mouse_over_id, lib_image_mouse_over_id);
 
795
  if(mouse_over_id == -1)
 
796
  {
 
797
    mouse_over_id = dev->image->id;
 
798
    DT_CTL_SET_GLOBAL(lib_image_mouse_over_id, mouse_over_id);
 
799
    dt_gui_metadata_update();
 
800
  }
 
801
 
 
802
  dt_control_t *ctl = darktable.control;
 
803
  const int32_t width_i  = self->width;
 
804
  const int32_t height_i = self->height;
 
805
  int32_t offx = 0.0f, offy = 0.0f;
 
806
  if(width_i  > DT_IMAGE_WINDOW_SIZE) offx =   (DT_IMAGE_WINDOW_SIZE-width_i) *.5f;
 
807
  if(height_i > DT_IMAGE_WINDOW_SIZE) offy =   (DT_IMAGE_WINDOW_SIZE-height_i)*.5f;
 
808
  int handled = 0;
 
809
  x += offx;
 
810
  y += offy;
 
811
  if(dev->gui_module && dev->gui_module->request_color_pick &&
 
812
      ctl->button_down &&
 
813
      ctl->button_down_which == 1)
 
814
  {
 
815
    // module requested a color box
 
816
    float zoom_x, zoom_y, bzoom_x, bzoom_y;
 
817
    dt_dev_get_pointer_zoom_pos(dev, x, y, &zoom_x, &zoom_y);
 
818
    dt_dev_get_pointer_zoom_pos(dev, ctl->button_x + offx, ctl->button_y + offy, &bzoom_x, &bzoom_y);
 
819
    dev->gui_module->color_picker_box[0] = fmaxf(0.0, fminf(.5f+bzoom_x, .5f+zoom_x));
 
820
    dev->gui_module->color_picker_box[1] = fmaxf(0.0, fminf(.5f+bzoom_y, .5f+zoom_y));
 
821
    dev->gui_module->color_picker_box[2] = fminf(1.0, fmaxf(.5f+bzoom_x, .5f+zoom_x));
 
822
    dev->gui_module->color_picker_box[3] = fminf(1.0, fmaxf(.5f+bzoom_y, .5f+zoom_y));
 
823
 
 
824
    dev->preview_pipe->changed |= DT_DEV_PIPE_SYNCH;
 
825
    dt_dev_invalidate_all(dev);
 
826
    dt_control_queue_draw_all();
 
827
    return;
 
828
  }
 
829
  if(dev->gui_module && dev->gui_module->mouse_moved) handled = dev->gui_module->mouse_moved(dev->gui_module, x, y, which);
 
830
  if(handled) return;
 
831
 
 
832
  if(darktable.control->button_down && darktable.control->button_down_which == 1)
 
833
  {
 
834
    // depending on dev_zoom, adjust dev_zoom_x/y.
 
835
    dt_dev_zoom_t zoom;
 
836
    int closeup;
 
837
    DT_CTL_GET_GLOBAL(zoom, dev_zoom);
 
838
    DT_CTL_GET_GLOBAL(closeup, dev_closeup);
 
839
    int procw, proch;
 
840
    dt_dev_get_processed_size(dev, &procw, &proch);
 
841
    const float scale = dt_dev_get_zoom_scale(dev, zoom, closeup ? 2 : 1, 0);
 
842
    float old_zoom_x, old_zoom_y;
 
843
    DT_CTL_GET_GLOBAL(old_zoom_x, dev_zoom_x);
 
844
    DT_CTL_GET_GLOBAL(old_zoom_y, dev_zoom_y);
 
845
    float zx = old_zoom_x - (1.0/scale)*(x - ctl->button_x - offx)/procw;
 
846
    float zy = old_zoom_y - (1.0/scale)*(y - ctl->button_y - offy)/proch;
 
847
    dt_dev_check_zoom_bounds(dev, &zx, &zy, zoom, closeup, NULL, NULL);
 
848
    DT_CTL_SET_GLOBAL(dev_zoom_x, zx);
 
849
    DT_CTL_SET_GLOBAL(dev_zoom_y, zy);
 
850
    ctl->button_x = x - offx;
 
851
    ctl->button_y = y - offy;
 
852
    dt_dev_invalidate(dev);
 
853
    dt_control_queue_draw_all();
 
854
  }
 
855
}
 
856
 
 
857
 
 
858
int button_released(dt_view_t *self, double x, double y, int which, uint32_t state)
 
859
{
 
860
  dt_develop_t *dev = darktable.develop;
 
861
  int handled = 0;
 
862
  if(dev->gui_module && dev->gui_module->button_released) handled = dev->gui_module->button_released(dev->gui_module, x, y, which, state);
 
863
  if(handled) return handled;
 
864
  if(which == 1) dt_control_change_cursor(GDK_LEFT_PTR);
 
865
  return 1;
 
866
}
 
867
 
 
868
 
 
869
int button_pressed(dt_view_t *self, double x, double y, int which, int type, uint32_t state)
 
870
{
 
871
  dt_develop_t *dev = (dt_develop_t *)self->data;
 
872
  const int32_t width_i  = self->width;
 
873
  const int32_t height_i = self->height;
 
874
  if(width_i  > DT_IMAGE_WINDOW_SIZE) x += (DT_IMAGE_WINDOW_SIZE-width_i) *.5f;
 
875
  if(height_i > DT_IMAGE_WINDOW_SIZE) y += (DT_IMAGE_WINDOW_SIZE-height_i)*.5f;
 
876
 
 
877
  int handled = 0;
 
878
  if(dev->gui_module && dev->gui_module->request_color_pick && which == 1)
 
879
  {
 
880
    float zoom_x, zoom_y;
 
881
    dt_dev_get_pointer_zoom_pos(dev, x, y, &zoom_x, &zoom_y);
 
882
    dev->gui_module->color_picker_box[0] = .5f+zoom_x;
 
883
    dev->gui_module->color_picker_box[1] = .5f+zoom_y;
 
884
    dev->gui_module->color_picker_box[2] = .5f+zoom_x;
 
885
    dev->gui_module->color_picker_box[3] = .5f+zoom_y;
 
886
    dt_control_queue_draw_all();
 
887
    return 1;
 
888
  }
 
889
  if(dev->gui_module && dev->gui_module->button_pressed) handled = dev->gui_module->button_pressed(dev->gui_module, x, y, which, type, state);
 
890
  if(handled) return handled;
 
891
 
 
892
  if(which == 1 && type == GDK_2BUTTON_PRESS) return 0;
 
893
  if(which == 1)
 
894
  {
 
895
    dt_control_change_cursor(GDK_HAND1);
 
896
    return 1;
 
897
  }
 
898
  if(which == 2)
 
899
  {
 
900
    // zoom to 1:1 2:1 and back
 
901
    dt_dev_zoom_t zoom;
 
902
    int closeup, procw, proch;
 
903
    float zoom_x, zoom_y;
 
904
    DT_CTL_GET_GLOBAL(zoom, dev_zoom);
 
905
    DT_CTL_GET_GLOBAL(closeup, dev_closeup);
 
906
    DT_CTL_GET_GLOBAL(zoom_x, dev_zoom_x);
 
907
    DT_CTL_GET_GLOBAL(zoom_y, dev_zoom_y);
 
908
    dt_dev_get_processed_size(dev, &procw, &proch);
 
909
    const float scale = dt_dev_get_zoom_scale(dev, zoom, closeup ? 2 : 1, 0);
 
910
    zoom_x += (1.0/scale)*(x - .5f*dev->width )/procw;
 
911
    zoom_y += (1.0/scale)*(y - .5f*dev->height)/proch;
 
912
    if(zoom == DT_ZOOM_1)
 
913
    {
 
914
      if(!closeup) closeup = 1;
 
915
      else
 
916
      {
 
917
        zoom = DT_ZOOM_FIT;
 
918
        zoom_x = zoom_y = 0.0f;
 
919
        closeup = 0;
 
920
      }
 
921
    }
 
922
    else zoom = DT_ZOOM_1;
 
923
    dt_dev_check_zoom_bounds(dev, &zoom_x, &zoom_y, zoom, closeup, NULL, NULL);
 
924
    DT_CTL_SET_GLOBAL(dev_zoom, zoom);
 
925
    DT_CTL_SET_GLOBAL(dev_closeup, closeup);
 
926
    DT_CTL_SET_GLOBAL(dev_zoom_x, zoom_x);
 
927
    DT_CTL_SET_GLOBAL(dev_zoom_y, zoom_y);
 
928
    dt_dev_invalidate(dev);
 
929
    return 1;
 
930
  }
 
931
  return 0;
 
932
}
 
933
 
 
934
 
 
935
void scrolled(dt_view_t *self, double x, double y, int up, int state)
 
936
{
 
937
  // free zoom
 
938
  dt_develop_t *dev = (dt_develop_t *)self->data;
 
939
  dt_dev_zoom_t zoom;
 
940
  int closeup, procw, proch;
 
941
  float zoom_x, zoom_y;
 
942
  DT_CTL_GET_GLOBAL(zoom, dev_zoom);
 
943
  DT_CTL_GET_GLOBAL(closeup, dev_closeup);
 
944
  DT_CTL_GET_GLOBAL(zoom_x, dev_zoom_x);
 
945
  DT_CTL_GET_GLOBAL(zoom_y, dev_zoom_y);
 
946
  dt_dev_get_processed_size(dev, &procw, &proch);
 
947
  float scale = dt_dev_get_zoom_scale(dev, zoom, closeup ? 2.0 : 1.0, 0);
 
948
  const float minscale = dt_dev_get_zoom_scale(dev, DT_ZOOM_FIT, 1.0, 0);
 
949
  // offset from center now (current zoom_{x,y} points there)
 
950
  float mouse_off_x = x - .5*dev->width, mouse_off_y = y - .5*dev->height;
 
951
  zoom_x += mouse_off_x/(procw*scale);
 
952
  zoom_y += mouse_off_y/(proch*scale);
 
953
  zoom = DT_ZOOM_FREE;
 
954
  closeup = 0;
 
955
  if(up) scale += .1f*(1.0f - minscale);
 
956
  else   scale -= .1f*(1.0f - minscale);
 
957
  DT_CTL_SET_GLOBAL(dev_zoom_scale, scale);
 
958
  if(scale > 0.99)            zoom = DT_ZOOM_1;
 
959
  if(scale < minscale + 0.01) zoom = DT_ZOOM_FIT;
 
960
  if(zoom != DT_ZOOM_1)
 
961
  {
 
962
    zoom_x -= mouse_off_x/(procw*scale);
 
963
    zoom_y -= mouse_off_y/(proch*scale);
 
964
  }
 
965
  dt_dev_check_zoom_bounds(dev, &zoom_x, &zoom_y, zoom, closeup, NULL, NULL);
 
966
  DT_CTL_SET_GLOBAL(dev_zoom, zoom);
 
967
  DT_CTL_SET_GLOBAL(dev_closeup, closeup);
 
968
  if(zoom != DT_ZOOM_1)
 
969
  {
 
970
    DT_CTL_SET_GLOBAL(dev_zoom_x, zoom_x);
 
971
    DT_CTL_SET_GLOBAL(dev_zoom_y, zoom_y);
 
972
  }
 
973
  dt_dev_invalidate(dev);
 
974
}
 
975
 
 
976
 
 
977
void border_scrolled(dt_view_t *view, double x, double y, int which, int up)
 
978
{
 
979
  dt_develop_t *dev = (dt_develop_t *)view->data;
 
980
  dt_dev_zoom_t zoom;
 
981
  int closeup;
 
982
  float zoom_x, zoom_y, scale;
 
983
  DT_CTL_GET_GLOBAL(zoom, dev_zoom);
 
984
  DT_CTL_GET_GLOBAL(closeup, dev_closeup);
 
985
  DT_CTL_GET_GLOBAL(zoom_x, dev_zoom_x);
 
986
  DT_CTL_GET_GLOBAL(zoom_y, dev_zoom_y);
 
987
  DT_CTL_GET_GLOBAL(scale, dev_zoom_scale);
 
988
  if(which > 1)
 
989
  {
 
990
    if(up) zoom_x -= 0.02;
 
991
    else   zoom_x += 0.02;
 
992
  }
 
993
  else
 
994
  {
 
995
    if(up) zoom_y -= 0.02;
 
996
    else   zoom_y += 0.02;
 
997
  }
 
998
  dt_dev_check_zoom_bounds(dev, &zoom_x, &zoom_y, zoom, closeup, NULL, NULL);
 
999
  DT_CTL_SET_GLOBAL(dev_zoom_x, zoom_x);
 
1000
  DT_CTL_SET_GLOBAL(dev_zoom_y, zoom_y);
 
1001
  dt_dev_invalidate(dev);
 
1002
  dt_control_queue_draw_all();
 
1003
}
 
1004
 
 
1005
 
 
1006
int key_pressed(dt_view_t *self, uint16_t which)
 
1007
{
 
1008
  dt_develop_t *dev = (dt_develop_t *)self->data;
 
1009
  int handled = 0;
 
1010
  if(dev->gui_module && dev->gui_module->key_pressed) handled = dev->gui_module->key_pressed(dev->gui_module, which);
 
1011
  if(handled) return handled;
 
1012
  return 0;
 
1013
}
 
1014
 
 
1015
 
 
1016
void configure(dt_view_t *self, int wd, int ht)
 
1017
{
 
1018
  dt_develop_t *dev = (dt_develop_t *)self->data;
 
1019
  dt_dev_configure(dev, wd, ht);
 
1020
}
 
1021