Logo Search packages:      
Sourcecode: inkscape version File versions

text-edit.cpp

#define __SP_TEXT_EDIT_C__

/**
 * \brief Text editing dialog
 *
 * Author:
 *   Lauris Kaplinski <lauris@ximian.com>
 *
 * Copyright (C) 1999-2002 Lauris Kaplinski
 * Copyright (C) 2000-2001 Ximian, Inc.
 *
 * Released under GNU GPL, read the file 'COPYING' for more information
 */

#include <config.h>

#include <string.h>
#include <libnrtype/FontFactory.h>
#include <libnrtype/font-instance.h>

#include <glib.h>
#include <gtk/gtk.h>

#ifdef WITH_GTKSPELL
extern "C" {
#include <gtkspell/gtkspell.h>
}
#endif

#include "macros.h"
#include <glibmm/i18n.h>
#include "helper/window.h"
#include "../widgets/font-selector.h"
#include "../forward.h"
#include "../inkscape.h"
#include "../document.h"
#include "../desktop.h"
#include "../desktop-style.h"
#include "../desktop-handles.h"
#include "../selection.h"
#include "../style.h"
#include "../sp-text.h"
#include "../inkscape-stock.h"
#include <libnrtype/font-style-to-pos.h>

#include "dialog-events.h"
#include "../prefs-utils.h"
#include "../verbs.h"
#include "../interface.h"
#include "../svg/stringstream.h"
#include "widgets/icon.h"
#include <xml/repr.h>

#include "text-edit.h"

#define VB_MARGIN 4

static void sp_text_edit_dialog_modify_selection (Inkscape::Application *inkscape, SPSelection *sel, guint flags, GtkWidget *dlg);
static void sp_text_edit_dialog_change_selection (Inkscape::Application *inkscape, SPSelection *sel, GtkWidget *dlg);

static void sp_text_edit_dialog_set_default (GtkButton *button, GtkWidget *dlg);
static void sp_text_edit_dialog_apply (GtkButton *button, GtkWidget *dlg);
static void sp_text_edit_dialog_close (GtkButton *button, GtkWidget *dlg);

static void sp_text_edit_dialog_read_selection (GtkWidget *dlg, gboolean style, gboolean content);

static void sp_text_edit_dialog_text_changed (GtkTextBuffer *tb, GtkWidget *dlg);
static void sp_text_edit_dialog_font_changed (SPFontSelector *fontsel, font_instance *font, GtkWidget *dlg);
static void sp_text_edit_dialog_any_toggled (GtkToggleButton *tb, GtkWidget *dlg);
static void sp_text_edit_dialog_line_spacing_changed (GtkEditable *editable, GtkWidget *dlg);

static SPText *sp_ted_get_selected_text_item (void);
static unsigned sp_ted_get_selected_text_count (void);


static const gchar *spacings[] = {"50%", "80%", "90%", "100%", "110%", "120%", "130%", "140%", "150%", "200%", "300%", NULL};

static GtkWidget *dlg = NULL;
static win_data wd;
// impossible original values to make sure they are read from prefs
static gint x = -1000, y = -1000, w = 0, h = 0; 
static gchar const *prefs_path = "dialogs.textandfont";




static void
sp_text_edit_dialog_destroy (GtkObject *object, gpointer data)
{
    sp_signal_disconnect_by_data (INKSCAPE, dlg);
    wd.win = dlg = NULL;
    wd.stop = 0;
}



static gboolean
sp_text_edit_dialog_delete (GtkObject *object, GdkEvent *event, gpointer data)
{
    gtk_window_get_position ((GtkWindow *) dlg, &x, &y);
    gtk_window_get_size ((GtkWindow *) dlg, &w, &h);

    prefs_set_int_attribute (prefs_path, "x", x);
    prefs_set_int_attribute (prefs_path, "y", y);
    prefs_set_int_attribute (prefs_path, "w", w);
    prefs_set_int_attribute (prefs_path, "h", h);

    return FALSE; // which means, go ahead and destroy it
}


/**
    These callbacks set the eatkeys flag when the text editor is entered and cancel it when it's left.
    This flag is used to prevent passing keys from the dialog to canvas, so that the text editor
    can handle keys like Esc and Ctrl+Z itself.
 */
gboolean
text_view_focus_in (GtkWidget *w, GdkEventKey *event, gpointer data)
{
    GObject *dlg = (GObject *) data;
    g_object_set_data (dlg, "eatkeys", GINT_TO_POINTER (TRUE));
    return FALSE;
}

gboolean
text_view_focus_out (GtkWidget *w, GdkEventKey *event, gpointer data)
{
    GObject *dlg = (GObject *) data;
    g_object_set_data (dlg, "eatkeys", GINT_TO_POINTER (FALSE));
    return FALSE;
}


