~valavanisalex/ubuntu/oneiric/inkscape/inkscape_0.48.1-2ubuntu4

« back to all changes in this revision

Viewing changes to src/ui/dialog/svg-fonts-dialog.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Kees Cook, Ted Gould, Kees Cook
  • Date: 2009-06-24 14:00:43 UTC
  • mfrom: (1.1.8 upstream)
  • Revision ID: james.westby@ubuntu.com-20090624140043-07stp20mry48hqup
Tags: 0.47~pre0-0ubuntu1
* New upstream release

[ Ted Gould ]
* debian/control: Adding libgsl0 and removing version specifics on boost

[ Kees Cook ]
* debian/watch: updated to run uupdate and mangle pre-release versions.
* Dropped patches that have been taken upstream:
  - 01_mips
  - 02-poppler-0.8.3
  - 03-chinese-inkscape
  - 05_fix_latex_patch
  - 06_gcc-4.4
  - 07_cdr2svg
  - 08_skip-bad-utf-on-pdf-import
  - 09_gtk-clist
  - 10_belarussian
  - 11_libpng
  - 12_desktop
  - 13_slider
  - 100_svg_import_improvements
  - 102_sp_pattern_painter_free
  - 103_bitmap_type_print

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/** @file
 
2
 * @brief SVG Fonts dialog - implementation
 
3
 */
 
4
/* Authors:
 
5
 *   Felipe C. da S. Sanches <felipe.sanches@gmail.com>
 
6
 *
 
7
 * Copyright (C) 2008 Authors
 
8
 * Released under GNU GPLv2 (or later).  Read the file 'COPYING' for more information.
 
9
 */
 
10
 
 
11
#ifdef HAVE_CONFIG_H
 
12
# include <config.h>
 
13
#endif
 
14
 
 
15
#ifdef ENABLE_SVG_FONTS
 
16
 
 
17
#include <2geom/pathvector.h>
 
18
#include "document-private.h"
 
19
#include <gtkmm/notebook.h>
 
20
#include <glibmm/i18n.h>
 
21
#include <message-stack.h>
 
22
#include "selection.h"
 
23
#include <string.h>
 
24
#include "svg/svg.h"
 
25
#include "svg-fonts-dialog.h"
 
26
#include "xml/node.h"
 
27
#include "xml/repr.h"
 
28
 
 
29
SvgFontDrawingArea::SvgFontDrawingArea(){
 
30
    this->text = "";
 
31
    this->svgfont = NULL;
 
32
}
 
33
 
 
34
void SvgFontDrawingArea::set_svgfont(SvgFont* svgfont){
 
35
    this->svgfont = svgfont;
 
36
}
 
37
 
 
38
void SvgFontDrawingArea::set_text(Glib::ustring text){
 
39
    this->text = text;
 
40
    redraw();
 
41
}
 
42
 
 
43
void SvgFontDrawingArea::set_size(int x, int y){
 
44
    this->x = x;
 
45
    this->y = y;
 
46
    ((Gtk::Widget*) this)->set_size_request(x, y);
 
47
}
 
48
 
 
49
void SvgFontDrawingArea::redraw(){
 
50
    ((Gtk::Widget*) this)->queue_draw();
 
51
}
 
52
 
 
53
bool SvgFontDrawingArea::on_expose_event (GdkEventExpose */*event*/){
 
54
  if (this->svgfont){
 
55
    Glib::RefPtr<Gdk::Window> window = get_window();
 
56
    Cairo::RefPtr<Cairo::Context> cr = window->create_cairo_context();
 
57
    cr->set_font_face( Cairo::RefPtr<Cairo::FontFace>(new Cairo::FontFace(this->svgfont->get_font_face(), false /* does not have reference */)) );
 
58
    cr->set_font_size (this->y-20);
 
59
    cr->move_to (10, 10);
 
60
    cr->show_text (this->text.c_str());
 
61
  }
 
62
  return TRUE;
 
63
}
 
