summaryrefslogtreecommitdiffstats
path: root/src/text-chemistry.cpp
diff options
context:
space:
mode:
authorMenTaLguY <mental@rydia.net>2006-01-16 02:36:01 +0000
committermental <mental@users.sourceforge.net>2006-01-16 02:36:01 +0000
commit179fa413b047bede6e32109e2ce82437c5fb8d34 (patch)
treea5a6ac2c1708bd02288fbd8edb2ff500ff2e0916 /src/text-chemistry.cpp
downloadinkscape-179fa413b047bede6e32109e2ce82437c5fb8d34.tar.gz
inkscape-179fa413b047bede6e32109e2ce82437c5fb8d34.zip
moving trunk for module inkscape
(bzr r1)
Diffstat (limited to 'src/text-chemistry.cpp')
-rw-r--r--src/text-chemistry.cpp390
1 files changed, 390 insertions, 0 deletions
diff --git a/src/text-chemistry.cpp b/src/text-chemistry.cpp
new file mode 100644
index 000000000..a61bbdf73
--- /dev/null
+++ b/src/text-chemistry.cpp
@@ -0,0 +1,390 @@
+#define __SP_TEXT_CHEMISTRY_C__
+
+/*
+ * Text commands
+ *
+ * Authors:
+ * bulia byak
+ *
+ * Copyright (C) 2004 authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include "libnr/nr-matrix-fns.h"
+#include "xml/repr.h"
+#include <glibmm/i18n.h>
+#include "sp-rect.h"
+#include "sp-textpath.h"
+#include "inkscape.h"
+#include "document.h"
+#include "message-stack.h"
+#include "selection.h"
+#include "desktop-handles.h"
+#include "text-editing.h"
+#include "sp-flowtext.h"
+#include "sp-flowregion.h"
+#include "sp-flowdiv.h"
+
+
+SPItem *
+text_in_selection(Inkscape::Selection *selection)
+{
+ for (GSList *items = (GSList *) selection->itemList();
+ items != NULL;
+ items = items->next) {
+ if (SP_IS_TEXT(items->data))
+ return ((SPItem *) items->data);
+ }
+ return NULL;
+}
+
+SPItem *
+flowtext_in_selection(Inkscape::Selection *selection)
+{
+ for (GSList *items = (GSList *) selection->itemList();
+ items != NULL;
+ items = items->next) {
+ if (SP_IS_FLOWTEXT(items->data))
+ return ((SPItem *) items->data);
+ }
+ return NULL;
+}
+
+SPItem *
+shape_in_selection(Inkscape::Selection *selection)
+{
+ for (GSList *items = (GSList *) selection->itemList();
+ items != NULL;
+ items = items->next) {
+ if (SP_IS_SHAPE(items->data))
+ return ((SPItem *) items->data);
+ }
+ return NULL;
+}
+
+void
+text_put_on_path()
+{
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ if (!desktop)
+ return;
+
+ Inkscape::Selection *selection = SP_DT_SELECTION(desktop);
+
+ SPItem *text = text_in_selection(selection);
+ SPItem *shape = shape_in_selection(selection);
+
+ if (!text || !shape || g_slist_length((GSList *) selection->itemList()) != 2) {
+ SP_DT_MSGSTACK(desktop)->flash(Inkscape::WARNING_MESSAGE, _("Select <b>a text and a path</b> to put text on path."));
+ return;
+ }
+
+ if (SP_IS_TEXT_TEXTPATH(text)) {
+ SP_DT_MSGSTACK(desktop)->flash(Inkscape::ERROR_MESSAGE, _("This text object is <b>already put to a path</b>. Remove it from the path first. Use <b>Shift+D</b> to look up its path."));
+ return;
+ }
+
+ if (SP_IS_RECT(shape)) {
+ // rect is the only SPShape which is not <path> yet, and thus SVG forbids us from putting text on it
+ SP_DT_MSGSTACK(desktop)->flash(Inkscape::ERROR_MESSAGE, _("You cannot put text on a rectangle in this version. Convert rectangle to path first."));
+ return;
+ }
+
+ Inkscape::Text::Layout const *layout = te_get_layout(text);
+ Inkscape::Text::Layout::Alignment text_alignment = layout->paragraphAlignment(layout->begin());
+
+ // 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);
+
+ // make a list of text children
+ GSList *text_reprs = NULL;
+ for (SPObject *o = SP_OBJECT(text)->children; o != NULL; o = o->next) {
+ text_reprs = g_slist_prepend(text_reprs, SP_OBJECT_REPR(o));
+ }
+
+ // create textPath and put it into the text
+ Inkscape::XML::Node *textpath = sp_repr_new("svg:textPath");
+ // reference the shape
+ textpath->setAttribute("xlink:href", g_strdup_printf("#%s", SP_OBJECT_REPR(shape)->attribute("id")));
+ if (text_alignment == Inkscape::Text::Layout::RIGHT)
+ textpath->setAttribute("startOffset", "100%");
+ else if (text_alignment == Inkscape::Text::Layout::CENTER)
+ textpath->setAttribute("startOffset", "50%");
+ SP_OBJECT_REPR(text)->addChild(textpath, NULL);
+
+ for ( GSList *i = text_reprs ; i ; i = i->next ) {
+ // make a copy of each text child
+ Inkscape::XML::Node *copy = ((Inkscape::XML::Node *) i->data)->duplicate();
+ // We cannot have multiline in textpath, so remove line attrs from tspans
+ if (!strcmp(copy->name(), "svg:tspan")) {
+ copy->setAttribute("sodipodi:role", NULL);
+ copy->setAttribute("x", NULL);
+ copy->setAttribute("y", NULL);
+ }
+ // remove the old repr from under text
+ SP_OBJECT_REPR(text)->removeChild((Inkscape::XML::Node *) i->data);
+ // put its copy into under textPath
+ textpath->addChild(copy, NULL); // fixme: copy id
+ }
+
+ // x/y are useless with textpath, and confuse Batik 1.5
+ SP_OBJECT_REPR(text)->setAttribute("x", NULL);
+ SP_OBJECT_REPR(text)->setAttribute("y", NULL);
+
+ sp_document_done(SP_DT_DOCUMENT(desktop));
+ g_slist_free(text_reprs);
+}
+
+void
+text_remove_from_path()
+{
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+
+ Inkscape::Selection *selection = SP_DT_SELECTION(desktop);
+
+ if (selection->isEmpty()) {
+ SP_DT_MSGSTACK(desktop)->flash(Inkscape::WARNING_MESSAGE, _("Select <b>a text on path</b> to remove it from path."));
+ return;
+ }
+
+ bool did = false;
+
+ for (GSList *items = g_slist_copy((GSList *) selection->itemList());
+ items != NULL;
+ items = items->next) {
+
+ if (!SP_IS_TEXT_TEXTPATH(SP_OBJECT(items->data))) {
+ continue;
+ }
+
+ SPObject *tp = sp_object_first_child(SP_OBJECT(items->data));
+
+ did = true;
+
+ sp_textpath_to_text(tp);
+ }
+
+ if (!did) {
+ SP_DT_MSGSTACK(desktop)->flash(Inkscape::ERROR_MESSAGE, _("<b>No texts-on-paths</b> in the selection."));
+ } else {
+ selection->setList(g_slist_copy((GSList *) selection->itemList())); // reselect to update statusbar description
+ sp_document_done(SP_DT_DOCUMENT(desktop));
+ }
+}
+
+void
+text_remove_all_kerns_recursively(SPObject *o)
+{
+ SP_OBJECT_REPR(o)->setAttribute("dx", NULL);
+ SP_OBJECT_REPR(o)->setAttribute("dy", NULL);
+ SP_OBJECT_REPR(o)->setAttribute("rotate", NULL);
+
+ for (SPObject *i = sp_object_first_child(o); i != NULL; i = SP_OBJECT_NEXT(i)) {
+ text_remove_all_kerns_recursively(i);
+ }
+}
+
+//FIXME: must work with text selection
+void
+text_remove_all_kerns()
+{
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+
+ Inkscape::Selection *selection = SP_DT_SELECTION(desktop);
+
+ if (selection->isEmpty()) {
+ SP_DT_MSGSTACK(desktop)->flash(Inkscape::WARNING_MESSAGE, _("Select <b>text(s)</b> to remove kerns from."));
+ return;
+ }
+
+ bool did = false;
+
+ for (GSList *items = g_slist_copy((GSList *) selection->itemList());
+ items != NULL;
+ items = items->next) {
+
+ if (!SP_IS_TEXT(SP_OBJECT(items->data))) {
+ continue;
+ }
+
+ text_remove_all_kerns_recursively(SP_OBJECT(items->data));
+ SP_OBJECT(items->data)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_TEXT_LAYOUT_MODIFIED_FLAG);
+ did = true;
+ }
+
+ if (!did) {
+ SP_DT_MSGSTACK(desktop)->flash(Inkscape::ERROR_MESSAGE, _("Select <b>text(s)</b> to remove kerns from."));
+ } else {
+ sp_document_done(SP_DT_DOCUMENT(desktop));
+ }
+}
+
+void
+text_flow_into_shape()
+{
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ if (!desktop)
+ return;
+
+ SPDocument *doc = SP_DT_DOCUMENT (desktop);
+
+ Inkscape::Selection *selection = SP_DT_SELECTION(desktop);
+
+ SPItem *text = text_in_selection(selection);
+ SPItem *shape = shape_in_selection(selection);
+
+ if (!text || !shape || g_slist_length((GSList *) selection->itemList()) < 2) {
+ SP_DT_MSGSTACK(desktop)->flash(Inkscape::WARNING_MESSAGE, _("Select <b>a text</b> and one or more <b>paths or shapes</b> to flow text into frame."));
+ 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);
+
+ 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
+ root_repr->setAttribute("style", SP_OBJECT_REPR(text)->attribute("style")); // fixme: transfer style attrs too
+ SP_OBJECT_REPR(SP_OBJECT_PARENT(shape))->appendChild(root_repr);
+ SPObject *root_object = doc->getObjectByRepr(root_repr);
+ g_return_if_fail(SP_IS_FLOWTEXT(root_object));
+
+ Inkscape::XML::Node *region_repr = sp_repr_new("svg:flowRegion");
+ root_repr->appendChild(region_repr);
+ SPObject *object = doc->getObjectByRepr(region_repr);
+ g_return_if_fail(SP_IS_FLOWREGION(object));
+
+ /* Add clones */
+ for (GSList *items = (GSList *) selection->itemList();
+ items != NULL;
+ items = items->next) {
+ SPItem *item = SP_ITEM(items->data);
+ if (SP_IS_SHAPE(item)){
+ Inkscape::XML::Node *clone = sp_repr_new("svg:use");
+ clone->setAttribute("x", "0");
+ clone->setAttribute("y", "0");
+ clone->setAttribute("xlink:href", g_strdup_printf("#%s", SP_OBJECT_REPR(item)->attribute("id")));
+
+ // add the new clone to the region
+ region_repr->appendChild(clone);
+ }
+ }
+
+ 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::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);
+
+ SP_OBJECT(text)->deleteObject (true);
+
+ sp_document_done(doc);
+
+ SP_DT_SELECTION(desktop)->set(SP_ITEM(root_object));
+
+ Inkscape::GC::release(root_repr);
+ Inkscape::GC::release(region_repr);
+ Inkscape::GC::release(para_repr);
+ Inkscape::GC::release(text_repr);
+}
+
+void
+text_unflow ()
+{
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ if (!desktop)
+ return;
+
+ SPDocument *doc = SP_DT_DOCUMENT (desktop);
+
+ Inkscape::Selection *selection = SP_DT_SELECTION(desktop);
+
+
+ if (!flowtext_in_selection(selection) || g_slist_length((GSList *) selection->itemList()) < 1) {
+ SP_DT_MSGSTACK(desktop)->flash(Inkscape::WARNING_MESSAGE, _("Select <b>a flowed text</b> to unflow it."));
+ return;
+ }
+
+ GSList *new_objs = NULL;
+ GSList *old_objs = NULL;
+
+ for (GSList *items = g_slist_copy((GSList *) selection->itemList());
+ items != NULL;
+ items = items->next) {
+
+ if (!SP_IS_FLOWTEXT(SP_OBJECT(items->data))) {
+ continue;
+ }
+
+ SPItem *flowtext = SP_ITEM(items->data);
+
+ /* Create <text> */
+ Inkscape::XML::Node *rtext = sp_repr_new("svg:text");
+ rtext->setAttribute("xml:space", "preserve"); // we preserve spaces in the text objects we create
+
+ /* Set style */
+ rtext->setAttribute("style", SP_OBJECT_REPR(flowtext)->attribute("style")); // fixme: transfer style attrs too; and from descendants
+
+ NRRect bbox;
+ sp_item_invoke_bbox(SP_ITEM(flowtext), &bbox, sp_item_i2doc_affine(SP_ITEM(flowtext)), TRUE);
+ NR::Point xy(bbox.x0, bbox.y0);
+ if (xy[NR::X] != 1e18 && xy[NR::Y] != 1e18) {
+ sp_repr_set_svg_double(rtext, "x", xy[NR::X]);
+ sp_repr_set_svg_double(rtext, "y", xy[NR::Y]);
+ }
+
+ /* Create <tspan> */
+ Inkscape::XML::Node *rtspan = sp_repr_new("svg:tspan");
+ rtspan->setAttribute("sodipodi:role", "line"); // otherwise, why bother creating the tspan?
+ rtext->addChild(rtspan, NULL);
+
+ gchar *text_string = sp_te_get_string_multiline(flowtext);
+ Inkscape::XML::Node *text_repr = sp_repr_new_text(text_string); // FIXME: transfer all formatting!!!
+ free(text_string);
+ rtspan->appendChild(text_repr);
+
+ SP_OBJECT_REPR(SP_OBJECT_PARENT(flowtext))->appendChild(rtext);
+ SPObject *text_object = doc->getObjectByRepr(rtext);
+
+ new_objs = g_slist_prepend (new_objs, text_object);
+ old_objs = g_slist_prepend (old_objs, flowtext);
+
+ Inkscape::GC::release(rtext);
+ Inkscape::GC::release(rtspan);
+ Inkscape::GC::release(text_repr);
+ }
+
+ selection->clear();
+ selection->setList(new_objs);
+ for (GSList *i = old_objs; i; i = i->next) {
+ SP_OBJECT(i->data)->deleteObject (true);
+ }
+
+ g_slist_free (old_objs);
+ g_slist_free (new_objs);
+
+ sp_document_done(doc);
+}
+
+
+
+/*
+ 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 :