void
sp_text_edit_dialog (void)
{

    if (!dlg) {
    
        gchar title[500];
        sp_ui_dialog_title_string (Inkscape::Verb::get(SP_VERB_DIALOG_TEXT), title);

        dlg = sp_window_new (title, TRUE);
        if (x == -1000 || y == -1000) {
            x = prefs_get_int_attribute (prefs_path, "x", 0);
            y = prefs_get_int_attribute (prefs_path, "y", 0);
        }
        
        if (w ==0 || h == 0) {
            w = prefs_get_int_attribute (prefs_path, "w", 0);
            h = prefs_get_int_attribute (prefs_path, "h", 0);
        }
        
        if (x != 0 || y != 0) {
            gtk_window_move ((GtkWindow *) dlg, x, y);
        } else {
            gtk_window_set_position(GTK_WINDOW(dlg), GTK_WIN_POS_CENTER);
        }
        
        if (w && h) 
            gtk_window_resize ((GtkWindow *) dlg, w, h);
        
        sp_transientize (dlg);
        wd.win = dlg;
        wd.stop = 0;
        g_signal_connect ( G_OBJECT (INKSCAPE), "activate_desktop", G_CALLBACK (sp_transientize_callback), &wd );
                           
        gtk_signal_connect ( GTK_OBJECT (dlg), "event", GTK_SIGNAL_FUNC (sp_dialog_event_handler), dlg );
                             
        gtk_signal_connect ( GTK_OBJECT (dlg), "destroy", G_CALLBACK (sp_text_edit_dialog_destroy), dlg );
        gtk_signal_connect ( GTK_OBJECT (dlg), "delete_event", G_CALLBACK (sp_text_edit_dialog_delete), dlg );
        g_signal_connect ( G_OBJECT (INKSCAPE), "shut_down", G_CALLBACK (sp_text_edit_dialog_delete), dlg );
                           
        g_signal_connect ( G_OBJECT (INKSCAPE), "dialogs_hide", G_CALLBACK (sp_dialog_hide), dlg );
        g_signal_connect ( G_OBJECT (INKSCAPE), "dialogs_unhide", G_CALLBACK (sp_dialog_unhide), dlg );

        gtk_window_set_policy (GTK_WINDOW (dlg), TRUE, TRUE, FALSE);

        GtkTooltips *tt = gtk_tooltips_new();

        // box containing the notebook and the bottom buttons
        GtkWidget *mainvb = gtk_vbox_new (FALSE, 0);
        gtk_container_add (GTK_CONTAINER (dlg), mainvb);

        // notebook
        GtkWidget *nb = gtk_notebook_new ();
        gtk_box_pack_start (GTK_BOX (mainvb), nb, TRUE, TRUE, 0);
        g_object_set_data (G_OBJECT (dlg), "notebook", nb);



        // Font tab
        {
            GtkWidget *l = gtk_label_new (_("Font"));
            GtkWidget *vb = gtk_vbox_new (FALSE, VB_MARGIN);
            gtk_container_set_border_width (GTK_CONTAINER (vb), VB_MARGIN);
            gtk_notebook_append_page (GTK_NOTEBOOK (nb), vb, l);

            /* HBox containing font selection and layout */
            GtkWidget *hb = gtk_hbox_new (FALSE, 0);
            gtk_box_pack_start (GTK_BOX (vb), hb, TRUE, TRUE, 0);

            // font and style selector
            GtkWidget *fontsel = sp_font_selector_new ();
            g_signal_connect ( G_OBJECT (fontsel), "font_set", G_CALLBACK (sp_text_edit_dialog_font_changed), dlg );
            gtk_box_pack_start (GTK_BOX (hb), fontsel, TRUE, TRUE, 0);
            g_object_set_data (G_OBJECT (dlg), "fontsel", fontsel);

            // Layout
            {
                GtkWidget *f = gtk_frame_new (_("Layout"));
                gtk_box_pack_start (GTK_BOX (hb), f, FALSE, FALSE, 4);
                GtkWidget *l_vb = gtk_vbox_new (FALSE, VB_MARGIN);
                gtk_container_add (GTK_CONTAINER (f), l_vb);

                {
                    GtkWidget *row = gtk_hbox_new (FALSE, VB_MARGIN);
                    GtkWidget *group;

                    // align left
                    {
                        GtkWidget *px = gtk_image_new_from_stock ( GTK_STOCK_JUSTIFY_LEFT, GTK_ICON_SIZE_LARGE_TOOLBAR );
                        GtkWidget *b = group = gtk_radio_button_new (NULL);
                        gtk_tooltips_set_tip (tt, b, _("Align lines left"), NULL);
                        gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
                        g_signal_connect ( G_OBJECT (b), "toggled", G_CALLBACK (sp_text_edit_dialog_any_toggled), dlg);
                        gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
                        gtk_container_add (GTK_CONTAINER (b), px);
                        gtk_box_pack_start (GTK_BOX (row), b, FALSE, FALSE, 0);
                        g_object_set_data (G_OBJECT (dlg), "text_anchor_start", b);
                    }

                    // align center
                    {
                        GtkWidget *px = gtk_image_new_from_stock ( GTK_STOCK_JUSTIFY_CENTER, GTK_ICON_SIZE_LARGE_TOOLBAR );
                        GtkWidget *b = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
                        /* TRANSLATORS: `Center' here is a verb. */
                        gtk_tooltips_set_tip (tt, b, _("Center lines"), NULL);
                        gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
                        g_signal_connect ( G_OBJECT (b), "toggled", G_CALLBACK (sp_text_edit_dialog_any_toggled), dlg );
                        gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE);
                        gtk_container_add (GTK_CONTAINER (b), px);
                        gtk_box_pack_start (GTK_BOX (row), b, FALSE, FALSE, 0);
                        g_object_set_data (G_OBJECT (dlg), "text_anchor_middle", b);
                    }

                    // align right
                    {
                        GtkWidget *px = gtk_image_new_from_stock ( GTK_STOCK_JUSTIFY_RIGHT, GTK_ICON_SIZE_LARGE_TOOLBAR );
                        GtkWidget *b = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
                        gtk_tooltips_set_tip (tt, b, _("Align lines right"), NULL);
                        gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
                        g_signal_connect ( G_OBJECT (b), "toggled", G_CALLBACK (sp_text_edit_dialog_any_toggled), dlg );
                        gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE);
                        gtk_container_add (GTK_CONTAINER (b), px);
                        gtk_box_pack_start (GTK_BOX (row), b, FALSE, FALSE, 0);
                        g_object_set_data (G_OBJECT (dlg), "text_anchor_end", b);
                    }

                    gtk_box_pack_start (GTK_BOX (l_vb), row, FALSE, FALSE, 0);
                }


                {
                    GtkWidget *row = gtk_hbox_new (FALSE, VB_MARGIN);
                    GtkWidget *group;

                    // horizontal
                    {
                        GtkWidget *px = sp_icon_new_scaled ( SP_ICON_SIZE_NOTEBOOK,
                                                      INKSCAPE_STOCK_WRITING_MODE_LR );
                        GtkWidget *b = group = gtk_radio_button_new (NULL);
                        gtk_tooltips_set_tip (tt, b, _("Horizontal text"), NULL);
                        gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
                        g_signal_connect ( G_OBJECT (b), "toggled", G_CALLBACK (sp_text_edit_dialog_any_toggled), dlg );
                        gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE);
                        gtk_container_add (GTK_CONTAINER (b), px);
                        gtk_box_pack_start (GTK_BOX (row), b, FALSE, FALSE, 0);
                        g_object_set_data (G_OBJECT (dlg), INKSCAPE_STOCK_WRITING_MODE_LR, b);
                    }

                    // vertical
                    {
                        GtkWidget *px = sp_icon_new_scaled ( SP_ICON_SIZE_NOTEBOOK,
                                                      INKSCAPE_STOCK_WRITING_MODE_TB );
                        GtkWidget *b = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
                        gtk_tooltips_set_tip (tt, b, _("Vertical text"), NULL);
                        gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
                        g_signal_connect ( G_OBJECT (b), "toggled", G_CALLBACK (sp_text_edit_dialog_any_toggled), dlg );
                        gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE);
                        gtk_container_add (GTK_CONTAINER (b), px);
                        gtk_box_pack_start (GTK_BOX (row), b, FALSE, FALSE, 0);
                        g_object_set_data (G_OBJECT (dlg), INKSCAPE_STOCK_WRITING_MODE_TB, b);
                    }

                    gtk_box_pack_start (GTK_BOX (l_vb), row, FALSE, FALSE, 0);
                }

                {
                    GtkWidget *row = gtk_hbox_new (FALSE, VB_MARGIN);

                    l = gtk_label_new (_("Line spacing:"));
                    gtk_misc_set_alignment (GTK_MISC (l), 1.0, 0.5);
                    gtk_box_pack_start (GTK_BOX (row), l, FALSE, FALSE, VB_MARGIN);

                    gtk_box_pack_start (GTK_BOX (l_vb), row, FALSE, FALSE, 0);
                }

                {
                    GtkWidget *row = gtk_hbox_new (FALSE, VB_MARGIN);

                    GtkWidget *c = gtk_combo_new ();
                    gtk_combo_set_value_in_list ((GtkCombo *) c, FALSE, FALSE);
                    gtk_combo_set_use_arrows ((GtkCombo *) c, TRUE);
                    gtk_combo_set_use_arrows_always ((GtkCombo *) c, TRUE);
                    gtk_widget_set_size_request (c, 64, -1);

                    { /* Setup strings */
                        GList *sl = NULL;
                        for (int i = 0; spacings[i]; i++) {
                            sl = g_list_prepend (sl, (void *) spacings[i]);
                        }
                        sl = g_list_reverse (sl);
                        gtk_combo_set_popdown_strings ((GtkCombo *) c, sl);
                        g_list_free (sl);
                    }

                    g_signal_connect ( (GObject *) ((GtkCombo *) c)->entry, 
                                       "changed", 
                                       (GCallback) sp_text_edit_dialog_line_spacing_changed,
                                       dlg );
                    gtk_box_pack_start (GTK_BOX (row), c, FALSE, FALSE, VB_MARGIN);
                    g_object_set_data (G_OBJECT (dlg), "line_spacing", c);

                    gtk_box_pack_start (GTK_BOX (l_vb), row, FALSE, FALSE, VB_MARGIN);
                }
            }

            /* Font preview */
            GtkWidget *preview = sp_font_preview_new ();
            gtk_box_pack_start (GTK_BOX (vb), preview, TRUE, TRUE, 4);
            g_object_set_data (G_OBJECT (dlg), "preview", preview);
        }


        // Text tab
        {
            GtkWidget *l = gtk_label_new (_("Text"));
            GtkWidget *vb = gtk_vbox_new (FALSE, VB_MARGIN);
            gtk_container_set_border_width (GTK_CONTAINER (vb), VB_MARGIN);
            gtk_notebook_append_page (GTK_NOTEBOOK (nb), vb, l);

            GtkWidget *scroller = gtk_scrolled_window_new ( NULL, NULL );
            gtk_scrolled_window_set_policy ( GTK_SCROLLED_WINDOW (scroller),
                                             GTK_POLICY_AUTOMATIC,
                                             GTK_POLICY_AUTOMATIC );
            gtk_scrolled_window_set_shadow_type ( GTK_SCROLLED_WINDOW(scroller), GTK_SHADOW_IN );
            gtk_widget_show (scroller);

            GtkTextBuffer *tb = gtk_text_buffer_new (NULL);
            GtkWidget *txt = gtk_text_view_new_with_buffer (tb);
#ifdef WITH_GTKSPELL
            GError *error = NULL;
            char *errortext = NULL;
            /* todo: Use computed xml:lang attribute of relevant element, if present, to specify the
               language (either as 2nd arg of gtkspell_new_attach, or with explicit
               gtkspell_set_language call in; see advanced.c example in gtkspell docs).
               sp_text_edit_dialog_read_selection looks like a suitable place. */
            if (gtkspell_new_attach(GTK_TEXT_VIEW(txt), NULL, &error) == NULL) {
                g_print("gtkspell error: %s\n", error->message);
                errortext = g_strdup_printf("GtkSpell was unable to initialize.\n"
                                            "%s", error->message);
                g_error_free(error);
            }
#endif
            gtk_widget_set_size_request (txt, -1, 64);
            gtk_text_view_set_editable (GTK_TEXT_VIEW (txt), TRUE);
            gtk_container_add (GTK_CONTAINER (scroller), txt);
            gtk_box_pack_start (GTK_BOX (vb), scroller, TRUE, TRUE, 0);
            g_signal_connect ( G_OBJECT (tb), "changed", 
                               G_CALLBACK (sp_text_edit_dialog_text_changed), dlg );
            g_signal_connect (G_OBJECT (txt), "focus-in-event", G_CALLBACK (text_view_focus_in), dlg);
            g_signal_connect (G_OBJECT (txt), "focus-out-event", G_CALLBACK (text_view_focus_out), dlg);
            g_object_set_data (G_OBJECT (dlg), "text", tb);
            g_object_set_data (G_OBJECT (dlg), "textw", txt);
        }

        /* Buttons */
        GtkWidget *hb = gtk_hbox_new (FALSE, VB_MARGIN);
        gtk_container_set_border_width (GTK_CONTAINER (hb), 4);
        gtk_box_pack_start (GTK_BOX (mainvb), hb, FALSE, FALSE, 0);

        {
            GtkWidget *b = gtk_button_new_with_label (_("Set as default"));
            g_signal_connect ( G_OBJECT (b), "clicked", 
                               G_CALLBACK (sp_text_edit_dialog_set_default), 
                               dlg );
            gtk_box_pack_start (GTK_BOX (hb), b, FALSE, FALSE, 0);
            g_object_set_data (G_OBJECT (dlg), "default", b);
        }

        {
            GtkWidget *b = gtk_button_new_from_stock (GTK_STOCK_CLOSE);
            g_signal_connect ( G_OBJECT (b), "clicked", 
                               G_CALLBACK (sp_text_edit_dialog_close), dlg );
            gtk_box_pack_end (GTK_BOX (hb), b, FALSE, FALSE, 0);
        }

        {
            GtkWidget *b = gtk_button_new_from_stock (GTK_STOCK_APPLY);
            g_signal_connect ( G_OBJECT (b), "clicked", 
                               G_CALLBACK (sp_text_edit_dialog_apply), dlg );
            gtk_box_pack_end ( GTK_BOX (hb), b, FALSE, FALSE, 0 );
            g_object_set_data (G_OBJECT (dlg), "apply", b);
        }

        g_signal_connect ( G_OBJECT (INKSCAPE), "modify_selection", 
                           G_CALLBACK (sp_text_edit_dialog_modify_selection), dlg);
        g_signal_connect ( G_OBJECT (INKSCAPE), "change_selection", 
                           G_CALLBACK (sp_text_edit_dialog_change_selection), dlg);

        gtk_widget_show_all (dlg);

        sp_text_edit_dialog_read_selection (dlg, TRUE, TRUE);
    }

    gtk_window_present ((GtkWindow *) dlg);

} // end of sp_text_edit_dialog()