64
 
 
65
namespace Inkscape {
 
66
namespace UI {
 
67
namespace Dialog {
 
68
 
 
69
/*
 
70
Gtk::HBox* SvgFontsDialog::AttrEntry(gchar* lbl, const SPAttributeEnum attr){
 
71
    Gtk::HBox* hbox = Gtk::manage(new Gtk::HBox());
 
72
    hbox->add(* Gtk::manage(new Gtk::Label(lbl)) );
 
73
    Gtk::Entry* entry = Gtk::manage(new Gtk::Entry());
 
74
    hbox->add(* entry );
 
75
    hbox->show_all();
 
76
 
 
77
    entry->signal_changed().connect(sigc::mem_fun(*this, &SvgFontsDialog::on_attr_changed));
 
78
    return hbox;
 
79
}
 
80
*/
 
81
 
 
82
SvgFontsDialog::AttrEntry::AttrEntry(SvgFontsDialog* d, gchar* lbl, const SPAttributeEnum attr){
 
83
    this->dialog = d;
 
84
    this->attr = attr;
 
85
    this->add(* Gtk::manage(new Gtk::Label(lbl)) );
 
86
    this->add(entry);
 
87
    this->show_all();
 
88
 
 
89
    entry.signal_changed().connect(sigc::mem_fun(*this, &SvgFontsDialog::AttrEntry::on_attr_changed));
 
90
}
 
91
 
 
92
void SvgFontsDialog::AttrEntry::set_text(char* t){
 
93
    if (!t) return;
 
94
    entry.set_text(t);
 
95
}
 
96
 
 
97
void SvgFontsDialog::AttrEntry::on_attr_changed(){
 
98
 
 
99
    SPObject* o = NULL;
 
100
    for(SPObject* node = this->dialog->get_selected_spfont()->children; node; node=node->next){
 
101
        switch(this->attr){
 
102
            case SP_PROP_FONT_FAMILY:
 
103
                if (SP_IS_FONTFACE(node)){
 
104
                    o = node;
 
105
                    continue;
 
106
                }
 
107
                break;
 
108
            default:
 
109
                o = NULL;
 
110
        }
 
111
    }
 
112
 
 
113
    const gchar* name = (const gchar*)sp_attribute_name(this->attr);
 
114
    if(name && o) {
 
115
        SP_OBJECT_REPR(o)->setAttribute((const gchar*) name, this->entry.get_text().c_str());
 
116
        o->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
 
117
 
 
118
        Glib::ustring undokey = "svgfonts:";
 
119
        undokey += name;
 
120
        sp_document_maybe_done(o->document, undokey.c_str(), SP_VERB_DIALOG_SVG_FONTS,
 
121
                               _("Set SVG Font attribute"));
 
122
    }
 
123
 
 
124
}
 
125
 
 
126
Gtk::HBox* SvgFontsDialog::AttrCombo(gchar* lbl, const SPAttributeEnum /*attr*/){
 
127
    Gtk::HBox* hbox = Gtk::manage(new Gtk::HBox());
 
128
    hbox->add(* Gtk::manage(new Gtk::Label(lbl)) );
 
129
    hbox->add(* Gtk::manage(new Gtk::ComboBox()) );
 
130
    hbox->show_all();
 
131
    return hbox;
 
132
}
 
133
 
 
134
/*
 
135
Gtk::HBox* SvgFontsDialog::AttrSpin(gchar* lbl){
 
136
    Gtk::HBox* hbox = Gtk::manage(new Gtk::HBox());
 
137
    hbox->add(* Gtk::manage(new Gtk::Label(lbl)) );
 
138
    hbox->add(* Gtk::manage(new Gtk::SpinBox()) );
 
139
    hbox->show_all();
 
140
    return hbox;
 
141
}*/
 
142
 
 
143
/*** SvgFontsDialog ***/
 
144
 
 
145
GlyphComboBox::GlyphComboBox(){
 
146
}
 
147
 
 
148
void GlyphComboBox::update(SPFont* spfont){
 
149
    if (!spfont) return
 
150
//TODO: figure out why do we need to append_text("") before clearing items properly...
 
151
 
 
152
    this->append_text(""); //Gtk is refusing to clear the combobox when I comment out this line
 
153
    this->clear_items();
 
154
 
 
155
    for(SPObject* node = spfont->children; node; node=node->next){
 
156
        if (SP_IS_GLYPH(node)){
 
157
            this->append_text(((SPGlyph*)node)->unicode);
 
158
        }
 
159
    }
 
160
}
 
161
 
 
162
void SvgFontsDialog::on_kerning_value_changed(){
 
163
    if (!this->kerning_pair) return;
 
164
    SPDocument* document = sp_desktop_document(this->getDesktop());
 
165
 
 
166
    //TODO: I am unsure whether this is the correct way of calling sp_document_maybe_done
 
167
    Glib::ustring undokey = "svgfonts:hkern:k:";
 
168
    undokey += this->kerning_pair->u1->attribute_string();
 
169
    undokey += ":";
 
170
    undokey += this->kerning_pair->u2->attribute_string();
 
171
 
 
172
    //slider values increase from right to left so that they match the kerning pair preview
 
173
    this->kerning_pair->repr->setAttribute("k", Glib::Ascii::dtostr(get_selected_spfont()->horiz_adv_x - kerning_slider.get_value()).c_str());
 
174
    sp_document_maybe_done(document, undokey.c_str(), SP_VERB_DIALOG_SVG_FONTS, _("Adjust kerning value"));
 
175
 
 
176
    //populate_kerning_pairs_box();
 
177
    kerning_preview.redraw();
 
178
    _font_da.redraw();
 
179
}
 
180
 
 
181
void SvgFontsDialog::glyphs_list_button_release(GdkEventButton* event)
 
182
{
 
183
    if((event->type == GDK_BUTTON_RELEASE) && (event->button == 3)) {
 
184
        _GlyphsContextMenu.popup(event->button, event->time);
 
185
    }
 
186
}
 
187
 
 
188
void SvgFontsDialog::kerning_pairs_list_button_release(GdkEventButton* event)
 
189
{
 
190
    if((event->type == GDK_BUTTON_RELEASE) && (event->button == 3)) {
 
191
        _KerningPairsContextMenu.popup(event->button, event->time);
 
192
    }
 
193
}
 
194
 
 
195
void SvgFontsDialog::fonts_list_button_release(GdkEventButton* event)
 
196
{
 
197
    if((event->type == GDK_BUTTON_RELEASE) && (event->button == 3)) {
 
198
        _FontsContextMenu.popup(event->button, event->time);
 
199
    }
 
200
}
 
201
 
 
202
void SvgFontsDialog::create_glyphs_popup_menu(Gtk::Widget& parent, sigc::slot<void> rem)
 
203
{
 
204
    Gtk::MenuItem* mi = Gtk::manage(new Gtk::ImageMenuItem(Gtk::Stock::REMOVE));
 
205
    _GlyphsContextMenu.append(*mi);
 
206
    mi->signal_activate().connect(rem);
 
207
    mi->show();
 
208
    _GlyphsContextMenu.accelerate(parent);
 
209
}
 
210
 
 
211
void SvgFontsDialog::create_kerning_pairs_popup_menu(Gtk::Widget& parent, sigc::slot<void> rem)
 
212
{
 
213
    Gtk::MenuItem* mi = Gtk::manage(new Gtk::ImageMenuItem(Gtk::Stock::REMOVE));
 
214
    _KerningPairsContextMenu.append(*mi);
 
215
    mi->signal_activate().connect(rem);
 
216
    mi->show();
 
217
    _KerningPairsContextMenu.accelerate(parent);
 
218
}
 
219
 
 
220
void SvgFontsDialog::create_fonts_popup_menu(Gtk::Widget& parent, sigc::slot<void> rem)
 
221
{
 
222
    Gtk::MenuItem* mi = Gtk::manage(new Gtk::ImageMenuItem(Gtk::Stock::REMOVE));
 
223
    _FontsContextMenu.append(*mi);
 
224
    mi->signal_activate().connect(rem);
 
225
    mi->show();
 
226
    _FontsContextMenu.accelerate(parent);
 
227
}
 
228
 
 
229
void SvgFontsDialog::update_sensitiveness(){
 
230
    if (get_selected_spfont()){
 
231
        global_vbox.set_sensitive(true);
 
232
        glyphs_vbox.set_sensitive(true);
 
233
        kerning_vbox.set_sensitive(true);
 
234
    } else {
 
235
        global_vbox.set_sensitive(false);
 
236
        glyphs_vbox.set_sensitive(false);
 
237
        kerning_vbox.set_sensitive(false);
 
238
    }
 
239
}
 
240
 
 
241
/* Add all fonts in the document to the combobox. */
 
242
void SvgFontsDialog::update_fonts()
 
243
{
 
244
    SPDesktop* desktop = this->getDesktop();
 
245
    SPDocument* document = sp_desktop_document(desktop);
 
246
    const GSList* fonts = sp_document_get_resource_list(document, "font");
 
247
 
 
248
    _model->clear();
 
249
    for(const GSList *l = fonts; l; l = l->next) {
 
250
        Gtk::TreeModel::Row row = *_model->append();
 
251
        SPFont* f = (SPFont*)l->data;
 
252
        row[_columns.spfont] = f;
 
253
        row[_columns.svgfont] = new SvgFont(f);
 
254
        const gchar* lbl = f->label();
 
255
        const gchar* id = SP_OBJECT_ID(f);
 
256
        row[_columns.label] = lbl ? lbl : (id ? id : "font");
 
257
    }
 
258
 
 
259
    update_sensitiveness();
 
260
}
 
261
 
 
262
void SvgFontsDialog::on_preview_text_changed(){
 
263
    _font_da.set_text((gchar*) _preview_entry.get_text().c_str());
 
264
    _font_da.set_text(_preview_entry.get_text());
 
265
}
 
266
 
 
267
void SvgFontsDialog::on_kerning_pair_selection_changed(){
 
268
    SPGlyphKerning* kern = get_selected_kerning_pair();
 
269
    if (!kern) {
 
270
        kerning_preview.set_text("");
 
271
        return;
 
272
    }
 
273
    Glib::ustring str;
 
274
    str += kern->u1->sample_glyph();
 
275
    str += kern->u2->sample_glyph();
 
276
 
 
277
    kerning_preview.set_text(str);
 
278
    this->kerning_pair = kern;
 
279
 
 
280
    //slider values increase from right to left so that they match the kerning pair preview
 
281
    kerning_slider.set_value(get_selected_spfont()->horiz_adv_x - kern->k);
 
282
}
 
283
 
 
284
void SvgFontsDialog::update_global_settings_tab(){
 
285
    SPFont* font = get_selected_spfont();
 
286
    if (!font) return;
 
287
 
 
288
    SPObject* obj;
 
289
    for (obj=font->children; obj; obj=obj->next){
 
290
        if (SP_IS_FONTFACE(obj)){
 
291
            _familyname_entry->set_text(((SPFontFace*) obj)->font_family);
 
292
        }
 
293
    }
 
294
}
 
295
 
 
296
void SvgFontsDialog::on_font_selection_changed(){
 
297
    SPFont* spfont = this->get_selected_spfont();
 
298
    if (!spfont) return;
 
299
 
 
300
    SvgFont* svgfont = this->get_selected_svgfont();
 
301
    first_glyph.update(spfont);
 
302
    second_glyph.update(spfont);
 
303
    kerning_preview.set_svgfont(svgfont);
 
304
    _font_da.set_svgfont(svgfont);
 
305
    _font_da.redraw();
 
306
 
 
307
    double set_width = spfont->horiz_adv_x;
 
308
    setwidth_spin.set_value(set_width);
 
309
 
 
310
    kerning_slider.set_range(0, set_width);
 
311
    kerning_slider.set_draw_value(false);
 
312
    kerning_slider.set_value(0);
 
313
 
 
314
    update_global_settings_tab();
 
315
    populate_glyphs_box();
 
316
    populate_kerning_pairs_box();
 
317
    update_sensitiveness();
 
318
}
 
319
 
 
320
void SvgFontsDialog::on_setwidth_changed(){
 
321
    SPFont* spfont = this->get_selected_spfont();
 
322
    if (spfont){
 
323
        spfont->horiz_adv_x = setwidth_spin.get_value();
 
324
        //TODO: tell cairo that the glyphs cache has to be invalidated
 
325
        //    The current solution is to recreate the whole cairo svgfont.
 
326
        //    This is not a good solution to the issue because big fonts will result in poor performance.
 
327
        update_glyphs();
 
328
    }
 
329
}
 
330
 
 
331
SPGlyphKerning* SvgFontsDialog::get_selected_kerning_pair()
 
332
{
 
333
    Gtk::TreeModel::iterator i = _KerningPairsList.get_selection()->get_selected();
 
334
    if(i)
 
335
        return (*i)[_KerningPairsListColumns.spnode];
 
336
    return NULL;
 
337
}
 
338
 
 
339
SvgFont* SvgFontsDialog::get_selected_svgfont()
 
340
{
 
341
    Gtk::TreeModel::iterator i = _FontsList.get_selection()->get_selected();
 
342
    if(i)
 
343
        return (*i)[_columns.svgfont];
 
344
    return NULL;
 
345
}
 
346
 
 
347
SPFont* SvgFontsDialog::get_selected_spfont()
 
348
{
 
349
    Gtk::TreeModel::iterator i = _FontsList.get_selection()->get_selected();
 
350
    if(i)
 
351
        return (*i)[_columns.spfont];
 
352
    return NULL;
 
353
}
 
354
 
 
355
SPGlyph* SvgFontsDialog::get_selected_glyph()
 
356
{
 
357
    Gtk::TreeModel::iterator i = _GlyphsList.get_selection()->get_selected();
 
358
    if(i)
 
359
        return (*i)[_GlyphsListColumns.glyph_node];
 
360
    return NULL;
 
361
}
 
362
 
 
363
Gtk::VBox* SvgFontsDialog::global_settings_tab(){
 
364
    _familyname_entry = new AttrEntry(this, (gchar*) _("Family Name:"), SP_PROP_FONT_FAMILY);
 
365
 
 
366
    global_vbox.pack_start(*_familyname_entry, false, false);
 
367
/*    global_vbox->add(*AttrCombo((gchar*) _("Style:"), SP_PROP_FONT_STYLE));
 
368
    global_vbox->add(*AttrCombo((gchar*) _("Variant:"), SP_PROP_FONT_VARIANT));
 
369
    global_vbox->add(*AttrCombo((gchar*) _("Weight:"), SP_PROP_FONT_WEIGHT));
 
370
*/
 
371
 
 
372
//Set Width (horiz_adv_x):
 
373
    Gtk::HBox* setwidth_hbox = Gtk::manage(new Gtk::HBox());
 
374
    setwidth_hbox->add(*Gtk::manage(new Gtk::Label(_("Set width:"))));
 
375
    setwidth_hbox->add(setwidth_spin);
 
376
 
 
377
    setwidth_spin.signal_changed().connect(sigc::mem_fun(*this, &SvgFontsDialog::on_setwidth_changed));
 
378
    setwidth_spin.set_range(0, 4096);
 
379
    setwidth_spin.set_increments(10, 0);
 
380
    global_vbox.pack_start(*setwidth_hbox, false, false);
 
381
 
 
382
    return &global_vbox;
 
383
}
 
384
 
 
385
void
 
386
SvgFontsDialog::populate_glyphs_box()
 
387
{
 
388
    if (!_GlyphsListStore) return;
 
389
    _GlyphsListStore->clear();
 
390
 
 
391
    SPFont* spfont = this->get_selected_spfont();
 
392
    _glyphs_observer.set(spfont);
 
393
 
 
394
    for(SPObject* node = spfont->children; node; node=node->next){
 
395
        if (SP_IS_GLYPH(node)){
 
396
            Gtk::TreeModel::Row row = *(_GlyphsListStore->append());
 
397
            row[_GlyphsListColumns.glyph_node] = (SPGlyph*) node;
 
398
            row[_GlyphsListColumns.glyph_name] = ((SPGlyph*) node)->glyph_name;
 
399
            row[_GlyphsListColumns.unicode] = ((SPGlyph*) node)->unicode;
 
400
        }
 
401
    }
 
402
}
 
403
 
 
404
void
 
405
SvgFontsDialog::populate_kerning_pairs_box()
 
406
{
 
407
    if (!_KerningPairsListStore) return;
 
408
    _KerningPairsListStore->clear();
 
409
 
 
410
    SPFont* spfont = this->get_selected_spfont();
 
411
 
 
412
    for(SPObject* node = spfont->children; node; node=node->next){
 
413
        if (SP_IS_HKERN(node)){
 
414
            Gtk::TreeModel::Row row = *(_KerningPairsListStore->append());
 
415
            row[_KerningPairsListColumns.first_glyph] = ((SPGlyphKerning*) node)->u1->attribute_string().c_str();
 
416
            row[_KerningPairsListColumns.second_glyph] = ((SPGlyphKerning*) node)->u2->attribute_string().c_str();
 
417
            row[_KerningPairsListColumns.kerning_value] = ((SPGlyphKerning*) node)->k;
 
418
            row[_KerningPairsListColumns.spnode] = (SPGlyphKerning*) node;
 
419
        }
 
420
    }
 
421
}
 
422
 
 
423
SPGlyph *new_glyph(SPDocument* document, SPFont *font, const int count)
 
424
{
 
425
    g_return_val_if_fail(font != NULL, NULL);
 
426
    Inkscape::XML::Document *xml_doc = sp_document_repr_doc(document);
 
427
 
 
428
    // create a new glyph
 
429
    Inkscape::XML::Node *repr;
 
430
    repr = xml_doc->createElement("svg:glyph");
 
431
 
 
432
    std::ostringstream os;
 
433
    os << _("glyph") << " " << count;
 
434
    repr->setAttribute("glyph-name", os.str().c_str());
 
435
 
 
436
    // Append the new glyph node to the current font
 
437
    SP_OBJECT_REPR(font)->appendChild(repr);
 
438
    Inkscape::GC::release(repr);
 
439
 
 
440
    // get corresponding object
 
441
    SPGlyph *g = SP_GLYPH( document->getObjectByRepr(repr) );
 
442
 
 
443
    g_assert(g != NULL);
 
444
    g_assert(SP_IS_GLYPH(g));
 
445
 
 
446
    return g;
 
447
}
 
448
 
 
449
void SvgFontsDialog::update_glyphs(){
 
450
    SPFont* font = get_selected_spfont();
 
451
    if (!font) return;
 
452
    populate_glyphs_box();
 
453
    populate_kerning_pairs_box();
 
454
    first_glyph.update(font);
 
455
    second_glyph.update(font);
 
456
    get_selected_svgfont()->refresh();
 
457
    _font_da.redraw();
 
458
}
 
459
 
 
460
void SvgFontsDialog::add_glyph(){
 
461
    const int count = _GlyphsListStore->children().size();
 
462
    SPDocument* doc = sp_desktop_document(this->getDesktop());
 
463
    /* SPGlyph* glyph =*/ new_glyph(doc, get_selected_spfont(), count+1);
 
464
 
 
465
    sp_document_done(doc, SP_VERB_DIALOG_SVG_FONTS, _("Add glyph"));
 
466
 
 
467
    update_glyphs();
 
468
}
 
469
 
 
470
void SvgFontsDialog::set_glyph_description_from_selected_path(){
 
471
    SPDesktop* desktop = this->getDesktop();
 
472
    if (!desktop) {
 
473
        g_warning("SvgFontsDialog: No active desktop");
 
474
        return;
 
475
    }
 
476
 
 
477
    Inkscape::MessageStack *msgStack = sp_desktop_message_stack(desktop);
 
478
    SPDocument* doc = sp_desktop_document(desktop);
 
479
    Inkscape::Selection* sel = sp_desktop_selection(desktop);
 
480
    if (sel->isEmpty()){
 
481
        char *msg = _("Select a <b>path</b> to define the curves of a glyph");
 
482
        msgStack->flash(Inkscape::ERROR_MESSAGE, msg);
 
483
        return;
 
484
    }
 
485
 
 
486
    Inkscape::XML::Node* node = (Inkscape::XML::Node*) g_slist_nth_data((GSList *)sel->reprList(), 0);
 
487
    if (!node) return;//TODO: should this be an assert?
 
488
    if (!node->matchAttributeName("d") || !node->attribute("d")){
 
489
        char *msg = _("The selected object does not have a <b>path</b> description.");
 
490
        msgStack->flash(Inkscape::ERROR_MESSAGE, msg);
 
491
        return;
 
492
    } //TODO: //Is there a better way to tell it to to the user?
 
493
 
 
494
    Geom::PathVector pathv = sp_svg_read_pathv(node->attribute("d"));
 
495
 
 
496
    //This matrix flips the glyph vertically
 
497
    Geom::Matrix m(Geom::Coord(1),Geom::Coord(0),Geom::Coord(0),Geom::Coord(-1),Geom::Coord(0),Geom::Coord(0));
 
498
    pathv*=m;
 
499
    //then we offset it
 
500
    pathv+=Geom::Point(Geom::Coord(0),Geom::Coord(get_selected_spfont()->horiz_adv_x));
 
501
 
 
502
    SPGlyph* glyph = get_selected_glyph();
 
503
    if (!glyph){
 
504
        char *msg = _("No glyph selected in the SVGFonts dialog.");
 
505
        msgStack->flash(Inkscape::ERROR_MESSAGE, msg);
 
506
        return;
 
507
    }
 
508
    glyph->repr->setAttribute("d", (char*) sp_svg_write_path (pathv));
 
509
    sp_document_done(doc, SP_VERB_DIALOG_SVG_FONTS, _("Set glyph curves"));
 
510
 
 
511
    update_glyphs();
 
512
}
 
513
 
 
514
void SvgFontsDialog::missing_glyph_description_from_selected_path(){
 
515
    SPDesktop* desktop = this->getDesktop();
 
516
    if (!desktop) {
 
517
        g_warning("SvgFontsDialog: No active desktop");
 
518
        return;
 
519
    }
 
520
 
 
521
    Inkscape::MessageStack *msgStack = sp_desktop_message_stack(desktop);
 
522
    SPDocument* doc = sp_desktop_document(desktop);
 
523
    Inkscape::Selection* sel = sp_desktop_selection(desktop);
 
524
    if (sel->isEmpty()){
 
525
        char *msg = _("Select a <b>path</b> to define the curves of a glyph");
 
526
        msgStack->flash(Inkscape::ERROR_MESSAGE, msg);
 
527
        return;
 
528
    }
 
529
 
 
530
    Inkscape::XML::Node* node = (Inkscape::XML::Node*) g_slist_nth_data((GSList *)sel->reprList(), 0);
 
531
    if (!node) return;//TODO: should this be an assert?
 
532
    if (!node->matchAttributeName("d") || !node->attribute("d")){
 
533
        char *msg = _("The selected object does not have a <b>path</b> description.");
 
534
        msgStack->flash(Inkscape::ERROR_MESSAGE, msg);
 
535
        return;
 
536
    } //TODO: //Is there a better way to tell it to to the user?
 
537
 
 
538
    Geom::PathVector pathv = sp_svg_read_pathv(node->attribute("d"));
 
539
 
 
540
    //This matrix flips the glyph vertically
 
541
    Geom::Matrix m(Geom::Coord(1),Geom::Coord(0),Geom::Coord(0),Geom::Coord(-1),Geom::Coord(0),Geom::Coord(0));
 
542
    pathv*=m;
 
543
    //then we offset it
 
544
//  pathv+=Geom::Point(Geom::Coord(0),Geom::Coord(get_selected_spfont()->horiz_adv_x));
 
545
    pathv+=Geom::Point(Geom::Coord(0),Geom::Coord(1000));//TODO: use here the units-per-em attribute?
 
546
 
 
547
    SPObject* obj;
 
548
    for (obj = get_selected_spfont()->children; obj; obj=obj->next){
 
549
        if (SP_IS_MISSING_GLYPH(obj)){
 
550
            obj->repr->setAttribute("d", (char*) sp_svg_write_path (pathv));
 
551
            sp_document_done(doc, SP_VERB_DIALOG_SVG_FONTS, _("Set glyph curves"));
 
552
        }
 
553
    }
 
554
 
 
555
    update_glyphs();
 
556
}
 
557
 
 
558
void SvgFontsDialog::reset_missing_glyph_description(){
 
559
    SPDesktop* desktop = this->getDesktop();
 
560
    if (!desktop) {
 
561
        g_warning("SvgFontsDialog: No active desktop");
 
562
        return;
 
563
    }
 
564
 
 
565
    SPDocument* doc = sp_desktop_document(desktop);
 
566
    SPObject* obj;
 
567
    for (obj = get_selected_spfont()->children; obj; obj=obj->next){
 
568
        if (SP_IS_MISSING_GLYPH(obj)){
 
569
            obj->repr->setAttribute("d", (char*) "M0,0h1000v1024h-1000z");
 
570
            sp_document_done(doc, SP_VERB_DIALOG_SVG_FONTS, _("Reset missing-glyph"));
 
571
        }
 
572
    }
 
573
 
 
574
    update_glyphs();
 
575
}
 
576
 
 
577
void SvgFontsDialog::glyph_name_edit(const Glib::ustring&, const Glib::ustring& str){
 
578
    Gtk::TreeModel::iterator i = _GlyphsList.get_selection()->get_selected();
 
579
    if (!i) return;
 
580
 
 
581
    SPGlyph* glyph = (*i)[_GlyphsListColumns.glyph_node];
 
582
    glyph->repr->setAttribute("glyph-name", str.c_str());
 
583
 
 
584
    SPDocument* doc = sp_desktop_document(this->getDesktop());
 
585
    sp_document_done(doc, SP_VERB_DIALOG_SVG_FONTS, _("Edit glyph name"));
 
586
 
 
587
    update_glyphs();
 
588
}
 
589
 
 
590
void SvgFontsDialog::glyph_unicode_edit(const Glib::ustring&, const Glib::ustring& str){
 
591
    Gtk::TreeModel::iterator i = _GlyphsList.get_selection()->get_selected();
 
592
    if (!i) return;
 
593
 
 
594
    SPGlyph* glyph = (*i)[_GlyphsListColumns.glyph_node];
 
595
    glyph->repr->setAttribute("unicode", str.c_str());
 
596
 
 
597
    SPDocument* doc = sp_desktop_document(this->getDesktop());
 
598
    sp_document_done(doc, SP_VERB_DIALOG_SVG_FONTS, _("Set glyph unicode"));
 
599
 
 
600
    update_glyphs();
 
601
}
 
602
 
 
603
void SvgFontsDialog::remove_selected_font(){
 
604
    SPFont* font = get_selected_spfont();
 
605
 
 
606
    sp_repr_unparent(font->repr);
 
607
    SPDocument* doc = sp_desktop_document(this->getDesktop());
 
608
    sp_document_done(doc, SP_VERB_DIALOG_SVG_FONTS, _("Remove font"));
 
609
 
 
610
    update_fonts();
 
611
}
 
612
 
 
613
void SvgFontsDialog::remove_selected_glyph(){
 
614
    if(!_GlyphsList.get_selection()) return;
 
615
 
 
616
    Gtk::TreeModel::iterator i = _GlyphsList.get_selection()->get_selected();
 
617
    if(!i) return;
 
618
 
 
619
    SPGlyph* glyph = (*i)[_GlyphsListColumns.glyph_node];
 
620
    sp_repr_unparent(glyph->repr);
 
621
 
 
622
    SPDocument* doc = sp_desktop_document(this->getDesktop());
 
623
    sp_document_done(doc, SP_VERB_DIALOG_SVG_FONTS, _("Remove glyph"));
 
624
 
 
625
    update_glyphs();
 
626
}
 
627
 
 
628
void SvgFontsDialog::remove_selected_kerning_pair(){
 
629
    if(!_KerningPairsList.get_selection()) return;
 
630
 
 
631
    Gtk::TreeModel::iterator i = _KerningPairsList.get_selection()->get_selected();
 
632
    if(!i) return;
 
633
 
 
634
    SPGlyphKerning* pair = (*i)[_KerningPairsListColumns.spnode];
 
635
    sp_repr_unparent(pair->repr);
 
636
 
 
637
    SPDocument* doc = sp_desktop_document(this->getDesktop());
 
638
    sp_document_done(doc, SP_VERB_DIALOG_SVG_FONTS, _("Remove kerning pair"));
 
639
 
 
640
    update_glyphs();
 
641
}
 
642
 
 
643
Gtk::VBox* SvgFontsDialog::glyphs_tab(){
 
644
    _GlyphsList.signal_button_release_event().connect_notify(sigc::mem_fun(*this, &SvgFontsDialog::glyphs_list_button_release));
 
645
    create_glyphs_popup_menu(_GlyphsList, sigc::mem_fun(*this, &SvgFontsDialog::remove_selected_glyph));
 
646
 
 
647
    Gtk::HBox* missing_glyph_hbox = Gtk::manage(new Gtk::HBox());
 
648
    Gtk::Label* missing_glyph_label = Gtk::manage(new Gtk::Label(_("Missing Glyph:")));
 
649
    missing_glyph_hbox->pack_start(*missing_glyph_label, false,false);
 
650
    missing_glyph_hbox->pack_start(missing_glyph_button, false,false);
 
651
    missing_glyph_hbox->pack_start(missing_glyph_reset_button, false,false);
 
652
    missing_glyph_button.set_label(_("From selection..."));
 
653
    missing_glyph_button.signal_clicked().connect(sigc::mem_fun(*this, &SvgFontsDialog::missing_glyph_description_from_selected_path));
 
654
    missing_glyph_reset_button.set_label(_("Reset"));
 
655
    missing_glyph_reset_button.signal_clicked().connect(sigc::mem_fun(*this, &SvgFontsDialog::reset_missing_glyph_description));
 
656
    
 
657
    glyphs_vbox.pack_start(*missing_glyph_hbox, false,false);
 
658
 
 
659
    glyphs_vbox.add(_GlyphsListScroller);
 
660
    _GlyphsListScroller.set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_ALWAYS);
 
661
    _GlyphsListScroller.set_size_request(-1, 290);//It seems that is does not work. Why? I want a box with larger height
 
662
    _GlyphsListScroller.add(_GlyphsList);
 
663
    _GlyphsListStore = Gtk::ListStore::create(_GlyphsListColumns);
 
664
    _GlyphsList.set_model(_GlyphsListStore);
 
665
    _GlyphsList.append_column_editable(_("Glyph name"), _GlyphsListColumns.glyph_name);
 
666
    _GlyphsList.append_column_editable(_("Matching string"), _GlyphsListColumns.unicode);
 
667
 
 
668
    Gtk::HBox* hb = Gtk::manage(new Gtk::HBox());
 
669
    add_glyph_button.set_label(_("Add Glyph"));
 
670
    add_glyph_button.signal_clicked().connect(sigc::mem_fun(*this, &SvgFontsDialog::add_glyph));
 
671
 
 
672
    hb->pack_start(add_glyph_button, false,false);
 
673
    hb->pack_start(glyph_from_path_button, false,false);
 
674
 
 
675
    glyphs_vbox.pack_start(*hb, false, false);
 
676
    glyph_from_path_button.set_label(_("Get curves from selection..."));
 
677
    glyph_from_path_button.signal_clicked().connect(sigc::mem_fun(*this, &SvgFontsDialog::set_glyph_description_from_selected_path));
 
678
 
 
679
    dynamic_cast<Gtk::CellRendererText*>( _GlyphsList.get_column_cell_renderer(0))->signal_edited().connect(
 
680
        sigc::mem_fun(*this, &SvgFontsDialog::glyph_name_edit));
 
681
 
 
682
    dynamic_cast<Gtk::CellRendererText*>( _GlyphsList.get_column_cell_renderer(1))->signal_edited().connect(
 
683
        sigc::mem_fun(*this, &SvgFontsDialog::glyph_unicode_edit));
 
684
 
 
685
    _glyphs_observer.signal_changed().connect(sigc::mem_fun(*this, &SvgFontsDialog::update_glyphs));
 
686
 
 
687
    return &glyphs_vbox;
 
688
}
 
689
 
 
690
void SvgFontsDialog::add_kerning_pair(){
 
691
    if (first_glyph.get_active_text() == "" ||
 
692
        second_glyph.get_active_text() == "") return;
 
693
 
 
694
    //look for this kerning pair on the currently selected font
 
695
    this->kerning_pair = NULL;
 
696
    for(SPObject* node = this->get_selected_spfont()->children; node; node=node->next){
 
697
        //TODO: It is not really correct to get only the first byte of each string.
 
698
        //TODO: We should also support vertical kerning
 
699
        if (SP_IS_HKERN(node) && ((SPGlyphKerning*)node)->u1->contains((gchar) first_glyph.get_active_text().c_str()[0])
 
700
            && ((SPGlyphKerning*)node)->u2->contains((gchar) second_glyph.get_active_text().c_str()[0]) ){
 
701
            this->kerning_pair = (SPGlyphKerning*)node;
 
702
            continue;
 
703
        }
 
704
    }
 
705
 
 
706
    if (this->kerning_pair) return; //We already have this kerning pair
 
707
 
 
708
    SPDocument* document = sp_desktop_document(this->getDesktop());
 
709
    Inkscape::XML::Document *xml_doc = sp_document_repr_doc(document);
 
710
 
 
711
    // create a new hkern node
 
712
    Inkscape::XML::Node *repr;
 
713
    repr = xml_doc->createElement("svg:hkern");
 
714
 
 
715
    repr->setAttribute("u1", first_glyph.get_active_text().c_str());
 
716
    repr->setAttribute("u2", second_glyph.get_active_text().c_str());
 
717
    repr->setAttribute("k", "0");
 
718
 
 
719
    // Append the new hkern node to the current font
 
720
    SP_OBJECT_REPR(get_selected_spfont())->appendChild(repr);
 
721
    Inkscape::GC::release(repr);
 
722
 
 
723
    // get corresponding object
 
724
    this->kerning_pair = SP_HKERN( document->getObjectByRepr(repr) );
 
725
 
 
726
    sp_document_done(document, SP_VERB_DIALOG_SVG_FONTS, _("Add kerning pair"));
 
727
}
 
728
 
 
729
Gtk::VBox* SvgFontsDialog::kerning_tab(){
 
730
    _KerningPairsList.signal_button_release_event().connect_notify(sigc::mem_fun(*this, &SvgFontsDialog::kerning_pairs_list_button_release));
 
731
    create_kerning_pairs_popup_menu(_KerningPairsList, sigc::mem_fun(*this, &SvgFontsDialog::remove_selected_kerning_pair));
 
732
 
 
733
//Kerning Setup:
 
734
    kerning_vbox.add(*Gtk::manage(new Gtk::Label(_("Kerning Setup:"))));
 
735
    Gtk::HBox* kerning_selector = Gtk::manage(new Gtk::HBox());
 
736
    kerning_selector->add(*Gtk::manage(new Gtk::Label(_("1st Glyph:"))));
 
737
    kerning_selector->add(first_glyph);
 
738
    kerning_selector->add(*Gtk::manage(new Gtk::Label(_("2nd Glyph:"))));
 
739
    kerning_selector->add(second_glyph);
 
740
    kerning_selector->add(add_kernpair_button);
 
741
    add_kernpair_button.set_label(_("Add pair"));
 
742
    add_kernpair_button.signal_clicked().connect(sigc::mem_fun(*this, &SvgFontsDialog::add_kerning_pair));
 
743
    _KerningPairsList.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SvgFontsDialog::on_kerning_pair_selection_changed));
 
744
    kerning_slider.signal_value_changed().connect(sigc::mem_fun(*this, &SvgFontsDialog::on_kerning_value_changed));
 
745
 
 
746
    kerning_vbox.pack_start(*kerning_selector, false,false);
 
747
 
 
748
    kerning_vbox.add(_KerningPairsListScroller);
 
749
    _KerningPairsListScroller.set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_ALWAYS);
 
750
    _KerningPairsListScroller.add(_KerningPairsList);
 
751
    _KerningPairsListStore = Gtk::ListStore::create(_KerningPairsListColumns);
 
752
    _KerningPairsList.set_model(_KerningPairsListStore);
 
753
    _KerningPairsList.append_column(_("First Unicode range"), _KerningPairsListColumns.first_glyph);
 
754
    _KerningPairsList.append_column(_("Second Unicode range"), _KerningPairsListColumns.second_glyph);
 
755
//    _KerningPairsList.append_column_numeric_editable(_("Kerning Value"), _KerningPairsListColumns.kerning_value, "%f");
 
756
 
 
757
    kerning_vbox.add((Gtk::Widget&) kerning_preview);
 
758
 
 
759
    Gtk::HBox* kerning_amount_hbox = Gtk::manage(new Gtk::HBox());
 
760
    kerning_vbox.pack_start(*kerning_amount_hbox, false,false);
 
761
    kerning_amount_hbox->add(*Gtk::manage(new Gtk::Label(_("Kerning value:"))));
 
762
    kerning_amount_hbox->add(kerning_slider);
 
763
 
 
764
    kerning_preview.set_size(300 + 20, 150 + 20);
 
765
    _font_da.set_size(150 + 20, 50 + 20);
 
