Hi, Please find attached my patches to fix Bug 37484 [1]. It would be great if someone could review them.
I ended up implementing my own method for scrolling to a listbox entry, and also making public the methods related to absolute position of entries in the list. I hope this was an OK thing to do? I tried hard to make the code that saves & restores list position compact and readable; please tell me if it makes sense. I have built and tested my changes a lot, but only on linux. Kind regards, Luke. [1] https://bugs.freedesktop.org/show_bug.cgi?id=37484
From f3726e31957995c8554cdb84e093854977dd7623 Mon Sep 17 00:00:00 2001 From: Luke Symes <allsy...@gmail.com> Date: Wed, 22 Jun 2011 15:40:26 +1200 Subject: [PATCH 1/3] Set the listbox height to an integer multiple of the listbox entry height. This ensures that we don't get a half visible entry at the bottom of the view. --- svtools/source/contnr/svimpbox.cxx | 11 +++++++++++ 1 files changed, 11 insertions(+), 0 deletions(-) diff --git a/svtools/source/contnr/svimpbox.cxx b/svtools/source/contnr/svimpbox.cxx index da5aff8..ab6d4e1 100644 --- a/svtools/source/contnr/svimpbox.cxx +++ b/svtools/source/contnr/svimpbox.cxx @@ -1358,8 +1358,19 @@ void SvImpLBox::InitScrollBarBox() void SvImpLBox::Resize() { Size aSize( pView->Control::GetOutputSizePixel()); + long nEntryHeight = pView->GetEntryHeight(); + int nEntryCount = 0; + if( aSize.Width() <= 0 || aSize.Height() <= 0 ) return; + if( nEntryHeight ) + { + // Set the view height to an integer multiple of the entry height. + nEntryCount = (int) aSize.Height() / nEntryHeight; + aSize.Height() = pView->GetEntryHeight() * nEntryCount; + pView->Control::SetOutputSizePixel( aSize ); + } + nFlags |= F_IN_RESIZE; InitScrollBarBox(); -- 1.7.5.4
From 6bb119906cb470c56a5fafde52bb98202d93f71c Mon Sep 17 00:00:00 2001 From: Luke Symes <allsy...@gmail.com> Date: Wed, 22 Jun 2011 15:56:50 +1200 Subject: [PATCH 2/3] Implement ScrollToAbsPos for listboxes. Scrolls the listbox so the given entry is the first visible entry. The existing MakeVisible is not good enough since it won't scroll down if the given entry is already visible. --- svtools/inc/svtools/svtreebx.hxx | 1 + svtools/inc/svtools/treelist.hxx | 6 ++++++ svtools/source/contnr/svimpbox.cxx | 26 ++++++++++++++++++++++++++ svtools/source/contnr/svtreebx.cxx | 5 +++++ svtools/source/inc/svimpbox.hxx | 1 + 5 files changed, 39 insertions(+), 0 deletions(-) diff --git a/svtools/inc/svtools/svtreebx.hxx b/svtools/inc/svtools/svtreebx.hxx index 4453d0f..2b0a100 100644 --- a/svtools/inc/svtools/svtreebx.hxx +++ b/svtools/inc/svtools/svtreebx.hxx @@ -369,6 +369,7 @@ public: SvLBoxEntry* GetFirstEntryInView() const; SvLBoxEntry* GetNextEntryInView(SvLBoxEntry*) const; + void ScrollToAbsPos( long nPos ); void ShowFocusRect( const SvLBoxEntry* pEntry ); void SetTabBar( TabBar* pTabBar ); diff --git a/svtools/inc/svtools/treelist.hxx b/svtools/inc/svtools/treelist.hxx index 6c296d2..63545ed 100644 --- a/svtools/inc/svtools/treelist.hxx +++ b/svtools/inc/svtools/treelist.hxx @@ -494,9 +494,15 @@ public: SvListEntry* LastSelected() const { return pModel->LastSelected(this); } + SvListEntry* GetEntryAtAbsPos( sal_uLong nAbsPos ) const + { return pModel->GetEntryAtAbsPos(nAbsPos); } + SvListEntry* GetEntryAtVisPos( sal_uLong nVisPos ) const { return pModel->GetEntryAtVisPos((SvListView*)this,nVisPos); } + sal_uLong GetAbsPos( SvListEntry* pEntry ) const + { return pModel->GetAbsPos(pEntry); } + sal_uLong GetVisiblePos( SvListEntry* pEntry ) const { return pModel->GetVisiblePos((SvListView*)this,pEntry); } diff --git a/svtools/source/contnr/svimpbox.cxx b/svtools/source/contnr/svimpbox.cxx index ab6d4e1..fd5a649 100644 --- a/svtools/source/contnr/svimpbox.cxx +++ b/svtools/source/contnr/svimpbox.cxx @@ -1012,6 +1012,32 @@ void SvImpLBox::MakeVisible( SvLBoxEntry* pEntry, sal_Bool bMoveToTop ) pView->Invalidate(); } +void SvImpLBox::ScrollToAbsPos( long nPos ) +{ + long nLastEntryPos = pView->GetAbsPos( pView->Last() ); + + if( nPos < 0 ) + nPos = 0; + else if( nPos > nLastEntryPos ) + nPos = nLastEntryPos; + + SvLBoxEntry* pEntry = (SvLBoxEntry*)pView->GetEntryAtAbsPos( nPos ); + if( !pEntry || pEntry == pStartEntry ) + return; + + if( pStartEntry || (m_nStyle & WB_FORCE_MAKEVISIBLE) ) + nFlags &= (~F_FILLING); + + if( pView->IsEntryVisible(pEntry) ) + { + pStartEntry = pEntry; + ShowCursor( sal_False ); + aVerSBar.SetThumbPos( nPos ); + ShowCursor( sal_True ); + if (GetUpdateMode()) + pView->Invalidate(); + } +} void SvImpLBox::RepaintSelectionItems() { diff --git a/svtools/source/contnr/svtreebx.cxx b/svtools/source/contnr/svtreebx.cxx index e9648d2..76c82b6 100644 --- a/svtools/source/contnr/svtreebx.cxx +++ b/svtools/source/contnr/svtreebx.cxx @@ -853,6 +853,11 @@ void SvTreeListBox::ScrollOutputArea( short nDeltaEntries ) NotifyEndScroll(); } +void SvTreeListBox::ScrollToAbsPos( long nPos ) +{ + pImp->ScrollToAbsPos( nPos ); +} + void SvTreeListBox::SetSelectionMode( SelectionMode eSelectMode ) { DBG_CHKTHIS(SvTreeListBox,0); diff --git a/svtools/source/inc/svimpbox.hxx b/svtools/source/inc/svimpbox.hxx index 01648d8..7f666fc 100644 --- a/svtools/source/inc/svimpbox.hxx +++ b/svtools/source/inc/svimpbox.hxx @@ -313,6 +313,7 @@ public: void SetCurEntry( SvLBoxEntry* ); Point GetEntryPosition( SvLBoxEntry* ) const; void MakeVisible( SvLBoxEntry* pEntry, sal_Bool bMoveToTop=sal_False ); + void ScrollToAbsPos( long nPos ); void PaintDDCursor( SvLBoxEntry* ); -- 1.7.5.4
From 36be5c5f7e4018ea78d0c0297d311fd46608491d Mon Sep 17 00:00:00 2001 From: Luke Symes <allsy...@gmail.com> Date: Wed, 22 Jun 2011 16:03:10 +1200 Subject: [PATCH 3/3] Implement GetLastEntryInView for SvTreeListBox. This function matches up with GetFirstEntryInView, and will be useful in saving the scroll state of a SvTreeListBox, in particular the CustomAnimationList. --- svtools/inc/svtools/svtreebx.hxx | 1 + svtools/source/contnr/svtreebx.cxx | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+), 0 deletions(-) diff --git a/svtools/inc/svtools/svtreebx.hxx b/svtools/inc/svtools/svtreebx.hxx index 2b0a100..29c3822 100644 --- a/svtools/inc/svtools/svtreebx.hxx +++ b/svtools/inc/svtools/svtreebx.hxx @@ -369,6 +369,7 @@ public: SvLBoxEntry* GetFirstEntryInView() const; SvLBoxEntry* GetNextEntryInView(SvLBoxEntry*) const; + SvLBoxEntry* GetLastEntryInView() const; void ScrollToAbsPos( long nPos ); void ShowFocusRect( const SvLBoxEntry* pEntry ); diff --git a/svtools/source/contnr/svtreebx.cxx b/svtools/source/contnr/svtreebx.cxx index 76c82b6..175d9cd 100644 --- a/svtools/source/contnr/svtreebx.cxx +++ b/svtools/source/contnr/svtreebx.cxx @@ -2452,6 +2452,28 @@ SvLBoxEntry* SvTreeListBox::GetNextEntryInView(SvLBoxEntry* pEntry ) const return pNext; } +SvLBoxEntry* SvTreeListBox::GetLastEntryInView() const +{ + SvLBoxEntry* pEntry = GetFirstEntryInView(); + SvLBoxEntry* pNext = 0; + while( pEntry ) + { + pNext = (SvLBoxEntry*)NextVisible( pEntry ); + if( pNext ) + { + Point aPos( GetEntryPosition(pNext) ); + const Size& rSize = pImp->GetOutputSize(); + if( aPos.Y() < 0 || aPos.Y() >= rSize.Height() ) + break; + else + pEntry = pNext; + } + else + break; + } + return pEntry; +} + void SvTreeListBox::ShowFocusRect( const SvLBoxEntry* pEntry ) { pImp->ShowFocusRect( pEntry ); -- 1.7.5.4
From b366cc0b91bd228efb8796c19f8c9440322bf30d Mon Sep 17 00:00:00 2001 From: Luke Symes <allsy...@gmail.com> Date: Wed, 22 Jun 2011 16:40:50 +1200 Subject: [PATCH 1/2] Restore the scroll position of the CustomAnimationList when it is updated. We save the position of the listview, and also the selection boundary. We move with the selection if it goes out of view, otherwise we restore the original scroll position. If the selection was out of view to start with, we scroll up/down to the first few entries. --- sd/source/ui/animations/CustomAnimationList.cxx | 86 +++++++++++++++++++++-- 1 files changed, 80 insertions(+), 6 deletions(-) diff --git a/sd/source/ui/animations/CustomAnimationList.cxx b/sd/source/ui/animations/CustomAnimationList.cxx index a1e64d2..224129a 100644 --- a/sd/source/ui/animations/CustomAnimationList.cxx +++ b/sd/source/ui/animations/CustomAnimationList.cxx @@ -587,21 +587,51 @@ void stl_append_effect_func::operator()(CustomAnimationEffectPtr pEffect) void CustomAnimationList::update() { mbIgnorePaint = true; + SetUpdateMode( sal_False ); CustomAnimationListEntry* pEntry = 0; std::list< CustomAnimationEffectPtr > aExpanded; std::list< CustomAnimationEffectPtr > aSelected; - CustomAnimationEffectPtr pFirstVisibleEffect; + CustomAnimationEffectPtr pFirstSelEffect; + CustomAnimationEffectPtr pLastSelEffect; + long nFirstVis = -1; + long nLastVis = -1; + long nFirstSelOld = -1; + long nFirstSelNew = -1; + long nLastSelOld = -1; + long nLastSelNew = -1; + bool bMoved = false; + bool bMovedUp = false; + bool bMovedDown = false; if( mpMainSequence.get() ) { - // save selection and expand states - pEntry = static_cast<CustomAnimationListEntry*>(FirstVisible()); + // save scroll position + pEntry = static_cast<CustomAnimationListEntry*>(GetFirstEntryInView()); + if( pEntry ) + nFirstVis = GetAbsPos( pEntry ); + + pEntry = static_cast<CustomAnimationListEntry*>(GetLastEntryInView()); + if( pEntry ) + nLastVis = GetAbsPos( pEntry ); + + pEntry = static_cast<CustomAnimationListEntry*>(FirstSelected()); if( pEntry ) - pFirstVisibleEffect = pEntry->getEffect(); + { + pFirstSelEffect = pEntry->getEffect(); + nFirstSelOld = GetAbsPos( pEntry ); + } + pEntry = static_cast<CustomAnimationListEntry*>(LastSelected()); + if( pEntry ) + { + pLastSelEffect = pEntry->getEffect(); + nLastSelOld = GetAbsPos( pEntry ); + } + + // save selection and expand states pEntry = static_cast<CustomAnimationListEntry*>(First()); while( pEntry ) @@ -668,15 +698,59 @@ void CustomAnimationList::update() if( std::find( aSelected.begin(), aSelected.end(), pEffect ) != aSelected.end() ) Select( pEntry ); - if( pFirstVisibleEffect == pEffect ) - MakeVisible( pEntry ); + if( pEffect == pFirstSelEffect ) + nFirstSelNew = GetAbsPos( pEntry ); + + if( pEffect == pLastSelEffect ) + nLastSelNew = GetAbsPos( pEntry ); } pEntry = static_cast<CustomAnimationListEntry*>(Next( pEntry )); } + + // Scroll to a selected entry, depending on where the selection moved. + bMoved = nFirstSelNew != nFirstSelOld; + bMovedUp = nFirstSelNew < nFirstSelOld; + bMovedDown = nFirstSelNew > nFirstSelOld; + + if( bMoved && nLastSelOld < nFirstVis && nLastSelNew < nFirstVis ) + { + // The selection is above the visible area. + // Scroll up to show the last few selected entries. + if( nLastSelNew - (nLastVis - nFirstVis) > nFirstSelNew) + { + // The entries in the selection range can't fit in view. + // Scroll so the last selected entry is last in view. + ScrollToAbsPos( nLastSelNew - (nLastVis - nFirstVis) ); + } + else + ScrollToAbsPos( nFirstSelNew ); + } + else if( bMoved && nFirstSelOld > nLastVis && nFirstSelNew > nLastVis ) + { + // The selection is below the visible area. + // Scroll down to the first few selected entries. + ScrollToAbsPos( nFirstSelNew ); + } + else if( bMovedUp && nFirstSelOld <= nFirstVis ) + { + // A visible entry has moved up out of view; scroll up one. + ScrollToAbsPos( nFirstVis - 1 ); + } + else if( bMovedDown && nLastSelOld >= nLastVis ) + { + // An entry has moved down out of view; scroll down one. + ScrollToAbsPos( nFirstVis + 1 ); + } + else + { + // The selection is still in view, or it hasn't moved. + ScrollToAbsPos( nFirstVis ); + } } mbIgnorePaint = false; + SetUpdateMode( sal_True ); Invalidate(); } -- 1.7.5.4
From c61c5af219b3884e3881a6305ba692dec61c6555 Mon Sep 17 00:00:00 2001 From: Luke Symes <allsy...@gmail.com> Date: Wed, 22 Jun 2011 19:13:11 +1200 Subject: [PATCH 2/2] Don't update CustomAnimationList when we are already updating it. When we update the CustomAnimationList, we restore the selection state, and we don't want this to cause more updates (since that makes the scrollbar flash annoyingly). --- sd/source/ui/animations/CustomAnimationList.cxx | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/sd/source/ui/animations/CustomAnimationList.cxx b/sd/source/ui/animations/CustomAnimationList.cxx index 224129a..196fc53 100644 --- a/sd/source/ui/animations/CustomAnimationList.cxx +++ b/sd/source/ui/animations/CustomAnimationList.cxx @@ -865,6 +865,8 @@ void CustomAnimationList::onSelectionChanged( Any aSelection ) void CustomAnimationList::SelectHdl() { + if( mbIgnorePaint ) + return; SvTreeListBox::SelectHdl(); mpController->onSelect(); } -- 1.7.5.4
_______________________________________________ LibreOffice mailing list LibreOffice@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/libreoffice