static void
sp_text_edit_dialog_modify_selection ( Inkscape::Application *inkscape, 
                                       SPSelection *sel, 
                                       guint flags, 
                                       GtkWidget *dlg )
{
    gboolean style, content;

    style = 
        ((flags & ( SP_OBJECT_CHILD_MODIFIED_FLAG | 
                    SP_OBJECT_STYLE_MODIFIED_FLAG  )) != 0 );
    
    content = 
        ((flags & ( SP_OBJECT_CHILD_MODIFIED_FLAG | 
                    SP_TEXT_CONTENT_MODIFIED_FLAG  )) != 0 );
    
    sp_text_edit_dialog_read_selection (dlg, style, content);

} // end of sp_text_edit_dialog_modify_selection()



static void
sp_text_edit_dialog_change_selection ( Inkscape::Application *inkscape, 
                                       SPSelection *sel, 
                                       GtkWidget *dlg )
{
    sp_text_edit_dialog_read_selection (dlg, TRUE, TRUE);
}


static void
sp_text_edit_dialog_update_object_text ( SPText *text )
{
        GtkTextBuffer *tb;
        GtkTextIter start, end;
        gchar *str;

        tb = (GtkTextBuffer*)g_object_get_data (G_OBJECT (dlg), "text");

        /* write text */
        if (gtk_text_buffer_get_modified (tb)) {
            gtk_text_buffer_get_bounds (tb, &start, &end);
            str = gtk_text_buffer_get_text (tb, &start, &end, TRUE);
            sp_text_set_repr_text_multiline (text, str);
            g_free (str);    
            gtk_text_buffer_set_modified (tb, FALSE);
        }
}