766
 
 
767
    return &kerning_vbox;
 
768
}
 
769
 
 
770
SPFont *new_font(SPDocument *document)
 
771
{
 
772
    g_return_val_if_fail(document != NULL, NULL);
 
773
 
 
774
    SPDefs *defs = (SPDefs *) SP_DOCUMENT_DEFS(document);
 
775
 
 
776
    Inkscape::XML::Document *xml_doc = sp_document_repr_doc(document);
 
777
 
 
778
    // create a new font
 
779
    Inkscape::XML::Node *repr;
 
780
    repr = xml_doc->createElement("svg:font");
 
781
 
 
782
    //By default, set the horizontal advance to 1024 units
 
783
    repr->setAttribute("horiz-adv-x", "1024");
 
784
 
 
785
    // Append the new font node to defs
 
786
    SP_OBJECT_REPR(defs)->appendChild(repr);
 
787
 
 
788
    //create a missing glyph
 
789
    Inkscape::XML::Node *fontface;
 
790
    fontface = xml_doc->createElement("svg:font-face");
 
791
    fontface->setAttribute("units-per-em", "1024");
 
792
    repr->appendChild(fontface);
 
793
 
 
794
    //create a missing glyph
 
795
    Inkscape::XML::Node *mg;
 
796
    mg = xml_doc->createElement("svg:missing-glyph");
 
797
    mg->setAttribute("d", "M0,0h1000v1024h-1000z");
 
798
    repr->appendChild(mg);
 
799
 
 
800
    // get corresponding object
 
801
    SPFont *f = SP_FONT( document->getObjectByRepr(repr) );
 
802
 
 
803
    g_assert(f != NULL);
 
804
    g_assert(SP_IS_FONT(f));
 
805
    Inkscape::GC::release(mg);
 
806
    Inkscape::GC::release(repr);
 
807
    return f;
 
808
}
 
