]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/spinbutt.cpp
Avoid unexpected negative array index (CID 41).
[wxWidgets.git] / src / gtk / spinbutt.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: spinbutt.cpp
3 // Purpose: wxSpinButton
4 // Author: Robert
5 // Modified by:
6 // RCS-ID: $Id$
7 // Copyright: (c) Robert Roebling
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 // For compilers that support precompilation, includes "wx.h".
12 #include "wx/wxprec.h"
13
14 #include "wx/spinbutt.h"
15
16 #if wxUSE_SPINBTN
17
18 #include "wx/utils.h"
19 #include "wx/math.h"
20 #include "wx/gtk/private.h"
21
22 //-----------------------------------------------------------------------------
23 // data
24 //-----------------------------------------------------------------------------
25
26 extern bool g_blockEventsOnDrag;
27
28 static const float sensitivity = 0.02;
29
30 //-----------------------------------------------------------------------------
31 // "value_changed"
32 //-----------------------------------------------------------------------------
33
34 extern "C" {
35 static void gtk_spinbutt_callback( GtkWidget *WXUNUSED(widget), wxSpinButton *win )
36 {
37 if (g_isIdle) wxapp_install_idle_handler();
38
39 if (!win->m_hasVMT) return;
40 if (g_blockEventsOnDrag) return;
41
42 float diff = win->m_adjust->value - win->m_oldPos;
43 if (fabs(diff) < sensitivity) return;
44
45 wxEventType command = wxEVT_NULL;
46
47 float line_step = win->m_adjust->step_increment;
48
49 if (fabs(diff-line_step) < sensitivity) command = wxEVT_SCROLL_LINEUP;
50 else if (fabs(diff+line_step) < sensitivity) command = wxEVT_SCROLL_LINEDOWN;
51 else command = wxEVT_SCROLL_THUMBTRACK;
52
53 int value = (int)ceil(win->m_adjust->value);
54
55 wxSpinEvent event( command, win->GetId());
56 event.SetPosition( value );
57 event.SetEventObject( win );
58
59 if ((win->GetEventHandler()->ProcessEvent( event )) &&
60 !event.IsAllowed() )
61 {
62 /* program has vetoed */
63 win->m_adjust->value = win->m_oldPos;
64
65 g_signal_handlers_disconnect_by_func (win->m_adjust,
66 (gpointer) gtk_spinbutt_callback,
67 win);
68
69 g_signal_emit_by_name (win->m_adjust, "value_changed");
70
71 g_signal_connect (win->m_adjust, "value_changed",
72 G_CALLBACK (gtk_spinbutt_callback), win);
73 return;
74 }
75
76 win->m_oldPos = win->m_adjust->value;
77
78 /* always send a thumbtrack event */
79 if (command != wxEVT_SCROLL_THUMBTRACK)
80 {
81 command = wxEVT_SCROLL_THUMBTRACK;
82 wxSpinEvent event2( command, win->GetId());
83 event2.SetPosition( value );
84 event2.SetEventObject( win );
85 win->GetEventHandler()->ProcessEvent( event2 );
86 }
87 }
88 }
89
90 //-----------------------------------------------------------------------------
91 // wxSpinButton
92 //-----------------------------------------------------------------------------
93
94 IMPLEMENT_DYNAMIC_CLASS(wxSpinButton,wxControl)
95 IMPLEMENT_DYNAMIC_CLASS(wxSpinEvent, wxNotifyEvent)
96
97 BEGIN_EVENT_TABLE(wxSpinButton, wxControl)
98 EVT_SIZE(wxSpinButton::OnSize)
99 END_EVENT_TABLE()
100
101 bool wxSpinButton::Create(wxWindow *parent,
102 wxWindowID id,
103 const wxPoint& pos,
104 const wxSize& size,
105 long style,
106 const wxString& name)
107 {
108 m_needParent = TRUE;
109
110 wxSize new_size = size,
111 sizeBest = DoGetBestSize();
112 new_size.x = sizeBest.x; // override width always
113 if (new_size.y == -1)
114 new_size.y = sizeBest.y;
115
116 if (!PreCreation( parent, pos, new_size ) ||
117 !CreateBase( parent, id, pos, new_size, style, wxDefaultValidator, name ))
118 {
119 wxFAIL_MSG( wxT("wxXX creation failed") );
120 return FALSE;
121 }
122
123 m_oldPos = 0.0;
124
125 m_adjust = (GtkAdjustment*) gtk_adjustment_new( 0.0, 0.0, 100.0, 1.0, 5.0, 0.0);
126
127 m_widget = gtk_spin_button_new( m_adjust, 0, 0 );
128
129 gtk_spin_button_set_wrap( GTK_SPIN_BUTTON(m_widget),
130 (int)(m_windowStyle & wxSP_WRAP) );
131
132 g_signal_connect (m_adjust, "value_changed",
133 G_CALLBACK (gtk_spinbutt_callback), this);
134
135 m_parent->DoAddChild( this );
136
137 PostCreation(new_size);
138
139 return TRUE;
140 }
141
142 int wxSpinButton::GetMin() const
143 {
144 wxCHECK_MSG( (m_widget != NULL), 0, wxT("invalid spin button") );
145
146 return (int)ceil(m_adjust->lower);
147 }
148
149 int wxSpinButton::GetMax() const
150 {
151 wxCHECK_MSG( (m_widget != NULL), 0, wxT("invalid spin button") );
152
153 return (int)ceil(m_adjust->upper);
154 }
155
156 int wxSpinButton::GetValue() const
157 {
158 wxCHECK_MSG( (m_widget != NULL), 0, wxT("invalid spin button") );
159
160 return (int)ceil(m_adjust->value);
161 }
162
163 void wxSpinButton::SetValue( int value )
164 {
165 wxCHECK_RET( (m_widget != NULL), wxT("invalid spin button") );
166
167 float fpos = (float)value;
168 m_oldPos = fpos;
169 if (fabs(fpos-m_adjust->value) < sensitivity) return;
170
171 m_adjust->value = fpos;
172
173 g_signal_emit_by_name (m_adjust, "value_changed");
174 }
175
176 void wxSpinButton::SetRange(int minVal, int maxVal)
177 {
178 wxCHECK_RET( (m_widget != NULL), wxT("invalid spin button") );
179
180 float fmin = (float)minVal;
181 float fmax = (float)maxVal;
182
183 if ((fabs(fmin-m_adjust->lower) < sensitivity) &&
184 (fabs(fmax-m_adjust->upper) < sensitivity))
185 {
186 return;
187 }
188
189 m_adjust->lower = fmin;
190 m_adjust->upper = fmax;
191
192 g_signal_emit_by_name (m_adjust, "changed");
193
194 // these two calls are required due to some bug in GTK
195 Refresh();
196 SetFocus();
197 }
198
199 void wxSpinButton::OnSize( wxSizeEvent &WXUNUSED(event) )
200 {
201 wxCHECK_RET( (m_widget != NULL), wxT("invalid spin button") );
202
203 m_width = DoGetBestSize().x;
204 gtk_widget_set_size_request( m_widget, m_width, m_height );
205 }
206
207 bool wxSpinButton::IsOwnGtkWindow( GdkWindow *window )
208 {
209 return GTK_SPIN_BUTTON(m_widget)->panel == window;
210 }
211
212 wxSize wxSpinButton::DoGetBestSize() const
213 {
214 wxSize best(15, 26); // FIXME
215 CacheBestSize(best);
216 return best;
217 }
218
219 // static
220 wxVisualAttributes
221 wxSpinButton::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
222 {
223 // TODO: overload to accept functions like gtk_spin_button_new?
224 // Until then use a similar type
225 return GetDefaultAttributesFromGTKWidget(gtk_button_new);
226 }
227
228 #endif