summaryrefslogtreecommitdiffstats
path: root/src/ui/tools/dropper-tool.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui/tools/dropper-tool.cpp')
-rw-r--r--src/ui/tools/dropper-tool.cpp265
1 files changed, 142 insertions, 123 deletions
diff --git a/src/ui/tools/dropper-tool.cpp b/src/ui/tools/dropper-tool.cpp
index 99177dc75..53a99e481 100644
--- a/src/ui/tools/dropper-tool.cpp
+++ b/src/ui/tools/dropper-tool.cpp
@@ -39,6 +39,8 @@
#include "pixmaps/cursor-dropper-f.xpm"
#include "pixmaps/cursor-dropper-s.xpm"
+#include "pixmaps/cursor-dropping-f.xpm"
+#include "pixmaps/cursor-dropping-s.xpm"
#include "ui/tools/dropper-tool.h"
#include "message-context.h"
@@ -46,9 +48,6 @@
using Inkscape::DocumentUndo;
-static GdkCursor *cursor_dropper_fill = NULL;
-static GdkCursor *cursor_dropper_stroke = NULL;
-
namespace Inkscape {
namespace UI {
namespace Tools {
@@ -60,18 +59,20 @@ const std::string& DropperTool::getPrefsPath() {
const std::string DropperTool::prefsPath = "/tools/dropper";
DropperTool::DropperTool()
- : ToolBase(cursor_dropper_f_xpm, 5, 5)
+ : ToolBase(cursor_dropper_f_xpm)
, R(0)
, G(0)
, B(0)
, alpha(0)
+ , radius(0)
+ , invert(false)
+ , stroke(false)
+ , dropping(false)
, dragging(false)
, grabbed(NULL)
, area(NULL)
, centre(0, 0)
{
- cursor_dropper_fill = sp_cursor_new_from_xpm(cursor_dropper_f_xpm , 5, 5);
- cursor_dropper_stroke = sp_cursor_new_from_xpm(cursor_dropper_s_xpm , 5, 5);
}
DropperTool::~DropperTool() {
@@ -117,41 +118,84 @@ void DropperTool::finish() {
this->area = NULL;
}
- if (cursor_dropper_fill) {
- g_object_unref(cursor_dropper_fill);
- cursor_dropper_fill = NULL;
- }
-
- if (cursor_dropper_stroke) {
- g_object_unref(cursor_dropper_stroke);
- cursor_dropper_fill = NULL;
- }
-
ToolBase::finish();
}
/**
* Returns the current dropper context color.
*/
-guint32 DropperTool::get_color() {
+guint32 DropperTool::get_color(bool invert) {
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
int pick = prefs->getInt("/tools/dropper/pick", SP_DROPPER_PICK_VISIBLE);
bool setalpha = prefs->getBool("/tools/dropper/setalpha", true);
- return SP_RGBA32_F_COMPOSE(this->R,
- this->G,
- this->B,
- (pick == SP_DROPPER_PICK_ACTUAL && setalpha) ? this->alpha : 1.0);
+ return SP_RGBA32_F_COMPOSE(
+ fabs(invert - this->R),
+ fabs(invert - this->G),
+ fabs(invert - this->B),
+ (pick == SP_DROPPER_PICK_ACTUAL && setalpha) ? this->alpha : 1.0);
}
bool DropperTool::root_handler(GdkEvent* event) {
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
int ret = FALSE;
-
int pick = prefs->getInt("/tools/dropper/pick", SP_DROPPER_PICK_VISIBLE);
- bool setalpha = prefs->getBool("/tools/dropper/setalpha", true);
+
+ // Decide first what kind of 'mode' we're in.
+ if (event->type == GDK_KEY_PRESS || event->type == GDK_KEY_RELEASE) {
+ switch (event->key.keyval) {
+ case GDK_KEY_Shift_L:
+ case GDK_KEY_Shift_R:
+ this->stroke = event->type == GDK_KEY_PRESS;
+ break;
+ case GDK_KEY_Control_L:
+ case GDK_KEY_Control_R:
+ this->dropping = event->type == GDK_KEY_PRESS;
+ break;
+ case GDK_KEY_Alt_L:
+ case GDK_KEY_Alt_R:
+ this->invert = event->type == GDK_KEY_PRESS;
+ break;
+ }
+ }
+
+ // Get color from selected object instead.
+ if(this->dropping) {
+ Inkscape::Selection *selection = desktop->getSelection();
+ g_assert(selection);
+ guint32 apply_color;
+ bool apply_set = false;
+ for (auto& obj: selection->objects()) {
+ if(obj->style) {
+ double opacity = 1.0;
+ if(!this->stroke && obj->style->fill.set) {
+ if(obj->style->fill_opacity.set) {
+ opacity = obj->style->fill_opacity.value;
+ }
+ apply_color = obj->style->fill.value.color.toRGBA32(opacity);
+ apply_set = true;
+ } else if(this->stroke && obj->style->stroke.set) {
+ if(obj->style->stroke_opacity.set) {
+ opacity = obj->style->stroke_opacity.value;
+ }
+ apply_color = obj->style->stroke.value.color.toRGBA32(opacity);
+ apply_set = true;
+ }
+ }
+ }
+ if(apply_set) {
+ this->R = SP_RGBA32_R_F(apply_color);
+ this->G = SP_RGBA32_G_F(apply_color);
+ this->B = SP_RGBA32_B_F(apply_color);
+ this->alpha = SP_RGBA32_A_F(apply_color);
+ } else {
+ // This means that having no selection or some other error
+ // we will default back to normal dropper mode.
+ this->dropping = false;
+ }
+ }
switch (event->type) {
case GDK_BUTTON_PRESS:
@@ -160,11 +204,12 @@ bool DropperTool::root_handler(GdkEvent* event) {
this->dragging = true;
ret = TRUE;
}
-
- sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate),
- GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK,
- NULL, event->button.time);
- this->grabbed = SP_CANVAS_ITEM(desktop->acetate);
+
+ sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate),
+ GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_BUTTON_RELEASE_MASK |
+ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK,
+ NULL, event->button.time);
+ this->grabbed = SP_CANVAS_ITEM(desktop->acetate);
break;
case GDK_MOTION_NOTIFY:
@@ -174,14 +219,6 @@ bool DropperTool::root_handler(GdkEvent* event) {
break;
} else if (!this->space_panning) {
// otherwise, constantly calculate color no matter is any button pressed or not
-
- // If one time pick with stroke set the pixmap
- if (prefs->getBool("/tools/dropper/onetimepick", false) && prefs->getInt("/dialogs/fillstroke/page", 0) == 1) {
- //TODO Only set when not set already
- GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(desktop->getCanvas()));
- gdk_window_set_cursor(window, cursor_dropper_stroke);
- }
-
double rw = 0.0;
double R(0), G(0), B(0), A(0);
@@ -190,10 +227,10 @@ bool DropperTool::root_handler(GdkEvent* event) {
// radius
rw = std::min(Geom::L2(Geom::Point(event->button.x, event->button.y) - this->centre), 400.0);
-
if (rw == 0) { // happens sometimes, little idea why...
break;
}
+ this->radius = rw;
Geom::Point const cd = desktop->w2d(this->centre);
Geom::Affine const w2dt = desktop->w2d();
@@ -242,74 +279,57 @@ bool DropperTool::root_handler(GdkEvent* event) {
}
// remember color
- this->R = R;
- this->G = G;
- this->B = B;
- this->alpha = A;
-
- // status message
- double alpha_to_set = setalpha? this->alpha : 1.0;
- guint32 c32 = SP_RGBA32_F_COMPOSE(R, G, B, alpha_to_set);
-
- gchar c[64];
- sp_svg_write_color(c, sizeof(c), c32);
-
- // alpha of color under cursor, to show in the statusbar
- // locale-sensitive printf is OK, since this goes to the UI, not into SVG
- gchar *alpha = g_strdup_printf(_(" alpha %.3g"), alpha_to_set);
- // where the color is picked, to show in the statusbar
- gchar *where = this->dragging ? g_strdup_printf(_(", averaged with radius %d"), (int) rw) : g_strdup_printf("%s", _(" under cursor"));
- // message, to show in the statusbar
- const gchar *message = this->dragging ? _("<b>Release mouse</b> to set color.") : _("<b>Click</b> to set fill, <b>Shift+click</b> to set stroke; <b>drag</b> to average color in area; with <b>Alt</b> to pick inverse color; <b>Ctrl+C</b> to copy the color under mouse to clipboard");
-
- this->defaultMessageContext()->setF(
- Inkscape::NORMAL_MESSAGE,
- "<b>%s%s</b>%s. %s", c,
- (pick == SP_DROPPER_PICK_VISIBLE) ? "" : alpha, where, message);
-
- g_free(where);
- g_free(alpha);
-
+ if(!this->dropping && (R != this->R || G != this->G || B != this->B || A != this->alpha)) {
+ this->R = R;
+ this->G = G;
+ this->B = B;
+ this->alpha = A;
+ }
ret = TRUE;
}
break;
case GDK_BUTTON_RELEASE:
if (event->button.button == 1 && !this->space_panning) {
- sp_canvas_item_hide(this->area);
- this->dragging = false;
-
- if (this->grabbed) {
- sp_canvas_item_ungrab(this->grabbed, event->button.time);
- this->grabbed = NULL;
- }
-
- double alpha_to_set = setalpha? this->alpha : 1.0;
-
- bool fill = !(event->button.state & GDK_SHIFT_MASK); // Stroke if Shift key held
-
- if (prefs->getBool("/tools/dropper/onetimepick", false)) {
- // "One time" pick from Fill/Stroke dialog stroke page, always apply fill or stroke (ignore <Shift> key)
- fill = (prefs->getInt("/dialogs/fillstroke/page", 0) == 0) ? true : false;
+ sp_canvas_item_hide(this->area);
+ this->dragging = false;
+
+ if (this->grabbed) {
+ sp_canvas_item_ungrab(this->grabbed, event->button.time);
+ this->grabbed = NULL;
+ }
+
+ Inkscape::Selection *selection = desktop->getSelection();
+ g_assert(selection);
+ std::vector<SPItem *> old_selection(selection->items().begin(), selection->items().end());
+ if(this->dropping) {
+ Geom::Point const button_w(event->button.x, event->button.y);
+ // remember clicked item, disregarding groups, honoring Alt
+ this->item_to_select = sp_event_context_find_item (desktop, button_w, event->button.state & GDK_MOD1_MASK, TRUE);
+
+ // Change selected object to object under cursor
+ if (this->item_to_select) {
+ std::vector<SPItem *> vec(selection->items().begin(), selection->items().end());
+ selection->set(this->item_to_select);
+ }
+ } else {
+ if (prefs->getBool("/tools/dropper/onetimepick", false)) {
+ // "One time" pick from Fill/Stroke dialog stroke page, always apply fill or stroke (ignore <Shift> key)
+ //fill = (prefs->getInt("/dialogs/fillstroke/page", 0) == 0) ? true : false;
+ }
}
// do the actual color setting
- sp_desktop_set_color(desktop,
- (event->button.state & GDK_MOD1_MASK)?
- ColorRGBA(1 - this->R, 1 - this->G, 1 - this->B, alpha_to_set) : ColorRGBA(this->R, this->G, this->B, alpha_to_set),
- false, fill);
+ sp_desktop_set_color(desktop, ColorRGBA(this->get_color(this->invert)), false, !this->stroke);
// REJON: set aux. toolbar input to hex color!
-
- if (event->button.state & GDK_SHIFT_MASK) {
- GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(desktop->getCanvas()));
- gdk_window_set_cursor(window, cursor_dropper_stroke);
- }
-
if (!(desktop->getSelection()->isEmpty())) {
DocumentUndo::done(desktop->getDocument(), SP_VERB_CONTEXT_DROPPER,
_("Set picked color"));
}
+ if(this->dropping) {
+ selection->setList(old_selection);
+ }
if (prefs->getBool("/tools/dropper/onetimepick", false)) {
prefs->setBool("/tools/dropper/onetimepick", false);
@@ -326,50 +346,49 @@ bool DropperTool::root_handler(GdkEvent* event) {
case GDK_KEY_PRESS:
switch (get_group0_keyval(&event->key)) {
- case GDK_KEY_Up:
- case GDK_KEY_Down:
- case GDK_KEY_KP_Up:
- case GDK_KEY_KP_Down:
+ case GDK_KEY_Up:
+ case GDK_KEY_Down:
+ case GDK_KEY_KP_Up:
+ case GDK_KEY_KP_Down:
// prevent the zoom field from activation
if (!MOD__CTRL_ONLY(event)) {
ret = TRUE;
}
break;
-
- case GDK_KEY_Escape:
+ case GDK_KEY_Escape:
desktop->getSelection()->clear();
- case GDK_KEY_Shift_L:
- case GDK_KEY_Shift_R:
- if (!desktop->isWaitingCursor() && !prefs->getBool("/tools/dropper/onetimepick", false)) {
- GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(desktop->getCanvas()));
- gdk_window_set_cursor(window, cursor_dropper_stroke);
- }
-
- break;
- default:
break;
}
break;
-
- case GDK_KEY_RELEASE:
- switch (get_group0_keyval(&event->key)) {
- case GDK_KEY_Shift_L:
- case GDK_KEY_Shift_R:
- if (!desktop->isWaitingCursor() && !prefs->getBool("/tools/dropper/onetimepick", false)) {
- GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(desktop->getCanvas()));
- gdk_window_set_cursor(window, cursor_dropper_fill);
- }
- break;
-
- default:
- break;
- }
- break;
-
- default:
- break;
}
+ // set the status message to the right text.
+ gchar c[64];
+ sp_svg_write_color(c, sizeof(c), this->get_color(this->invert));
+
+ // alpha of color under cursor, to show in the statusbar
+ // locale-sensitive printf is OK, since this goes to the UI, not into SVG
+ gchar *alpha = g_strdup_printf(_(" alpha %.3g"), this->alpha);
+ // where the color is picked, to show in the statusbar
+ gchar *where = this->dragging ? g_strdup_printf(_(", averaged with radius %d"), (int) this->radius) : g_strdup_printf("%s", _(" under cursor"));
+ // message, to show in the statusbar
+ const gchar *message = this->dragging ? _("<b>Release mouse</b> to set color.") : _("<b>Click</b> to set fill, <b>Shift+click</b> to set stroke; <b>drag</b> to average color in area; with <b>Alt</b> to pick inverse color; <b>Ctrl+C</b> to copy the color under mouse to clipboard");
+
+ this->defaultMessageContext()->setF(
+ Inkscape::NORMAL_MESSAGE,
+ "<b>%s%s</b>%s. %s", c,
+ (pick == SP_DROPPER_PICK_VISIBLE) ? "" : alpha, where, message);
+
+ g_free(where);
+ g_free(alpha);
+
+ // Set the right cursor for the mode and apply the special Fill color
+ auto xpm = (this->dropping ? (this->stroke ? cursor_dropping_s_xpm : cursor_dropping_f_xpm) :
+ (this->stroke ? cursor_dropper_s_xpm : cursor_dropper_f_xpm));
+ GdkCursor *cursor = sp_cursor_from_xpm(xpm, this->get_color(this->invert));
+ GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(desktop->getCanvas()));
+ gdk_window_set_cursor(window, cursor);
+
if (!ret) {
ret = ToolBase::root_handler(event);
}