diff --git a/src/text-context.cpp b/src/text-context.cpp
index a181f4f6fb22d70f63128da9fe536da50ce68dd3..e6f4f083b2945b006b0496707f328f5204255aac 100644 (file)
--- a/src/text-context.cpp
+++ b/src/text-context.cpp
#include "desktop.h"
#include "desktop-style.h"
#include "desktop-handles.h"
-#include "desktop-affine.h"
#include "message-stack.h"
#include "message-context.h"
#include "pixmaps/cursor-text.xpm"
#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 "selection-chemistry.h"
#include "text-editing.h"
#include "text-context.h"
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<SPCanvasItem*>();
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();
sp_canvas_item_ungrab(tc->grabbed, GDK_CURRENT_TIME);
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;
- }
-}
-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 */
-};
+ Inkscape::Rubberband::get(ec->desktop)->stop();
+}
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_DT_CONTROLS(desktop), SP_TYPE_CTRLLINE, NULL);
+ 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);
sp_ctrlline_set_rgba32(SP_CTRLLINE(tc->cursor), 0x000000ff);
sp_canvas_item_hide(tc->cursor);
- tc->indicator = sp_canvas_item_new(SP_DT_CONTROLS(desktop), SP_TYPE_CTRLRECT, NULL);
- SP_CTRLRECT(tc->indicator)->setRectangle(NR::Rect(NR::Point(0, 0), NR::Point(100, 100)));
+ tc->indicator = sp_canvas_item_new(sp_desktop_controls(desktop), SP_TYPE_CTRLRECT, NULL);
+ 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_DT_CONTROLS(desktop), SP_TYPE_CTRLRECT, NULL);
- SP_CTRLRECT(tc->frame)->setRectangle(NR::Rect(NR::Point(0, 0), NR::Point(100, 100)));
+ tc->frame = sp_canvas_item_new(sp_desktop_controls(desktop), SP_TYPE_CTRLRECT, NULL);
+ 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) {
- GtkWidget *canvas = GTK_WIDGET(SP_DT_CANVAS(desktop));
+ GtkWidget *canvas = GTK_WIDGET(sp_desktop_canvas(desktop));
/* im preedit handling is very broken in inkscape for
* multi-byte characters. See bug 1086769.
if (((SPEventContextClass *) parent_class)->setup)
((SPEventContextClass *) parent_class)->setup(ec);
- SPItem *item = SP_DT_SELECTION(ec->desktop)->singleItem();
+ 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);
- sp_repr_synthesize_events(shape_repr, &ec_shape_repr_events, ec);
- }
+ ec->shape_editor->set_item(item, SH_KNOTHOLDER);
}
- tc->sel_changed_connection = SP_DT_SELECTION(desktop)->connectChanged(
+ tc->sel_changed_connection = sp_desktop_selection(desktop)->connectChanged(
sigc::bind(sigc::ptr_fun(&sp_text_context_selection_changed), tc)
);
- tc->sel_modified_connection = SP_DT_SELECTION(desktop)->connectModified(
+ tc->sel_modified_connection = sp_desktop_selection(desktop)->connectModified(
sigc::bind(sigc::ptr_fun(&sp_text_context_selection_modified), tc)
);
tc->style_set_connection = desktop->connectSetStyle(
sigc::bind(sigc::ptr_fun(&sp_text_context_style_query), tc)
);
- sp_text_context_selection_changed(SP_DT_SELECTION(desktop), tc);
+ 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();
}
}
{
SPTextContext *tc = SP_TEXT_CONTEXT(ec);
+ if (ec->desktop) {
+ sp_signal_disconnect_by_data(sp_desktop_canvas(ec->desktop), tc);
+ }
+
ec->enableGrDrag(false);
tc->style_set_connection.disconnect();
gtk_object_destroy(*it);
}
tc->text_selection_quads.clear();
-
- if (ec->desktop) {
- sp_signal_disconnect_by_data(SP_DT_CANVAS(ec->desktop), tc);
- }
}
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 +338,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_DT_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 +383,18 @@ 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;
+ sp_event_context_discard_delayed_snap_event(event_context);
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) {
@@ -413,14 +402,14 @@ sp_text_context_item_handler(SPEventContext *ec, SPItem *item, GdkEvent *event)
if (new_end < tc->text_sel_start) {
if (!layout->isStartOfWord(new_end))
new_end.prevStartOfWord();
- } else
+ } else
if (!layout->isEndOfWord(new_end))
new_end.nextEndOfWord();
} else if (tc->dragging == 3) {
// triple-click dragging: go by line
if (new_end < tc->text_sel_start)
new_end.thisStartOfLine();
- else
+ else
new_end.thisEndOfLine();
}
// update display
@@ -429,19 +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);
- SP_CTRLRECT(tc->indicator)->setRectangle(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)) {
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;
SPEventContext *ec = SP_EVENT_CONTEXT(tc);
/* Create <text> */
- Inkscape::XML::Node *rtext = sp_repr_new("svg:text");
+ Inkscape::XML::Document *xml_doc = sp_document_repr_doc(SP_EVENT_CONTEXT_DESKTOP(ec)->doc());
+ Inkscape::XML::Node *rtext = xml_doc->createElement("svg:text");
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 <tspan> */
- Inkscape::XML::Node *rtspan = sp_repr_new("svg:tspan");
+ Inkscape::XML::Node *rtspan = xml_doc->createElement("svg:tspan");
rtspan->setAttribute("sodipodi:role", "line"); // otherwise, why bother creating the tspan?
rtext->addChild(rtspan, NULL);
Inkscape::GC::release(rtspan);
/* Create TEXT */
- Inkscape::XML::Node *rstring = sp_repr_new_text("");
+ Inkscape::XML::Node *rstring = xml_doc->createTextNode("");
rtspan->addChild(rstring, NULL);
Inkscape::GC::release(rstring);
SPItem *text_item = SP_ITEM(ec->desktop->currentLayer()->appendChildRepr(rtext));
/* fixme: Is selection::changed really immediate? */
/* yes, it's immediate .. why does it matter? */
- SP_DT_SELECTION(ec->desktop)->set(text_item);
+ 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_DT_DOCUMENT(ec->desktop));
+ sp_document_done(sp_desktop_document(ec->desktop), SP_VERB_CONTEXT_TEXT,
+ _("Create text"));
}
/**
tc->unipos = 0;
tc->uni[tc->unipos] = '\0';
- if (!g_unichar_isprint((gunichar) uv)) {
+ if ( !g_unichar_isprint(static_cast<gunichar>(uv))
+ && !(g_unichar_validate(static_cast<gunichar>(uv)) && (g_unichar_type(static_cast<gunichar>(uv)) == G_UNICODE_PRIVATE_USE) ) ) {
// This may be due to bad input, so it goes to statusbar.
tc->desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE,
_("Non-printable character"));
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_DT_DOCUMENT(tc->desktop));
+ sp_document_done(sp_desktop_document(tc->desktop), SP_VERB_DIALOG_TRANSFORM,
+ _("Insert Unicode character"));
}
}
}
}
tc->defaultMessageContext()->setF(Inkscape::NORMAL_MESSAGE,
- _("Unicode: %s: %s"), tc->uni, utf8);
+ _("Unicode (<b>Enter</b> to finish): %s: %s"), tc->uni, utf8);
} else {
- tc->defaultMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("Unicode: "));
+ tc->defaultMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("Unicode (<b>Enter</b> to finish): "));
}
}
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_POINTER_MOTION_HINT_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;
return TRUE;
}
break;
- case GDK_MOTION_NOTIFY:
+ case GDK_MOTION_NOTIFY:
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, _("<b>Flowed text frame</b>: %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, _("<b>Flowed text frame</b>: %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) {
+ case GDK_BUTTON_RELEASE:
+ 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_DT_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);
+ sp_desktop_selection(desktop)->clear();
+ Geom::Point dtp = desktop->w2d(Geom::Point(event->button.x, event->button.y));
+ tc->pdoc = desktop->dt2doc(dtp);
tc->show = TRUE;
tc->phase = 1;
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; <b>Enter</b> 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; <b>Enter</b> 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);
- SP_DT_SELECTION(desktop)->set(ft);
- ec->desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Flowed text is created."));
- sp_document_done(SP_DT_DOCUMENT(desktop));
+ /* Set style */
+ sp_desktop_apply_style_tool(desktop, SP_OBJECT_REPR(ft), "/tools/text", true);
+ sp_desktop_selection(desktop)->set(ft);
+ 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 <b>too small</b> for the current font size. Flowed text not created."));
+ desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("The frame is <b>too small</b> for the current font size. Flowed text not created."));
}
}
tc->creating = false;
}
/* Exit unimode. */
tc->unimode = false;
- ec->defaultMessageContext()->clear();
+ event_context->defaultMessageContext()->clear();
return TRUE;
}
// Cancel unimode.
tc->unimode = false;
gtk_im_context_reset(tc->imc);
- ec->defaultMessageContext()->clear();
+ event_context->defaultMessageContext()->clear();
return TRUE;
}
}
}
- 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) {
+ case GDK_x:
+ case GDK_X:
+ if (MOD__ALT_ONLY) {
+ desktop->setToolboxFocusTo ("altx-text");
+ return TRUE;
+ }
+ break;
case GDK_space:
if (MOD__CTRL_ONLY) {
/* No-break space */
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_DT_DOCUMENT(ec->desktop));
+ 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;
}
break;
case GDK_U:
case GDK_u:
- if (MOD__CTRL_ONLY) {
+ 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: "));
+ event_context->defaultMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("Unicode (<b>Enter</b> to finish): "));
}
if (tc->imc) {
gtk_im_context_reset(tc->imc);
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_DT_DOCUMENT(ec->desktop));
+ 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);
return TRUE;
if (MOD__CTRL_ONLY && tc->text) {
SPStyle const *style = sp_te_style_at_position(tc->text, std::min(tc->text_sel_start, tc->text_sel_end));
SPCSSAttr *css = sp_repr_css_attr_new();
- if (style->font_style.computed == SP_CSS_FONT_STYLE_NORMAL)
- sp_repr_css_set_property(css, "font-style", "italic");
- else
+ if (style->font_style.computed != SP_CSS_FONT_STYLE_NORMAL)
sp_repr_css_set_property(css, "font-style", "normal");
+ else
+ sp_repr_css_set_property(css, "font-style", "italic");
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_DT_DOCUMENT(ec->desktop));
+ 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);
return TRUE;
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 <text>
}
- 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_DT_DOCUMENT(ec->desktop));
+ 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_DT_DOCUMENT(ec->desktop));
+ 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_DT_DOCUMENT(ec->desktop));
+ sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_TEXT,
+ _("Delete"));
}
return TRUE;
case GDK_Left:
@@ -928,16 +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_DT_DOCUMENT(ec->desktop), "kern:left");
+ 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;
}
}
@@ -947,16 +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_DT_DOCUMENT(ec->desktop), "kern:right");
+ 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;
}
}
@@ -966,16 +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_DT_DOCUMENT(ec->desktop), "kern:up");
+ 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;
}
}
@@ -985,16 +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_DT_DOCUMENT(ec->desktop), "kern:down");
+ 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;
}
}
@@ -1003,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;
- else
- cursor_movement_operator = &Inkscape::Text::Layout::iterator::thisStartOfLine;
+ tc->text_sel_end.thisStartOfShape();
+ else
+ tc->text_sel_end.thisStartOfLine();
+ cursor_moved = true;
break;
}
return TRUE;
@@ -1013,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;
- else
- cursor_movement_operator = &Inkscape::Text::Layout::iterator::thisEndOfLine;
+ tc->text_sel_end.nextStartOfShape();
+ else
+ 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;
@@ -1026,10 +1142,11 @@ 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_DT_SELECTION(ec->desktop)->clear();
+ sp_desktop_selection(desktop)->clear();
}
+ tc->nascent_object = FALSE;
return TRUE;
case GDK_bracketleft:
if (tc->text) {
@@ -1037,18 +1154,19 @@ 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_DT_DOCUMENT(ec->desktop), "textrot:ccw");
+ 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);
return TRUE;
- }
+ }
}
break;
case GDK_bracketright:
@@ -1057,14 +1175,15 @@ 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_DT_DOCUMENT(ec->desktop), "textrot:cw");
+ 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);
return TRUE;
@@ -1077,16 +1196,20 @@ 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_DT_DOCUMENT(ec->desktop), "linespacing:dec");
+ 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_DT_DOCUMENT(ec->desktop), "letterspacing:dec");
+ 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"));
+
}
sp_text_context_update_cursor(tc);
sp_text_context_update_text_selection(tc);
@@ -1100,16 +1223,20 @@ 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_DT_DOCUMENT(ec->desktop), "linespacing:inc");
+ 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_DT_DOCUMENT(ec->desktop), "letterspacing:inc");
+ 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"));
+
}
sp_text_context_update_cursor(tc);
sp_text_context_update_text_selection(tc);
@@ -1121,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) {
@@ -1150,8 +1274,11 @@ 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 if ((group0_keyval == GDK_x || group0_keyval == GDK_X) && MOD__ALT_ONLY) {
+ desktop->setToolboxFocusTo ("altx-text");
+ return TRUE;
}
}
break;
// 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
}
// there is an active text object in this context, or a new object was just created
Glib::RefPtr<Gtk::Clipboard> 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->text_sel_start = tc->text_sel_end = sp_te_insert_line(tc->text, tc->text_sel_start);
begin = end + 1;
}
- sp_document_done(SP_DT_DOCUMENT(ec->desktop));
+ sp_document_done(sp_desktop_document(ec->desktop), SP_VERB_CONTEXT_TEXT,
+ _("Paste text"));
return true;
}
return sp_te_get_string_multiline(tc->text, tc->text_sel_start, tc->text_sel_end);
}
+SPCSSAttr *
+sp_text_get_style_at_cursor(SPEventContext const *ec)
+{
+ if (!SP_IS_TEXT_CONTEXT(ec))
+ return NULL;
+ SPTextContext const *tc = SP_TEXT_CONTEXT(ec);
+ if (tc->text == NULL)
+ return NULL;
+
+ SPObject const *obj = sp_te_object_at_position(tc->text, tc->text_sel_end);
+ if (obj)
+ return take_style_from_item((SPItem *) obj);
+ return NULL;
+}
+
/**
Deletes the currently selected characters. Returns false if there is no
text selection currently.
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;
}
@@ -1266,27 +1447,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;
- }
-
+ 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);
- sp_repr_synthesize_events(shape_repr, &ec_shape_repr_events, ec);
- }
+ ec->shape_editor->set_item(item, SH_KNOTHOLDER);
}
if (tc->text && (item != tc->text)) {
@@ -1310,7 +1474,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);
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_DT_DOCUMENT(tc->desktop));
+ 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);
@@ -1356,11 +1521,15 @@ sp_text_context_style_query(SPStyle *style, int property, SPTextContext *tc)
if (!begin_it.prevCharacter())
end_it.nextCharacter();
for (Inkscape::Text::Layout::iterator it = begin_it ; it < end_it ; it.nextStartOfSpan()) {
- SPObject const *pos_obj = NULL;
- layout->getSourceOfCharacter(it, (void**)&pos_obj);
- if (pos_obj == NULL) 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
+ SPObject const *pos_obj = 0;
+ void *rawptr = 0;
+ layout->getSourceOfCharacter(it, &rawptr);
+ if (!rawptr || !SP_IS_OBJECT(rawptr))
+ continue;
+ pos_obj = SP_OBJECT(rawptr);
+ 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);
}
{
GdkRectangle im_cursor = { 0, 0, 1, 1 };
+ // due to interruptible display, tc may already be destroyed during a display update before
+ // the cursor update (can't do both atomically, alas)
+ 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;
+ Inkscape::Text::Layout const *layout = te_get_layout(tc->text);
+ int const nChars = layout->iteratorToCharIndex(layout->end());
if (SP_IS_FLOWTEXT(tc->text)) {
SPItem *frame = SP_FLOWTEXT(tc->text)->get_frame (NULL); // first frame only
if (frame) {
sp_canvas_item_show(tc->frame);
- SP_CTRLRECT(tc->frame)->setRectangle(sp_item_bbox_desktop(frame));
+ Geom::OptRect frame_bbox = sp_item_bbox_desktop(frame);
+ if (frame_bbox) {
+ SP_CTRLRECT(tc->frame)->setRectangle(*frame_bbox);
+ }
}
- SP_EVENT_CONTEXT(tc)->_message_context->set(Inkscape::NORMAL_MESSAGE, _("Type flowed text; <b>Enter</b> to start new paragraph."));
+ SP_EVENT_CONTEXT(tc)->_message_context->setF(Inkscape::NORMAL_MESSAGE, _("Type or edit flowed text (%d characters); <b>Enter</b> to start new paragraph."), nChars);
} else {
- SP_EVENT_CONTEXT(tc)->_message_context->set(Inkscape::NORMAL_MESSAGE, _("Type text; <b>Enter</b> to start new line."));
+ SP_EVENT_CONTEXT(tc)->_message_context->setF(Inkscape::NORMAL_MESSAGE, _("Type or edit text (%d characters); <b>Enter</b> to start new line."), nChars);
}
} else {
static void sp_text_context_update_text_selection(SPTextContext *tc)
{
+ // due to interruptible display, tc may already be destroyed during a display update before
+ // the selection update (can't do both atomically, alas)
+ if (!tc->desktop) return;
+
for (std::vector<SPCanvasItem*>::iterator it = tc->text_selection_quads.begin() ; it != tc->text_selection_quads.end() ; it++) {
sp_canvas_item_hide(*it);
gtk_object_destroy(*it);
}
tc->text_selection_quads.clear();
- std::vector<NR::Point> quads;
+ std::vector<Geom::Point> 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_DT_CONTROLS(tc->desktop), SP_TYPE_CTRLQUADR, NULL);
- sp_ctrlquadr_set_rgba32(SP_CTRLQUADR(quad_canvasitem), 0x000000ff);
+ quad_canvasitem = sp_canvas_item_new(sp_desktop_controls(tc->desktop), SP_TYPE_CTRLQUADR, NULL);
+ // 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);
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);
}
}
{
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
// 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);
sp_text_context_update_cursor(tc);
sp_text_context_update_text_selection(tc);
- sp_document_done(SP_OBJECT_DOCUMENT(tc->text));
+ sp_document_done(SP_OBJECT_DOCUMENT(tc->text), SP_VERB_CONTEXT_TEXT,
+ _("Type text"));
+}
+
+void
+sp_text_context_place_cursor (SPTextContext *tc, SPObject *text, Inkscape::Text::Layout::iterator where)
+{
+ SP_EVENT_CONTEXT_DESKTOP (tc)->selection->set (text);
+ tc->text_sel_start = tc->text_sel_end = where;
+ sp_text_context_update_cursor(tc);
+ sp_text_context_update_text_selection(tc);
+}
+
+void
+sp_text_context_place_cursor_at (SPTextContext *tc, SPObject *text, Geom::Point const p)
+{
+ SP_EVENT_CONTEXT_DESKTOP (tc)->selection->set (text);
+ sp_text_context_place_cursor (tc, text, sp_te_get_position_by_coords(tc->text, p));
+}
+
+Inkscape::Text::Layout::iterator *sp_text_context_get_cursor_position(SPTextContext *tc, SPObject *text)
+{
+ if (text != tc->text)
+ return NULL;
+ return &(tc->text_sel_end);
}