SPCSSAttr *
sp_get_text_dialog_style ()
{
        GtkWidget *fontsel = (GtkWidget*)g_object_get_data (G_OBJECT (dlg), "fontsel");

        SPCSSAttr *css = sp_repr_css_attr_new ();

        /* font */
        font_instance *font = sp_font_selector_get_font (SP_FONT_SELECTOR (fontsel));

                        if ( font ) {
                              gchar c[256];
                              font->Family(c, 256);
                              sp_repr_css_set_property (css, "font-family", c);
                              
                              font->Attribute( "weight", c, 256);
                              sp_repr_css_set_property (css, "font-weight", c);
                              
                              font->Attribute("style", c, 256);
                              sp_repr_css_set_property (css, "font-style", c);
                              
                              font->Attribute("stretch", c, 256);
                              sp_repr_css_set_property (css, "font-stretch", c);
                              
                              font->Attribute("variant", c, 256);
                              sp_repr_css_set_property (css, "font-variant", c);
                              
                              Inkscape::SVGOStringStream os;
                              os << sp_font_selector_get_size (SP_FONT_SELECTOR (fontsel));
                              sp_repr_css_set_property (css, "font-size", os.str().c_str());
                              
                              font->Unref();
                              font=NULL;
                        }
                        
        /* Layout */
        GtkWidget *b = (GtkWidget*)g_object_get_data (G_OBJECT (dlg), "text_anchor_start");
        
        if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (b))) {
            sp_repr_css_set_property (css, "text-anchor", "start");
        } else {
            b = (GtkWidget*)g_object_get_data ( G_OBJECT (dlg), 
                                                "text_anchor_middle");
            if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (b))) {
                sp_repr_css_set_property (css, "text-anchor", "middle");
            } else {
                sp_repr_css_set_property (css, "text-anchor", "end");
            }
        }
        
        b = (GtkWidget*)g_object_get_data (G_OBJECT (dlg), INKSCAPE_STOCK_WRITING_MODE_LR );
        
        if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (b))) {
            sp_repr_css_set_property (css, "writing-mode", "lr");
        } else {
            sp_repr_css_set_property (css, "writing-mode", "tb");
        }

        // Note that CSS 1.1 does not support line-height; we set it for consistency, but also set
        // sodipodi:linespacing for backwards compatibility; in 1.2 we use line-height for flowtext
        GtkWidget *combo = (GtkWidget*)g_object_get_data ((GObject *) dlg, "line_spacing");
        const char *sstr = gtk_entry_get_text ((GtkEntry *) ((GtkCombo *) (combo))->entry);
        sp_repr_css_set_property (css, "line-height", sstr);

        return css;
}