809
 
 
810
void set_font_family(SPFont* font, char* str){
 
811
    if (!font) return;
 
812
    SPObject* obj;
 
813
    for (obj=font->children; obj; obj=obj->next){
 
814
        if (SP_IS_FONTFACE(obj)){
 
815
            obj->repr->setAttribute("font-family", str);
 
816
        }
 
817
    }
 
818
 
 
819
    sp_document_done(font->document, SP_VERB_DIALOG_SVG_FONTS, _("Set font family"));
 
820
}
 
821
 
 
822
void SvgFontsDialog::add_font(){
 
823
    SPDocument* doc = sp_desktop_document(this->getDesktop());
 
824
    SPFont* font = new_font(doc);
 
825
 
 
826
    const int count = _model->children().size();
 
827
    std::ostringstream os, os2;
 
828
    os << _("font") << " " << count;
 
829
    font->setLabel(os.str().c_str());
 
830
 
 
831
    os2 << "SVGFont " << count;
 
832
    SPObject* obj;
 
833
    for (obj=font->children; obj; obj=obj->next){
 
834
        if (SP_IS_FONTFACE(obj)){
 
835
            obj->repr->setAttribute("font-family", os2.str().c_str());
 
836
        }
 
837
    }
 
838
 
 
839
    update_fonts();
 
840
//    select_font(font);
 
841
 
 
842
    sp_document_done(doc, SP_VERB_DIALOG_SVG_FONTS, _("Add font"));
 
843
}
 
