Fawkes API
Fawkes Development Version
|
00001 00002 /*************************************************************************** 00003 * throbber.cpp - Fawkes throbber 00004 * 00005 * Created: Tue Nov 04 16:38:03 2008 00006 * Copyright 2008 Tim Niemueller [www.niemueller.de] 00007 * 00008 ****************************************************************************/ 00009 00010 /* This program is free software; you can redistribute it and/or modify 00011 * it under the terms of the GNU General Public License as published by 00012 * the Free Software Foundation; either version 2 of the License, or 00013 * (at your option) any later version. A runtime exception applies to 00014 * this software (see LICENSE.GPL_WRE file mentioned below for details). 00015 * 00016 * This program is distributed in the hope that it will be useful, 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00019 * GNU Library General Public License for more details. 00020 * 00021 * Read the full text in the LICENSE.GPL_WRE file in the doc directory. 00022 */ 00023 00024 #include <gui_utils/throbber.h> 00025 00026 #include <core/exception.h> 00027 #include <algorithm> 00028 00029 namespace fawkes { 00030 #if 0 /* just to make Emacs auto-indent happy */ 00031 } 00032 #endif 00033 00034 #define SPINNER_ICON_NAME "process-working" 00035 #define SPINNER_FALLBACK_ICON_NAME "gnome-spinner" 00036 #define SPINNER_DEFAULT_TIMEOUT 100 00037 00038 00039 /** @class Throbber <gui_utils/throbber.h> 00040 * Simple Gtk Throbber/Spinner. 00041 * The throbber shows a spinning icon as a small image. It has been specifically 00042 * prepared to be used as a custom image Gtk::ToolItem in a Gtk::Toolbar. 00043 * The icon is defined by the currently active Gtk theme. 00044 * @author Tim Niemueller 00045 */ 00046 00047 #ifdef HAVE_GLADEMM 00048 /** Constructor. 00049 * Special ctor to be used with Glade's get_widget_derived(). 00050 * @param cobject Gtk C object 00051 * @param refxml Glade's XML reference 00052 */ 00053 Throbber::Throbber(BaseObjectType* cobject, 00054 const Glib::RefPtr<Gnome::Glade::Xml>& refxml) 00055 : Gtk::Image(cobject) 00056 { 00057 Gtk::Container *parent = get_parent(); 00058 Gtk::ToolItem *toolitem = dynamic_cast<Gtk::ToolItem *>(parent); 00059 if ( toolitem ) { 00060 ctor(toolitem->get_icon_size()); 00061 } else { 00062 // We have no clue, just try button 00063 ctor(Gtk::IconSize(Gtk::ICON_SIZE_BUTTON)); 00064 } 00065 } 00066 #endif 00067 00068 00069 /** Constructor. 00070 * @param icon_size desired icon size. Be aware that the icon may not be available 00071 * in all sizes in the current theme. 00072 */ 00073 Throbber::Throbber(Gtk::IconSize &icon_size) 00074 { 00075 ctor(icon_size); 00076 } 00077 00078 00079 void 00080 Throbber::ctor(Gtk::IconSize icon_size) 00081 { 00082 __timeout = SPINNER_DEFAULT_TIMEOUT; 00083 __icon_size = icon_size; 00084 00085 int isw = 0, ish = 0; 00086 #if GTKMM_MAJOR_VERSION > 2 || ( GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 14 ) 00087 Glib::RefPtr<Gtk::Settings> settings = Gtk::Settings::get_for_screen(get_screen()); 00088 if ( ! Gtk::IconSize::lookup(icon_size, isw, ish, settings) ) { 00089 throw Exception("Could not get icon sizes"); 00090 } 00091 #else 00092 if ( ! Gtk::IconSize::lookup(icon_size, isw, ish) ) { 00093 throw Exception("Could not get icon sizes"); 00094 } 00095 #endif 00096 int requested_size = std::max(isw, ish); 00097 00098 Glib::RefPtr<Gtk::IconTheme> icon_theme = Gtk::IconTheme::get_for_screen(get_screen()); 00099 Gtk::IconInfo icon_info = icon_theme->lookup_icon(SPINNER_ICON_NAME, 00100 requested_size, 00101 Gtk::IconLookupFlags()); 00102 if ( ! icon_info ) { 00103 icon_info = icon_theme->lookup_icon(SPINNER_FALLBACK_ICON_NAME, 00104 requested_size, Gtk::IconLookupFlags()); 00105 if ( ! icon_info ) { 00106 throw Exception("Could not find neither default nor fallback throbber icon"); 00107 } 00108 } 00109 00110 int size = icon_info.get_base_size(); 00111 00112 #ifdef GLIBMM_EXCEPTIONS_ENABLED 00113 Glib::RefPtr<Gdk::Pixbuf> icon = icon_info.load_icon(); 00114 #else 00115 std::auto_ptr<Glib::Error> error; 00116 Glib::RefPtr<Gdk::Pixbuf> icon = icon_info.load_icon(error); 00117 #endif 00118 00119 int pixwidth = icon->get_width(); 00120 int pixheight = icon->get_height(); 00121 00122 for (int y = 0; y < pixheight; y += size) { 00123 for (int x = 0; x < pixwidth ; x += size) { 00124 if ( (x + size <= icon->get_width()) && 00125 (y + size <= icon->get_height()) ) { 00126 Glib::RefPtr<Gdk::Pixbuf> p = Gdk::Pixbuf::create_subpixbuf(icon, x, y, size, size); 00127 __pixbufs.push_back(p); 00128 } 00129 } 00130 } 00131 00132 if ( __pixbufs.empty() ) { 00133 throw Exception("Could not extract any throbber images from pixbuf"); 00134 } 00135 00136 __current = 0; 00137 set(__pixbufs.front()); 00138 } 00139 00140 00141 /** Draw next image. 00142 * @return always true 00143 */ 00144 bool 00145 Throbber::draw_next() 00146 { 00147 __current = (__current + 1) % __pixbufs.size(); 00148 if ( (__current == 0) && (__pixbufs.size() > 1) ) { 00149 __current = 1; 00150 } 00151 set(__pixbufs[__current]); 00152 00153 return true; 00154 } 00155 00156 00157 /** Set the animation timeout. 00158 * The animation timeout is the time between two frames. It defaults to 100ms. 00159 * @param timeout new timeout for animation in ms 00160 */ 00161 void 00162 Throbber::set_timeout(unsigned int timeout) 00163 { 00164 __timeout = timeout; 00165 } 00166 00167 00168 /** Check if animation is running. 00169 * @return true if animation is currently running, false otherwise. 00170 */ 00171 bool 00172 Throbber::anim_running() 00173 { 00174 return (__timeout_connection && __timeout_connection.connected()); 00175 } 00176 00177 /** Start animation. */ 00178 void 00179 Throbber::start_anim() 00180 { 00181 if ( ! __timeout_connection || ! __timeout_connection.connected()) { 00182 __timeout_connection = Glib::signal_timeout().connect( 00183 sigc::mem_fun(*this, &Throbber::draw_next), __timeout); 00184 } 00185 } 00186 00187 /** Stop animation. */ 00188 void 00189 Throbber::stop_anim() 00190 { 00191 if (__timeout_connection && __timeout_connection.connected()) { 00192 __timeout_connection.disconnect(); 00193 } 00194 00195 __current = 0; 00196 set(__pixbufs.front()); 00197 } 00198 00199 00200 /** Set image from stock ID. 00201 * The image will be overwritten by a running animation or when the 00202 * animation is started again. It will not be automatically reset to this 00203 * stock ID if the animation stops, rather you have to do this by yourself. 00204 * @param stock_id stock ID of image to set 00205 */ 00206 void 00207 Throbber::set_stock(const Gtk::StockID& stock_id) 00208 { 00209 set(stock_id, __icon_size); 00210 } 00211 00212 00213 } // end namespace fawkes