X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Ftext-context.cpp;h=ad9211cbac0e363ef79d759c38fd2416288f3317;hb=19f2d6797853686cf668528be392548100e92025;hp=f2dd4bf2ba72b2bef1f6cb8d723a3ddfc1378e00;hpb=6c92c2b7a53374072574aeac6095974e45065ce8;p=inkscape.git diff --git a/src/text-context.cpp b/src/text-context.cpp index f2dd4bf2b..ad9211cba 100644 --- a/src/text-context.cpp +++ b/src/text-context.cpp @@ -44,11 +44,12 @@ #include "object-edit.h" #include "xml/repr.h" #include "xml/node-event-vector.h" -#include "prefs-utils.h" +#include "preferences.h" #include "rubberband.h" #include "sp-metrics.h" #include "context-fns.h" #include "verbs.h" +#include "shape-editor.h" #include "text-editing.h" @@ -131,13 +132,10 @@ sp_text_context_init(SPTextContext *tc) event_context->tolerance = 0; event_context->within_tolerance = false; - event_context->shape_repr = NULL; - event_context->shape_knot_holder = NULL; - tc->imc = NULL; tc->text = NULL; - tc->pdoc = NR::Point(0, 0); + tc->pdoc = Geom::Point(0, 0); new (&tc->text_sel_start) Inkscape::Text::Layout::iterator(); new (&tc->text_sel_end) Inkscape::Text::Layout::iterator(); new (&tc->text_selection_quads) std::vector(); @@ -171,6 +169,10 @@ sp_text_context_dispose(GObject *obj) tc->style_set_connection.~connection(); tc->sel_changed_connection.~connection(); tc->sel_modified_connection.~connection(); + + delete ec->shape_editor; + ec->shape_editor = NULL; + tc->text_sel_end.~iterator(); tc->text_sel_start.~iterator(); tc->text_selection_quads.~vector(); @@ -182,32 +184,22 @@ sp_text_context_dispose(GObject *obj) tc->grabbed = NULL; } - Inkscape::Rubberband::get()->stop(); - - if (ec->shape_knot_holder) { - sp_knot_holder_destroy(ec->shape_knot_holder); - ec->shape_knot_holder = NULL; - } - if (ec->shape_repr) { // remove old listener - sp_repr_remove_listener_by_data(ec->shape_repr, ec); - Inkscape::GC::release(ec->shape_repr); - ec->shape_repr = 0; - } + Inkscape::Rubberband::get(ec->desktop)->stop(); } -static Inkscape::XML::NodeEventVector ec_shape_repr_events = { - NULL, /* child_added */ - NULL, /* child_removed */ - ec_shape_event_attr_changed, - NULL, /* content_changed */ - NULL /* order_changed */ -}; - static void sp_text_context_setup(SPEventContext *ec) { SPTextContext *tc = SP_TEXT_CONTEXT(ec); SPDesktop *desktop = ec->desktop; + GtkSettings* settings = gtk_settings_get_default(); + gint timeout = 0; + g_object_get( settings, "gtk-cursor-blink-time", &timeout, NULL ); + if (timeout < 0) { + timeout = 200; + } else { + timeout /= 2; + } tc->cursor = sp_canvas_item_new(sp_desktop_controls(desktop), SP_TYPE_CTRLLINE, NULL); sp_ctrlline_set_coords(SP_CTRLLINE(tc->cursor), 100, 0, 100, 100); @@ -215,16 +207,16 @@ sp_text_context_setup(SPEventContext *ec) sp_canvas_item_hide(tc->cursor); tc->indicator = sp_canvas_item_new(sp_desktop_controls(desktop), SP_TYPE_CTRLRECT, NULL); - SP_CTRLRECT(tc->indicator)->setRectangle(NR::Rect(NR::Point(0, 0), NR::Point(100, 100))); + SP_CTRLRECT(tc->indicator)->setRectangle(Geom::Rect(Geom::Point(0, 0), Geom::Point(100, 100))); SP_CTRLRECT(tc->indicator)->setColor(0x0000ff7f, false, 0); sp_canvas_item_hide(tc->indicator); tc->frame = sp_canvas_item_new(sp_desktop_controls(desktop), SP_TYPE_CTRLRECT, NULL); - SP_CTRLRECT(tc->frame)->setRectangle(NR::Rect(NR::Point(0, 0), NR::Point(100, 100))); + SP_CTRLRECT(tc->frame)->setRectangle(Geom::Rect(Geom::Point(0, 0), Geom::Point(100, 100))); SP_CTRLRECT(tc->frame)->setColor(0x0000ff7f, false, 0); sp_canvas_item_hide(tc->frame); - tc->timeout = gtk_timeout_add(250, (GtkFunction) sp_text_context_timeout, ec); + tc->timeout = gtk_timeout_add(timeout, (GtkFunction) sp_text_context_timeout, ec); tc->imc = gtk_im_multicontext_new(); if (tc->imc) { @@ -251,15 +243,11 @@ sp_text_context_setup(SPEventContext *ec) if (((SPEventContextClass *) parent_class)->setup) ((SPEventContextClass *) parent_class)->setup(ec); + ec->shape_editor = new ShapeEditor(ec->desktop); + SPItem *item = sp_desktop_selection(ec->desktop)->singleItem(); if (item && SP_IS_FLOWTEXT (item) && SP_FLOWTEXT(item)->has_internal_frame()) { - ec->shape_knot_holder = sp_item_knot_holder(item, ec->desktop); - Inkscape::XML::Node *shape_repr = SP_OBJECT_REPR(SP_FLOWTEXT(item)->get_frame(NULL)); - if (shape_repr) { - ec->shape_repr = shape_repr; - Inkscape::GC::anchor(shape_repr); - sp_repr_add_listener(shape_repr, &ec_shape_repr_events, ec); - } + ec->shape_editor->set_item(item, SH_KNOTHOLDER); } tc->sel_changed_connection = sp_desktop_selection(desktop)->connectChanged( @@ -277,10 +265,11 @@ sp_text_context_setup(SPEventContext *ec) sp_text_context_selection_changed(sp_desktop_selection(desktop), tc); - if (prefs_get_int_attribute("tools.text", "selcue", 0) != 0) { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + if (prefs->getBool("/tools/text/selcue")) { ec->enableSelectionCue(); } - if (prefs_get_int_attribute("tools.text", "gradientdrag", 0) != 0) { + if (prefs->getBool("/tools/text/gradientdrag")) { ec->enableGrDrag(); } } @@ -338,10 +327,10 @@ sp_text_context_finish(SPEventContext *ec) static gint -sp_text_context_item_handler(SPEventContext *ec, SPItem *item, GdkEvent *event) +sp_text_context_item_handler(SPEventContext *event_context, SPItem *item, GdkEvent *event) { - SPTextContext *tc = SP_TEXT_CONTEXT(ec); - SPDesktop *desktop = ec->desktop; + SPTextContext *tc = SP_TEXT_CONTEXT(event_context); + SPDesktop *desktop = event_context->desktop; SPItem *item_ungrouped; gint ret = FALSE; @@ -350,14 +339,14 @@ sp_text_context_item_handler(SPEventContext *ec, SPItem *item, GdkEvent *event) switch (event->type) { case GDK_BUTTON_PRESS: - if (event->button.button == 1) { + if (event->button.button == 1 && !event_context->space_panning) { // find out clicked item, disregarding groups - item_ungrouped = desktop->item_at_point(NR::Point(event->button.x, event->button.y), TRUE); + item_ungrouped = desktop->item_at_point(Geom::Point(event->button.x, event->button.y), TRUE); if (SP_IS_TEXT(item_ungrouped) || SP_IS_FLOWTEXT(item_ungrouped)) { - sp_desktop_selection(ec->desktop)->set(item_ungrouped); + sp_desktop_selection(desktop)->set(item_ungrouped); if (tc->text) { // find out click point in document coordinates - NR::Point p = ec->desktop->w2d(NR::Point(event->button.x, event->button.y)); + Geom::Point p = desktop->w2d(Geom::Point(event->button.x, event->button.y)); // set the cursor closest to that point tc->text_sel_start = tc->text_sel_end = sp_te_get_position_by_coords(tc->text, p); // update display @@ -395,17 +384,17 @@ sp_text_context_item_handler(SPEventContext *ec, SPItem *item, GdkEvent *event) } break; case GDK_BUTTON_RELEASE: - if (event->button.button == 1 && tc->dragging) { + if (event->button.button == 1 && tc->dragging && !event_context->space_panning) { tc->dragging = 0; ret = TRUE; } break; case GDK_MOTION_NOTIFY: - if (event->motion.state & GDK_BUTTON1_MASK && tc->dragging) { + if (event->motion.state & GDK_BUTTON1_MASK && tc->dragging && !event_context->space_panning) { Inkscape::Text::Layout const *layout = te_get_layout(tc->text); if (!layout) break; // find out click point in document coordinates - NR::Point p = ec->desktop->w2d(NR::Point(event->button.x, event->button.y)); + Geom::Point p = desktop->w2d(Geom::Point(event->button.x, event->button.y)); // set the cursor closest to that point Inkscape::Text::Layout::iterator new_end = sp_te_get_position_by_coords(tc->text, p); if (tc->dragging == 2) { @@ -429,22 +418,23 @@ sp_text_context_item_handler(SPEventContext *ec, SPItem *item, GdkEvent *event) sp_text_context_update_cursor(tc); sp_text_context_update_text_selection(tc); } + gobble_motion_events(GDK_BUTTON1_MASK); ret = TRUE; break; } // find out item under mouse, disregarding groups - item_ungrouped = desktop->item_at_point(NR::Point(event->button.x, event->button.y), TRUE); + item_ungrouped = desktop->item_at_point(Geom::Point(event->button.x, event->button.y), TRUE); if (SP_IS_TEXT(item_ungrouped) || SP_IS_FLOWTEXT(item_ungrouped)) { sp_canvas_item_show(tc->indicator); - NR::Maybe ibbox = sp_item_bbox_desktop(item_ungrouped); + Geom::OptRect ibbox = sp_item_bbox_desktop(item_ungrouped); if (ibbox) { SP_CTRLRECT(tc->indicator)->setRectangle(*ibbox); } - ec->cursor_shape = cursor_text_insert_xpm; - ec->hot_x = 7; - ec->hot_y = 10; - sp_event_context_update_cursor(ec); + event_context->cursor_shape = cursor_text_insert_xpm; + event_context->hot_x = 7; + event_context->hot_y = 10; + sp_event_context_update_cursor(event_context); sp_text_context_update_text_selection(tc); if (SP_IS_TEXT (item_ungrouped)) { @@ -464,7 +454,7 @@ sp_text_context_item_handler(SPEventContext *ec, SPItem *item, GdkEvent *event) if (!ret) { if (((SPEventContextClass *) parent_class)->item_handler) - ret = ((SPEventContextClass *) parent_class)->item_handler(ec, item, event); + ret = ((SPEventContextClass *) parent_class)->item_handler(event_context, item, event); } return ret; @@ -481,10 +471,10 @@ sp_text_context_setup_text(SPTextContext *tc) rtext->setAttribute("xml:space", "preserve"); // we preserve spaces in the text objects we create /* Set style */ - sp_desktop_apply_style_tool(SP_EVENT_CONTEXT_DESKTOP(ec), rtext, "tools.text", true); + sp_desktop_apply_style_tool(SP_EVENT_CONTEXT_DESKTOP(ec), rtext, "/tools/text", true); - sp_repr_set_svg_double(rtext, "x", tc->pdoc[NR::X]); - sp_repr_set_svg_double(rtext, "y", tc->pdoc[NR::Y]); + sp_repr_set_svg_double(rtext, "x", tc->pdoc[Geom::X]); + sp_repr_set_svg_double(rtext, "y", tc->pdoc[Geom::Y]); /* Create */ Inkscape::XML::Node *rtspan = xml_doc->createElement("svg:tspan"); @@ -501,9 +491,10 @@ sp_text_context_setup_text(SPTextContext *tc) /* yes, it's immediate .. why does it matter? */ sp_desktop_selection(ec->desktop)->set(text_item); Inkscape::GC::release(rtext); - text_item->transform = SP_ITEM(ec->desktop->currentRoot())->getRelativeTransform(ec->desktop->currentLayer()); + text_item->transform = sp_item_i2doc_affine(SP_ITEM(ec->desktop->currentLayer())).inverse(); + text_item->updateRepr(); - sp_document_done(sp_desktop_document(ec->desktop), SP_VERB_CONTEXT_TEXT, + sp_document_done(sp_desktop_document(ec->desktop), SP_VERB_CONTEXT_TEXT, _("Create text")); } @@ -542,7 +533,7 @@ insert_uni_char(SPTextContext *const tc) tc->text_sel_start = tc->text_sel_end = sp_te_replace(tc->text, tc->text_sel_start, tc->text_sel_end, u); sp_text_context_update_cursor(tc); sp_text_context_update_text_selection(tc); - sp_document_done(sp_desktop_document(tc->desktop), SP_VERB_DIALOG_TRANSFORM, + sp_document_done(sp_desktop_document(tc->desktop), SP_VERB_DIALOG_TRANSFORM, _("Insert Unicode character")); } } @@ -585,39 +576,37 @@ show_curr_uni_char(SPTextContext *const tc) } static gint -sp_text_context_root_handler(SPEventContext *const ec, GdkEvent *const event) +sp_text_context_root_handler(SPEventContext *const event_context, GdkEvent *const event) { - SPTextContext *const tc = SP_TEXT_CONTEXT(ec); + SPTextContext *const tc = SP_TEXT_CONTEXT(event_context); - SPDesktop *desktop = ec->desktop; + SPDesktop *desktop = event_context->desktop; sp_canvas_item_hide(tc->indicator); sp_text_context_validate_cursor_iterators(tc); - ec->tolerance = prefs_get_int_attribute_limited("options.dragtolerance", "value", 0, 0, 100); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + event_context->tolerance = prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100); switch (event->type) { case GDK_BUTTON_PRESS: - if (event->button.button == 1) { - - SPDesktop *desktop = SP_EVENT_CONTEXT_DESKTOP(ec); + if (event->button.button == 1 && !event_context->space_panning) { if (Inkscape::have_viable_layer(desktop, desktop->messageStack()) == false) { return TRUE; } // save drag origin - ec->xp = (gint) event->button.x; - ec->yp = (gint) event->button.y; - ec->within_tolerance = true; + event_context->xp = (gint) event->button.x; + event_context->yp = (gint) event->button.y; + event_context->within_tolerance = true; - NR::Point const button_pt(event->button.x, event->button.y); + Geom::Point const button_pt(event->button.x, event->button.y); tc->p0 = desktop->w2d(button_pt); - Inkscape::Rubberband::get()->start(desktop, tc->p0); + Inkscape::Rubberband::get(desktop)->start(desktop, tc->p0); sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate), - GDK_KEY_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | - GDK_POINTER_MOTION_MASK, + GDK_KEY_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK, NULL, event->button.time); tc->grabbed = SP_CANVAS_ITEM(desktop->acetate); tc->creating = 1; @@ -630,54 +619,54 @@ sp_text_context_root_handler(SPEventContext *const ec, GdkEvent *const event) if (tc->over_text) { tc->over_text = 0; // update cursor and statusbar: we are not over a text object now - ec->cursor_shape = cursor_text_xpm; - ec->hot_x = 7; - ec->hot_y = 7; - sp_event_context_update_cursor(ec); + event_context->cursor_shape = cursor_text_xpm; + event_context->hot_x = 7; + event_context->hot_y = 7; + sp_event_context_update_cursor(event_context); desktop->event_context->defaultMessageContext()->clear(); } - if (tc->creating && event->motion.state & GDK_BUTTON1_MASK) { - if ( ec->within_tolerance - && ( abs( (gint) event->motion.x - ec->xp ) < ec->tolerance ) - && ( abs( (gint) event->motion.y - ec->yp ) < ec->tolerance ) ) { + if (tc->creating && event->motion.state & GDK_BUTTON1_MASK && !event_context->space_panning) { + if ( event_context->within_tolerance + && ( abs( (gint) event->motion.x - event_context->xp ) < event_context->tolerance ) + && ( abs( (gint) event->motion.y - event_context->yp ) < event_context->tolerance ) ) { break; // do not drag if we're within tolerance from origin } // Once the user has moved farther than tolerance from the original location // (indicating they intend to draw, not click), then always process the // motion notify coordinates as given (no snapping back to origin) - ec->within_tolerance = false; + event_context->within_tolerance = false; - NR::Point const motion_pt(event->motion.x, event->motion.y); - NR::Point const p = desktop->w2d(motion_pt); + Geom::Point const motion_pt(event->motion.x, event->motion.y); + Geom::Point const p = desktop->w2d(motion_pt); - Inkscape::Rubberband::get()->move(p); + Inkscape::Rubberband::get(desktop)->move(p); gobble_motion_events(GDK_BUTTON1_MASK); // status text - GString *xs = SP_PX_TO_METRIC_STRING(fabs((p - tc->p0)[NR::X]), desktop->namedview->getDefaultMetric()); - GString *ys = SP_PX_TO_METRIC_STRING(fabs((p - tc->p0)[NR::Y]), desktop->namedview->getDefaultMetric()); - ec->_message_context->setF(Inkscape::NORMAL_MESSAGE, _("Flowed text frame: %s × %s"), xs->str, ys->str); + GString *xs = SP_PX_TO_METRIC_STRING(fabs((p - tc->p0)[Geom::X]), desktop->namedview->getDefaultMetric()); + GString *ys = SP_PX_TO_METRIC_STRING(fabs((p - tc->p0)[Geom::Y]), desktop->namedview->getDefaultMetric()); + event_context->_message_context->setF(Inkscape::IMMEDIATE_MESSAGE, _("Flowed text frame: %s × %s"), xs->str, ys->str); g_string_free(xs, FALSE); g_string_free(ys, FALSE); } break; case GDK_BUTTON_RELEASE: - if (event->button.button == 1) { + if (event->button.button == 1 && !event_context->space_panning) { if (tc->grabbed) { sp_canvas_item_ungrab(tc->grabbed, GDK_CURRENT_TIME); tc->grabbed = NULL; } - Inkscape::Rubberband::get()->stop(); + Inkscape::Rubberband::get(desktop)->stop(); - if (tc->creating && ec->within_tolerance) { + if (tc->creating && event_context->within_tolerance) { /* Button 1, set X & Y & new item */ sp_desktop_selection(desktop)->clear(); - NR::Point dtp = ec->desktop->w2d(NR::Point(event->button.x, event->button.y)); - tc->pdoc = sp_desktop_dt2root_xy_point(ec->desktop, dtp); + Geom::Point dtp = desktop->w2d(Geom::Point(event->button.x, event->button.y)); + tc->pdoc = sp_desktop_dt2doc_xy_point(desktop, dtp); tc->show = TRUE; tc->phase = 1; @@ -687,26 +676,26 @@ sp_text_context_root_handler(SPEventContext *const ec, GdkEvent *const event) sp_canvas_item_show(tc->cursor); // Cursor height is defined by the new text object's font size; it needs to be set // articifically here, for the text object does not exist yet: - double cursor_height = sp_desktop_get_font_size_tool(ec->desktop); - sp_ctrlline_set_coords(SP_CTRLLINE(tc->cursor), dtp, dtp + NR::Point(0, cursor_height)); - ec->_message_context->set(Inkscape::NORMAL_MESSAGE, _("Type text; Enter to start new line.")); // FIXME:: this is a copy of a string from _update_cursor below, do not desync + double cursor_height = sp_desktop_get_font_size_tool(desktop); + sp_ctrlline_set_coords(SP_CTRLLINE(tc->cursor), dtp, dtp + Geom::Point(0, cursor_height)); + event_context->_message_context->set(Inkscape::NORMAL_MESSAGE, _("Type text; Enter to start new line.")); // FIXME:: this is a copy of a string from _update_cursor below, do not desync - ec->within_tolerance = false; + event_context->within_tolerance = false; } else if (tc->creating) { - NR::Point const button_pt(event->button.x, event->button.y); - NR::Point p1 = desktop->w2d(button_pt); - double cursor_height = sp_desktop_get_font_size_tool(ec->desktop); - if (fabs(p1[NR::Y] - tc->p0[NR::Y]) > cursor_height) { + Geom::Point const button_pt(event->button.x, event->button.y); + Geom::Point p1 = desktop->w2d(button_pt); + double cursor_height = sp_desktop_get_font_size_tool(desktop); + if (fabs(p1[Geom::Y] - tc->p0[Geom::Y]) > cursor_height) { // otherwise even one line won't fit; most probably a slip of hand (even if bigger than tolerance) SPItem *ft = create_flowtext_with_internal_frame (desktop, tc->p0, p1); /* Set style */ - sp_desktop_apply_style_tool(SP_EVENT_CONTEXT_DESKTOP(ec), SP_OBJECT_REPR(ft), "tools.text", true); + sp_desktop_apply_style_tool(desktop, SP_OBJECT_REPR(ft), "/tools/text", true); sp_desktop_selection(desktop)->set(ft); - ec->desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Flowed text is created.")); - sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_TEXT, + desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Flowed text is created.")); + sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_TEXT, _("Create flowed text")); } else { - ec->desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("The frame is too small for the current font size. Flowed text not created.")); + desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("The frame is too small for the current font size. Flowed text not created.")); } } tc->creating = false; @@ -766,7 +755,7 @@ sp_text_context_root_handler(SPEventContext *const ec, GdkEvent *const event) } /* Exit unimode. */ tc->unimode = false; - ec->defaultMessageContext()->clear(); + event_context->defaultMessageContext()->clear(); return TRUE; } @@ -774,7 +763,7 @@ sp_text_context_root_handler(SPEventContext *const ec, GdkEvent *const event) // Cancel unimode. tc->unimode = false; gtk_im_context_reset(tc->imc); - ec->defaultMessageContext()->clear(); + event_context->defaultMessageContext()->clear(); return TRUE; } @@ -811,7 +800,17 @@ sp_text_context_root_handler(SPEventContext *const ec, GdkEvent *const event) } } - bool (Inkscape::Text::Layout::iterator::*cursor_movement_operator)() = NULL; + Inkscape::Text::Layout::iterator old_start = tc->text_sel_start; + Inkscape::Text::Layout::iterator old_end = tc->text_sel_end; + bool cursor_moved = false; + int screenlines = 1; + if (tc->text) { + double spacing = sp_te_get_average_linespacing(tc->text); + Geom::Rect const d = desktop->get_display_area(); + screenlines = (int) floor(fabs(d.min()[Geom::Y] - d.max()[Geom::Y])/spacing) - 1; + if (screenlines <= 0) + screenlines = 1; + } /* Neither unimode nor IM consumed key; process text tool shortcuts */ switch (group0_keyval) { @@ -832,8 +831,8 @@ sp_text_context_root_handler(SPEventContext *const ec, GdkEvent *const event) tc->text_sel_start = tc->text_sel_end = sp_te_replace(tc->text, tc->text_sel_start, tc->text_sel_end, "\302\240"); sp_text_context_update_cursor(tc); sp_text_context_update_text_selection(tc); - ec->desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("No-break space")); - sp_document_done(sp_desktop_document(ec->desktop), SP_VERB_CONTEXT_TEXT, + desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("No-break space")); + sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_TEXT, _("Insert no-break space")); return TRUE; } @@ -843,11 +842,11 @@ sp_text_context_root_handler(SPEventContext *const ec, GdkEvent *const event) if (MOD__CTRL_ONLY || (MOD__CTRL && MOD__SHIFT)) { if (tc->unimode) { tc->unimode = false; - ec->defaultMessageContext()->clear(); + event_context->defaultMessageContext()->clear(); } else { tc->unimode = true; tc->unipos = 0; - ec->defaultMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("Unicode (Enter to finish): ")); + event_context->defaultMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("Unicode (Enter to finish): ")); } if (tc->imc) { gtk_im_context_reset(tc->imc); @@ -870,7 +869,7 @@ sp_text_context_root_handler(SPEventContext *const ec, GdkEvent *const event) sp_repr_css_set_property(css, "font-weight", "normal"); sp_te_apply_style(tc->text, tc->text_sel_start, tc->text_sel_end, css); sp_repr_css_attr_unref(css); - sp_document_done(sp_desktop_document(ec->desktop), SP_VERB_CONTEXT_TEXT, + sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_TEXT, _("Make bold")); sp_text_context_update_cursor(tc); sp_text_context_update_text_selection(tc); @@ -888,7 +887,7 @@ sp_text_context_root_handler(SPEventContext *const ec, GdkEvent *const event) sp_repr_css_set_property(css, "font-style", "normal"); sp_te_apply_style(tc->text, tc->text_sel_start, tc->text_sel_end, css); sp_repr_css_attr_unref(css); - sp_document_done(sp_desktop_document(ec->desktop), SP_VERB_CONTEXT_TEXT, + sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_TEXT, _("Make italic")); sp_text_context_update_cursor(tc); sp_text_context_update_text_selection(tc); @@ -912,37 +911,87 @@ sp_text_context_root_handler(SPEventContext *const ec, GdkEvent *const event) case GDK_Return: case GDK_KP_Enter: + { if (!tc->text) { // printable key; create text if none (i.e. if nascent_object) sp_text_context_setup_text(tc); tc->nascent_object = 0; // we don't need it anymore, having created a real } - tc->text_sel_start = tc->text_sel_end = sp_te_delete(tc->text, tc->text_sel_start, tc->text_sel_end); + + iterator_pair enter_pair; + bool success = sp_te_delete(tc->text, tc->text_sel_start, tc->text_sel_end, enter_pair); + (void)success; // TODO cleanup + tc->text_sel_start = tc->text_sel_end = enter_pair.first; + tc->text_sel_start = tc->text_sel_end = sp_te_insert_line(tc->text, tc->text_sel_start); + sp_text_context_update_cursor(tc); sp_text_context_update_text_selection(tc); - sp_document_done(sp_desktop_document(ec->desktop), SP_VERB_CONTEXT_TEXT, + sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_TEXT, _("New line")); return TRUE; + } case GDK_BackSpace: if (tc->text) { // if nascent_object, do nothing, but return TRUE; same for all other delete and move keys - if (tc->text_sel_start == tc->text_sel_end) + + bool noSelection = false; + + if (tc->text_sel_start == tc->text_sel_end) { tc->text_sel_start.prevCursorPosition(); - tc->text_sel_start = tc->text_sel_end = sp_te_delete(tc->text, tc->text_sel_start, tc->text_sel_end); + noSelection = true; + } + + iterator_pair bspace_pair; + bool success = sp_te_delete(tc->text, tc->text_sel_start, tc->text_sel_end, bspace_pair); + + if (noSelection) { + if (success) { + tc->text_sel_start = tc->text_sel_end = bspace_pair.first; + } else { // nothing deleted + tc->text_sel_start = tc->text_sel_end = bspace_pair.second; + } + } else { + if (success) { + tc->text_sel_start = tc->text_sel_end = bspace_pair.first; + } else { // nothing deleted + tc->text_sel_start = bspace_pair.first; + tc->text_sel_end = bspace_pair.second; + } + } + sp_text_context_update_cursor(tc); sp_text_context_update_text_selection(tc); - sp_document_done(sp_desktop_document(ec->desktop), SP_VERB_CONTEXT_TEXT, + sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_TEXT, _("Backspace")); } return TRUE; case GDK_Delete: case GDK_KP_Delete: if (tc->text) { - if (tc->text_sel_start == tc->text_sel_end) + bool noSelection = false; + + if (tc->text_sel_start == tc->text_sel_end) { tc->text_sel_end.nextCursorPosition(); - tc->text_sel_start = tc->text_sel_end = sp_te_delete(tc->text, tc->text_sel_start, tc->text_sel_end); + noSelection = true; + } + + iterator_pair del_pair; + bool success = sp_te_delete(tc->text, tc->text_sel_start, tc->text_sel_end, del_pair); + + if (noSelection) { + tc->text_sel_start = tc->text_sel_end = del_pair.first; + } else { + if (success) { + tc->text_sel_start = tc->text_sel_end = del_pair.first; + } else { // nothing deleted + tc->text_sel_start = del_pair.first; + tc->text_sel_end = del_pair.second; + } + } + + sp_text_context_update_cursor(tc); sp_text_context_update_text_selection(tc); - sp_document_done(sp_desktop_document(ec->desktop), SP_VERB_CONTEXT_TEXT, + sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_TEXT, _("Delete")); } return TRUE; @@ -951,17 +1000,22 @@ sp_text_context_root_handler(SPEventContext *const ec, GdkEvent *const event) case GDK_KP_4: if (tc->text) { if (MOD__ALT) { + gint mul = 1 + gobble_key_events( + get_group0_keyval(&event->key), 0); // with any mask if (MOD__SHIFT) - sp_te_adjust_kerning_screen(tc->text, tc->text_sel_start, tc->text_sel_end, ec->desktop, NR::Point(-10, 0)); + sp_te_adjust_kerning_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, Geom::Point(mul*-10, 0)); else - sp_te_adjust_kerning_screen(tc->text, tc->text_sel_start, tc->text_sel_end, ec->desktop, NR::Point(-1, 0)); + sp_te_adjust_kerning_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, Geom::Point(mul*-1, 0)); sp_text_context_update_cursor(tc); sp_text_context_update_text_selection(tc); - sp_document_maybe_done(sp_desktop_document(ec->desktop), "kern:left", SP_VERB_CONTEXT_TEXT, + sp_document_maybe_done(sp_desktop_document(desktop), "kern:left", SP_VERB_CONTEXT_TEXT, _("Kern to the left")); } else { - cursor_movement_operator = MOD__CTRL ? &Inkscape::Text::Layout::iterator::cursorLeftWithControl - : &Inkscape::Text::Layout::iterator::cursorLeft; + if (MOD__CTRL) + tc->text_sel_end.cursorLeftWithControl(); + else + tc->text_sel_end.cursorLeft(); + cursor_moved = true; break; } } @@ -971,17 +1025,22 @@ sp_text_context_root_handler(SPEventContext *const ec, GdkEvent *const event) case GDK_KP_6: if (tc->text) { if (MOD__ALT) { + gint mul = 1 + gobble_key_events( + get_group0_keyval(&event->key), 0); // with any mask if (MOD__SHIFT) - sp_te_adjust_kerning_screen(tc->text, tc->text_sel_start, tc->text_sel_end, ec->desktop, NR::Point(10, 0)); + sp_te_adjust_kerning_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, Geom::Point(mul*10, 0)); else - sp_te_adjust_kerning_screen(tc->text, tc->text_sel_start, tc->text_sel_end, ec->desktop, NR::Point(1, 0)); + sp_te_adjust_kerning_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, Geom::Point(mul*1, 0)); sp_text_context_update_cursor(tc); sp_text_context_update_text_selection(tc); - sp_document_maybe_done(sp_desktop_document(ec->desktop), "kern:right", SP_VERB_CONTEXT_TEXT, + sp_document_maybe_done(sp_desktop_document(desktop), "kern:right", SP_VERB_CONTEXT_TEXT, _("Kern to the right")); } else { - cursor_movement_operator = MOD__CTRL ? &Inkscape::Text::Layout::iterator::cursorRightWithControl - : &Inkscape::Text::Layout::iterator::cursorRight; + if (MOD__CTRL) + tc->text_sel_end.cursorRightWithControl(); + else + tc->text_sel_end.cursorRight(); + cursor_moved = true; break; } } @@ -991,18 +1050,23 @@ sp_text_context_root_handler(SPEventContext *const ec, GdkEvent *const event) case GDK_KP_8: if (tc->text) { if (MOD__ALT) { + gint mul = 1 + gobble_key_events( + get_group0_keyval(&event->key), 0); // with any mask if (MOD__SHIFT) - sp_te_adjust_kerning_screen(tc->text, tc->text_sel_start, tc->text_sel_end, ec->desktop, NR::Point(0, -10)); + sp_te_adjust_kerning_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, Geom::Point(0, mul*-10)); else - sp_te_adjust_kerning_screen(tc->text, tc->text_sel_start, tc->text_sel_end, ec->desktop, NR::Point(0, -1)); + sp_te_adjust_kerning_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, Geom::Point(0, mul*-1)); sp_text_context_update_cursor(tc); sp_text_context_update_text_selection(tc); - sp_document_maybe_done(sp_desktop_document(ec->desktop), "kern:up", SP_VERB_CONTEXT_TEXT, + sp_document_maybe_done(sp_desktop_document(desktop), "kern:up", SP_VERB_CONTEXT_TEXT, _("Kern up")); } else { - cursor_movement_operator = MOD__CTRL ? &Inkscape::Text::Layout::iterator::cursorUpWithControl - : &Inkscape::Text::Layout::iterator::cursorUp; + if (MOD__CTRL) + tc->text_sel_end.cursorUpWithControl(); + else + tc->text_sel_end.cursorUp(); + cursor_moved = true; break; } } @@ -1012,18 +1076,23 @@ sp_text_context_root_handler(SPEventContext *const ec, GdkEvent *const event) case GDK_KP_2: if (tc->text) { if (MOD__ALT) { + gint mul = 1 + gobble_key_events( + get_group0_keyval(&event->key), 0); // with any mask if (MOD__SHIFT) - sp_te_adjust_kerning_screen(tc->text, tc->text_sel_start, tc->text_sel_end, ec->desktop, NR::Point(0, 10)); + sp_te_adjust_kerning_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, Geom::Point(0, mul*10)); else - sp_te_adjust_kerning_screen(tc->text, tc->text_sel_start, tc->text_sel_end, ec->desktop, NR::Point(0, 1)); + sp_te_adjust_kerning_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, Geom::Point(0, mul*1)); sp_text_context_update_cursor(tc); sp_text_context_update_text_selection(tc); - sp_document_maybe_done(sp_desktop_document(ec->desktop), "kern:down", SP_VERB_CONTEXT_TEXT, + sp_document_maybe_done(sp_desktop_document(desktop), "kern:down", SP_VERB_CONTEXT_TEXT, _("Kern down")); } else { - cursor_movement_operator = MOD__CTRL ? &Inkscape::Text::Layout::iterator::cursorDownWithControl - : &Inkscape::Text::Layout::iterator::cursorDown; + if (MOD__CTRL) + tc->text_sel_end.cursorDownWithControl(); + else + tc->text_sel_end.cursorDown(); + cursor_moved = true; break; } } @@ -1032,9 +1101,10 @@ sp_text_context_root_handler(SPEventContext *const ec, GdkEvent *const event) case GDK_KP_Home: if (tc->text) { if (MOD__CTRL) - cursor_movement_operator = &Inkscape::Text::Layout::iterator::thisStartOfShape; + tc->text_sel_end.thisStartOfShape(); else - cursor_movement_operator = &Inkscape::Text::Layout::iterator::thisStartOfLine; + tc->text_sel_end.thisStartOfLine(); + cursor_moved = true; break; } return TRUE; @@ -1042,9 +1112,26 @@ sp_text_context_root_handler(SPEventContext *const ec, GdkEvent *const event) case GDK_KP_End: if (tc->text) { if (MOD__CTRL) - cursor_movement_operator = &Inkscape::Text::Layout::iterator::nextStartOfShape; + tc->text_sel_end.nextStartOfShape(); else - cursor_movement_operator = &Inkscape::Text::Layout::iterator::thisEndOfLine; + tc->text_sel_end.thisEndOfLine(); + cursor_moved = true; + break; + } + return TRUE; + case GDK_Page_Down: + case GDK_KP_Page_Down: + if (tc->text) { + tc->text_sel_end.cursorDown(screenlines); + cursor_moved = true; + break; + } + return TRUE; + case GDK_Page_Up: + case GDK_KP_Page_Up: + if (tc->text) { + tc->text_sel_end.cursorUp(screenlines); + cursor_moved = true; break; } return TRUE; @@ -1055,9 +1142,9 @@ sp_text_context_root_handler(SPEventContext *const ec, GdkEvent *const event) sp_canvas_item_ungrab(tc->grabbed, GDK_CURRENT_TIME); tc->grabbed = NULL; } - Inkscape::Rubberband::get()->stop(); + Inkscape::Rubberband::get(desktop)->stop(); } else { - sp_desktop_selection(ec->desktop)->clear(); + sp_desktop_selection(desktop)->clear(); } tc->nascent_object = FALSE; return TRUE; @@ -1067,14 +1154,14 @@ sp_text_context_root_handler(SPEventContext *const ec, GdkEvent *const event) if (MOD__ALT) { if (MOD__SHIFT) { // FIXME: alt+shift+[] does not work, don't know why - sp_te_adjust_rotation_screen(tc->text, tc->text_sel_start, tc->text_sel_end, ec->desktop, -10); + sp_te_adjust_rotation_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, -10); } else { - sp_te_adjust_rotation_screen(tc->text, tc->text_sel_start, tc->text_sel_end, ec->desktop, -1); + sp_te_adjust_rotation_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, -1); } } else { - sp_te_adjust_rotation(tc->text, tc->text_sel_start, tc->text_sel_end, ec->desktop, -90); + sp_te_adjust_rotation(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, -90); } - sp_document_maybe_done(sp_desktop_document(ec->desktop), "textrot:ccw", SP_VERB_CONTEXT_TEXT, + sp_document_maybe_done(sp_desktop_document(desktop), "textrot:ccw", SP_VERB_CONTEXT_TEXT, _("Rotate counterclockwise")); sp_text_context_update_cursor(tc); sp_text_context_update_text_selection(tc); @@ -1088,14 +1175,14 @@ sp_text_context_root_handler(SPEventContext *const ec, GdkEvent *const event) if (MOD__ALT) { if (MOD__SHIFT) { // FIXME: alt+shift+[] does not work, don't know why - sp_te_adjust_rotation_screen(tc->text, tc->text_sel_start, tc->text_sel_end, ec->desktop, 10); + sp_te_adjust_rotation_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, 10); } else { - sp_te_adjust_rotation_screen(tc->text, tc->text_sel_start, tc->text_sel_end, ec->desktop, 1); + sp_te_adjust_rotation_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, 1); } } else { - sp_te_adjust_rotation(tc->text, tc->text_sel_start, tc->text_sel_end, ec->desktop, 90); + sp_te_adjust_rotation(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, 90); } - sp_document_maybe_done(sp_desktop_document(ec->desktop), "textrot:cw", SP_VERB_CONTEXT_TEXT, + sp_document_maybe_done(sp_desktop_document(desktop), "textrot:cw", SP_VERB_CONTEXT_TEXT, _("Rotate clockwise")); sp_text_context_update_cursor(tc); sp_text_context_update_text_selection(tc); @@ -1109,18 +1196,18 @@ sp_text_context_root_handler(SPEventContext *const ec, GdkEvent *const event) if (MOD__ALT) { if (MOD__CTRL) { if (MOD__SHIFT) - sp_te_adjust_linespacing_screen(tc->text, tc->text_sel_start, tc->text_sel_end, ec->desktop, -10); + sp_te_adjust_linespacing_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, -10); else - sp_te_adjust_linespacing_screen(tc->text, tc->text_sel_start, tc->text_sel_end, ec->desktop, -1); - sp_document_maybe_done(sp_desktop_document(ec->desktop), "linespacing:dec", SP_VERB_CONTEXT_TEXT, + sp_te_adjust_linespacing_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, -1); + sp_document_maybe_done(sp_desktop_document(desktop), "linespacing:dec", SP_VERB_CONTEXT_TEXT, _("Contract line spacing")); } else { if (MOD__SHIFT) - sp_te_adjust_tspan_letterspacing_screen(tc->text, tc->text_sel_start, tc->text_sel_end, ec->desktop, -10); + sp_te_adjust_tspan_letterspacing_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, -10); else - sp_te_adjust_tspan_letterspacing_screen(tc->text, tc->text_sel_start, tc->text_sel_end, ec->desktop, -1); - sp_document_maybe_done(sp_desktop_document(ec->desktop), "letterspacing:dec", SP_VERB_CONTEXT_TEXT, + sp_te_adjust_tspan_letterspacing_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, -1); + sp_document_maybe_done(sp_desktop_document(desktop), "letterspacing:dec", SP_VERB_CONTEXT_TEXT, _("Contract letter spacing")); } @@ -1136,18 +1223,18 @@ sp_text_context_root_handler(SPEventContext *const ec, GdkEvent *const event) if (MOD__ALT) { if (MOD__CTRL) { if (MOD__SHIFT) - sp_te_adjust_linespacing_screen(tc->text, tc->text_sel_start, tc->text_sel_end, ec->desktop, 10); + sp_te_adjust_linespacing_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, 10); else - sp_te_adjust_linespacing_screen(tc->text, tc->text_sel_start, tc->text_sel_end, ec->desktop, 1); - sp_document_maybe_done(sp_desktop_document(ec->desktop), "linespacing:inc", SP_VERB_CONTEXT_TEXT, + sp_te_adjust_linespacing_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, 1); + sp_document_maybe_done(sp_desktop_document(desktop), "linespacing:inc", SP_VERB_CONTEXT_TEXT, _("Expand line spacing")); } else { if (MOD__SHIFT) - sp_te_adjust_tspan_letterspacing_screen(tc->text, tc->text_sel_start, tc->text_sel_end, ec->desktop, 10); + sp_te_adjust_tspan_letterspacing_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, 10); else - sp_te_adjust_tspan_letterspacing_screen(tc->text, tc->text_sel_start, tc->text_sel_end, ec->desktop, 1); - sp_document_maybe_done(sp_desktop_document(ec->desktop), "letterspacing:inc", SP_VERB_CONTEXT_TEXT, + sp_te_adjust_tspan_letterspacing_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, 1); + sp_document_maybe_done(sp_desktop_document(desktop), "letterspacing:inc", SP_VERB_CONTEXT_TEXT, _("Expand letter spacing")); } @@ -1161,10 +1248,7 @@ sp_text_context_root_handler(SPEventContext *const ec, GdkEvent *const event) break; } - if (cursor_movement_operator) { - Inkscape::Text::Layout::iterator old_start = tc->text_sel_start; - Inkscape::Text::Layout::iterator old_end = tc->text_sel_end; - (tc->text_sel_end.*cursor_movement_operator)(); + if (cursor_moved) { if (!MOD__SHIFT) tc->text_sel_start = tc->text_sel_end; if (old_start != tc->text_sel_start || old_end != tc->text_sel_end) { @@ -1190,7 +1274,7 @@ sp_text_context_root_handler(SPEventContext *const ec, GdkEvent *const event) sp_canvas_item_ungrab(tc->grabbed, GDK_CURRENT_TIME); tc->grabbed = NULL; } - Inkscape::Rubberband::get()->stop(); + Inkscape::Rubberband::get(desktop)->stop(); } } } @@ -1208,7 +1292,7 @@ sp_text_context_root_handler(SPEventContext *const ec, GdkEvent *const event) // if nobody consumed it so far if (((SPEventContextClass *) parent_class)->root_handler) { // and there's a handler in parent context, - return ((SPEventContextClass *) parent_class)->root_handler(ec, event); // send event to parent + return ((SPEventContextClass *) parent_class)->root_handler(event_context, event); // send event to parent } else { return FALSE; // return "I did nothing" value so that global shortcuts can be activated } @@ -1229,10 +1313,36 @@ sp_text_paste_inline(SPEventContext *ec) // there is an active text object in this context, or a new object was just created Glib::RefPtr refClipboard = Gtk::Clipboard::get(); - Glib::ustring const text = refClipboard->wait_for_text(); - - if (!text.empty()) { - + Glib::ustring const clip_text = refClipboard->wait_for_text(); + + if (!clip_text.empty()) { + // Fix for 244940 + // The XML standard defines the following as valid characters + // (Extensible Markup Language (XML) 1.0 (Fourth Edition) paragraph 2.2) + // char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] + // Since what comes in off the paste buffer will go right into XML, clean + // the text here. + Glib::ustring text(clip_text); + Glib::ustring::iterator itr = text.begin(); + gunichar paste_string_uchar; + + while(itr != text.end()) + { + paste_string_uchar = *itr; + + // Make sure we don't have a control character. We should really check + // for the whole range above... Add the rest of the invalid cases from + // above if we find additional issues + if(paste_string_uchar >= 0x00000020 || + paste_string_uchar == 0x00000009 || + paste_string_uchar == 0x0000000A || + paste_string_uchar == 0x0000000D) { + itr++; + } else { + itr = text.erase(itr); + } + } + if (!tc->text) { // create text if none (i.e. if nascent_object) sp_text_context_setup_text(tc); tc->nascent_object = 0; // we don't need it anymore, having created a real @@ -1251,7 +1361,7 @@ sp_text_paste_inline(SPEventContext *ec) tc->text_sel_start = tc->text_sel_end = sp_te_insert_line(tc->text, tc->text_sel_start); begin = end + 1; } - sp_document_done(sp_desktop_document(ec->desktop), SP_VERB_CONTEXT_TEXT, + sp_document_done(sp_desktop_document(ec->desktop), SP_VERB_CONTEXT_TEXT, _("Paste text")); return true; @@ -1291,9 +1401,21 @@ bool sp_text_delete_selection(SPEventContext *ec) if (tc->text_sel_start == tc->text_sel_end) return false; - tc->text_sel_start = tc->text_sel_end = sp_te_delete(tc->text, tc->text_sel_start, tc->text_sel_end); + + iterator_pair pair; + bool success = sp_te_delete(tc->text, tc->text_sel_start, tc->text_sel_end, pair); + + + if (success) { + tc->text_sel_start = tc->text_sel_end = pair.first; + } else { // nothing deleted + tc->text_sel_start = pair.first; + tc->text_sel_end = pair.second; + } + sp_text_context_update_cursor(tc); sp_text_context_update_text_selection(tc); + return true; } @@ -1307,26 +1429,10 @@ sp_text_context_selection_changed(Inkscape::Selection *selection, SPTextContext SPEventContext *ec = SP_EVENT_CONTEXT(tc); - if (ec->shape_knot_holder) { // destroy knotholder - sp_knot_holder_destroy(ec->shape_knot_holder); - ec->shape_knot_holder = NULL; - } - - if (ec->shape_repr) { // remove old listener - sp_repr_remove_listener_by_data(ec->shape_repr, ec); - Inkscape::GC::release(ec->shape_repr); - ec->shape_repr = 0; - } - - SPItem *item = selection->singleItem(); + ec->shape_editor->unset_item(SH_KNOTHOLDER); + SPItem *item = selection->singleItem(); if (item && SP_IS_FLOWTEXT (item) && SP_FLOWTEXT(item)->has_internal_frame()) { - ec->shape_knot_holder = sp_item_knot_holder(item, ec->desktop); - Inkscape::XML::Node *shape_repr = SP_OBJECT_REPR(SP_FLOWTEXT(item)->get_frame(NULL)); - if (shape_repr) { - ec->shape_repr = shape_repr; - Inkscape::GC::anchor(shape_repr); - sp_repr_add_listener(shape_repr, &ec_shape_repr_events, ec); - } + ec->shape_editor->set_item(item, SH_KNOTHOLDER); } if (tc->text && (item != tc->text)) { @@ -1350,7 +1456,7 @@ sp_text_context_selection_changed(Inkscape::Selection *selection, SPTextContext } static void -sp_text_context_selection_modified(Inkscape::Selection *selection, guint flags, SPTextContext *tc) +sp_text_context_selection_modified(Inkscape::Selection */*selection*/, guint /*flags*/, SPTextContext *tc) { sp_text_context_update_cursor(tc); sp_text_context_update_text_selection(tc); @@ -1365,7 +1471,7 @@ sp_text_context_style_set(SPCSSAttr const *css, SPTextContext *tc) return false; // will get picked up by the parent and applied to the whole text object sp_te_apply_style(tc->text, tc->text_sel_start, tc->text_sel_end, css); - sp_document_done(sp_desktop_document(tc->desktop), SP_VERB_CONTEXT_TEXT, + sp_document_done(sp_desktop_document(tc->desktop), SP_VERB_CONTEXT_TEXT, _("Set text style")); sp_text_context_update_cursor(tc); sp_text_context_update_text_selection(tc); @@ -1400,10 +1506,12 @@ sp_text_context_style_query(SPStyle *style, int property, SPTextContext *tc) SPObject const *pos_obj = 0; void *rawptr = 0; layout->getSourceOfCharacter(it, &rawptr); + if (!rawptr || !SP_IS_OBJECT(rawptr)) + continue; pos_obj = SP_OBJECT(rawptr); - if (pos_obj == 0) continue; - while (SP_OBJECT_STYLE(pos_obj) == NULL && SP_OBJECT_PARENT(pos_obj)) - pos_obj = SP_OBJECT_PARENT(pos_obj); // SPStrings don't have style + while (SP_IS_STRING(pos_obj) && SP_OBJECT_PARENT(pos_obj)) { + pos_obj = SP_OBJECT_PARENT(pos_obj); // SPStrings don't have style + } styles_list = g_slist_prepend(styles_list, (gpointer)pos_obj); } @@ -1435,26 +1543,29 @@ sp_text_context_update_cursor(SPTextContext *tc, bool scroll_to_see) if (!tc->desktop) return; if (tc->text) { - NR::Point p0, p1; + Geom::Point p0, p1; sp_te_get_cursor_coords(tc->text, tc->text_sel_end, p0, p1); - NR::Point const d0 = p0 * sp_item_i2d_affine(SP_ITEM(tc->text)); - NR::Point const d1 = p1 * sp_item_i2d_affine(SP_ITEM(tc->text)); + Geom::Point const d0 = p0 * sp_item_i2d_affine(SP_ITEM(tc->text)); + Geom::Point const d1 = p1 * sp_item_i2d_affine(SP_ITEM(tc->text)); // scroll to show cursor if (scroll_to_see) { - NR::Point const dm = (d0 + d1) / 2; - // unlike mouse moves, here we must scroll all the way at first shot, so we override the autoscrollspeed - SP_EVENT_CONTEXT(tc)->desktop->scroll_to_point(&dm, 1.0); + Geom::Point const center = SP_EVENT_CONTEXT(tc)->desktop->get_display_area().midpoint(); + if (Geom::L2(d0 - center) > Geom::L2(d1 - center)) + // unlike mouse moves, here we must scroll all the way at first shot, so we override the autoscrollspeed + SP_EVENT_CONTEXT(tc)->desktop->scroll_to_point(d0, 1.0); + else + SP_EVENT_CONTEXT(tc)->desktop->scroll_to_point(d1, 1.0); } sp_canvas_item_show(tc->cursor); sp_ctrlline_set_coords(SP_CTRLLINE(tc->cursor), d0, d1); /* fixme: ... need another transformation to get canvas widget coordinate space? */ - im_cursor.x = (int) floor(d0[NR::X]); - im_cursor.y = (int) floor(d0[NR::Y]); - im_cursor.width = (int) floor(d1[NR::X]) - im_cursor.x; - im_cursor.height = (int) floor(d1[NR::Y]) - im_cursor.y; + im_cursor.x = (int) floor(d0[Geom::X]); + im_cursor.y = (int) floor(d0[Geom::Y]); + im_cursor.width = (int) floor(d1[Geom::X]) - im_cursor.x; + im_cursor.height = (int) floor(d1[Geom::Y]) - im_cursor.y; tc->show = TRUE; tc->phase = 1; @@ -1463,7 +1574,7 @@ sp_text_context_update_cursor(SPTextContext *tc, bool scroll_to_see) SPItem *frame = SP_FLOWTEXT(tc->text)->get_frame (NULL); // first frame only if (frame) { sp_canvas_item_show(tc->frame); - NR::Maybe frame_bbox = sp_item_bbox_desktop(frame); + Geom::OptRect frame_bbox = sp_item_bbox_desktop(frame); if (frame_bbox) { SP_CTRLRECT(tc->frame)->setRectangle(*frame_bbox); } @@ -1500,13 +1611,15 @@ static void sp_text_context_update_text_selection(SPTextContext *tc) } tc->text_selection_quads.clear(); - std::vector quads; + std::vector quads; if (tc->text != NULL) quads = sp_te_create_selection_quads(tc->text, tc->text_sel_start, tc->text_sel_end, sp_item_i2d_affine(tc->text)); for (unsigned i = 0 ; i < quads.size() ; i += 4) { SPCanvasItem *quad_canvasitem; quad_canvasitem = sp_canvas_item_new(sp_desktop_controls(tc->desktop), SP_TYPE_CTRLQUADR, NULL); - sp_ctrlquadr_set_rgba32(SP_CTRLQUADR(quad_canvasitem), 0x000000ff); + // FIXME: make the color settable in prefs + // for now, use semitrasparent blue, as cairo cannot do inversion :( + sp_ctrlquadr_set_rgba32(SP_CTRLQUADR(quad_canvasitem), 0x00777777); sp_ctrlquadr_set_coords(SP_CTRLQUADR(quad_canvasitem), quads[i], quads[i+1], quads[i+2], quads[i+3]); sp_canvas_item_show(quad_canvasitem); tc->text_selection_quads.push_back(quad_canvasitem); @@ -1517,12 +1630,13 @@ static gint sp_text_context_timeout(SPTextContext *tc) { if (tc->show) { + sp_canvas_item_show(tc->cursor); if (tc->phase) { tc->phase = 0; - sp_canvas_item_hide(tc->cursor); + sp_ctrlline_set_rgba32(SP_CTRLLINE(tc->cursor), 0x000000ff); } else { tc->phase = 1; - sp_canvas_item_show(tc->cursor); + sp_ctrlline_set_rgba32(SP_CTRLLINE(tc->cursor), 0xffffffff); } } @@ -1534,9 +1648,15 @@ sp_text_context_forget_text(SPTextContext *tc) { if (! tc->text) return; SPItem *ti = tc->text; + (void)ti; /* We have to set it to zero, * or selection changed signal messes everything up */ tc->text = NULL; + +/* FIXME: this automatic deletion when nothing is inputted crashes the XML edittor and also crashes when duplicating an empty flowtext. + So don't create an empty flowtext in the first place? Create it when first character is typed. + */ +/* if ((SP_IS_TEXT(ti) || SP_IS_FLOWTEXT(ti)) && sp_te_input_is_empty(ti)) { Inkscape::XML::Node *text_repr=SP_OBJECT_REPR(ti); // the repr may already have been unparented @@ -1545,26 +1665,29 @@ sp_text_context_forget_text(SPTextContext *tc) // the XML editor if ( text_repr && sp_repr_parent(text_repr) ) { sp_repr_unparent(text_repr); + sp_document_done(sp_desktop_document(tc->desktop), SP_VERB_CONTEXT_TEXT, + _("Remove empty text")); } } +*/ } gint -sptc_focus_in(GtkWidget *widget, GdkEventFocus *event, SPTextContext *tc) +sptc_focus_in(GtkWidget */*widget*/, GdkEventFocus */*event*/, SPTextContext *tc) { gtk_im_context_focus_in(tc->imc); return FALSE; } gint -sptc_focus_out(GtkWidget *widget, GdkEventFocus *event, SPTextContext *tc) +sptc_focus_out(GtkWidget */*widget*/, GdkEventFocus */*event*/, SPTextContext *tc) { gtk_im_context_focus_out(tc->imc); return FALSE; } static void -sptc_commit(GtkIMContext *imc, gchar *string, SPTextContext *tc) +sptc_commit(GtkIMContext */*imc*/, gchar *string, SPTextContext *tc) { if (!tc->text) { sp_text_context_setup_text(tc); @@ -1575,7 +1698,7 @@ sptc_commit(GtkIMContext *imc, gchar *string, SPTextContext *tc) sp_text_context_update_cursor(tc); sp_text_context_update_text_selection(tc); - sp_document_done(SP_OBJECT_DOCUMENT(tc->text), SP_VERB_CONTEXT_TEXT, + sp_document_done(SP_OBJECT_DOCUMENT(tc->text), SP_VERB_CONTEXT_TEXT, _("Type text")); }