"Fossies" - the Fresh Open Source Software Archive

Member "darktable-2.6.3/src/gui/guides.c" (20 Oct 2019, 16696 Bytes) of package /linux/misc/darktable-2.6.3.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "guides.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 2.6.3_vs_3.0.0.rc0.

    1 /*
    2  *    This file is part of darktable,
    3  *    copyright (c) 2012-2015 tobias ellinghaus.
    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 <glib.h>
   20 
   21 #include "bauhaus/bauhaus.h"
   22 #include "common/darktable.h"
   23 #include "gui/guides.h"
   24 
   25 typedef struct dt_QRect_t
   26 {
   27   float left, top, right, bottom, width, height;
   28 } dt_QRect_t;
   29 
   30 static void dt_guides_q_rect(dt_QRect_t *R1, float left, float top, float width, float height)
   31 {
   32   R1->left = left;
   33   R1->top = top;
   34   R1->right = left + width;
   35   R1->bottom = top + height;
   36   R1->width = width;
   37   R1->height = height;
   38 }
   39 
   40 
   41 static void dt_guides_draw_simple_grid(cairo_t *cr, const float x, const float y, const float w,
   42                                        const float h, float zoom_scale)
   43 {
   44   float right = x + w;
   45   float bottom = y + h;
   46   // cairo_set_operator(cr, CAIRO_OPERATOR_XOR);
   47   cairo_set_line_width(cr, 1.0 / zoom_scale);
   48   cairo_set_source_rgb(cr, .2, .2, .2);
   49   dt_draw_grid(cr, 3, x, y, right, bottom);
   50   cairo_translate(cr, 1.0 / zoom_scale, 1.0 / zoom_scale);
   51   cairo_set_source_rgb(cr, .8, .8, .8);
   52   dt_draw_grid(cr, 3, x, y, right, bottom);
   53   cairo_set_source_rgba(cr, .8, .8, .8, 0.5);
   54   double dashes = 5.0 / zoom_scale;
   55   cairo_set_dash(cr, &dashes, 1, 0);
   56   dt_draw_grid(cr, 9, x, y, right, bottom);
   57 }
   58 
   59 
   60 static void dt_guides_draw_diagonal_method(cairo_t *cr, const float x, const float y, const float w, const float h)
   61 {
   62   if(w > h)
   63   {
   64     dt_draw_line(cr, x, y, x + h, y + h);
   65     dt_draw_line(cr, x, y + h, x + h, y);
   66     dt_draw_line(cr, x + w - h, y, x + w, y + h);
   67     dt_draw_line(cr, x + w - h, y + h, x + w, y);
   68   }
   69   else
   70   {
   71     dt_draw_line(cr, x, y, x + w, y + w);
   72     dt_draw_line(cr, x, y + w, x + w, y);
   73     dt_draw_line(cr, x, y + h - w, x + w, y + h);
   74     dt_draw_line(cr, x, y + h, x + w, y + h - w);
   75   }
   76 }
   77 
   78 
   79 static void dt_guides_draw_rules_of_thirds(cairo_t *cr, const float left, const float top,
   80                                            const float width, const float height)
   81 {
   82   const float right = left + width, bottom = top + height;
   83   const float x_3 = width / 3.0, y_3 = height / 3.0;
   84 
   85   dt_draw_line(cr, left + x_3, top, left + x_3, bottom);
   86   dt_draw_line(cr, left + 2 * x_3, top, left + 2 * x_3, bottom);
   87 
   88   dt_draw_line(cr, left, top + y_3, right, top + y_3);
   89   dt_draw_line(cr, left, top + 2 * y_3, right, top + 2 * y_3);
   90 }
   91 
   92 
   93 static void dt_guides_draw_harmonious_triangles(cairo_t *cr, const float left, const float top, const float width,
   94                                                 const float height/*, const float dst*/)
   95 {
   96   int dst = (int)((height * cos(atan(width / height)) / (cos(atan(height / width)))));
   97 
   98   dt_draw_line(cr, -width / 2, -height / 2, width / 2, height / 2);
   99   dt_draw_line(cr, -width / 2 + dst, -height / 2, -width / 2, height / 2);
  100   dt_draw_line(cr, width / 2, -height / 2, width / 2 - dst, height / 2);
  101 }
  102 
  103 
  104 #define PERSPECTIVE_LINES 16
  105 static void dt_guides_draw_perspective(cairo_t *cr, const float x, const float y, const float w, const float h)
  106 {
  107   const float rotation_step = 2.0 / PERSPECTIVE_LINES,
  108               line_length = w * w + h * h; // no need for sqrt or *0.25, this is inside a cairo_clip anyway
  109 
  110   cairo_save(cr);
  111   for(int i = 0; i < PERSPECTIVE_LINES; i++)
  112   {
  113     cairo_save(cr);
  114     cairo_rotate(cr, -M_PI * rotation_step * i);
  115     dt_draw_line(cr, 0, 0, line_length, 0);
  116     cairo_restore(cr);
  117   }
  118   cairo_restore(cr);
  119 }
  120 #undef PERSPECTIVE_LINES
  121 
  122 
  123 #define X_LINES 49
  124 #define Y_LINES 33
  125 #define CROSSES 6
  126 static void dt_guides_draw_metering(cairo_t *cr, const float x, const float y, const float w, const float h)
  127 {
  128   const float x_step = w / (X_LINES - 1), y_step = h / (Y_LINES - 1), length_short = MIN(w, h) * 0.02,
  129               length_middle = length_short * 1.5,
  130               length_long = length_middle * 1.5; // these are effectively * 2!
  131 
  132   cairo_save(cr);
  133   cairo_translate(cr, x, y);
  134 
  135   // along x axis
  136   cairo_save(cr);
  137   cairo_translate(cr, 0, h * 0.5);
  138   for(int i = 0; i < X_LINES; i++)
  139     if(i % 4 != 0)
  140       dt_draw_line(cr, i * x_step, -length_short, i * x_step, length_short); // short lines
  141     else if(i % 12 != 0)
  142       dt_draw_line(cr, i * x_step, -length_middle, i * x_step, length_middle); // medium lines
  143     else if(i != X_LINES / 2)
  144       dt_draw_line(cr, i * x_step, -length_long, i * x_step, length_long); // long lines
  145     else
  146       dt_draw_line(cr, i * x_step, -h * 0.5, i * x_step, h * 0.5); // middle line
  147   cairo_restore(cr);
  148 
  149   // along y axis
  150   cairo_save(cr);
  151   cairo_translate(cr, w * 0.5, 0);
  152   for(int i = 0; i < Y_LINES; i++)
  153     if((i - 4) % 4 != 0)
  154       dt_draw_line(cr, -length_short, i * y_step, length_short, i * y_step); // short lines
  155     else if(i == Y_LINES / 2)
  156       dt_draw_line(cr, -w * 0.5, i * y_step, w * 0.5, i * y_step); // middle line
  157     else if((i - 4) % 12 != 0)
  158       dt_draw_line(cr, -length_middle, i * y_step, length_middle, i * y_step); // medium lines
  159     else
  160       dt_draw_line(cr, -length_long, i * y_step, length_long, i * y_step); // long lines
  161   cairo_restore(cr);
  162 
  163   // small crosses
  164   const float length_cross = length_short * .5, cross_x_step = w / CROSSES, cross_y_step = h / CROSSES;
  165   for(int cx = 1; cx < CROSSES; cx++)
  166     for(int cy = 1; cy < CROSSES; cy++)
  167       if(cx != CROSSES / 2 && cy != CROSSES / 2)
  168       {
  169         float _x = cx * cross_x_step, _y = cy * cross_y_step;
  170         dt_draw_line(cr, _x - length_cross, _y, _x + length_cross, _y);
  171         dt_draw_line(cr, _x, _y - length_cross, _x, _y + length_cross);
  172       }
  173   cairo_restore(cr);
  174 }
  175 #undef X_LINES
  176 #undef y_LINES
  177 #undef CROSSES
  178 
  179 #define RADIANS(degrees) ((degrees) * (M_PI / 180.))
  180 static void dt_guides_draw_golden_mean(cairo_t *cr, dt_QRect_t *R1, dt_QRect_t *R2, dt_QRect_t *R3, dt_QRect_t *R4,
  181                                        dt_QRect_t *R5, dt_QRect_t *R6, dt_QRect_t *R7, gboolean goldenSection,
  182                                        gboolean goldenTriangle, gboolean goldenSpiralSection, gboolean goldenSpiral)
  183 {
  184   // Drawing Golden sections.
  185   if(goldenSection)
  186   {
  187     // horizontal lines:
  188     dt_draw_line(cr, R1->left, R2->top, R2->right, R2->top);
  189     dt_draw_line(cr, R1->left, R1->top + R2->height, R2->right, R1->top + R2->height);
  190 
  191     // vertical lines:
  192     dt_draw_line(cr, R1->right, R1->top, R1->right, R1->bottom);
  193     dt_draw_line(cr, R1->left + R2->width, R1->top, R1->left + R2->width, R1->bottom);
  194   }
  195 
  196   // Drawing Golden triangle guides.
  197   if(goldenTriangle)
  198   {
  199     dt_draw_line(cr, R1->left, R1->bottom, R2->right, R1->top);
  200     dt_draw_line(cr, R1->left, R1->top, R2->right - R1->width, R1->bottom);
  201     dt_draw_line(cr, R1->left + R1->width, R1->top, R2->right, R1->bottom);
  202   }
  203 
  204   // Drawing Golden spiral sections.
  205   if(goldenSpiralSection)
  206   {
  207     dt_draw_line(cr, R1->right, R1->top, R1->right, R1->bottom);
  208     dt_draw_line(cr, R2->left, R2->top, R2->right, R2->top);
  209     dt_draw_line(cr, R3->left, R3->top, R3->left, R3->bottom);
  210     dt_draw_line(cr, R4->left, R4->bottom, R4->right, R4->bottom);
  211     dt_draw_line(cr, R5->right, R5->top, R5->right, R5->bottom);
  212     dt_draw_line(cr, R6->left, R6->top, R6->right, R6->top);
  213     dt_draw_line(cr, R7->left, R7->top, R7->left, R7->bottom);
  214   }
  215 
  216   // Drawing Golden Spiral.
  217   if(goldenSpiral)
  218   {
  219     cairo_save(cr);
  220     cairo_new_sub_path(cr);
  221     cairo_scale(cr, R1->width / R1->height, 1);
  222     cairo_arc(cr, R1->right / R1->width * R1->height, R1->top, R1->height, RADIANS(90), RADIANS(180));
  223     cairo_restore(cr);
  224 
  225     cairo_save(cr);
  226     cairo_new_sub_path(cr);
  227     cairo_scale(cr, R2->width / R2->height, 1);
  228     cairo_arc(cr, R2->left / R2->width * R2->height, R2->top, R2->height, RADIANS(0), RADIANS(90));
  229     cairo_restore(cr);
  230 
  231     cairo_save(cr);
  232     cairo_new_sub_path(cr);
  233     cairo_scale(cr, R3->width / R3->height, 1);
  234     cairo_arc(cr, R3->left / R3->width * R3->height, R3->bottom, R3->height, RADIANS(270), RADIANS(360));
  235     cairo_restore(cr);
  236 
  237     cairo_save(cr);
  238     cairo_new_sub_path(cr);
  239     cairo_scale(cr, 1, R4->height / R4->width);
  240     cairo_arc(cr, R4->right, R4->bottom / R4->height * R4->width, R4->width, RADIANS(180), RADIANS(270));
  241     cairo_restore(cr);
  242 
  243     cairo_save(cr);
  244     cairo_new_sub_path(cr);
  245     cairo_scale(cr, 1, R5->height / R5->width);
  246     cairo_arc(cr, R5->right, R5->top / R5->height * R5->width, R5->width, RADIANS(90), RADIANS(180));
  247     cairo_restore(cr);
  248 
  249     cairo_save(cr);
  250     cairo_new_sub_path(cr);
  251     cairo_scale(cr, 1, R6->height / R6->width);
  252     cairo_arc(cr, R6->left, R6->top / R6->height * R6->width, R6->width, RADIANS(0), RADIANS(90));
  253     cairo_restore(cr);
  254 
  255     cairo_save(cr);
  256     cairo_new_sub_path(cr);
  257     cairo_scale(cr, R7->width / R7->height, 1);
  258     cairo_arc(cr, R7->left / R7->width * R7->height, R7->bottom, R7->height, RADIANS(270), RADIANS(360));
  259     cairo_restore(cr);
  260 
  261     cairo_save(cr);
  262     cairo_new_sub_path(cr);
  263     cairo_scale(cr, (R6->width - R7->width) / R7->height, 1);
  264     cairo_arc(cr, R7->left / (R6->width - R7->width) * R7->height, R7->bottom, R7->height, RADIANS(210),
  265               RADIANS(270));
  266     cairo_restore(cr);
  267   }
  268 }
  269 #undef RADIANS
  270 
  271 
  272 ///////// wrappers for the guides system
  273 
  274 typedef struct _golden_mean_t
  275 {
  276   int which;
  277   gboolean golden_section;
  278   gboolean golden_triangle;
  279   gboolean golden_spiral_section;
  280   gboolean golden_spiral;
  281 } _golden_mean_t;
  282 
  283 static void _guides_draw_grid(cairo_t *cr, const float x, const float y,
  284                               const float w, const float h,
  285                               const float zoom_scale, void *user_data)
  286 {
  287   dt_guides_draw_simple_grid(cr, x, y, w, h, zoom_scale);
  288 }
  289 static void _guides_draw_rules_of_thirds(cairo_t *cr, const float x, const float y,
  290                                          const float w, const float h,
  291                                          const float zoom_scale, void *user_data)
  292 {
  293   dt_guides_draw_rules_of_thirds(cr, x, y, w, h);
  294 }
  295 static void _guides_draw_metering(cairo_t *cr, const float x, const float y,
  296                                   const float w, const float h,
  297                                   const float zoom_scale, void *user_data)
  298 {
  299   dt_guides_draw_metering(cr, x, y, w, h);
  300 }
  301 static void _guides_draw_perspective(cairo_t *cr, const float x, const float y,
  302                                      const float w, const float h,
  303                                      const float zoom_scale, void *user_data)
  304 {
  305   dt_guides_draw_perspective(cr, x, y, w, h);
  306 }
  307 static void _guides_draw_diagonal_method(cairo_t *cr, const float x, const float y,
  308                                          const float w, const float h,
  309                                          const float zoom_scale, void *user_data)
  310 {
  311   dt_guides_draw_diagonal_method(cr, x, y, w, h);
  312 }
  313 static void _guides_draw_harmonious_triangles(cairo_t *cr, const float x, const float y,
  314                                               const float w, const float h,
  315                                               const float zoom_scale, void *user_data)
  316 {
  317   dt_guides_draw_harmonious_triangles(cr, x, y, w, h);
  318 }
  319 static void _guides_draw_golden_mean(cairo_t *cr, const float x, const float y,
  320                                      const float w, const float h,
  321                                      const float zoom_scale, void *user_data)
  322 {
  323   _golden_mean_t *d = (_golden_mean_t *)user_data;
  324 
  325   // lengths for the golden mean and half the sizes of the region:
  326   float w_g = w * INVPHI;
  327   float h_g = h * INVPHI;
  328   float w_2 = w / 2;
  329   float h_2 = h / 2;
  330 
  331   dt_QRect_t R1, R2, R3, R4, R5, R6, R7;
  332   dt_guides_q_rect(&R1, -w_2, -h_2, w_g, h);
  333 
  334   // w - 2*w_2 corrects for one-pixel difference
  335   // so that R2.right() is really at the right end of the region
  336   dt_guides_q_rect(&R2, w_g - w_2, h_2 - h_g, w - w_g + 1 - (w - 2 * w_2), h_g);
  337   dt_guides_q_rect(&R3, w_2 - R2.width * INVPHI, -h_2, R2.width * INVPHI, h - R2.height);
  338   dt_guides_q_rect(&R4, R2.left, R1.top, R3.left - R2.left, R3.height * INVPHI);
  339   dt_guides_q_rect(&R5, R4.left, R4.bottom, R4.width * INVPHI, R3.height - R4.height);
  340   dt_guides_q_rect(&R6, R5.left + R5.width, R5.bottom - R5.height * INVPHI, R3.left - R5.right,
  341                    R5.height * INVPHI);
  342   dt_guides_q_rect(&R7, R6.right - R6.width * INVPHI, R4.bottom, R6.width * INVPHI, R5.height - R6.height);
  343 
  344   dt_guides_draw_golden_mean(cr, &R1, &R2, &R3, &R4, &R5, &R6, &R7, d->golden_section, d->golden_triangle,
  345                              d->golden_spiral_section, d->golden_spiral);
  346 }
  347 static inline void _golden_mean_set_data(_golden_mean_t *data, int which)
  348 {
  349   data->which = which;
  350   data->golden_section = which == 0 || which == 3;
  351   data->golden_triangle = 0;
  352   data->golden_spiral_section = which == 1 || which == 3;
  353   data->golden_spiral = which == 2 || which == 3;
  354 }
  355 static void _golden_mean_changed(GtkWidget *combo, _golden_mean_t *user_data)
  356 {
  357   int which = dt_bauhaus_combobox_get(combo);
  358 
  359   // remember setting
  360   dt_conf_set_int("plugins/darkroom/clipping/golden_extras", which);
  361 
  362   _golden_mean_set_data(user_data, which);
  363 
  364   dt_control_queue_redraw_center();
  365 }
  366 static GtkWidget *_guides_gui_golden_mean(dt_iop_module_t *self, void *user_data)
  367 {
  368   _golden_mean_t *data = (_golden_mean_t *)user_data;
  369   GtkWidget *golden_extras = dt_bauhaus_combobox_new(self);
  370   dt_bauhaus_widget_set_label(golden_extras, NULL, _("extra"));
  371   dt_bauhaus_combobox_add(golden_extras, _("golden sections"));
  372   dt_bauhaus_combobox_add(golden_extras, _("golden spiral sections"));
  373   dt_bauhaus_combobox_add(golden_extras, _("golden spiral"));
  374   dt_bauhaus_combobox_add(golden_extras, _("all"));
  375   gtk_widget_set_tooltip_text(golden_extras, _("show some extra guides"));
  376   dt_bauhaus_combobox_set(golden_extras, data->which);
  377   g_signal_connect(G_OBJECT(golden_extras), "value-changed", G_CALLBACK(_golden_mean_changed), user_data);
  378 
  379   return golden_extras;
  380 }
  381 
  382 
  383 static void _guides_add_guide(GList **list, const char *name,
  384                               dt_guides_draw_callback draw,
  385                               dt_guides_widget_callback widget,
  386                               void *user_data, GDestroyNotify free)
  387 {
  388   dt_guides_t *guide = (dt_guides_t *)malloc(sizeof(dt_guides_t));
  389   g_strlcpy(guide->name, name, sizeof(guide->name));
  390   guide->draw = draw;
  391   guide->widget = widget;
  392   guide->user_data = user_data;
  393   guide->free = free;
  394   *list = g_list_append(*list, guide);
  395 }
  396 
  397 void dt_guides_add_guide(const char *name, dt_guides_draw_callback draw, dt_guides_widget_callback widget, void *user_data, GDestroyNotify free)
  398 {
  399   _guides_add_guide(&darktable.guides, name, draw, widget, user_data, free);
  400 }
  401 
  402 GList *dt_guides_init()
  403 {
  404   GList *guides = NULL;
  405 
  406 
  407   _guides_add_guide(&guides, _("grid"), _guides_draw_grid, NULL, NULL, NULL); // TODO: make the number of lines configurable with a slider?
  408   _guides_add_guide(&guides, _("rules of thirds"), _guides_draw_rules_of_thirds, NULL, NULL, NULL);
  409   _guides_add_guide(&guides, _("metering"), _guides_draw_metering, NULL, NULL, NULL);
  410   _guides_add_guide(&guides, _("perspective"), _guides_draw_perspective, NULL, NULL, NULL); // TODO: make the number of lines configurable with a slider?
  411   _guides_add_guide(&guides, _("diagonal method"), _guides_draw_diagonal_method, NULL, NULL, NULL);
  412   _guides_add_guide(&guides, _("harmonious triangles"), _guides_draw_harmonious_triangles, NULL, NULL, NULL);
  413   {
  414     _golden_mean_t *user_data = (_golden_mean_t *)malloc(sizeof(_golden_mean_t));
  415     _golden_mean_set_data(user_data, dt_conf_get_int("plugins/darkroom/clipping/golden_extras"));
  416     _guides_add_guide(&guides, _("golden mean"), _guides_draw_golden_mean, _guides_gui_golden_mean, user_data, free);
  417   }
  418 
  419   return guides;
  420 }
  421 
  422 static void free_guide(void *data)
  423 {
  424   dt_guides_t *guide = (dt_guides_t *)data;
  425   if(guide->free) guide->free(guide->user_data);
  426   free(guide);
  427 }
  428 
  429 void dt_guides_cleanup(GList *guides)
  430 {
  431   g_list_free_full(guides, free_guide);
  432 }
  433 
  434 // modelines: These editor modelines have been set for all relevant files by tools/update_modelines.sh
  435 // vim: shiftwidth=2 expandtab tabstop=2 cindent
  436 // kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;