844
 
 
845
SvgFontsDialog::SvgFontsDialog()
 
846
 : UI::Widget::Panel("", "/dialogs/svgfonts", SP_VERB_DIALOG_SVG_FONTS), _add(Gtk::Stock::NEW)
 
847
{
 
848
    _add.signal_clicked().connect(sigc::mem_fun(*this, &SvgFontsDialog::add_font));
 
849
 
 
850
    Gtk::HBox* hbox = Gtk::manage(new Gtk::HBox());
 
851
    Gtk::VBox* vbox = Gtk::manage(new Gtk::VBox());
 
852
 
 
853
    vbox->pack_start(_FontsList);
 
854
    vbox->pack_start(_add, false, false);
 
855
    hbox->add(*vbox);
 
856
    hbox->add(_font_settings);
 
857
    _getContents()->add(*hbox);
 
858
 
 
859
//List of SVGFonts declared in a document:
 
860
    _model = Gtk::ListStore::create(_columns);
 
861
    _FontsList.set_model(_model);
 
862
    _FontsList.append_column_editable(_("_Font"), _columns.label);
 
863
    _FontsList.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SvgFontsDialog::on_font_selection_changed));
 
864
 
 
865
    this->update_fonts();
 
866
 
 
867
    Gtk::Notebook *tabs = Gtk::manage(new Gtk::Notebook());
 
