20#include <glibmm/i18n.h>
21#include <gtkmm/checkbutton.h>
22#include <gtkmm/image.h>
23#include <gtkmm/snapshot.h>
24#include <gtkmm/togglebutton.h>
35#define noICON_VERBOSE 1
59 :
DialogBase(
"/dialogs/iconpreview",
"IconPreview")
61 , drawing_doc(nullptr)
64 , renderTimer(nullptr)
68 , selectionButton(nullptr)
72 bool pack = prefs->
getBool(
"/iconpreview/pack",
true);
74 std::vector<Glib::ustring> pref_sizes = prefs->
getAllDirs(
"/iconpreview/sizes/default");
76 for (
auto & pref_size : pref_sizes) {
77 if (prefs->
getBool(pref_size +
"/show",
true)) {
78 int sizeVal = prefs->
getInt(pref_size +
"/value", -1);
80 sizes.push_back(sizeVal);
86 sizes = {16, 24, 32, 48, 128};
93 for (std::size_t i = 0; i <
sizes.size(); ++i) {
94 labels[i] = Glib::ustring::compose(
"%1 x %1",
sizes[i]);
99 auto const magBox = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::VERTICAL);
102 magnified.set_halign(Gtk::Align::CENTER);
103 magnified.set_valign(Gtk::Align::CENTER);
105 auto const magFrame = Gtk::make_managed<UI::Widget::Frame>(_(
"Magnified:"));
107 magFrame->add_css_class(
"icon-preview");
108 magFrame->set_vexpand();
110 magBox->append(*magFrame);
113 auto const verts = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::VERTICAL);
115 Gtk::Box *horiz =
nullptr;
118 for (
auto i =
sizes.size(); i-- > 0;) {
119 images[i] = Gtk::make_managed<Gtk::Image>();
124 buttons[i] = Gtk::make_managed<Gtk::ToggleButton>();
125 buttons[i]->add_css_class(
"icon-preview");
126 buttons[i]->set_has_frame(
false);
129 if (prefs->
getBool(
"/iconpreview/showFrames",
true)) {
130 auto const frame = Gtk::make_managed<Gtk::Frame>();
131 frame->set_child(*
images[i]);
132 frame->add_css_class(
"icon-preview");
140 buttons[i]->set_halign(Gtk::Align::CENTER);
141 buttons[i]->set_valign(Gtk::Align::CENTER);
143 if (!
pack || (avail == 0 && previous == 0)) {
148 static constexpr int pad = 12;
150 if (avail < pad || (
sizes[i] > avail &&
sizes[i] < previous)) {
154 if (!horiz &&
sizes[i] <= previous) {
158 if (
sizes[i] <= avail) {
160 horiz = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::HORIZONTAL);
161 horiz->set_halign(Gtk::Align::CENTER);
163 verts->prepend(*horiz);
178 splitter.set_valign(Gtk::Align::START);
180 splitter.set_shrink_start_child(
false);
181 auto const actuals = Gtk::make_managed<UI::Widget::Frame>(_(
"Actual Size:"));
182 actuals->add(*verts);
184 splitter.set_resize_end_child(
false);
185 splitter.set_shrink_end_child(
false);
187 selectionButton = Gtk::make_managed<Gtk::CheckButton>(C_(
"Icon preview window",
"Sele_ction"),
true);
189 selectionButton->set_tooltip_text(_(
"Selection only or whole document"));
192 bool const val = prefs->
getBool(
"/iconpreview/selectionOnly");
221 gint64 micr = g_get_monotonic_time();
222 gint64 mins = ((int)round(micr / 60000000)) % 60;
223 gdouble dsecs = micr / 1000000;
224 gchar *ptr = g_strdup_printf(
":%02u:%f", mins, dsecs);
256 drawing = std::make_unique<Inkscape::Drawing>();
283 timer = std::make_unique<Glib::Timer>();
287 g_message(
"%s Deferring refresh as too soon. calling queueRefresh()",
getTimestr().c_str() );
293 g_message(
"%s Refreshing preview.",
getTimestr().c_str() );
318 g_message(
"%s resetting timer",
getTimestr().c_str() );
326 bool callAgain =
true;
328 timer = std::make_unique<Glib::Timer>();
332 g_message(
"%s refreshCB() timer has progressed",
getTimestr().c_str() );
337 g_message(
"%s refreshCB() setting pending false",
getTimestr().c_str() );
349 g_message(
"%s queueRefresh() Setting pending true",
getTimestr().c_str() );
352 timer = std::make_unique<Glib::Timer>();
362 prefs->
setBool(
"/iconpreview/selectionOnly", selectionOnly);
363 if ( !selectionOnly ) {
372 int bytesPerPixel = 4;
374 for (
int y = 0; y <
height; y += spacing ) {
375 auto ptr = px + y *
stride;
376 for (
int x = 0; x <
width; x += spacing ) {
382 ptr += bytesPerPixel * (spacing - 1);
418 ptr[0 -
stride * 3] = 0xff;
457 g_message(
" box --'%s' (%f,%f)-(%f,%f)",
name, (
double)ibox.
left(), (
double)ibox.
top(), (
double)ibox.
right(), (
double)ibox.
bottom());
468 if (
int block = std::max(
width,
height); block !=
static_cast<int>(psize)) {
470 g_message(
" resizing");
472 sf = (double)psize / (
double)block;
478 ibox = scaled_box.roundOutwards();
480 g_message(
" box2 --'%s' (%f,%f)-(%f,%f)",
name, (
double)ibox.
left(), (
double)ibox.
top(), (
double)ibox.
right(), (
double)ibox.
bottom());
503 g_message(
" area --'%s' (%f,%f)-(%f,%f)",
name, (
double)area.
left(), (
double)area.
top(), (
double)area.
right(), (
double)area.
bottom());
504 g_message(
" ua --'%s' (%f,%f)-(%f,%f)",
name, (
double)ua.
left(), (
double)ua.
top(), (
double)ua.
right(), (
double)ua.
bottom());
508 auto s = Cairo::ImageSurface::create(Cairo::ImageSurface::Format::ARGB32, psize, psize);
513 auto cr = Cairo::Context::create(s);
514 cr->set_source_rgba(bg[0], bg[1], bg[2], bg[3]);
515 cr->rectangle(0, 0, psize, psize);
524 overlayPixels(s->get_data(), psize, psize, s->get_stride(), 0x00, 0x00, 0xff);
534 gchar
const *
id = obj->
getId();
541 g_message(
"%s setting up to render '%s' as the icon",
getTimestr().c_str(),
id );
544 for (std::size_t i = 0; i <
sizes.size(); ++i) {
553 g_message(
" render took %f seconds.",
renderTimer->elapsed());
566 snapshot->append_color(Gdk::RGBA{0, 0, 0}, Gdk::Rectangle{0, 0, get_width(), get_height()});
569 auto node = gsk_texture_scale_node_new(
_texture->gobj(), Gdk::Graphene::Rect{0, 0, 128, 128}.gobj(), GSK_SCALING_FILTER_NEAREST);
570 gtk_snapshot_append_node(snapshot->gobj(),
node);
571 gsk_render_node_unref(
node);
Axis aligned, non-empty, generic rectangle.
static CRect from_xywh(C x, C y, C w, C h)
Create rectangle from origin and dimensions.
C right() const
Return rightmost coordinate of the rectangle (+X is to the right).
C top() const
Return top coordinate of the rectangle (+Y is downwards).
C left() const
Return leftmost coordinate of the rectangle (+X is to the right).
C height() const
Get the vertical extent of the rectangle.
C width() const
Get the horizontal extent of the rectangle.
CPoint min() const
Get the corner of the rectangle with smallest coordinate values.
C bottom() const
Return bottom coordinate of the rectangle (+Y is downwards).
Two-dimensional point with integer coordinates.
Minimal wrapper over Cairo.
void setTransform(Geom::Affine const &trans)
void update(Geom::IntRect const &area=Geom::IntRect::infinite(), Geom::Affine const &affine=Geom::identity(), unsigned flags=DrawingItem::STATE_ALL, unsigned reset=0)
void render(DrawingContext &dc, Geom::IntRect const &area, unsigned flags=0) const
SPItemRange items()
Returns a range of selected SPItems.
Colors::Color const & getDefaultBackgroundColor() const
Preference storage class.
bool getBool(Glib::ustring const &pref_path, bool def=false)
Retrieve a Boolean value.
static Preferences * get()
Access the singleton Preferences object.
int getInt(Glib::ustring const &pref_path, int def=0)
Retrieve an integer.
std::vector< Glib::ustring > getAllDirs(Glib::ustring const &path)
Get all subdirectories of the specified directory.
void setBool(Glib::ustring const &pref_path, bool value)
Set a Boolean value.
The set of selected SPObjects for a given document and layer model.
DialogBase is the base class for the dialog system.
Selection * getSelection() const
SPDocument * getDocument() const
SPDesktop * getDesktop() const
std::vector< Gtk::Image * > images
void queueRefreshIfAutoRefreshEnabled()
void selectionModified(Selection *selection, guint flags) override
void removeDrawing()
Safely delete the Inkscape::Drawing and references to it.
void documentReplaced() override
std::vector< Glib::RefPtr< Gdk::Texture > > textures
void on_button_clicked(int which)
std::unique_ptr< Glib::Timer > timer
void selectionChanged(Selection *selection) override
sigc::scoped_connection docDesConn
std::unique_ptr< Drawing > drawing
void renderPreview(SPObject *obj)
Gtk::CheckButton * selectionButton
std::unique_ptr< Glib::Timer > renderTimer
~IconPreviewPanel() final
std::vector< Gtk::ToggleButton * > buttons
std::vector< Glib::ustring > labels
Glib::RefPtr< Gdk::Texture > _texture
void snapshot_vfunc(Glib::RefPtr< Gtk::Snapshot > const &snapshot) override
void set(Glib::RefPtr< Gdk::Texture > const &texture)
SPDocument * getDocument() const
Typed SVG document implementation.
SPRoot * getRoot()
Returns our SPRoot.
SPObject * getObjectById(std::string const &id) const
Geom::OptRect preferredBounds() const
Inkscape::PageManager & getPageManager()
sigc::connection connectDestroy(sigc::signal< void()>::slot_type slot)
Geom::OptRect documentVisualBounds() const
Get item's visual bbox in document coordinate system.
Inkscape::DrawingItem * invoke_show(Inkscape::Drawing &drawing, unsigned int key, unsigned int flags)
void invoke_hide(unsigned int key)
static unsigned int display_key_new(unsigned numkeys)
Allocates unique integer keys.
SPObject is an abstract base class of all of the document nodes at the SVG document level.
char const * getId() const
Returns the objects current ID string.
Editable view implementation.
Cairo drawing context with Inkscape extensions.
A simple dialog for previewing icon representation.
Inkscape::XML::Node * node
std::vector< Point > intersect(const xAx &C1, const xAx &C2)
static void overlayPixels(unsigned char *px, int width, int height, int stride, unsigned r, unsigned g, unsigned b)
static Cairo::RefPtr< Cairo::ImageSurface > sp_icon_doc_icon(SPDocument *doc, Drawing &drawing, char const *name, unsigned psize)
static Glib::ustring getTimestr()
static void pack(PackType const pack_type, Gtk::Box &box, Gtk::Widget &child, bool const expand, bool const fill, unsigned const padding)
static void append(std::vector< T > &target, std::vector< T > &&source)
SPRoot: SVG <svg> implementation.
Glib::RefPtr< Gdk::Texture > to_texture(Cairo::RefPtr< Cairo::Surface > const &surface)
Convert an image surface in ARGB32 format to a texture.