1 /** @file
2 * @brief A simple dialog for previewing icon representation.
3 */
4 /* Authors:
5 * Jon A. Cruz
6 * Bob Jamison
7 * Other dudes from The Inkscape Organization
8 *
9 * Copyright (C) 2004 Bob Jamison
10 * Copyright (C) 2005 Jon A. Cruz
11 *
12 * Released under GNU GPL, read the file 'COPYING' for more information
13 */
14 #ifdef HAVE_CONFIG_H
15 # include <config.h>
16 #endif
18 #include <gtk/gtk.h>
19 #include <glib/gmem.h>
20 #include <glibmm/i18n.h>
21 #include <gtkmm/buttonbox.h>
22 #include <gtkmm/stock.h>
24 #include "desktop.h"
25 #include "desktop-handles.h"
26 #include "display/nr-arena.h"
27 #include "document.h"
28 #include "inkscape.h"
29 #include "preferences.h"
30 #include "selection.h"
31 #include "sp-root.h"
32 #include "xml/repr.h"
34 #include "icon-preview.h"
36 extern "C" {
37 // takes doc, root, icon, and icon name to produce pixels
38 guchar *
39 sp_icon_doc_icon( SPDocument *doc, NRArenaItem *root,
40 const gchar *name, unsigned int psize );
41 }
43 namespace Inkscape {
44 namespace UI {
45 namespace Dialogs {
48 IconPreviewPanel&
49 IconPreviewPanel::getInstance()
50 {
51 static IconPreviewPanel &instance = *new IconPreviewPanel();
53 instance.refreshPreview();
55 return instance;
56 }
58 //#########################################################################
59 //## E V E N T S
60 //#########################################################################
62 void IconPreviewPanel::on_button_clicked(int which)
63 {
64 if ( hot != which ) {
65 buttons[hot]->set_active( false );
67 hot = which;
68 updateMagnify();
69 _getContents()->queue_draw();
70 }
71 }
76 //#########################################################################
77 //## C O N S T R U C T O R / D E S T R U C T O R
78 //#########################################################################
79 /**
80 * Constructor
81 */
82 IconPreviewPanel::IconPreviewPanel() :
83 UI::Widget::Panel("", "/dialogs/iconpreview", SP_VERB_VIEW_ICON_PREVIEW),
84 hot(1),
85 refreshButton(0),
86 selectionButton(0)
87 {
88 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
89 numEntries = 0;
91 std::vector<Glib::ustring> pref_sizes = prefs->getAllDirs("/iconpreview/sizes/default");
92 std::vector<int> rawSizes;
94 for (std::vector<Glib::ustring>::iterator i = pref_sizes.begin(); i != pref_sizes.end(); ++i) {
95 if (prefs->getBool(*i + "/show", true)) {
96 int sizeVal = prefs->getInt(*i + "/value", -1);
97 if (sizeVal > 0) {
98 rawSizes.push_back(sizeVal);
99 }
100 }
101 }
103 if ( !rawSizes.empty() ) {
104 numEntries = rawSizes.size();
105 sizes = new int[numEntries];
106 int i = 0;
107 for ( std::vector<int>::iterator it = rawSizes.begin(); it != rawSizes.end(); ++it, ++i ) {
108 sizes[i] = *it;
109 }
110 }
112 if ( numEntries < 1 )
113 {
114 numEntries = 5;
115 sizes = new int[numEntries];
116 sizes[0] = 16;
117 sizes[1] = 24;
118 sizes[2] = 32;
119 sizes[3] = 48;
120 sizes[4] = 128;
121 }
123 pixMem = new guchar*[numEntries];
124 images = new Gtk::Image*[numEntries];
125 labels = new Glib::ustring*[numEntries];
126 buttons = new Gtk::ToggleToolButton*[numEntries];
129 for ( int i = 0; i < numEntries; i++ ) {
130 char *label = g_strdup_printf(_("%d x %d"), sizes[i], sizes[i]);
131 labels[i] = new Glib::ustring(label);
132 g_free(label);
133 pixMem[i] = 0;
134 images[i] = 0;
135 }
138 magLabel.set_label( *labels[hot] );
140 Gtk::VBox* magBox = new Gtk::VBox();
142 magBox->pack_start( magnified );
143 magBox->pack_start( magLabel, Gtk::PACK_SHRINK );
146 Gtk::VBox * verts = new Gtk::VBox();
147 for ( int i = 0; i < numEntries; i++ ) {
148 pixMem[i] = new guchar[4 * sizes[i] * sizes[i]];
149 memset( pixMem[i], 0x00, 4 * sizes[i] * sizes[i] );
151 GdkPixbuf *pb = gdk_pixbuf_new_from_data( pixMem[i], GDK_COLORSPACE_RGB, TRUE, 8, sizes[i], sizes[i], sizes[i] * 4, /*(GdkPixbufDestroyNotify)g_free*/NULL, NULL );
152 GtkImage* img = GTK_IMAGE( gtk_image_new_from_pixbuf( pb ) );
153 images[i] = Glib::wrap(img);
154 Glib::ustring label(*labels[i]);
155 buttons[i] = new Gtk::ToggleToolButton(label);
156 buttons[i]->set_active( i == hot );
157 buttons[i]->set_icon_widget(*images[i]);
159 tips.set_tip((*buttons[i]), label);
161 buttons[i]->signal_clicked().connect( sigc::bind<int>( sigc::mem_fun(*this, &IconPreviewPanel::on_button_clicked), i) );
164 verts->add(*buttons[i]);
165 }
167 iconBox.pack_start(splitter);
168 splitter.pack1( *magBox, true, true );
169 splitter.pack2( *verts, false, false );
172 //## The Refresh button
175 Gtk::HButtonBox* holder = new Gtk::HButtonBox( Gtk::BUTTONBOX_END );
176 _getContents()->pack_end(*holder, false, false);
178 selectionButton = new Gtk::ToggleButton(_("Selection")); // , GTK_RESPONSE_APPLY
179 holder->pack_start( *selectionButton, false, false );
180 tips.set_tip((*selectionButton), _("Selection only or whole document"));
181 selectionButton->signal_clicked().connect( sigc::mem_fun(*this, &IconPreviewPanel::modeToggled) );
183 gint val = prefs->getBool("/iconpreview/selectionOnly");
184 selectionButton->set_active( val != 0 );
186 refreshButton = new Gtk::Button(Gtk::Stock::REFRESH); // , GTK_RESPONSE_APPLY
187 holder->pack_end( *refreshButton, false, false );
188 tips.set_tip((*refreshButton), _("Refresh the icons"));
189 refreshButton->signal_clicked().connect( sigc::mem_fun(*this, &IconPreviewPanel::refreshPreview) );
192 _getContents()->pack_start(iconBox, Gtk::PACK_EXPAND_WIDGET);
194 show_all_children();
195 }
197 //#########################################################################
198 //## M E T H O D S
199 //#########################################################################
202 void IconPreviewPanel::refreshPreview()
203 {
204 SPDesktop *desktop = getDesktop();
205 if ( desktop ) {
207 if ( selectionButton && selectionButton->get_active() )
208 {
209 Inkscape::Selection * sel = sp_desktop_selection(desktop);
210 if ( sel ) {
211 //g_message("found a selection to play with");
213 GSList const *items = sel->itemList();
214 SPObject *target = 0;
215 while ( items && !target ) {
216 SPItem* item = SP_ITEM( items->data );
217 SPObject * obj = SP_OBJECT(item);
218 gchar const *id = SP_OBJECT_ID( obj );
219 if ( id ) {
220 target = obj;
221 }
223 items = g_slist_next(items);
224 }
225 if ( target ) {
226 renderPreview(target);
227 }
228 }
229 }
230 else
231 {
232 SPObject *target = desktop->currentRoot();
233 if ( target ) {
234 renderPreview(target);
235 }
236 }
237 }
238 }
240 void IconPreviewPanel::modeToggled()
241 {
242 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
243 prefs->setBool("/iconpreview/selectionOnly", (selectionButton && selectionButton->get_active()));
245 refreshPreview();
246 }
248 void IconPreviewPanel::renderPreview( SPObject* obj )
249 {
250 SPDocument * doc = SP_OBJECT_DOCUMENT(obj);
251 gchar * id = SP_OBJECT_ID(obj);
253 // g_message(" setting up to render '%s' as the icon", id );
255 NRArenaItem *root = NULL;
257 /* Create new arena */
258 NRArena *arena = NRArena::create();
260 /* Create ArenaItem and set transform */
261 unsigned int visionkey = sp_item_display_key_new(1);
263 root = sp_item_invoke_show ( SP_ITEM( SP_DOCUMENT_ROOT(doc) ),
264 arena, visionkey, SP_ITEM_SHOW_DISPLAY );
266 for ( int i = 0; i < numEntries; i++ ) {
267 guchar * px = sp_icon_doc_icon( doc, root, id, sizes[i] );
268 // g_message( " size %d %s", sizes[i], (px ? "worked" : "failed") );
269 if ( px ) {
270 memcpy( pixMem[i], px, sizes[i] * sizes[i] * 4 );
271 g_free( px );
272 px = 0;
273 } else {
274 memset( pixMem[i], 0, sizes[i] * sizes[i] * 4 );
275 }
276 images[i]->queue_draw();
277 }
278 updateMagnify();
280 sp_item_invoke_hide(SP_ITEM(sp_document_root(doc)), visionkey);
281 nr_object_unref((NRObject *) arena);
282 }
284 void IconPreviewPanel::updateMagnify()
285 {
286 Glib::RefPtr<Gdk::Pixbuf> buf = images[hot]->get_pixbuf()->scale_simple( 128, 128, Gdk::INTERP_NEAREST );
287 magLabel.set_label( *labels[hot] );
288 magnified.set( buf );
289 magnified.queue_draw();
290 magnified.get_parent()->queue_draw();
291 }
294 } //namespace Dialogs
295 } //namespace UI
296 } //namespace Inkscape
298 /*
299 Local Variables:
300 mode:c++
301 c-file-style:"stroustrup"
302 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
303 indent-tabs-mode:nil
304 fill-column:99
305 End:
306 */
307 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :