]> git.saurik.com Git - wxWidgets.git/blame - src/gtk1/scrolwin.cpp
cleanup
[wxWidgets.git] / src / gtk1 / scrolwin.cpp
CommitLineData
30954328
RR
1/////////////////////////////////////////////////////////////////////////////
2// Name: generic/scrolwin.cpp
3// Purpose: wxScrolledWindow implementation
4// Author: Julian Smart
5// Modified by:
6// Created: 01/02/97
7// RCS-ID: $Id$
8// Copyright: (c) Julian Smart and Markus Holzem
9// Licence: wxWindows license
10/////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
20#ifdef __GNUG__
21 #pragma implementation "scrolwin.h"
22#endif
23
24// For compilers that support precompilation, includes "wx.h".
25#include "wx/wxprec.h"
26
27#ifdef __BORLANDC__
28 #pragma hdrstop
29#endif
30
31#include "wx/utils.h"
32#include "wx/dcclient.h"
33
34#include "wx/gtk/scrolwin.h"
35#include "wx/panel.h"
36
37#include <gtk/gtk.h>
38#include "wx/gtk/win_gtk.h"
39
40// ----------------------------------------------------------------------------
41// event tables
42// ----------------------------------------------------------------------------
43
44BEGIN_EVENT_TABLE(wxScrolledWindow, wxPanel)
45 EVT_SIZE(wxScrolledWindow::OnSize)
46 EVT_PAINT(wxScrolledWindow::OnPaint)
47 EVT_CHAR(wxScrolledWindow::OnChar)
48END_EVENT_TABLE()
49
50IMPLEMENT_DYNAMIC_CLASS(wxScrolledWindow, wxPanel)
51
52// ============================================================================
53// implementation
54// ============================================================================
55
56//-----------------------------------------------------------------------------
57// data
58//-----------------------------------------------------------------------------
59
60extern bool g_blockEventsOnDrag;
61
62//-----------------------------------------------------------------------------
63// idle system
64//-----------------------------------------------------------------------------
65
66extern void wxapp_install_idle_handler();
67extern bool g_isIdle;
68
69//-----------------------------------------------------------------------------
70// "value_changed" from m_vAdjust
71//-----------------------------------------------------------------------------
72
73static void gtk_scrolled_window_vscroll_callback( GtkAdjustment *adjust, wxScrolledWindow *win )
74{
75 if (g_isIdle)
76 wxapp_install_idle_handler();
77
78 if (g_blockEventsOnDrag) return;
79
80 if (!win->m_hasVMT) return;
81
82 win->GtkVScroll( adjust->value );
83}
84
85//-----------------------------------------------------------------------------
86// "value_changed" from m_hAdjust
87//-----------------------------------------------------------------------------
88
89static void gtk_scrolled_window_hscroll_callback( GtkAdjustment *adjust, wxScrolledWindow *win )
90{
91 if (g_isIdle)
92 wxapp_install_idle_handler();
93
94 if (g_blockEventsOnDrag) return;
95 if (!win->m_hasVMT) return;
96
97 win->GtkHScroll( adjust->value );
98}
99
100//-----------------------------------------------------------------------------
101// InsertChild for wxScrolledWindow
102//-----------------------------------------------------------------------------
103
104static void wxInsertChildInScrolledWindow( wxWindow* parent, wxWindow* child )
105{
106 /* the window might have been scrolled already, do we
107 have to adapt the position */
108 GtkPizza *pizza = GTK_PIZZA(parent->m_wxwindow);
109 child->m_x += pizza->xoffset;
110 child->m_y += pizza->yoffset;
111
112 gtk_pizza_put( GTK_PIZZA(parent->m_wxwindow),
113 GTK_WIDGET(child->m_widget),
114 child->m_x,
115 child->m_y,
116 child->m_width,
117 child->m_height );
118}
119
120// ----------------------------------------------------------------------------
121// wxScrolledWindow creation
122// ----------------------------------------------------------------------------
123
124wxScrolledWindow::wxScrolledWindow()
125{
126 m_xScrollPixelsPerLine = 0;
127 m_yScrollPixelsPerLine = 0;
128 m_xScrollingEnabled = TRUE;
129 m_yScrollingEnabled = TRUE;
130 m_xScrollPosition = 0;
131 m_yScrollPosition = 0;
132 m_xScrollLines = 0;
133 m_yScrollLines = 0;
134 m_xScrollLinesPerPage = 0;
135 m_yScrollLinesPerPage = 0;
136 m_targetWindow = (wxWindow*) NULL;
137}
138
139bool wxScrolledWindow::Create(wxWindow *parent,
140 wxWindowID id,
141 const wxPoint& pos,
142 const wxSize& size,
143 long style,
144 const wxString& name)
145{
146 if (!PreCreation( parent, pos, size ) ||
147 !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
148 {
149 wxFAIL_MSG( wxT("wxWindow creation failed") );
150 return FALSE;
151 }
152
153 m_insertCallback = wxInsertChildInScrolledWindow;
154
155 m_xScrollPixelsPerLine = 0;
156 m_yScrollPixelsPerLine = 0;
157 m_xScrollingEnabled = TRUE;
158 m_yScrollingEnabled = TRUE;
159 m_xScrollPosition = 0;
160 m_yScrollPosition = 0;
161 m_xScrollLines = 0;
162 m_yScrollLines = 0;
163 m_xScrollLinesPerPage = 0;
164 m_yScrollLinesPerPage = 0;
165
166 m_targetWindow = this;
167
168 m_widget = gtk_scrolled_window_new( (GtkAdjustment *) NULL, (GtkAdjustment *) NULL );
169 GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
170
171 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(m_widget);
172
173 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
174 scroll_class->scrollbar_spacing = 0;
175
176 gtk_scrolled_window_set_policy( scrolledWindow, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
177
178 m_hAdjust = gtk_range_get_adjustment( GTK_RANGE(scrolledWindow->hscrollbar) );
179 m_vAdjust = gtk_range_get_adjustment( GTK_RANGE(scrolledWindow->vscrollbar) );
180
181 m_wxwindow = gtk_pizza_new();
182
183 gtk_container_add( GTK_CONTAINER(m_widget), m_wxwindow );
184
185 GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
186
187 if (HasFlag(wxRAISED_BORDER))
188 {
189 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_OUT );
190 }
191 else if (HasFlag(wxSUNKEN_BORDER))
192 {
193 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_IN );
194 }
195 else if (HasFlag(wxSIMPLE_BORDER))
196 {
197 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_THIN );
198 }
199 else
200 {
201 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_NONE );
202 }
203
204 GTK_WIDGET_SET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
205 m_acceptsFocus = TRUE;
206
207 // I _really_ don't want scrollbars in the beginning
208 m_vAdjust->lower = 0.0;
209 m_vAdjust->upper = 1.0;
210 m_vAdjust->value = 0.0;
211 m_vAdjust->step_increment = 1.0;
212 m_vAdjust->page_increment = 1.0;
213 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
214 m_hAdjust->lower = 0.0;
215 m_hAdjust->upper = 1.0;
216 m_hAdjust->value = 0.0;
217 m_hAdjust->step_increment = 1.0;
218 m_hAdjust->page_increment = 1.0;
219 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
220
221 // these handlers get notified when screen updates are required either when
222 // scrolling or when the window size (and therefore scrollbar configuration)
223 // has changed
224 gtk_signal_connect( GTK_OBJECT(m_hAdjust), "value_changed",
225 (GtkSignalFunc) gtk_scrolled_window_hscroll_callback, (gpointer) this );
226 gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed",
227 (GtkSignalFunc) gtk_scrolled_window_vscroll_callback, (gpointer) this );
228
229 gtk_widget_show( m_wxwindow );
230
231 if (m_parent)
232 m_parent->DoAddChild( this );
233
234 PostCreation();
235
236 Show( TRUE );
237
238 return TRUE;
239}
240
241wxScrolledWindow::~wxScrolledWindow()
242{
243}
244
245// ----------------------------------------------------------------------------
246// setting scrolling parameters
247// ----------------------------------------------------------------------------
248
249/*
250 * pixelsPerUnitX/pixelsPerUnitY: number of pixels per unit (e.g. pixels per text line)
251 * noUnitsX/noUnitsY: : no. units per scrollbar
252 */
253void wxScrolledWindow::SetScrollbars (int pixelsPerUnitX, int pixelsPerUnitY,
254 int noUnitsX, int noUnitsY,
255 int xPos, int yPos, bool noRefresh )
256{
257 m_xScrollPixelsPerLine = pixelsPerUnitX;
258 m_yScrollPixelsPerLine = pixelsPerUnitY;
259 m_xScrollPosition = xPos;
260 m_yScrollPosition = yPos;
261 m_xScrollLines = noUnitsX;
262 m_yScrollLines = noUnitsY;
263
264 m_hAdjust->lower = 0.0;
265 m_hAdjust->upper = noUnitsX;
266 m_hAdjust->value = xPos;
267 m_hAdjust->step_increment = 1.0;
268 m_hAdjust->page_increment = 1.0;
269
270 m_vAdjust->lower = 0.0;
271 m_vAdjust->upper = noUnitsY;
272 m_vAdjust->value = yPos;
273 m_vAdjust->step_increment = 1.0;
274 m_vAdjust->page_increment = 1.0;
275
276 AdjustScrollbars();
277}
278
279void wxScrolledWindow::AdjustScrollbars()
280{
281 int w, h;
282 m_targetWindow->GetClientSize( &w, &h );
283
284 if (m_xScrollPixelsPerLine == 0)
285 m_hAdjust->page_size = 1.0;
286 else
287 m_hAdjust->page_size = (w / m_xScrollPixelsPerLine);
288
289 if (m_yScrollPixelsPerLine == 0)
290 m_vAdjust->page_size = 1.0;
291 else
292 m_vAdjust->page_size = (h / m_yScrollPixelsPerLine);
293
294 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
295 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
296}
297
298// ----------------------------------------------------------------------------
299// target window handling
300// ----------------------------------------------------------------------------
301
302void wxScrolledWindow::SetTargetWindow( wxWindow *target )
303{
304 wxASSERT_MSG( target, wxT("target window must not be NULL") );
305 m_targetWindow = target;
306}
307
308wxWindow *wxScrolledWindow::GetTargetWindow()
309{
310 return m_targetWindow;
311}
312
313// Override this function if you don't want to have wxScrolledWindow
314// automatically change the origin according to the scroll position.
315void wxScrolledWindow::PrepareDC(wxDC& dc)
316{
317 dc.SetDeviceOrigin( -m_xScrollPosition * m_xScrollPixelsPerLine,
318 -m_yScrollPosition * m_yScrollPixelsPerLine );
319}
320
321void wxScrolledWindow::GetScrollPixelsPerUnit (int *x_unit, int *y_unit) const
322{
323 if ( x_unit )
324 *x_unit = m_xScrollPixelsPerLine;
325 if ( y_unit )
326 *y_unit = m_yScrollPixelsPerLine;
327}
328
329int wxScrolledWindow::GetScrollPageSize(int orient) const
330{
331 if ( orient == wxHORIZONTAL )
332 return m_xScrollLinesPerPage;
333 else
334 return m_yScrollLinesPerPage;
335}
336
337void wxScrolledWindow::SetScrollPageSize(int orient, int pageSize)
338{
339 if ( orient == wxHORIZONTAL )
340 m_xScrollLinesPerPage = pageSize;
341 else
342 m_yScrollLinesPerPage = pageSize;
343}
344
345/*
346 * Scroll to given position (scroll position, not pixel position)
347 */
348void wxScrolledWindow::Scroll( int x_pos, int y_pos )
349{
350 if (!m_targetWindow)
351 return;
352
353 if (((x_pos == -1) || (x_pos == m_xScrollPosition)) &&
354 ((y_pos == -1) || (y_pos == m_yScrollPosition))) return;
355
356 int w, h;
357 m_targetWindow->GetClientSize(&w, &h);
358
359 if ((x_pos != -1) && (m_xScrollPixelsPerLine))
360 {
361 int old_x = m_xScrollPosition;
362 m_xScrollPosition = x_pos;
363
364 // Calculate page size i.e. number of scroll units you get on the
365 // current client window
366 int noPagePositions = (int) ( (w/(double)m_xScrollPixelsPerLine) + 0.5 );
367 if (noPagePositions < 1) noPagePositions = 1;
368
369 // Correct position if greater than extent of canvas minus
370 // the visible portion of it or if below zero
371 m_xScrollPosition = wxMin( m_xScrollLines-noPagePositions, m_xScrollPosition );
372 m_xScrollPosition = wxMax( 0, m_xScrollPosition );
373
374 if (old_x != m_xScrollPosition) {
375 m_targetWindow->ScrollWindow( (old_x-m_xScrollPosition)*m_xScrollPixelsPerLine, 0 );
376 }
377 }
378 if ((y_pos != -1) && (m_yScrollPixelsPerLine))
379 {
380 int old_y = m_yScrollPosition;
381 m_yScrollPosition = y_pos;
382
383 // Calculate page size i.e. number of scroll units you get on the
384 // current client window
385 int noPagePositions = (int) ( (h/(double)m_yScrollPixelsPerLine) + 0.5 );
386 if (noPagePositions < 1) noPagePositions = 1;
387
388 // Correct position if greater than extent of canvas minus
389 // the visible portion of it or if below zero
390 m_yScrollPosition = wxMin( m_yScrollLines-noPagePositions, m_yScrollPosition );
391 m_yScrollPosition = wxMax( 0, m_yScrollPosition );
392
393 if (old_y != m_yScrollPosition) {
394 m_targetWindow->ScrollWindow( 0, (old_y-m_yScrollPosition)*m_yScrollPixelsPerLine );
395 }
396 }
397}
398
399void wxScrolledWindow::GtkVScroll( float value )
400{
401 Scroll( -1, (int)(value+0.5) );
402}
403
404void wxScrolledWindow::GtkHScroll( float value )
405{
406 Scroll( (int)(value+0.5), -1 );
407}
408
409void wxScrolledWindow::EnableScrolling (bool x_scroll, bool y_scroll)
410{
411 m_xScrollingEnabled = x_scroll;
412 m_yScrollingEnabled = y_scroll;
413}
414
415void wxScrolledWindow::GetVirtualSize (int *x, int *y) const
416{
417 if ( x )
418 *x = m_xScrollPixelsPerLine * m_xScrollLines;
419 if ( y )
420 *y = m_yScrollPixelsPerLine * m_yScrollLines;
421}
422
423// Where the current view starts from
424void wxScrolledWindow::GetViewStart (int *x, int *y) const
425{
426 if ( x )
427 *x = m_xScrollPosition;
428 if ( y )
429 *y = m_yScrollPosition;
430}
431
432void wxScrolledWindow::CalcScrolledPosition(int x, int y, int *xx, int *yy) const
433{
434 if ( xx )
435 *xx = x - m_xScrollPosition * m_xScrollPixelsPerLine;
436 if ( yy )
437 *yy = y - m_yScrollPosition * m_yScrollPixelsPerLine;
438}
439
440void wxScrolledWindow::CalcUnscrolledPosition(int x, int y, int *xx, int *yy) const
441{
442 if ( xx )
443 *xx = x + m_xScrollPosition * m_xScrollPixelsPerLine;
444 if ( yy )
445 *yy = y + m_yScrollPosition * m_yScrollPixelsPerLine;
446}
447
448// ----------------------------------------------------------------------------
449// event handlers
450// ----------------------------------------------------------------------------
451
452// Default OnSize resets scrollbars, if any
453void wxScrolledWindow::OnSize(wxSizeEvent& WXUNUSED(event))
454{
455#if wxUSE_CONSTRAINTS
456 if (GetAutoLayout())
457 Layout();
458#endif
459
460 AdjustScrollbars();
461}
462
463// This calls OnDraw, having adjusted the origin according to the current
464// scroll position
465void wxScrolledWindow::OnPaint(wxPaintEvent& WXUNUSED(event))
466{
467 wxPaintDC dc(this);
468 PrepareDC(dc);
469
470 OnDraw(dc);
471}
472
473// kbd handling: notice that we use OnChar() and not OnKeyDown() for
474// compatibility here - if we used OnKeyDown(), the programs which process
475// arrows themselves in their OnChar() would never get the message and like
476// this they always have the priority
477void wxScrolledWindow::OnChar(wxKeyEvent& event)
478{
479 int stx, sty, // view origin
480 szx, szy, // view size (total)
481 clix, cliy; // view size (on screen)
482
483 ViewStart(&stx, &sty);
484 GetClientSize(&clix, &cliy);
485 GetVirtualSize(&szx, &szy);
486
487 if( m_xScrollPixelsPerLine )
488 {
489 clix /= m_xScrollPixelsPerLine;
490 szx /= m_xScrollPixelsPerLine;
491 }
492 else
493 {
494 clix = 0;
495 szx = -1;
496 }
497 if( m_yScrollPixelsPerLine )
498 {
499 cliy /= m_yScrollPixelsPerLine;
500 szy /= m_yScrollPixelsPerLine;
501 }
502 else
503 {
504 cliy = 0;
505 szy = -1;
506 }
507
508 int dsty;
509 switch ( event.KeyCode() )
510 {
511 case WXK_PAGEUP:
512 case WXK_PRIOR:
513 dsty = sty - (5 * cliy / 6);
514 Scroll(-1, (dsty == -1) ? 0 : dsty);
515 break;
516
517 case WXK_PAGEDOWN:
518 case WXK_NEXT:
519 Scroll(-1, sty + (5 * cliy / 6));
520 break;
521
522 case WXK_HOME:
523 Scroll(0, event.ControlDown() ? 0 : -1);
524 break;
525
526 case WXK_END:
527 Scroll(szx - clix, event.ControlDown() ? szy - cliy : -1);
528 break;
529
530 case WXK_UP:
531 Scroll(-1, sty - 1);
532 break;
533
534 case WXK_DOWN:
535 Scroll(-1, sty + 1);
536 break;
537
538 case WXK_LEFT:
539 Scroll(stx - 1, -1);
540 break;
541
542 case WXK_RIGHT:
543 Scroll(stx + 1, -1);
544 break;
545
546 default:
547 // not for us
548 event.Skip();
549 }
550}