]> git.saurik.com Git - wxWidgets.git/blame - src/gtk1/scrolwin.cpp
added pragmas to disable icc warning when va_arg is used with a pointer type
[wxWidgets.git] / src / gtk1 / scrolwin.cpp
CommitLineData
30954328 1/////////////////////////////////////////////////////////////////////////////
e1437456 2// Name: gtk/scrolwin.cpp
30954328 3// Purpose: wxScrolledWindow implementation
47a3ff38 4// Author: Robert Roebling
566d84a7 5// Modified by: Ron Lee
30954328
RR
6// Created: 01/02/97
7// RCS-ID: $Id$
47a3ff38 8// Copyright: (c) Robert Roebling
65571936 9// Licence: wxWindows licence
30954328
RR
10/////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
30954328
RR
20// For compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
24 #pragma hdrstop
25#endif
26
e1bf3ad3 27#include "wx/scrolwin.h"
30954328
RR
28#include "wx/utils.h"
29#include "wx/dcclient.h"
30954328 30#include "wx/panel.h"
30486297 31#include "wx/sizer.h"
30954328 32
9e691f46 33#include "wx/gtk/private.h"
30954328
RR
34#include "wx/gtk/win_gtk.h"
35
36// ----------------------------------------------------------------------------
37// event tables
38// ----------------------------------------------------------------------------
39
40BEGIN_EVENT_TABLE(wxScrolledWindow, wxPanel)
d9a4f620 41 EVT_SCROLLWIN(wxScrolledWindow::OnScroll)
30954328
RR
42 EVT_SIZE(wxScrolledWindow::OnSize)
43 EVT_PAINT(wxScrolledWindow::OnPaint)
44 EVT_CHAR(wxScrolledWindow::OnChar)
45END_EVENT_TABLE()
46
47IMPLEMENT_DYNAMIC_CLASS(wxScrolledWindow, wxPanel)
48
49// ============================================================================
50// implementation
51// ============================================================================
52
53//-----------------------------------------------------------------------------
54// data
55//-----------------------------------------------------------------------------
56
57extern bool g_blockEventsOnDrag;
cf19b0bd 58extern bool g_blockEventsOnScroll;
30954328
RR
59
60//-----------------------------------------------------------------------------
61// idle system
62//-----------------------------------------------------------------------------
63
64extern void wxapp_install_idle_handler();
65extern bool g_isIdle;
66
67//-----------------------------------------------------------------------------
68// "value_changed" from m_vAdjust
69//-----------------------------------------------------------------------------
70
865bb325 71extern "C" {
9e691f46
VZ
72static void gtk_scrolled_window_vscroll_callback( GtkAdjustment *adjust,
73 SCROLLBAR_CBACK_ARG
74 wxScrolledWindow *win )
30954328
RR
75{
76 if (g_isIdle)
77 wxapp_install_idle_handler();
78
79 if (g_blockEventsOnDrag) return;
80
81 if (!win->m_hasVMT) return;
47a3ff38 82
9e691f46
VZ
83 win->GtkVScroll( adjust->value,
84 GET_SCROLL_TYPE(GTK_SCROLLED_WINDOW(win->m_widget)->vscrollbar) );
30954328 85}
865bb325 86}
30954328
RR
87
88//-----------------------------------------------------------------------------
89// "value_changed" from m_hAdjust
90//-----------------------------------------------------------------------------
91
865bb325 92extern "C" {
9e691f46
VZ
93static void gtk_scrolled_window_hscroll_callback( GtkAdjustment *adjust,
94 SCROLLBAR_CBACK_ARG
95 wxScrolledWindow *win )
30954328
RR
96{
97 if (g_isIdle)
98 wxapp_install_idle_handler();
99
100 if (g_blockEventsOnDrag) return;
101 if (!win->m_hasVMT) return;
102
9e691f46
VZ
103 win->GtkHScroll( adjust->value,
104 GET_SCROLL_TYPE(GTK_SCROLLED_WINDOW(win->m_widget)->hscrollbar) );
30954328 105}
865bb325 106}
30954328 107
cf19b0bd
RR
108//-----------------------------------------------------------------------------
109// "button_press_event" from scrollbar
110//-----------------------------------------------------------------------------
111
865bb325 112extern "C" {
cf19b0bd
RR
113static gint gtk_scrollbar_button_press_callback( GtkRange *widget,
114 GdkEventButton *gdk_event,
115 wxWindowGTK *win)
116{
117 if (g_isIdle)
118 wxapp_install_idle_handler();
119
120 g_blockEventsOnScroll = TRUE;
9e691f46
VZ
121
122 // FIXME: there is no slider field any more, what was meant here?
123#ifndef __WXGTK20__
cf19b0bd 124 win->m_isScrolling = (gdk_event->window == widget->slider);
9e691f46 125#endif
cf19b0bd
RR
126
127 return FALSE;
128}
865bb325 129}
cf19b0bd
RR
130
131//-----------------------------------------------------------------------------
132// "button_release_event" from scrollbar
133//-----------------------------------------------------------------------------
134
865bb325 135extern "C" {
cf19b0bd
RR
136static gint gtk_scrollbar_button_release_callback( GtkRange *widget,
137 GdkEventButton *WXUNUSED(gdk_event),
138 wxWindowGTK *win)
139{
140// don't test here as we can release the mouse while being over
141// a different window than the slider
142//
143// if (gdk_event->window != widget->slider) return FALSE;
144
145 g_blockEventsOnScroll = FALSE;
146
147 if (win->m_isScrolling)
148 {
149 wxEventType command = wxEVT_SCROLLWIN_THUMBRELEASE;
150 int value = -1;
151 int dir = -1;
152
153 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(win->m_widget);
154 if (widget == GTK_RANGE(scrolledWindow->hscrollbar))
155 {
156 value = (int)(win->m_hAdjust->value+0.5);
157 dir = wxHORIZONTAL;
158 }
159 if (widget == GTK_RANGE(scrolledWindow->vscrollbar))
160 {
161 value = (int)(win->m_vAdjust->value+0.5);
162 dir = wxVERTICAL;
163 }
164
165 wxScrollWinEvent event( command, value, dir );
166 event.SetEventObject( win );
167 win->GetEventHandler()->ProcessEvent( event );
168 }
169
170 win->m_isScrolling = FALSE;
171
172 return FALSE;
173}
865bb325 174}
cf19b0bd 175
30954328
RR
176//-----------------------------------------------------------------------------
177// InsertChild for wxScrolledWindow
178//-----------------------------------------------------------------------------
179
180static void wxInsertChildInScrolledWindow( wxWindow* parent, wxWindow* child )
181{
830ed6d9
RR
182 // The window might have been scrolled already, do we
183 // have to adapt the position.
30954328
RR
184 GtkPizza *pizza = GTK_PIZZA(parent->m_wxwindow);
185 child->m_x += pizza->xoffset;
186 child->m_y += pizza->yoffset;
187
188 gtk_pizza_put( GTK_PIZZA(parent->m_wxwindow),
189 GTK_WIDGET(child->m_widget),
190 child->m_x,
191 child->m_y,
192 child->m_width,
193 child->m_height );
194}
195
196// ----------------------------------------------------------------------------
197// wxScrolledWindow creation
198// ----------------------------------------------------------------------------
199
830ed6d9 200void wxScrolledWindow::Init()
30954328
RR
201{
202 m_xScrollPixelsPerLine = 0;
203 m_yScrollPixelsPerLine = 0;
204 m_xScrollingEnabled = TRUE;
205 m_yScrollingEnabled = TRUE;
206 m_xScrollPosition = 0;
207 m_yScrollPosition = 0;
30954328
RR
208 m_xScrollLinesPerPage = 0;
209 m_yScrollLinesPerPage = 0;
210 m_targetWindow = (wxWindow*) NULL;
d9a4f620
RR
211 m_scaleX = 1.0;
212 m_scaleY = 1.0;
e1437456 213 m_hasScrolling = TRUE;
30954328
RR
214}
215
216bool wxScrolledWindow::Create(wxWindow *parent,
217 wxWindowID id,
218 const wxPoint& pos,
219 const wxSize& size,
220 long style,
221 const wxString& name)
222{
830ed6d9
RR
223 Init();
224
30954328
RR
225 if (!PreCreation( parent, pos, size ) ||
226 !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
227 {
228 wxFAIL_MSG( wxT("wxWindow creation failed") );
229 return FALSE;
230 }
231
232 m_insertCallback = wxInsertChildInScrolledWindow;
39c869a6 233
30954328
RR
234 m_targetWindow = this;
235
236 m_widget = gtk_scrolled_window_new( (GtkAdjustment *) NULL, (GtkAdjustment *) NULL );
237 GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
238
239 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(m_widget);
240
241 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
242 scroll_class->scrollbar_spacing = 0;
243
244 gtk_scrolled_window_set_policy( scrolledWindow, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
245
246 m_hAdjust = gtk_range_get_adjustment( GTK_RANGE(scrolledWindow->hscrollbar) );
247 m_vAdjust = gtk_range_get_adjustment( GTK_RANGE(scrolledWindow->vscrollbar) );
248
249 m_wxwindow = gtk_pizza_new();
250
251 gtk_container_add( GTK_CONTAINER(m_widget), m_wxwindow );
252
253 GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
254
255 if (HasFlag(wxRAISED_BORDER))
256 {
257 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_OUT );
258 }
259 else if (HasFlag(wxSUNKEN_BORDER))
260 {
261 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_IN );
262 }
263 else if (HasFlag(wxSIMPLE_BORDER))
264 {
265 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_THIN );
266 }
267 else
268 {
269 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_NONE );
270 }
271
272 GTK_WIDGET_SET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
273 m_acceptsFocus = TRUE;
274
275 // I _really_ don't want scrollbars in the beginning
276 m_vAdjust->lower = 0.0;
277 m_vAdjust->upper = 1.0;
278 m_vAdjust->value = 0.0;
279 m_vAdjust->step_increment = 1.0;
4ca24f18 280 m_vAdjust->page_increment = 2.0;
30954328
RR
281 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
282 m_hAdjust->lower = 0.0;
283 m_hAdjust->upper = 1.0;
284 m_hAdjust->value = 0.0;
285 m_hAdjust->step_increment = 1.0;
4ca24f18 286 m_hAdjust->page_increment = 2.0;
30954328
RR
287 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
288
830ed6d9
RR
289 // Handlers for new scrollbar values
290 GtkVConnectEvent();
291 GtkHConnectEvent();
30954328 292
cf19b0bd 293 // these handlers block mouse events to any window during scrolling such as
77ffb593 294 // motion events and prevent GTK and wxWidgets from fighting over where the
cf19b0bd
RR
295 // slider should be
296
297 gtk_signal_connect( GTK_OBJECT(scrolledWindow->vscrollbar), "button_press_event",
298 (GtkSignalFunc)gtk_scrollbar_button_press_callback, (gpointer) this );
299
300 gtk_signal_connect( GTK_OBJECT(scrolledWindow->hscrollbar), "button_press_event",
301 (GtkSignalFunc)gtk_scrollbar_button_press_callback, (gpointer) this );
302
303 gtk_signal_connect( GTK_OBJECT(scrolledWindow->vscrollbar), "button_release_event",
304 (GtkSignalFunc)gtk_scrollbar_button_release_callback, (gpointer) this );
305
306 gtk_signal_connect( GTK_OBJECT(scrolledWindow->hscrollbar), "button_release_event",
307 (GtkSignalFunc)gtk_scrollbar_button_release_callback, (gpointer) this );
308
30954328
RR
309 gtk_widget_show( m_wxwindow );
310
311 if (m_parent)
312 m_parent->DoAddChild( this );
30486297 313
c9c4b3a0 314 m_focusWidget = m_wxwindow;
30954328
RR
315
316 PostCreation();
317
318 Show( TRUE );
2b5f62a0 319
30954328
RR
320 return TRUE;
321}
322
30954328
RR
323// ----------------------------------------------------------------------------
324// setting scrolling parameters
325// ----------------------------------------------------------------------------
326
566d84a7
RL
327void wxScrolledWindow::DoSetVirtualSize( int x, int y )
328{
329 wxPanel::DoSetVirtualSize( x, y );
330 AdjustScrollbars();
92aff599 331
92aff599
RL
332 if (GetAutoLayout())
333 Layout();
566d84a7
RL
334}
335
844adaa4
JS
336// wxWindow's GetBestVirtualSize returns the actual window size,
337// whereas we want to return the virtual size
338wxSize wxScrolledWindow::GetBestVirtualSize() const
339{
340 wxSize clientSize( GetClientSize() );
341 if (GetSizer())
342 {
343 wxSize minSize( GetSizer()->CalcMin() );
344
345 return wxSize( wxMax( clientSize.x, minSize.x ), wxMax( clientSize.y, minSize.y ) );
346 }
347 else
348 return clientSize;
349}
350
351// return the size best suited for the current window
352// (this isn't a virtual size, this is a sensible size for the window)
353wxSize wxScrolledWindow::DoGetBestSize() const
354{
355 wxSize best;
356
357 if ( GetSizer() )
358 {
359 wxSize b = GetSizer()->GetMinSize();
360
361 // Only use the content to set the window size in the direction
362 // where there's no scrolling; otherwise we're going to get a huge
363 // window in the direction in which scrolling is enabled
364 int ppuX, ppuY;
365 GetScrollPixelsPerUnit(& ppuX, & ppuY);
366
367 wxSize minSize;
368 if ( GetMinSize().IsFullySpecified() )
369 minSize = GetMinSize();
370 else
371 minSize = GetSize();
372
373 if (ppuX > 0)
374 b.x = minSize.x;
375 if (ppuY > 0)
376 b.y = minSize.y;
377 best = b;
378 }
379 else
380 return wxWindow::DoGetBestSize();
381
382 // Add any difference between size and client size
383 wxSize diff = GetSize() - GetClientSize();
384 best.x += wxMax(0, diff.x);
385 best.y += wxMax(0, diff.y);
386
387 return best;
388}
389
30954328
RR
390/*
391 * pixelsPerUnitX/pixelsPerUnitY: number of pixels per unit (e.g. pixels per text line)
392 * noUnitsX/noUnitsY: : no. units per scrollbar
393 */
566d84a7
RL
394void wxScrolledWindow::SetScrollbars( int pixelsPerUnitX, int pixelsPerUnitY,
395 int noUnitsX, int noUnitsY,
396 int xPos, int yPos, bool noRefresh )
30954328 397{
1adff2f5
JS
398 int xs, ys;
399 GetViewStart (& xs, & ys);
400
401 int old_x = m_xScrollPixelsPerLine * xs;
402 int old_y = m_yScrollPixelsPerLine * ys;
30486297 403
30954328
RR
404 m_xScrollPixelsPerLine = pixelsPerUnitX;
405 m_yScrollPixelsPerLine = pixelsPerUnitY;
39c869a6 406
566d84a7
RL
407 m_hAdjust->value = m_xScrollPosition = xPos;
408 m_vAdjust->value = m_yScrollPosition = yPos;
30954328 409
2b5f62a0
VZ
410 // Setting hints here should arguably be deprecated, but without it
411 // a sizer might override this manual scrollbar setting in old code.
878ddad5 412 // m_targetWindow->SetVirtualSizeHints( noUnitsX * pixelsPerUnitX, noUnitsY * pixelsPerUnitY );
30486297 413
f18f464c
VZ
414 int w = noUnitsX * pixelsPerUnitX;
415 int h = noUnitsY * pixelsPerUnitY;
416 m_targetWindow->SetVirtualSize( w ? w : wxDefaultCoord,
417 h ? h : wxDefaultCoord);
2b5f62a0 418
ec7482df
RR
419 if (!noRefresh)
420 {
421 int new_x = m_xScrollPixelsPerLine * m_xScrollPosition;
422 int new_y = m_yScrollPixelsPerLine * m_yScrollPosition;
30486297 423
566d84a7 424 m_targetWindow->ScrollWindow( old_x - new_x, old_y - new_y );
ec7482df 425 }
30954328
RR
426}
427
428void wxScrolledWindow::AdjustScrollbars()
429{
430 int w, h;
566d84a7
RL
431 int vw, vh;
432
30954328 433 m_targetWindow->GetClientSize( &w, &h );
566d84a7 434 m_targetWindow->GetVirtualSize( &vw, &vh );
878ddad5 435
30954328 436 if (m_xScrollPixelsPerLine == 0)
4ca24f18
RR
437 {
438 m_hAdjust->upper = 1.0;
47a3ff38 439 m_hAdjust->page_increment = 1.0;
30954328 440 m_hAdjust->page_size = 1.0;
4ca24f18 441 }
30954328 442 else
4ca24f18 443 {
878ddad5
RR
444 m_hAdjust->upper = (vw+m_xScrollPixelsPerLine-1) / m_xScrollPixelsPerLine;
445 m_hAdjust->page_size = w / m_xScrollPixelsPerLine;
bf67b135 446 m_hAdjust->page_increment = w / m_xScrollPixelsPerLine;
39c869a6 447
878ddad5
RR
448 // Special case. When client and virtual size are very close but
449 // the client is big enough, kill scrollbar.
450
451 if ((m_hAdjust->page_size < m_hAdjust->upper) && (w >= vw))
452 m_hAdjust->page_size += 1.0;
453
566d84a7
RL
454 // If the scrollbar hits the right side, move the window
455 // right to keep it from over extending.
4ca24f18 456
2b5f62a0 457 if ((m_hAdjust->value != 0.0) && (m_hAdjust->value + m_hAdjust->page_size > m_hAdjust->upper))
566d84a7 458 {
2b5f62a0
VZ
459 m_hAdjust->value = m_hAdjust->upper - m_hAdjust->page_size;
460 if (m_hAdjust->value < 0.0)
461 m_hAdjust->value = 0.0;
462
b03f81b7 463 if (GetChildren().GetCount() == 0)
2b5f62a0
VZ
464 m_xScrollPosition = (int)m_hAdjust->value; // This is enough without child windows
465 else
466 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "value_changed" ); // Actually scroll window
566d84a7 467 }
4ca24f18
RR
468 }
469
30954328 470 if (m_yScrollPixelsPerLine == 0)
4ca24f18
RR
471 {
472 m_vAdjust->upper = 1.0;
47a3ff38 473 m_vAdjust->page_increment = 1.0;
30954328 474 m_vAdjust->page_size = 1.0;
4ca24f18 475 }
30954328 476 else
4ca24f18 477 {
878ddad5
RR
478 m_vAdjust->upper = (vh+m_yScrollPixelsPerLine-1) / m_yScrollPixelsPerLine;
479 m_vAdjust->page_size = h / m_yScrollPixelsPerLine;
bf67b135 480 m_vAdjust->page_increment = h / m_yScrollPixelsPerLine;
878ddad5
RR
481
482 if ((m_vAdjust->page_size < m_vAdjust->upper) && (h >= vh))
483 m_vAdjust->page_size += 1.0;
39c869a6 484
2b5f62a0 485 if ((m_vAdjust->value != 0.0) && (m_vAdjust->value + m_vAdjust->page_size > m_vAdjust->upper))
566d84a7 486 {
2b5f62a0
VZ
487 m_vAdjust->value = m_vAdjust->upper - m_vAdjust->page_size;
488 if (m_vAdjust->value < 0.0)
489 m_vAdjust->value = 0.0;
490
b03f81b7 491 if (GetChildren().GetCount() == 0)
2b5f62a0
VZ
492 m_yScrollPosition = (int)m_vAdjust->value;
493 else
494 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "value_changed" );
566d84a7 495 }
4ca24f18
RR
496 }
497
47a3ff38
RR
498 m_xScrollLinesPerPage = (int)(m_hAdjust->page_increment + 0.5);
499 m_yScrollLinesPerPage = (int)(m_vAdjust->page_increment + 0.5);
39c869a6 500
30954328
RR
501 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
502 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
503}
504
566d84a7 505
30954328
RR
506// ----------------------------------------------------------------------------
507// target window handling
508// ----------------------------------------------------------------------------
509
13ff9344 510void wxScrolledWindow::SetTargetWindow( wxWindow *target, bool WXUNUSED(pushEventHandler) )
30954328
RR
511{
512 wxASSERT_MSG( target, wxT("target window must not be NULL") );
513 m_targetWindow = target;
514}
515
bfe35776 516wxWindow *wxScrolledWindow::GetTargetWindow() const
30954328
RR
517{
518 return m_targetWindow;
519}
520
521// Override this function if you don't want to have wxScrolledWindow
522// automatically change the origin according to the scroll position.
5de9f492 523void wxScrolledWindow::DoPrepareDC(wxDC& dc)
30954328
RR
524{
525 dc.SetDeviceOrigin( -m_xScrollPosition * m_xScrollPixelsPerLine,
526 -m_yScrollPosition * m_yScrollPixelsPerLine );
527}
528
566d84a7
RL
529void wxScrolledWindow::SetScrollRate( int xstep, int ystep )
530{
531 int old_x = m_xScrollPixelsPerLine * m_xScrollPosition;
532 int old_y = m_yScrollPixelsPerLine * m_yScrollPosition;
533
534 m_xScrollPixelsPerLine = xstep;
535 m_yScrollPixelsPerLine = ystep;
536
537 int new_x = m_xScrollPixelsPerLine * m_xScrollPosition;
538 int new_y = m_yScrollPixelsPerLine * m_yScrollPosition;
539
540 m_targetWindow->ScrollWindow( old_x - new_x, old_y - new_y );
541
542 AdjustScrollbars();
543}
544
30954328
RR
545void wxScrolledWindow::GetScrollPixelsPerUnit (int *x_unit, int *y_unit) const
546{
547 if ( x_unit )
548 *x_unit = m_xScrollPixelsPerLine;
549 if ( y_unit )
550 *y_unit = m_yScrollPixelsPerLine;
551}
552
553int wxScrolledWindow::GetScrollPageSize(int orient) const
554{
555 if ( orient == wxHORIZONTAL )
556 return m_xScrollLinesPerPage;
557 else
558 return m_yScrollLinesPerPage;
559}
560
561void wxScrolledWindow::SetScrollPageSize(int orient, int pageSize)
562{
563 if ( orient == wxHORIZONTAL )
564 m_xScrollLinesPerPage = pageSize;
565 else
566 m_yScrollLinesPerPage = pageSize;
567}
568
d9a4f620
RR
569void wxScrolledWindow::OnScroll(wxScrollWinEvent& event)
570{
571 int orient = event.GetOrientation();
0bc0cd5d 572
d9a4f620
RR
573 int nScrollInc = CalcScrollInc(event);
574 if (nScrollInc == 0) return;
575
576 if (orient == wxHORIZONTAL)
577 {
578 int newPos = m_xScrollPosition + nScrollInc;
579 SetScrollPos(wxHORIZONTAL, newPos, TRUE );
580 }
581 else
582 {
583 int newPos = m_yScrollPosition + nScrollInc;
584 SetScrollPos(wxVERTICAL, newPos, TRUE );
585 }
586
587 if (orient == wxHORIZONTAL)
588 {
589 m_xScrollPosition += nScrollInc;
590 }
591 else
592 {
593 m_yScrollPosition += nScrollInc;
594 }
595
596 if (orient == wxHORIZONTAL)
597 {
598 if (m_xScrollingEnabled)
599 m_targetWindow->ScrollWindow(-m_xScrollPixelsPerLine * nScrollInc, 0, (const wxRect *) NULL);
600 else
601 m_targetWindow->Refresh();
602 }
603 else
604 {
605 if (m_yScrollingEnabled)
606 m_targetWindow->ScrollWindow(0, -m_yScrollPixelsPerLine * nScrollInc, (const wxRect *) NULL);
607 else
608 m_targetWindow->Refresh();
609 }
610}
611
30954328
RR
612void wxScrolledWindow::Scroll( int x_pos, int y_pos )
613{
566d84a7 614 wxASSERT_MSG( m_targetWindow != 0, _T("No target window") );
30954328
RR
615
616 if (((x_pos == -1) || (x_pos == m_xScrollPosition)) &&
617 ((y_pos == -1) || (y_pos == m_yScrollPosition))) return;
618
30954328
RR
619 if ((x_pos != -1) && (m_xScrollPixelsPerLine))
620 {
830ed6d9
RR
621 int max = (int)(m_hAdjust->upper - m_hAdjust->page_size + 0.5);
622 if (max < 0) max = 0;
623 if (x_pos > max) x_pos = max;
624 if (x_pos < 0) x_pos = 0;
39c869a6 625
30954328
RR
626 int old_x = m_xScrollPosition;
627 m_xScrollPosition = x_pos;
aafe4488 628 m_hAdjust->value = x_pos;
39c869a6 629
aafe4488 630 m_targetWindow->ScrollWindow( (old_x-m_xScrollPosition)*m_xScrollPixelsPerLine, 0 );
39c869a6 631
77ffb593 632 // Just update the scrollbar, don't send any wxWidgets event
830ed6d9 633 GtkHDisconnectEvent();
aafe4488 634 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "value_changed" );
830ed6d9 635 GtkHConnectEvent();
30954328 636 }
39c869a6 637
30954328
RR
638 if ((y_pos != -1) && (m_yScrollPixelsPerLine))
639 {
830ed6d9
RR
640 int max = (int)(m_vAdjust->upper - m_vAdjust->page_size + 0.5);
641 if (max < 0) max = 0;
642 if (y_pos > max) y_pos = max;
643 if (y_pos < 0) y_pos = 0;
39c869a6 644
30954328
RR
645 int old_y = m_yScrollPosition;
646 m_yScrollPosition = y_pos;
aafe4488 647 m_vAdjust->value = y_pos;
39c869a6 648
aafe4488 649 m_targetWindow->ScrollWindow( 0, (old_y-m_yScrollPosition)*m_yScrollPixelsPerLine );
39c869a6 650
77ffb593 651 // Just update the scrollbar, don't send any wxWidgets event
830ed6d9 652 GtkVDisconnectEvent();
aafe4488 653 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "value_changed" );
830ed6d9 654 GtkVConnectEvent();
30954328
RR
655 }
656}
657
9e691f46
VZ
658// TODO: [VH]Scroll functions should be combined
659
660void wxScrolledWindow::GtkVScroll( float value, unsigned int scroll_type )
30954328 661{
566d84a7 662 wxASSERT_MSG( m_targetWindow != 0, _T("No target window") );
aafe4488
RR
663
664 if (m_yScrollPixelsPerLine == 0)
665 return;
39c869a6 666
aafe4488 667 int y_pos = (int)(value+0.5);
39c869a6 668
aafe4488
RR
669 if (y_pos == m_yScrollPosition)
670 return;
39c869a6 671
9e691f46 672 wxEventType command = GtkScrollWinTypeToWx(scroll_type);
d9a4f620 673
0bc0cd5d 674 wxScrollWinEvent event( command, y_pos, wxVERTICAL );
d9a4f620
RR
675 event.SetEventObject( this );
676 GetEventHandler()->ProcessEvent( event );
30954328
RR
677}
678
9e691f46 679void wxScrolledWindow::GtkHScroll( float value, unsigned int scroll_type )
30954328 680{
566d84a7 681 wxASSERT_MSG( m_targetWindow != 0, _T("No target window") );
39c869a6 682
aafe4488
RR
683 if (m_xScrollPixelsPerLine == 0)
684 return;
39c869a6 685
aafe4488 686 int x_pos = (int)(value+0.5);
0bc0cd5d 687
aafe4488
RR
688 if (x_pos == m_xScrollPosition)
689 return;
aafe4488 690
9e691f46 691 wxEventType command = GtkScrollWinTypeToWx(scroll_type);
d9a4f620 692
0bc0cd5d 693 wxScrollWinEvent event( command, x_pos, wxHORIZONTAL );
d9a4f620
RR
694 event.SetEventObject( this );
695 GetEventHandler()->ProcessEvent( event );
30954328
RR
696}
697
698void wxScrolledWindow::EnableScrolling (bool x_scroll, bool y_scroll)
699{
700 m_xScrollingEnabled = x_scroll;
701 m_yScrollingEnabled = y_scroll;
702}
703
30954328
RR
704// Where the current view starts from
705void wxScrolledWindow::GetViewStart (int *x, int *y) const
706{
707 if ( x )
708 *x = m_xScrollPosition;
709 if ( y )
710 *y = m_yScrollPosition;
711}
712
8c2f3797 713void wxScrolledWindow::DoCalcScrolledPosition(int x, int y, int *xx, int *yy) const
30954328 714{
1adff2f5
JS
715 int xs, ys;
716 GetViewStart (& xs, & ys);
717
30954328 718 if ( xx )
1adff2f5 719 *xx = x - xs * m_xScrollPixelsPerLine;
30954328 720 if ( yy )
1adff2f5 721 *yy = y - ys * m_yScrollPixelsPerLine;
30954328
RR
722}
723
8c2f3797 724void wxScrolledWindow::DoCalcUnscrolledPosition(int x, int y, int *xx, int *yy) const
30954328 725{
1adff2f5
JS
726 int xs, ys;
727 GetViewStart (& xs, & ys);
728
30954328 729 if ( xx )
1adff2f5 730 *xx = x + xs * m_xScrollPixelsPerLine;
30954328 731 if ( yy )
1adff2f5 732 *yy = y + ys * m_yScrollPixelsPerLine;
30954328
RR
733}
734
d9a4f620
RR
735int wxScrolledWindow::CalcScrollInc(wxScrollWinEvent& event)
736{
737 int pos = event.GetPosition();
738 int orient = event.GetOrientation();
739
740 int nScrollInc = 0;
741 if (event.GetEventType() == wxEVT_SCROLLWIN_TOP)
742 {
743 if (orient == wxHORIZONTAL)
744 nScrollInc = - m_xScrollPosition;
745 else
746 nScrollInc = - m_yScrollPosition;
747 } else
748 if (event.GetEventType() == wxEVT_SCROLLWIN_BOTTOM)
749 {
750 if (orient == wxHORIZONTAL)
566d84a7 751 nScrollInc = GetVirtualSize().GetWidth() / m_xScrollPixelsPerLine - m_xScrollPosition;
d9a4f620 752 else
566d84a7 753 nScrollInc = GetVirtualSize().GetHeight() / m_yScrollPixelsPerLine - m_yScrollPosition;
d9a4f620
RR
754 } else
755 if (event.GetEventType() == wxEVT_SCROLLWIN_LINEUP)
756 {
757 nScrollInc = -1;
758 } else
759 if (event.GetEventType() == wxEVT_SCROLLWIN_LINEDOWN)
760 {
761 nScrollInc = 1;
762 } else
763 if (event.GetEventType() == wxEVT_SCROLLWIN_PAGEUP)
764 {
765 if (orient == wxHORIZONTAL)
766 nScrollInc = -GetScrollPageSize(wxHORIZONTAL);
767 else
768 nScrollInc = -GetScrollPageSize(wxVERTICAL);
769 } else
770 if (event.GetEventType() == wxEVT_SCROLLWIN_PAGEDOWN)
771 {
772 if (orient == wxHORIZONTAL)
773 nScrollInc = GetScrollPageSize(wxHORIZONTAL);
774 else
775 nScrollInc = GetScrollPageSize(wxVERTICAL);
776 } else
777 if ((event.GetEventType() == wxEVT_SCROLLWIN_THUMBTRACK) ||
778 (event.GetEventType() == wxEVT_SCROLLWIN_THUMBRELEASE))
779 {
780 if (orient == wxHORIZONTAL)
781 nScrollInc = pos - m_xScrollPosition;
782 else
783 nScrollInc = pos - m_yScrollPosition;
784 }
785
786 if (orient == wxHORIZONTAL)
787 {
788 if (m_xScrollPixelsPerLine > 0)
789 {
830ed6d9
RR
790 int max = (int)(m_hAdjust->upper - m_hAdjust->page_size + 0.5);
791 if (max < 0) max = 0;
d9a4f620
RR
792
793 if ( (m_xScrollPosition + nScrollInc) < 0 )
794 nScrollInc = -m_xScrollPosition; // As -ve as we can go
830ed6d9
RR
795 else if ( (m_xScrollPosition + nScrollInc) > max )
796 nScrollInc = max - m_xScrollPosition; // As +ve as we can go
d9a4f620
RR
797 }
798 else
799 m_targetWindow->Refresh();
800 }
801 else
802 {
803 if (m_yScrollPixelsPerLine > 0)
804 {
830ed6d9
RR
805 int max = (int)(m_vAdjust->upper - m_vAdjust->page_size + 0.5);
806 if (max < 0) max = 0;
d9a4f620
RR
807
808 if ( (m_yScrollPosition + nScrollInc) < 0 )
809 nScrollInc = -m_yScrollPosition; // As -ve as we can go
830ed6d9
RR
810 else if ( (m_yScrollPosition + nScrollInc) > max )
811 nScrollInc = max - m_yScrollPosition; // As +ve as we can go
d9a4f620
RR
812 }
813 else
814 m_targetWindow->Refresh();
815 }
816
817 return nScrollInc;
818}
819
f47ae6e7 820void wxScrolledWindow::SetScrollPos( int orient, int pos, bool refresh )
0bc0cd5d
RR
821{
822 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
823
824 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
825
826 if (orient == wxHORIZONTAL)
827 {
830ed6d9
RR
828 int max = (int)(m_hAdjust->upper - m_hAdjust->page_size + 0.5);
829 if (max < 0) max = 0;
39c869a6 830
830ed6d9
RR
831 if (pos > max) pos = 0;
832 if (pos < 0) pos = 0;
39c869a6 833
830ed6d9
RR
834 if (pos == (int)(m_hAdjust->value+0.5)) return;
835 m_hAdjust->value = pos;
0bc0cd5d
RR
836 }
837 else
838 {
830ed6d9
RR
839 int max = (int)(m_vAdjust->upper - m_vAdjust->page_size + 0.5);
840 if (max < 0) max = 0;
39c869a6 841
830ed6d9
RR
842 if (pos > max) pos = 0;
843 if (pos < 0) pos = 0;
39c869a6 844
830ed6d9
RR
845 if (pos == (int)(m_vAdjust->value+0.5)) return;
846 m_vAdjust->value = pos;
0bc0cd5d
RR
847 }
848
849 if (m_wxwindow->window)
850 {
851 if (orient == wxHORIZONTAL)
852 {
77ffb593 853 // Just update the scrollbar, don't send any wxWidgets event
830ed6d9 854 GtkHDisconnectEvent();
0bc0cd5d 855 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "value_changed" );
830ed6d9 856 GtkHConnectEvent();
0bc0cd5d
RR
857 }
858 else
859 {
77ffb593 860 // Just update the scrollbar, don't send any wxWidgets event
830ed6d9 861 GtkVDisconnectEvent();
0bc0cd5d 862 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "value_changed" );
830ed6d9 863 GtkVConnectEvent();
0bc0cd5d
RR
864 }
865 }
866}
867
830ed6d9
RR
868void wxScrolledWindow::GtkVConnectEvent()
869{
870 gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed",
871 (GtkSignalFunc) gtk_scrolled_window_vscroll_callback, (gpointer) this );
872}
873
874void wxScrolledWindow::GtkHConnectEvent()
875{
876 gtk_signal_connect( GTK_OBJECT(m_hAdjust), "value_changed",
877 (GtkSignalFunc) gtk_scrolled_window_hscroll_callback, (gpointer) this );
878}
879
880void wxScrolledWindow::GtkHDisconnectEvent()
881{
882 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust),
883 (GtkSignalFunc) gtk_scrolled_window_hscroll_callback, (gpointer) this );
884}
885
886void wxScrolledWindow::GtkVDisconnectEvent()
887{
888 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust),
889 (GtkSignalFunc) gtk_scrolled_window_vscroll_callback, (gpointer) this );
890}
891
30486297
RD
892bool wxScrolledWindow::Layout()
893{
566d84a7 894 if (GetSizer() && m_targetWindow == this)
30486297 895 {
566d84a7
RL
896 // If we're the scroll target, take into account the
897 // virtual size and scrolled position of the window.
898
30486297
RD
899 int x, y, w, h;
900 CalcScrolledPosition(0,0, &x,&y);
901 GetVirtualSize(&w, &h);
902 GetSizer()->SetDimension(x, y, w, h);
903 return TRUE;
904 }
905 else
906 return wxPanel::Layout(); // fall back to default for LayoutConstraints
907}
908
30954328
RR
909// ----------------------------------------------------------------------------
910// event handlers
911// ----------------------------------------------------------------------------
912
913// Default OnSize resets scrollbars, if any
914void wxScrolledWindow::OnSize(wxSizeEvent& WXUNUSED(event))
915{
c376d80f 916 if ( m_targetWindow->GetAutoLayout() )
2b5f62a0 917 {
c376d80f
RR
918 wxSize size = m_targetWindow->GetBestVirtualSize();
919
920 // This will call ::Layout() and ::AdjustScrollbars()
921 SetVirtualSize( size );
2b5f62a0
VZ
922 }
923 else
924 {
925 AdjustScrollbars();
926 }
30954328
RR
927}
928
929// This calls OnDraw, having adjusted the origin according to the current
930// scroll position
931void wxScrolledWindow::OnPaint(wxPaintEvent& WXUNUSED(event))
932{
933 wxPaintDC dc(this);
934 PrepareDC(dc);
935
936 OnDraw(dc);
937}
938
939// kbd handling: notice that we use OnChar() and not OnKeyDown() for
940// compatibility here - if we used OnKeyDown(), the programs which process
941// arrows themselves in their OnChar() would never get the message and like
942// this they always have the priority
943void wxScrolledWindow::OnChar(wxKeyEvent& event)
944{
945 int stx, sty, // view origin
946 szx, szy, // view size (total)
947 clix, cliy; // view size (on screen)
948
2b5f62a0 949 GetViewStart(&stx, &sty);
30954328
RR
950 GetClientSize(&clix, &cliy);
951 GetVirtualSize(&szx, &szy);
952
953 if( m_xScrollPixelsPerLine )
954 {
955 clix /= m_xScrollPixelsPerLine;
956 szx /= m_xScrollPixelsPerLine;
957 }
958 else
959 {
960 clix = 0;
961 szx = -1;
962 }
963 if( m_yScrollPixelsPerLine )
964 {
965 cliy /= m_yScrollPixelsPerLine;
966 szy /= m_yScrollPixelsPerLine;
967 }
968 else
969 {
970 cliy = 0;
971 szy = -1;
972 }
973
39c869a6
VZ
974 int xScrollOld = GetScrollPos(wxHORIZONTAL),
975 yScrollOld = GetScrollPos(wxVERTICAL);
976
30954328 977 int dsty;
12a3f227 978 switch ( event.GetKeyCode() )
30954328
RR
979 {
980 case WXK_PAGEUP:
981 case WXK_PRIOR:
982 dsty = sty - (5 * cliy / 6);
983 Scroll(-1, (dsty == -1) ? 0 : dsty);
984 break;
985
986 case WXK_PAGEDOWN:
987 case WXK_NEXT:
988 Scroll(-1, sty + (5 * cliy / 6));
989 break;
990
991 case WXK_HOME:
992 Scroll(0, event.ControlDown() ? 0 : -1);
993 break;
994
995 case WXK_END:
996 Scroll(szx - clix, event.ControlDown() ? szy - cliy : -1);
997 break;
998
999 case WXK_UP:
1000 Scroll(-1, sty - 1);
1001 break;
1002
1003 case WXK_DOWN:
1004 Scroll(-1, sty + 1);
1005 break;
1006
1007 case WXK_LEFT:
1008 Scroll(stx - 1, -1);
1009 break;
1010
1011 case WXK_RIGHT:
1012 Scroll(stx + 1, -1);
1013 break;
1014
1015 default:
1016 // not for us
1017 event.Skip();
39c869a6
VZ
1018 return;
1019 }
1020
1021 int xScroll = GetScrollPos(wxHORIZONTAL);
1022 if ( xScroll != xScrollOld )
1023 {
17a1ebd1
VZ
1024 wxScrollWinEvent eventS(wxEVT_SCROLLWIN_THUMBTRACK, xScroll,
1025 wxHORIZONTAL);
1026 eventS.SetEventObject(this);
1027 GetEventHandler()->ProcessEvent(eventS);
39c869a6
VZ
1028 }
1029
1030 int yScroll = GetScrollPos(wxVERTICAL);
1031 if ( yScroll != yScrollOld )
1032 {
17a1ebd1
VZ
1033 wxScrollWinEvent eventS(wxEVT_SCROLLWIN_THUMBTRACK, yScroll,
1034 wxVERTICAL);
1035 eventS.SetEventObject(this);
1036 GetEventHandler()->ProcessEvent(eventS);
30954328
RR
1037 }
1038}
3379ed37 1039
566d84a7
RL
1040
1041// vi:sts=4:sw=4:et