Code

Make icon preview selection sticky by default.
[inkscape.git] / src / ui / dialog / icon-preview.cpp
index 336afc3c563f872c291358b76640062f05741678..0eddfa285d9268949aa0a9ff1249f05336e6797d 100644 (file)
@@ -7,7 +7,7 @@
  *   Other dudes from The Inkscape Organization
  *
  * Copyright (C) 2004 Bob Jamison
- * Copyright (C) 2005 Jon A. Cruz
+ * Copyright (C) 2005,2010 Jon A. Cruz
  *
  * Released under GNU GPL, read the file 'COPYING' for more information
  */
@@ -18,6 +18,7 @@
 #include <gtk/gtk.h>
 #include <glib/gmem.h>
 #include <glibmm/i18n.h>
+#include <gtkmm/alignment.h>
 #include <gtkmm/buttonbox.h>
 #include <gtkmm/stock.h>
 
@@ -42,17 +43,16 @@ sp_icon_doc_icon( SPDocument *doc, NRArenaItem *root,
 
 namespace Inkscape {
 namespace UI {
-namespace Dialogs {
+namespace Dialog {
 
 
-IconPreviewPanel&
-IconPreviewPanel::getInstance()
+IconPreviewPanel &IconPreviewPanel::getInstance()
 {
-    static IconPreviewPanel &instance = *new IconPreviewPanel();
+    IconPreviewPanel *instance = new IconPreviewPanel();
 
-    instance.refreshPreview();
+    instance->refreshPreview();
 
-    return instance;
+    return *instance;
 }
 
 //#########################################################################
@@ -81,16 +81,27 @@ void IconPreviewPanel::on_button_clicked(int which)
  */
 IconPreviewPanel::IconPreviewPanel() :
     UI::Widget::Panel("", "/dialogs/iconpreview", SP_VERB_VIEW_ICON_PREVIEW),
+    deskTrack(),
+    desktop(0),
+    document(0),
+    timer(0),
+    pending(false),
+    targetId(),
     hot(1),
-    refreshButton(0),
-    selectionButton(0)
+    selectionButton(0),
+    desktopChangeConn(),
+    docReplacedConn(),
+    docModConn(),
+    selChangedConn()
 {
     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
     numEntries = 0;
 
+    bool pack = prefs->getBool("/iconpreview/pack", true);
+
     std::vector<Glib::ustring> pref_sizes = prefs->getAllDirs("/iconpreview/sizes/default");
     std::vector<int> rawSizes;
-    
+
     for (std::vector<Glib::ustring>::iterator i = pref_sizes.begin(); i != pref_sizes.end(); ++i) {
         if (prefs->getBool(*i + "/show", true)) {
             int sizeVal = prefs->getInt(*i + "/value", -1);
@@ -139,12 +150,18 @@ IconPreviewPanel::IconPreviewPanel() :
 
     Gtk::VBox* magBox = new Gtk::VBox();
 
-    magBox->pack_start( magnified );
+    Gtk::Frame *magFrame = Gtk::manage(new Gtk::Frame(_("Magnified:")));
+    magFrame->add( magnified );
+
+    magBox->pack_start( *magFrame, Gtk::PACK_EXPAND_WIDGET );
     magBox->pack_start( magLabel, Gtk::PACK_SHRINK );
 
 
-    Gtk::VBox * verts = new Gtk::VBox();
-    for ( int i = 0; i < numEntries; i++ ) {
+    Gtk::VBox *verts = new Gtk::VBox();
+    Gtk::HBox *horiz = 0;
+    int previous = 0;
+    int avail = 0;
+    for ( int i = numEntries - 1; i >= 0; --i ) {
         pixMem[i] = new guchar[4 * sizes[i] * sizes[i]];
         memset( pixMem[i], 0x00, 4 *  sizes[i] * sizes[i] );
 
@@ -154,44 +171,90 @@ IconPreviewPanel::IconPreviewPanel() :
         Glib::ustring label(*labels[i]);
         buttons[i] = new Gtk::ToggleToolButton(label);
         buttons[i]->set_active( i == hot );
-        buttons[i]->set_icon_widget(*images[i]);
+        if ( prefs->getBool("/iconpreview/showFrames", true) ) {
+            Gtk::Frame *frame = new Gtk::Frame();
+            frame->set_shadow_type(Gtk::SHADOW_ETCHED_IN);
+            frame->add(*images[i]);
+            buttons[i]->set_icon_widget(*Gtk::manage(frame));
+        } else {
+            buttons[i]->set_icon_widget(*images[i]);
+        }
 
         tips.set_tip((*buttons[i]), label);
 
         buttons[i]->signal_clicked().connect( sigc::bind<int>( sigc::mem_fun(*this, &IconPreviewPanel::on_button_clicked), i) );
 
 
-        verts->add(*buttons[i]);
+        Gtk::Alignment *align = Gtk::manage(new Gtk::Alignment(0.5, 0.5, 0, 0));
+        align->add(*buttons[i]);
+
+        int pad = 12;
+        if ( !pack || ( (avail == 0) && (previous == 0) ) ) {
+            verts->pack_end(*align, Gtk::PACK_SHRINK);
+            previous = sizes[i];
+            avail = sizes[i];
+        } else {
+            if ((avail < pad) || ((sizes[i] > avail) && (sizes[i] < previous))) {
+                horiz = 0;
+            }
+            if ((horiz == 0) && (sizes[i] <= previous)) {
+                avail = previous;
+            }
+            if (sizes[i] <= avail) {
+                if (!horiz) {
+                    horiz = Gtk::manage(new Gtk::HBox());
+                    avail = previous;
+                    verts->pack_end(*horiz, Gtk::PACK_SHRINK);
+                }
+                horiz->pack_start(*align, Gtk::PACK_EXPAND_WIDGET);
+                avail -= sizes[i];
+                avail -= pad; // a little extra for padding
+            } else {
+                horiz = 0;
+                verts->pack_end(*align, Gtk::PACK_SHRINK);
+            }
+        }
     }
 
     iconBox.pack_start(splitter);
     splitter.pack1( *magBox, true, true );
-    splitter.pack2( *verts, false, false );
-
-
-    //## The Refresh button
+    Gtk::Frame *actuals = Gtk::manage(new Gtk::Frame(_("Actual Size:")));
+    actuals->add(*verts);
+    splitter.pack2( *actuals, false, false );
 
 
-    Gtk::HButtonBox* holder = new Gtk::HButtonBox( Gtk::BUTTONBOX_END );
-    _getContents()->pack_end(*holder, false, false);
-
-    selectionButton = new Gtk::ToggleButton(_("Selection")); // , GTK_RESPONSE_APPLY
-    holder->pack_start( *selectionButton, false, false );
+    selectionButton = new Gtk::CheckButton(_("Selection")); // , GTK_RESPONSE_APPLY
+    magBox->pack_start( *selectionButton, Gtk::PACK_SHRINK );
     tips.set_tip((*selectionButton), _("Selection only or whole document"));
     selectionButton->signal_clicked().connect( sigc::mem_fun(*this, &IconPreviewPanel::modeToggled) );
 
     gint val = prefs->getBool("/iconpreview/selectionOnly");
     selectionButton->set_active( val != 0 );
 
-    refreshButton = new Gtk::Button(Gtk::Stock::REFRESH); // , GTK_RESPONSE_APPLY
-    holder->pack_end( *refreshButton, false, false );
-    tips.set_tip((*refreshButton), _("Refresh the icons"));
-    refreshButton->signal_clicked().connect( sigc::mem_fun(*this, &IconPreviewPanel::refreshPreview) );
-
 
-    _getContents()->pack_start(iconBox, Gtk::PACK_EXPAND_WIDGET);
+    _getContents()->pack_start(iconBox, Gtk::PACK_SHRINK);
 
     show_all_children();
+
+    // Connect this up last
+    desktopChangeConn = deskTrack.connectDesktopChanged( sigc::mem_fun(*this, &IconPreviewPanel::setDesktop) );
+    deskTrack.connect(GTK_WIDGET(gobj()));
+}
+
+IconPreviewPanel::~IconPreviewPanel()
+{
+    setDesktop(0);
+    if (timer) {
+        timer->stop();
+        delete timer;
+        timer = 0;
+    }
+
+    selChangedConn.disconnect();
+    docModConn.disconnect();
+    docReplacedConn.disconnect();
+    desktopChangeConn.disconnect();
+    deskTrack.disconnect();
 }
 
 //#########################################################################
@@ -199,48 +262,121 @@ IconPreviewPanel::IconPreviewPanel() :
 //#########################################################################
 
 
+void IconPreviewPanel::setDesktop( SPDesktop* desktop )
+{
+    Panel::setDesktop(desktop);
+
+    SPDocument *newDoc = (desktop) ? desktop->doc() : 0;
+
+    if ( desktop != this->desktop ) {
+        docReplacedConn.disconnect();
+        selChangedConn.disconnect();
+
+        this->desktop = Panel::getDesktop();
+        if ( this->desktop ) {
+            docReplacedConn = this->desktop->connectDocumentReplaced(sigc::hide<0>(sigc::mem_fun(this, &IconPreviewPanel::setDocument)));
+            if (this->desktop->selection) {
+                selChangedConn = desktop->selection->connectChanged(sigc::hide(sigc::mem_fun(this, &IconPreviewPanel::queueRefresh)));
+            }
+        }
+    }
+    setDocument(newDoc);
+    deskTrack.setBase(desktop);
+}
+
+void IconPreviewPanel::setDocument( SPDocument *document )
+{
+    if (this->document != document) {
+        docModConn.disconnect();
+
+        this->document = document;
+        if (this->document) {
+            docModConn = this->document->connectModified(sigc::hide(sigc::mem_fun(this, &IconPreviewPanel::queueRefresh)));
+            queueRefresh();
+        }
+    }
+}
+
 void IconPreviewPanel::refreshPreview()
 {
     SPDesktop *desktop = getDesktop();
-    if ( desktop ) {
-
+    if (!timer) {
+        timer = new Glib::Timer();
+    }
+    if (timer->elapsed() < 0.1) {
+        // Do not refresh too quickly
+        queueRefresh();
+    } else if ( desktop ) {
+        bool hold = Inkscape::Preferences::get()->getBool("/iconpreview/selectionHold", true);
         if ( selectionButton && selectionButton->get_active() )
         {
-            Inkscape::Selection * sel = sp_desktop_selection(desktop);
-            if ( sel ) {
-                //g_message("found a selection to play with");
-
-                GSList const *items = sel->itemList();
-                SPObject *target = 0;
-                while ( items && !target ) {
-                    SPItem* item = SP_ITEM( items->data );
-                    SPObject * obj = SP_OBJECT(item);
-                    gchar const *id = SP_OBJECT_ID( obj );
-                    if ( id ) {
-                        target = obj;
+            SPObject *target = (hold && !targetId.empty()) ? desktop->doc()->getObjectById( targetId.c_str() ) : 0;
+            if ( !target ) {
+                targetId.clear();
+                Inkscape::Selection * sel = sp_desktop_selection(desktop);
+                if ( sel ) {
+                    //g_message("found a selection to play with");
+
+                    GSList const *items = sel->itemList();
+                    while ( items && !target ) {
+                        SPItem* item = SP_ITEM( items->data );
+                        SPObject * obj = SP_OBJECT(item);
+                        gchar const *id = obj->getId();
+                        if ( id ) {
+                            targetId = id;
+                            target = obj;
+                        }
+
+                        items = g_slist_next(items);
                     }
-
-                    items = g_slist_next(items);
-                }
-                if ( target ) {
-                    renderPreview(target);
                 }
             }
-        }
-        else
-        {
+            if ( target ) {
+                renderPreview(target);
+            }
+        } else {
             SPObject *target = desktop->currentRoot();
             if ( target ) {
                 renderPreview(target);
             }
         }
+        timer->reset();
+    }
+}
+
+bool IconPreviewPanel::refreshCB()
+{
+    bool callAgain = true;
+    if (!timer) {
+        timer = new Glib::Timer();
+    }
+    if ( timer->elapsed() > 0.1 ) {
+        callAgain = false;
+        refreshPreview();
+        pending = false;
+    }
+    return callAgain;
+}
+
+void IconPreviewPanel::queueRefresh()
+{
+    if (!pending) {
+        pending = true;
+        if (!timer) {
+            timer = new Glib::Timer();
+        }
+        Glib::signal_idle().connect( sigc::mem_fun(this, &IconPreviewPanel::refreshCB), Glib::PRIORITY_DEFAULT_IDLE );
     }
 }
 
 void IconPreviewPanel::modeToggled()
 {
     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
-    prefs->setBool("/iconpreview/selectionOnly", (selectionButton && selectionButton->get_active()));
+    bool selectionOnly = (selectionButton && selectionButton->get_active());
+    prefs->setBool("/iconpreview/selectionOnly", selectionOnly);
+    if ( !selectionOnly ) {
+        targetId.clear();
+    }
 
     refreshPreview();
 }
@@ -248,7 +384,7 @@ void IconPreviewPanel::modeToggled()
 void IconPreviewPanel::renderPreview( SPObject* obj )
 {
     SPDocument * doc = SP_OBJECT_DOCUMENT(obj);
-    gchar * id = SP_OBJECT_ID(obj);
+    gchar const * id = obj->getId();
 
 //    g_message(" setting up to render '%s' as the icon", id );
 
@@ -290,7 +426,6 @@ void IconPreviewPanel::updateMagnify()
     magnified.get_parent()->queue_draw();
 }
 
-
 } //namespace Dialogs
 } //namespace UI
 } //namespace Inkscape