]> git.saurik.com Git - wxWidgets.git/blame - src/gtk1/scrolwin.cpp
Too quick a trigger finger first time. Compile error fixed.
[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
30954328
RR
356 if ((x_pos != -1) && (m_xScrollPixelsPerLine))
357 {
358 int old_x = m_xScrollPosition;
359 m_xScrollPosition = x_pos;
aafe4488
RR
360 m_hAdjust->value = x_pos;
361
362 m_targetWindow->ScrollWindow( (old_x-m_xScrollPosition)*m_xScrollPixelsPerLine, 0 );
363
364 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "value_changed" );
30954328 365 }
aafe4488 366
30954328
RR
367 if ((y_pos != -1) && (m_yScrollPixelsPerLine))
368 {
369 int old_y = m_yScrollPosition;
370 m_yScrollPosition = y_pos;
aafe4488 371 m_vAdjust->value = y_pos;
30954328 372
aafe4488
RR
373 m_targetWindow->ScrollWindow( 0, (old_y-m_yScrollPosition)*m_yScrollPixelsPerLine );
374
375 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "value_changed" );
30954328
RR
376 }
377}
378
379void wxScrolledWindow::GtkVScroll( float value )
380{
aafe4488
RR
381 if (!m_targetWindow)
382 return;
383
384 if (m_yScrollPixelsPerLine == 0)
385 return;
386
387 int y_pos = (int)(value+0.5);
388
389 if (y_pos == m_yScrollPosition)
390 return;
391
392 int old_y = m_yScrollPosition;
393 m_yScrollPosition = y_pos;
394
395 m_targetWindow->ScrollWindow( 0, (old_y-m_yScrollPosition)*m_yScrollPixelsPerLine );
30954328
RR
396}
397
398void wxScrolledWindow::GtkHScroll( float value )
399{
aafe4488
RR
400 if (!m_targetWindow)
401 return;
402
403 if (m_xScrollPixelsPerLine == 0)
404 return;
405
406 int x_pos = (int)(value+0.5);
407
408 if (x_pos == m_xScrollPosition)
409 return;
410
411 int old_x = m_xScrollPosition;
412 m_xScrollPosition = x_pos;
413
414 m_targetWindow->ScrollWindow( (old_x-m_xScrollPosition)*m_xScrollPixelsPerLine, 0 );
30954328
RR
415}
416
417void wxScrolledWindow::EnableScrolling (bool x_scroll, bool y_scroll)
418{
419 m_xScrollingEnabled = x_scroll;
420 m_yScrollingEnabled = y_scroll;
421}
422
423void wxScrolledWindow::GetVirtualSize (int *x, int *y) const
424{
425 if ( x )
426 *x = m_xScrollPixelsPerLine * m_xScrollLines;
427 if ( y )
428 *y = m_yScrollPixelsPerLine * m_yScrollLines;
429}
430
431// Where the current view starts from
432void wxScrolledWindow::GetViewStart (int *x, int *y) const
433{
434 if ( x )
435 *x = m_xScrollPosition;
436 if ( y )
437 *y = m_yScrollPosition;
438}
439
440void wxScrolledWindow::CalcScrolledPosition(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
448void wxScrolledWindow::CalcUnscrolledPosition(int x, int y, int *xx, int *yy) const
449{
450 if ( xx )
451 *xx = x + m_xScrollPosition * m_xScrollPixelsPerLine;
452 if ( yy )
453 *yy = y + m_yScrollPosition * m_yScrollPixelsPerLine;
454}
455
456// ----------------------------------------------------------------------------
457// event handlers
458// ----------------------------------------------------------------------------
459
460// Default OnSize resets scrollbars, if any
461void wxScrolledWindow::OnSize(wxSizeEvent& WXUNUSED(event))
462{
463#if wxUSE_CONSTRAINTS
464 if (GetAutoLayout())
465 Layout();
466#endif
467
468 AdjustScrollbars();
469}
470
471// This calls OnDraw, having adjusted the origin according to the current
472// scroll position
473void wxScrolledWindow::OnPaint(wxPaintEvent& WXUNUSED(event))
474{
475 wxPaintDC dc(this);
476 PrepareDC(dc);
477
478 OnDraw(dc);
479}
480
481// kbd handling: notice that we use OnChar() and not OnKeyDown() for
482// compatibility here - if we used OnKeyDown(), the programs which process
483// arrows themselves in their OnChar() would never get the message and like
484// this they always have the priority
485void wxScrolledWindow::OnChar(wxKeyEvent& event)
486{
487 int stx, sty, // view origin
488 szx, szy, // view size (total)
489 clix, cliy; // view size (on screen)
490
491 ViewStart(&stx, &sty);
492 GetClientSize(&clix, &cliy);
493 GetVirtualSize(&szx, &szy);
494
495 if( m_xScrollPixelsPerLine )
496 {
497 clix /= m_xScrollPixelsPerLine;
498 szx /= m_xScrollPixelsPerLine;
499 }
500 else
501 {
502 clix = 0;
503 szx = -1;
504 }
505 if( m_yScrollPixelsPerLine )
506 {
507 cliy /= m_yScrollPixelsPerLine;
508 szy /= m_yScrollPixelsPerLine;
509 }
510 else
511 {
512 cliy = 0;
513 szy = -1;
514 }
515
516 int dsty;
517 switch ( event.KeyCode() )
518 {
519 case WXK_PAGEUP:
520 case WXK_PRIOR:
521 dsty = sty - (5 * cliy / 6);
522 Scroll(-1, (dsty == -1) ? 0 : dsty);
523 break;
524
525 case WXK_PAGEDOWN:
526 case WXK_NEXT:
527 Scroll(-1, sty + (5 * cliy / 6));
528 break;
529
530 case WXK_HOME:
531 Scroll(0, event.ControlDown() ? 0 : -1);
532 break;
533
534 case WXK_END:
535 Scroll(szx - clix, event.ControlDown() ? szy - cliy : -1);
536 break;
537
538 case WXK_UP:
539 Scroll(-1, sty - 1);
540 break;
541
542 case WXK_DOWN:
543 Scroll(-1, sty + 1);
544 break;
545
546 case WXK_LEFT:
547 Scroll(stx - 1, -1);
548 break;
549
550 case WXK_RIGHT:
551 Scroll(stx + 1, -1);
552 break;
553
554 default:
555 // not for us
556 event.Skip();
557 }
558}