X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/30954328be6e8261886c60cf509cbf303fd279bf..0a0fc5b527437ddb5d41057d60506bfb22ea2bd3:/src/gtk1/scrolwin.cpp diff --git a/src/gtk1/scrolwin.cpp b/src/gtk1/scrolwin.cpp index 2d64124e7c..2f5bd81523 100644 --- a/src/gtk1/scrolwin.cpp +++ b/src/gtk1/scrolwin.cpp @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: generic/scrolwin.cpp +// Name: gtk/scrolwin.cpp // Purpose: wxScrolledWindow implementation // Author: Julian Smart // Modified by: @@ -42,6 +42,7 @@ // ---------------------------------------------------------------------------- BEGIN_EVENT_TABLE(wxScrolledWindow, wxPanel) + EVT_SCROLLWIN(wxScrolledWindow::OnScroll) EVT_SIZE(wxScrolledWindow::OnSize) EVT_PAINT(wxScrolledWindow::OnPaint) EVT_CHAR(wxScrolledWindow::OnChar) @@ -58,6 +59,7 @@ IMPLEMENT_DYNAMIC_CLASS(wxScrolledWindow, wxPanel) //----------------------------------------------------------------------------- extern bool g_blockEventsOnDrag; +extern bool g_blockEventsOnScroll; //----------------------------------------------------------------------------- // idle system @@ -97,14 +99,74 @@ static void gtk_scrolled_window_hscroll_callback( GtkAdjustment *adjust, wxScrol win->GtkHScroll( adjust->value ); } +//----------------------------------------------------------------------------- +// "button_press_event" from scrollbar +//----------------------------------------------------------------------------- + +static gint gtk_scrollbar_button_press_callback( GtkRange *widget, + GdkEventButton *gdk_event, + wxWindowGTK *win) +{ + if (g_isIdle) + wxapp_install_idle_handler(); + + g_blockEventsOnScroll = TRUE; + win->m_isScrolling = (gdk_event->window == widget->slider); + + return FALSE; +} + +//----------------------------------------------------------------------------- +// "button_release_event" from scrollbar +//----------------------------------------------------------------------------- + +static gint gtk_scrollbar_button_release_callback( GtkRange *widget, + GdkEventButton *WXUNUSED(gdk_event), + wxWindowGTK *win) +{ +// don't test here as we can release the mouse while being over +// a different window than the slider +// +// if (gdk_event->window != widget->slider) return FALSE; + + g_blockEventsOnScroll = FALSE; + + if (win->m_isScrolling) + { + wxEventType command = wxEVT_SCROLLWIN_THUMBRELEASE; + int value = -1; + int dir = -1; + + GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(win->m_widget); + if (widget == GTK_RANGE(scrolledWindow->hscrollbar)) + { + value = (int)(win->m_hAdjust->value+0.5); + dir = wxHORIZONTAL; + } + if (widget == GTK_RANGE(scrolledWindow->vscrollbar)) + { + value = (int)(win->m_vAdjust->value+0.5); + dir = wxVERTICAL; + } + + wxScrollWinEvent event( command, value, dir ); + event.SetEventObject( win ); + win->GetEventHandler()->ProcessEvent( event ); + } + + win->m_isScrolling = FALSE; + + return FALSE; +} + //----------------------------------------------------------------------------- // InsertChild for wxScrolledWindow //----------------------------------------------------------------------------- static void wxInsertChildInScrolledWindow( wxWindow* parent, wxWindow* child ) { - /* the window might have been scrolled already, do we - have to adapt the position */ + // The window might have been scrolled already, do we + // have to adapt the position. GtkPizza *pizza = GTK_PIZZA(parent->m_wxwindow); child->m_x += pizza->xoffset; child->m_y += pizza->yoffset; @@ -121,7 +183,7 @@ static void wxInsertChildInScrolledWindow( wxWindow* parent, wxWindow* child ) // wxScrolledWindow creation // ---------------------------------------------------------------------------- -wxScrolledWindow::wxScrolledWindow() +void wxScrolledWindow::Init() { m_xScrollPixelsPerLine = 0; m_yScrollPixelsPerLine = 0; @@ -134,6 +196,9 @@ wxScrolledWindow::wxScrolledWindow() m_xScrollLinesPerPage = 0; m_yScrollLinesPerPage = 0; m_targetWindow = (wxWindow*) NULL; + m_scaleX = 1.0; + m_scaleY = 1.0; + m_hasScrolling = TRUE; } bool wxScrolledWindow::Create(wxWindow *parent, @@ -143,6 +208,8 @@ bool wxScrolledWindow::Create(wxWindow *parent, long style, const wxString& name) { + Init(); + if (!PreCreation( parent, pos, size ) || !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name )) { @@ -151,17 +218,6 @@ bool wxScrolledWindow::Create(wxWindow *parent, } m_insertCallback = wxInsertChildInScrolledWindow; - - m_xScrollPixelsPerLine = 0; - m_yScrollPixelsPerLine = 0; - m_xScrollingEnabled = TRUE; - m_yScrollingEnabled = TRUE; - m_xScrollPosition = 0; - m_yScrollPosition = 0; - m_xScrollLines = 0; - m_yScrollLines = 0; - m_xScrollLinesPerPage = 0; - m_yScrollLinesPerPage = 0; m_targetWindow = this; @@ -218,18 +274,32 @@ bool wxScrolledWindow::Create(wxWindow *parent, m_hAdjust->page_increment = 1.0; gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" ); - // these handlers get notified when screen updates are required either when - // scrolling or when the window size (and therefore scrollbar configuration) - // has changed - gtk_signal_connect( GTK_OBJECT(m_hAdjust), "value_changed", - (GtkSignalFunc) gtk_scrolled_window_hscroll_callback, (gpointer) this ); - gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed", - (GtkSignalFunc) gtk_scrolled_window_vscroll_callback, (gpointer) this ); + // Handlers for new scrollbar values + GtkVConnectEvent(); + GtkHConnectEvent(); + + // these handlers block mouse events to any window during scrolling such as + // motion events and prevent GTK and wxWindows from fighting over where the + // slider should be + + gtk_signal_connect( GTK_OBJECT(scrolledWindow->vscrollbar), "button_press_event", + (GtkSignalFunc)gtk_scrollbar_button_press_callback, (gpointer) this ); + + gtk_signal_connect( GTK_OBJECT(scrolledWindow->hscrollbar), "button_press_event", + (GtkSignalFunc)gtk_scrollbar_button_press_callback, (gpointer) this ); + + gtk_signal_connect( GTK_OBJECT(scrolledWindow->vscrollbar), "button_release_event", + (GtkSignalFunc)gtk_scrollbar_button_release_callback, (gpointer) this ); + + gtk_signal_connect( GTK_OBJECT(scrolledWindow->hscrollbar), "button_release_event", + (GtkSignalFunc)gtk_scrollbar_button_release_callback, (gpointer) this ); gtk_widget_show( m_wxwindow ); if (m_parent) m_parent->DoAddChild( this ); + + m_focusWidget = m_wxwindow; PostCreation(); @@ -238,10 +308,6 @@ bool wxScrolledWindow::Create(wxWindow *parent, return TRUE; } -wxScrolledWindow::~wxScrolledWindow() -{ -} - // ---------------------------------------------------------------------------- // setting scrolling parameters // ---------------------------------------------------------------------------- @@ -254,43 +320,57 @@ void wxScrolledWindow::SetScrollbars (int pixelsPerUnitX, int pixelsPerUnitY, int noUnitsX, int noUnitsY, int xPos, int yPos, bool noRefresh ) { + int old_x = m_xScrollPixelsPerLine * m_xScrollPosition; + int old_y = m_yScrollPixelsPerLine * m_yScrollPosition; + m_xScrollPixelsPerLine = pixelsPerUnitX; m_yScrollPixelsPerLine = pixelsPerUnitY; - m_xScrollPosition = xPos; - m_yScrollPosition = yPos; m_xScrollLines = noUnitsX; m_yScrollLines = noUnitsY; - + m_xScrollPosition = xPos; + m_yScrollPosition = yPos; + m_hAdjust->lower = 0.0; m_hAdjust->upper = noUnitsX; m_hAdjust->value = xPos; m_hAdjust->step_increment = 1.0; - m_hAdjust->page_increment = 1.0; + m_hAdjust->page_increment = 2.0; m_vAdjust->lower = 0.0; m_vAdjust->upper = noUnitsY; m_vAdjust->value = yPos; m_vAdjust->step_increment = 1.0; - m_vAdjust->page_increment = 1.0; + m_vAdjust->page_increment = 2.0; AdjustScrollbars(); + + if (!noRefresh) + { + int new_x = m_xScrollPixelsPerLine * m_xScrollPosition; + int new_y = m_yScrollPixelsPerLine * m_yScrollPosition; + + m_targetWindow->ScrollWindow( old_x-new_x, old_y-new_y ); + } } void wxScrolledWindow::AdjustScrollbars() { int w, h; m_targetWindow->GetClientSize( &w, &h ); - + if (m_xScrollPixelsPerLine == 0) m_hAdjust->page_size = 1.0; else m_hAdjust->page_size = (w / m_xScrollPixelsPerLine); - + if (m_yScrollPixelsPerLine == 0) m_vAdjust->page_size = 1.0; else m_vAdjust->page_size = (h / m_yScrollPixelsPerLine); - + + m_xScrollLinesPerPage = (int)(m_hAdjust->page_size + 0.5); + m_yScrollLinesPerPage = (int)(m_vAdjust->page_size + 0.5); + gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" ); gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" ); } @@ -342,9 +422,49 @@ void wxScrolledWindow::SetScrollPageSize(int orient, int pageSize) m_yScrollLinesPerPage = pageSize; } -/* - * Scroll to given position (scroll position, not pixel position) - */ +void wxScrolledWindow::OnScroll(wxScrollWinEvent& event) +{ + int orient = event.GetOrientation(); + + int nScrollInc = CalcScrollInc(event); + if (nScrollInc == 0) return; + + if (orient == wxHORIZONTAL) + { + int newPos = m_xScrollPosition + nScrollInc; + SetScrollPos(wxHORIZONTAL, newPos, TRUE ); + } + else + { + int newPos = m_yScrollPosition + nScrollInc; + SetScrollPos(wxVERTICAL, newPos, TRUE ); + } + + if (orient == wxHORIZONTAL) + { + m_xScrollPosition += nScrollInc; + } + else + { + m_yScrollPosition += nScrollInc; + } + + if (orient == wxHORIZONTAL) + { + if (m_xScrollingEnabled) + m_targetWindow->ScrollWindow(-m_xScrollPixelsPerLine * nScrollInc, 0, (const wxRect *) NULL); + else + m_targetWindow->Refresh(); + } + else + { + if (m_yScrollingEnabled) + m_targetWindow->ScrollWindow(0, -m_yScrollPixelsPerLine * nScrollInc, (const wxRect *) NULL); + else + m_targetWindow->Refresh(); + } +} + void wxScrolledWindow::Scroll( int x_pos, int y_pos ) { if (!m_targetWindow) @@ -353,57 +473,97 @@ void wxScrolledWindow::Scroll( int x_pos, int y_pos ) if (((x_pos == -1) || (x_pos == m_xScrollPosition)) && ((y_pos == -1) || (y_pos == m_yScrollPosition))) return; - int w, h; - m_targetWindow->GetClientSize(&w, &h); - if ((x_pos != -1) && (m_xScrollPixelsPerLine)) { + int max = (int)(m_hAdjust->upper - m_hAdjust->page_size + 0.5); + if (max < 0) max = 0; + if (x_pos > max) x_pos = max; + if (x_pos < 0) x_pos = 0; + int old_x = m_xScrollPosition; m_xScrollPosition = x_pos; + m_hAdjust->value = x_pos; - // Calculate page size i.e. number of scroll units you get on the - // current client window - int noPagePositions = (int) ( (w/(double)m_xScrollPixelsPerLine) + 0.5 ); - if (noPagePositions < 1) noPagePositions = 1; - - // Correct position if greater than extent of canvas minus - // the visible portion of it or if below zero - m_xScrollPosition = wxMin( m_xScrollLines-noPagePositions, m_xScrollPosition ); - m_xScrollPosition = wxMax( 0, m_xScrollPosition ); + m_targetWindow->ScrollWindow( (old_x-m_xScrollPosition)*m_xScrollPixelsPerLine, 0 ); - if (old_x != m_xScrollPosition) { - m_targetWindow->ScrollWindow( (old_x-m_xScrollPosition)*m_xScrollPixelsPerLine, 0 ); - } + // Just update the scrollbar, don't send any wxWindows event + GtkHDisconnectEvent(); + gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "value_changed" ); + GtkHConnectEvent(); } + if ((y_pos != -1) && (m_yScrollPixelsPerLine)) { + int max = (int)(m_vAdjust->upper - m_vAdjust->page_size + 0.5); + if (max < 0) max = 0; + if (y_pos > max) y_pos = max; + if (y_pos < 0) y_pos = 0; + int old_y = m_yScrollPosition; m_yScrollPosition = y_pos; + m_vAdjust->value = y_pos; - // Calculate page size i.e. number of scroll units you get on the - // current client window - int noPagePositions = (int) ( (h/(double)m_yScrollPixelsPerLine) + 0.5 ); - if (noPagePositions < 1) noPagePositions = 1; + m_targetWindow->ScrollWindow( 0, (old_y-m_yScrollPosition)*m_yScrollPixelsPerLine ); - // Correct position if greater than extent of canvas minus - // the visible portion of it or if below zero - m_yScrollPosition = wxMin( m_yScrollLines-noPagePositions, m_yScrollPosition ); - m_yScrollPosition = wxMax( 0, m_yScrollPosition ); - - if (old_y != m_yScrollPosition) { - m_targetWindow->ScrollWindow( 0, (old_y-m_yScrollPosition)*m_yScrollPixelsPerLine ); - } + // Just update the scrollbar, don't send any wxWindows event + GtkVDisconnectEvent(); + gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "value_changed" ); + GtkVConnectEvent(); } } void wxScrolledWindow::GtkVScroll( float value ) { - Scroll( -1, (int)(value+0.5) ); + if (!m_targetWindow) + return; + + if (m_yScrollPixelsPerLine == 0) + return; + + int y_pos = (int)(value+0.5); + + if (y_pos == m_yScrollPosition) + return; + + GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(m_widget); + GtkRange *range = GTK_RANGE(scrolledWindow->vscrollbar); + + wxEventType command = wxEVT_SCROLLWIN_THUMBTRACK; + if (range->scroll_type == GTK_SCROLL_STEP_BACKWARD) command = wxEVT_SCROLLWIN_LINEUP; + else if (range->scroll_type == GTK_SCROLL_STEP_FORWARD) command = wxEVT_SCROLLWIN_LINEDOWN; + else if (range->scroll_type == GTK_SCROLL_PAGE_BACKWARD) command = wxEVT_SCROLLWIN_PAGEUP; + else if (range->scroll_type == GTK_SCROLL_PAGE_FORWARD) command = wxEVT_SCROLLWIN_PAGEDOWN; + + wxScrollWinEvent event( command, y_pos, wxVERTICAL ); + event.SetEventObject( this ); + GetEventHandler()->ProcessEvent( event ); } void wxScrolledWindow::GtkHScroll( float value ) { - Scroll( (int)(value+0.5), -1 ); + if (!m_targetWindow) + return; + + if (m_xScrollPixelsPerLine == 0) + return; + + int x_pos = (int)(value+0.5); + + if (x_pos == m_xScrollPosition) + return; + + GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(m_widget); + GtkRange *range = GTK_RANGE(scrolledWindow->hscrollbar); + + wxEventType command = wxEVT_SCROLLWIN_THUMBTRACK; + if (range->scroll_type == GTK_SCROLL_STEP_BACKWARD) command = wxEVT_SCROLLWIN_LINEUP; + else if (range->scroll_type == GTK_SCROLL_STEP_FORWARD) command = wxEVT_SCROLLWIN_LINEDOWN; + else if (range->scroll_type == GTK_SCROLL_PAGE_BACKWARD) command = wxEVT_SCROLLWIN_PAGEUP; + else if (range->scroll_type == GTK_SCROLL_PAGE_FORWARD) command = wxEVT_SCROLLWIN_PAGEDOWN; + + wxScrollWinEvent event( command, x_pos, wxHORIZONTAL ); + event.SetEventObject( this ); + GetEventHandler()->ProcessEvent( event ); } void wxScrolledWindow::EnableScrolling (bool x_scroll, bool y_scroll) @@ -445,6 +605,163 @@ void wxScrolledWindow::CalcUnscrolledPosition(int x, int y, int *xx, int *yy) co *yy = y + m_yScrollPosition * m_yScrollPixelsPerLine; } +int wxScrolledWindow::CalcScrollInc(wxScrollWinEvent& event) +{ + int pos = event.GetPosition(); + int orient = event.GetOrientation(); + + int nScrollInc = 0; + if (event.GetEventType() == wxEVT_SCROLLWIN_TOP) + { + if (orient == wxHORIZONTAL) + nScrollInc = - m_xScrollPosition; + else + nScrollInc = - m_yScrollPosition; + } else + if (event.GetEventType() == wxEVT_SCROLLWIN_BOTTOM) + { + if (orient == wxHORIZONTAL) + nScrollInc = m_xScrollLines - m_xScrollPosition; + else + nScrollInc = m_yScrollLines - m_yScrollPosition; + } else + if (event.GetEventType() == wxEVT_SCROLLWIN_LINEUP) + { + nScrollInc = -1; + } else + if (event.GetEventType() == wxEVT_SCROLLWIN_LINEDOWN) + { + nScrollInc = 1; + } else + if (event.GetEventType() == wxEVT_SCROLLWIN_PAGEUP) + { + if (orient == wxHORIZONTAL) + nScrollInc = -GetScrollPageSize(wxHORIZONTAL); + else + nScrollInc = -GetScrollPageSize(wxVERTICAL); + } else + if (event.GetEventType() == wxEVT_SCROLLWIN_PAGEDOWN) + { + if (orient == wxHORIZONTAL) + nScrollInc = GetScrollPageSize(wxHORIZONTAL); + else + nScrollInc = GetScrollPageSize(wxVERTICAL); + } else + if ((event.GetEventType() == wxEVT_SCROLLWIN_THUMBTRACK) || + (event.GetEventType() == wxEVT_SCROLLWIN_THUMBRELEASE)) + { + if (orient == wxHORIZONTAL) + nScrollInc = pos - m_xScrollPosition; + else + nScrollInc = pos - m_yScrollPosition; + } + + if (orient == wxHORIZONTAL) + { + if (m_xScrollPixelsPerLine > 0) + { + int max = (int)(m_hAdjust->upper - m_hAdjust->page_size + 0.5); + if (max < 0) max = 0; + + if ( (m_xScrollPosition + nScrollInc) < 0 ) + nScrollInc = -m_xScrollPosition; // As -ve as we can go + else if ( (m_xScrollPosition + nScrollInc) > max ) + nScrollInc = max - m_xScrollPosition; // As +ve as we can go + } + else + m_targetWindow->Refresh(); + } + else + { + if (m_yScrollPixelsPerLine > 0) + { + int max = (int)(m_vAdjust->upper - m_vAdjust->page_size + 0.5); + if (max < 0) max = 0; + + if ( (m_yScrollPosition + nScrollInc) < 0 ) + nScrollInc = -m_yScrollPosition; // As -ve as we can go + else if ( (m_yScrollPosition + nScrollInc) > max ) + nScrollInc = max - m_yScrollPosition; // As +ve as we can go + } + else + m_targetWindow->Refresh(); + } + + return nScrollInc; +} + +void wxScrolledWindow::SetScrollPos( int orient, int pos, bool WXUNUSED(refresh) ) +{ + wxCHECK_RET( m_widget != NULL, wxT("invalid window") ); + + wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") ); + + if (orient == wxHORIZONTAL) + { + int max = (int)(m_hAdjust->upper - m_hAdjust->page_size + 0.5); + if (max < 0) max = 0; + + if (pos > max) pos = 0; + if (pos < 0) pos = 0; + + if (pos == (int)(m_hAdjust->value+0.5)) return; + m_hAdjust->value = pos; + } + else + { + int max = (int)(m_vAdjust->upper - m_vAdjust->page_size + 0.5); + if (max < 0) max = 0; + + if (pos > max) pos = 0; + if (pos < 0) pos = 0; + + if (pos == (int)(m_vAdjust->value+0.5)) return; + m_vAdjust->value = pos; + } + + if (m_wxwindow->window) + { + if (orient == wxHORIZONTAL) + { + // Just update the scrollbar, don't send any wxWindows event + GtkHDisconnectEvent(); + gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "value_changed" ); + GtkHConnectEvent(); + } + else + { + // Just update the scrollbar, don't send any wxWindows event + GtkVDisconnectEvent(); + gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "value_changed" ); + GtkVConnectEvent(); + } + } +} + +void wxScrolledWindow::GtkVConnectEvent() +{ + gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed", + (GtkSignalFunc) gtk_scrolled_window_vscroll_callback, (gpointer) this ); +} + +void wxScrolledWindow::GtkHConnectEvent() +{ + gtk_signal_connect( GTK_OBJECT(m_hAdjust), "value_changed", + (GtkSignalFunc) gtk_scrolled_window_hscroll_callback, (gpointer) this ); +} + +void wxScrolledWindow::GtkHDisconnectEvent() +{ + gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust), + (GtkSignalFunc) gtk_scrolled_window_hscroll_callback, (gpointer) this ); +} + +void wxScrolledWindow::GtkVDisconnectEvent() +{ + gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust), + (GtkSignalFunc) gtk_scrolled_window_vscroll_callback, (gpointer) this ); +} + // ---------------------------------------------------------------------------- // event handlers // ---------------------------------------------------------------------------- @@ -505,6 +822,9 @@ void wxScrolledWindow::OnChar(wxKeyEvent& event) szy = -1; } + int xScrollOld = GetScrollPos(wxHORIZONTAL), + yScrollOld = GetScrollPos(wxVERTICAL); + int dsty; switch ( event.KeyCode() ) { @@ -546,5 +866,25 @@ void wxScrolledWindow::OnChar(wxKeyEvent& event) default: // not for us event.Skip(); + return; + } + + int xScroll = GetScrollPos(wxHORIZONTAL); + if ( xScroll != xScrollOld ) + { + wxScrollWinEvent event(wxEVT_SCROLLWIN_THUMBTRACK, xScroll, + wxHORIZONTAL); + event.SetEventObject(this); + GetEventHandler()->ProcessEvent(event); + } + + int yScroll = GetScrollPos(wxVERTICAL); + if ( yScroll != yScrollOld ) + { + wxScrollWinEvent event(wxEVT_SCROLLWIN_THUMBTRACK, yScroll, + wxVERTICAL); + event.SetEventObject(this); + GetEventHandler()->ProcessEvent(event); } } +