1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/activityindicator.cpp
3 // Purpose: wxActivityIndicator implementation for wxGTK.
4 // Author: Vadim Zeitlin
5 // Created: 2015-03-05
6 // Copyright: (c) 2015 Vadim Zeitlin <vadim@wxwidgets.org>
7 // Licence: wxWindows licence
8 ///////////////////////////////////////////////////////////////////////////////
9
10 // ============================================================================
11 // declarations
12 // ============================================================================
13
14 // ----------------------------------------------------------------------------
15 // headers
16 // ----------------------------------------------------------------------------
17
18 // for compilers that support precompilation, includes "wx.h".
19 #include "wx/wxprec.h"
20
21
22 #if wxUSE_ACTIVITYINDICATOR && defined(__WXGTK220__)
23
24 #include "wx/activityindicator.h"
25
26 #include "wx/math.h"
27
28 #include "wx/gtk/private/wrapgtk.h"
29
30 // Macro return the specified expression only if GTK+ run time version is less
31 // than 2.20 and compiling it only if it is less than 3.0 (which is why this
32 // has to be a macro and not a function).
33 #if defined(__WXGTK220__) && !defined(__WXGTK3__)
34 #define RETURN_IF_NO_GTK_SPINNER(expr) \
35 if ( !wx_is_at_least_gtk2(20) ) { return expr; }
36 #else
37 #define RETURN_IF_NO_GTK_SPINNER(expr)
38 #endif
39
40 // ============================================================================
41 // implementation
42 // ============================================================================
43
44 wxIMPLEMENT_DYNAMIC_CLASS(wxActivityIndicator, wxControl);
45
46 bool
Create(wxWindow * parent,wxWindowID winid,const wxPoint & pos,const wxSize & size,long style,const wxString & name)47 wxActivityIndicator::Create(wxWindow* parent,
48 wxWindowID winid,
49 const wxPoint& pos,
50 const wxSize& size,
51 long style,
52 const wxString& name)
53 {
54 RETURN_IF_NO_GTK_SPINNER(
55 wxActivityIndicatorGeneric::Create(parent, winid, pos, size, style, name)
56 )
57
58 if ( !PreCreation(parent, pos, size) ||
59 !CreateBase(parent, winid, pos, size, style, name) )
60 return false;
61
62 m_widget = gtk_spinner_new();
63 g_object_ref(m_widget);
64
65 m_parent->DoAddChild(this);
66
67 PostCreation(size);
68
69 return true;
70 }
71
Start()72 void wxActivityIndicator::Start()
73 {
74 RETURN_IF_NO_GTK_SPINNER( wxActivityIndicatorGeneric::Start() )
75
76 wxCHECK_RET( m_widget, wxS("Must be created first") );
77
78 gtk_spinner_start(GTK_SPINNER(m_widget));
79 }
80
Stop()81 void wxActivityIndicator::Stop()
82 {
83 RETURN_IF_NO_GTK_SPINNER( wxActivityIndicatorGeneric::Stop() )
84
85 wxCHECK_RET( m_widget, wxS("Must be created first") );
86
87 gtk_spinner_stop(GTK_SPINNER(m_widget));
88 }
89
IsRunning() const90 bool wxActivityIndicator::IsRunning() const
91 {
92 RETURN_IF_NO_GTK_SPINNER( wxActivityIndicatorGeneric::IsRunning() )
93
94 if ( !m_widget )
95 return false;
96
97 gboolean b;
98 g_object_get(m_widget, "active", &b, NULL);
99
100 return b != 0;
101 }
102
DoGetBestClientSize() const103 wxSize wxActivityIndicator::DoGetBestClientSize() const
104 {
105 RETURN_IF_NO_GTK_SPINNER( wxActivityIndicatorGeneric::DoGetBestClientSize() )
106
107 if ( !m_widget )
108 return wxDefaultSize;
109
110 gint w, h;
111
112 #ifdef __WXGTK3__
113 // gtk_widget_get_preferred_size() seems to return the size based on the
114 // current size of the widget and also always returns 0 if it is hidden,
115 // so ask GtkSpinner for its preferred size directly instead of using it.
116 GtkWidgetClass* const wc = GTK_WIDGET_GET_CLASS(m_widget);
117
118 // We're not interested in the natural size (and it's the same as minimal
119 // one anyhow currently), but we still need a non-NULL pointer for it.
120 gint dummy;
121 wc->get_preferred_width(m_widget, &w, &dummy);
122 wc->get_preferred_height(m_widget, &h, &dummy);
123 #else // GTK+ 2
124 // GTK+ 2 doesn't return any valid preferred size for this control, so we
125 // use the size of something roughly equivalent to it.
126 gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &w, &h);
127 #endif // GTK+ 3/2
128
129 // Adjust for the window variant: note that the default size in GTK+ 3 is
130 // really small (12px until ~3.10, 16px since then), so we use this size as
131 // the small size and double it for the normal size.
132 double factor = 0.;
133 switch ( GetWindowVariant() )
134 {
135 case wxWINDOW_VARIANT_MAX:
136 wxFAIL_MSG(wxS("Invalid window variant"));
137 wxFALLTHROUGH;
138
139 case wxWINDOW_VARIANT_NORMAL:
140 factor = 2.;
141 break;
142
143 case wxWINDOW_VARIANT_SMALL:
144 factor = 1.;
145 break;
146
147 case wxWINDOW_VARIANT_MINI:
148 factor = 0.75;
149 break;
150
151 case wxWINDOW_VARIANT_LARGE:
152 // GTK+ 3.11+ limits GtkSpinner size to twice its minimal size, so
153 // the effective factor here is actually just 2, i.e. the same as
154 // for the normal size, but use something larger just in case GTK+
155 // changes its mind again later.
156 factor = 2.5;
157 break;
158 }
159
160 wxASSERT_MSG( !wxIsSameDouble(factor, 0), wxS("Unknown window variant") );
161
162 return wxSize(wxRound(w*factor), wxRound(h*factor));
163 }
164
165 #endif // wxUSE_ACTIVITYINDICATOR
166