From 090b64622aefb974887ffe27031360a5022acc99 Mon Sep 17 00:00:00 2001 From: mental Date: Sun, 4 Mar 2007 19:06:34 +0000 Subject: [PATCH] adapt code to new Maybe/bbox regime --- src/conn-avoid-ref.cpp | 8 +- src/dialogs/clonetiler.cpp | 39 ++-- src/dialogs/stroke-style.cpp | 101 ++++++----- src/dialogs/tiledialog.cpp | 101 +++++++---- src/dialogs/unclump.cpp | 23 ++- src/flood-context.cpp | 340 +++++++++++++++++++++++------------ src/main.cpp | 58 +++++- src/selection-chemistry.cpp | 77 ++++---- src/selection.cpp | 21 +-- src/sp-conn-end-pair.cpp | 9 +- src/sp-conn-end.cpp | 20 ++- src/sp-item.cpp | 31 ++-- src/sp-shape.cpp | 12 +- src/splivarot.cpp | 33 ++-- 14 files changed, 557 insertions(+), 316 deletions(-) diff --git a/src/conn-avoid-ref.cpp b/src/conn-avoid-ref.cpp index 2a55d43b0..540e8205f 100644 --- a/src/conn-avoid-ref.cpp +++ b/src/conn-avoid-ref.cpp @@ -191,13 +191,15 @@ static Avoid::Polygn avoid_item_poly(SPItem const *item) // by the sp_*_update functions, e.g., text. sp_document_ensure_up_to_date(item->document); - NR::Rect rHull = item->getBounds(sp_item_i2doc_affine(item)); - + NR::Maybe rHull = item->getBounds(sp_item_i2doc_affine(item)); + if (!rHull) { + return Avoid::newPoly(0); + } double spacing = desktop->namedview->connector_spacing; // Add a little buffer around the edge of each object. - NR::Rect rExpandedHull = NR::expand(rHull, -spacing); + NR::Rect rExpandedHull = NR::expand(*rHull, -spacing); poly = Avoid::newPoly(4); for (unsigned n = 0; n < 4; ++n) { diff --git a/src/dialogs/clonetiler.cpp b/src/dialogs/clonetiler.cpp index 00fcac48e..cbf858f4d 100644 --- a/src/dialogs/clonetiler.cpp +++ b/src/dialogs/clonetiler.cpp @@ -786,6 +786,11 @@ clonetiler_trace_pick (NR::Rect box) /* Set up pixblock */ guchar *px = g_new(guchar, 4 * width * height); + + if (px == NULL) { + return 0; // buffer is too big or too small, cannot pick, so return 0 + } + memset(px, 0x00, 4 * width * height); /* Render */ @@ -793,7 +798,7 @@ clonetiler_trace_pick (NR::Rect box) nr_pixblock_setup_extern( &pb, NR_PIXBLOCK_MODE_R8G8B8A8N, ibox.x0, ibox.y0, ibox.x1, ibox.y1, px, 4 * width, FALSE, FALSE ); - nr_arena_item_invoke_render( trace_root, &ibox, &pb, + nr_arena_item_invoke_render(NULL, trace_root, &ibox, &pb, NR_ARENA_ITEM_RENDER_NO_CACHE ); double R = 0, G = 0, B = 0, A = 0; @@ -1080,15 +1085,20 @@ clonetiler_apply (GtkWidget *widget, void *) w = sp_repr_get_double_attribute (obj_repr, "inkscape:tile-w", 0); h = sp_repr_get_double_attribute (obj_repr, "inkscape:tile-h", 0); } else { - NR::Rect const r = SP_ITEM(obj)->getBounds(sp_item_i2doc_affine(SP_ITEM(obj))); - c = r.midpoint(); - w = r.dimensions()[NR::X]; - h = r.dimensions()[NR::Y]; - - sp_repr_set_svg_double(obj_repr, "inkscape:tile-w", w); - sp_repr_set_svg_double(obj_repr, "inkscape:tile-h", h); - sp_repr_set_svg_double(obj_repr, "inkscape:tile-cx", c[NR::X]); - sp_repr_set_svg_double(obj_repr, "inkscape:tile-cy", c[NR::Y]); + NR::Maybe r = SP_ITEM(obj)->getBounds(sp_item_i2doc_affine(SP_ITEM(obj))); + if (r) { + c = r->midpoint(); + w = r->dimensions()[NR::X]; + h = r->dimensions()[NR::Y]; + + sp_repr_set_svg_double(obj_repr, "inkscape:tile-cx", c[NR::X]); + sp_repr_set_svg_double(obj_repr, "inkscape:tile-cy", c[NR::Y]); + sp_repr_set_svg_double(obj_repr, "inkscape:tile-w", w); + sp_repr_set_svg_double(obj_repr, "inkscape:tile-h", h); + } else { + c = NR::Point(0, 0); + w = h = 0; + } } NR::Point cur = NR::Point (0, 0); @@ -1281,12 +1291,9 @@ clonetiler_apply (GtkWidget *widget, void *) center_set = true; } - gchar affinestr[80]; - if (sp_svg_transform_write(affinestr, 79, t)) { - clone->setAttribute("transform", affinestr); - } else { - clone->setAttribute("transform", NULL); - } + gchar *affinestr=sp_svg_transform_write(t); + clone->setAttribute("transform", affinestr); + g_free(affinestr); if (opacity < 1.0) { sp_repr_set_css_double(clone, "opacity", opacity); diff --git a/src/dialogs/stroke-style.cpp b/src/dialogs/stroke-style.cpp index 53c5c722f..7894a89b8 100644 --- a/src/dialogs/stroke-style.cpp +++ b/src/dialogs/stroke-style.cpp @@ -83,7 +83,7 @@ static GtkWidget * marker_mid_menu = NULL; static GtkWidget * marker_end_menu = NULL; static SPObject *ink_extract_marker_name(gchar const *n); -static void ink_markers_menu_update(); +static void ink_markers_menu_update(SPWidget* spw); static Inkscape::UI::Cache::SvgPreview svg_preview_cache; @@ -184,14 +184,6 @@ sp_stroke_style_widget_change_subselection ( Inkscape::Application *inkscape, sp_stroke_style_paint_update (spw); } -static void -sp_stroke_style_widget_transientize_callback(Inkscape::Application *inkscape, - SPDesktop *desktop, - SPWidget *spw ) -{ - ink_markers_menu_update(); -} - /** * Gets the active stroke style property, then sets the appropriate color, alpha, gradient, * pattern, etc. for the paint-selector. @@ -567,6 +559,16 @@ sp_stroke_radio_button(GtkWidget *tb, char const *icon, } +static void +sp_stroke_style_widget_transientize_callback(Inkscape::Application *inkscape, + SPDesktop *desktop, + SPWidget *spw ) +{ +// TODO: Either of these will cause crashes sometimes +// sp_stroke_style_line_update( SP_WIDGET(spw), desktop ? sp_desktop_selection(desktop) : NULL); +// ink_markers_menu_update(spw); +} + /** * Creates a copy of the marker named mname, determines its visible and renderable * area in menu_id's bounding box, and then renders it. This allows us to fill in @@ -609,9 +611,9 @@ sp_marker_prev_new(unsigned psize, gchar const *mname, // Find object's bbox in document NR::Matrix const i2doc(sp_item_i2doc_affine(SP_ITEM(object))); - NR::Rect const dbox = SP_ITEM(object)->getBounds(i2doc); + NR::Maybe dbox = SP_ITEM(object)->getBounds(i2doc); - if (dbox.isEmpty()) { + if (!dbox) { return NULL; } @@ -623,7 +625,7 @@ sp_marker_prev_new(unsigned psize, gchar const *mname, pixbuf = svg_preview_cache.get_preview_from_cache(key); if (pixbuf == NULL) { - pixbuf = render_pixbuf(root, sf, dbox, psize); + pixbuf = render_pixbuf(root, sf, *dbox, psize); svg_preview_cache.set_preview_in_cache(key, pixbuf); } @@ -719,15 +721,6 @@ sp_marker_list_from_doc (GtkWidget *m, SPDocument *current_doc, SPDocument *sour GSList *ml = ink_marker_list_get(source); GSList *clean_ml = NULL; - // Do this here, outside of loop, to speed up preview generation: - /* Create new arena */ - NRArena const *arena = NRArena::create(); - /* Create ArenaItem and set transform */ - unsigned const visionkey = sp_item_display_key_new(1); -/* - NRArenaItem *root = sp_item_invoke_show( SP_ITEM(SP_DOCUMENT_ROOT (sandbox)), (NRArena *) arena, visionkey, SP_ITEM_SHOW_DISPLAY ); -*/ - for (; ml != NULL; ml = ml->next) { if (!SP_IS_MARKER(ml->data)) continue; @@ -786,7 +779,7 @@ ink_marker_menu_create_menu(GtkWidget *m, gchar *menu_id, SPDocument *doc, SPDoc GtkWidget *i = gtk_menu_item_new(); gtk_widget_show(i); -// g_object_set_data(G_OBJECT(i), "marker", (void *) "none"); + g_object_set_data(G_OBJECT(i), "marker", (void *) "none"); GtkWidget *hb = gtk_hbox_new(FALSE, MARKER_ITEM_MARGIN); gtk_widget_show(hb); @@ -825,6 +818,7 @@ ink_marker_menu_create_menu(GtkWidget *m, gchar *menu_id, SPDocument *doc, SPDoc sp_document_ensure_up_to_date(doc); sp_marker_list_from_doc ( m, doc, markers_doc, NULL, sandbox, menu_id ); } + } @@ -912,9 +906,14 @@ sp_marker_select(GtkOptionMenu *mnu, GtkWidget *spw) gchar *menu_id = (gchar *) g_object_get_data(G_OBJECT(mnu), "menu_id"); sp_repr_css_set_property(css, menu_id, marker); - Inkscape::Selection *selection = sp_desktop_selection(desktop); - GSList const *items = selection->itemList(); - for (; items != NULL; items = items->next) { + // Also update the marker dropdown menus, so the document's markers + // show up at the top of the menu +// sp_stroke_style_line_update( SP_WIDGET(spw), desktop ? sp_desktop_selection(desktop) : NULL); + ink_markers_menu_update(SP_WIDGET(spw)); + + Inkscape::Selection *selection = sp_desktop_selection(desktop); + GSList const *items = selection->itemList(); + for (; items != NULL; items = items->next) { SPItem *item = (SPItem *) items->data; if (!SP_IS_SHAPE(item) || SP_IS_RECT(item)) // can't set marker to rect, until it's converted to using continue; @@ -931,35 +930,66 @@ sp_marker_select(GtkOptionMenu *mnu, GtkWidget *spw) sp_document_done(document, SP_VERB_DIALOG_FILL_STROKE, _("Set markers")); - // Lastly, also update the marker dropdown menus, so the document's markers - // show up at the top of the menu - ink_markers_menu_update(); }; +static int +ink_marker_menu_get_pos(GtkMenu* mnu, gchar* markname) { + + if (markname == NULL) + markname = (gchar *) g_object_get_data(G_OBJECT(gtk_menu_get_active(mnu)), "marker"); + + if (markname == NULL) + return 0; + + GList *kids = GTK_MENU_SHELL(mnu)->children; + int i = 0; + for (; kids != NULL; kids = kids->next) { + gchar *mark = (gchar *) g_object_get_data(G_OBJECT(kids->data), "marker"); + if ( mark && strcmp(mark, markname) == 0 ) { + break; + } + i++; + } + return i; +} + static void -ink_markers_menu_update() { +ink_markers_menu_update(SPWidget* spw) { SPDesktop *desktop = inkscape_active_desktop(); SPDocument *document = sp_desktop_document(desktop); SPDocument *sandbox = ink_markers_preview_doc (); GtkWidget *m; + int pos; + gtk_signal_handler_block_by_func( GTK_OBJECT(marker_start_menu), GTK_SIGNAL_FUNC(sp_marker_select), spw); + pos = ink_marker_menu_get_pos(GTK_MENU(gtk_option_menu_get_menu(GTK_OPTION_MENU(marker_start_menu))), NULL); m = gtk_menu_new(); gtk_widget_show(m); ink_marker_menu_create_menu(m, "marker-start", document, sandbox); gtk_option_menu_remove_menu(GTK_OPTION_MENU(marker_start_menu)); gtk_option_menu_set_menu(GTK_OPTION_MENU(marker_start_menu), m); + gtk_option_menu_set_history(GTK_OPTION_MENU(marker_start_menu), pos); + gtk_signal_handler_unblock_by_func( GTK_OBJECT(marker_start_menu), GTK_SIGNAL_FUNC(sp_marker_select), spw); + gtk_signal_handler_block_by_func( GTK_OBJECT(marker_mid_menu), GTK_SIGNAL_FUNC(sp_marker_select), spw); + pos = ink_marker_menu_get_pos(GTK_MENU(gtk_option_menu_get_menu(GTK_OPTION_MENU(marker_mid_menu))), NULL); m = gtk_menu_new(); gtk_widget_show(m); ink_marker_menu_create_menu(m, "marker-mid", document, sandbox); gtk_option_menu_remove_menu(GTK_OPTION_MENU(marker_mid_menu)); gtk_option_menu_set_menu(GTK_OPTION_MENU(marker_mid_menu), m); + gtk_option_menu_set_history(GTK_OPTION_MENU(marker_mid_menu), pos); + gtk_signal_handler_unblock_by_func( GTK_OBJECT(marker_mid_menu), GTK_SIGNAL_FUNC(sp_marker_select), spw); + gtk_signal_handler_block_by_func( GTK_OBJECT(marker_end_menu), GTK_SIGNAL_FUNC(sp_marker_select), spw); + pos = ink_marker_menu_get_pos(GTK_MENU(gtk_option_menu_get_menu(GTK_OPTION_MENU(marker_end_menu))), NULL); m = gtk_menu_new(); gtk_widget_show(m); ink_marker_menu_create_menu(m, "marker-end", document, sandbox); gtk_option_menu_remove_menu(GTK_OPTION_MENU(marker_end_menu)); gtk_option_menu_set_menu(GTK_OPTION_MENU(marker_end_menu), m); + gtk_option_menu_set_history(GTK_OPTION_MENU(marker_end_menu), pos); + gtk_signal_handler_unblock_by_func( GTK_OBJECT(marker_end_menu), GTK_SIGNAL_FUNC(sp_marker_select), spw); } /** @@ -1734,17 +1764,7 @@ ink_marker_menu_set_current(SPObject *marker, GtkOptionMenu *mnu) else markname = g_strdup(SP_OBJECT_REPR(marker)->attribute("id")); - int markpos = 0; - GList *kids = GTK_MENU_SHELL(m)->children; - int i = 0; - for (; kids != NULL; kids = kids->next) { - gchar *mark = (gchar *) g_object_get_data(G_OBJECT(kids->data), "marker"); - if ( mark && strcmp(mark, markname) == 0 ) { - markpos = i; - break; - } - i++; - } + int markpos = ink_marker_menu_get_pos(m, markname); gtk_option_menu_set_history(GTK_OPTION_MENU(mnu), markpos); g_free (markname); @@ -1847,7 +1867,6 @@ ink_extract_marker_name(gchar const *n) gchar* b = g_strdup(p); b[c] = '\0'; - SPDesktop *desktop = inkscape_active_desktop(); SPDocument *doc = sp_desktop_document(desktop); SPObject *marker = doc->getObjectById(b); diff --git a/src/dialogs/tiledialog.cpp b/src/dialogs/tiledialog.cpp index d56d083ba..b10f952da 100644 --- a/src/dialogs/tiledialog.cpp +++ b/src/dialogs/tiledialog.cpp @@ -49,18 +49,23 @@ sp_compare_x_position(SPItem *first, SPItem *second) using NR::X; using NR::Y; - NR::Rect const a = first->getBounds(sp_item_i2doc_affine(first)); - double const a_height = a.dimensions()[Y]; + NR::Maybe a = first->getBounds(sp_item_i2doc_affine(first)); + NR::Maybe b = second->getBounds(sp_item_i2doc_affine(second)); - NR::Rect const b = second->getBounds(sp_item_i2doc_affine(second)); - double const b_height = b.dimensions()[Y]; + if ( !a || !b ) { + // FIXME? + return 0; + } + + double const a_height = a->dimensions()[Y]; + double const b_height = b->dimensions()[Y]; bool a_in_b_vert = false; - if ((a.min()[Y] < b.min()[Y] + 0.1) && (a.min()[Y] > b.min()[Y] - b_height)) { + if ((a->min()[Y] < b->min()[Y] + 0.1) && (a->min()[Y] > b->min()[Y] - b_height)) { a_in_b_vert = true; - } else if ((b.min()[Y] < a.min()[Y] + 0.1) && (b.min()[Y] > a.min()[Y] - a_height)) { + } else if ((b->min()[Y] < a->min()[Y] + 0.1) && (b->min()[Y] > a->min()[Y] - a_height)) { a_in_b_vert = true; - } else if (b.min()[Y] == a.min()[Y]) { + } else if (b->min()[Y] == a->min()[Y]) { a_in_b_vert = true; } else { a_in_b_vert = false; @@ -69,10 +74,10 @@ sp_compare_x_position(SPItem *first, SPItem *second) if (!a_in_b_vert) { return -1; } - if (a_in_b_vert && a.min()[X] > b.min()[X]) { + if (a_in_b_vert && a->min()[X] > b->min()[X]) { return 1; } - if (a_in_b_vert && a.min()[X] < b.min()[X]) { + if (a_in_b_vert && a->min()[X] < b->min()[X]) { return -1; } return 0; @@ -84,13 +89,18 @@ sp_compare_x_position(SPItem *first, SPItem *second) int sp_compare_y_position(SPItem *first, SPItem *second) { - NR::Rect const a = first->getBounds(sp_item_i2doc_affine(first)); - NR::Rect const b = second->getBounds(sp_item_i2doc_affine(second)); + NR::Maybe a = first->getBounds(sp_item_i2doc_affine(first)); + NR::Maybe b = second->getBounds(sp_item_i2doc_affine(second)); + + if ( !a || !b ) { + // FIXME? + return 0; + } - if (a.min()[NR::Y] > b.min()[NR::Y]) { + if (a->min()[NR::Y] > b->min()[NR::Y]) { return 1; } - if (a.min()[NR::Y] < b.min()[NR::Y]) { + if (a->min()[NR::Y] < b->min()[NR::Y]) { return -1; } @@ -159,17 +169,22 @@ void TileDialog::Grid_Arrange () cnt=0; for (; items != NULL; items = items->next) { SPItem *item = SP_ITEM(items->data); - NR::Rect const b = item->getBounds(sp_item_i2doc_affine(item)); - width = b.dimensions()[NR::X]; - height = b.dimensions()[NR::Y]; - cx = b.midpoint()[NR::X]; - cy = b.midpoint()[NR::Y]; - - if (b.min()[NR::X] < grid_left) { - grid_left = b.min()[NR::X]; + NR::Maybe b = item->getBounds(sp_item_i2doc_affine(item)); + if (!b) { + continue; + } + + width = b->dimensions()[NR::X]; + height = b->dimensions()[NR::Y]; + + cx = b->midpoint()[NR::X]; + cy = b->midpoint()[NR::Y]; + + if (b->min()[NR::X] < grid_left) { + grid_left = b->min()[NR::X]; } - if (b.min()[NR::Y] < grid_top) { - grid_top = b.min()[NR::Y]; + if (b->min()[NR::Y] < grid_top) { + grid_top = b->min()[NR::Y]; } if (width > col_width) { col_width = width; @@ -196,15 +211,18 @@ void TileDialog::Grid_Arrange () const GSList *sizes = sorted; for (; sizes != NULL; sizes = sizes->next) { SPItem *item = SP_ITEM(sizes->data); - NR::Rect const b = item->getBounds(sp_item_i2doc_affine(item)); - width = b.dimensions()[NR::X]; - height = b.dimensions()[NR::Y]; - if (width > col_widths[(cnt % NoOfCols)]) { - col_widths[(cnt % NoOfCols)] = width; - } - if (height > row_heights[(cnt / NoOfCols)]) { - row_heights[(cnt / NoOfCols)] = height; + NR::Maybe b = item->getBounds(sp_item_i2doc_affine(item)); + if (b) { + width = b->dimensions()[NR::X]; + height = b->dimensions()[NR::Y]; + if (width > col_widths[(cnt % NoOfCols)]) { + col_widths[(cnt % NoOfCols)] = width; + } + if (height > row_heights[(cnt / NoOfCols)]) { + row_heights[(cnt / NoOfCols)] = height; + } } + cnt++; } @@ -300,20 +318,25 @@ g_print("\n row = %f col = %f selection x= %f selection y = %f", total_row_h for (; current_row != NULL; current_row = current_row->next) { SPItem *item=SP_ITEM(current_row->data); Inkscape::XML::Node *repr = SP_OBJECT_REPR(item); - NR::Rect const b = item->getBounds(sp_item_i2doc_affine(item)); - width = b.dimensions()[NR::X]; - height = b.dimensions()[NR::Y]; + NR::Maybe b = item->getBounds(sp_item_i2doc_affine(item)); + NR::Point min; + if (b) { + width = b->dimensions()[NR::X]; + height = b->dimensions()[NR::Y]; + min = b->min(); + } else { + width = height = 0; + min = NR::Point(0, 0); + } + row = cnt / NoOfCols; col = cnt % NoOfCols; - // original before I started fecking about with it. - // new_x = grid_left + (((col_width - width)/2)*HorizAlign) + (( col_width + paddingx ) * (cnt % NoOfCols)); - // new_y = grid_top + (((row_height - height)/2)*VertAlign) +(( row_height + paddingy ) * (cnt / NoOfCols)); - new_x = grid_left + (((col_widths[col] - width)/2)*HorizAlign) + col_xs[col]; new_y = grid_top + (((row_heights[row] - height)/2)*VertAlign) + row_ys[row]; - NR::Point move = NR::Point(new_x - b.min()[NR::X], b.min()[NR::Y] - new_y); // why are the two args the opposite ways round??? + // signs are inverted between x and y due to y inversion + NR::Point move = NR::Point(new_x - min[NR::X], min[NR::Y] - new_y); NR::Matrix const &affine = NR::Matrix(NR::translate(move)); sp_item_set_i2d_affine(item, sp_item_i2d_affine(item) * affine); sp_item_write_transform(item, repr, item->transform, NULL); diff --git a/src/dialogs/unclump.cpp b/src/dialogs/unclump.cpp index f067aef5f..a15e17bc7 100644 --- a/src/dialogs/unclump.cpp +++ b/src/dialogs/unclump.cpp @@ -34,10 +34,15 @@ unclump_center (SPItem *item) return i->second; } - NR::Rect const r = item->getBounds(sp_item_i2d_affine(item)); - NR::Point const c = r.midpoint(); - c_cache[SP_OBJECT_ID(item)] = c; - return c; + NR::Maybe r = item->getBounds(sp_item_i2d_affine(item)); + if (r) { + NR::Point const c = r->midpoint(); + c_cache[SP_OBJECT_ID(item)] = c; + return c; + } else { + // FIXME + return NR::Point(0, 0); + } } NR::Point @@ -48,9 +53,13 @@ unclump_wh (SPItem *item) if ( i != wh_cache.end() ) { wh = i->second; } else { - NR::Rect const r = item->getBounds(sp_item_i2d_affine(item)); - wh = r.dimensions(); - wh_cache[SP_OBJECT_ID(item)] = wh; + NR::Maybe r = item->getBounds(sp_item_i2d_affine(item)); + if (r) { + wh = r->dimensions(); + wh_cache[SP_OBJECT_ID(item)] = wh; + } else { + wh = NR::Point(0, 0); + } } return wh; diff --git a/src/flood-context.cpp b/src/flood-context.cpp index 6de193e9d..e8c5f8f38 100644 --- a/src/flood-context.cpp +++ b/src/flood-context.cpp @@ -32,8 +32,9 @@ #include "snap.h" #include "desktop.h" #include "desktop-style.h" +#include "message-stack.h" #include "message-context.h" -#include "pixmaps/cursor-rect.xpm" +#include "pixmaps/cursor-paintbucket.xpm" #include "flood-context.h" #include "sp-metrics.h" #include @@ -47,7 +48,6 @@ #include "display/nr-arena.h" #include "display/nr-arena-image.h" #include "display/canvas-arena.h" -#include "helper/png-write.h" #include "libnr/nr-pixops.h" #include "libnr/nr-matrix-rotate-ops.h" #include "libnr/nr-matrix-translate-ops.h" @@ -83,15 +83,6 @@ static void sp_flood_finish(SPFloodContext *rc); static SPEventContextClass *parent_class; -struct SPEBP { - int width, height, sheight; - guchar r, g, b, a; - NRArenaItem *root; // the root arena item to show; it is assumed that all unneeded items are hidden - guchar *px; - unsigned (*status)(float, void *); - void *data; -}; - GtkType sp_flood_context_get_type() { static GType type = 0; @@ -129,9 +120,9 @@ static void sp_flood_context_init(SPFloodContext *flood_context) { SPEventContext *event_context = SP_EVENT_CONTEXT(flood_context); - event_context->cursor_shape = cursor_rect_xpm; - event_context->hot_x = 4; - event_context->hot_y = 4; + event_context->cursor_shape = cursor_paintbucket_xpm; + event_context->hot_x = 11; + event_context->hot_y = 30; event_context->xp = 0; event_context->yp = 0; event_context->tolerance = 0; @@ -232,47 +223,30 @@ static void sp_flood_context_setup(SPEventContext *ec) rc->_message_context = new Inkscape::MessageContext((ec->desktop)->messageStack()); } -/** -Hide all items which are not listed in list, recursively, skipping groups and defs -*/ -static void -hide_other_items_recursively(SPObject *o, GSList *list, unsigned dkey) -{ - if (SP_IS_ITEM(o) - && !SP_IS_DEFS(o) - && !SP_IS_ROOT(o) - && !SP_IS_GROUP(o) - && !g_slist_find(list, o)) - { - sp_item_invoke_hide(SP_ITEM(o), dkey); - } - - // recurse - if (!g_slist_find(list, o)) { - for (SPObject *child = sp_object_first_child(o) ; child != NULL; child = SP_OBJECT_NEXT(child) ) { - hide_other_items_recursively(child, list, dkey); - } - } -} - inline unsigned char * get_pixel(guchar *px, int x, int y, int width) { return px + (x + y * width) * 4; } -static bool compare_pixels(unsigned char *a, unsigned char *b, int fuzziness) { +static bool compare_pixels(unsigned char *a, unsigned char *b, int tolerance) { + int diff = 0; for (int i = 0; i < 4; i++) { - if (a[i] != b[i]) { - return false; - } + diff += (int)abs(a[i] - b[i]); } - return true; + return ((diff / 4) <= tolerance); } -static void try_add_to_queue(std::queue *fill_queue, guchar *px, unsigned char *orig, int x, int y, int width) { +static bool try_add_to_queue(std::queue *fill_queue, guchar *px, guchar *trace_px, unsigned char *orig, int x, int y, int width, int tolerance, bool fill_switch) { unsigned char *t = get_pixel(px, x, y, width); - if (compare_pixels(t, orig, 0)) { - fill_queue->push(NR::Point(x, y)); + if (compare_pixels(t, orig, tolerance)) { + unsigned char *trace_t = get_pixel(trace_px, x, y, width); + if (trace_t[3] != 255) { + if (fill_switch) { + fill_queue->push(NR::Point(x, y)); + } + } + return false; } + return true; } static void do_trace(GdkPixbuf *px, SPDesktop *desktop, NR::Matrix transform) { @@ -292,13 +266,15 @@ static void do_trace(GdkPixbuf *px, SPDesktop *desktop, NR::Matrix transform) { long totalNodeCount = 0L; + double offset = prefs_get_double_attribute_limited("tools.paintbucket", "offset", 1.5, 0.0, 2.0); + for (unsigned int i=0 ; icreateElement("svg:path"); /* Set style */ - sp_desktop_apply_style_tool (desktop, pathRepr, "tools.flood", false); + sp_desktop_apply_style_tool (desktop, pathRepr, "tools.paintbucket", false); NArtBpath *bpath = sp_svg_read_path(result.getPathData().c_str()); Path *path = bpath_to_Path(bpath); @@ -313,7 +289,7 @@ static void do_trace(GdkPixbuf *px, SPDesktop *desktop, NR::Matrix transform) { Shape *expanded_path_shape = new Shape(); expanded_path_shape->ConvertToShape(path_shape, fill_nonZero); - path_shape->MakeOffset(expanded_path_shape, 1.5, join_round, 4); + path_shape->MakeOffset(expanded_path_shape, offset, join_round, 4); expanded_path_shape->ConvertToShape(path_shape, fill_positive); Path *expanded_path = new Path(); @@ -330,12 +306,27 @@ static void do_trace(GdkPixbuf *px, SPDesktop *desktop, NR::Matrix transform) { delete expanded_path; pathRepr->setAttribute("d", str); g_free(str); - + layer_repr->addChild(pathRepr, NULL); SPObject *reprobj = document->getObjectByRepr(pathRepr); if (reprobj) { sp_item_write_transform(SP_ITEM(reprobj), pathRepr, transform, NULL); + + // premultiply the item transform by the accumulated parent transform in the paste layer + NR::Matrix local = sp_item_i2doc_affine(SP_GROUP(desktop->currentLayer())); + if (!local.test_identity()) { + gchar const *t_str = pathRepr->attribute("transform"); + NR::Matrix item_t (NR::identity()); + if (t_str) + sp_svg_transform_read(t_str, &item_t); + item_t *= local.inverse(); + // (we're dealing with unattached repr, so we write to its attr instead of using sp_item_set_transform) + gchar *affinestr=sp_svg_transform_write(item_t); + pathRepr->setAttribute("transform", affinestr); + g_free(affinestr); + } + Inkscape::Selection *selection = sp_desktop_selection(desktop); selection->set(reprobj); pathRepr->setPosition(-1); @@ -345,6 +336,74 @@ static void do_trace(GdkPixbuf *px, SPDesktop *desktop, NR::Matrix transform) { } } +struct bitmap_coords_info { + bool is_left; + int x; + int y; + int y_limit; + int width; + int tolerance; + bool top_fill; + bool bottom_fill; + NR::Rect bbox; + NR::Rect screen; +}; + +enum ScanlineCheckResult { + SCANLINE_CHECK_OK, + SCANLINE_CHECK_ABORTED, + SCANLINE_CHECK_BOUNDARY +}; + +static ScanlineCheckResult perform_bitmap_scanline_check(std::queue *fill_queue, guchar *px, guchar *trace_px, unsigned char *orig_color, bitmap_coords_info bci) { + bool aborted = false; + bool reached_screen_boundary = false; + bool ok; + + bool keep_tracing; + unsigned char *t, *trace_t; + + do { + ok = false; + if (bci.is_left) { + keep_tracing = (bci.x >= 0); + } else { + keep_tracing = (bci.x < bci.width); + } + + if (keep_tracing) { + t = get_pixel(px, bci.x, bci.y, bci.width); + if (compare_pixels(t, orig_color, bci.tolerance)) { + for (int i = 0; i < 4; i++) { t[i] = 255 - t[i]; } + trace_t = get_pixel(trace_px, bci.x, bci.y, bci.width); + trace_t[3] = 255; + if (bci.y > 0) { + bci.top_fill = try_add_to_queue(fill_queue, px, trace_px, orig_color, bci.x, bci.y - 1, bci.width, bci.tolerance, bci.top_fill); + } + if (bci.y < bci.y_limit) { + bci.bottom_fill = try_add_to_queue(fill_queue, px, trace_px, orig_color, bci.x, bci.y + 1, bci.width, bci.tolerance, bci.bottom_fill); + } + if (bci.is_left) { + bci.x--; + } else { + bci.x++; + } + ok = true; + } + } else { + if (bci.bbox.min()[NR::X] > bci.screen.min()[NR::X]) { + aborted = true; break; + } else { + reached_screen_boundary = true; + } + } + } while (ok); + + if (aborted) { return SCANLINE_CHECK_ABORTED; } + if (reached_screen_boundary) { return SCANLINE_CHECK_BOUNDARY; } + return SCANLINE_CHECK_OK; +} + static void sp_flood_do_flood_fill(SPEventContext *event_context, GdkEvent *event) { SPDesktop *desktop = event_context->desktop; SPDocument *document = sp_desktop_document(desktop); @@ -356,21 +415,33 @@ static void sp_flood_do_flood_fill(SPEventContext *event_context, GdkEvent *even sp_document_ensure_up_to_date (document); SPItem *document_root = SP_ITEM(SP_DOCUMENT_ROOT(document)); - NR::Rect bbox = document_root->getBounds(NR::identity()); + NR::Maybe bbox = document_root->getBounds(NR::identity()); + + if (!bbox) { + desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Area is not bounded, cannot fill.")); + return; + } + + double zoom_scale = desktop->current_zoom(); + double padding = 1.6; - if (bbox.isEmpty()) { return; } + NR::Rect screen = desktop->get_display_area(); - int width = (int)ceil(bbox.extent(NR::X)); - int height = (int)ceil(bbox.extent(NR::Y)); + int width = (int)ceil(screen.extent(NR::X) * zoom_scale * padding); + int height = (int)ceil(screen.extent(NR::Y) * zoom_scale * padding); - NR::Point origin(bbox.min()[NR::X], bbox.min()[NR::Y]); + NR::Point origin(screen.min()[NR::X], + sp_document_height(document) - screen.extent(NR::Y) - screen.min()[NR::Y]); + + origin[NR::X] = origin[NR::X] + (screen.extent(NR::X) * ((1 - padding) / 2)); + origin[NR::Y] = origin[NR::Y] + (screen.extent(NR::Y) * ((1 - padding) / 2)); - NR::scale scale(width / (bbox.extent(NR::X)), height / (bbox.extent(NR::Y))); + NR::scale scale(zoom_scale, zoom_scale); NR::Matrix affine = scale * NR::translate(-origin * scale); /* Create ArenaItems and set transform */ NRArenaItem *root = sp_item_invoke_show(SP_ITEM(sp_document_root(document)), arena, dkey, SP_ITEM_SHOW_DISPLAY); - nr_arena_item_set_transform(root, affine); + nr_arena_item_set_transform(NR_ARENA_ITEM(root), affine); NRGC gc(NULL); nr_matrix_set_identity(&gc.transform); @@ -383,31 +454,31 @@ static void sp_flood_do_flood_fill(SPEventContext *event_context, GdkEvent *even nr_arena_item_invoke_update(root, &final_bbox, &gc, NR_ARENA_ITEM_STATE_ALL, NR_ARENA_ITEM_STATE_NONE); -// /* Set up pixblocks */ guchar *px = g_new(guchar, 4 * width * height); memset(px, 0x00, 4 * width * height); - guchar *trace_px = g_new(guchar, 4 * width * height); - memset(trace_px, 0x00, 4 * width * height); - NRPixBlock B; nr_pixblock_setup_extern( &B, NR_PIXBLOCK_MODE_R8G8B8A8N, final_bbox.x0, final_bbox.y0, final_bbox.x1, final_bbox.y1, px, 4 * width, FALSE, FALSE ); - nr_arena_item_invoke_render( root, &final_bbox, &B, NR_ARENA_ITEM_RENDER_NO_CACHE ); - + nr_arena_item_invoke_render(NULL, root, &final_bbox, &B, NR_ARENA_ITEM_RENDER_NO_CACHE ); nr_pixblock_release(&B); + + // Hide items + sp_item_invoke_hide(SP_ITEM(sp_document_root(document)), dkey); + nr_arena_item_unref(root); nr_object_unref((NRObject *) arena); - double zoom_scale = desktop->current_zoom(); - NR::Point pw = NR::Point(event->button.x / zoom_scale, sp_document_height(document) + (event->button.y / zoom_scale)) * affine; pw[NR::X] = (int)MIN(width - 1, MAX(0, pw[NR::X])); pw[NR::Y] = (int)MIN(height - 1, MAX(0, pw[NR::Y])); + guchar *trace_px = g_new(guchar, 4 * width * height); + memset(trace_px, 0x00, 4 * width * height); + std::queue fill_queue; fill_queue.push(pw); @@ -418,67 +489,87 @@ static void sp_flood_do_flood_fill(SPEventContext *event_context, GdkEvent *even unsigned char *orig_px = get_pixel(px, (int)pw[NR::X], (int)pw[NR::Y], width); for (int i = 0; i < 4; i++) { orig_color[i] = orig_px[i]; } + int tolerance = (255 * prefs_get_int_attribute_limited("tools.paintbucket", "tolerance", 1, 0, 100)) / 100; + + bool reached_screen_boundary = false; + + bitmap_coords_info bci; + + bci.y_limit = y_limit; + bci.width = width; + bci.tolerance = tolerance; + bci.bbox = *bbox; + bci.screen = screen; + while (!fill_queue.empty() && !aborted) { NR::Point cp = fill_queue.front(); fill_queue.pop(); unsigned char *s = get_pixel(px, (int)cp[NR::X], (int)cp[NR::Y], width); // same color at this point - if (compare_pixels(s, orig_color, 0)) { - int left = (int)cp[NR::X]; - int right = (int)cp[NR::X] + 1; + if (compare_pixels(s, orig_color, tolerance)) { int x = (int)cp[NR::X]; int y = (int)cp[NR::Y]; + bool top_fill = true; + bool bottom_fill = true; + if (y > 0) { - try_add_to_queue(&fill_queue, px, orig_color, x, y - 1, width); + top_fill = try_add_to_queue(&fill_queue, px, trace_px, orig_color, x, y - 1, width, tolerance, top_fill); } else { - aborted = true; break; + if (bbox->min()[NR::Y] > screen.min()[NR::Y]) { + aborted = true; break; + } else { + reached_screen_boundary = true; + } } if (y < y_limit) { - try_add_to_queue(&fill_queue, px, orig_color, x, y + 1, width); + bottom_fill = try_add_to_queue(&fill_queue, px, trace_px, orig_color, x, y + 1, width, tolerance, bottom_fill); } else { - aborted = true; break; - } - - unsigned char *t, *trace_t; - bool ok = false; - - do { - ok = false; - // go left - if (left >= 0) { - t = get_pixel(px, left, y, width); - if (compare_pixels(t, orig_color, 0)) { - for (int i = 0; i < 4; i++) { t[i] = 255 - t[i]; } - trace_t = get_pixel(trace_px, left, y, width); - trace_t[3] = 255; - if (y > 0) { try_add_to_queue(&fill_queue, px, orig_color, left, y - 1, width); } - if (y < y_limit) { try_add_to_queue(&fill_queue, px, orig_color, left, y + 1, width); } - left--; ok = true; - } - } else { + if (bbox->max()[NR::Y] < screen.max()[NR::Y]) { aborted = true; break; - } - } while (ok); - - do { - ok = false; - // go left - if (right < width) { - t = get_pixel(px, right, y, width); - if (compare_pixels(t, orig_color, 0)) { - for (int i = 0; i < 4; i++) { t[i] = 255 - t[i]; } - trace_t = get_pixel(trace_px, right, y, width); - trace_t[3] = 255; - if (y > 0) { try_add_to_queue(&fill_queue, px, orig_color, right, y - 1, width); } - if (y < y_limit) { try_add_to_queue(&fill_queue, px, orig_color, right, y + 1, width); } - right++; ok = true; - } } else { - aborted = true; break; + reached_screen_boundary = true; } - } while (ok); + } + + bci.is_left = true; + bci.x = x; + bci.y = y; + bci.top_fill = top_fill; + bci.bottom_fill = bottom_fill; + + ScanlineCheckResult result = perform_bitmap_scanline_check(&fill_queue, px, trace_px, orig_color, bci); + + switch (result) { + case SCANLINE_CHECK_ABORTED: + aborted = true; + break; + case SCANLINE_CHECK_BOUNDARY: + reached_screen_boundary = true; + break; + default: + break; + } + + bci.is_left = false; + bci.x = x + 1; + bci.y = y; + bci.top_fill = top_fill; + bci.bottom_fill = bottom_fill; + + result = perform_bitmap_scanline_check(&fill_queue, px, trace_px, orig_color, bci); + + switch (result) { + case SCANLINE_CHECK_ABORTED: + aborted = true; + break; + case SCANLINE_CHECK_BOUNDARY: + reached_screen_boundary = true; + break; + default: + break; + } } } @@ -486,9 +577,14 @@ static void sp_flood_do_flood_fill(SPEventContext *event_context, GdkEvent *even if (aborted) { g_free(trace_px); + desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Area is not bounded, cannot fill.")); return; } + if (reached_screen_boundary) { + desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Only the visible part of the bounded area was filled. If you want to fill all of the area, undo, zoom out, and fill again.")); + } + GdkPixbuf* pixbuf = gdk_pixbuf_new_from_data(trace_px, GDK_COLORSPACE_RGB, TRUE, @@ -496,13 +592,13 @@ static void sp_flood_do_flood_fill(SPEventContext *event_context, GdkEvent *even (GdkPixbufDestroyNotify)g_free, NULL); - g_free(trace_px); - NR::Matrix inverted_affine = NR::Matrix(affine).inverse(); do_trace(pixbuf, desktop, inverted_affine); - sp_document_done(document, SP_VERB_CONTEXT_FLOOD, _("Flood fill")); + g_free(trace_px); + + sp_document_done(document, SP_VERB_CONTEXT_PAINTBUCKET, _("Fill bounded area")); } static gint sp_flood_context_item_handler(SPEventContext *event_context, SPItem *item, GdkEvent *event) @@ -511,10 +607,6 @@ static gint sp_flood_context_item_handler(SPEventContext *event_context, SPItem switch (event->type) { case GDK_BUTTON_PRESS: - if ( event->button.button == 1 ) { - sp_flood_do_flood_fill(event_context, event); - ret = TRUE; - } break; // motion and release are always on root (why?) default: @@ -530,6 +622,8 @@ static gint sp_flood_context_item_handler(SPEventContext *event_context, SPItem static gint sp_flood_context_root_handler(SPEventContext *event_context, GdkEvent *event) { + SPDesktop *desktop = event_context->desktop; + gint ret = FALSE; switch (event->type) { case GDK_BUTTON_PRESS: @@ -539,6 +633,20 @@ static gint sp_flood_context_root_handler(SPEventContext *event_context, GdkEven ret = TRUE; } break; + case GDK_KEY_PRESS: + switch (get_group0_keyval (&event->key)) { + case GDK_Up: + case GDK_Down: + case GDK_KP_Up: + case GDK_KP_Down: + // prevent the zoom field from activation + if (!MOD__CTRL_ONLY) + ret = TRUE; + break; + default: + break; + } + break; default: break; } @@ -567,8 +675,8 @@ static void sp_flood_finish(SPFloodContext *rc) sp_canvas_end_forced_full_redraws(desktop->canvas); sp_desktop_selection(desktop)->set(rc->item); - sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_RECT, - _("Create floodangle")); + sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_PAINTBUCKET, + _("Fill bounded area")); rc->item = NULL; } diff --git a/src/main.cpp b/src/main.cpp index c5d9256bf..dff671c63 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -108,6 +108,8 @@ using Inkscape::Extension::Internal::PrintWin32; #include "application/application.h" +#include "main-cmdlineact.h" + enum { SP_ARG_NONE, SP_ARG_NOGUI, @@ -144,6 +146,9 @@ enum { SP_ARG_QUERY_ID, SP_ARG_VERSION, SP_ARG_VACUUM_DEFS, + SP_ARG_VERB_LIST, + SP_ARG_VERB, + SP_ARG_SELECT, SP_ARG_LAST }; @@ -366,6 +371,21 @@ struct poptOption options[] = { N_("Remove unused definitions from the defs section(s) of the document"), NULL}, + {"verb-list", 0, + POPT_ARG_NONE, NULL, SP_ARG_VERB_LIST, + N_("List the IDs of all the verbs in Inkscape"), + NULL}, + + {"verb", 0, + POPT_ARG_STRING, NULL, SP_ARG_VERB, + N_("Verb to call when Inkscape opens."), + N_("VERB-ID")}, + + {"select", 0, + POPT_ARG_STRING, NULL, SP_ARG_SELECT, + N_("Object ID to select when Inkscape opens."), + N_("OBJECT-ID")}, + POPT_AUTOHELP POPT_TABLEEND }; @@ -654,6 +674,7 @@ sp_main_gui(int argc, char const **argv) } } + Glib::signal_idle().connect(sigc::ptr_fun(&Inkscape::CmdLineAction::idle)); main_instance.run(); #ifdef WIN32 @@ -736,6 +757,7 @@ sp_main_console(int argc, char const **argv) do_query_dimension (doc, false, sp_query_x? NR::X : NR::Y, sp_query_id); } } + fl = g_slist_remove(fl, fl->data); } @@ -767,15 +789,20 @@ do_query_dimension (SPDocument *doc, bool extent, NR::Dim2 const axis, const gch if (o) { sp_document_ensure_up_to_date (doc); SPItem *item = ((SPItem *) o); - NR::Rect area = item->getBounds(sp_item_i2doc_affine(item)); // "true" SVG bbox for scripting - Inkscape::SVGOStringStream os; - if (extent) { - os << area.extent(axis); + // "true" SVG bbox for scripting + NR::Maybe area = item->getBounds(sp_item_i2doc_affine(item)); + if (area) { + Inkscape::SVGOStringStream os; + if (extent) { + os << area->extent(axis); + } else { + os << area->min()[axis]; + } + g_print ("%s", os.str().c_str()); } else { - os << area.min()[axis]; + g_print("0"); } - g_print ("%s", os.str().c_str()); } } @@ -1370,6 +1397,25 @@ sp_process_args(poptContext ctx) exit(0); break; } + case SP_ARG_VERB_LIST: { + // This really shouldn't go here, we should init the app. + // But, since we're just exiting in this path, there is + // no harm, and this is really a better place to put + // everything else. + Inkscape::Extension::init(); + Inkscape::Verb::list(); + exit(0); + break; + } + case SP_ARG_VERB: + case SP_ARG_SELECT: { + gchar const *arg = poptGetOptArg(ctx); + if (arg != NULL) { + // printf("Adding in: %s\n", arg); + new Inkscape::CmdLineAction((a == SP_ARG_VERB), arg); + } + break; + } default: { break; } diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index 680a2e871..34041b204 100644 --- a/src/selection-chemistry.cpp +++ b/src/selection-chemistry.cpp @@ -591,17 +591,15 @@ sp_item_list_common_parent_group(const GSList *items) /** Finds out the minimum common bbox of the selected items */ -NR::Rect +static NR::Maybe enclose_items(const GSList *items) { g_assert(items != NULL); - NR::Rect r = sp_item_bbox_desktop((SPItem *) items->data); - - for (GSList *i = items->next; i; i = i->next) { + NR::Maybe r = NR::Nothing(); + for (GSList const *i = items; i; i = i->next) { r = NR::Rect::union_bounds(r, sp_item_bbox_desktop((SPItem *) i->data)); } - return r; } @@ -647,24 +645,28 @@ sp_selection_raise() rev = g_slist_sort(rev, (GCompareFunc) sp_item_repr_compare_position); // find out the common bbox of the selected items - NR::Rect selected = enclose_items(items); + NR::Maybe selected = enclose_items(items); // for all objects in the selection (starting from top) - while (rev) { - SPObject *child = SP_OBJECT(rev->data); - // for each selected object, find the next sibling - for (SPObject *newref = child->next; newref; newref = newref->next) { - // if the sibling is an item AND overlaps our selection, - if (SP_IS_ITEM(newref) && selected.intersects(sp_item_bbox_desktop(SP_ITEM(newref)))) { - // AND if it's not one of our selected objects, - if (!g_slist_find((GSList *) items, newref)) { - // move the selected object after that sibling - grepr->changeOrder(SP_OBJECT_REPR(child), SP_OBJECT_REPR(newref)); + if (selected) { + while (rev) { + SPObject *child = SP_OBJECT(rev->data); + // for each selected object, find the next sibling + for (SPObject *newref = child->next; newref; newref = newref->next) { + // if the sibling is an item AND overlaps our selection, + if (SP_IS_ITEM(newref) && selected->intersects(sp_item_bbox_desktop(SP_ITEM(newref)))) { + // AND if it's not one of our selected objects, + if (!g_slist_find((GSList *) items, newref)) { + // move the selected object after that sibling + grepr->changeOrder(SP_OBJECT_REPR(child), SP_OBJECT_REPR(newref)); + } + break; } - break; } + rev = g_slist_remove(rev, child); } - rev = g_slist_remove(rev, child); + } else { + g_slist_free(rev); } sp_document_done(sp_desktop_document(desktop), SP_VERB_SELECTION_RAISE, @@ -731,7 +733,7 @@ sp_selection_lower() Inkscape::XML::Node *grepr = SP_OBJECT_REPR(group); // find out the common bbox of the selected items - NR::Rect selected = enclose_items(items); + NR::Maybe selected = enclose_items(items); /* construct direct-ordered list of selected children */ GSList *rev = g_slist_copy((GSList *) items); @@ -739,30 +741,33 @@ sp_selection_lower() rev = g_slist_reverse(rev); // for all objects in the selection (starting from top) - while (rev) { - SPObject *child = SP_OBJECT(rev->data); - // for each selected object, find the prev sibling - for (SPObject *newref = prev_sibling(child); newref; newref = prev_sibling(newref)) { - // if the sibling is an item AND overlaps our selection, - if (SP_IS_ITEM(newref) && selected.intersects(sp_item_bbox_desktop(SP_ITEM(newref)))) { - // AND if it's not one of our selected objects, - if (!g_slist_find((GSList *) items, newref)) { - // move the selected object before that sibling - SPObject *put_after = prev_sibling(newref); - if (put_after) - grepr->changeOrder(SP_OBJECT_REPR(child), SP_OBJECT_REPR(put_after)); - else - SP_OBJECT_REPR(child)->setPosition(0); + if (selected) { + while (rev) { + SPObject *child = SP_OBJECT(rev->data); + // for each selected object, find the prev sibling + for (SPObject *newref = prev_sibling(child); newref; newref = prev_sibling(newref)) { + // if the sibling is an item AND overlaps our selection, + if (SP_IS_ITEM(newref) && selected->intersects(sp_item_bbox_desktop(SP_ITEM(newref)))) { + // AND if it's not one of our selected objects, + if (!g_slist_find((GSList *) items, newref)) { + // move the selected object before that sibling + SPObject *put_after = prev_sibling(newref); + if (put_after) + grepr->changeOrder(SP_OBJECT_REPR(child), SP_OBJECT_REPR(put_after)); + else + SP_OBJECT_REPR(child)->setPosition(0); + } + break; } - break; } + rev = g_slist_remove(rev, child); } - rev = g_slist_remove(rev, child); + } else { + g_slist_free(rev); } sp_document_done(sp_desktop_document(desktop), SP_VERB_SELECTION_LOWER, _("Lower")); - } void sp_selection_lower_to_bottom() diff --git a/src/selection.cpp b/src/selection.cpp index a27e45cb2..82c82b523 100644 --- a/src/selection.cpp +++ b/src/selection.cpp @@ -317,21 +317,18 @@ NRRect *Selection::bounds(NRRect *bbox) const NR::Rect Selection::bounds() const { GSList const *items = const_cast(this)->itemList(); - if (!items) { - return NR::Rect(NR::Point(0, 0), NR::Point(0, 0)); - } - - GSList const *i = items; - NR::Rect bbox = sp_item_bbox_desktop(SP_ITEM(i->data)); - GSList const *i_start = i; - while (i != NULL) { - if (i != i_start) - bbox = NR::Rect::union_bounds(bbox, sp_item_bbox_desktop(SP_ITEM(i->data))); - i = i->next; + NR::Maybe bbox = NR::Nothing(); + for ( GSList const *i = items ; i != NULL ; i = i->next ) { + bbox = NR::Rect::union_bounds(bbox, sp_item_bbox_desktop(SP_ITEM(i->data))); } - return bbox; + // TODO: return NR::Maybe + if (bbox) { + return *bbox; + } else { + return NR::Rect(NR::Point(0, 0), NR::Point(0, 0)); + } } NRRect *Selection::boundsInDocument(NRRect *bbox) const { diff --git a/src/sp-conn-end-pair.cpp b/src/sp-conn-end-pair.cpp index 25466a4a4..7c8527776 100644 --- a/src/sp-conn-end-pair.cpp +++ b/src/sp-conn-end-pair.cpp @@ -164,8 +164,13 @@ SPConnEndPair::getEndpoints(NR::Point endPts[]) const { for (unsigned h = 0; h < 2; ++h) { if ( h2attItem[h] ) { - NR::Rect const bbox = h2attItem[h]->getBounds(sp_item_i2doc_affine(h2attItem[h])); - endPts[h] = bbox.midpoint(); + NR::Maybe bbox = h2attItem[h]->getBounds(sp_item_i2doc_affine(h2attItem[h])); + if (bbox) { + endPts[h] = bbox->midpoint(); + } else { + // FIXME + endPts[h] = NR::Point(0, 0); + } } else { diff --git a/src/sp-conn-end.cpp b/src/sp-conn-end.cpp index 7c0d96506..7a8a60dd0 100644 --- a/src/sp-conn-end.cpp +++ b/src/sp-conn-end.cpp @@ -64,15 +64,19 @@ sp_conn_end_move_compensate(NR::Matrix const *mp, SPItem *moved_item, /* Initial end-points: centre of attached object. */ NR::Point h2endPt_icoordsys[2]; NR::Matrix h2i2anc[2]; - NR::Rect h2bbox_icoordsys[2] = { - h2attItem[0]->getBounds(NR::identity()), - h2attItem[1]->getBounds(NR::identity()) - }; + NR::Rect h2bbox_icoordsys[2]; NR::Point last_seg_endPt[2] = { sp_curve_second_point(path->curve), sp_curve_penultimate_point(path->curve) }; for (unsigned h = 0; h < 2; ++h) { + NR::Maybe bbox = h2attItem[h]->getBounds(NR::identity()); + if (bbox) { + h2bbox_icoordsys[h] = *bbox; + } else { + // FIXME + h2bbox_icoordsys[h] = NR::Rect(NR::Point(0, 0), NR::Point(0, 0)); + } h2i2anc[h] = i2anc_affine(h2attItem[h], ancestor); h2endPt_icoordsys[h] = h2bbox_icoordsys[h].midpoint(); } @@ -107,7 +111,13 @@ sp_conn_end_move_compensate(NR::Matrix const *mp, SPItem *moved_item, NR::Rect otherpt_rect = NR::Rect(other_endpt, other_endpt); NR::Rect h2bbox_icoordsys[2] = { otherpt_rect, otherpt_rect }; - h2bbox_icoordsys[ind] = h2attItem[ind]->getBounds(NR::identity()); + NR::Maybe bbox = h2attItem[ind]->getBounds(NR::identity()); + if (bbox) { + h2bbox_icoordsys[ind] = *bbox; + } else { + // FIXME + h2bbox_icoordsys[ind] = NR::Rect(NR::Point(0, 0), NR::Point(0, 0)); + } h2i2anc = i2anc_affine(h2attItem[ind], ancestor); h2endPt_icoordsys[ind] = h2bbox_icoordsys[ind].midpoint(); diff --git a/src/sp-item.cpp b/src/sp-item.cpp index c2ef93714..2d3ab3ea3 100644 --- a/src/sp-item.cpp +++ b/src/sp-item.cpp @@ -277,12 +277,12 @@ SPItem::setExplicitlyHidden(bool const val) { */ void SPItem::setCenter(NR::Point object_centre) { - NR::Rect bbox = getBounds(sp_item_i2d_affine(this)); - if (!bbox.isEmpty()) { - transform_center_x = object_centre[NR::X] - bbox.midpoint()[NR::X]; + NR::Maybe bbox = getBounds(sp_item_i2d_affine(this)); + if (bbox) { + transform_center_x = object_centre[NR::X] - bbox->midpoint()[NR::X]; if (fabs(transform_center_x) < 1e-5) // rounding error transform_center_x = 0; - transform_center_y = object_centre[NR::Y] - bbox.midpoint()[NR::Y]; + transform_center_y = object_centre[NR::Y] - bbox->midpoint()[NR::Y]; if (fabs(transform_center_y) < 1e-5) // rounding error transform_center_y = 0; } @@ -299,9 +299,9 @@ bool SPItem::isCenterSet() { } NR::Point SPItem::getCenter() { - NR::Rect bbox = getBounds(sp_item_i2d_affine(this)); - if (!bbox.isEmpty()) { - return bbox.midpoint() + NR::Point (this->transform_center_x, this->transform_center_y); + NR::Maybe bbox = getBounds(sp_item_i2d_affine(this)); + if (bbox) { + return bbox->midpoint() + NR::Point (this->transform_center_x, this->transform_center_y); } else { return NR::Point (0, 0); // something's wrong! } @@ -634,12 +634,9 @@ sp_item_write(SPObject *const object, Inkscape::XML::Node *repr, guint flags) { SPItem *item = SP_ITEM(object); - gchar c[256]; - if (sp_svg_transform_write(c, 256, item->transform)) { - repr->setAttribute("transform", c); - } else { - repr->setAttribute("transform", NULL); - } + gchar *c = sp_svg_transform_write(item->transform); + repr->setAttribute("transform", c); + g_free(c); SPObject const *const parent = SP_OBJECT_PARENT(object); /** \todo Can someone please document why this is conditional on having @@ -812,12 +809,14 @@ NR::Rect sp_item_bbox_desktop(SPItem *item) static void sp_item_private_snappoints(SPItem const *item, SnapPointsIter p) { - NR::Rect const bbox = item->getBounds(sp_item_i2d_affine(item)); + NR::Maybe bbox = item->getBounds(sp_item_i2d_affine(item)); /* Just a pair of opposite corners of the bounding box suffices given that we don't yet support angled guide lines. */ - *p = bbox.min(); - *p = bbox.max(); + if (bbox) { + *p = bbox->min(); + *p = bbox->max(); + } } void sp_item_snappoints(SPItem const *item, SnapPointsIter p) diff --git a/src/sp-shape.cpp b/src/sp-shape.cpp index 7d472088c..cfeee3a29 100644 --- a/src/sp-shape.cpp +++ b/src/sp-shape.cpp @@ -238,13 +238,15 @@ sp_shape_update (SPObject *object, SPCtx *ctx, unsigned int flags) if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_PARENT_MODIFIED_FLAG)) { /* This is suboptimal, because changing parent style schedules recalculation */ /* But on the other hand - how can we know that parent does not tie style and transform */ - NR::Rect const paintbox = SP_ITEM(object)->getBounds(NR::identity()); + NR::Maybe paintbox = SP_ITEM(object)->getBounds(NR::identity()); for (SPItemView *v = SP_ITEM (shape)->display; v != NULL; v = v->next) { NRArenaShape * const s = NR_ARENA_SHAPE(v->arenaitem); if (flags & SP_OBJECT_MODIFIED_FLAG) { nr_arena_shape_set_path(s, shape->curve, (flags & SP_OBJECT_USER_MODIFIED_FLAG_B)); } - s->setPaintBox(paintbox); + if (paintbox) { + s->setPaintBox(*paintbox); + } } } @@ -753,8 +755,10 @@ sp_shape_show (SPItem *item, NRArena *arena, unsigned int key, unsigned int flag NRArenaShape * const s = NR_ARENA_SHAPE(arenaitem); nr_arena_shape_set_style(s, object->style); nr_arena_shape_set_path(s, shape->curve, false); - NR::Rect const paintbox = item->getBounds(NR::identity()); - s->setPaintBox(paintbox); + NR::Maybe paintbox = item->getBounds(NR::identity()); + if (paintbox) { + s->setPaintBox(*paintbox); + } if (sp_shape_has_markers (shape)) { diff --git a/src/splivarot.cpp b/src/splivarot.cpp index ecafd2f04..cf07fba16 100644 --- a/src/splivarot.cpp +++ b/src/splivarot.cpp @@ -474,11 +474,7 @@ sp_selected_path_boolop(bool_op bop, const unsigned int verb, const Glib::ustrin // premultiply by the inverse of parent's repr SPItem *parent_item = SP_ITEM(sp_desktop_document(desktop)->getObjectByRepr(parent)); NR::Matrix local = sp_item_i2doc_affine(parent_item); - gchar affinestr[80]; - gchar *transform = NULL; - if (!local.test_identity() && sp_svg_transform_write(affinestr, 79, local.inverse())) { - transform = affinestr; - } + gchar *transform = sp_svg_transform_write(local); // now that we have the result, add it on the canvas if ( bop == bool_op_cut || bop == bool_op_slice ) { @@ -575,6 +571,8 @@ sp_selected_path_boolop(bool_op bop, const unsigned int verb, const Glib::ustrin Inkscape::GC::release(repr); } + g_free(transform); + sp_document_done(sp_desktop_document(desktop), verb, description); delete res; @@ -1574,8 +1572,12 @@ sp_selected_path_simplify_items(SPDesktop *desktop, continue; if (simplifyIndividualPaths) { - NR::Rect itemBbox = item->getBounds(sp_item_i2d_affine(item)); - simplifySize = L2(itemBbox.dimensions()); + NR::Maybe itemBbox = item->getBounds(sp_item_i2d_affine(item)); + if (itemBbox) { + simplifySize = L2(itemBbox->dimensions()); + } else { + simplifySize = 0; + } } @@ -1723,6 +1725,17 @@ Path_for_item(SPItem *item, bool doTransformation, bool transformFull) bpath=SP_CURVE_BPATH(curve); } + Path *dest = bpath_to_Path(bpath); + + if ( doTransformation ) { + if ( bpath ) g_free(bpath); + } else { + sp_curve_unref(curve); + } + return dest; +} + +Path *bpath_to_Path(NArtBpath const *bpath) { Path *dest = new Path; dest->SetBackData(false); { @@ -1776,12 +1789,6 @@ Path_for_item(SPItem *item, bool doTransformation, bool transformFull) if (closed) dest->Close(); } - - if ( doTransformation ) { - if ( bpath ) g_free(bpath); - } else { - sp_curve_unref(curve); - } return dest; } -- 2.30.2