]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/scrolwin.cpp
fix wxExecute() return code checks and removed not working code to open URLs in new...
[wxWidgets.git] / src / gtk / scrolwin.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: gtk/scrolwin.cpp
3 // Purpose: wxScrolledWindow implementation
4 // Author: Robert Roebling
5 // Modified by: Ron Lee
6 // Created: 01/02/97
7 // RCS-ID: $Id$
8 // Copyright: (c) Robert Roebling
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #include "wx/scrolwin.h"
28 #include "wx/utils.h"
29 #include "wx/dcclient.h"
30 #include "wx/panel.h"
31 #include "wx/sizer.h"
32
33 #include "wx/gtk/private.h"
34 #include "wx/gtk/win_gtk.h"
35
36 // ----------------------------------------------------------------------------
37 // event tables
38 // ----------------------------------------------------------------------------
39
40 BEGIN_EVENT_TABLE(wxScrolledWindow, wxPanel)
41 EVT_SCROLLWIN(wxScrolledWindow::OnScroll)
42 EVT_SIZE(wxScrolledWindow::OnSize)
43 EVT_PAINT(wxScrolledWindow::OnPaint)
44 EVT_CHAR(wxScrolledWindow::OnChar)
45 END_EVENT_TABLE()
46
47 IMPLEMENT_DYNAMIC_CLASS(wxScrolledWindow, wxPanel)
48
49 // ============================================================================
50 // implementation
51 // ============================================================================
52
53 //-----------------------------------------------------------------------------
54 // data
55 //-----------------------------------------------------------------------------
56
57 extern bool g_blockEventsOnDrag;
58 extern bool g_blockEventsOnScroll;
59
60 //-----------------------------------------------------------------------------
61 // idle system
62 //-----------------------------------------------------------------------------
63
64 extern void wxapp_install_idle_handler();
65 extern bool g_isIdle;
66
67 //-----------------------------------------------------------------------------
68 // "value_changed" from m_vAdjust
69 //-----------------------------------------------------------------------------
70
71 extern "C" {
72 static void gtk_scrolled_window_vscroll_callback( GtkAdjustment *adjust,
73 SCROLLBAR_CBACK_ARG
74 wxScrolledWindow *win )
75 {
76 if (g_isIdle)
77 wxapp_install_idle_handler();
78
79 if (g_blockEventsOnDrag) return;
80
81 if (!win->m_hasVMT) return;
82
83 win->GtkVScroll( adjust->value,
84 GET_SCROLL_TYPE(GTK_SCROLLED_WINDOW(win->m_widget)->vscrollbar) );
85 }
86 }
87
88 //-----------------------------------------------------------------------------
89 // "value_changed" from m_hAdjust
90 //-----------------------------------------------------------------------------
91
92 extern "C" {
93 static void gtk_scrolled_window_hscroll_callback( GtkAdjustment *adjust,
94 SCROLLBAR_CBACK_ARG
95 wxScrolledWindow *win )
96 {
97 if (g_isIdle)
98 wxapp_install_idle_handler();
99
100 if (g_blockEventsOnDrag) return;
101 if (!win->m_hasVMT) return;
102
103 win->GtkHScroll( adjust->value,
104 GET_SCROLL_TYPE(GTK_SCROLLED_WINDOW(win->m_widget)->hscrollbar) );
105 }
106 }
107
108 //-----------------------------------------------------------------------------
109 // "button_press_event" from scrollbar
110 //-----------------------------------------------------------------------------
111
112 extern "C" {
113 static 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;
121
122 // FIXME: there is no slider field any more, what was meant here?
123 #ifndef __WXGTK20__
124 win->m_isScrolling = (gdk_event->window == widget->slider);
125 #endif
126
127 return FALSE;
128 }
129 }
130
131 //-----------------------------------------------------------------------------
132 // "button_release_event" from scrollbar
133 //-----------------------------------------------------------------------------
134
135 extern "C" {
136 static 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 }
174 }
175
176 //-----------------------------------------------------------------------------
177 // InsertChild for wxScrolledWindow
178 //-----------------------------------------------------------------------------
179
180 static void wxInsertChildInScrolledWindow( wxWindow* parent, wxWindow* child )
181 {
182 // The window might have been scrolled already, do we
183 // have to adapt the position.
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
200 void wxScrolledWindow::Init()
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;
208 m_xScrollLinesPerPage = 0;
209 m_yScrollLinesPerPage = 0;
210 m_targetWindow = (wxWindow*) NULL;
211 m_scaleX = 1.0;
212 m_scaleY = 1.0;
213 m_hasScrolling = TRUE;
214 }
215
216 bool wxScrolledWindow::Create(wxWindow *parent,
217 wxWindowID id,
218 const wxPoint& pos,
219 const wxSize& size,
220 long style,
221 const wxString& name)
222 {
223 Init();
224
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;
233
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;
280 m_vAdjust->page_increment = 2.0;
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;
286 m_hAdjust->page_increment = 2.0;
287 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
288
289 // Handlers for new scrollbar values
290 GtkVConnectEvent();
291 GtkHConnectEvent();
292
293 // these handlers block mouse events to any window during scrolling such as
294 // motion events and prevent GTK and wxWidgets from fighting over where the
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
309 gtk_widget_show( m_wxwindow );
310
311 if (m_parent)
312 m_parent->DoAddChild( this );
313
314 m_focusWidget = m_wxwindow;
315
316 PostCreation();
317
318 Show( TRUE );
319
320 return TRUE;
321 }
322
323 // ----------------------------------------------------------------------------
324 // setting scrolling parameters
325 // ----------------------------------------------------------------------------
326
327 void wxScrolledWindow::DoSetVirtualSize( int x, int y )
328 {
329 wxPanel::DoSetVirtualSize( x, y );
330 AdjustScrollbars();
331
332 if (GetAutoLayout())
333 Layout();
334 }
335
336 // wxWindow's GetBestVirtualSize returns the actual window size,
337 // whereas we want to return the virtual size
338 wxSize 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)
353 wxSize 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
390 /*
391 * pixelsPerUnitX/pixelsPerUnitY: number of pixels per unit (e.g. pixels per text line)
392 * noUnitsX/noUnitsY: : no. units per scrollbar
393 */
394 void wxScrolledWindow::SetScrollbars( int pixelsPerUnitX, int pixelsPerUnitY,
395 int noUnitsX, int noUnitsY,
396 int xPos, int yPos, bool noRefresh )
397 {
398 int xs, ys;
399 GetViewStart (& xs, & ys);
400
401 int old_x = m_xScrollPixelsPerLine * xs;
402 int old_y = m_yScrollPixelsPerLine * ys;
403
404 m_xScrollPixelsPerLine = pixelsPerUnitX;
405 m_yScrollPixelsPerLine = pixelsPerUnitY;
406
407 m_hAdjust->value = m_xScrollPosition = xPos;
408 m_vAdjust->value = m_yScrollPosition = yPos;
409
410 // Setting hints here should arguably be deprecated, but without it
411 // a sizer might override this manual scrollbar setting in old code.
412 // m_targetWindow->SetVirtualSizeHints( noUnitsX * pixelsPerUnitX, noUnitsY * pixelsPerUnitY );
413
414 int w = noUnitsX * pixelsPerUnitX;
415 int h = noUnitsY * pixelsPerUnitY;
416 m_targetWindow->SetVirtualSize( w ? w : wxDefaultCoord,
417 h ? h : wxDefaultCoord);
418
419 if (!noRefresh)
420 {
421 int new_x = m_xScrollPixelsPerLine * m_xScrollPosition;
422 int new_y = m_yScrollPixelsPerLine * m_yScrollPosition;
423
424 m_targetWindow->ScrollWindow( old_x - new_x, old_y - new_y );
425 }
426 }
427
428 void wxScrolledWindow::AdjustScrollbars()
429 {
430 int w, h;
431 int vw, vh;
432
433 m_targetWindow->GetClientSize( &w, &h );
434 m_targetWindow->GetVirtualSize( &vw, &vh );
435
436 if (m_xScrollPixelsPerLine == 0)
437 {
438 m_hAdjust->upper = 1.0;
439 m_hAdjust->page_increment = 1.0;
440 m_hAdjust->page_size = 1.0;
441 }
442 else
443 {
444 m_hAdjust->upper = (vw+m_xScrollPixelsPerLine-1) / m_xScrollPixelsPerLine;
445 m_hAdjust->page_size = w / m_xScrollPixelsPerLine;
446 m_hAdjust->page_increment = w / m_xScrollPixelsPerLine;
447
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
454 // If the scrollbar hits the right side, move the window
455 // right to keep it from over extending.
456
457 if ((m_hAdjust->value != 0.0) && (m_hAdjust->value + m_hAdjust->page_size > m_hAdjust->upper))
458 {
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
463 if (GetChildren().GetCount() == 0)
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
467 }
468 }
469
470 if (m_yScrollPixelsPerLine == 0)
471 {
472 m_vAdjust->upper = 1.0;
473 m_vAdjust->page_increment = 1.0;
474 m_vAdjust->page_size = 1.0;
475 }
476 else
477 {
478 m_vAdjust->upper = (vh+m_yScrollPixelsPerLine-1) / m_yScrollPixelsPerLine;
479 m_vAdjust->page_size = h / m_yScrollPixelsPerLine;
480 m_vAdjust->page_increment = h / m_yScrollPixelsPerLine;
481
482 if ((m_vAdjust->page_size < m_vAdjust->upper) && (h >= vh))
483 m_vAdjust->page_size += 1.0;
484
485 if ((m_vAdjust->value != 0.0) && (m_vAdjust->value + m_vAdjust->page_size > m_vAdjust->upper))
486 {
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
491 if (GetChildren().GetCount() == 0)
492 m_yScrollPosition = (int)m_vAdjust->value;
493 else
494 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "value_changed" );
495 }
496 }
497
498 m_xScrollLinesPerPage = (int)(m_hAdjust->page_increment + 0.5);
499 m_yScrollLinesPerPage = (int)(m_vAdjust->page_increment + 0.5);
500
501 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
502 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
503 }
504
505
506 // ----------------------------------------------------------------------------
507 // target window handling
508 // ----------------------------------------------------------------------------
509
510 void wxScrolledWindow::SetTargetWindow( wxWindow *target, bool WXUNUSED(pushEventHandler) )
511 {
512 wxASSERT_MSG( target, wxT("target window must not be NULL") );
513 m_targetWindow = target;
514 }
515
516 wxWindow *wxScrolledWindow::GetTargetWindow() const
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.
523 void wxScrolledWindow::DoPrepareDC(wxDC& dc)
524 {
525 dc.SetDeviceOrigin( -m_xScrollPosition * m_xScrollPixelsPerLine,
526 -m_yScrollPosition * m_yScrollPixelsPerLine );
527 }
528
529 void 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
545 void 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
553 int wxScrolledWindow::GetScrollPageSize(int orient) const
554 {
555 if ( orient == wxHORIZONTAL )
556 return m_xScrollLinesPerPage;
557 else
558 return m_yScrollLinesPerPage;
559 }
560
561 void wxScrolledWindow::SetScrollPageSize(int orient, int pageSize)
562 {
563 if ( orient == wxHORIZONTAL )
564 m_xScrollLinesPerPage = pageSize;
565 else
566 m_yScrollLinesPerPage = pageSize;
567 }
568
569 void wxScrolledWindow::OnScroll(wxScrollWinEvent& event)
570 {
571 int orient = event.GetOrientation();
572
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
612 void wxScrolledWindow::Scroll( int x_pos, int y_pos )
613 {
614 wxASSERT_MSG( m_targetWindow != 0, _T("No target window") );
615
616 if (((x_pos == -1) || (x_pos == m_xScrollPosition)) &&
617 ((y_pos == -1) || (y_pos == m_yScrollPosition))) return;
618
619 if ((x_pos != -1) && (m_xScrollPixelsPerLine))
620 {
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;
625
626 int old_x = m_xScrollPosition;
627 m_xScrollPosition = x_pos;
628 m_hAdjust->value = x_pos;
629
630 m_targetWindow->ScrollWindow( (old_x-m_xScrollPosition)*m_xScrollPixelsPerLine, 0 );
631
632 // Just update the scrollbar, don't send any wxWidgets event
633 GtkHDisconnectEvent();
634 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "value_changed" );
635 GtkHConnectEvent();
636 }
637
638 if ((y_pos != -1) && (m_yScrollPixelsPerLine))
639 {
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;
644
645 int old_y = m_yScrollPosition;
646 m_yScrollPosition = y_pos;
647 m_vAdjust->value = y_pos;
648
649 m_targetWindow->ScrollWindow( 0, (old_y-m_yScrollPosition)*m_yScrollPixelsPerLine );
650
651 // Just update the scrollbar, don't send any wxWidgets event
652 GtkVDisconnectEvent();
653 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "value_changed" );
654 GtkVConnectEvent();
655 }
656 }
657
658 // TODO: [VH]Scroll functions should be combined
659
660 void wxScrolledWindow::GtkVScroll( float value, unsigned int scroll_type )
661 {
662 wxASSERT_MSG( m_targetWindow != 0, _T("No target window") );
663
664 if (m_yScrollPixelsPerLine == 0)
665 return;
666
667 int y_pos = (int)(value+0.5);
668
669 if (y_pos == m_yScrollPosition)
670 return;
671
672 wxEventType command = GtkScrollWinTypeToWx(scroll_type);
673
674 wxScrollWinEvent event( command, y_pos, wxVERTICAL );
675 event.SetEventObject( this );
676 GetEventHandler()->ProcessEvent( event );
677 }
678
679 void wxScrolledWindow::GtkHScroll( float value, unsigned int scroll_type )
680 {
681 wxASSERT_MSG( m_targetWindow != 0, _T("No target window") );
682
683 if (m_xScrollPixelsPerLine == 0)
684 return;
685
686 int x_pos = (int)(value+0.5);
687
688 if (x_pos == m_xScrollPosition)
689 return;
690
691 wxEventType command = GtkScrollWinTypeToWx(scroll_type);
692
693 wxScrollWinEvent event( command, x_pos, wxHORIZONTAL );
694 event.SetEventObject( this );
695 GetEventHandler()->ProcessEvent( event );
696 }
697
698 void wxScrolledWindow::EnableScrolling (bool x_scroll, bool y_scroll)
699 {
700 m_xScrollingEnabled = x_scroll;
701 m_yScrollingEnabled = y_scroll;
702 }
703
704 // Where the current view starts from
705 void wxScrolledWindow::GetViewStart (int *x, int *y) const
706 {
707 if ( x )
708 *x = m_xScrollPosition;
709 if ( y )
710 *y = m_yScrollPosition;
711 }
712
713 void wxScrolledWindow::DoCalcScrolledPosition(int x, int y, int *xx, int *yy) const
714 {
715 int xs, ys;
716 GetViewStart (& xs, & ys);
717
718 if ( xx )
719 *xx = x - xs * m_xScrollPixelsPerLine;
720 if ( yy )
721 *yy = y - ys * m_yScrollPixelsPerLine;
722 }
723
724 void wxScrolledWindow::DoCalcUnscrolledPosition(int x, int y, int *xx, int *yy) const
725 {
726 int xs, ys;
727 GetViewStart (& xs, & ys);
728
729 if ( xx )
730 *xx = x + xs * m_xScrollPixelsPerLine;
731 if ( yy )
732 *yy = y + ys * m_yScrollPixelsPerLine;
733 }
734
735 int 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)
751 nScrollInc = GetVirtualSize().GetWidth() / m_xScrollPixelsPerLine - m_xScrollPosition;
752 else
753 nScrollInc = GetVirtualSize().GetHeight() / m_yScrollPixelsPerLine - m_yScrollPosition;
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 {
790 int max = (int)(m_hAdjust->upper - m_hAdjust->page_size + 0.5);
791 if (max < 0) max = 0;
792
793 if ( (m_xScrollPosition + nScrollInc) < 0 )
794 nScrollInc = -m_xScrollPosition; // As -ve as we can go
795 else if ( (m_xScrollPosition + nScrollInc) > max )
796 nScrollInc = max - m_xScrollPosition; // As +ve as we can go
797 }
798 else
799 m_targetWindow->Refresh();
800 }
801 else
802 {
803 if (m_yScrollPixelsPerLine > 0)
804 {
805 int max = (int)(m_vAdjust->upper - m_vAdjust->page_size + 0.5);
806 if (max < 0) max = 0;
807
808 if ( (m_yScrollPosition + nScrollInc) < 0 )
809 nScrollInc = -m_yScrollPosition; // As -ve as we can go
810 else if ( (m_yScrollPosition + nScrollInc) > max )
811 nScrollInc = max - m_yScrollPosition; // As +ve as we can go
812 }
813 else
814 m_targetWindow->Refresh();
815 }
816
817 return nScrollInc;
818 }
819
820 void wxScrolledWindow::SetScrollPos( int orient, int pos, bool refresh )
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 {
828 int max = (int)(m_hAdjust->upper - m_hAdjust->page_size + 0.5);
829 if (max < 0) max = 0;
830
831 if (pos > max) pos = 0;
832 if (pos < 0) pos = 0;
833
834 if (pos == (int)(m_hAdjust->value+0.5)) return;
835 m_hAdjust->value = pos;
836 }
837 else
838 {
839 int max = (int)(m_vAdjust->upper - m_vAdjust->page_size + 0.5);
840 if (max < 0) max = 0;
841
842 if (pos > max) pos = 0;
843 if (pos < 0) pos = 0;
844
845 if (pos == (int)(m_vAdjust->value+0.5)) return;
846 m_vAdjust->value = pos;
847 }
848
849 if (m_wxwindow->window)
850 {
851 if (orient == wxHORIZONTAL)
852 {
853 // Just update the scrollbar, don't send any wxWidgets event
854 GtkHDisconnectEvent();
855 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "value_changed" );
856 GtkHConnectEvent();
857 }
858 else
859 {
860 // Just update the scrollbar, don't send any wxWidgets event
861 GtkVDisconnectEvent();
862 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "value_changed" );
863 GtkVConnectEvent();
864 }
865 }
866 }
867
868 void wxScrolledWindow::GtkVConnectEvent()
869 {
870 gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed",
871 (GtkSignalFunc) gtk_scrolled_window_vscroll_callback, (gpointer) this );
872 }
873
874 void wxScrolledWindow::GtkHConnectEvent()
875 {
876 gtk_signal_connect( GTK_OBJECT(m_hAdjust), "value_changed",
877 (GtkSignalFunc) gtk_scrolled_window_hscroll_callback, (gpointer) this );
878 }
879
880 void wxScrolledWindow::GtkHDisconnectEvent()
881 {
882 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust),
883 (GtkSignalFunc) gtk_scrolled_window_hscroll_callback, (gpointer) this );
884 }
885
886 void wxScrolledWindow::GtkVDisconnectEvent()
887 {
888 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust),
889 (GtkSignalFunc) gtk_scrolled_window_vscroll_callback, (gpointer) this );
890 }
891
892 bool wxScrolledWindow::Layout()
893 {
894 if (GetSizer() && m_targetWindow == this)
895 {
896 // If we're the scroll target, take into account the
897 // virtual size and scrolled position of the window.
898
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
909 // ----------------------------------------------------------------------------
910 // event handlers
911 // ----------------------------------------------------------------------------
912
913 // Default OnSize resets scrollbars, if any
914 void wxScrolledWindow::OnSize(wxSizeEvent& WXUNUSED(event))
915 {
916 if ( m_targetWindow->GetAutoLayout() )
917 {
918 wxSize size = m_targetWindow->GetBestVirtualSize();
919
920 // This will call ::Layout() and ::AdjustScrollbars()
921 SetVirtualSize( size );
922 }
923 else
924 {
925 AdjustScrollbars();
926 }
927 }
928
929 // This calls OnDraw, having adjusted the origin according to the current
930 // scroll position
931 void 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
943 void 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
949 GetViewStart(&stx, &sty);
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
974 int xScrollOld = GetScrollPos(wxHORIZONTAL),
975 yScrollOld = GetScrollPos(wxVERTICAL);
976
977 int dsty;
978 switch ( event.GetKeyCode() )
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();
1018 return;
1019 }
1020
1021 int xScroll = GetScrollPos(wxHORIZONTAL);
1022 if ( xScroll != xScrollOld )
1023 {
1024 wxScrollWinEvent event(wxEVT_SCROLLWIN_THUMBTRACK, xScroll,
1025 wxHORIZONTAL);
1026 event.SetEventObject(this);
1027 GetEventHandler()->ProcessEvent(event);
1028 }
1029
1030 int yScroll = GetScrollPos(wxVERTICAL);
1031 if ( yScroll != yScrollOld )
1032 {
1033 wxScrollWinEvent event(wxEVT_SCROLLWIN_THUMBTRACK, yScroll,
1034 wxVERTICAL);
1035 event.SetEventObject(this);
1036 GetEventHandler()->ProcessEvent(event);
1037 }
1038 }
1039
1040
1041 // vi:sts=4:sw=4:et