summaryrefslogtreecommitdiffstats
path: root/src/libnrtype/font-lister.h
blob: 5d73119d4de49c08300b514e7592daf3ea9beb5c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
// SPDX-License-Identifier: GPL-2.0-or-later
#ifndef FONT_LISTER_H
#define FONT_LISTER_H

/*
 * Font selection widgets
 *
 * Authors:
 *   Chris Lahey <clahey@ximian.com>
 *   Lauris Kaplinski <lauris@kaplinski.com>
 *   Tavmjong Bah <tavmjong@free.fr>
 *
 * Copyright (C) 1999-2001 Ximian, Inc.
 * Copyright (C) 2002 Lauris Kaplinski
 * Copyright (C) 2013 Tavmjong Bah
 *
 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
 */

#include <map>
#include <set>

#include <glibmm/ustring.h>
#include <glibmm/stringutils.h> // For strescape()

#include <gtkmm/liststore.h>
#include <gtkmm/treemodelcolumn.h>
#include <gtkmm/treepath.h>

class SPObject;
class SPDocument;
class SPCSSAttr;
class SPStyle;

namespace Gtk {
class CellRenderer;
}

namespace Inkscape {

/**
 *  This class enumerates fonts using libnrtype into reusable data stores and
 *  allows for random access to the font-family list and the font-style list.
 *  Setting the font-family updates the font-style list. "Style" in this case
 *  refers to everything but family and size (e.g. italic/oblique, weight).
 *
 *  This class handles font-family lists and fonts that are not on the system,
 *  where there is not an entry in the fontInstanceMap.
 *
 *  This class uses the idea of "font_spec". This is a plain text string as used by
 *  Pango. It is similar to the CSS font shorthand except that font-family comes
 *  first and in this class the font-size is not used.
 *
 *  This class uses the FontFactory class to get a list of system fonts
 *  and to find best matches via Pango. The Pango interface is only setup
 *  to deal with fonts that are on the system so care must be taken. For
 *  example, best matches should only be done with the first font-family
 *  in a font-family list. If the first font-family is not on the system
 *  then a generic font-family should be used (sans-serif -> Sans).
 *
 *  This class is used by the UI interface (text-toolbar, font-select, etc.).
 *  Those items can change the selected font family and style here. When that
 *  happens. this class emits a signal for those items to update their displayed
 *  values.
 *
 *  This class is a singleton (one instance per Inkscape session). Since fonts
 *  used in a document are added to the list, there really should be one
 *  instance per document.
 *
 *  "Font" includes family and style. It should not be used when one
 *  means font-family.
 */

class FontLister {
public:
    enum Exceptions {
        FAMILY_NOT_FOUND,
        STYLE_NOT_FOUND
    };

    virtual ~FontLister();

    /**
     * GtkTreeModelColumnRecord for the font-family list Gtk::ListStore
     */
    struct FontListClass : public Gtk::TreeModelColumnRecord {
        /**
         * Column containing the family name
         */
        Gtk::TreeModelColumn<Glib::ustring> family;

        /**
         * Column containing the styles for each family name.
         */
        Gtk::TreeModelColumn<GList *> styles;

        /**
         * Column containing flag if font is on system
         */
        Gtk::TreeModelColumn<bool> onSystem;
        
        /**
         * Not actually a column.
         * Necessary for quick initialization of FontLister,
         * we initially store the pango family and if the
         * font style is actually used we'll cache it in
         * %styles.
         */
        Gtk::TreeModelColumn<PangoFontFamily *> pango_family;
        
        FontListClass()
        {
            add(family);
            add(styles);
            add(onSystem);
            add(pango_family);
        }
    };

    FontListClass FontList;

    struct FontStyleListClass : public Gtk::TreeModelColumnRecord {
        /**
         * Column containing the styles as Font designer used.
         */
        Gtk::TreeModelColumn<Glib::ustring> displayStyle;

        /**
         * Column containing the styles in CSS/Pango format.
         */
        Gtk::TreeModelColumn<Glib::ustring> cssStyle;

        FontStyleListClass()
        {
            add(cssStyle);
            add(displayStyle);
        }
    };

    FontStyleListClass FontStyleList;

    /** 
     * @return the ListStore with the family names
     *
     * The return is const and the function is declared as const.
     * The ListStore is ready to be used after class instantiation
     * and should not be modified.
     */
    const Glib::RefPtr<Gtk::ListStore> get_font_list() const;

    /**
     * @return the ListStore with the styles
     */
    const Glib::RefPtr<Gtk::ListStore> get_style_list() const;

    /** 
     * Inserts a font family or font-fallback list (for use when not
     *  already in document or on system).
     */
    void insert_font_family(Glib::ustring new_family);

    /**
     * Updates font list to include fonts in document.
     */
    void update_font_list(SPDocument *document);

public:
    static Inkscape::FontLister *get_instance();

    /**
     * Takes a hand written font spec and returns a Pango generated one in
     *  standard form.
     */
    Glib::ustring canonize_fontspec(Glib::ustring fontspec);

    /**
     * Find closest system font to given font.
     */
    Glib::ustring system_fontspec(Glib::ustring fontspec);

    /**
     * Gets font-family and style from fontspec.
     *  font-family and style returned.
     */
    std::pair<Glib::ustring, Glib::ustring> ui_from_fontspec(Glib::ustring fontspec);