static void
sp_text_edit_dialog_set_default (GtkButton *button, GtkWidget *dlg)
{
    GtkWidget *def = (GtkWidget*)g_object_get_data (G_OBJECT (dlg), "default");

    SPCSSAttr *css = sp_get_text_dialog_style ();

    g_object_set_data (G_OBJECT (dlg), "blocked", GINT_TO_POINTER (TRUE));
    sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
    g_object_set_data (G_OBJECT (dlg), "blocked", GINT_TO_POINTER (FALSE));

    sp_repr_css_attr_unref (css);

    gtk_widget_set_sensitive (def, FALSE);
}



static void
sp_text_edit_dialog_apply (GtkButton *button, GtkWidget *dlg)
{
    g_object_set_data (G_OBJECT (dlg), "blocked", GINT_TO_POINTER (TRUE));

    GtkWidget *apply = (GtkWidget*)g_object_get_data (G_OBJECT (dlg), "apply");
    GtkWidget *def = (GtkWidget*)g_object_get_data (G_OBJECT (dlg), "default");

    unsigned items = 0;
    const GSList *item_list = SP_DT_SELECTION(SP_ACTIVE_DESKTOP)->itemList();
    bool text_changed = false, style_changed = false;

    SPCSSAttr *css = sp_get_text_dialog_style ();

    for (; item_list != NULL; item_list = item_list->next) { 
        // apply style to the reprs of all text objects in the selection
        if (SP_IS_TEXT (item_list->data)) {
            SPText *text = SP_TEXT(item_list->data);

        // FIXME: use sp_desktop_set_style instead!
        sp_desktop_apply_css_recursive (SP_OBJECT(text), css, true);
        // backwards compatibility:
        sp_repr_set_attr (SP_OBJECT_REPR(text), "sodipodi:linespacing", sp_repr_css_property (css, "line-height", NULL));

            ++items;
            style_changed = true;
        }
    }
    
    if (items == 0) { 
        // no text objects; apply style to prefs for new objects
        sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
        gtk_widget_set_sensitive (def, FALSE);
    } else if (items == 1) {
        /* exactly one text object; now set its text, too */
        SPItem *item = SP_DT_SELECTION(SP_ACTIVE_DESKTOP)->singleItem();
        if (SP_IS_TEXT (item)) {
            sp_text_edit_dialog_update_object_text (SP_TEXT(item));
            text_changed = true;
        }
    } 

    // complete the transaction
    if (style_changed || text_changed) {
        sp_document_done (SP_DT_DOCUMENT (SP_ACTIVE_DESKTOP));
    }

    gtk_widget_set_sensitive (apply, FALSE);

    sp_repr_css_attr_unref (css);

    g_object_set_data (G_OBJECT (dlg), "blocked", GINT_TO_POINTER (FALSE));
}



