From 1771eb1d62c6aef4e094f43df1ac1412d0176f35 Mon Sep 17 00:00:00 2001 From: Jasper van de Gronde Date: Mon, 6 Sep 2010 11:16:22 +0200 Subject: [PATCH] Color preview in cursor --- src/arc-context.cpp | 1 + src/desktop-style.cpp | 5 ++ src/event-context.cpp | 46 ++++++++++++++----- src/event-context.h | 2 + src/pixmaps/cursor-ellipse.xpm | 26 ++++++----- src/pixmaps/cursor-rect.xpm | 26 ++++++----- src/pixmaps/cursor-star.xpm | 34 +++++++------- src/rect-context.cpp | 1 + src/sp-cursor.cpp | 83 ++++++++++++++++++++++++++++++++-- src/sp-cursor.h | 1 + src/star-context.cpp | 1 + 11 files changed, 170 insertions(+), 56 deletions(-) diff --git a/src/arc-context.cpp b/src/arc-context.cpp index 3c0d9ccda..ddfb8f923 100644 --- a/src/arc-context.cpp +++ b/src/arc-context.cpp @@ -107,6 +107,7 @@ static void sp_arc_context_init(SPArcContext *arc_context) event_context->tolerance = 0; event_context->within_tolerance = false; event_context->item_to_select = NULL; + event_context->tool_url = "/tools/shapes/arc"; arc_context->item = NULL; diff --git a/src/desktop-style.cpp b/src/desktop-style.cpp index 5866b14fb..5615a8ea9 100644 --- a/src/desktop-style.cpp +++ b/src/desktop-style.cpp @@ -41,6 +41,7 @@ #include "xml/repr.h" #include "libnrtype/font-style-to-pos.h" #include "sp-path.h" +#include "event-context.h" #include "desktop-style.h" #include "svg/svg-icc-color.h" @@ -195,6 +196,10 @@ sp_desktop_set_style(SPDesktop *desktop, SPCSSAttr *css, bool change, bool write // 3. If nobody has intercepted the signal, apply the style to the selection if (!intercepted) { + // If we have an event context, update its cursor (TODO: it could be neater to do this with the signal sent above, but what if the signal gets intercepted?) + if (desktop->event_context) { + sp_event_context_update_cursor(desktop->event_context); + } // Remove text attributes if not text... // Do this once in case a zillion objects are selected. diff --git a/src/event-context.cpp b/src/event-context.cpp index 5d60379c8..56f875844 100644 --- a/src/event-context.cpp +++ b/src/event-context.cpp @@ -44,6 +44,7 @@ #include "desktop.h" #include "desktop-handles.h" #include "desktop-events.h" +#include "desktop-style.h" #include "widgets/desktop-widget.h" #include "sp-namedview.h" #include "selection.h" @@ -62,6 +63,7 @@ #include "ui/tool/control-point.h" #include "shape-editor.h" #include "sp-guide.h" +#include "color.h" static void sp_event_context_class_init(SPEventContextClass *klass); static void sp_event_context_init(SPEventContext *event_context); @@ -141,6 +143,7 @@ static void sp_event_context_init(SPEventContext *event_context) { event_context->shape_editor = NULL; event_context->_delayed_snap_event = NULL; event_context->_dse_callback_in_process = false; + event_context->tool_url = NULL; } /** @@ -183,17 +186,38 @@ void sp_event_context_update_cursor(SPEventContext *ec) { if (w->window) { /* fixme: */ if (ec->cursor_shape) { - GdkBitmap *bitmap = NULL; - GdkBitmap *mask = NULL; - sp_cursor_bitmap_and_mask_from_xpm(&bitmap, &mask, ec->cursor_shape); - if ((bitmap != NULL) && (mask != NULL)) { - if (ec->cursor) - gdk_cursor_unref(ec->cursor); - ec->cursor = gdk_cursor_new_from_pixmap(bitmap, mask, - &w->style->black, &w->style->white, ec->hot_x, - ec->hot_y); - g_object_unref(bitmap); - g_object_unref(mask); + GdkDisplay *display = gdk_display_get_default(); + if (ec->tool_url && gdk_display_supports_cursor_alpha(display) && gdk_display_supports_cursor_color(display)) { + bool fillHasColor=false, strokeHasColor=false; + guint32 fillColor = sp_desktop_get_color_tool(ec->desktop, ec->tool_url, true, &fillHasColor); + guint32 strokeColor = sp_desktop_get_color_tool(ec->desktop, ec->tool_url, false, &strokeHasColor); + double fillOpacity = fillHasColor ? sp_desktop_get_opacity_tool(ec->desktop, ec->tool_url, true) : 0; + double strokeOpacity = strokeHasColor ? sp_desktop_get_opacity_tool(ec->desktop, ec->tool_url, false) : 0; + GdkPixbuf *pixbuf = sp_cursor_pixbuf_from_xpm( + ec->cursor_shape, + w->style->black, w->style->white, + SP_RGBA32_U_COMPOSE(SP_RGBA32_R_U(fillColor),SP_RGBA32_G_U(fillColor),SP_RGBA32_B_U(fillColor),SP_COLOR_F_TO_U(fillOpacity)), + SP_RGBA32_U_COMPOSE(SP_RGBA32_R_U(strokeColor),SP_RGBA32_G_U(strokeColor),SP_RGBA32_B_U(strokeColor),SP_COLOR_F_TO_U(strokeOpacity)) + ); + if (pixbuf != NULL) { + if (ec->cursor) + gdk_cursor_unref(ec->cursor); + ec->cursor = gdk_cursor_new_from_pixbuf(display, pixbuf, ec->hot_x, ec->hot_y); + g_object_unref(pixbuf); + } + } else { + GdkBitmap *bitmap = NULL; + GdkBitmap *mask = NULL; + sp_cursor_bitmap_and_mask_from_xpm(&bitmap, &mask, ec->cursor_shape); + if ((bitmap != NULL) && (mask != NULL)) { + if (ec->cursor) + gdk_cursor_unref(ec->cursor); + ec->cursor = gdk_cursor_new_from_pixmap(bitmap, mask, + &w->style->black, &w->style->white, ec->hot_x, + ec->hot_y); + g_object_unref(bitmap); + g_object_unref(mask); + } } } gdk_window_set_cursor(w->window, ec->cursor); diff --git a/src/event-context.h b/src/event-context.h index 76c74e26c..fc22762fd 100644 --- a/src/event-context.h +++ b/src/event-context.h @@ -128,6 +128,8 @@ struct SPEventContext : public GObject { DelayedSnapEvent *_delayed_snap_event; bool _dse_callback_in_process; + + char const * tool_url; ///< the (preferences) url for the tool (if a subclass corresponding to a tool is used) }; /** diff --git a/src/pixmaps/cursor-ellipse.xpm b/src/pixmaps/cursor-ellipse.xpm index 7a230bd55..b0f20d18c 100644 --- a/src/pixmaps/cursor-ellipse.xpm +++ b/src/pixmaps/cursor-ellipse.xpm @@ -1,8 +1,10 @@ /* XPM */ static char const *cursor_ellipse_xpm[] = { -"32 32 3 1", +"32 32 5 1", " c None", ". c #FFFFFF", +"% c Stroke", +"* c Fill", "+ c #000000", " ... ", " .+. ", @@ -12,17 +14,17 @@ static char const *cursor_ellipse_xpm[] = { "....+.... ", " .+. ", " .+. ....... ", -" ... ....+++++.... ", -" ..+++.....+++.. ", -" ..+...........+.. ", -" ..+.............+.. ", -" .+...............+. ", -" .+...............+. ", -" .+...............+. ", -" ..+.............+.. ", -" ..+...........+.. ", -" ..+++.....+++.. ", -" ....+++++.... ", +" ... ....%%%%%.... ", +" ..%%%*****%%%.. ", +" ..%***********%.. ", +" ..%*************%.. ", +" .%***************%. ", +" .%***************%. ", +" .%***************%. ", +" ..%*************%.. ", +" ..%***********%.. ", +" ..%%%*****%%%.. ", +" ....%%%%%.... ", " ....... ", " ", " ", diff --git a/src/pixmaps/cursor-rect.xpm b/src/pixmaps/cursor-rect.xpm index 149624aa7..69007bc77 100644 --- a/src/pixmaps/cursor-rect.xpm +++ b/src/pixmaps/cursor-rect.xpm @@ -1,8 +1,10 @@ /* XPM */ static char const *cursor_rect_xpm[] = { -"32 32 3 1", +"32 32 5 1", " c None", ". c #FFFFFF", +"% c Stroke", +"* c Fill", "+ c #000000", " ... ", " .+. ", @@ -12,17 +14,17 @@ static char const *cursor_rect_xpm[] = { "....+.... ", " .+. ", " .+. ................. ", -" ... .+++++++++++++++. ", -" .+.............+. ", -" .+.............+. ", -" .+.............+. ", -" .+.............+. ", -" .+.............+. ", -" .+.............+. ", -" .+.............+. ", -" .+.............+. ", -" .+.............+. ", -" .+++++++++++++++. ", +" ... .%%%%%%%%%%%%%%%. ", +" .%*************%. ", +" .%*************%. ", +" .%*************%. ", +" .%*************%. ", +" .%*************%. ", +" .%*************%. ", +" .%*************%. ", +" .%*************%. ", +" .%*************%. ", +" .%%%%%%%%%%%%%%%. ", " ................. ", " ", " ", diff --git a/src/pixmaps/cursor-star.xpm b/src/pixmaps/cursor-star.xpm index 80d312ace..eedf448e4 100644 --- a/src/pixmaps/cursor-star.xpm +++ b/src/pixmaps/cursor-star.xpm @@ -1,8 +1,10 @@ /* XPM */ static char const *cursor_star_xpm[] = { -"32 32 3 1", +"32 32 5 1", " c None", ". c #FFFFFF", +"% c Stroke", +"* c Fill", "+ c #000000", " ... ", " .+. ", @@ -10,21 +12,21 @@ static char const *cursor_star_xpm[] = { "....+.... ", ".+++ +++. ", "....+.... .. ", -" .+. .++. ", -" .+. .++. ", -" ... .++. ", -" .+..+. ", -" ........+..+........ ", -" .++++++....++++++. ", -" .++..........++. ", -" ..++......++.. ", -" .+......+. ", -" .+......+. ", -" .+...++...+. ", -" .+.++..++.+. ", -" .+.+.. ..+.+. ", -" .++. .++. ", -" .+. .+. ", +" .+. .%%. ", +" .+. .%%. ", +" ... .%%. ", +" .%**%* ", +" ........%**%........ ", +" .%%%%%%****%%%%%%. ", +" .%%**********%%. ", +" ..%%******%%.. ", +" .%******%. ", +" .%******%. ", +" .%***%%***%. ", +" .%*%%..%%*%. ", +" .%*%.. ..%*%. ", +" .%%. .%%. ", +" .%. .%. ", " .. .. ", " ", " ", diff --git a/src/rect-context.cpp b/src/rect-context.cpp index d60a6630b..81f615571 100644 --- a/src/rect-context.cpp +++ b/src/rect-context.cpp @@ -110,6 +110,7 @@ static void sp_rect_context_init(SPRectContext *rect_context) event_context->tolerance = 0; event_context->within_tolerance = false; event_context->item_to_select = NULL; + event_context->tool_url = "/tools/shapes/rect"; rect_context->item = NULL; diff --git a/src/sp-cursor.cpp b/src/sp-cursor.cpp index 4bbba5f10..5ec80c9f6 100644 --- a/src/sp-cursor.cpp +++ b/src/sp-cursor.cpp @@ -16,6 +16,8 @@ #include #include #include +#include +#include "color.h" #include "sp-cursor.h" void @@ -32,7 +34,7 @@ sp_cursor_bitmap_and_mask_from_xpm(GdkBitmap **bitmap, GdkBitmap **mask, gchar c g_return_if_fail (colors >= 3); int transparent_color = ' '; - int black_color = '.'; + std::string black_colors; char pixmap_buffer[(32 * 32)/8]; char mask_buffer[(32 * 32)/8]; @@ -51,12 +53,16 @@ sp_cursor_bitmap_and_mask_from_xpm(GdkBitmap **bitmap, GdkBitmap **mask, gchar c p++; } - if (strcmp(p, "None") == 0) { + if (strcmp(p, "None") == 0) { transparent_color = ccode; } + if (strcmp(p, "Stroke") == 0) { + black_colors.push_back(ccode); + } + if (strcmp(p, "#000000") == 0) { - black_color = ccode; + black_colors.push_back(ccode); } } @@ -67,10 +73,10 @@ sp_cursor_bitmap_and_mask_from_xpm(GdkBitmap **bitmap, GdkBitmap **mask, gchar c char maskv = 0; for (int pix = 0; pix < 8; pix++, x++){ - if (xpm[4+y][x] != transparent_color) { + if (xpm[1+colors+y][x] != transparent_color) { maskv |= 1 << pix; - if (xpm[4+y][x] == black_color) { + if (black_colors.find(xpm[1+colors+y][x]) != std::string::npos) { value |= 1 << pix; } } @@ -85,6 +91,73 @@ sp_cursor_bitmap_and_mask_from_xpm(GdkBitmap **bitmap, GdkBitmap **mask, gchar c *mask = gdk_bitmap_create_from_data(NULL, mask_buffer, 32, 32); } +static void free_cursor_data(guchar *pixels, gpointer data) { + delete [] reinterpret_cast(pixels); +} + +struct RGBA { + guchar v[4]; + RGBA() { v[0] = 0; v[1] = 0; v[2] = 0; v[3] = 0; } + RGBA(guchar r, guchar g, guchar b, guchar a) { v[0] = r; v[1] = g; v[2] = b; v[3] = a; } + operator guint32 const () const { return *reinterpret_cast(v); } +}; + +GdkPixbuf* +sp_cursor_pixbuf_from_xpm(gchar const *const *xpm, GdkColor const& black, GdkColor const& white, guint32 fill, guint32 stroke) +{ + int height; + int width; + int colors; + int pix; + sscanf(xpm[0], "%d %d %d %d", &height, &width, &colors, &pix); + + //g_return_if_fail (height == 32); + //g_return_if_fail (width == 32); + //g_return_if_fail (colors >= 3); + + std::map colorMap; + + for (int i = 0; i < colors; i++) { + + char const *p = xpm[1 + i]; + char const ccode = *p; + + p++; + while (isspace(*p)) { + p++; + } + p++; + while (isspace(*p)) { + p++; + } + + if (strcmp(p, "None") == 0) { + colorMap.insert(std::make_pair(ccode, RGBA())); + } else if (strcmp(p, "Fill") == 0) { + colorMap.insert(std::make_pair(ccode, RGBA(SP_RGBA32_R_U(fill),SP_RGBA32_G_U(fill),SP_RGBA32_B_U(fill),SP_RGBA32_A_U(fill)))); + } else if (strcmp(p, "Stroke") == 0) { + colorMap.insert(std::make_pair(ccode, RGBA(SP_RGBA32_R_U(stroke),SP_RGBA32_G_U(stroke),SP_RGBA32_B_U(stroke),SP_RGBA32_A_U(stroke)))); + } else if (strcmp(p, "#000000") == 0) { + colorMap.insert(std::make_pair(ccode, RGBA(black.red,black.green,black.blue,255))); + } else if (strcmp(p, "#FFFFFF") == 0) { + colorMap.insert(std::make_pair(ccode, RGBA(white.red,white.green,white.blue,255))); + } else { + colorMap.insert(std::make_pair(ccode, RGBA())); + } + } + + guint32 *pixmap_buffer = new guint32[width * height]; + + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + std::map::const_iterator it = colorMap.find(xpm[1+colors+y][x]); + pixmap_buffer[y * width + x] = it==colorMap.end() ? 0u : it->second; + } + } + + return gdk_pixbuf_new_from_data(reinterpret_cast(pixmap_buffer), GDK_COLORSPACE_RGB, TRUE, 8, width, height, width*sizeof(guint32), free_cursor_data, NULL); +} + GdkCursor * sp_cursor_new_from_xpm(gchar const *const *xpm, gint hot_x, gint hot_y) { diff --git a/src/sp-cursor.h b/src/sp-cursor.h index 1c40bdc44..4ab90d169 100644 --- a/src/sp-cursor.h +++ b/src/sp-cursor.h @@ -4,6 +4,7 @@ #include void sp_cursor_bitmap_and_mask_from_xpm(GdkBitmap **bitmap, GdkBitmap **mask, gchar const *const *xpm); +GdkPixbuf* sp_cursor_pixbuf_from_xpm(gchar const *const *xpm, GdkColor const& black, GdkColor const& white, guint32 fill, guint32 stroke); GdkCursor *sp_cursor_new_from_xpm(gchar const *const *xpm, gint hot_x, gint hot_y); #endif diff --git a/src/star-context.cpp b/src/star-context.cpp index 9a2a67a57..603865ce1 100644 --- a/src/star-context.cpp +++ b/src/star-context.cpp @@ -111,6 +111,7 @@ sp_star_context_init (SPStarContext * star_context) event_context->tolerance = 0; event_context->within_tolerance = false; event_context->item_to_select = NULL; + event_context->tool_url = "/tools/shapes/star"; star_context->item = NULL; -- 2.30.2