/* This file is part of darktable, Copyright (C) 2011-2026 darktable developers. darktable is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. darktable is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with darktable. If not, see . */ #pragma once #include "bauhaus/bauhaus.h" // FIXME: if we don't use histogram ROI this include can move to scopes/histogram.c #include "common/histogram.h" #include "common/iop_profile.h" #include "gui/gtk.h" G_BEGIN_DECLS typedef enum dt_scopes_mode_type_t { DT_SCOPES_MODE_VECTORSCOPE = 0, DT_SCOPES_MODE_WAVEFORM, DT_SCOPES_MODE_SPLIT, // must come after waveform and vectorscope DT_SCOPES_MODE_PARADE, // must come after waveform as uses waveform data DT_SCOPES_MODE_HISTOGRAM, DT_SCOPES_MODE_N // needs to be the last one } dt_scopes_mode_type_t; typedef enum dt_scopes_highlight_t { DT_SCOPES_HIGHLIGHT_NONE = 0, DT_SCOPES_HIGHLIGHT_BLACK_POINT, DT_SCOPES_HIGHLIGHT_EXPOSURE } dt_scopes_highlight_t; typedef enum dt_scopes_rgb_t { DT_SCOPES_RGB_RED = 0, DT_SCOPES_RGB_GREEN, DT_SCOPES_RGB_BLUE, DT_SCOPES_RGB_N // needs to be the last one } dt_scopes_rgb_t; typedef gboolean scopes_channels_t[DT_SCOPES_RGB_N]; struct dt_scopes_t; struct dt_scopes_mode_t; /** structure used to store pointers to the functions implementing scope modes */ /** plus a few per-class descriptive data items */ typedef struct dt_scopes_functions_t { // name (untranslated) of the current view const char* (*name)(const struct dt_scopes_mode_t *const self); void (*process)(struct dt_scopes_mode_t *const self, const float *const input, // FIXME: should ROI by dt_histogram_roi_t or another type? dt_histogram_roi_t *const roi, const dt_iop_order_iccprofile_info_t *vs_prof); // FIXME: do want a proper clear function or just tag as not up to date? void (*clear)(struct dt_scopes_mode_t *const self); void (*draw_bkgd)(const struct dt_scopes_mode_t *const self, cairo_t *cr, const int width, const int height); void (*draw_grid)(const struct dt_scopes_mode_t *const self, cairo_t *cr, const int width, const int height); void (*draw_highlight)(const struct dt_scopes_mode_t *const self, cairo_t *cr, dt_scopes_highlight_t highlight, const int width, const int height); void (*draw_scope)(const struct dt_scopes_mode_t *const self, cairo_t *cr, const int width, const int height); void (*draw_scope_channels)(const struct dt_scopes_mode_t *const self, cairo_t *cr, const int width, const int height, const scopes_channels_t channels); // FIXME: rename to something more sensible dt_scopes_highlight_t (*get_highlight)(const struct dt_scopes_mode_t *const self, const double posx, const double posy); // returns 0 <= pos <= 1 where a pos of 1 is a drag across the full // width/height of the scope (depending on mode exposure drag axis) double (*get_exposure_delta)(const struct dt_scopes_mode_t *const self, const double offset_x, const double offset_y); void (*append_to_tooltip)(const struct dt_scopes_mode_t *const self, gchar **tip); void (*eventbox_scroll)(struct dt_scopes_mode_t *const self, gdouble x, gdouble y, gdouble delta_x, gdouble delta_y, GdkModifierType state); // set option button icons to current state, updates tooltips // accordingly, and if necessary update any state which depends on // current option buttons void (*update_buttons)(const struct dt_scopes_mode_t *const self); void (*mode_enter)(struct dt_scopes_mode_t *const self); void (*mode_leave)(const struct dt_scopes_mode_t *const self); void (*gui_init)(struct dt_scopes_mode_t *const self, struct dt_scopes_t *const scopes); void (*add_options)(struct dt_scopes_mode_t *const mode, dt_action_t *dark); void (*gui_cleanup)(struct dt_scopes_mode_t *const self); } dt_scopes_functions_t; typedef struct dt_scopes_mode_t { const dt_scopes_functions_t *functions; void *data; GtkWidget *button_activate; // GtkDarktableToggleButton to activate GtkWidget *options_box; // GtkBox with option buttons gulong toggle_signal_handler; int update_counter; // point back to parent // FIXME: is this healthy? struct dt_scopes_t *scopes; } dt_scopes_mode_t; /** structure used to define internal storage for a scope */ typedef struct dt_scopes_t { dt_scopes_mode_t *cur_mode; // scope currently displayed // FIXME: should this be a GList which is appended with scopes on module init? dt_scopes_mode_t modes[DT_SCOPES_MODE_N]; // all available modes int update_counter; // most recent pixelpipe vs mode data dt_scopes_highlight_t highlight; // depends on mouse position scopes_channels_t channels; // display state chosen by RGB buttons gboolean dragging; // to block motion handling during drag gdouble last_offset_x, last_offset_y; // for drag handling // UI elements GtkWidget *overlay; // GtkOverlay -- scope and buttons GtkWidget *button_box_left; // GtkBox -- scope mode buttons GtkWidget *button_box_split; // GtkBox -- option buttons for left scope GtkWidget *outer_box_split; // GtkBox -- full-width wrapper positioning button_box_split GtkWidget *button_box_right; // GtkBox -- option buttons for main scope GtkWidget *button_box_rgb; // GtkBox -- RGB channels buttons GtkWidget *channel_buttons[DT_SCOPES_RGB_N]; // Array of GtkToggleButton -- RGB channels GtkWidget *scope_draw; // GtkDrawingArea -- scope & resize // for access to data during process/draw dt_pthread_mutex_t lock; } dt_scopes_t; /** the scope-specific function tables */ // FIXME: does this even need to be declared if it is set up within each scopes/*.c? extern const dt_scopes_functions_t dt_scopes_functions_histogram; extern const dt_scopes_functions_t dt_scopes_functions_waveform; extern const dt_scopes_functions_t dt_scopes_functions_parade; extern const dt_scopes_functions_t dt_scopes_functions_vectorscope; extern const dt_scopes_functions_t dt_scopes_functions_split; // FIXME: instead of making these extern & relying on linker (obscure?) make them part of dt_scopes_t? extern void lib_histogram_draw_bkgd(const dt_scopes_mode_t *const self, cairo_t *cr, const int width, const int height); // FIXME: is there any reason this needs to be called with an argument? extern void lib_histogram_update_tooltip(const dt_scopes_t *const scopes); #define dt_scopes_func_exists(mode, func) ((mode)->functions->func != NULL) // FIXME: print warning if func not defined in function table? -- but then how do we return a value? #define dt_scopes_call(mode, func, ...) (mode)->functions->func(mode, ##__VA_ARGS__) // FIXME: can make this return a value? #define dt_scopes_call_if_exists(mode, func, ...) \ { \ dt_scopes_mode_t *m = mode; \ if(m->functions->func) \ m->functions->func(m, ##__VA_ARGS__); \ } static inline void dt_scopes_refresh(const dt_scopes_t *const scopes) { gtk_widget_queue_draw(scopes->scope_draw); } static inline void dt_scopes_reprocess() { if(dt_view_get_current() == DT_VIEW_DARKROOM) dt_dev_process_preview(darktable.develop); else dt_control_queue_redraw_center(); } G_END_DECLS // clang-format off // modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py // vim: shiftwidth=2 expandtab tabstop=2 cindent // kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified; // clang-format on