2
* @brief SVG Fonts dialog - implementation
5
* Felipe C. da S. Sanches <felipe.sanches@gmail.com>
7
* Copyright (C) 2008 Authors
8
* Released under GNU GPLv2 (or later). Read the file 'COPYING' for more information.
15
#ifdef ENABLE_SVG_FONTS
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"
25
#include "svg-fonts-dialog.h"
29
SvgFontDrawingArea::SvgFontDrawingArea(){
34
void SvgFontDrawingArea::set_svgfont(SvgFont* svgfont){
35
this->svgfont = svgfont;
38
void SvgFontDrawingArea::set_text(Glib::ustring text){
43
void SvgFontDrawingArea::set_size(int x, int y){
46
((Gtk::Widget*) this)->set_size_request(x, y);
49
void SvgFontDrawingArea::redraw(){
50
((Gtk::Widget*) this)->queue_draw();
53
bool SvgFontDrawingArea::on_expose_event (GdkEventExpose */*event*/){
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);
60
cr->show_text (this->text.c_str());
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());
77
entry->signal_changed().connect(sigc::mem_fun(*this, &SvgFontsDialog::on_attr_changed));
82
SvgFontsDialog::AttrEntry::AttrEntry(SvgFontsDialog* d, gchar* lbl, const SPAttributeEnum attr){
85
this->add(* Gtk::manage(new Gtk::Label(lbl)) );
89
entry.signal_changed().connect(sigc::mem_fun(*this, &SvgFontsDialog::AttrEntry::on_attr_changed));
92
void SvgFontsDialog::AttrEntry::set_text(char* t){
97
void SvgFontsDialog::AttrEntry::on_attr_changed(){
100
for(SPObject* node = this->dialog->get_selected_spfont()->children; node; node=node->next){
102
case SP_PROP_FONT_FAMILY:
103
if (SP_IS_FONTFACE(node)){
113
const gchar* name = (const gchar*)sp_attribute_name(this->attr);
115
SP_OBJECT_REPR(o)->setAttribute((const gchar*) name, this->entry.get_text().c_str());
116
o->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
118
Glib::ustring undokey = "svgfonts:";
120
sp_document_maybe_done(o->document, undokey.c_str(), SP_VERB_DIALOG_SVG_FONTS,
121
_("Set SVG Font attribute"));
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()) );
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()) );
143
/*** SvgFontsDialog ***/
145
GlyphComboBox::GlyphComboBox(){
148
void GlyphComboBox::update(SPFont* spfont){
150
//TODO: figure out why do we need to append_text("") before clearing items properly...
152
this->append_text(""); //Gtk is refusing to clear the combobox when I comment out this line
155
for(SPObject* node = spfont->children; node; node=node->next){
156
if (SP_IS_GLYPH(node)){
157
this->append_text(((SPGlyph*)node)->unicode);
162
void SvgFontsDialog::on_kerning_value_changed(){
163
if (!this->kerning_pair) return;
164
SPDocument* document = sp_desktop_document(this->getDesktop());
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();
170
undokey += this->kerning_pair->u2->attribute_string();
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"));
176
//populate_kerning_pairs_box();
177
kerning_preview.redraw();
181
void SvgFontsDialog::glyphs_list_button_release(GdkEventButton* event)
183
if((event->type == GDK_BUTTON_RELEASE) && (event->button == 3)) {
184
_GlyphsContextMenu.popup(event->button, event->time);
188
void SvgFontsDialog::kerning_pairs_list_button_release(GdkEventButton* event)
190
if((event->type == GDK_BUTTON_RELEASE) && (event->button == 3)) {
191
_KerningPairsContextMenu.popup(event->button, event->time);
195
void SvgFontsDialog::fonts_list_button_release(GdkEventButton* event)
197
if((event->type == GDK_BUTTON_RELEASE) && (event->button == 3)) {
198
_FontsContextMenu.popup(event->button, event->time);
202
void SvgFontsDialog::create_glyphs_popup_menu(Gtk::Widget& parent, sigc::slot<void> rem)
204
Gtk::MenuItem* mi = Gtk::manage(new Gtk::ImageMenuItem(Gtk::Stock::REMOVE));
205
_GlyphsContextMenu.append(*mi);
206
mi->signal_activate().connect(rem);
208
_GlyphsContextMenu.accelerate(parent);
211
void SvgFontsDialog::create_kerning_pairs_popup_menu(Gtk::Widget& parent, sigc::slot<void> rem)
213
Gtk::MenuItem* mi = Gtk::manage(new Gtk::ImageMenuItem(Gtk::Stock::REMOVE));
214
_KerningPairsContextMenu.append(*mi);
215
mi->signal_activate().connect(rem);
217
_KerningPairsContextMenu.accelerate(parent);
220
void SvgFontsDialog::create_fonts_popup_menu(Gtk::Widget& parent, sigc::slot<void> rem)
222
Gtk::MenuItem* mi = Gtk::manage(new Gtk::ImageMenuItem(Gtk::Stock::REMOVE));
223
_FontsContextMenu.append(*mi);
224
mi->signal_activate().connect(rem);
226
_FontsContextMenu.accelerate(parent);
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);
235
global_vbox.set_sensitive(false);
236
glyphs_vbox.set_sensitive(false);
237
kerning_vbox.set_sensitive(false);
241
/* Add all fonts in the document to the combobox. */
242
void SvgFontsDialog::update_fonts()
244
SPDesktop* desktop = this->getDesktop();
245
SPDocument* document = sp_desktop_document(desktop);
246
const GSList* fonts = sp_document_get_resource_list(document, "font");
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");
259
update_sensitiveness();
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());
267
void SvgFontsDialog::on_kerning_pair_selection_changed(){
268
SPGlyphKerning* kern = get_selected_kerning_pair();
270
kerning_preview.set_text("");
274
str += kern->u1->sample_glyph();
275
str += kern->u2->sample_glyph();
277
kerning_preview.set_text(str);
278
this->kerning_pair = kern;
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);
284
void SvgFontsDialog::update_global_settings_tab(){
285
SPFont* font = get_selected_spfont();
289
for (obj=font->children; obj; obj=obj->next){
290
if (SP_IS_FONTFACE(obj)){
291
_familyname_entry->set_text(((SPFontFace*) obj)->font_family);
296
void SvgFontsDialog::on_font_selection_changed(){
297
SPFont* spfont = this->get_selected_spfont();
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);
307
double set_width = spfont->horiz_adv_x;
308
setwidth_spin.set_value(set_width);
310
kerning_slider.set_range(0, set_width);
311
kerning_slider.set_draw_value(false);
312
kerning_slider.set_value(0);
314
update_global_settings_tab();
315
populate_glyphs_box();
316
populate_kerning_pairs_box();
317
update_sensitiveness();
320
void SvgFontsDialog::on_setwidth_changed(){
321
SPFont* spfont = this->get_selected_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.
331
SPGlyphKerning* SvgFontsDialog::get_selected_kerning_pair()
333
Gtk::TreeModel::iterator i = _KerningPairsList.get_selection()->get_selected();
335
return (*i)[_KerningPairsListColumns.spnode];
339
SvgFont* SvgFontsDialog::get_selected_svgfont()
341
Gtk::TreeModel::iterator i = _FontsList.get_selection()->get_selected();
343
return (*i)[_columns.svgfont];
347
SPFont* SvgFontsDialog::get_selected_spfont()
349
Gtk::TreeModel::iterator i = _FontsList.get_selection()->get_selected();
351
return (*i)[_columns.spfont];
355
SPGlyph* SvgFontsDialog::get_selected_glyph()
357
Gtk::TreeModel::iterator i = _GlyphsList.get_selection()->get_selected();
359
return (*i)[_GlyphsListColumns.glyph_node];
363
Gtk::VBox* SvgFontsDialog::global_settings_tab(){
364
_familyname_entry = new AttrEntry(this, (gchar*) _("Family Name:"), SP_PROP_FONT_FAMILY);
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));
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);
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);
386
SvgFontsDialog::populate_glyphs_box()
388
if (!_GlyphsListStore) return;
389
_GlyphsListStore->clear();
391
SPFont* spfont = this->get_selected_spfont();
392
_glyphs_observer.set(spfont);
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;
405
SvgFontsDialog::populate_kerning_pairs_box()
407
if (!_KerningPairsListStore) return;
408
_KerningPairsListStore->clear();
410
SPFont* spfont = this->get_selected_spfont();
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;
423
SPGlyph *new_glyph(SPDocument* document, SPFont *font, const int count)
425
g_return_val_if_fail(font != NULL, NULL);
426
Inkscape::XML::Document *xml_doc = sp_document_repr_doc(document);
428
// create a new glyph
429
Inkscape::XML::Node *repr;
430
repr = xml_doc->createElement("svg:glyph");
432
std::ostringstream os;
433
os << _("glyph") << " " << count;
434
repr->setAttribute("glyph-name", os.str().c_str());
436
// Append the new glyph node to the current font
437
SP_OBJECT_REPR(font)->appendChild(repr);
438
Inkscape::GC::release(repr);
440
// get corresponding object
441
SPGlyph *g = SP_GLYPH( document->getObjectByRepr(repr) );
444
g_assert(SP_IS_GLYPH(g));
449
void SvgFontsDialog::update_glyphs(){
450
SPFont* font = get_selected_spfont();
452
populate_glyphs_box();
453
populate_kerning_pairs_box();
454
first_glyph.update(font);
455
second_glyph.update(font);
456
get_selected_svgfont()->refresh();
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);
465
sp_document_done(doc, SP_VERB_DIALOG_SVG_FONTS, _("Add glyph"));
470
void SvgFontsDialog::set_glyph_description_from_selected_path(){
471
SPDesktop* desktop = this->getDesktop();
473
g_warning("SvgFontsDialog: No active desktop");
477
Inkscape::MessageStack *msgStack = sp_desktop_message_stack(desktop);
478
SPDocument* doc = sp_desktop_document(desktop);
479
Inkscape::Selection* sel = sp_desktop_selection(desktop);
481
char *msg = _("Select a <b>path</b> to define the curves of a glyph");
482
msgStack->flash(Inkscape::ERROR_MESSAGE, msg);
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);
492
} //TODO: //Is there a better way to tell it to to the user?
494
Geom::PathVector pathv = sp_svg_read_pathv(node->attribute("d"));
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));
500
pathv+=Geom::Point(Geom::Coord(0),Geom::Coord(get_selected_spfont()->horiz_adv_x));
502
SPGlyph* glyph = get_selected_glyph();
504
char *msg = _("No glyph selected in the SVGFonts dialog.");
505
msgStack->flash(Inkscape::ERROR_MESSAGE, msg);
508
glyph->repr->setAttribute("d", (char*) sp_svg_write_path (pathv));
509
sp_document_done(doc, SP_VERB_DIALOG_SVG_FONTS, _("Set glyph curves"));
514
void SvgFontsDialog::missing_glyph_description_from_selected_path(){
515
SPDesktop* desktop = this->getDesktop();
517
g_warning("SvgFontsDialog: No active desktop");
521
Inkscape::MessageStack *msgStack = sp_desktop_message_stack(desktop);
522
SPDocument* doc = sp_desktop_document(desktop);
523
Inkscape::Selection* sel = sp_desktop_selection(desktop);
525
char *msg = _("Select a <b>path</b> to define the curves of a glyph");
526
msgStack->flash(Inkscape::ERROR_MESSAGE, msg);
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);
536
} //TODO: //Is there a better way to tell it to to the user?
538
Geom::PathVector pathv = sp_svg_read_pathv(node->attribute("d"));
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));
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?
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"));
558
void SvgFontsDialog::reset_missing_glyph_description(){
559
SPDesktop* desktop = this->getDesktop();
561
g_warning("SvgFontsDialog: No active desktop");
565
SPDocument* doc = sp_desktop_document(desktop);
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"));
577
void SvgFontsDialog::glyph_name_edit(const Glib::ustring&, const Glib::ustring& str){
578
Gtk::TreeModel::iterator i = _GlyphsList.get_selection()->get_selected();
581
SPGlyph* glyph = (*i)[_GlyphsListColumns.glyph_node];
582
glyph->repr->setAttribute("glyph-name", str.c_str());
584
SPDocument* doc = sp_desktop_document(this->getDesktop());
585
sp_document_done(doc, SP_VERB_DIALOG_SVG_FONTS, _("Edit glyph name"));
590
void SvgFontsDialog::glyph_unicode_edit(const Glib::ustring&, const Glib::ustring& str){
591
Gtk::TreeModel::iterator i = _GlyphsList.get_selection()->get_selected();
594
SPGlyph* glyph = (*i)[_GlyphsListColumns.glyph_node];
595
glyph->repr->setAttribute("unicode", str.c_str());
597
SPDocument* doc = sp_desktop_document(this->getDesktop());
598
sp_document_done(doc, SP_VERB_DIALOG_SVG_FONTS, _("Set glyph unicode"));
603
void SvgFontsDialog::remove_selected_font(){
604
SPFont* font = get_selected_spfont();
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"));
613
void SvgFontsDialog::remove_selected_glyph(){
614
if(!_GlyphsList.get_selection()) return;
616
Gtk::TreeModel::iterator i = _GlyphsList.get_selection()->get_selected();
619
SPGlyph* glyph = (*i)[_GlyphsListColumns.glyph_node];
620
sp_repr_unparent(glyph->repr);
622
SPDocument* doc = sp_desktop_document(this->getDesktop());
623
sp_document_done(doc, SP_VERB_DIALOG_SVG_FONTS, _("Remove glyph"));
628
void SvgFontsDialog::remove_selected_kerning_pair(){
629
if(!_KerningPairsList.get_selection()) return;
631
Gtk::TreeModel::iterator i = _KerningPairsList.get_selection()->get_selected();
634
SPGlyphKerning* pair = (*i)[_KerningPairsListColumns.spnode];
635
sp_repr_unparent(pair->repr);
637
SPDocument* doc = sp_desktop_document(this->getDesktop());
638
sp_document_done(doc, SP_VERB_DIALOG_SVG_FONTS, _("Remove kerning pair"));
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));
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));
657
glyphs_vbox.pack_start(*missing_glyph_hbox, false,false);
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);
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));
672
hb->pack_start(add_glyph_button, false,false);
673
hb->pack_start(glyph_from_path_button, false,false);
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));
679
dynamic_cast<Gtk::CellRendererText*>( _GlyphsList.get_column_cell_renderer(0))->signal_edited().connect(
680
sigc::mem_fun(*this, &SvgFontsDialog::glyph_name_edit));
682
dynamic_cast<Gtk::CellRendererText*>( _GlyphsList.get_column_cell_renderer(1))->signal_edited().connect(
683
sigc::mem_fun(*this, &SvgFontsDialog::glyph_unicode_edit));
685
_glyphs_observer.signal_changed().connect(sigc::mem_fun(*this, &SvgFontsDialog::update_glyphs));
690
void SvgFontsDialog::add_kerning_pair(){
691
if (first_glyph.get_active_text() == "" ||
692
second_glyph.get_active_text() == "") return;
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;
706
if (this->kerning_pair) return; //We already have this kerning pair
708
SPDocument* document = sp_desktop_document(this->getDesktop());
709
Inkscape::XML::Document *xml_doc = sp_document_repr_doc(document);
711
// create a new hkern node
712
Inkscape::XML::Node *repr;
713
repr = xml_doc->createElement("svg:hkern");
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");
719
// Append the new hkern node to the current font
720
SP_OBJECT_REPR(get_selected_spfont())->appendChild(repr);
721
Inkscape::GC::release(repr);
723
// get corresponding object
724
this->kerning_pair = SP_HKERN( document->getObjectByRepr(repr) );
726
sp_document_done(document, SP_VERB_DIALOG_SVG_FONTS, _("Add kerning pair"));
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));
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));
746
kerning_vbox.pack_start(*kerning_selector, false,false);
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");
757
kerning_vbox.add((Gtk::Widget&) kerning_preview);
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);
764
kerning_preview.set_size(300 + 20, 150 + 20);
765
_font_da.set_size(150 + 20, 50 + 20);
767
return &kerning_vbox;
770
SPFont *new_font(SPDocument *document)
772
g_return_val_if_fail(document != NULL, NULL);
774
SPDefs *defs = (SPDefs *) SP_DOCUMENT_DEFS(document);
776
Inkscape::XML::Document *xml_doc = sp_document_repr_doc(document);
779
Inkscape::XML::Node *repr;
780
repr = xml_doc->createElement("svg:font");
782
//By default, set the horizontal advance to 1024 units
783
repr->setAttribute("horiz-adv-x", "1024");
785
// Append the new font node to defs
786
SP_OBJECT_REPR(defs)->appendChild(repr);
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);
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);
800
// get corresponding object
801
SPFont *f = SP_FONT( document->getObjectByRepr(repr) );
804
g_assert(SP_IS_FONT(f));
805
Inkscape::GC::release(mg);
806
Inkscape::GC::release(repr);
810
void set_font_family(SPFont* font, char* str){
813
for (obj=font->children; obj; obj=obj->next){
814
if (SP_IS_FONTFACE(obj)){
815
obj->repr->setAttribute("font-family", str);
819
sp_document_done(font->document, SP_VERB_DIALOG_SVG_FONTS, _("Set font family"));
822
void SvgFontsDialog::add_font(){
823
SPDocument* doc = sp_desktop_document(this->getDesktop());
824
SPFont* font = new_font(doc);
826
const int count = _model->children().size();
827
std::ostringstream os, os2;
828
os << _("font") << " " << count;
829
font->setLabel(os.str().c_str());
831
os2 << "SVGFont " << count;
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());
840
// select_font(font);
842
sp_document_done(doc, SP_VERB_DIALOG_SVG_FONTS, _("Add font"));
845
SvgFontsDialog::SvgFontsDialog()
846
: UI::Widget::Panel("", "/dialogs/svgfonts", SP_VERB_DIALOG_SVG_FONTS), _add(Gtk::Stock::NEW)
848
_add.signal_clicked().connect(sigc::mem_fun(*this, &SvgFontsDialog::add_font));
850
Gtk::HBox* hbox = Gtk::manage(new Gtk::HBox());
851
Gtk::VBox* vbox = Gtk::manage(new Gtk::VBox());
853
vbox->pack_start(_FontsList);
854
vbox->pack_start(_add, false, false);
856
hbox->add(_font_settings);
857
_getContents()->add(*hbox);
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));
865
this->update_fonts();
867
Gtk::Notebook *tabs = Gtk::manage(new Gtk::Notebook());
868
tabs->set_scrollable();
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);
874
_font_settings.add(*tabs);
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"));
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);
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));
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));
893
_getContents()->show_all();
896
SvgFontsDialog::~SvgFontsDialog(){}
898
} // namespace Dialog
900
} // namespace Inkscape
902
#endif //#ifdef ENABLE_SVG_FONTS
907
c-file-style:"stroustrup"
908
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
913
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :