Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/editors/interface/eyedroppers/eyedropper_colorband.c')
-rw-r--r--source/blender/editors/interface/eyedroppers/eyedropper_colorband.c367
1 files changed, 367 insertions, 0 deletions
diff --git a/source/blender/editors/interface/eyedroppers/eyedropper_colorband.c b/source/blender/editors/interface/eyedroppers/eyedropper_colorband.c
new file mode 100644
index 00000000000..3f63a8020ed
--- /dev/null
+++ b/source/blender/editors/interface/eyedroppers/eyedropper_colorband.c
@@ -0,0 +1,367 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2009 Blender Foundation. All rights reserved. */
+
+/** \file
+ * \ingroup edinterface
+ *
+ * Eyedropper (Color Band).
+ *
+ * Operates by either:
+ * - Dragging a straight line, sampling pixels formed by the line to extract a gradient.
+ * - Clicking on points, adding each color to the end of the color-band.
+ *
+ * Defines:
+ * - #UI_OT_eyedropper_colorramp
+ * - #UI_OT_eyedropper_colorramp_point
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_screen_types.h"
+
+#include "BLI_bitmap_draw_2d.h"
+#include "BLI_math_vector.h"
+
+#include "BKE_colorband.h"
+#include "BKE_context.h"
+
+#include "RNA_access.h"
+#include "RNA_prototypes.h"
+
+#include "UI_interface.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "interface_intern.h"
+
+#include "eyedropper_intern.h"
+
+typedef struct Colorband_RNAUpdateCb {
+ PointerRNA ptr;
+ PropertyRNA *prop;
+} Colorband_RNAUpdateCb;
+
+typedef struct EyedropperColorband {
+ int event_xy_last[2];
+ /* Alpha is currently fixed at 1.0, may support in future. */
+ float (*color_buffer)[4];
+ int color_buffer_alloc;
+ int color_buffer_len;
+ bool sample_start;
+ ColorBand init_color_band;
+ ColorBand *color_band;
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ bool is_undo;
+ bool is_set;
+} EyedropperColorband;
+
+/* For user-data only. */
+struct EyedropperColorband_Context {
+ bContext *context;
+ EyedropperColorband *eye;
+};
+
+static bool eyedropper_colorband_init(bContext *C, wmOperator *op)
+{
+ ColorBand *band = NULL;
+
+ uiBut *but = UI_context_active_but_get(C);
+
+ PointerRNA rna_update_ptr = PointerRNA_NULL;
+ PropertyRNA *rna_update_prop = NULL;
+ bool is_undo = true;
+
+ if (but == NULL) {
+ /* pass */
+ }
+ else {
+ if (but->type == UI_BTYPE_COLORBAND) {
+ /* When invoked with a hotkey, we can find the band in 'but->poin'. */
+ band = (ColorBand *)but->poin;
+ }
+ else {
+ /* When invoked from a button it's in custom_data field. */
+ band = (ColorBand *)but->custom_data;
+ }
+
+ if (band) {
+ rna_update_ptr = ((Colorband_RNAUpdateCb *)but->func_argN)->ptr;
+ rna_update_prop = ((Colorband_RNAUpdateCb *)but->func_argN)->prop;
+ is_undo = UI_but_flag_is_set(but, UI_BUT_UNDO);
+ }
+ }
+
+ if (!band) {
+ const PointerRNA ptr = CTX_data_pointer_get_type(C, "color_ramp", &RNA_ColorRamp);
+ if (ptr.data != NULL) {
+ band = ptr.data;
+
+ /* Set this to a sub-member of the property to trigger an update. */
+ rna_update_ptr = ptr;
+ rna_update_prop = &rna_ColorRamp_color_mode;
+ is_undo = RNA_struct_undo_check(ptr.type);
+ }
+ }
+
+ if (!band) {
+ return false;
+ }
+
+ EyedropperColorband *eye = MEM_callocN(sizeof(EyedropperColorband), __func__);
+ eye->color_buffer_alloc = 16;
+ eye->color_buffer = MEM_mallocN(sizeof(*eye->color_buffer) * eye->color_buffer_alloc, __func__);
+ eye->color_buffer_len = 0;
+ eye->color_band = band;
+ eye->init_color_band = *eye->color_band;
+ eye->ptr = rna_update_ptr;
+ eye->prop = rna_update_prop;
+ eye->is_undo = is_undo;
+
+ op->customdata = eye;
+
+ return true;
+}
+
+static void eyedropper_colorband_sample_point(bContext *C,
+ EyedropperColorband *eye,
+ const int m_xy[2])
+{
+ if (eye->event_xy_last[0] != m_xy[0] || eye->event_xy_last[1] != m_xy[1]) {
+ float col[4];
+ col[3] = 1.0f; /* TODO: sample alpha */
+ eyedropper_color_sample_fl(C, m_xy, col);
+ if (eye->color_buffer_len + 1 == eye->color_buffer_alloc) {
+ eye->color_buffer_alloc *= 2;
+ eye->color_buffer = MEM_reallocN(eye->color_buffer,
+ sizeof(*eye->color_buffer) * eye->color_buffer_alloc);
+ }
+ copy_v4_v4(eye->color_buffer[eye->color_buffer_len], col);
+ eye->color_buffer_len += 1;
+ copy_v2_v2_int(eye->event_xy_last, m_xy);
+ eye->is_set = true;
+ }
+}
+
+static bool eyedropper_colorband_sample_callback(int mx, int my, void *userdata)
+{
+ struct EyedropperColorband_Context *data = userdata;
+ bContext *C = data->context;
+ EyedropperColorband *eye = data->eye;
+ const int cursor[2] = {mx, my};
+ eyedropper_colorband_sample_point(C, eye, cursor);
+ return true;
+}
+
+static void eyedropper_colorband_sample_segment(bContext *C,
+ EyedropperColorband *eye,
+ const int m_xy[2])
+{
+ /* Since the mouse tends to move rather rapidly we use #BLI_bitmap_draw_2d_line_v2v2i
+ * to interpolate between the reported coordinates */
+ struct EyedropperColorband_Context userdata = {C, eye};
+ BLI_bitmap_draw_2d_line_v2v2i(
+ eye->event_xy_last, m_xy, eyedropper_colorband_sample_callback, &userdata);
+}
+
+static void eyedropper_colorband_exit(bContext *C, wmOperator *op)
+{
+ WM_cursor_modal_restore(CTX_wm_window(C));
+
+ if (op->customdata) {
+ EyedropperColorband *eye = op->customdata;
+ MEM_freeN(eye->color_buffer);
+ MEM_freeN(eye);
+ op->customdata = NULL;
+ }
+}
+
+static void eyedropper_colorband_apply(bContext *C, wmOperator *op)
+{
+ EyedropperColorband *eye = op->customdata;
+ /* Always filter, avoids noise in resulting color-band. */
+ const bool filter_samples = true;
+ BKE_colorband_init_from_table_rgba(
+ eye->color_band, eye->color_buffer, eye->color_buffer_len, filter_samples);
+ eye->is_set = true;
+ if (eye->prop) {
+ RNA_property_update(C, &eye->ptr, eye->prop);
+ }
+}
+
+static void eyedropper_colorband_cancel(bContext *C, wmOperator *op)
+{
+ EyedropperColorband *eye = op->customdata;
+ if (eye->is_set) {
+ *eye->color_band = eye->init_color_band;
+ if (eye->prop) {
+ RNA_property_update(C, &eye->ptr, eye->prop);
+ }
+ }
+ eyedropper_colorband_exit(C, op);
+}
+
+/* main modal status check */
+static int eyedropper_colorband_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ EyedropperColorband *eye = op->customdata;
+ /* handle modal keymap */
+ if (event->type == EVT_MODAL_MAP) {
+ switch (event->val) {
+ case EYE_MODAL_CANCEL:
+ eyedropper_colorband_cancel(C, op);
+ return OPERATOR_CANCELLED;
+ case EYE_MODAL_SAMPLE_CONFIRM: {
+ const bool is_undo = eye->is_undo;
+ eyedropper_colorband_sample_segment(C, eye, event->xy);
+ eyedropper_colorband_apply(C, op);
+ eyedropper_colorband_exit(C, op);
+ /* Could support finished & undo-skip. */
+ return is_undo ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+ }
+ case EYE_MODAL_SAMPLE_BEGIN:
+ /* enable accum and make first sample */
+ eye->sample_start = true;
+ eyedropper_colorband_sample_point(C, eye, event->xy);
+ eyedropper_colorband_apply(C, op);
+ copy_v2_v2_int(eye->event_xy_last, event->xy);
+ break;
+ case EYE_MODAL_SAMPLE_RESET:
+ break;
+ }
+ }
+ else if (event->type == MOUSEMOVE) {
+ if (eye->sample_start) {
+ eyedropper_colorband_sample_segment(C, eye, event->xy);
+ eyedropper_colorband_apply(C, op);
+ }
+ }
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int eyedropper_colorband_point_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ EyedropperColorband *eye = op->customdata;
+ /* handle modal keymap */
+ if (event->type == EVT_MODAL_MAP) {
+ switch (event->val) {
+ case EYE_MODAL_POINT_CANCEL:
+ eyedropper_colorband_cancel(C, op);
+ return OPERATOR_CANCELLED;
+ case EYE_MODAL_POINT_CONFIRM:
+ eyedropper_colorband_apply(C, op);
+ eyedropper_colorband_exit(C, op);
+ return OPERATOR_FINISHED;
+ case EYE_MODAL_POINT_REMOVE_LAST:
+ if (eye->color_buffer_len > 0) {
+ eye->color_buffer_len -= 1;
+ eyedropper_colorband_apply(C, op);
+ }
+ break;
+ case EYE_MODAL_POINT_SAMPLE:
+ eyedropper_colorband_sample_point(C, eye, event->xy);
+ eyedropper_colorband_apply(C, op);
+ if (eye->color_buffer_len == MAXCOLORBAND) {
+ eyedropper_colorband_exit(C, op);
+ return OPERATOR_FINISHED;
+ }
+ break;
+ case EYE_MODAL_SAMPLE_RESET:
+ *eye->color_band = eye->init_color_band;
+ if (eye->prop) {
+ RNA_property_update(C, &eye->ptr, eye->prop);
+ }
+ eye->color_buffer_len = 0;
+ break;
+ }
+ }
+ return OPERATOR_RUNNING_MODAL;
+}
+
+/* Modal Operator init */
+static int eyedropper_colorband_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ /* init */
+ if (eyedropper_colorband_init(C, op)) {
+ wmWindow *win = CTX_wm_window(C);
+ /* Workaround for de-activating the button clearing the cursor, see T76794 */
+ UI_context_active_but_clear(C, win, CTX_wm_region(C));
+ WM_cursor_modal_set(win, WM_CURSOR_EYEDROPPER);
+
+ /* add temp handler */
+ WM_event_add_modal_handler(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+ }
+ return OPERATOR_CANCELLED;
+}
+
+/* Repeat operator */
+static int eyedropper_colorband_exec(bContext *C, wmOperator *op)
+{
+ /* init */
+ if (eyedropper_colorband_init(C, op)) {
+
+ /* do something */
+
+ /* cleanup */
+ eyedropper_colorband_exit(C, op);
+
+ return OPERATOR_FINISHED;
+ }
+ return OPERATOR_CANCELLED;
+}
+
+static bool eyedropper_colorband_poll(bContext *C)
+{
+ uiBut *but = UI_context_active_but_get(C);
+ if (but && but->type == UI_BTYPE_COLORBAND) {
+ return true;
+ }
+ const PointerRNA ptr = CTX_data_pointer_get_type(C, "color_ramp", &RNA_ColorRamp);
+ if (ptr.data != NULL) {
+ return true;
+ }
+ return false;
+}
+
+void UI_OT_eyedropper_colorramp(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Eyedropper Colorband";
+ ot->idname = "UI_OT_eyedropper_colorramp";
+ ot->description = "Sample a color band";
+
+ /* api callbacks */
+ ot->invoke = eyedropper_colorband_invoke;
+ ot->modal = eyedropper_colorband_modal;
+ ot->cancel = eyedropper_colorband_cancel;
+ ot->exec = eyedropper_colorband_exec;
+ ot->poll = eyedropper_colorband_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_INTERNAL;
+
+ /* properties */
+}
+
+void UI_OT_eyedropper_colorramp_point(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Eyedropper Colorband (Points)";
+ ot->idname = "UI_OT_eyedropper_colorramp_point";
+ ot->description = "Point-sample a color band";
+
+ /* api callbacks */
+ ot->invoke = eyedropper_colorband_invoke;
+ ot->modal = eyedropper_colorband_point_modal;
+ ot->cancel = eyedropper_colorband_cancel;
+ ot->exec = eyedropper_colorband_exec;
+ ot->poll = eyedropper_colorband_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_INTERNAL;
+
+ /* properties */
+}