From e7a5f3e4a4758ac8353e070265e9bf03ed7228c9 Mon Sep 17 00:00:00 2001 From: buliabyak Date: Mon, 8 Jan 2007 11:51:08 +0000 Subject: [PATCH] patch from bug 1497803 by Gustav Broberg; allow to reflow an already flowed text --- src/sp-flowtext.cpp | 56 +++++++----------- src/sp-flowtext.h | 18 ++++-- src/text-chemistry.cpp | 126 ++++++++++++++++++++++++++++++++++------- src/text-chemistry.h | 1 + src/verbs.cpp | 2 +- 5 files changed, 144 insertions(+), 59 deletions(-) diff --git a/src/sp-flowtext.cpp b/src/sp-flowtext.cpp index 8858d534d..ec6fd0427 100644 --- a/src/sp-flowtext.cpp +++ b/src/sp-flowtext.cpp @@ -25,6 +25,7 @@ #include "sp-use.h" #include "sp-rect.h" #include "text-tag-attributes.h" +#include "text-chemistry.h" #include "livarot/Shape.h" @@ -511,40 +512,36 @@ void SPFlowtext::_clearFlow(NRArenaGroup *in_arena) } } -void SPFlowtext::convert_to_text() +Inkscape::XML::Node * +SPFlowtext::getAsText() { - SPDesktop *desktop = SP_ACTIVE_DESKTOP; - Inkscape::Selection *selection = sp_desktop_selection(desktop); - SPItem *item = selection->singleItem(); - if (!SP_IS_FLOWTEXT(item)) return; + if (!this->layout.outputExists()) return NULL; - SPFlowtext *group = SP_FLOWTEXT(item); - - if (!group->layout.outputExists()) return; + SPItem *item = SP_ITEM(this); Inkscape::XML::Node *repr = sp_repr_new("svg:text"); repr->setAttribute("xml:space", "preserve"); - repr->setAttribute("style", SP_OBJECT_REPR(group)->attribute("style")); - NR::Point anchor_point = group->layout.characterAnchorPoint(group->layout.begin()); + repr->setAttribute("style", SP_OBJECT_REPR(this)->attribute("style")); + NR::Point anchor_point = this->layout.characterAnchorPoint(this->layout.begin()); sp_repr_set_svg_double(repr, "x", anchor_point[NR::X]); sp_repr_set_svg_double(repr, "y", anchor_point[NR::Y]); - for (Inkscape::Text::Layout::iterator it = group->layout.begin() ; it != group->layout.end() ; ) { - - Inkscape::XML::Node *line_tspan = sp_repr_new("svg:tspan"); + for (Inkscape::Text::Layout::iterator it = this->layout.begin() ; it != this->layout.end() ; ) { + Inkscape::XML::Node *line_tspan = sp_repr_new("svg:tspan"); line_tspan->setAttribute("sodipodi:role", "line"); Inkscape::Text::Layout::iterator it_line_end = it; it_line_end.nextStartOfLine(); + while (it != it_line_end) { - Inkscape::XML::Node *span_tspan = sp_repr_new("svg:tspan"); - NR::Point anchor_point = group->layout.characterAnchorPoint(it); + Inkscape::XML::Node *span_tspan = sp_repr_new("svg:tspan"); + NR::Point anchor_point = this->layout.characterAnchorPoint(it); // use kerning to simulate justification and whatnot Inkscape::Text::Layout::iterator it_span_end = it; it_span_end.nextStartOfSpan(); Inkscape::Text::Layout::OptionalTextTagAttrs attrs; - group->layout.simulateLayoutUsingKerning(it, it_span_end, &attrs); + this->layout.simulateLayoutUsingKerning(it, it_span_end, &attrs); // set x,y attributes only when we need to bool set_x = false; bool set_y = false; @@ -573,9 +570,9 @@ void SPFlowtext::convert_to_text() SPObject *source_obj = 0; void *rawptr = 0; Glib::ustring::iterator span_text_start_iter; - group->layout.getSourceOfCharacter(it, &rawptr, &span_text_start_iter); + this->layout.getSourceOfCharacter(it, &rawptr, &span_text_start_iter); source_obj = SP_OBJECT (rawptr); - gchar *style_text = sp_style_write_difference((SP_IS_STRING(source_obj) ? source_obj->parent : source_obj)->style, group->style); + gchar *style_text = sp_style_write_difference((SP_IS_STRING(source_obj) ? source_obj->parent : source_obj)->style, this->style); if (style_text && *style_text) { span_tspan->setAttribute("style", style_text); g_free(style_text); @@ -586,12 +583,12 @@ void SPFlowtext::convert_to_text() SPObject *span_end_obj = 0; void *rawptr = 0; Glib::ustring::iterator span_text_end_iter; - group->layout.getSourceOfCharacter(it_span_end, &rawptr, &span_text_end_iter); + this->layout.getSourceOfCharacter(it_span_end, &rawptr, &span_text_end_iter); span_end_obj = SP_OBJECT(rawptr); if (span_end_obj != source_obj) { - if (it_span_end == group->layout.end()) { + if (it_span_end == this->layout.end()) { span_text_end_iter = span_text_start_iter; - for (int i = group->layout.iteratorToCharIndex(it_span_end) - group->layout.iteratorToCharIndex(it) ; i ; --i) + for (int i = this->layout.iteratorToCharIndex(it_span_end) - this->layout.iteratorToCharIndex(it) ; i ; --i) ++span_text_end_iter; } else span_text_end_iter = string->end(); // spans will never straddle a source boundary @@ -609,24 +606,13 @@ void SPFlowtext::convert_to_text() it = it_span_end; line_tspan->appendChild(span_tspan); - Inkscape::GC::release(span_tspan); + Inkscape::GC::release(span_tspan); } repr->appendChild(line_tspan); - Inkscape::GC::release(line_tspan); + Inkscape::GC::release(line_tspan); } - Inkscape::XML::Node *parent = SP_OBJECT_REPR(item)->parent(); - parent->appendChild(repr); - SPItem *new_item = (SPItem *) sp_desktop_document(desktop)->getObjectByRepr(repr); - sp_item_write_transform(new_item, repr, item->transform); - SP_OBJECT(new_item)->updateRepr(); - - Inkscape::GC::release(repr); - selection->set(new_item); - item->deleteObject(); - - sp_document_done(sp_desktop_document(desktop), SP_VERB_NONE, - _("Convert flowed text to text")); + return repr; } SPItem *SPFlowtext::get_frame(SPItem *after) diff --git a/src/sp-flowtext.h b/src/sp-flowtext.h index 39f443440..144157dc9 100644 --- a/src/sp-flowtext.h +++ b/src/sp-flowtext.h @@ -20,10 +20,9 @@ struct SPFlowtext : public SPItem { /** Completely recalculates the layout. */ void rebuildLayout(); - /** Converts the current selection (which must be a flowroot) into - a \ tree, keeping all the formatting and positioning, but losing - the automatic wrapping ability. */ - static void convert_to_text(); + /** Converts the flowroot in into a \ tree, keeping all the formatting and positioning, + but losing the automatic wrapping ability. */ + Inkscape::XML::Node *getAsText(); SPItem *get_frame(SPItem *after); @@ -56,3 +55,14 @@ GType sp_flowtext_get_type (void); SPItem *create_flowtext_with_internal_frame (SPDesktop *desktop, NR::Point p1, NR::Point p2); #endif + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/text-chemistry.cpp b/src/text-chemistry.cpp index e2f5b8335..4ea47fd27 100644 --- a/src/text-chemistry.cpp +++ b/src/text-chemistry.cpp @@ -23,8 +23,10 @@ #include "document.h" #include "message-stack.h" #include "selection.h" +#include "style.h" #include "desktop-handles.h" #include "text-editing.h" +#include "text-chemistry.h" #include "sp-flowtext.h" #include "sp-flowregion.h" #include "sp-flowdiv.h" @@ -100,17 +102,32 @@ text_put_on_path() return; } - if (SP_IS_FLOWTEXT(text)) { - sp_desktop_message_stack(desktop)->flash(Inkscape::ERROR_MESSAGE, _("You cannot put flowtext on a path. Convert flowtext to text first.")); - return; - } - if (SP_IS_RECT(shape)) { // rect is the only SPShape which is not yet, and thus SVG forbids us from putting text on it sp_desktop_message_stack(desktop)->flash(Inkscape::ERROR_MESSAGE, _("You cannot put text on a rectangle in this version. Convert rectangle to path first.")); return; } + // if a flowed text is selected, convert it to a regular text object + if (SP_IS_FLOWTEXT(text)) { + Inkscape::XML::Node *repr = SP_FLOWTEXT(text)->getAsText(); + Inkscape::XML::Node *parent = SP_OBJECT_REPR(text)->parent(); + parent->appendChild(repr); + + SPItem *new_item = (SPItem *) sp_desktop_document(desktop)->getObjectByRepr(repr); + sp_item_write_transform(new_item, repr, text->transform); + SP_OBJECT(new_item)->updateRepr(); + + Inkscape::GC::release(repr); + text->deleteObject(); // delete the orignal flowtext + + sp_document_ensure_up_to_date(sp_desktop_document(desktop)); + + selection->clear(); + + text = new_item; // point to the new text + } + Inkscape::Text::Layout const *layout = te_get_layout(text); Inkscape::Text::Layout::Alignment text_alignment = layout->paragraphAlignment(layout->begin()); @@ -255,7 +272,7 @@ text_flow_into_shape() Inkscape::Selection *selection = sp_desktop_selection(desktop); - SPItem *text = text_in_selection(selection); + SPItem *text = text_or_flowtext_in_selection(selection); SPItem *shape = shape_in_selection(selection); if (!text || !shape || g_slist_length((GSList *) selection->itemList()) < 2) { @@ -263,9 +280,11 @@ text_flow_into_shape() return; } - // remove transform from text, but recursively scale text's fontsize by the expansion - SP_TEXT(text)->_adjustFontsizeRecursive(text, NR::expansion(SP_ITEM(text)->transform)); - SP_OBJECT_REPR(text)->setAttribute("transform", NULL); + if (SP_IS_TEXT(text)) { + // remove transform from text, but recursively scale text's fontsize by the expansion + SP_TEXT(text)->_adjustFontsizeRecursive(text, NR::expansion(SP_ITEM(text)->transform)); + SP_OBJECT_REPR(text)->setAttribute("transform", NULL); + } Inkscape::XML::Node *root_repr = sp_repr_new("svg:flowRoot"); root_repr->setAttribute("xml:space", "preserve"); // we preserve spaces in the text objects we create @@ -295,16 +314,32 @@ text_flow_into_shape() } } - Inkscape::XML::Node *para_repr = sp_repr_new("svg:flowPara"); - root_repr->appendChild(para_repr); - object = doc->getObjectByRepr(para_repr); - g_return_if_fail(SP_IS_FLOWPARA(object)); + if (SP_IS_TEXT(text)) { // flow from text, as string + Inkscape::XML::Node *para_repr = sp_repr_new("svg:flowPara"); + root_repr->appendChild(para_repr); + object = doc->getObjectByRepr(para_repr); + g_return_if_fail(SP_IS_FLOWPARA(object)); - Inkscape::Text::Layout const *layout = te_get_layout(text); - Glib::ustring text_ustring = sp_te_get_string_multiline(text, layout->begin(), layout->end()); + Inkscape::Text::Layout const *layout = te_get_layout(text); + Glib::ustring text_ustring = sp_te_get_string_multiline(text, layout->begin(), layout->end()); + + Inkscape::XML::Node *text_repr = sp_repr_new_text(text_ustring.c_str()); // FIXME: transfer all formatting! and convert newlines into flowParas! + para_repr->appendChild(text_repr); - Inkscape::XML::Node *text_repr = sp_repr_new_text(text_ustring.c_str()); // FIXME: transfer all formatting! and convert newlines into flowParas! - para_repr->appendChild(text_repr); + Inkscape::GC::release(para_repr); + Inkscape::GC::release(text_repr); + + } else { // reflow an already flowed text, preserving paras + for (SPObject *o = SP_OBJECT(text)->children; o != NULL; o = o->next) { + if (SP_IS_FLOWPARA(o)) { + Inkscape::XML::Node *para_repr = SP_OBJECT_REPR(o)->duplicate(); + root_repr->appendChild(para_repr); + object = doc->getObjectByRepr(para_repr); + g_return_if_fail(SP_IS_FLOWPARA(object)); + Inkscape::GC::release(para_repr); + } + } + } SP_OBJECT(text)->deleteObject (true); @@ -315,8 +350,6 @@ text_flow_into_shape() Inkscape::GC::release(root_repr); Inkscape::GC::release(region_repr); - Inkscape::GC::release(para_repr); - Inkscape::GC::release(text_repr); } void @@ -398,6 +431,61 @@ text_unflow () _("Unflow flowed text")); } +void +flowtext_to_text() +{ + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + + Inkscape::Selection *selection = sp_desktop_selection(desktop); + + if (selection->isEmpty()) { + sp_desktop_message_stack(desktop)->flash(Inkscape::WARNING_MESSAGE, + _("Select flowed text(s) to convert.")); + return; + } + + bool did = false; + + GSList *reprs = NULL; + GSList *items = g_slist_copy((GSList *) selection->itemList()); + for (; items != NULL; items = items->next) { + + SPItem *item = (SPItem *) items->data; + + if (!SP_IS_FLOWTEXT(item)) + continue; + + did = true; + + Inkscape::XML::Node *repr = SP_FLOWTEXT(item)->getAsText(); + Inkscape::XML::Node *parent = SP_OBJECT_REPR(item)->parent(); + parent->appendChild(repr); + + SPItem *new_item = (SPItem *) sp_desktop_document(desktop)->getObjectByRepr(repr); + sp_item_write_transform(new_item, repr, item->transform); + SP_OBJECT(new_item)->updateRepr(); + + Inkscape::GC::release(repr); + item->deleteObject(); + + reprs = g_slist_prepend(reprs, repr); + } + + g_slist_free(items); + + if (did) { + sp_document_done(sp_desktop_document(desktop), + SP_VERB_OBJECT_FLOWTEXT_TO_TEXT, + _("Convert flowed text to text")); + selection->setReprList(reprs); + } else { + sp_desktop_message_stack(desktop)-> + flash(Inkscape::ERROR_MESSAGE, + _("No flowed text(s) to convert in the selection.")); + } + + g_slist_free(reprs); +} /* diff --git a/src/text-chemistry.h b/src/text-chemistry.h index 77fd44a61..7762b8fbc 100644 --- a/src/text-chemistry.h +++ b/src/text-chemistry.h @@ -19,6 +19,7 @@ void text_remove_from_path (void); void text_remove_all_kerns (void); void text_flow_into_shape(); void text_unflow(); +void flowtext_to_text(); #endif diff --git a/src/verbs.cpp b/src/verbs.cpp index 9c25c761d..476170e99 100644 --- a/src/verbs.cpp +++ b/src/verbs.cpp @@ -1276,7 +1276,7 @@ ObjectVerb::perform( SPAction *action, void *data, void *pdata ) text_unflow(); break; case SP_VERB_OBJECT_FLOWTEXT_TO_TEXT: - SPFlowtext::convert_to_text(); + flowtext_to_text(); break; case SP_VERB_OBJECT_FLIP_HORIZONTAL: if (tools_isactive(dt, TOOLS_NODES)) { -- 2.30.2