    /**
     * Sets font-family and style after a selection change.
     *  New font-family and style returned.
     */
    std::pair<Glib::ustring, Glib::ustring> selection_update();

    /** 
     * Sets current_fontspec, etc. If check is false, won't
     *  try to find best style match (assumes style in fontspec
     *  valid for given font-family).
     */
    void set_fontspec(Glib::ustring fontspec, bool check = true);

    Glib::ustring get_fontspec() { return (canonize_fontspec(current_family + ", " + current_style)); }

    /**
     * Changes font-family, updating style list and attempting to find
     *  closest style to current_style style (if check_style is true).
     *  New font-family and style returned.
     *  Does NOT update current_family and current_style.
     *  (For potential use in font-selector which doesn't update until
     *  "Apply" button clicked.)
     */
    std::pair<Glib::ustring, Glib::ustring> new_font_family(Glib::ustring family, bool check_style = true);

    /** 
     * Sets font-family, updating style list and attempting
     *  to find closest style to old current_style.
     *  New font-family and style returned.
     *  Updates current_family and current_style.
     *  Calls new_font_family().
     *  (For use in text-toolbar where update is immediate.)
     */
    std::pair<Glib::ustring, Glib::ustring> set_font_family(Glib::ustring family, bool check_style = true,
                                                            bool emit = true);

    /**
     * Sets font-family from row in list store.
     *  The row can be used to determine if we are in the
     *  document or system part of the font-family list.
     *  This is needed to handle scrolling through the
     *  font-family list correctly.
     *  Calls set_font_family().
     */
    std::pair<Glib::ustring, Glib::ustring> set_font_family(int row, bool check_style = true, bool emit = true);

    Glib::ustring get_font_family()
    {
        return current_family;
    }

    int get_font_family_row()
    {
        return current_family_row;
    }

    /**
     * Sets style. Does not validate style for family.
     */
    void set_font_style(Glib::ustring style, bool emit = true);

    Glib::ustring get_font_style()
    {
        return current_style;
    }

    Glib::ustring fontspec_from_style(SPStyle *style);

    /**
     * Fill css using given fontspec (doesn't need to be member function).
     */
    void fill_css(SPCSSAttr *css, Glib::ustring fontspec = "");

    Gtk::TreeModel::Row get_row_for_font() { return get_row_for_font (current_family); }

    Gtk::TreeModel::Row get_row_for_font(Glib::ustring family);

    Gtk::TreePath get_path_for_font(Glib::ustring family);

    bool is_path_for_font(Gtk::TreePath path, Glib::ustring family);

    Gtk::TreeModel::Row get_row_for_style() { return get_row_for_style (current_style); }

    Gtk::TreeModel::Row get_row_for_style(Glib::ustring style);

    Gtk::TreePath get_path_for_style(Glib::ustring style);

    std::pair<Gtk::TreePath, Gtk::TreePath> get_paths(Glib::ustring family, Glib::ustring style);

    /**
     * Return best style match for new font given style for old font.
     */
    Glib::ustring get_best_style_match(Glib::ustring family, Glib::ustring style);

    /**
     * Ensures the style list for a particular family has been created.
     */
    void ensureRowStyles(Glib::RefPtr<Gtk::TreeModel> model, Gtk::TreeModel::iterator const iter);

    /**
     * Get markup for font-family.
     */
    Glib::ustring get_font_family_markup(Gtk::TreeIter const &iter);

    /**
     * Let users of FontLister know to update GUI.
     * This is to allow synchronization of changes across multiple widgets.
     * Handlers should block signals.
     * Input is fontspec to set.
     */
    sigc::connection connectUpdate(sigc::slot<void> slot) {
        return update_signal.connect(slot);
    }

    bool blocked() { return block; }

private:
    FontLister();

    void update_font_data_recursive(SPObject& r, std::map<Glib::ustring, std::set<Glib::ustring>> &font_data);

	void font_family_row_update(int start=0);

    Glib::RefPtr<Gtk::ListStore> font_list_store;
    Glib::RefPtr<Gtk::ListStore> style_list_store;

    /**
     * Info for currently selected font (what is shown in the UI).
     *  May include font-family lists and fonts not on system.
     */
    int current_family_row;
    Glib::ustring current_family;
    Glib::ustring current_style;

    /**
     * If a font-family is not on system, this list of styles is used.
     */
    GList *default_styles;

    bool block;
    void emit_update();
    sigc::signal<void> update_signal;
};

} // namespace Inkscape

// Helper functions
bool font_lister_separator_func (const Glib::RefPtr<Gtk::TreeModel>& model,
                                 const Gtk::TreeModel::iterator& iter);

gboolean font_lister_separator_func2(GtkTreeModel *model,
                                    GtkTreeIter *iter,
                                    gpointer /*data*/);

void font_lister_cell_data_func (Gtk::CellRenderer *renderer, Gtk::TreeIter const &iter);

void font_lister_cell_data_func_markup (Gtk::CellRenderer *renderer, Gtk::TreeIter const &iter);

void font_lister_cell_data_func2(GtkCellLayout * /*cell_layout*/,
                                GtkCellRenderer *cell,
                                GtkTreeModel *model,
                                GtkTreeIter *iter,
                                gpointer /*data*/);

void font_lister_style_cell_data_func (Gtk::CellRenderer *renderer, Gtk::TreeIter const &iter);

#endif

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