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 /** Constructor. 00048 * Special ctor to be used with Gtk::Builder's get_widget_derived(). 00049 * @param cobject Gtk C object 00050 * @param builder Gtk builder 00051 */ 00052 Throbber::Throbber(BaseObjectType* cobject, 00053 const Glib::RefPtr<Gtk::Builder> &builder) 00054 : Gtk::Image(cobject) 00055 { 00056 Gtk::Container *parent = get_parent(); 00057 Gtk::ToolItem *toolitem = dynamic_cast<Gtk::ToolItem *>(parent); 00058 if ( toolitem ) { 00059 ctor(toolitem->get_icon_size()); 00060 } else { 00061 // We have no clue, just try button 00062 ctor(Gtk::IconSize(Gtk::ICON_SIZE_BUTTON)); 00063 } 00064 } 00065 00066 00067 /** Constructor. 00068 * @param icon_size desired icon size. Be aware that the icon may not be available 00069 * in all sizes in the current theme. 00070 */ 00071 Throbber::Throbber(Gtk::IconSize &icon_size) 00072 { 00073 ctor(icon_size); 00074 } 00075 00076 00077 void 00078 Throbber::ctor(Gtk::IconSize icon_size) 00079 { 00080 __timeout = SPINNER_DEFAULT_TIMEOUT; 00081 __icon_size = icon_size; 00082 00083 int isw = 0, ish = 0; 00084 #if GTKMM_MAJOR_VERSION > 2 || ( GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 14 ) 00085 Glib::RefPtr<Gtk::Settings> settings = Gtk::Settings::get_for_screen(get_screen()); 00086 if ( ! Gtk::IconSize::lookup(icon_size, isw, ish, settings) ) { 00087 throw Exception("Could not get icon sizes"); 00088 } 00089 #else 00090 if ( ! Gtk::IconSize::lookup(icon_size, isw, ish) ) { 00091 throw Exception("Could not get icon sizes"); 00092 } 00093 #endif 00094 int requested_size = std::max(isw, ish); 00095 00096 Glib::RefPtr<Gtk::IconTheme> icon_theme = Gtk::IconTheme::get_for_screen(get_screen()); 00097 Gtk::IconInfo icon_info = icon_theme->lookup_icon(SPINNER_ICON_NAME, 00098 requested_size, 00099 Gtk::IconLookupFlags()); 00100 if ( ! icon_info ) { 00101 icon_info = icon_theme->lookup_icon(SPINNER_FALLBACK_ICON_NAME, 00102 requested_size, Gtk::IconLookupFlags()); 00103 if ( ! icon_info ) { 00104 throw Exception("Could not find neither default nor fallback throbber icon"); 00105 } 00106 } 00107 00108 int size = icon_info.get_base_size(); 00109 00110 #ifdef GLIBMM_EXCEPTIONS_ENABLED 00111 Glib::RefPtr<Gdk::Pixbuf> icon = icon_info.load_icon(); 00112 #else 00113 std::auto_ptr<Glib::Error> error; 00114 Glib::RefPtr<Gdk::Pixbuf> icon = icon_info.load_icon(error); 00115 #endif 00116 00117 int pixwidth = icon->get_width(); 00118 int pixheight = icon->get_height(); 00119 00120 for (int y = 0; y < pixheight; y += size) { 00121 for (int x = 0; x < pixwidth ; x += size) { 00122 if ( (x + size <= icon->get_width()) && 00123 (y + size <= icon->get_height()) ) { 00124 Glib::RefPtr<Gdk::Pixbuf> p = Gdk::Pixbuf::create_subpixbuf(icon, x, y, size, size); 00125 __pixbufs.push_back(p); 00126 } 00127 } 00128 } 00129 00130 if ( __pixbufs.empty() ) { 00131 throw Exception("Could not extract any throbber images from pixbuf"); 00132 } 00133 00134 __current = 0; 00135 set(__pixbufs.front()); 00136 } 00137 00138 00139 /** Draw next image. 00140 * @return always true 00141 */ 00142 bool 00143 Throbber::draw_next() 00144 { 00145 __current = (__current + 1) % __pixbufs.size(); 00146 if ( (__current == 0) && (__pixbufs.size() > 1) ) { 00147 __current = 1; 00148 } 00149 set(__pixbufs[__current]); 00150 00151 return true; 00152 } 00153 00154 00155 /** Set the animation timeout. 00156 * The animation timeout is the time between two frames. It defaults to 100ms. 00157 * @param timeout new timeout for animation in ms 00158 */ 00159 void 00160 Throbber::set_timeout(unsigned int timeout) 00161 { 00162 __timeout = timeout; 00163 } 00164 00165 00166 /** Check if animation is running. 00167 * @return true if animation is currently running, false otherwise. 00168 */ 00169 bool 00170 Throbber::anim_running() 00171 { 00172 return (__timeout_connection && __timeout_connection.connected()); 00173 } 00174 00175 /** Start animation. */ 00176 void 00177 Throbber::start_anim() 00178 { 00179 if ( ! __timeout_connection || ! __timeout_connection.connected()) { 00180 __timeout_connection = Glib::signal_timeout().connect( 00181 sigc::mem_fun(*this, &Throbber::draw_next), __timeout); 00182 } 00183 } 00184 00185 /** Stop animation. */ 00186 void 00187 Throbber::stop_anim() 00188 { 00189 if (__timeout_connection && __timeout_connection.connected()) { 00190 __timeout_connection.disconnect(); 00191 } 00192 00193 __current = 0; 00194 set(__pixbufs.front()); 00195 } 00196 00197 00198 /** Set image from stock ID. 00199 * The image will be overwritten by a running animation or when the 00200 * animation is started again. It will not be automatically reset to this 00201 * stock ID if the animation stops, rather you have to do this by yourself. 00202 * @param stock_id stock ID of image to set 00203 */ 00204 void 00205 Throbber::set_stock(const Gtk::StockID& stock_id) 00206 { 00207 set(stock_id, __icon_size); 00208 } 00209 00210 00211 } // end namespace fawkes