static void
sp_text_edit_dialog_close (GtkButton *button, GtkWidget *dlg)
{
    gtk_widget_destroy (GTK_WIDGET (dlg));
}



static void
sp_text_edit_dialog_read_selection ( GtkWidget *dlg, 
                                     gboolean dostyle, 
                                     gboolean docontent )
{
    if (g_object_get_data (G_OBJECT (dlg), "blocked")) 
        return;
    
    g_object_set_data (G_OBJECT (dlg), "blocked", GINT_TO_POINTER (TRUE));

    GtkWidget *notebook = (GtkWidget*)g_object_get_data (G_OBJECT (dlg), "notebook");
    GtkWidget *textw = (GtkWidget*)g_object_get_data (G_OBJECT (dlg), "textw");
    GtkWidget *fontsel = (GtkWidget*)g_object_get_data (G_OBJECT (dlg), "fontsel");
    GtkWidget *preview = (GtkWidget*)g_object_get_data (G_OBJECT (dlg), "preview");
    GtkWidget *apply = (GtkWidget*)g_object_get_data (G_OBJECT (dlg), "apply");
    GtkWidget *def = (GtkWidget*)g_object_get_data (G_OBJECT (dlg), "default");

    GtkTextBuffer *tb = (GtkTextBuffer*)g_object_get_data (G_OBJECT (dlg), "text");

    SPText *text = sp_ted_get_selected_text_item ();

    SPRepr *repr;
    SPStyle *style;
    if (text)
    {
        guint items = sp_ted_get_selected_text_count ();
        if (items == 1) {
            gtk_widget_set_sensitive (textw, TRUE);
        } else {
            gtk_widget_set_sensitive (textw, FALSE);
        }
        gtk_widget_set_sensitive (apply, FALSE);
        gtk_widget_set_sensitive (def, TRUE);
        style = SP_OBJECT_STYLE (text);

        if (docontent) {
            gchar *str;
            str = sp_text_get_string_multiline (text);

            if (str) {
                int pos;
                pos = 0;

                if (items == 1) {
                    gtk_text_buffer_set_text (tb, str, strlen (str));
                    gtk_text_buffer_set_modified (tb, FALSE);
                }
                sp_font_preview_set_phrase (SP_FONT_PREVIEW (preview), str);
                g_free (str);

            } else {
                gtk_text_buffer_set_text (tb, "", 0);
                sp_font_preview_set_phrase (SP_FONT_PREVIEW (preview), NULL);
            }
        } // end of if (docontent)
        repr = SP_OBJECT_REPR (text);
        
    } else {
        gtk_widget_set_sensitive (textw, FALSE);
        gtk_widget_set_sensitive (apply, FALSE);
        gtk_widget_set_sensitive (def, FALSE);
        repr = inkscape_get_repr (INKSCAPE, "tools.text");
        if (repr) {
            gtk_widget_set_sensitive (notebook, TRUE);
            style = sp_style_new ();
            sp_style_read_from_repr (style, repr);
        } else {
            gtk_widget_set_sensitive (notebook, FALSE);
            style = sp_style_new ();
        }
    }

    if (dostyle) {
        GtkWidget *b, *combo;
        const gchar *sstr;

        font_instance *font = (font_factory::Default())->Face ( style->text->font_family.value, font_style_to_pos(*style) );

        if (font) {
            // the font is oversized, so we need to pass the true size separately
            sp_font_selector_set_font (SP_FONT_SELECTOR (fontsel), font, style->font_size.computed);
            sp_font_preview_set_font (SP_FONT_PREVIEW (preview), font, SP_FONT_SELECTOR(fontsel));
                                    font->Unref();
                                    font=NULL;
        }

        if (style->text_anchor.computed == SP_CSS_TEXT_ANCHOR_START) {
            b = (GtkWidget*)g_object_get_data ( G_OBJECT (dlg), 
                                                "text_anchor_start" );
        } else if (style->text_anchor.computed == SP_CSS_TEXT_ANCHOR_MIDDLE) {
            b = (GtkWidget*)g_object_get_data ( G_OBJECT (dlg), 
                                                "text_anchor_middle" );
        } else {
            b = (GtkWidget*)g_object_get_data ( G_OBJECT (dlg), 
                                                "text_anchor_end" );
        }

        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b), TRUE);
        
        if (style->writing_mode.computed == SP_CSS_WRITING_MODE_LR) {
            b = (GtkWidget*)g_object_get_data ( G_OBJECT (dlg), 
                                                INKSCAPE_STOCK_WRITING_MODE_LR );
        } else {
            b = (GtkWidget*)g_object_get_data ( G_OBJECT (dlg), 
                                                INKSCAPE_STOCK_WRITING_MODE_TB );
        }
        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b), TRUE);
        combo = (GtkWidget*)g_object_get_data ( G_OBJECT (dlg), 
                                                "line_spacing" );
        sstr = (repr) ? sp_repr_attr (repr, "sodipodi:linespacing") : NULL;
        gtk_entry_set_text ((GtkEntry *) ((GtkCombo *) (combo))->entry, 
                    (sstr) ? sstr : (const gchar *) "100%");
    }

    g_object_set_data (G_OBJECT (dlg), "blocked", NULL);
   
} // end of sp_text_edit_dialog_read_selection()