868
    tabs->set_scrollable();
 
869
 
 
870
    tabs->append_page(*global_settings_tab(), _("_Global Settings"), true);
 
871
    tabs->append_page(*glyphs_tab(), _("_Glyphs"), true);
 
872
    tabs->append_page(*kerning_tab(), _("_Kerning"), true);
 
873
 
 
874
    _font_settings.add(*tabs);
 
875
 
 
876
//Text Preview:
 
877
    _preview_entry.signal_changed().connect(sigc::mem_fun(*this, &SvgFontsDialog::on_preview_text_changed));
 
878
    _getContents()->add((Gtk::Widget&) _font_da);
 
879
    _preview_entry.set_text(_("Sample Text"));
 
880
    _font_da.set_text(_("Sample Text"));
 
881
 
 
882
    Gtk::HBox* preview_entry_hbox = Gtk::manage(new Gtk::HBox());
 
883
    _getContents()->add(*preview_entry_hbox);
 
884
    preview_entry_hbox->add(*Gtk::manage(new Gtk::Label(_("Preview Text:"))));
 
885
    preview_entry_hbox->add(_preview_entry);
 
886
 
 
887
    _FontsList.signal_button_release_event().connect_notify(sigc::mem_fun(*this, &SvgFontsDialog::fonts_list_button_release));
 
888
    create_fonts_popup_menu(_FontsList, sigc::mem_fun(*this, &SvgFontsDialog::remove_selected_font));
 
889
 
 
890
    _defs_observer.set(SP_DOCUMENT_DEFS(sp_desktop_document(this->getDesktop())));
 
891
    _defs_observer.signal_changed().connect(sigc::mem_fun(*this, &SvgFontsDialog::update_fonts));
 
892
 
 
893
    _getContents()->show_all();
 
894
}
 
895
 
 
896
SvgFontsDialog::~SvgFontsDialog(){}
 
897
 
 
898
} // namespace Dialog
 
899
} // namespace UI
 
900
} // namespace Inkscape
 
901
 
 
902
#endif //#ifdef ENABLE_SVG_FONTS
 
903
 
 
904
/*
 
905
  Local Variables:
 
906
  mode:c++
 
907
  c-file-style:"stroustrup"
 
908
  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
 
909
  indent-tabs-mode:nil
 
910
  fill-column:99
 
911
  End:
 
912
*/
 
913
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :