]> git.saurik.com Git - wxWidgets.git/blame - src/gtk1/scrolbar.cpp
Fix memory leak when a spacer is added, and crash when a window is added before wxSiz...
[wxWidgets.git] / src / gtk1 / scrolbar.cpp
CommitLineData
c801d85f 1/////////////////////////////////////////////////////////////////////////////
1e6feb95 2// Name: src/gtk/scrolbar.cpp
c801d85f
KB
3// Purpose:
4// Author: Robert Roebling
f96aa4d9
RR
5// Id: $Id$
6// Copyright: (c) 1998 Robert Roebling
65571936 7// Licence: wxWindows licence
c801d85f
KB
8/////////////////////////////////////////////////////////////////////////////
9
10
14f355c2 11#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
c801d85f
KB
12#pragma implementation "scrolbar.h"
13#endif
14
14f355c2
VS
15// For compilers that support precompilation, includes "wx.h".
16#include "wx/wxprec.h"
dcf924a3
RR
17
18#if wxUSE_SCROLLBAR
19
1e6feb95
VZ
20#include "wx/scrolbar.h"
21
c801d85f 22#include "wx/utils.h"
463c4d71 23#include "wx/math.h"
9e691f46 24#include "wx/gtk/private.h"
83624f79 25
acfd422a
RR
26//-----------------------------------------------------------------------------
27// idle system
28//-----------------------------------------------------------------------------
29
30extern void wxapp_install_idle_handler();
31extern bool g_isIdle;
32
66bd6b93
RR
33//-----------------------------------------------------------------------------
34// data
35//-----------------------------------------------------------------------------
36
37extern bool g_blockEventsOnDrag;
76ed8f8d 38extern bool g_blockEventsOnScroll;
7c2f14ee 39static wxEventType g_currentUpDownEvent = wxEVT_NULL;
66bd6b93 40
aed8ac3f
RR
41static const float sensitivity = 0.02;
42
c801d85f 43//-----------------------------------------------------------------------------
b4071e91 44// "value_changed"
c801d85f
KB
45//-----------------------------------------------------------------------------
46
9e691f46
VZ
47// FIXME: is GtkScrollType really passed to us as 2nd argument?
48
865bb325 49extern "C" {
9e691f46
VZ
50static void gtk_scrollbar_callback( GtkAdjustment *adjust,
51 SCROLLBAR_CBACK_ARG
52 wxScrollBar *win )
a2615ebc 53{
acfd422a
RR
54 if (g_isIdle) wxapp_install_idle_handler();
55
a2053b27 56 if (!win->m_hasVMT) return;
2d17d68f 57 if (g_blockEventsOnDrag) return;
a2615ebc 58
e1811a01 59 float diff = adjust->value - win->m_oldPos;
aed8ac3f 60 if (fabs(diff) < sensitivity) return;
a2615ebc 61
e1811a01
RR
62 win->m_oldPos = adjust->value;
63
9e691f46 64 wxEventType command = GtkScrollTypeToWx(GET_SCROLL_TYPE(win->m_widget));
e1811a01 65
0a07a7d8 66 double dvalue = adjust->value;
a9f21e71 67 int value = (int)(dvalue < 0 ? dvalue - 0.5 : dvalue + 0.5);
a2615ebc 68
f03fc89f 69 int orient = win->HasFlag(wxSB_VERTICAL) ? wxVERTICAL : wxHORIZONTAL;
a2615ebc 70
7c2f14ee
RR
71 // throw a LINEUP / LINEDOWN event if necessary
72 if (g_currentUpDownEvent != wxEVT_NULL)
73 {
74 wxScrollEvent event( g_currentUpDownEvent, win->GetId(), value, orient );
75 event.SetEventObject( win );
76 win->GetEventHandler()->ProcessEvent( event );
77 }
1b24b2b4
RR
78
79 // throw other event (wxEVT_SCROLL_THUMBTRACK)
80 wxScrollEvent event( command, win->GetId(), value, orient );
81 event.SetEventObject( win );
82 win->GetEventHandler()->ProcessEvent( event );
7c2f14ee 83
c801d85f 84/*
2d17d68f
RR
85 wxCommandEvent cevent( wxEVT_COMMAND_SCROLLBAR_UPDATED, win->GetId() );
86 cevent.SetEventObject( win );
87 win->ProcessEvent( cevent );
c801d85f 88*/
6de97a3b 89}
865bb325 90}
c801d85f 91
cb43b372
RR
92//-----------------------------------------------------------------------------
93// "button_press_event" from slider
94//-----------------------------------------------------------------------------
865bb325 95extern "C" {
a2615ebc
VZ
96static gint gtk_scrollbar_button_press_callback( GtkRange *widget,
97 GdkEventButton *gdk_event,
f03fc89f 98 wxScrollBar *win )
cb43b372 99{
acfd422a
RR
100 if (g_isIdle) wxapp_install_idle_handler();
101
7c2f14ee
RR
102 // check if a LINEUP/LINEDOWN event must be thrown
103 // I suppose here the size of scrollbar top/bottom buttons is 16px height
104 if (gdk_event->type == GDK_BUTTON_PRESS && gdk_event->button == 1)
105 {
106 int scroll_height, mouse_pos;
107
108 // get the mouse position when the click is done
03ed1dae 109 if (win->HasFlag(wxSB_VERTICAL))
7c2f14ee
RR
110 {
111 scroll_height = GTK_WIDGET(widget)->allocation.height - 16;
112 mouse_pos = (int)gdk_event->y;
113 }
114 else
115 {
116 scroll_height = GTK_WIDGET(widget)->allocation.width - 16;
117 mouse_pos = (int)gdk_event->x;
118 }
119
120 // compare mouse position to scrollbar height
121 if (mouse_pos > scroll_height)
122 g_currentUpDownEvent = wxEVT_SCROLL_LINEDOWN;
123 else if (mouse_pos < 16)
124 g_currentUpDownEvent = wxEVT_SCROLL_LINEUP;
125 }
2a23d363 126
9e691f46 127#ifndef __WXGTK20__
7c2f14ee 128 // There is no slider field any more
2a23d363 129 win->m_isScrolling = (gdk_event->window == widget->slider);
9e691f46 130#endif
a2615ebc 131
acfd422a 132 return FALSE;
cb43b372 133}
865bb325 134}
cb43b372
RR
135
136//-----------------------------------------------------------------------------
137// "button_release_event" from slider
138//-----------------------------------------------------------------------------
139
865bb325 140extern "C" {
a2615ebc
VZ
141static gint
142gtk_scrollbar_button_release_callback( GtkRange *WXUNUSED(widget),
143 GdkEventButton *WXUNUSED(gdk_event),
144 wxScrollBar *win )
cb43b372 145{
a2615ebc
VZ
146 if (g_isIdle)
147 wxapp_install_idle_handler();
148
2a23d363
RR
149 if (win->m_isScrolling)
150 {
7d56fb8f 151 wxEventType command = wxEVT_SCROLL_THUMBRELEASE;
2a23d363 152 int value = (int)ceil(win->m_adjust->value);
193e19cf 153 int orient = win->HasFlag(wxSB_VERTICAL) ? wxVERTICAL : wxHORIZONTAL;
2a23d363 154
193e19cf 155 wxScrollEvent event( command, win->GetId(), value, orient );
2a23d363
RR
156 event.SetEventObject( win );
157 win->GetEventHandler()->ProcessEvent( event );
158 }
a2615ebc 159
2a23d363 160 win->m_isScrolling = FALSE;
a2615ebc 161
7c2f14ee
RR
162 // reset the LINEUP/LINEDOWN flag when the mouse button is released
163 g_currentUpDownEvent = wxEVT_NULL;
164
2d17d68f 165 return FALSE;
cb43b372 166}
865bb325 167}
cb43b372 168
b4071e91
RR
169//-----------------------------------------------------------------------------
170// wxScrollBar
171//-----------------------------------------------------------------------------
172
c801d85f
KB
173IMPLEMENT_DYNAMIC_CLASS(wxScrollBar,wxControl)
174
0a07a7d8 175wxScrollBar::~wxScrollBar()
c801d85f 176{
6de97a3b 177}
c801d85f 178
debe6624 179bool wxScrollBar::Create(wxWindow *parent, wxWindowID id,
c801d85f 180 const wxPoint& pos, const wxSize& size,
6de97a3b 181 long style, const wxValidator& validator, const wxString& name )
c801d85f 182{
2d17d68f
RR
183 m_needParent = TRUE;
184 m_acceptsFocus = TRUE;
a2615ebc 185
4dcaf11a
RR
186 if (!PreCreation( parent, pos, size ) ||
187 !CreateBase( parent, id, pos, size, style, validator, name ))
188 {
223d09f6 189 wxFAIL_MSG( wxT("wxScrollBar creation failed") );
0a07a7d8 190 return FALSE;
4dcaf11a 191 }
6de97a3b 192
2d17d68f 193 m_oldPos = 0.0;
c801d85f 194
d9bd1494 195 if ((style & wxSB_VERTICAL) == wxSB_VERTICAL)
2d17d68f 196 m_widget = gtk_vscrollbar_new( (GtkAdjustment *) NULL );
d9bd1494
SB
197 else
198 m_widget = gtk_hscrollbar_new( (GtkAdjustment *) NULL );
199
2d17d68f 200 m_adjust = gtk_range_get_adjustment( GTK_RANGE(m_widget) );
a2615ebc
VZ
201
202 gtk_signal_connect( GTK_OBJECT(m_adjust),
2d17d68f 203 "value_changed",
a2615ebc 204 (GtkSignalFunc) gtk_scrollbar_callback,
f03fc89f 205 (gpointer) this );
a2615ebc 206 gtk_signal_connect( GTK_OBJECT(m_widget),
2d17d68f 207 "button_press_event",
a2615ebc 208 (GtkSignalFunc)gtk_scrollbar_button_press_callback,
f03fc89f 209 (gpointer) this );
a2615ebc 210 gtk_signal_connect( GTK_OBJECT(m_widget),
2d17d68f 211 "button_release_event",
a2615ebc 212 (GtkSignalFunc)gtk_scrollbar_button_release_callback,
f03fc89f 213 (gpointer) this );
cb43b372 214
f03fc89f 215 m_parent->DoAddChild( this );
a2615ebc 216
abdeb9e7 217 PostCreation(size);
a2615ebc 218
2d17d68f 219 return TRUE;
6de97a3b 220}
c801d85f 221
0a07a7d8 222int wxScrollBar::GetThumbPosition() const
c801d85f 223{
0a07a7d8 224 double val = m_adjust->value;
a9f21e71 225 return (int)(val < 0 ? val - 0.5 : val + 0.5);
6de97a3b 226}
c801d85f
KB
227
228int wxScrollBar::GetThumbSize() const
229{
2d17d68f 230 return (int)(m_adjust->page_size+0.5);
6de97a3b 231}
c801d85f
KB
232
233int wxScrollBar::GetPageSize() const
234{
2d17d68f 235 return (int)(m_adjust->page_increment+0.5);
6de97a3b 236}
c801d85f
KB
237
238int wxScrollBar::GetRange() const
239{
2d17d68f 240 return (int)(m_adjust->upper+0.5);
6de97a3b 241}
c801d85f 242
4fabb575 243void wxScrollBar::SetThumbPosition( int viewStart )
c801d85f 244{
2d17d68f 245 if (m_isScrolling) return;
a2615ebc 246
2d17d68f
RR
247 float fpos = (float)viewStart;
248 m_oldPos = fpos;
249 if (fabs(fpos-m_adjust->value) < 0.2) return;
250 m_adjust->value = fpos;
a2615ebc
VZ
251
252 gtk_signal_disconnect_by_func( GTK_OBJECT(m_adjust),
253 (GtkSignalFunc) gtk_scrollbar_callback,
2a23d363 254 (gpointer) this );
a2615ebc 255
2d17d68f 256 gtk_signal_emit_by_name( GTK_OBJECT(m_adjust), "value_changed" );
a2615ebc
VZ
257
258 gtk_signal_connect( GTK_OBJECT(m_adjust),
2a23d363 259 "value_changed",
a2615ebc 260 (GtkSignalFunc) gtk_scrollbar_callback,
2a23d363 261 (gpointer) this );
6de97a3b 262}
c801d85f 263
debe6624
JS
264void wxScrollBar::SetScrollbar( int position, int thumbSize, int range, int pageSize,
265 bool WXUNUSED(refresh) )
c801d85f 266{
2d17d68f
RR
267 float fpos = (float)position;
268 float frange = (float)range;
269 float fthumb = (float)thumbSize;
270 float fpage = (float)pageSize;
a2615ebc 271
2d17d68f
RR
272 if ((fabs(frange-m_adjust->upper) < 0.2) &&
273 (fabs(fthumb-m_adjust->page_size) < 0.2) &&
274 (fabs(fpage-m_adjust->page_increment) < 0.2))
275 {
276 SetThumbPosition( position );
277 return;
278 }
a2615ebc 279
2d17d68f 280 m_oldPos = fpos;
a2615ebc 281
2d17d68f
RR
282 m_adjust->lower = 0.0;
283 m_adjust->upper = frange;
284 m_adjust->value = fpos;
285 m_adjust->step_increment = 1.0;
286 m_adjust->page_increment = (float)(wxMax(fpage,0));
287 m_adjust->page_size = fthumb;
288
289 gtk_signal_emit_by_name( GTK_OBJECT(m_adjust), "changed" );
6de97a3b 290}
c801d85f 291
2d17d68f 292/* Backward compatibility */
0a07a7d8 293int wxScrollBar::GetValue() const
c801d85f 294{
2d17d68f 295 return GetThumbPosition();
6de97a3b 296}
c801d85f 297
debe6624 298void wxScrollBar::SetValue( int viewStart )
c801d85f 299{
2d17d68f 300 SetThumbPosition( viewStart );
6de97a3b 301}
c801d85f
KB
302
303void wxScrollBar::GetValues( int *viewStart, int *viewLength, int *objectLength, int *pageLength ) const
304{
2d17d68f
RR
305 int pos = (int)(m_adjust->value+0.5);
306 int thumb = (int)(m_adjust->page_size+0.5);
307 int page = (int)(m_adjust->page_increment+0.5);
308 int range = (int)(m_adjust->upper+0.5);
a2615ebc 309
2d17d68f
RR
310 *viewStart = pos;
311 *viewLength = range;
312 *objectLength = thumb;
313 *pageLength = page;
6de97a3b 314}
c801d85f
KB
315
316int wxScrollBar::GetViewLength() const
317{
2d17d68f 318 return (int)(m_adjust->upper+0.5);
6de97a3b 319}
c801d85f
KB
320
321int wxScrollBar::GetObjectLength() const
322{
2d17d68f 323 return (int)(m_adjust->page_size+0.5);
6de97a3b 324}
c801d85f 325
debe6624 326void wxScrollBar::SetPageSize( int pageLength )
c801d85f 327{
2d17d68f
RR
328 int pos = (int)(m_adjust->value+0.5);
329 int thumb = (int)(m_adjust->page_size+0.5);
330 int range = (int)(m_adjust->upper+0.5);
331 SetScrollbar( pos, thumb, range, pageLength );
6de97a3b 332}
c801d85f 333
debe6624 334void wxScrollBar::SetObjectLength( int objectLength )
c801d85f 335{
2d17d68f
RR
336 int pos = (int)(m_adjust->value+0.5);
337 int page = (int)(m_adjust->page_increment+0.5);
338 int range = (int)(m_adjust->upper+0.5);
339 SetScrollbar( pos, objectLength, range, page );
6de97a3b 340}
c801d85f 341
debe6624 342void wxScrollBar::SetViewLength( int viewLength )
c801d85f 343{
2d17d68f
RR
344 int pos = (int)(m_adjust->value+0.5);
345 int thumb = (int)(m_adjust->page_size+0.5);
346 int page = (int)(m_adjust->page_increment+0.5);
347 SetScrollbar( pos, thumb, viewLength, page );
6de97a3b 348}
c801d85f 349
b4071e91
RR
350bool wxScrollBar::IsOwnGtkWindow( GdkWindow *window )
351{
2d17d68f 352 GtkRange *range = GTK_RANGE(m_widget);
9e691f46
VZ
353 return ( (window == GTK_WIDGET(range)->window)
354#ifndef __WXGTK20__
355 || (window == range->trough)
356 || (window == range->slider)
357 || (window == range->step_forw)
358 || (window == range->step_back)
359#endif // GTK+ 1.x
360 );
b4071e91 361}
58614078 362
7f980cff
VS
363wxSize wxScrollBar::DoGetBestSize() const
364{
365 return wxControl::DoGetBestSize();
366}
367
9d522606
RD
368// static
369wxVisualAttributes
370wxScrollBar::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
371{
372 return GetDefaultAttributesFromGTKWidget(gtk_vscrollbar_new);
373}
374
dcf924a3 375#endif