static void
sp_text_edit_dialog_text_changed (GtkTextBuffer *tb, GtkWidget *dlg)
{
    GtkWidget *textw, *preview, *apply, *def;
    SPText *text;
    GtkTextIter start, end;
    gchar *str;

    if (g_object_get_data (G_OBJECT (dlg), "blocked")) 
        return;

    text = sp_ted_get_selected_text_item ();

    textw = (GtkWidget*)g_object_get_data (G_OBJECT (dlg), "textw");
    preview = (GtkWidget*)g_object_get_data (G_OBJECT (dlg), "preview");
    apply = (GtkWidget*)g_object_get_data (G_OBJECT (dlg), "apply");
    def = (GtkWidget*)g_object_get_data (G_OBJECT (dlg), "default");

    gtk_text_buffer_get_bounds (tb, &start, &end);
    str = gtk_text_buffer_get_text (tb, &start, &end, TRUE);

    if (str && *str) {
        sp_font_preview_set_phrase (SP_FONT_PREVIEW (preview), str);
    } else {
        sp_font_preview_set_phrase (SP_FONT_PREVIEW (preview), NULL);
    }
    g_free (str);

    if (text) {
        gtk_widget_set_sensitive (apply, TRUE);
    }
    gtk_widget_set_sensitive (def, TRUE);

} // end of sp_text_edit_dialog_text_changed()



