summaryrefslogtreecommitdiffstats
path: root/src/ui/dialog/attrdialog.h
blob: e85d42d7229c892353e3522b4a616de349d67aa2 (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
// SPDX-License-Identifier: GPL-2.0-or-later
/** @file
 * @brief A dialog for XML attributes based on Gtk TreeView
 */
/* Authors:
 *   Martin Owens
 *
 * Copyright (C) Martin Owens 2018 <doctormo@gmail.com>
 *
 * Released under GNU GPLv2 or later, read the file 'COPYING' for more information
 */

#ifndef SEEN_UI_DIALOGS_ATTRDIALOG_H
#define SEEN_UI_DIALOGS_ATTRDIALOG_H

#include <gtkmm/builder.h>
#include <gtkmm/dialog.h>
#include <gtkmm/liststore.h>
#include <gtkmm/popover.h>
#include <gtkmm/scrolledwindow.h>
#include <gtkmm/textview.h>
#include <gtkmm/treeview.h>
#include <memory>

#include "helper/auto-connection.h"
#include "inkscape-application.h"
#include "message.h"
#include "ui/dialog/dialog-base.h"
#include "ui/syntax.h"
#include "xml/node-observer.h"

namespace Inkscape {
class MessageStack;
class MessageContext;
namespace UI {
namespace Dialog {

/**
 * @brief The AttrDialog class
 * This dialog allows to add, delete and modify XML attributes created in the
 * xml editor.
 */
class AttrDialog
	: public DialogBase
	, private XML::NodeObserver
{
public:
    AttrDialog();
    ~AttrDialog() override;

    void setRepr(Inkscape::XML::Node * repr);
    Gtk::ScrolledWindow& get_scrolled_window() { return _scrolled_window; }
    Gtk::Box& get_status_box() { return _status_box; }
    void adjust_popup_edit_size();
    void set_mono_font(bool mono);

private:
    // builder comes first, so it is initialized before other data members
    Glib::RefPtr<Gtk::Builder> _builder;

    // Data structure
    class AttrColumns : public Gtk::TreeModel::ColumnRecord
    {
    public:
        AttrColumns()
        {
            add(_attributeName);
            add(_attributeValue);
            add(_attributeValueRender);
        }
        Gtk::TreeModelColumn<Glib::ustring> _attributeName;
        Gtk::TreeModelColumn<Glib::ustring> _attributeValue;
        Gtk::TreeModelColumn<Glib::ustring> _attributeValueRender;
    };
    AttrColumns _attrColumns;

    // TreeView
    Gtk::TreeView& _treeView;
    Glib::RefPtr<Gtk::ListStore> _store;
    Gtk::CellRendererText *_nameRenderer;
    Gtk::CellRendererText *_valueRenderer;
    Gtk::TreeViewColumn *_nameCol;
    Gtk::TreeViewColumn *_valueCol;
    Gtk::Popover *_popover;
    Glib::ustring _value_path;
    Glib::ustring _value_editing;
    // Status bar
    std::shared_ptr<Inkscape::MessageStack> _message_stack;
    std::unique_ptr<Inkscape::MessageContext> _message_context;
    // Widgets
    Gtk::ScrolledWindow& _scrolled_window;
    Gtk::ScrolledWindow& _scrolled_text_view;
    // Variables - Inkscape
    Inkscape::XML::Node* _repr{nullptr};
    Gtk::Box& _status_box;
    Gtk::Label& _status;
    bool _updating = true;

    // Helper functions
    void setUndo(Glib::ustring const &event_description);
    /**
     * Sets the XML status bar, depending on which attr is selected.
     */
    void attr_reset_context(gint attr);

    /**
     * Signal handlers
     */
    auto_connection _message_changed_connection;
    bool onNameKeyPressed(GdkEventKey *event, Gtk::Entry *entry);
    bool onValueKeyPressed(GdkEventKey *event, Gtk::Entry *entry);
    void onAttrDelete(Glib::ustring path);
    bool onAttrCreate(GdkEventButton *event);
    bool onKeyPressed(GdkEventKey *event);
    void truncateDigits() const;
    void popClosed();
    void startNameEdit(Gtk::CellEditable *cell, const Glib::ustring &path);
    void startValueEdit(Gtk::CellEditable *cell, const Glib::ustring &path);
    void nameEdited(const Glib::ustring &path, const Glib::ustring &name);
    void valueEdited(const Glib::ustring &path, const Glib::ustring &value);
    void valueEditedPop();
    void storeMoveToNext(Gtk::TreeModel::Path modelpath);

private:
    // Text/comment nodes
    Gtk::ScrolledWindow& _content_sw;
    std::unique_ptr<Syntax::TextEditView> _text_edit;  // text content editing (plain text)
    std::unique_ptr<Syntax::TextEditView> _style_edit; // embedded CSS style (with syntax coloring)

    // Attribute value editing
    std::unique_ptr<Syntax::TextEditView> _css_edit;    // in-line CSS style
    std::unique_ptr<Syntax::TextEditView> _svgd_edit;   // SVG path data
    std::unique_ptr<Syntax::TextEditView> _points_edit; // points in a <polygon> or <polyline>
    std::unique_ptr<Syntax::TextEditView> _attr_edit;   // all other attributes (plain text)
    Syntax::TextEditView* _current_text_edit = nullptr; // current text edit for attribute value editing
    auto_connection _adjust_size;
    auto_connection _close_popup;
    int _rounding_precision = 0;

    bool key_callback(GdkEventKey* event);
    void notifyAttributeChanged(XML::Node &repr, GQuark name, Util::ptr_shared old_value, Util::ptr_shared new_value) final;
	void notifyContentChanged(XML::Node &node, Util::ptr_shared old_content, Util::ptr_shared new_content) final;
    static Glib::ustring round_numbers(const Glib::ustring& text, int precision);
    Gtk::TextView &_activeTextView() const;
    void set_current_textedit(Syntax::TextEditView* edit);
    static std::unique_ptr<Syntax::TextEditView> init_text_view(AttrDialog* owner, Syntax::SyntaxMode coloring, bool map);
};

} // namespace Dialog
} // namespace UI
} // namespace Inkscape

#endif // SEEN_UI_DIALOGS_ATTRDIALOG_H