diff --git a/TODO b/TODO new file mode 100644 index 0000000000..0094f28c79 --- /dev/null +++ b/TODO @@ -0,0 +1,8 @@ +All + +1. extended listbox interface? +2. problem with horz scrolling: the focus rect isn't drawn entirely... + +MSW + +GTK diff --git a/include/wx/defs.h b/include/wx/defs.h index f5665e32a0..65df678745 100644 --- a/include/wx/defs.h +++ b/include/wx/defs.h @@ -880,6 +880,13 @@ enum wxBorder // Override CTL3D or native 3D styles for children #define wxNO_3D 0x00800000 +// wxALWAYS_SHOW_SB: instead of hiding the scrollbar when it is not needed, +// disable it - but still show (see also wxLB_ALWAYS_SB style) +// +// NB: as this style is only supported by wxUniversal so far as it doesn't use +// wxUSER_COLOURS/wxNO_3D, we reuse the same style value +#define wxALWAYS_SHOW_SB 0x00800000 + // Clip children when painting, which reduces flicker in e.g. frames and // splitter windows, but can't be used in a panel where a static box must be // 'transparent' (panel paints the background for it) diff --git a/include/wx/univ/control.h b/include/wx/univ/control.h index 9caee6e0d4..e62a21f041 100644 --- a/include/wx/univ/control.h +++ b/include/wx/univ/control.h @@ -90,10 +90,6 @@ public: const wxString& strArg = wxEmptyString); protected: - // by default static controls don't have the border and all the others do - // have it - virtual wxBorder GetDefaultBorder() const; - // create the event translator object for this control: the base class // action creates the default one which doesn't do anything virtual wxInputHandler *CreateInputHandler() const; diff --git a/include/wx/univ/inphand.h b/include/wx/univ/inphand.h index b22c2bd19f..a3f031fc54 100644 --- a/include/wx/univ/inphand.h +++ b/include/wx/univ/inphand.h @@ -223,6 +223,7 @@ protected: wxRenderer *m_renderer; wxWindow *m_winCapture; + int m_btnCapture; }; #endif // _WX_UNIV_INPHAND_H_ diff --git a/include/wx/univ/listbox.h b/include/wx/univ/listbox.h index 3b96c1f470..59d65ee299 100644 --- a/include/wx/univ/listbox.h +++ b/include/wx/univ/listbox.h @@ -75,12 +75,9 @@ public: virtual void Clear(); virtual void Delete(int n); - virtual int GetCount() const - { return (int)m_strings.GetCount(); } - virtual wxString GetString(int n) const - { return m_strings[n]; } - virtual void SetString(int n, const wxString& s) - { m_strings[n] = s; RefreshItem(n); } + virtual int GetCount() const { return (int)m_strings.GetCount(); } + virtual wxString GetString(int n) const { return m_strings[n]; } + virtual void SetString(int n, const wxString& s); virtual int FindString(const wxString& s) const { return m_strings.Index(s); } @@ -125,10 +122,11 @@ public: void Select(bool sel = TRUE); void EnsureVisible(); - // get, calculating it if necessary, the number of items per page and the - // height of each line + // get, calculating it if necessary, the number of items per page, the + // height of each line and the max width of an item int GetItemsPerPage() const; wxCoord GetLineHeight() const; + wxCoord GetMaxWidth() const; // override the wxControl virtual methods virtual bool PerformAction(const wxControlAction& action, @@ -138,6 +136,7 @@ public: protected: virtual wxSize DoGetBestClientSize() const; virtual void DoDraw(wxControlRenderer *renderer); + virtual wxBorder GetDefaultBorder() const; // common part of all ctors void Init(); @@ -160,6 +159,10 @@ protected: // calculate the number of items per page using our current size void CalcItemsPerPage(); + // can/should we have a horz scrollbar? + bool HasHorzScrollbar() const + { return (m_windowStyle & wxLB_HSCROLL) != 0; } + // the array containing all items (it is sorted if the listbox has // wxLB_SORT style) wxArrayString m_strings; @@ -185,13 +188,16 @@ private: // the height of one line in the listbox (all lines have the same height) wxCoord m_lineHeight; + // the maximal width of a listbox item + wxCoord m_maxWidth; + // the number of items per page size_t m_itemsPerPage; // if the number of items has changed we may need to show/hide the // scrollbar - bool m_updateScrollbar, - m_showScrollbar; + bool m_updateScrollbarX, m_updateScrollbarY, + m_showScrollbarX, m_showScrollbarY; // if the current item has changed, we might need to scroll if it went out // of the window diff --git a/include/wx/univ/renderer.h b/include/wx/univ/renderer.h index c26e071185..fedc58176b 100644 --- a/include/wx/univ/renderer.h +++ b/include/wx/univ/renderer.h @@ -135,6 +135,10 @@ public: const wxRect& rect, int flags = 0) = 0; + // draw the rectangle in the corner between two scrollbars + virtual void DrawScrollCorner(wxDC& dc, + const wxRect& rect) = 0; + // draw an item of a wxControlWithItems virtual void DrawItem(wxDC& dc, const wxString& label, @@ -144,6 +148,10 @@ public: // geometry functions // ------------------ + // get the dimensions of the border: rect.x/y contain the width/height of + // the left/top side, width/heigh - of the right/bottom one + virtual wxRect GetBorderDimensions(wxBorder border) const = 0; + // adjust the size of the control of the given class: for most controls, // this just takes into account the border, but for some (buttons, for // example) it is more complicated - the result being, in any case, that @@ -156,6 +164,9 @@ public: wxScrollBar::Element elem, int thumbPos = -1) const = 0; + // returns the size of the scrollbar shaft excluding the arrows + virtual wxCoord GetScrollbarSize(const wxScrollBar *scrollbar) = 0; + // returns one of wxHT_SCROLLBAR_XXX constants virtual wxHitTest HitTestScrollbar(const wxScrollBar *scrollbar, const wxPoint& pt) const = 0; @@ -266,6 +277,9 @@ public: const wxRect& rect, int flags = 0) { m_renderer->DrawScrollbarShaft(dc, orient, rect, flags); } + virtual void DrawScrollCorner(wxDC& dc, + const wxRect& rect) + { m_renderer->DrawScrollCorner(dc, rect); } virtual void DrawItem(wxDC& dc, const wxString& label, const wxRect& rect, @@ -274,11 +288,15 @@ public: virtual void AdjustSize(wxSize *size, const wxWindow *window) { m_renderer->AdjustSize(size, window); } + virtual wxRect GetBorderDimensions(wxBorder border) const + { m_renderer->GetBorderDimensions(border); } virtual wxRect GetScrollbarRect(const wxScrollBar *scrollbar, wxScrollBar::Element elem, int thumbPos = -1) const { return m_renderer->GetScrollbarRect(scrollbar, elem, thumbPos); } + virtual wxCoord GetScrollbarSize(const wxScrollBar *scrollbar) + { return m_renderer->GetScrollbarSize(scrollbar); } virtual wxHitTest HitTestScrollbar(const wxScrollBar *scrollbar, const wxPoint& pt) const { return m_renderer->HitTestScrollbar(scrollbar, pt); } diff --git a/include/wx/univ/scrolbar.h b/include/wx/univ/scrolbar.h index bca358022c..a94119d293 100644 --- a/include/wx/univ/scrolbar.h +++ b/include/wx/univ/scrolbar.h @@ -103,11 +103,12 @@ public: // wxScrollBar sub elements state (combination of wxCONTROL_XXX) void SetState(Element which, int flags); - int GetState(Element which) const { return m_elementsState[which]; } + int GetState(Element which) const; protected: virtual wxSize DoGetBestClientSize() const; virtual void DoDraw(wxControlRenderer *renderer); + virtual wxBorder GetDefaultBorder() const { return wxBORDER_NONE; } // event handler void OnIdle(wxIdleEvent& event); diff --git a/include/wx/univ/window.h b/include/wx/univ/window.h index 07ef1ac8b2..6b5fae4402 100644 --- a/include/wx/univ/window.h +++ b/include/wx/univ/window.h @@ -64,9 +64,16 @@ public: const wxSize& size = wxDefaultSize, long style = 0, const wxString& name = wxPanelNameStr) - : wxWindowNative(parent, id, pos, size, style, name) + : wxWindowNative(parent, id, pos, size, style | wxCLIP_CHILDREN, name) { Init(); } + bool Create(wxWindow *parent, + wxWindowID id, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = 0, + const wxString& name = wxPanelNameStr); + // background pixmap support // ------------------------- @@ -93,6 +100,9 @@ public: virtual void ScrollWindow(int dx, int dy, const wxRect* rect = (wxRect *) NULL); + // take into account the borders here + virtual wxPoint GetClientAreaOrigin() const; + // miscellaneous other methods // --------------------------- @@ -130,6 +140,9 @@ protected: // draw the control background, return TRUE if done virtual bool DoDrawBackground(wxControlRenderer *renderer); + // draw the controls border + virtual void DoDrawBorder(wxControlRenderer *renderer); + // draw the controls contents virtual void DoDraw(wxControlRenderer *renderer); diff --git a/include/wx/window.h b/include/wx/window.h index 3d9e71fa4c..4b95efc9dd 100644 --- a/include/wx/window.h +++ b/include/wx/window.h @@ -259,6 +259,17 @@ public: return wxSize(w, h); } + // get the origin of the client area of the window relative to the + // window top left corner (the client area may be shifted because of + // the borders, scrollbars, other decorations...) + virtual wxPoint GetClientAreaOrigin() const; + + // get the client rectangle in window (i.e. client) coordinates + wxRect GetClientRect() const + { + return wxRect(GetClientAreaOrigin(), GetClientSize()); + } + // get the size best suited for the window (in fact, minimal // acceptable size using which it will still look "nice") wxSize GetBestSize() const { return DoGetBestSize(); } diff --git a/samples/univ/univ.cpp b/samples/univ/univ.cpp index 55b4a8acef..c29cc74a88 100644 --- a/samples/univ/univ.cpp +++ b/samples/univ/univ.cpp @@ -317,10 +317,13 @@ MyUnivFrame::MyUnivFrame(const wxString& title) }; wxListBox *lbox = new wxListBox(this, -1, wxPoint(550, 10), wxDefaultSize, WXSIZEOF(choices), choices, - wxLB_MULTIPLE); - for ( int i = 0; i < 20; i++ ) + wxLB_MULTIPLE | wxLB_ALWAYS_SB); + lbox = new wxListBox(this, -1, wxPoint(550, 300), wxDefaultSize, + 0, NULL, wxLB_HSCROLL); + for ( int i = 1; i <= 20; i++ ) { - lbox->Append(wxString::Format(_T("entry %d"), i)); + lbox->Append(wxString::Format(_T("%sentry %d"), + i % 10 ? _T("") : _T("very very long "), i)); } } diff --git a/src/common/wincmn.cpp b/src/common/wincmn.cpp index 23ae0e8d5f..fc0baf9bd1 100644 --- a/src/common/wincmn.cpp +++ b/src/common/wincmn.cpp @@ -391,7 +391,11 @@ void wxWindowBase::Fit() { if ( GetChildren().GetCount() > 0 ) { - SetClientSize(DoGetBestSize()); + // leave a margin for compatibility with old version + wxSize size = DoGetBestSize(); + size.x += 7; + size.y += 14; + SetClientSize(size); } //else: do nothing if we have no children } @@ -439,8 +443,7 @@ wxSize wxWindowBase::DoGetBestSize() const maxY = wy + wh; } - // leave a margin - return wxSize(maxX + 7, maxY + 14); + return wxSize(maxX, maxY); } else { @@ -450,6 +453,12 @@ wxSize wxWindowBase::DoGetBestSize() const } } +// by default the origin is not shifted +wxPoint wxWindowBase::GetClientAreaOrigin() const +{ + return wxPoint(0, 0); +} + // set the min/max size of the window void wxWindowBase::SetSizeHints(int minW, int minH, int maxW, int maxH, diff --git a/src/generic/scrolwin.cpp b/src/generic/scrolwin.cpp index e402269a21..8cb0777556 100644 --- a/src/generic/scrolwin.cpp +++ b/src/generic/scrolwin.cpp @@ -419,6 +419,8 @@ void wxScrollHelper::AdjustScrollbars() // current client window int noPagePositions = (int) ( (w/(double)m_xScrollPixelsPerLine) + 0.5 ); if (noPagePositions < 1) noPagePositions = 1; + if ( noPagePositions > m_xScrollLines ) + noPagePositions = m_xScrollLines; // Correct position if greater than extent of canvas minus // the visible portion of it or if below zero @@ -441,6 +443,8 @@ void wxScrollHelper::AdjustScrollbars() // current client window int noPagePositions = (int) ( (h/(double)m_yScrollPixelsPerLine) + 0.5 ); if (noPagePositions < 1) noPagePositions = 1; + if ( noPagePositions > m_yScrollLines ) + noPagePositions = m_yScrollLines; // Correct position if greater than extent of canvas minus // the visible portion of it or if below zero diff --git a/src/univ/control.cpp b/src/univ/control.cpp index a5e0432ef4..1bd4a65ee5 100644 --- a/src/univ/control.cpp +++ b/src/univ/control.cpp @@ -77,7 +77,6 @@ bool wxControl::Create(wxWindow *parent, if ( !wxControlBase::Create(parent, id, pos, size, style, validator, name) ) return FALSE; - m_renderer = wxTheme::Get()->GetRenderer(); m_handler = CreateInputHandler(); SetBackgroundColour(parent->GetBackgroundColour()); @@ -193,13 +192,4 @@ bool wxControl::PerformAction(const wxControlAction& action, return FALSE; } -// ---------------------------------------------------------------------------- -// border -// ---------------------------------------------------------------------------- - -wxBorder wxControl::GetDefaultBorder() const -{ - return AcceptsFocus() ? wxBORDER_SUNKEN : wxBORDER_NONE; -} - #endif // wxUSE_CONTROLS diff --git a/src/univ/listbox.cpp b/src/univ/listbox.cpp index 0d314fd524..415735d8ce 100644 --- a/src/univ/listbox.cpp +++ b/src/univ/listbox.cpp @@ -62,6 +62,7 @@ void wxListBox::Init() // will be calculated later when needed m_lineHeight = 0; m_itemsPerPage = 0; + m_maxWidth = 0; // no items hence no current item m_current = -1; @@ -69,8 +70,12 @@ void wxListBox::Init() // no need to update anything initially m_updateCount = 0; - m_updateScrollbar = - m_showScrollbar = FALSE; + + // no scrollbars to show nor update + m_updateScrollbarX = + m_showScrollbarX = + m_updateScrollbarY = + m_showScrollbarY = FALSE; } bool wxListBox::Create(wxWindow *parent, @@ -83,6 +88,11 @@ bool wxListBox::Create(wxWindow *parent, const wxValidator& validator, const wxString &name) { + // for compatibility accept both the new and old styles - they mean the + // same thing for us + if ( style & wxLB_ALWAYS_SB ) + style |= wxALWAYS_SHOW_SB; + if ( !wxControl::Create(parent, id, pos, size, style, wxDefaultValidator, name) ) return FALSE; @@ -113,7 +123,20 @@ int wxListBox::DoAppend(const wxString& item) size_t index = m_strings.Add(item); m_clientData.Insert(NULL, index); - m_updateScrollbar = TRUE; + m_updateScrollbarY = TRUE; + + if ( HasHorzScrollbar() ) + { + // has the max width increased? + wxClientDC dc(this); + wxCoord width; + dc.GetTextExtent(item, &width, NULL); + if ( width > m_maxWidth ) + { + m_maxWidth = width; + m_updateScrollbarX = TRUE; + } + } RefreshItem(m_strings.GetCount() - 1); @@ -133,7 +156,14 @@ void wxListBox::DoInsertItems(const wxArrayString& items, int pos) m_clientData.Insert(NULL, pos + n); } - m_updateScrollbar = TRUE; + // the number of items has changed + m_updateScrollbarY = TRUE; + + // the max width also might have changed - just recalculate it instead of + // keeping track of it here, this is probably more efficient for a typical + // use pattern + m_maxWidth = 0; + m_updateScrollbarX = TRUE; RefreshItems(pos, count); } @@ -143,6 +173,9 @@ void wxListBox::DoSetItems(const wxArrayString& items, void **clientData) DoClear(); size_t count = items.GetCount(); + if ( !count ) + return; + m_strings.Alloc(count); m_clientData.Alloc(count); for ( size_t n = 0; n < count; n++ ) @@ -151,11 +184,46 @@ void wxListBox::DoSetItems(const wxArrayString& items, void **clientData) m_clientData.Insert(clientData ? clientData[n] : NULL, index); } - m_updateScrollbar = TRUE; + m_updateScrollbarY = TRUE; RefreshAll(); } +void wxListBox::SetString(int n, const wxString& s) +{ + if ( HasHorzScrollbar() ) + { + // we need to update m_maxWidth as changing the string may cause the + // horz scrollbar [dis]appear + wxCoord widthOld; + GetTextExtent(m_strings[n], &widthOld, NULL); + m_strings[n] = s; + + // has the max length changed? + wxCoord width; + GetTextExtent(s, &width, NULL); + + // it might have increased if the new string is long + if ( width > m_maxWidth ) + { + m_maxWidth = width; + m_updateScrollbarX = TRUE; + } + // or also decreased if the old string was the longest one + else if ( (width < m_maxWidth) && (widthOld == m_maxWidth) ) + { + m_maxWidth = 0; + m_updateScrollbarX = TRUE; + } + } + else // no horz scrollbar + { + m_strings[n] = s; + } + + RefreshItem(n); +} + // ---------------------------------------------------------------------------- // removing strings // ---------------------------------------------------------------------------- @@ -180,7 +248,7 @@ void wxListBox::Clear() { DoClear(); - m_updateScrollbar = TRUE; + m_updateScrollbarY = TRUE; RefreshAll(); } @@ -198,7 +266,7 @@ void wxListBox::Delete(int n) m_clientData.RemoveAt(n); - m_updateScrollbar = TRUE; + m_updateScrollbarY = TRUE; RefreshItems(n, GetCount() - n); } @@ -337,8 +405,8 @@ void wxListBox::RefreshItem(int n) // add this item to the others which we have to refresh if ( m_updateFrom < n ) { - if ( m_updateCount < n - m_updateFrom ) - m_updateFrom = n - m_updateFrom; + if ( m_updateCount < n - m_updateFrom + 1 ) + m_updateCount = n - m_updateFrom + 1; } else // n <= m_updateFrom { @@ -355,20 +423,51 @@ void wxListBox::RefreshAll() void wxListBox::OnIdle(wxIdleEvent& event) { - if ( m_updateScrollbar ) + if ( m_updateScrollbarY || m_updateScrollbarX ) { - // is our height enough to show all items? - wxCoord lineHeight = GetLineHeight(); - bool showScrollbar = GetCount()*lineHeight > GetClientSize().y; - if ( showScrollbar != m_showScrollbar ) - { - // TODO: support for horz scrollbar - SetScrollbars(0, lineHeight, 0, GetCount()); + wxSize size = GetClientSize(); - m_showScrollbar = showScrollbar; + // is our height enough to show all items? + int nLines = GetCount(); + wxCoord lineHeight = GetLineHeight(); + bool showScrollbarY = nLines*lineHeight > size.y; + + // check the width too if required + wxCoord charWidth, maxWidth; + bool showScrollbarX; + if ( HasHorzScrollbar() ) + { + charWidth = GetCharWidth(); + maxWidth = GetMaxWidth(); + showScrollbarX = maxWidth > size.x; + } + else // never show it + { + charWidth = maxWidth = 0; + showScrollbarX = FALSE; } - m_updateScrollbar = FALSE; + // reset scrollbars if something changed + if ( (showScrollbarY != m_showScrollbarY) || + (showScrollbarX != m_showScrollbarX) ) + { + int x, y; + GetViewStart(&x, &y); + SetScrollbars(charWidth, lineHeight, + showScrollbarX + ? (maxWidth + 2*charWidth - 1) / charWidth + : 0, + showScrollbarY + ? nLines + : 0, + x, y); + + m_showScrollbarX = showScrollbarX; + m_showScrollbarY = showScrollbarY; + } + + m_updateScrollbarX = FALSE; + m_updateScrollbarY = FALSE; } if ( m_currentChanged ) @@ -390,14 +489,13 @@ void wxListBox::OnIdle(wxIdleEvent& event) } else { - wxRect rect; - rect.x = 0; - rect.y = m_updateFrom*GetLineHeight(); - rect.width = 32767; // larger than our size + wxRect rect = GetClientRect(); + rect.y += m_updateFrom*GetLineHeight(); rect.height = m_updateCount*GetLineHeight(); + CalcScrolledPosition(rect.x, rect.y, &rect.x, &rect.y); wxLogTrace(_T("listbox"), _T("Refreshing items %d..%d (%d-%d)"), - m_updateFrom, m_updateFrom + m_updateCount, + m_updateFrom, m_updateFrom + m_updateCount - 1, rect.GetTop(), rect.GetBottom()); Refresh(TRUE, &rect); @@ -411,10 +509,16 @@ void wxListBox::OnIdle(wxIdleEvent& event) // drawing // ---------------------------------------------------------------------------- +wxBorder wxListBox::GetDefaultBorder() const +{ + return wxBORDER_SUNKEN; +} + void wxListBox::DoDraw(wxControlRenderer *renderer) { +#if 0 // draw the border first - if ( m_showScrollbar ) + if ( m_showScrollbarY ) { // we need to draw a border around the client area renderer->GetRect().width -= GetScrollbar(wxVERTICAL)->GetSize().x; @@ -422,21 +526,25 @@ void wxListBox::DoDraw(wxControlRenderer *renderer) // the base class version does it for us wxControl::DoDraw(renderer); +#endif // adjust the DC to account for scrolling wxDC& dc = renderer->GetDC(); PrepareDC(dc); // get the items which must be redrawn -#if 0 - int y; - GetViewStart(NULL, &y); +#if 1 wxCoord lineHeight = GetLineHeight(); wxRegion rgnUpdate = GetUpdateRegion(); + rgnUpdate.Intersect(GetClientRect()); //dc.SetClippingRegion(rgnUpdate); wxRect rectUpdate = rgnUpdate.GetBox(); - size_t itemFirst = rectUpdate.GetTop() / lineHeight, - itemLast = (rectUpdate.GetBottom() + lineHeight - 1) / lineHeight, + + int yTop, yBottom; + CalcUnscrolledPosition(0, rectUpdate.GetTop(), NULL, &yTop); + CalcUnscrolledPosition(0, rectUpdate.GetBottom(), NULL, &yBottom); + size_t itemFirst = yTop / lineHeight, + itemLast = (yBottom + lineHeight - 1) / lineHeight, itemMax = m_strings.GetCount(); if ( itemFirst >= itemMax ) @@ -499,6 +607,25 @@ wxCoord wxListBox::GetLineHeight() const return m_lineHeight; } +wxCoord wxListBox::GetMaxWidth() const +{ + if ( m_maxWidth == -1 ) + { + wxCoord width; + size_t count = m_strings.GetCount(); + for ( size_t n =0; n < count; n++ ) + { + GetTextExtent(m_strings[n], &width, NULL); + if ( width > m_maxWidth ) + { + wxConstCast(this, wxListBox)->m_maxWidth = width; + } + } + } + + return m_maxWidth; +} + void wxListBox::OnSize(wxSizeEvent& event) { // recalculate the number of items per page @@ -509,7 +636,7 @@ void wxListBox::OnSize(wxSizeEvent& event) void wxListBox::DoSetFirstItem(int n) { - wxFAIL_MSG( _T("TODO") ); + SetCurrentItem(n); } wxSize wxListBox::DoGetBestClientSize() const @@ -582,7 +709,7 @@ void wxListBox::SetCurrentItem(int n) if ( n != m_current ) { if ( m_current != -1 ) - RefreshItem(n); + RefreshItem(m_current); m_current = n; @@ -605,7 +732,7 @@ void wxListBox::SetCurrentItem(int n) void wxListBox::EnsureVisible() { - if ( !m_showScrollbar ) + if ( !m_showScrollbarY ) { // nothing to do - everything is shown anyhow return; @@ -720,6 +847,7 @@ wxStdListboxInputHandler::wxStdListboxInputHandler(wxInputHandler *handler) : wxStdInputHandler(handler) { m_winCapture = NULL; + m_btnCapture = 0; } int wxStdListboxInputHandler::HitTest(const wxListBox *lbox, @@ -736,8 +864,8 @@ bool wxStdListboxInputHandler::HandleKey(wxControl *control, const wxKeyEvent& event, bool pressed) { - // we're only interested in the key presses - if ( pressed ) + // we're only interested in the (normal) key presses + if ( pressed && !event.AltDown() ) { wxControlAction action; switch ( event.GetKeyCode() ) @@ -773,18 +901,32 @@ bool wxStdListboxInputHandler::HandleMouse(wxControl *control, // mouse events: for both of them clicking the item selects or toggles it, // but multiple selection listboxes are different: the item is focused // when clicked and only toggled when the button is released - if ( ((control->GetWindowStyle() & wxLB_MULTIPLE) && event.ButtonUp()) - || event.ButtonDown() || event.LeftDClick() ) + if ( (m_btnCapture && + (control->GetWindowStyle() & wxLB_MULTIPLE) && + event.ButtonUp(m_btnCapture)) + || event.ButtonDown() + || event.LeftDClick() ) { wxListBox *lbox = wxStaticCast(control, wxListBox); int item = HitTest(lbox, event); if ( item != -1 ) { wxControlAction action; - if ( event.ButtonUp() ) + if ( m_btnCapture && event.ButtonUp(m_btnCapture) ) { - m_winCapture->ReleaseMouse(); - m_winCapture = NULL; + if ( m_winCapture ) + { + m_winCapture->ReleaseMouse(); + m_winCapture = NULL; + m_btnCapture = 0; + } + else + { + // this is not supposed to happen - if we get here, the + // even is from the mouse button which had been pressed + // before and we must have captured the mouse back then + wxFAIL_MSG(_T("logic error in listbox mosue handling")); + } action = wxACTION_LISTBOX_TOGGLE; } @@ -797,8 +939,11 @@ bool wxStdListboxInputHandler::HandleMouse(wxControl *control, // capture the mouse to track the selected item m_winCapture = lbox; m_winCapture->CaptureMouse(); - - action = wxACTION_LISTBOX_SETFOCUS; + m_btnCapture = event.LeftDown() + ? 1 + : event.RightDown() + ? 3 + : 2; } else { @@ -809,13 +954,19 @@ bool wxStdListboxInputHandler::HandleMouse(wxControl *control, { action = wxACTION_LISTBOX_SELECT; } + + // in any case, clicking an item makes it the current one + lbox->PerformAction(wxACTION_LISTBOX_SETFOCUS, item); } else // event.LeftDClick() { action = wxACTION_LISTBOX_ACTIVATE; } - lbox->PerformAction(action, item); + if ( !!action ) + { + lbox->PerformAction(action, item); + } return TRUE; } diff --git a/src/univ/renderer.cpp b/src/univ/renderer.cpp index 50220c1df3..5f03a976b4 100644 --- a/src/univ/renderer.cpp +++ b/src/univ/renderer.cpp @@ -325,14 +325,6 @@ void wxControlRenderer::DrawBorder() // draw outline m_renderer->DrawBorder(m_dc, m_window->GetBorder(), m_rect, flags, &m_rect); - - // fill the inside unless we have the background bitmap as we don't want to - // overwrite it - if ( !m_window->GetBackgroundBitmap().Ok() ) - { - m_renderer->DrawBackground(m_dc, m_window->GetBackgroundColour(), - m_rect, flags); - } } void wxControlRenderer::DrawLabel(const wxBitmap& bitmap, @@ -398,12 +390,19 @@ void wxControlRenderer::DrawBitmap(const wxBitmap& bitmap) void wxControlRenderer::DrawBackgroundBitmap() { - // get the bitmap and the flags - int alignment; - wxStretch stretch; - wxBitmap bmp = m_window->GetBackgroundBitmap(&alignment, &stretch); - - DrawBitmap(bmp, m_rect, alignment, stretch); + if ( m_window->GetBackgroundBitmap().Ok() ) + { + // get the bitmap and the flags + int alignment; + wxStretch stretch; + wxBitmap bmp = m_window->GetBackgroundBitmap(&alignment, &stretch); + DrawBitmap(bmp, m_rect, alignment, stretch); + } + else // just fill it with bg colour if no bitmap + { + m_renderer->DrawBackground(m_dc, m_window->GetBackgroundColour(), + m_rect, m_window->GetStateFlags()); + } } void wxControlRenderer::DrawBitmap(const wxBitmap& bitmap, @@ -549,7 +548,7 @@ void wxControlRenderer::DrawScrollbar(const wxScrollBar *scrollbar, // and the thumb wxScrollBar::Element elem = wxScrollBar::Element_Thumb; wxRect rectThumb = m_renderer->GetScrollbarRect(scrollbar, elem); - if ( rgnUpdate.Contains(rectThumb) ) + if ( rectThumb.width && rectThumb.height && rgnUpdate.Contains(rectThumb) ) { wxLogTrace(_T("scroll"), _T("drawing thumb at (%d, %d)-(%d, %d)"), rectThumb.GetLeft(), @@ -580,13 +579,31 @@ void wxControlRenderer::DrawItems(const wxListBox *lbox, { // prepare for the drawing: calc the initial position wxCoord lineHeight = lbox->GetLineHeight(); - int lines, pixelsPerLine; - lbox->GetViewStart(NULL, &lines); - lbox->GetScrollPixelsPerUnit(NULL, &pixelsPerLine); - wxRect rect = m_rect; - rect.y += itemFirst*lineHeight - lines*pixelsPerLine; + + // note that SetClippingRegion() needs the physical (unscrolled) + // coordinates while we use the logical (scrolled) ones for the drawing + // itself + wxRect rect = lbox->GetClientRect(); + + // keep the text inside the client rect or we will overwrite the vertical + // scrollbar for the long strings + m_dc.SetClippingRegion(rect.x, rect.y, rect.width + 1, rect.height + 1); + + // the rect should go to the right visible border + int widthTotal; + lbox->GetVirtualSize(&widthTotal, NULL); + if ( widthTotal ) + rect.width = widthTotal; + //else: no horz scrolling at all + + // adjust the rect position now + lbox->CalcScrolledPosition(rect.x, rect.y, &rect.x, &rect.y); + rect.y += itemFirst*lineHeight; rect.height = lineHeight; + // we'll keep the text colour unchanged + m_dc.SetTextForeground(lbox->GetForegroundColour()); + // an item should have the focused rect only when the app has focus, so // make sure that we never set wxCONTROL_FOCUSED flag if it doesn't int itemCurrent = wxTheApp->IsActive() ? lbox->GetCurrentItem() : -1; diff --git a/src/univ/scrolbar.cpp b/src/univ/scrolbar.cpp index 1829407da5..7760bffc1b 100644 --- a/src/univ/scrolbar.cpp +++ b/src/univ/scrolbar.cpp @@ -54,12 +54,19 @@ public: const wxControlAction& action, wxScrollBar *control); + void StartAutoScroll(); + virtual void Notify(); +protected: + void DoNotify(); + private: wxStdScrollBarInputHandler *m_handler; wxControlAction m_action; wxScrollBar *m_control; + + bool m_skipNext; }; // ============================================================================ @@ -101,9 +108,8 @@ bool wxScrollBar::Create(wxWindow *parent, const wxValidator& validator, const wxString &name) { - // the scrollbars always have the standard border so far + // the scrollbars never have the border style &= ~wxBORDER_MASK; - style |= wxBORDER_SUNKEN; if ( !wxControl::Create(parent, id, pos, size, style, wxDefaultValidator, name) ) return FALSE; @@ -221,27 +227,38 @@ void wxScrollBar::OnIdle(wxIdleEvent& event) { // we try to avoid redrawing the entire shaft (which might // be quite long) if possible by only redrawing the area - // between the old and current positions of the thumb - if ( m_thumbPosOld != -1 ) + // wich really changed + if ( (n == Element_Bar_1 || n == Element_Bar_2) && + (m_thumbPosOld != -1) ) { + // the less efficient but more reliable (i.e. this will + // probably work everywhere) version: refresh the + // distance covered by thumb since the last update +#if 0 wxRect rectOld = GetRenderer()->GetScrollbarRect(this, - (Element)n, - m_thumbPosOld); + (Element)n, + m_thumbPosOld); if ( IsVertical() ) { if ( n == Element_Bar_1 ) rect.SetTop(rectOld.GetBottom()); else - rect.SetBottom(rect.GetTop()); + rect.SetBottom(rectOld.GetBottom()); } else // horizontal { if ( n == Element_Bar_1 ) rect.SetLeft(rectOld.GetRight()); else - rect.SetRight(rect.GetLeft()); + rect.SetRight(rectOld.GetRight()); } +#else // efficient version: only repaint the area occupied by + // the thumb previously - we can't do better than this + rect = GetRenderer()->GetScrollbarRect(this, + Element_Thumb, + m_thumbPosOld); +#endif // 0/1 } Refresh(TRUE, &rect); @@ -265,12 +282,22 @@ void wxScrollBar::DoDraw(wxControlRenderer *renderer) } // ---------------------------------------------------------------------------- -// input processing +// state flags // ---------------------------------------------------------------------------- +int wxScrollBar::GetState(Element which) const +{ + // if the entire scrollbar is disabled, all of its elements are too + int flags = m_elementsState[which]; + if ( !IsEnabled() ) + flags |= wxCONTROL_DISABLED; + + return flags; +} + void wxScrollBar::SetState(Element which, int flags) { - if ( (m_elementsState[which] & ~wxCONTROL_DIRTY) != (unsigned)flags ) + if ( (int)(m_elementsState[which] & ~wxCONTROL_DIRTY) != flags ) { m_elementsState[which] = flags | wxCONTROL_DIRTY; @@ -278,6 +305,10 @@ void wxScrollBar::SetState(Element which, int flags) } } +// ---------------------------------------------------------------------------- +// input processing +// ---------------------------------------------------------------------------- + bool wxScrollBar::PerformAction(const wxControlAction& action, long numArg, const wxString& strArg) @@ -389,11 +420,40 @@ wxScrollBarTimer::wxScrollBarTimer(wxStdScrollBarInputHandler *handler, m_handler = handler; m_action = action; m_control = control; + + m_skipNext = FALSE; +} + +void wxScrollBarTimer::StartAutoScroll() +{ + // start scrolling immediately + DoNotify(); + + // there is an initial delay before the scrollbar starts scrolling - + // implement it by ignoring the first timer expiration and only start + // scrolling from the second one + m_skipNext = TRUE; + Start(200); // FIXME: hardcoded delay +} + +void wxScrollBarTimer::DoNotify() +{ + m_handler->OnScrollTimer(m_control, m_action); } void wxScrollBarTimer::Notify() { - m_handler->OnScrollTimer(m_control, m_action); + if ( m_skipNext ) + { + // scroll normally now - reduce the delay + Start(50); // FIXME: hardcoded delay + + m_skipNext = FALSE; + } + else + { + DoNotify(); + } } // ---------------------------------------------------------------------------- @@ -603,14 +663,12 @@ bool wxStdScrollBarInputHandler::HandleMouse(wxControl *control, // start dragging if ( hasAction ) { - m_timerScroll = new wxScrollBarTimer(this, - action, - scrollbar); - // start scrolling immediately - m_timerScroll->Notify(); - - // and continue it later - m_timerScroll->Start(50); // FIXME hardcoded delay + // this slightly unreadable code is necessary because + // m_timerScroll is of class wxTimer, not wxScrollBarTimer + wxScrollBarTimer *timerScroll = + new wxScrollBarTimer(this, action, scrollbar); + m_timerScroll = timerScroll; + timerScroll->StartAutoScroll(); } //else: no (immediate) action diff --git a/src/univ/themes/gtk.cpp b/src/univ/themes/gtk.cpp index e974084605..6bcc16454a 100644 --- a/src/univ/themes/gtk.cpp +++ b/src/univ/themes/gtk.cpp @@ -95,17 +95,21 @@ public: wxOrientation orient, const wxRect& rect, int flags = 0); + virtual void DrawScrollCorner(wxDC& dc, + const wxRect& rect); virtual void DrawItem(wxDC& dc, const wxString& label, const wxRect& rect, int flags = 0); virtual void AdjustSize(wxSize *size, const wxWindow *window); + virtual wxRect GetBorderDimensions(wxBorder border) const; // hit testing for the input handlers virtual wxRect GetScrollbarRect(const wxScrollBar *scrollbar, wxScrollBar::Element elem, int thumbPos = -1) const; + virtual wxCoord GetScrollbarSize(const wxScrollBar *scrollbar); virtual wxHitTest HitTestScrollbar(const wxScrollBar *scrollbar, const wxPoint& pt) const; virtual wxCoord ScrollbarToPixel(const wxScrollBar *scrollbar, @@ -547,7 +551,7 @@ void wxGTKRenderer::DrawBorder(wxDC& dc, break; default: - wxFAIL_MSG(_T("unknwon border type")); + wxFAIL_MSG(_T("unknown border type")); // fall through case wxBORDER_DEFAULT: @@ -559,6 +563,44 @@ void wxGTKRenderer::DrawBorder(wxDC& dc, *rectIn = rect; } +wxRect wxGTKRenderer::GetBorderDimensions(wxBorder border) const +{ + wxCoord width; + switch ( border ) + { + case wxBORDER_RAISED: + case wxBORDER_SUNKEN: + width = 2; + break; + + case wxBORDER_SIMPLE: + case wxBORDER_STATIC: + width = 1; + break; + + case wxBORDER_DOUBLE: + width = 3; + break; + + default: + wxFAIL_MSG(_T("unknown border type")); + // fall through + + case wxBORDER_DEFAULT: + case wxBORDER_NONE: + width = 0; + break; + } + + wxRect rect; + rect.x = + rect.y = + rect.width = + rect.height = width; + + return rect; +} + // ---------------------------------------------------------------------------- // button border // ---------------------------------------------------------------------------- @@ -1091,6 +1133,11 @@ void wxGTKRenderer::DrawScrollbarShaft(wxDC& dc, DoDrawBackground(dc, m_scheme->Get(wxColourScheme::SCROLLBAR), rectBar); } +void wxGTKRenderer::DrawScrollCorner(wxDC& dc, const wxRect& rect) +{ + DoDrawBackground(dc, m_scheme->Get(wxColourScheme::CONTROL), rect); +} + wxRect wxGTKRenderer::GetScrollbarRect(const wxScrollBar *scrollbar, wxScrollBar::Element elem, int thumbPos) const @@ -1099,6 +1146,11 @@ wxRect wxGTKRenderer::GetScrollbarRect(const wxScrollBar *scrollbar, thumbPos, GetScrollbarArrowSize(scrollbar)); } +wxCoord wxGTKRenderer::GetScrollbarSize(const wxScrollBar *scrollbar) +{ + return StandardScrollBarSize(scrollbar, GetScrollbarArrowSize(scrollbar)); +} + wxHitTest wxGTKRenderer::HitTestScrollbar(const wxScrollBar *scrollbar, const wxPoint& pt) const { @@ -1149,34 +1201,9 @@ void wxGTKRenderer::AdjustSize(wxSize *size, const wxWindow *window) else { // take into account the border width - wxBorder border = (wxBorder)(window->GetWindowStyle() & wxBORDER_MASK); - switch ( border ) - { - case wxBORDER_SUNKEN: - case wxBORDER_RAISED: - size->x += 4; - size->y += 4; - break; - - case wxBORDER_SIMPLE: - case wxBORDER_STATIC: - size->x += 2; - size->y += 2; - break; - - case wxBORDER_DOUBLE: - size->x += 6; - size->y += 6; - break; - - default: - wxFAIL_MSG(_T("unknwon border type")); - // fall through - - case wxBORDER_DEFAULT: - case wxBORDER_NONE: - break; - } + wxRect rectBorder = GetBorderDimensions(window->GetBorder()); + size->x += rectBorder.x + rectBorder.width; + size->y += rectBorder.y + rectBorder.height; } } diff --git a/src/univ/themes/win32.cpp b/src/univ/themes/win32.cpp index 6a280e387d..76d94f049f 100644 --- a/src/univ/themes/win32.cpp +++ b/src/univ/themes/win32.cpp @@ -113,23 +113,27 @@ public: wxOrientation orient, const wxRect& rect, int flags = 0); + virtual void DrawScrollCorner(wxDC& dc, + const wxRect& rect); virtual void DrawItem(wxDC& dc, const wxString& label, const wxRect& rect, int flags = 0); virtual void AdjustSize(wxSize *size, const wxWindow *window); + virtual wxRect GetBorderDimensions(wxBorder border) const; virtual wxRect GetScrollbarRect(const wxScrollBar *scrollbar, wxScrollBar::Element elem, int thumbPos = -1) const; + virtual wxCoord GetScrollbarSize(const wxScrollBar *scrollbar); virtual wxHitTest HitTestScrollbar(const wxScrollBar *scrollbar, const wxPoint& pt) const; virtual wxCoord ScrollbarToPixel(const wxScrollBar *scrollbar, int thumbPos = -1); virtual int PixelToScrollbar(const wxScrollBar *scrollbar, wxCoord coord); virtual wxCoord GetListboxItemHeight(wxCoord fontHeight) - { return fontHeight + 2; } + { return fontHeight; } protected: // common part of DrawLabel() and DrawItem() @@ -709,7 +713,7 @@ void wxWin32Renderer::DrawBorder(wxDC& dc, break; default: - wxFAIL_MSG(_T("unknwon border type")); + wxFAIL_MSG(_T("unknown border type")); // fall through case wxBORDER_DEFAULT: @@ -721,6 +725,44 @@ void wxWin32Renderer::DrawBorder(wxDC& dc, *rectIn = rect; } +wxRect wxWin32Renderer::GetBorderDimensions(wxBorder border) const +{ + wxCoord width; + switch ( border ) + { + case wxBORDER_RAISED: + case wxBORDER_SUNKEN: + width = 2; + break; + + case wxBORDER_SIMPLE: + case wxBORDER_STATIC: + width = 1; + break; + + case wxBORDER_DOUBLE: + width = 3; + break; + + default: + wxFAIL_MSG(_T("unknown border type")); + // fall through + + case wxBORDER_DEFAULT: + case wxBORDER_NONE: + width = 0; + break; + } + + wxRect rect; + rect.x = + rect.y = + rect.width = + rect.height = width; + + return rect; +} + // ---------------------------------------------------------------------------- // button border // ---------------------------------------------------------------------------- @@ -847,29 +889,34 @@ void wxWin32Renderer::DrawFocusRect(wxDC& dc, const wxRect& rect) #if 0 DrawRect(dc, &rect, wxPen(*wxBLACK, 0, wxDOT)); #else - // draw the pixels manually + // draw the pixels manually: note that to behave in the same manner as + // DrawRect(), we must exclude the bottom and right borders from the + // rectangle + wxCoord x1 = rect.GetLeft(), + y1 = rect.GetTop(), + x2 = rect.GetRight(), + y2 = rect.GetBottom(); + dc.SetPen(wxPen(*wxBLACK, 0, wxSOLID)); - //dc.SetLogicalFunction(wxXOR); + dc.SetLogicalFunction(wxINVERT); - // Windows quirk: appears to draw them like this, from right to left - // (and I don't have Hebrew windows to see what happens there :-) - for ( wxCoord x = rect.GetRight(); x >= rect.GetLeft(); x -= 2 ) - { - dc.DrawPoint(x, rect.GetTop()); - dc.DrawPoint(x, rect.GetBottom()); - } + wxCoord z; + for ( z = x1 + 1; z < x2; z += 2 ) + dc.DrawPoint(z, rect.GetTop()); - wxCoord shift = rect.width % 2 ? 0 : 1; - for ( wxCoord y = rect.GetTop() + 2; y <= rect.GetBottom(); y+= 2 ) - { - dc.DrawPoint(rect.GetLeft(), y - shift); - dc.DrawPoint(rect.GetRight(), y); - } + wxCoord shift = z == x2 ? 0 : 1; + for ( z = y1 + shift; z < y2; z += 2 ) + dc.DrawPoint(x2, z); - if ( shift ) - { - dc.DrawPoint(rect.GetLeft(), rect.GetBottom() - 1); - } + shift = z == y2 ? 0 : 1; + for ( z = x2 - shift; z > x1; z -= 2 ) + dc.DrawPoint(z, y2); + + shift = z == x1 ? 0 : 1; + for ( z = y2 - shift; z > y1; z -= 2 ) + dc.DrawPoint(x1, z); + + dc.SetLogicalFunction(wxCOPY); #endif // 0/1 } @@ -912,6 +959,16 @@ void wxWin32Renderer::DrawLabel(wxDC& dc, if ( flags & wxCONTROL_FOCUSED ) { + if ( flags & wxCONTROL_PRESSED ) + { + // the focus rectangle is never pressed, so undo the shift done + // above + rectText.x--; + rectText.y--; + rectText.width--; + rectText.height--; + } + DrawFocusRect(dc, rectText); } } @@ -924,20 +981,21 @@ void wxWin32Renderer::DrawItem(wxDC& dc, wxColour colFg; if ( flags & wxCONTROL_SELECTED ) { - dc.SetBrush(wxBrush(m_scheme->Get(wxColourScheme::HIGHLIGHT), wxSOLID)); - dc.SetPen(*wxTRANSPARENT_PEN); - dc.DrawRectangle(rect); + wxColour colBg = m_scheme->Get(wxColourScheme::HIGHLIGHT); colFg = dc.GetTextForeground(); dc.SetTextForeground(m_scheme->Get(wxColourScheme::HIGHLIGHT_TEXT)); + dc.SetBrush(wxBrush(colBg, wxSOLID)); + dc.SetPen(wxPen(colBg, 0, wxSOLID)); + dc.DrawRectangle(rect); } wxRect rectText = rect; rectText.x += 2; + rectText.width -= 2; dc.DrawLabel(label, wxNullBitmap, rectText); if ( flags & wxCONTROL_FOCUSED ) { - dc.SetBrush(*wxTRANSPARENT_BRUSH); DrawFocusRect(dc, rect); } @@ -1037,6 +1095,7 @@ void wxWin32Renderer::DrawArrowButton(wxDC& dc, wxArrowStyle arrowStyle) { wxRect rect = rectAll; + DoDrawBackground(dc, m_scheme->Get(wxColourScheme::CONTROL), rect); DrawArrowBorder(dc, &rect, arrowStyle == Arrow_Pressed); DrawArrow(dc, rect, arrowDir, arrowStyle); } @@ -1061,6 +1120,11 @@ void wxWin32Renderer::DrawScrollbarShaft(wxDC& dc, rectBar); } +void wxWin32Renderer::DrawScrollCorner(wxDC& dc, const wxRect& rect) +{ + DoDrawBackground(dc, m_scheme->Get(wxColourScheme::CONTROL), rect); +} + wxRect wxWin32Renderer::GetScrollbarRect(const wxScrollBar *scrollbar, wxScrollBar::Element elem, int thumbPos) const @@ -1069,6 +1133,11 @@ wxRect wxWin32Renderer::GetScrollbarRect(const wxScrollBar *scrollbar, thumbPos, m_sizeScrollbarArrow); } +wxCoord wxWin32Renderer::GetScrollbarSize(const wxScrollBar *scrollbar) +{ + return StandardScrollBarSize(scrollbar, m_sizeScrollbarArrow); +} + wxHitTest wxWin32Renderer::HitTestScrollbar(const wxScrollBar *scrollbar, const wxPoint& pt) const { @@ -1115,34 +1184,9 @@ void wxWin32Renderer::AdjustSize(wxSize *size, const wxWindow *window) else { // take into account the border width - wxBorder border = (wxBorder)(window->GetWindowStyle() & wxBORDER_MASK); - switch ( border ) - { - case wxBORDER_SUNKEN: - case wxBORDER_RAISED: - size->x += 4; - size->y += 4; - break; - - case wxBORDER_SIMPLE: - case wxBORDER_STATIC: - size->x += 2; - size->y += 2; - break; - - case wxBORDER_DOUBLE: - size->x += 6; - size->y += 6; - break; - - default: - wxFAIL_MSG(_T("unknwon border type")); - // fall through - - case wxBORDER_DEFAULT: - case wxBORDER_NONE: - break; - } + wxRect rectBorder = GetBorderDimensions(window->GetBorder()); + size->x += rectBorder.x + rectBorder.width; + size->y += rectBorder.y + rectBorder.height; } } diff --git a/src/univ/winuniv.cpp b/src/univ/winuniv.cpp index 35d8301112..04878ed7a6 100644 --- a/src/univ/winuniv.cpp +++ b/src/univ/winuniv.cpp @@ -73,7 +73,31 @@ void wxWindow::Init() m_isCurrent = FALSE; - m_renderer = (wxRenderer *)NULL; + m_renderer = wxTheme::Get()->GetRenderer(); +} + +bool wxWindow::Create(wxWindow *parent, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) +{ + if ( !wxWindowNative::Create(parent, id, pos, size, + style | wxCLIP_CHILDREN, name) ) + { + return FALSE; + } + + // if we should always have the scrollbar, do show it + if ( GetWindowStyle() & wxALWAYS_SHOW_SB ) + { + m_scrollbarVert = new wxScrollBar(this, -1, + wxDefaultPosition, wxDefaultSize, + wxSB_VERTICAL); + } + + return TRUE; } // ---------------------------------------------------------------------------- @@ -110,13 +134,22 @@ const wxBitmap& wxWindow::GetBackgroundBitmap(int *alignment, // the event handler executed when the window background must be painted void wxWindow::OnErase(wxEraseEvent& event) { - wxControlRenderer renderer(this, *event.GetDC(), - wxTheme::Get()->GetRenderer()); + wxControlRenderer renderer(this, *event.GetDC(), m_renderer); - if ( !DoDrawBackground(&renderer) ) + DoDrawBackground(&renderer); + + // if we have both scrollbars, we also have a square in the corner between + // them which we must paint + if ( m_scrollbarVert && m_scrollbarHorz ) { - // not processed - event.Skip(); + wxRect rectCorner; + wxPoint ptOrigin = GetClientAreaOrigin(); + wxSize sizeClient = GetClientSize(); + rectCorner.x = ptOrigin.x + m_scrollbarHorz->GetSize().x; + rectCorner.y = ptOrigin.y + m_scrollbarVert->GetSize().y; + rectCorner.width = m_scrollbarVert->GetSize().x; + rectCorner.height = m_scrollbarHorz->GetSize().y; + m_renderer->DrawScrollCorner(*event.GetDC(), rectCorner); } } @@ -134,26 +167,30 @@ void wxWindow::OnPaint(wxPaintEvent& event) wxPaintDC dc(this); wxControlRenderer renderer(this, dc, m_renderer); - // do draw the control! + // first, draw the border + DoDrawBorder(&renderer); + + // and then draw the control DoDraw(&renderer); } } bool wxWindow::DoDrawBackground(wxControlRenderer *renderer) { - if ( !m_bitmapBg.Ok() ) - return FALSE; - renderer->DrawBackgroundBitmap(); return TRUE; } -void wxWindow::DoDraw(wxControlRenderer *renderer) +void wxWindow::DoDrawBorder(wxControlRenderer *renderer) { renderer->DrawBorder(); } +void wxWindow::DoDraw(wxControlRenderer *renderer) +{ +} + // ---------------------------------------------------------------------------- // state flags // ---------------------------------------------------------------------------- @@ -251,15 +288,39 @@ void wxWindow::DoSetClientSize(int width, int height) wxWindowNative::DoSetClientSize(width, height); } +wxPoint wxWindow::GetClientAreaOrigin() const +{ + wxPoint pt = wxWindowBase::GetClientAreaOrigin(); + + if ( m_renderer ) + pt += m_renderer->GetBorderDimensions(GetBorder()).GetPosition(); + + return pt; +} + void wxWindow::DoGetClientSize(int *width, int *height) const { wxWindowNative::DoGetClientSize(width, height); - if ( width && m_scrollbarVert ) - *width -= m_scrollbarVert->GetSize().x; + wxRect rectBorder; + if ( m_renderer ) + rectBorder = m_renderer->GetBorderDimensions(GetBorder()); - if ( height && m_scrollbarHorz ) - *height -= m_scrollbarHorz->GetSize().y; + if ( width ) + { + if ( m_scrollbarVert ) + *width -= m_scrollbarVert->GetSize().x; + + *width -= rectBorder.x + rectBorder.width; + } + + if ( height ) + { + if ( m_scrollbarHorz ) + *height -= m_scrollbarHorz->GetSize().y; + + *height -= rectBorder.y + rectBorder.height; + } } // ---------------------------------------------------------------------------- @@ -270,21 +331,31 @@ void wxWindow::DoGetClientSize(int *width, int *height) const void wxWindow::PositionScrollbars() { - wxCoord x, y; - DoGetSize(&x, &y); + wxRect rectClient = GetClientRect(); int width = m_scrollbarVert ? m_scrollbarVert->GetSize().x : 0; int height = m_scrollbarHorz ? m_scrollbarHorz->GetSize().y : 0; if ( m_scrollbarVert ) - m_scrollbarVert->SetSize(x - width, 0, width, y - height); + { + m_scrollbarVert->SetSize(rectClient.GetRight() - 1, + rectClient.GetTop() - 2, + width, + rectClient.GetHeight()); + } + if ( m_scrollbarHorz ) - m_scrollbarHorz->SetSize(0, y - height, x - width, height); + { + m_scrollbarHorz->SetSize(rectClient.GetLeft() - 2, + rectClient.GetBottom() - 1, + rectClient.GetWidth(), + height); + } } void wxWindow::SetScrollbar(int orient, int pos, - int thumb, + int pageSize, int range, bool refresh) { @@ -305,19 +376,31 @@ void wxWindow::SetScrollbar(int orient, PositionScrollbars(); } + else if ( GetWindowStyle() & wxALWAYS_SHOW_SB ) + { + // we might have disabled it before + scrollbar->Enable(); + } - scrollbar->SetScrollbar(pos, thumb, range, thumb, refresh); + scrollbar->SetScrollbar(pos, pageSize, range, pageSize, refresh); } else // no range means no scrollbar { if ( scrollbar ) { - delete scrollbar; - - if ( orient & wxVERTICAL ) - m_scrollbarVert = NULL; + if ( GetWindowStyle() & wxALWAYS_SHOW_SB ) + { + scrollbar->Disable(); + } else - m_scrollbarHorz = NULL; + { + delete scrollbar; + + if ( orient & wxVERTICAL ) + m_scrollbarVert = NULL; + else + m_scrollbarHorz = NULL; + } } } } @@ -367,7 +450,10 @@ void wxWindow::ScrollWindow(int dx, int dy, const wxRect *rect) wxLogTrace(_T("scroll"), _T("window is %dx%d, scroll by %d, %d"), sizeTotal.x, sizeTotal.y, dx, dy); - wxPoint ptSource, ptDest; + wxPoint ptSource, ptDest, ptOrigin; + ptSource = + ptDest = + ptOrigin = GetClientAreaOrigin(); wxSize size; size.x = sizeTotal.x - abs(dx); size.y = sizeTotal.y - abs(dy); @@ -386,27 +472,23 @@ void wxWindow::ScrollWindow(int dx, int dy, const wxRect *rect) if ( dx < 0 ) { // scroll to the right, move to the left - ptSource.x = -dx; - ptDest.x = 0; + ptSource.x -= dx; } else { // scroll to the left, move to the right - ptSource.x = 0; - ptDest.x = dx; + ptDest.x += dx; } if ( dy < 0 ) { // scroll down, move up - ptSource.y = -dy; - ptDest.y = 0; + ptSource.y -= dy; } else { // scroll up, move down - ptSource.y = 0; - ptDest.y = dy; + ptDest.y += dy; } // do move @@ -429,23 +511,23 @@ void wxWindow::ScrollWindow(int dx, int dy, const wxRect *rect) // it bad? wxRect rect; + rect.x = ptOrigin.x; + rect.y = ptOrigin.y; if ( dx ) { if ( dx < 0 ) { // refresh the area along the right border - rect.x = size.x; + rect.x += size.x; rect.width = -dx; } else { // refresh the area along the left border - rect.x = 0; rect.width = dx; } - rect.y = 0; rect.height = sizeTotal.y; wxLogTrace(_T("scroll"), _T("refreshing (%d, %d)-(%d, %d)"), @@ -459,17 +541,15 @@ void wxWindow::ScrollWindow(int dx, int dy, const wxRect *rect) if ( dy < 0 ) { // refresh the area along the bottom border - rect.y = size.y; + rect.y += size.y; rect.height = -dy; } else { // refresh the area along the top border - rect.y = 0; rect.height = dy; } - rect.x = 0; rect.width = sizeTotal.x; wxLogTrace(_T("scroll"), _T("refreshing (%d, %d)-(%d, %d)"),