static void
sp_text_edit_dialog_font_changed ( SPFontSelector *fsel, 
                                   font_instance *font, 
                                   GtkWidget *dlg )
{
    GtkWidget *preview, *apply, *def;
    SPText *text;

    if (g_object_get_data (G_OBJECT (dlg), "blocked")) 
        return;

    text = sp_ted_get_selected_text_item ();

    preview = (GtkWidget*)g_object_get_data (G_OBJECT (dlg), "preview");
    apply = (GtkWidget*)g_object_get_data (G_OBJECT (dlg), "apply");
    def = (GtkWidget*)g_object_get_data (G_OBJECT (dlg), "default");

    sp_font_preview_set_font (SP_FONT_PREVIEW (preview), font, SP_FONT_SELECTOR(fsel));

    if (text) {
        gtk_widget_set_sensitive (apply, TRUE);
    }
    gtk_widget_set_sensitive (def, TRUE);

} // end of sp_text_edit_dialog_font_changed()



static void
sp_text_edit_dialog_any_toggled (GtkToggleButton *tb, GtkWidget *dlg)
{
    GtkWidget *apply, *def;
    SPText *text;

    if (g_object_get_data (G_OBJECT (dlg), "blocked"))
        return;

    text = sp_ted_get_selected_text_item ();

    apply = (GtkWidget*)g_object_get_data (G_OBJECT (dlg), "apply");
    def = (GtkWidget*)g_object_get_data (G_OBJECT (dlg), "default");

    if (text) {
        gtk_widget_set_sensitive (apply, TRUE);
    }
    gtk_widget_set_sensitive (def, TRUE);
}



static void
sp_text_edit_dialog_line_spacing_changed (GtkEditable *editable, GtkWidget *dlg)
{
    GtkWidget *apply, *def;
    SPText *text;

    if (g_object_get_data ((GObject *) dlg, "blocked")) 
        return;

    text = sp_ted_get_selected_text_item ();

    apply = (GtkWidget*)g_object_get_data (G_OBJECT (dlg), "apply");
    def = (GtkWidget*)g_object_get_data (G_OBJECT (dlg), "default");

    if (text) {
        gtk_widget_set_sensitive (apply, TRUE);
    }
    gtk_widget_set_sensitive (def, TRUE);
}



static SPText *
sp_ted_get_selected_text_item (void)
{
    if (!SP_ACTIVE_DESKTOP)
        return NULL;

    for (const GSList *item = SP_DT_SELECTION(SP_ACTIVE_DESKTOP)->itemList();
         item != NULL;
         item = item->next)
    {
        if (SP_IS_TEXT(item->data))
            return SP_TEXT (item->data);
    }

    return NULL;
}



static unsigned
sp_ted_get_selected_text_count (void)
{
    if (!SP_ACTIVE_DESKTOP) 
        return 0;

    unsigned int items = 0;

    for (const GSList *item = SP_DT_SELECTION(SP_ACTIVE_DESKTOP)->itemList();
         item != NULL;
         item = item->next)
    {
        if (SP_IS_TEXT(item->data))
            ++items;
    }

    return items;
}

/*
  Local Variables:
  mode:c++
  c-file-style:"stroustrup"
  c-file-offsets:((innamespace . 0)(inline-open . 0))
  indent-tabs-mode:nil
  fill-column:99
  End:
*/
// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :

Generated by  Doxygen 1.6.0   Back to index