Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
iconview-item-factory.h
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
2//
3// This is an item factory for a ColumnView container. It creates an item with picture and label.
4// During "bind" phase it will ask for label markup and picture image, plus tooltip, and populate item.
5
6#ifndef _ICONVIEWITEMFACTORY_H_
7#define _ICONVIEWITEMFACTORY_H_
8
9#include <gdkmm/texture.h>
10#include <glibmm/objectbase.h>
11#include <glibmm/refptr.h>
12#include <glibmm/ustring.h>
13#include <gtkmm/binlayout.h>
14#include <gtkmm/centerbox.h>
15#include <gtkmm/image.h>
16#include <gtkmm/label.h>
17#include <gtkmm/overlay.h>
18#include <gtkmm/picture.h>
19#include <gtkmm/signallistitemfactory.h>
20#include <gtkmm/widget.h>
21#include <memory>
22#include <unordered_map>
23
24namespace Inkscape::UI {
25
27public:
28 struct ItemData {
29 Glib::ustring label_markup;
30 Glib::RefPtr<Gdk::Texture> image;
31 Glib::ustring tooltip;
32 };
33
34 static std::unique_ptr<IconViewItemFactory> create(std::function<ItemData (Glib::RefPtr<Glib::ObjectBase>&)> get_item) {
35 return std::unique_ptr<IconViewItemFactory>(new IconViewItemFactory(std::move(get_item)));
36 }
37
38 Glib::RefPtr<Gtk::ListItemFactory> get_factory() { return _factory; }
39
40 // requests that labels are created (or not); gridview needs to be refreshed afterwards
41 void set_include_label(bool enable_labels) { _enable_labels = enable_labels; }
42
43 // keep track of bound items, so we can query them
44 void set_track_bindings(bool track) { _track_items = track; }
45
46 Glib::RefPtr<Glib::ObjectBase> find_item(Gtk::Widget& item_container) {
47 auto it = _bound_items.find(item_container.get_first_child());
48 return it != _bound_items.end() ? it->second : Glib::RefPtr<Glib::ObjectBase>();
49 }
50
51 void set_use_tooltip_markup(bool use_markup = true) { _use_markup = use_markup; }
52
53private:
54 IconViewItemFactory(std::function<ItemData (Glib::RefPtr<Glib::ObjectBase>&)> get_item):
55 _get_item_data(std::move(get_item)) {
56
57 _factory = Gtk::SignalListItemFactory::create();
58
59 _connections.emplace_back(_factory->signal_setup().connect([this](const Glib::RefPtr<Gtk::ListItem>& list_item) {
60 auto box = Gtk::make_managed<Gtk::CenterBox>();
61 box->add_css_class("item-box");
62 box->set_orientation(Gtk::Orientation::VERTICAL);
63 auto image = Gtk::make_managed<Gtk::Picture>();
64 // add bin layout manager, so picture doesn't propagete its size to the parent container;
65 // that way picture widget can be freely resized to desired dimensions and it will not grow beyond them
66 image->set_layout_manager(Gtk::BinLayout::create());
67 image->set_halign(Gtk::Align::CENTER);
68 image->set_valign(Gtk::Align::CENTER);
69 box->set_start_widget(*image);
70 // add a label below the picture
71 if (_enable_labels) {
72 auto label = Gtk::make_managed<Gtk::Label>();
73 label->set_vexpand();
74 label->set_valign(Gtk::Align::START);
75 box->set_end_widget(*label);
76 }
77
78 list_item->set_child(*box);
79 }));
80
81 _connections.emplace_back(_factory->signal_bind().connect([this](const Glib::RefPtr<Gtk::ListItem>& list_item) {
82 auto item = list_item->get_item();
83
84 auto box = dynamic_cast<Gtk::CenterBox*>(list_item->get_child());
85 if (!box) return;
86 auto image = dynamic_cast<Gtk::Picture*>(box->get_start_widget());
87 if (!image) return;
88 auto label = dynamic_cast<Gtk::Label*>(box->get_end_widget());
89
90 auto item_data = _get_item_data(item);
91
92 image->set_can_shrink(true);
93 image->set_content_fit(Gtk::ContentFit::CONTAIN);
94 auto tex = item_data.image;
95 image->set_paintable(tex);
96 // poor man's high dpi support here:
97 auto scale = box->get_scale_factor();
98 auto width = tex ? tex->get_intrinsic_width() / scale : 0;
99 auto height = tex ? tex->get_intrinsic_height() / scale : 0;
100 image->set_size_request(width, height);
101
102 if (label) {
103 label->set_markup(item_data.label_markup);
104 label->set_max_width_chars(std::min(5 + width / 10, 12));
105 label->set_wrap();
106 label->set_wrap_mode(Pango::WrapMode::WORD_CHAR);
107 label->set_natural_wrap_mode(Gtk::NaturalWrapMode::WORD);
108 label->set_justify(Gtk::Justification::CENTER);
109 label->set_valign(Gtk::Align::START);
110 }
111
112 if (_use_markup) {
113 box->set_tooltip_markup(item_data.tooltip);
114 } else {
115 box->set_tooltip_text(item_data.tooltip);
116 }
117
118 if (_track_items) _bound_items[box] = item;
119 }));
120
121 _connections.emplace_back(_factory->signal_unbind().connect([this](const Glib::RefPtr<Gtk::ListItem>& list_item) {
122 if (_track_items) {
123 auto box = dynamic_cast<Gtk::CenterBox*>(list_item->get_child());
124 _bound_items.erase(box);
125 }
126 }));
127 }
128
129 std::function<ItemData (Glib::RefPtr<Glib::ObjectBase>&)> _get_item_data;
130 Glib::RefPtr<Gtk::SignalListItemFactory> _factory;
131 bool _use_markup = false;
132 bool _enable_labels = true;
133 bool _track_items = false;
134 std::unordered_map<Gtk::Widget*, Glib::RefPtr<Glib::ObjectBase>> _bound_items;
135 std::vector<sigc::scoped_connection> _connections;
136};
137
138} // namespace
139
140#endif
double scale
Definition aa.cpp:228
IconViewItemFactory(std::function< ItemData(Glib::RefPtr< Glib::ObjectBase > &)> get_item)
std::unordered_map< Gtk::Widget *, Glib::RefPtr< Glib::ObjectBase > > _bound_items
void set_include_label(bool enable_labels)
Glib::RefPtr< Gtk::ListItemFactory > get_factory()
std::function< ItemData(Glib::RefPtr< Glib::ObjectBase > &)> _get_item_data
void set_use_tooltip_markup(bool use_markup=true)
Glib::RefPtr< Glib::ObjectBase > find_item(Gtk::Widget &item_container)
std::vector< sigc::scoped_connection > _connections
Glib::RefPtr< Gtk::SignalListItemFactory > _factory
static std::unique_ptr< IconViewItemFactory > create(std::function< ItemData(Glib::RefPtr< Glib::ObjectBase > &)> get_item)
std::unique_ptr< Magick::Image > image
SPItem * item
Glib::ustring label
User interface code.
Definition desktop.h:113
STL namespace.
double height
double width