~ubuntu-dev/wxwidgets2.6/upstream-debian

« back to all changes in this revision

Viewing changes to src/gtk/slider.cpp

  • Committer: Daniel T Chen
  • Date: 2006-06-26 10:15:11 UTC
  • Revision ID: crimsun@ubuntu.com-20060626101511-a4436cec4c6d9b35
ImportĀ DebianĀ 2.6.3.2.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/////////////////////////////////////////////////////////////////////////////
 
2
// Name:        gtk/slider.cpp
 
3
// Purpose:
 
4
// Author:      Robert Roebling
 
5
// Id:          $Id: slider.cpp,v 1.58.2.3 2006/03/10 18:45:31 RD Exp $
 
6
// Copyright:   (c) 1998 Robert Roebling
 
7
// Licence:     wxWindows licence
 
8
/////////////////////////////////////////////////////////////////////////////
 
9
 
 
10
#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
 
11
#pragma implementation "slider.h"
 
12
#endif
 
13
 
 
14
// For compilers that support precompilation, includes "wx.h".
 
15
#include "wx/wxprec.h"
 
16
 
 
17
#include "wx/slider.h"
 
18
 
 
19
#if wxUSE_SLIDER
 
20
 
 
21
#include "wx/utils.h"
 
22
#include "wx/math.h"
 
23
#include "wx/gtk/private.h"
 
24
 
 
25
//-----------------------------------------------------------------------------
 
26
// idle system
 
27
//-----------------------------------------------------------------------------
 
28
 
 
29
extern void wxapp_install_idle_handler();
 
30
extern bool g_isIdle;
 
31
 
 
32
//-----------------------------------------------------------------------------
 
33
// data
 
34
//-----------------------------------------------------------------------------
 
35
 
 
36
extern bool g_blockEventsOnDrag;
 
37
 
 
38
// ----------------------------------------------------------------------------
 
39
// helper functions
 
40
// ----------------------------------------------------------------------------
 
41
 
 
42
// compare 2 adjustment values up to some (hardcoded) precision
 
43
static inline bool AreSameAdjustValues(double x, double y)
 
44
{
 
45
    return fabs(x - y) < 0.02;
 
46
}
 
47
 
 
48
static inline int AdjustValueToInt(double x)
 
49
{
 
50
    // we want to round to the nearest integer, i.e. 0.9 is rounded to 1 and
 
51
    // -0.9 is rounded to -1
 
52
    return (int)(x < 0 ? x - 0.5 : x + 0.5);
 
53
}
 
54
 
 
55
// process a scroll event
 
56
static void
 
57
ProcessScrollEvent(wxSlider *win, wxEventType evtType, double dvalue)
 
58
{
 
59
    const int orient = win->HasFlag(wxSL_VERTICAL) ? wxVERTICAL
 
60
                                                   : wxHORIZONTAL;
 
61
 
 
62
    const int value = (int)(dvalue < 0 ? dvalue - 0.5 : dvalue + 0.5);
 
63
 
 
64
    // if we have any "special" event (i.e. the value changed by a line or a
 
65
    // page), send this specific event first
 
66
    if ( evtType != wxEVT_NULL )
 
67
    {
 
68
        wxScrollEvent event( evtType, win->GetId(), value, orient );
 
69
        event.SetEventObject( win );
 
70
        win->GetEventHandler()->ProcessEvent( event );
 
71
    }
 
72
 
 
73
    // but, in any case, except if we're dragging the slider (and so the change
 
74
    // is not definitive), send a generic "changed" event
 
75
    if ( evtType != wxEVT_SCROLL_THUMBTRACK )
 
76
    {
 
77
        wxScrollEvent event(wxEVT_SCROLL_CHANGED, win->GetId(), value, orient);
 
78
        event.SetEventObject( win );
 
79
        win->GetEventHandler()->ProcessEvent( event );
 
80
    }
 
81
 
 
82
    // and also generate a command event for compatibility
 
83
    wxCommandEvent event( wxEVT_COMMAND_SLIDER_UPDATED, win->GetId() );
 
84
    event.SetEventObject( win );
 
85
    event.SetInt( value );
 
86
    win->GetEventHandler()->ProcessEvent( event );
 
87
}
 
88
 
 
89
//-----------------------------------------------------------------------------
 
90
// "value_changed"
 
91
//-----------------------------------------------------------------------------
 
92
 
 
93
extern "C" {
 
94
static void gtk_slider_callback( GtkAdjustment *adjust,
 
95
                                 SCROLLBAR_CBACK_ARG
 
96
                                 wxSlider *win )
 
97
{
 
98
    if (g_isIdle) wxapp_install_idle_handler();
 
99
 
 
100
    if (!win->m_hasVMT) return;
 
101
    if (g_blockEventsOnDrag) return;
 
102
 
 
103
    const double dvalue = adjust->value;
 
104
    const double diff = dvalue - win->m_oldPos;
 
105
    if ( AreSameAdjustValues(diff, 0) )
 
106
        return;
 
107
 
 
108
    wxEventType evtType;
 
109
    if ( win->m_isScrolling )
 
110
        evtType = wxEVT_SCROLL_THUMBTRACK;
 
111
    // it could seem that UP/DOWN are inversed but this is what wxMSW does
 
112
    else if ( AreSameAdjustValues(diff, adjust->step_increment) )
 
113
        evtType = wxEVT_SCROLL_LINEDOWN;
 
114
    else if ( AreSameAdjustValues(diff, -adjust->step_increment) )
 
115
        evtType = wxEVT_SCROLL_LINEUP;
 
116
    else if ( AreSameAdjustValues(diff, adjust->page_increment) )
 
117
        evtType = wxEVT_SCROLL_PAGEDOWN;
 
118
    else if ( AreSameAdjustValues(diff, -adjust->page_increment) )
 
119
        evtType = wxEVT_SCROLL_PAGEUP;
 
120
    else if ( AreSameAdjustValues(adjust->value, adjust->lower) )
 
121
        evtType = wxEVT_SCROLL_TOP;
 
122
    else if ( AreSameAdjustValues(adjust->value, adjust->upper) )
 
123
        evtType = wxEVT_SCROLL_BOTTOM;
 
124
    else
 
125
        evtType = wxEVT_NULL; // wxEVT_SCROLL_CHANGED will still be generated
 
126
 
 
127
    ProcessScrollEvent(win, evtType, dvalue);
 
128
 
 
129
    win->m_oldPos = dvalue;
 
130
}
 
131
 
 
132
#ifdef __WXGTK20__
 
133
static gint gtk_slider_button_press_callback( GtkWidget * /* widget */,
 
134
                                              GdkEventButton * /* gdk_event */,
 
135
                                              wxWindowGTK *win)
 
136
{
 
137
    // indicate that the thumb is being dragged with the mouse
 
138
    win->m_isScrolling = true;
 
139
 
 
140
    return FALSE;
 
141
}
 
142
 
 
143
static gint gtk_slider_button_release_callback( GtkWidget *scale,
 
144
                                                GdkEventButton * /* gdk_event */,
 
145
                                                wxSlider *win)
 
146
{
 
147
    // not scrolling any longer
 
148
    win->m_isScrolling = false;
 
149
 
 
150
    ProcessScrollEvent(win, wxEVT_SCROLL_THUMBRELEASE,
 
151
                       GTK_RANGE(scale)->adjustment->value);
 
152
 
 
153
    return FALSE;
 
154
}
 
155
#endif
 
156
 
 
157
}
 
158
 
 
159
//-----------------------------------------------------------------------------
 
160
// wxSlider
 
161
//-----------------------------------------------------------------------------
 
162
 
 
163
IMPLEMENT_DYNAMIC_CLASS(wxSlider,wxControl)
 
164
 
 
165
bool wxSlider::Create(wxWindow *parent, wxWindowID id,
 
166
        int value, int minValue, int maxValue,
 
167
        const wxPoint& pos, const wxSize& size,
 
168
        long style, const wxValidator& validator, const wxString& name )
 
169
{
 
170
    m_acceptsFocus = TRUE;
 
171
    m_needParent = TRUE;
 
172
 
 
173
    if (!PreCreation( parent, pos, size ) ||
 
174
        !CreateBase( parent, id, pos, size, style, validator, name ))
 
175
    {
 
176
        wxFAIL_MSG( wxT("wxSlider creation failed") );
 
177
        return FALSE;
 
178
    }
 
179
 
 
180
    m_oldPos = 0.0;
 
181
 
 
182
    if (style & wxSL_VERTICAL)
 
183
        m_widget = gtk_vscale_new( (GtkAdjustment *) NULL );
 
184
    else
 
185
        m_widget = gtk_hscale_new( (GtkAdjustment *) NULL );
 
186
 
 
187
    if (style & wxSL_LABELS)
 
188
    {
 
189
        gtk_scale_set_draw_value( GTK_SCALE( m_widget ), TRUE );
 
190
        gtk_scale_set_digits( GTK_SCALE( m_widget ), 0 );
 
191
 
 
192
        /* labels need more space and too small window will
 
193
           cause junk to appear on the dialog */
 
194
        if (style & wxSL_VERTICAL)
 
195
        {
 
196
            wxSize sz( size );
 
197
            if (sz.x < 35)
 
198
            {
 
199
                sz.x = 35;
 
200
                SetSize( sz );
 
201
            }
 
202
        }
 
203
        else
 
204
        {
 
205
            wxSize sz( size );
 
206
            if (sz.y < 35)
 
207
            {
 
208
                sz.y = 35;
 
209
                SetSize( sz );
 
210
            }
 
211
        }
 
212
    }
 
213
    else
 
214
        gtk_scale_set_draw_value( GTK_SCALE( m_widget ), FALSE );
 
215
 
 
216
    m_adjust = gtk_range_get_adjustment( GTK_RANGE(m_widget) );
 
217
 
 
218
#ifdef __WXGTK20__
 
219
    if (style & wxSL_INVERSE)
 
220
        gtk_range_set_inverted( GTK_RANGE(m_widget), TRUE );
 
221
#endif
 
222
 
 
223
    GtkEnableEvents();
 
224
 
 
225
#ifdef __WXGTK20__
 
226
    g_signal_connect (m_widget, "button_press_event",
 
227
                      G_CALLBACK (gtk_slider_button_press_callback),
 
228
                      this);
 
229
    g_signal_connect (m_widget, "button_release_event",
 
230
                      G_CALLBACK (gtk_slider_button_release_callback),
 
231
                      this);
 
232
#endif
 
233
 
 
234
    SetRange( minValue, maxValue );
 
235
    SetValue( value );
 
236
 
 
237
    m_parent->DoAddChild( this );
 
238
 
 
239
    PostCreation(size);
 
240
 
 
241
    return TRUE;
 
242
}
 
243
 
 
244
int wxSlider::GetValue() const
 
245
{
 
246
    return AdjustValueToInt(m_adjust->value);
 
247
}
 
248
 
 
249
void wxSlider::SetValue( int value )
 
250
{
 
251
    double fpos = (double)value;
 
252
    m_oldPos = fpos;
 
253
    if ( AreSameAdjustValues(fpos, m_adjust->value) )
 
254
        return;
 
255
 
 
256
    m_adjust->value = fpos;
 
257
 
 
258
    GtkDisableEvents();
 
259
 
 
260
    gtk_signal_emit_by_name( GTK_OBJECT(m_adjust), "value_changed" );
 
261
 
 
262
    GtkEnableEvents();
 
263
}
 
264
 
 
265
void wxSlider::SetRange( int minValue, int maxValue )
 
266
{
 
267
    double fmin = (double)minValue;
 
268
    double fmax = (double)maxValue;
 
269
 
 
270
    if ((fabs(fmin-m_adjust->lower) < 0.2) &&
 
271
        (fabs(fmax-m_adjust->upper) < 0.2))
 
272
    {
 
273
        return;
 
274
    }
 
275
 
 
276
    m_adjust->lower = fmin;
 
277
    m_adjust->upper = fmax;
 
278
    m_adjust->step_increment = 1.0;
 
279
    m_adjust->page_increment = ceil((fmax-fmin) / 10.0);
 
280
 
 
281
    GtkDisableEvents();
 
282
 
 
283
    gtk_signal_emit_by_name( GTK_OBJECT(m_adjust), "changed" );
 
284
 
 
285
    GtkEnableEvents();
 
286
}
 
287
 
 
288
int wxSlider::GetMin() const
 
289
{
 
290
    return (int)ceil(m_adjust->lower);
 
291
}
 
292
 
 
293
int wxSlider::GetMax() const
 
294
{
 
295
    return (int)ceil(m_adjust->upper);
 
296
}
 
297
 
 
298
void wxSlider::SetPageSize( int pageSize )
 
299
{
 
300
    double fpage = (double)pageSize;
 
301
 
 
302
    if (fabs(fpage-m_adjust->page_increment) < 0.2) return;
 
303
 
 
304
    m_adjust->page_increment = fpage;
 
305
 
 
306
    GtkDisableEvents();
 
307
 
 
308
    gtk_signal_emit_by_name( GTK_OBJECT(m_adjust), "changed" );
 
309
 
 
310
    GtkEnableEvents();
 
311
}
 
312
 
 
313
int wxSlider::GetPageSize() const
 
314
{
 
315
    return (int)ceil(m_adjust->page_increment);
 
316
}
 
317
 
 
318
void wxSlider::SetThumbLength( int len )
 
319
{
 
320
    double flen = (double)len;
 
321
 
 
322
    if (fabs(flen-m_adjust->page_size) < 0.2) return;
 
323
 
 
324
    m_adjust->page_size = flen;
 
325
 
 
326
    GtkDisableEvents();
 
327
 
 
328
    gtk_signal_emit_by_name( GTK_OBJECT(m_adjust), "changed" );
 
329
 
 
330
    GtkEnableEvents();
 
331
}
 
332
 
 
333
int wxSlider::GetThumbLength() const
 
334
{
 
335
    return (int)ceil(m_adjust->page_size);
 
336
}
 
337
 
 
338
void wxSlider::SetLineSize( int WXUNUSED(lineSize) )
 
339
{
 
340
}
 
341
 
 
342
int wxSlider::GetLineSize() const
 
343
{
 
344
    return 0;
 
345
}
 
346
 
 
347
bool wxSlider::IsOwnGtkWindow( GdkWindow *window )
 
348
{
 
349
    GtkRange *range = GTK_RANGE(m_widget);
 
350
#ifdef __WXGTK20__
 
351
    return (range->event_window == window);
 
352
#else
 
353
    return ( (window == GTK_WIDGET(range)->window)
 
354
                || (window == range->trough)
 
355
                || (window == range->slider)
 
356
                || (window == range->step_forw)
 
357
                || (window == range->step_back) );
 
358
#endif
 
359
}
 
360
 
 
361
void wxSlider::GtkDisableEvents()
 
362
{
 
363
    gtk_signal_disconnect_by_func( GTK_OBJECT(m_adjust),
 
364
                        GTK_SIGNAL_FUNC(gtk_slider_callback),
 
365
                        (gpointer) this );
 
366
}
 
367
 
 
368
void wxSlider::GtkEnableEvents()
 
369
{
 
370
    gtk_signal_connect( GTK_OBJECT (m_adjust),
 
371
                        "value_changed",
 
372
                        GTK_SIGNAL_FUNC(gtk_slider_callback),
 
373
                        (gpointer) this );
 
374
}
 
375
 
 
376
// static
 
377
wxVisualAttributes
 
378
wxSlider::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
 
379
{
 
380
    return GetDefaultAttributesFromGTKWidget(gtk_vscale_new);
 
381
}
 
382
 
 
383
#endif