summaryrefslogtreecommitdiff
path: root/sd/source/ui/animations/CustomAnimationList.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sd/source/ui/animations/CustomAnimationList.cxx')
-rw-r--r--sd/source/ui/animations/CustomAnimationList.cxx1116
1 files changed, 477 insertions, 639 deletions
diff --git a/sd/source/ui/animations/CustomAnimationList.cxx b/sd/source/ui/animations/CustomAnimationList.cxx
index 4793d8aafcca..559ac92a6b5c 100644
--- a/sd/source/ui/animations/CustomAnimationList.cxx
+++ b/sd/source/ui/animations/CustomAnimationList.cxx
@@ -29,20 +29,18 @@
#include <com/sun/star/drawing/XDrawPage.hpp>
#include "CustomAnimationList.hxx"
#include <CustomAnimationPreset.hxx>
-#include <vcl/settings.hxx>
-#include <vcl/builderfactory.hxx>
#include <vcl/commandevent.hxx>
#include <vcl/event.hxx>
+#include <vcl/image.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weldutils.hxx>
#include <tools/debug.hxx>
+#include <tools/gen.hxx>
#include <osl/diagnose.h>
#include <sdresid.hxx>
-#include <vcl/svlbitm.hxx>
-#include <vcl/treelistentry.hxx>
-#include <vcl/viewdataentry.hxx>
-
-
#include <strings.hrc>
#include <bitmaps.hlst>
@@ -215,33 +213,35 @@ static OUString getDescription( const Any& rTarget, bool bWithText )
return aDescription;
}
-class CustomAnimationListEntryItem : public SvLBoxString
+class CustomAnimationListEntryItem
{
public:
CustomAnimationListEntryItem(const OUString& aDescription,
- const CustomAnimationEffectPtr& pEffect, CustomAnimationList* pParent);
- void InitViewData(SvTreeListBox*,SvTreeListEntry*,SvViewDataItem* = nullptr) override;
- virtual std::unique_ptr<SvLBoxItem> Clone(SvLBoxItem const * pSource) const override;
+ const CustomAnimationEffectPtr& pEffect);
+ const CustomAnimationEffectPtr& getEffect() const { return mpEffect; }
+
+ Size GetSize(vcl::RenderContext& rRenderContext);
+ void Paint(vcl::RenderContext& rRenderContext, const ::tools::Rectangle& rRect, bool bSelected);
+ void PaintEffect(vcl::RenderContext& rRenderContext, const ::tools::Rectangle& rRect, bool bSelected);
+ void PaintTrigger(vcl::RenderContext& rRenderContext, const ::tools::Rectangle& rRect);
- virtual void Paint(const Point&, SvTreeListBox& rDev, vcl::RenderContext& rRenderContext,
- const SvViewDataEntry* pView,const SvTreeListEntry& rEntry) override;
private:
- VclPtr<CustomAnimationList> mpParent;
OUString msDescription;
OUString msEffectName;
CustomAnimationEffectPtr mpEffect;
+
static const long nIconWidth = 19;
static const long nItemMinHeight = 38;
};
-CustomAnimationListEntryItem::CustomAnimationListEntryItem( const OUString& aDescription, const CustomAnimationEffectPtr& pEffect, CustomAnimationList* pParent )
-: SvLBoxString( aDescription )
-, mpParent( pParent )
-, msDescription( aDescription )
-, msEffectName( OUString() )
-, mpEffect(pEffect)
+CustomAnimationListEntryItem::CustomAnimationListEntryItem(const OUString& aDescription, const CustomAnimationEffectPtr& pEffect)
+ : msDescription(aDescription)
+ , msEffectName(OUString())
+ , mpEffect(pEffect)
{
- switch(mpEffect->getPresetClass())
+ if (!mpEffect)
+ return;
+ switch (mpEffect->getPresetClass())
{
case EffectPresetClass::ENTRANCE:
msEffectName = SdResId(STR_CUSTOMANIMATION_ENTRANCE); break;
@@ -257,30 +257,85 @@ CustomAnimationListEntryItem::CustomAnimationListEntryItem( const OUString& aDes
msEffectName = msEffectName.replaceFirst( "%1" , CustomAnimationPresets::getCustomAnimationPresets().getUINameForPresetId(mpEffect->getPresetId()));
}
-void CustomAnimationListEntryItem::InitViewData( SvTreeListBox* pView, SvTreeListEntry* pEntry, SvViewDataItem* pViewData )
+IMPL_STATIC_LINK(CustomAnimationList, CustomRenderHdl, weld::TreeView::render_args, aPayload, void)
{
- if( !pViewData )
- pViewData = pView->GetViewDataItem( pEntry, this );
-
- long width = pView->GetTextWidth( msDescription ) + nIconWidth;
- if( width < (pView->GetTextWidth( msEffectName ) + 2*nIconWidth))
- width = pView->GetTextWidth( msEffectName ) + 2*nIconWidth;
-
- Size aSize( width, pView->GetTextHeight() );
- if( aSize.Height() < nItemMinHeight )
- aSize.setHeight( nItemMinHeight );
- pViewData->mnWidth = aSize.Width();
- pViewData->mnHeight = aSize.Height();
+ vcl::RenderContext& rRenderContext = std::get<0>(aPayload);
+ const ::tools::Rectangle& rRect = std::get<1>(aPayload);
+ bool bSelected = std::get<2>(aPayload);
+ const OUString& rId = std::get<3>(aPayload);
+
+ CustomAnimationListEntryItem* pItem = reinterpret_cast<CustomAnimationListEntryItem*>(rId.toInt64());
+
+ pItem->Paint(rRenderContext, rRect, bSelected);
}
-void CustomAnimationListEntryItem::Paint(const Point& rPos, SvTreeListBox& rDev, vcl::RenderContext& rRenderContext,
- const SvViewDataEntry* /*pView*/, const SvTreeListEntry& rEntry)
+IMPL_STATIC_LINK(CustomAnimationList, CustomGetSizeHdl, weld::TreeView::get_size_args, aPayload, Size)
{
+ vcl::RenderContext& rRenderContext = aPayload.first;
+ const OUString& rId = aPayload.second;
+
+ CustomAnimationListEntryItem* pItem = reinterpret_cast<CustomAnimationListEntryItem*>(rId.toInt64());
+ return pItem->GetSize(rRenderContext);
+}
+
+Size CustomAnimationListEntryItem::GetSize(vcl::RenderContext& rRenderContext)
+{
+ auto width = rRenderContext.GetTextWidth( msDescription ) + nIconWidth;
+ if (width < (rRenderContext.GetTextWidth( msEffectName ) + 2*nIconWidth))
+ width = rRenderContext.GetTextWidth( msEffectName ) + 2*nIconWidth;
+
+ Size aSize(width, rRenderContext.GetTextHeight());
+ if (aSize.Height() < nItemMinHeight)
+ aSize.setHeight(nItemMinHeight);
+ return aSize;
+}
+
+void CustomAnimationListEntryItem::PaintTrigger(vcl::RenderContext& rRenderContext, const ::tools::Rectangle& rRect)
+{
+ Size aSize(rRect.GetSize());
+
+ ::tools::Rectangle aOutRect(rRect);
+
+ // fill the background
+ Color aColor(rRenderContext.GetSettings().GetStyleSettings().GetDialogColor());
+
+ rRenderContext.Push();
+ rRenderContext.SetFillColor(aColor);
+ rRenderContext.SetLineColor();
+ rRenderContext.DrawRect(aOutRect);
+
+ // Erase the four corner pixels to make the rectangle appear rounded.
+ rRenderContext.SetLineColor(rRenderContext.GetSettings().GetStyleSettings().GetWindowColor());
+ rRenderContext.DrawPixel(aOutRect.TopLeft());
+ rRenderContext.DrawPixel(Point(aOutRect.Right(), aOutRect.Top()));
+ rRenderContext.DrawPixel(Point(aOutRect.Left(), aOutRect.Bottom()));
+ rRenderContext.DrawPixel(Point(aOutRect.Right(), aOutRect.Bottom()));
+
+ // draw the category title
+
+ int nVertBorder = ((aSize.Height() - rRenderContext.GetTextHeight()) >> 1);
+ int nHorzBorder = rRenderContext.LogicToPixel(Size(3, 3), MapMode(MapUnit::MapAppFont)).Width();
+
+ aOutRect.AdjustLeft(nHorzBorder );
+ aOutRect.AdjustRight( -nHorzBorder );
+ aOutRect.AdjustTop( nVertBorder );
+ aOutRect.AdjustBottom( -nVertBorder );
- const SvViewDataItem* pViewData = mpParent->GetViewDataItem(&rEntry, this);
+ rRenderContext.DrawText(aOutRect, rRenderContext.GetEllipsisString(msDescription, aOutRect.GetWidth()));
+ rRenderContext.Pop();
+}
- Point aPos(rPos);
- int nItemHeight = pViewData->mnHeight;
+void CustomAnimationListEntryItem::PaintEffect(vcl::RenderContext& rRenderContext, const ::tools::Rectangle& rRect, bool bSelected)
+{
+ rRenderContext.Push(PushFlags::TEXTCOLOR);
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ if (bSelected)
+ rRenderContext.SetTextColor(rStyleSettings.GetHighlightTextColor());
+ else
+ rRenderContext.SetTextColor(rStyleSettings.GetDialogTextColor());
+
+ Point aPos(rRect.TopLeft());
+ int nItemHeight = rRect.GetHeight();
sal_Int16 nNodeType = mpEffect->getNodeType();
if (nNodeType == EffectNodeType::ON_CLICK )
@@ -296,12 +351,12 @@ void CustomAnimationListEntryItem::Paint(const Point& rPos, SvTreeListBox& rDev,
//FIXME With previous image not defined in CustomAnimation.src
}
- aPos.AdjustX(nIconWidth );
-
+ aPos.AdjustX(nIconWidth);
- rRenderContext.DrawText(aPos, rRenderContext.GetEllipsisString(msDescription, rDev.GetOutputSizePixel().Width() - aPos.X()));
+ //TODO, full width of widget ?
+ rRenderContext.DrawText(aPos, rRenderContext.GetEllipsisString(msDescription, rRect.GetWidth()));
- aPos.AdjustY(nIconWidth );
+ aPos.AdjustY(nIconWidth);
OUString sImage;
switch (mpEffect->getPresetClass())
@@ -341,369 +396,129 @@ void CustomAnimationListEntryItem::Paint(const Point& rPos, SvTreeListBox& rDev,
}
aPos.AdjustX(nIconWidth );
- aPos.AdjustY((nItemHeight/2 - rDev.GetTextHeight()) >> 1 );
-
- rRenderContext.DrawText(aPos, rRenderContext.GetEllipsisString(msEffectName, rDev.GetOutputSizePixel().Width() - aPos.X()));
-}
-
-std::unique_ptr<SvLBoxItem> CustomAnimationListEntryItem::Clone(SvLBoxItem const *) const
-{
- return nullptr;
-}
-
-namespace {
-
-class CustomAnimationListEntry : public SvTreeListEntry
-{
-public:
- CustomAnimationListEntry();
- explicit CustomAnimationListEntry(const CustomAnimationEffectPtr& pEffect);
-
- const CustomAnimationEffectPtr& getEffect() const { return mpEffect; }
-
-private:
- CustomAnimationEffectPtr mpEffect;
-};
+ aPos.AdjustY((nItemHeight/2 - rRenderContext.GetTextHeight()) >> 1 );
+ rRenderContext.DrawText(aPos, rRenderContext.GetEllipsisString(msEffectName, rRect.GetWidth()));
+ rRenderContext.Pop();
}
-CustomAnimationListEntry::CustomAnimationListEntry()
-{
-}
-
-CustomAnimationListEntry::CustomAnimationListEntry(const CustomAnimationEffectPtr& pEffect)
-: mpEffect( pEffect )
-{
-}
-
-namespace {
-
-class CustomAnimationTriggerEntryItem : public SvLBoxString
+void CustomAnimationListEntryItem::Paint(vcl::RenderContext& rRenderContext, const ::tools::Rectangle& rRect, bool bSelected)
{
-public:
- explicit CustomAnimationTriggerEntryItem( const OUString& aDescription );
-
- void InitViewData( SvTreeListBox*,SvTreeListEntry*,SvViewDataItem* = nullptr ) override;
- virtual std::unique_ptr<SvLBoxItem> Clone(SvLBoxItem const * pSource) const override;
- virtual void Paint(const Point& rPos, SvTreeListBox& rOutDev, vcl::RenderContext& rRenderContext,
- const SvViewDataEntry* pView, const SvTreeListEntry& rEntry) override;
-
-private:
- OUString msDescription;
- static const long nIconWidth = 19;
-};
-
+ if (mpEffect)
+ PaintEffect(rRenderContext, rRect, bSelected);
+ else
+ PaintTrigger(rRenderContext, rRect);
}
-CustomAnimationTriggerEntryItem::CustomAnimationTriggerEntryItem( const OUString& aDescription )
-: SvLBoxString( aDescription ), msDescription( aDescription )
+CustomAnimationList::CustomAnimationList(std::unique_ptr<weld::TreeView> xTreeView,
+ std::unique_ptr<weld::Label> xLabel,
+ std::unique_ptr<weld::Widget> xScrolledWindow)
+ : mxTreeView(std::move(xTreeView))
+ , maDropTargetHelper(*this)
+ , mxEmptyLabel(std::move(xLabel))
+ , mxEmptyLabelParent(std::move(xScrolledWindow))
+ , mbIgnorePaint(false)
+ , mpController(nullptr)
+ , mnLastGroupId(0)
+ , mnPostExpandEvent(nullptr)
+ , mnPostCollapseEvent(nullptr)
{
+ mxEmptyLabel->set_stack_background();
+
+ mxTreeView->set_selection_mode(SelectionMode::Multiple);
+ mxTreeView->set_column_custom_renderer(0);
+ mxTreeView->connect_changed(LINK(this, CustomAnimationList, SelectHdl));
+ mxTreeView->connect_key_press(LINK(this, CustomAnimationList, KeyInputHdl));
+ mxTreeView->connect_popup_menu(LINK(this, CustomAnimationList, CommandHdl));
+ mxTreeView->connect_row_activated(LINK(this, CustomAnimationList, DoubleClickHdl));
+ mxTreeView->connect_expanding(LINK(this, CustomAnimationList, ExpandHdl));
+ mxTreeView->connect_collapsing(LINK(this, CustomAnimationList, CollapseHdl));
+ mxTreeView->connect_drag_begin(LINK(this, CustomAnimationList, DragBeginHdl));
+ mxTreeView->connect_custom_get_size(LINK(this, CustomAnimationList, CustomGetSizeHdl));
+ mxTreeView->connect_custom_render(LINK(this, CustomAnimationList, CustomRenderHdl));
}
-void CustomAnimationTriggerEntryItem::InitViewData( SvTreeListBox* pView, SvTreeListEntry* pEntry, SvViewDataItem* pViewData )
+CustomAnimationListDropTarget::CustomAnimationListDropTarget(CustomAnimationList& rTreeView)
+ : DropTargetHelper(rTreeView.get_widget().get_drop_target())
+ , m_rTreeView(rTreeView)
{
- if( !pViewData )
- pViewData = pView->GetViewDataItem( pEntry, this );
-
- Size aSize(pView->GetTextWidth( msDescription ) + 2 * nIconWidth, pView->GetTextHeight() );
- if( aSize.Height() < nIconWidth )
- aSize.setHeight( nIconWidth );
- pViewData->mnWidth = aSize.Width();
- pViewData->mnHeight = aSize.Height();
}
-void CustomAnimationTriggerEntryItem::Paint(const Point& rPos, SvTreeListBox& rDev, vcl::RenderContext& rRenderContext,
- const SvViewDataEntry* /*pView*/, const SvTreeListEntry& /*rEntry*/)
+sal_Int8 CustomAnimationListDropTarget::AcceptDrop(const AcceptDropEvent& rEvt)
{
- Size aSize(rDev.GetOutputSizePixel().Width(), rDev.GetEntryHeight());
-
- Point aPos(0, rPos.Y());
-
- ::tools::Rectangle aOutRect(aPos, aSize);
-
- // fill the background
- Color aColor(rRenderContext.GetSettings().GetStyleSettings().GetDialogColor());
-
- rRenderContext.Push();
- rRenderContext.SetFillColor(aColor);
- rRenderContext.SetLineColor();
- rRenderContext.DrawRect(aOutRect);
-
- // Erase the four corner pixels to make the rectangle appear rounded.
- rRenderContext.SetLineColor(rRenderContext.GetSettings().GetStyleSettings().GetWindowColor());
- rRenderContext.DrawPixel(aOutRect.TopLeft());
- rRenderContext.DrawPixel(Point(aOutRect.Right(), aOutRect.Top()));
- rRenderContext.DrawPixel(Point(aOutRect.Left(), aOutRect.Bottom()));
- rRenderContext.DrawPixel(Point(aOutRect.Right(), aOutRect.Bottom()));
-
- // draw the category title
+ sal_Int8 nAccept = m_rTreeView.AcceptDrop(rEvt);
- int nVertBorder = ((aSize.Height() - rDev.GetTextHeight()) >> 1);
- int nHorzBorder = rRenderContext.LogicToPixel(Size(3, 3), MapMode(MapUnit::MapAppFont)).Width();
-
- aOutRect.AdjustLeft(nHorzBorder );
- aOutRect.AdjustRight( -nHorzBorder );
- aOutRect.AdjustTop( nVertBorder );
- aOutRect.AdjustBottom( -nVertBorder );
-
- rRenderContext.DrawText(aOutRect, rRenderContext.GetEllipsisString(msDescription, aOutRect.GetWidth()));
- rRenderContext.Pop();
-}
+ if (nAccept != DND_ACTION_NONE)
+ {
+ // to enable the autoscroll when we're close to the edges
+ weld::TreeView& rWidget = m_rTreeView.get_widget();
+ rWidget.get_dest_row_at_pos(rEvt.maPosPixel, nullptr);
+ }
-std::unique_ptr<SvLBoxItem> CustomAnimationTriggerEntryItem::Clone(SvLBoxItem const *) const
-{
- return nullptr;
+ return nAccept;
}
-CustomAnimationList::CustomAnimationList( vcl::Window* pParent )
- : SvTreeListBox( pParent, WB_TABSTOP | WB_BORDER | WB_HASLINES | WB_HASBUTTONS | WB_HASBUTTONSATROOT )
- , mbIgnorePaint(false)
- , mpController(nullptr)
- , mnLastGroupId(0)
- , mpLastParentEntry(nullptr)
- , mpDndEffectDragging(nullptr)
- , mpDndEffectInsertBefore(nullptr)
+sal_Int8 CustomAnimationListDropTarget::ExecuteDrop(const ExecuteDropEvent& rEvt)
{
- EnableContextMenuHandling();
- SetSelectionMode( SelectionMode::Multiple );
- SetOptimalImageIndent();
- SetNodeDefaultImages();
-
- SetDragDropMode(DragDropMode::CTRL_MOVE);
+ return m_rTreeView.ExecuteDrop(rEvt);
}
// D'n'D #1: Record selected effects for drag'n'drop.
-void CustomAnimationList::StartDrag( sal_Int8 nAction, const Point& rPosPixel )
+IMPL_LINK(CustomAnimationList, DragBeginHdl, bool&, rUnsetDragIcon, bool)
{
+ rUnsetDragIcon = false;
+
// Record which effects are selected:
// Since NextSelected(..) iterates through the selected items in the order they
// were selected, create a sorted list for simpler drag'n'drop algorithms.
mDndEffectsSelected.clear();
- for( SvTreeListEntry* pEntry = First(); pEntry; pEntry = Next(pEntry) )
- {
- if( IsSelected(pEntry) )
- {
- mDndEffectsSelected.push_back( pEntry );
- }
- }
-
- // Allow normal processing; this calls our NotifyStartDrag().
- SvTreeListBox::StartDrag( nAction, rPosPixel );
-}
-
-// D'n'D #2: Prepare selected element for moving.
-DragDropMode CustomAnimationList::NotifyStartDrag( TransferDataContainer& /*rData*/, SvTreeListEntry* pEntry )
-{
- // Restore selection for multiple selected effects.
- // Do it here to remove a flicker on the UI with effects being unselected and reselected.
- for( auto &pEffect : mDndEffectsSelected )
- SelectListEntry( pEffect, true);
+ mxTreeView->selected_foreach([this](weld::TreeIter& rEntry){
+ mDndEffectsSelected.emplace_back(mxTreeView->make_iterator(&rEntry));
+ return false;
+ });
// Note: pEntry is the effect with focus (if multiple effects are selected)
- mpDndEffectDragging = pEntry;
- mpDndEffectInsertBefore = pEntry;
+ mxDndEffectDragging = mxTreeView->make_iterator();
+ mxTreeView->get_cursor(mxDndEffectDragging.get());
+ mxDndEffectInsertBefore = mxTreeView->make_iterator(mxDndEffectDragging.get());
- return DragDropMode::CTRL_MOVE;
+ // Allow normal processing.
+ return false;
}
// D'n'D #3: Called each time mouse moves during drag
sal_Int8 CustomAnimationList::AcceptDrop( const AcceptDropEvent& rEvt )
{
- /*
- Don't call SvTreeListBox::AcceptDrop because it puts an unnecessary
- highlight via ImplShowTargetEmphasis()
- */
-
sal_Int8 ret = DND_ACTION_NONE;
- const bool bIsMove = ( DND_ACTION_MOVE == rEvt.mnAction );
- if( mpDndEffectDragging && !rEvt.mbLeaving && bIsMove )
- {
- SvTreeListEntry* pEntry = GetDropTarget( rEvt.maPosPixel );
-
- const bool bOverASelectedEffect =
- std::find( mDndEffectsSelected.begin(), mDndEffectsSelected.end(), pEntry ) != mDndEffectsSelected.end();
- if( pEntry && !bOverASelectedEffect )
- {
- ReparentChildrenDuringDrag();
-
- ReorderEffectsInUiDuringDragOver( pEntry );
- }
-
- // Return DND_ACTION_MOVE on internal drag'n'drops so that ExecuteDrop() is called.
- // Return MOVE even if we are over other dragged effect because dragged effect moves.
+ const bool bIsMove = DND_ACTION_MOVE == rEvt.mnAction;
+ if (mxDndEffectDragging && !rEvt.mbLeaving && bIsMove)
ret = DND_ACTION_MOVE;
- }
-
return ret;
}
-// D'n'D: For each dragged effect, re-parent (only in the UI) non-selected
-// visible children so they are not dragged with the parent.
-void CustomAnimationList::ReparentChildrenDuringDrag()
-{
- /*
- Re-parent (only in the UI!):
- a) the dragged effect's first non-selected child to the root, and
- b) the remaining non-selected children to that re-parented 1st child.
- */
- for( auto &pEffect : mDndEffectsSelected )
- {
- const bool bExpandedWithChildren = GetVisibleChildCount( pEffect ) > 0;
- if( bExpandedWithChildren )
- {
- SvTreeListEntry* pEntryParent = GetParent( pEffect );
-
- SvTreeListEntry* pFirstNonSelectedChild = nullptr;
- sal_uLong nInsertNextChildPos = 0;
-
- // Process all children of this effect
- SvTreeListEntry* pChild = FirstChild( pEffect );
- while( pChild && ( GetParent( pChild ) == pEffect ) )
- {
- // Start by finding next child because if pChild moves, we cannot then
- // ask it what the next child is because it's no longer with its siblings.
- SvTreeListEntry* pNextChild = Next( pChild );
-
- // Skip selected effects: they stay with their previous parent to be moved.
- // During drag, the IsSelected() set changes, so use mDndEffectsSelected instead
- const bool bIsSelected = std::find( mDndEffectsSelected.begin(), mDndEffectsSelected.end(), pChild ) != mDndEffectsSelected.end();
- if( !bIsSelected )
- {
- // Re-parent 1st non-selected child to root, below all the other children.
- if( !pFirstNonSelectedChild )
- {
- pFirstNonSelectedChild = pChild;
- sal_uLong nInsertAfterPos = SvTreeList::GetRelPos( pEffect ) + 1;
- pModel->Move( pFirstNonSelectedChild, pEntryParent, nInsertAfterPos );
- }
- else
- {
- // Re-parent remaining non-selected children to 1st child
- ++nInsertNextChildPos;
- pModel->Move( pChild, pFirstNonSelectedChild, nInsertNextChildPos );
- }
- }
-
- pChild = pNextChild;
- }
-
- // Expand all children (they were previously visible)
- if( pFirstNonSelectedChild )
- Expand( pFirstNonSelectedChild );
-
- }
- }
-}
-
-// D'n'D: Update UI to show where dragged event will appear if dropped now.
-void CustomAnimationList::ReorderEffectsInUiDuringDragOver( SvTreeListEntry* pOverEntry )
-{
- /*
- Update the order of effects in *just the UI* while the user is dragging.
- The model (MainSequence) will only be changed after the user drops
- the effect so that there is minimal work to do if the drag is canceled.
- Plus only one undo record should be created per drag, and changing
- the model recreates all effects (on a background timer) which invalidates
- all effect pointers.
- */
-
- // Compute new location in *UI*
- SvTreeListEntry* pNewParent = nullptr;
- sal_uLong nInsertAfterPos = 0;
-
- Point aPosOverEffect( GetEntryPosition(pOverEntry) );
- Point aPosDraggedEffect( GetEntryPosition(mpDndEffectDragging) );
- const bool bDraggingUp = (aPosDraggedEffect.Y() - aPosOverEffect.Y()) > 0;
-
- if( bDraggingUp )
- {
- // Drag up --> place above the element we are over
- pNewParent = GetParent( pOverEntry );
- nInsertAfterPos = SvTreeList::GetRelPos( pOverEntry );
- mpDndEffectInsertBefore = pOverEntry;
- }
- else
- {
- // Drag down --> place below the element we are over
- SvTreeListEntry* pNextVisBelowTarget = NextVisible( pOverEntry );
- if( pNextVisBelowTarget )
- {
- // Match parent of NEXT visible effect (works for sub-items too)
- pNewParent = GetParent( pNextVisBelowTarget );
- nInsertAfterPos = SvTreeList::GetRelPos( pNextVisBelowTarget );
- mpDndEffectInsertBefore = pNextVisBelowTarget;
- }
- else
- {
- // Over the last element: no next to work with
- pNewParent = GetParent( pOverEntry );
- nInsertAfterPos = SvTreeList::GetRelPos( pOverEntry ) + 1;
- mpDndEffectInsertBefore = nullptr;
- }
- }
-
- // Move each selected effect in *just* the UI to show where it would be if dropped.
- // This leaves the exist parent relationships in the non-dragged elements so that
- // the list does not seem to change structure during drag. Parent relationships will
- // be correctly recreated on drop.
- for( auto aItr = mDndEffectsSelected.rbegin();
- aItr != mDndEffectsSelected.rend();
- ++aItr)
- {
- SvTreeListEntry* pEffect = *aItr;
-
- // Move only effects whose parents is not selected because
- // they will automatically move when their parent is moved.
- const bool bParentIsSelected =
- std::find(mDndEffectsSelected.begin(), mDndEffectsSelected.end(), GetParent(pEffect)) != mDndEffectsSelected.end();
-
- if( !bParentIsSelected )
- {
- // If the current effect is being moved down, the insert position must be decremented
- // after move if it will have the same parent as it currently does because it moves
- // from above the insertion point to below it, hence changing its index.
- // Must decide move-up vs move-down for each effect being dragged because we may be
- // processing a discontinuous set of selected effects (some below, some above insertion point)
- Point aCurPosOverEffect( GetEntryPosition( pOverEntry ) );
- Point aCurPosMovedEffect( GetEntryPosition( pEffect ) );
- const bool bCurDraggingDown = ( aCurPosMovedEffect.Y() - aCurPosOverEffect.Y() ) < 0;
- const bool bWillHaveSameParent = ( pNewParent == GetParent(pEffect) );
-
- pModel->Move( pEffect, pNewParent, nInsertAfterPos );
-
- if( bCurDraggingDown && bWillHaveSameParent )
- --nInsertAfterPos;
- }
- }
-
- // Restore selection (calling Select() is slow; SelectListEntry() is faster)
- for( auto &pEffect : mDndEffectsSelected )
- SelectListEntry( pEffect, true);
-}
-
// D'n'D #5: Tell model to update effect order.
-sal_Int8 CustomAnimationList::ExecuteDrop( const ExecuteDropEvent& /*rEvt*/ )
+sal_Int8 CustomAnimationList::ExecuteDrop(const ExecuteDropEvent& rEvt)
{
- // NOTE: We cannot just override NotifyMoving() because it's not called
- // since we dynamically reorder effects during drag.
-
- sal_Int8 ret = DND_ACTION_NONE;
+ if (!mxTreeView->get_dest_row_at_pos(rEvt.maPosPixel, mxDndEffectInsertBefore.get()))
+ mxDndEffectInsertBefore.reset();
- const bool bMovingEffect = ( mpDndEffectDragging != nullptr );
- const bool bMoveNotSelf = ( mpDndEffectInsertBefore != mpDndEffectDragging );
+ const bool bMovingEffect = ( mxDndEffectDragging != nullptr );
+ const bool bMoveNotSelf = !mxDndEffectInsertBefore || (mxDndEffectDragging && mxTreeView->iter_compare(*mxDndEffectInsertBefore, *mxDndEffectDragging) != 0);
const bool bHaveSequence = ( mpMainSequence.get() != nullptr );
if( bMovingEffect && bMoveNotSelf && bHaveSequence )
{
- CustomAnimationListEntry* pTarget = static_cast< CustomAnimationListEntry* >( mpDndEffectInsertBefore );
+ CustomAnimationListEntryItem* pTarget = mxDndEffectInsertBefore ?
+ reinterpret_cast<CustomAnimationListEntryItem*>(mxTreeView->get_id(*mxDndEffectInsertBefore).toInt64()) :
+ nullptr;
// Build list of effects
std::vector< CustomAnimationEffectPtr > aEffects;
for( const auto &pEntry : mDndEffectsSelected )
{
- CustomAnimationListEntry* pCustomAnimationEffect = static_cast< CustomAnimationListEntry* >( pEntry );
- aEffects.push_back( pCustomAnimationEffect->getEffect() );
+ CustomAnimationListEntryItem* pCustomAnimationEffect = reinterpret_cast<CustomAnimationListEntryItem*>(mxTreeView->get_id(*pEntry).toInt64());
+ aEffects.push_back(pCustomAnimationEffect->getEffect());
}
// Callback to observer to have it update the model.
@@ -713,90 +528,82 @@ sal_Int8 CustomAnimationList::ExecuteDrop( const ExecuteDropEvent& /*rEvt*/ )
pTarget ? pTarget->getEffect() : nullptr );
// Reset selection
- Select( mpDndEffectDragging );
-
- ret = DND_ACTION_MOVE;
+ mxTreeView->select(*mxDndEffectDragging);
+ Select();
}
- // NOTE: Don't call SvTreeListBox::ExecuteDrop(...) because all required
+ // NOTE: Don't call default handler because all required
// move operations have been completed here to update the model.
- return ret;
-}
-
-// D'n'D #6: Cleanup (regardless of if we were target of drop or not)
-void CustomAnimationList::DragFinished( sal_Int8 /*nDropAction*/ )
-{
- mpDndEffectDragging = nullptr;
- mpDndEffectInsertBefore = nullptr;
- mDndEffectsSelected.clear();
-
- // Rebuild because we may have re-parented the dragged effect's first child.
- // Can hit this without running ExecuteDrop(...) when drag canceled.
- mpMainSequence->rebuild();
-
- // Note: Don't call SvTreeListBox::DragFinished(...) because we don't call
- // SvTreeListBox::ExecuteDrop(...) which sets variables that are
- // needed in its DragFinished(...) method.
+ return DND_ACTION_NONE;
}
-VCL_BUILDER_FACTORY(CustomAnimationList)
-
CustomAnimationList::~CustomAnimationList()
{
- disposeOnce();
-}
+ if (mnPostExpandEvent)
+ {
+ Application::RemoveUserEvent(mnPostExpandEvent);
+ mnPostExpandEvent = nullptr;
+ }
+
+ if (mnPostCollapseEvent)
+ {
+ Application::RemoveUserEvent(mnPostCollapseEvent);
+ mnPostCollapseEvent = nullptr;
+ }
-void CustomAnimationList::dispose()
-{
if( mpMainSequence.get() )
mpMainSequence->removeListener( this );
clear();
-
- mxMenu.disposeAndClear();
- mxBuilder.reset();
-
- SvTreeListBox::dispose();
}
-void CustomAnimationList::KeyInput( const KeyEvent& rKEvt )
+IMPL_LINK(CustomAnimationList, KeyInputHdl, const KeyEvent&, rKEvt, bool)
{
const int nKeyCode = rKEvt.GetKeyCode().GetCode();
- switch( nKeyCode )
+ switch (nKeyCode)
{
case KEY_DELETE:
mpController->onContextMenu("remove");
- return;
+ return true;
case KEY_INSERT:
mpController->onContextMenu("create");
- return;
+ return true;
case KEY_SPACE:
+ {
+ std::unique_ptr<weld::TreeIter> xEntry = mxTreeView->make_iterator();
+ if (mxTreeView->get_cursor(xEntry.get()))
{
- const Point aPos;
- const CommandEvent aCEvt( aPos, CommandEventId::ContextMenu );
- Command( aCEvt );
- return;
+ auto aRect = mxTreeView->get_row_area(*xEntry);
+ const Point aPos(aRect.getWidth() / 2, aRect.getHeight() / 2);
+ const CommandEvent aCEvt(aPos, CommandEventId::ContextMenu);
+ CommandHdl(aCEvt);
+ return true;
}
-
+ }
}
-
- ::SvTreeListBox::KeyInput( rKEvt );
+ return false;
}
/** selects or deselects the given effect.
Selections of other effects are not changed */
void CustomAnimationList::select( const CustomAnimationEffectPtr& pEffect )
{
- CustomAnimationListEntry* pEntry = static_cast< CustomAnimationListEntry* >(First());
- while( pEntry )
+ CustomAnimationListEntryItem* pEntry = nullptr;
+
+ std::unique_ptr<weld::TreeIter> xEntry = mxTreeView->make_iterator();
+ if (mxTreeView->get_iter_first(*xEntry))
{
- if( pEntry->getEffect() == pEffect )
+ do
{
- Select( pEntry );
- MakeVisible( pEntry );
- break;
- }
- pEntry = static_cast< CustomAnimationListEntry* >(Next( pEntry ));
+ CustomAnimationListEntryItem* pTestEntry = reinterpret_cast<CustomAnimationListEntryItem*>(mxTreeView->get_id(*xEntry).toInt64());
+ if (pTestEntry->getEffect() == pEffect)
+ {
+ mxTreeView->select(*xEntry);
+ mxTreeView->scroll_to_row(*xEntry);
+ pEntry = pTestEntry;
+ break;
+ }
+ } while (mxTreeView->iter_next(*xEntry));
}
if( !pEntry )
@@ -808,9 +615,13 @@ void CustomAnimationList::select( const CustomAnimationEffectPtr& pEffect )
void CustomAnimationList::clear()
{
- Clear();
+ mxEntries.clear();
+ mxTreeView->clear();
- mpLastParentEntry = nullptr;
+ mxEmptyLabelParent->show();
+ mxTreeView->hide();
+
+ mxLastParentEntry.reset();
mxLastTargetShape = nullptr;
}
@@ -841,9 +652,6 @@ void stl_append_effect_func::operator()(const CustomAnimationEffectPtr& pEffect)
void CustomAnimationList::update()
{
mbIgnorePaint = true;
- SetUpdateMode( false );
-
- CustomAnimationListEntry* pEntry = nullptr;
std::vector< CustomAnimationEffectPtr > aVisible;
std::vector< CustomAnimationEffectPtr > aSelected;
@@ -856,62 +664,77 @@ void CustomAnimationList::update()
long nFirstSelOld = -1;
long nLastSelOld = -1;
+ std::unique_ptr<weld::TreeIter> xEntry = mxTreeView->make_iterator();
+
if( mpMainSequence.get() )
{
- // save scroll position
- pEntry = static_cast<CustomAnimationListEntry*>(GetFirstEntryInView());
- if( pEntry )
- nFirstVis = GetAbsPos( pEntry );
+ std::unique_ptr<weld::TreeIter> xLastSelectedEntry;
+ std::unique_ptr<weld::TreeIter> xLastVisibleEntry;
- pEntry = static_cast<CustomAnimationListEntry*>(GetLastEntryInView());
- if( pEntry )
- nLastVis = GetAbsPos( pEntry );
+ // save selection, current, and expand (visible) states
+ mxTreeView->all_foreach([this, &aVisible, &nFirstVis, &xLastVisibleEntry,
+ &aSelected, &nFirstSelOld, &pFirstSelEffect, &xLastSelectedEntry](weld::TreeIter& rEntry){
+ CustomAnimationListEntryItem* pEntry = reinterpret_cast<CustomAnimationListEntryItem*>(mxTreeView->get_id(rEntry).toInt64());
+ CustomAnimationEffectPtr pEffect(pEntry->getEffect());
+ if (pEffect.get())
+ {
+ if (weld::IsEntryVisible(*mxTreeView, rEntry))
+ {
+ aVisible.push_back(pEffect);
+ // save scroll position
+ if (nFirstVis == -1)
+ nFirstVis = weld::GetAbsPos(*mxTreeView, rEntry);
+ if (!xLastVisibleEntry)
+ xLastVisibleEntry = mxTreeView->make_iterator(&rEntry);
+ else
+ mxTreeView->copy_iterator(rEntry, *xLastVisibleEntry);
+ }
- pEntry = static_cast<CustomAnimationListEntry*>(FirstSelected());
- if( pEntry )
- {
- pFirstSelEffect = pEntry->getEffect();
- nFirstSelOld = GetAbsPos( pEntry );
- }
+ if (mxTreeView->is_selected(rEntry))
+ {
+ aSelected.push_back(pEffect);
+ if (nFirstSelOld == -1)
+ {
+ pFirstSelEffect = pEffect;
+ nFirstSelOld = weld::GetAbsPos(*mxTreeView, rEntry);
+ }
+ if (!xLastSelectedEntry)
+ xLastSelectedEntry = mxTreeView->make_iterator(&rEntry);
+ else
+ mxTreeView->copy_iterator(rEntry, *xLastSelectedEntry);
+ }
+ }
+
+ return false;
+ });
- pEntry = static_cast<CustomAnimationListEntry*>(LastSelected());
- if( pEntry )
+ if (xLastSelectedEntry)
{
+ CustomAnimationListEntryItem* pEntry = reinterpret_cast<CustomAnimationListEntryItem*>(mxTreeView->get_id(*xLastSelectedEntry).toInt64());
pLastSelEffect = pEntry->getEffect();
- nLastSelOld = GetAbsPos( pEntry );
+ nLastSelOld = weld::GetAbsPos(*mxTreeView, *xLastSelectedEntry);
}
- // save selection, current, and expand (visible) states
- pEntry = static_cast<CustomAnimationListEntry*>(First());
+ if (xLastVisibleEntry)
+ nLastVis = weld::GetAbsPos(*mxTreeView, *xLastVisibleEntry);
- while( pEntry )
+ if (mxTreeView->get_cursor(xEntry.get()))
{
- CustomAnimationEffectPtr pEffect( pEntry->getEffect() );
- if( pEffect.get() )
- {
- if( IsEntryVisible( pEntry ) )
- aVisible.push_back( pEffect );
-
- if( IsSelected( pEntry ) )
- aSelected.push_back( pEffect );
- }
-
- pEntry = static_cast<CustomAnimationListEntry*>(Next( pEntry ));
- }
-
- pEntry = static_cast<CustomAnimationListEntry*>(GetCurEntry());
- if( pEntry )
+ CustomAnimationListEntryItem* pEntry = reinterpret_cast<CustomAnimationListEntryItem*>(mxTreeView->get_id(*xEntry).toInt64());
aCurrent = pEntry->getEffect();
+ }
}
// rebuild list
+
+ mxTreeView->freeze();
+
clear();
- if( mpMainSequence.get() )
+
+ if (mpMainSequence.get())
{
- long nFirstSelNew = -1;
- long nLastSelNew = -1;
std::for_each( mpMainSequence->getBegin(), mpMainSequence->getEnd(), stl_append_effect_func( *this ) );
- mpLastParentEntry = nullptr;
+ mxLastParentEntry.reset();
auto rInteractiveSequenceVector = mpMainSequence->getInteractiveSequenceVector();
@@ -920,54 +743,76 @@ void CustomAnimationList::update()
Reference< XShape > xShape( pIS->getTriggerShape() );
if( xShape.is() )
{
- SvTreeListEntry* pLBoxEntry = new CustomAnimationListEntry;
- pLBoxEntry->AddItem(std::make_unique<SvLBoxContextBmp>(Image(), Image(), false));
OUString aDescription = SdResId(STR_CUSTOMANIMATION_TRIGGER) + ": " +
getShapeDescription( xShape, false );
- pLBoxEntry->AddItem(std::make_unique<CustomAnimationTriggerEntryItem>(aDescription));
- Insert( pLBoxEntry );
- SvViewDataEntry* pViewData = GetViewData( pLBoxEntry );
- if( pViewData )
- pViewData->SetSelectable(false);
+ mxEntries.emplace_back(std::make_unique<CustomAnimationListEntryItem>(aDescription, nullptr));
+
+ OUString sId(OUString::number(reinterpret_cast<sal_Int64>(mxEntries.back().get())));
+ mxTreeView->insert(nullptr, -1, &aDescription, &sId, nullptr, nullptr, nullptr, false, nullptr);
std::for_each( pIS->getBegin(), pIS->getEnd(), stl_append_effect_func( *this ) );
- mpLastParentEntry = nullptr;
+ mxLastParentEntry.reset();
}
}
+ }
- // restore selection state, expand state, and current-entry (under cursor)
- pEntry = static_cast<CustomAnimationListEntry*>(First());
+ mxTreeView->thaw();
- while( pEntry )
+ if (mxTreeView->n_children())
+ {
+ mxEmptyLabelParent->hide();
+ mxTreeView->show();
+ }
+
+ if (mpMainSequence.get())
+ {
+ long nFirstSelNew = -1;
+ long nLastSelNew = -1;
+
+ std::vector<std::unique_ptr<weld::TreeIter>> aNewSelection;
+
+ // restore selection state, expand state, and current-entry (under cursor)
+ if (mxTreeView->get_iter_first(*xEntry))
{
- CustomAnimationEffectPtr pEffect( pEntry->getEffect() );
- if( pEffect.get() )
+ do
{
- // Any effects that were visible should still be visible, so expand their parents.
- // (a previously expanded parent may have moved leaving a child to now be the new parent to expand)
- if( std::find( aVisible.begin(), aVisible.end(), pEffect ) != aVisible.end() )
- {
- if( GetParent(pEntry) )
- Expand( GetParent(pEntry) );
- }
+ CustomAnimationListEntryItem* pEntry = reinterpret_cast<CustomAnimationListEntryItem*>(mxTreeView->get_id(*xEntry).toInt64());
- if( std::find( aSelected.begin(), aSelected.end(), pEffect ) != aSelected.end() )
- Select( pEntry );
+ CustomAnimationEffectPtr pEffect( pEntry->getEffect() );
+ if (pEffect.get())
+ {
+ // Any effects that were visible should still be visible, so expand their parents.
+ // (a previously expanded parent may have moved leaving a child to now be the new parent to expand)
+ if( std::find( aVisible.begin(), aVisible.end(), pEffect ) != aVisible.end() )
+ {
+ if (mxTreeView->get_iter_depth(*xEntry))
+ {
+ std::unique_ptr<weld::TreeIter> xParentEntry = mxTreeView->make_iterator(xEntry.get());
+ mxTreeView->iter_parent(*xParentEntry);
+ mxTreeView->expand_row(*xParentEntry);
+ }
+ }
- // Restore the cursor; don't use SetCurEntry() as it may deselect other effects
- if( pEffect == aCurrent )
- SetCursor( pEntry );
+ if( std::find( aSelected.begin(), aSelected.end(), pEffect ) != aSelected.end() )
+ aNewSelection.emplace_back(mxTreeView->make_iterator(xEntry.get()));
- if( pEffect == pFirstSelEffect )
- nFirstSelNew = GetAbsPos( pEntry );
+ // Restore the cursor, as it may deselect other effects wait until
+ // after the loop to reset the selection
+ if( pEffect == aCurrent )
+ mxTreeView->set_cursor(*xEntry);
- if( pEffect == pLastSelEffect )
- nLastSelNew = GetAbsPos( pEntry );
- }
+ if (pEffect == pFirstSelEffect)
+ nFirstSelNew = weld::GetAbsPos(*mxTreeView, *xEntry);
- pEntry = static_cast<CustomAnimationListEntry*>(Next( pEntry ));
+ if (pEffect == pLastSelEffect)
+ nLastSelNew = weld::GetAbsPos(*mxTreeView, *xEntry);
+ }
+ } while (mxTreeView->iter_next(*xEntry));
}
+ for (const auto& rEntry : aNewSelection)
+ mxTreeView->select(*rEntry);
+
// Scroll to a selected entry, depending on where the selection moved.
const bool bMoved = nFirstSelNew != nFirstSelOld;
const bool bMovedUp = nFirstSelNew < nFirstSelOld;
@@ -981,103 +826,104 @@ void CustomAnimationList::update()
{
// 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) );
+ mxTreeView->vadjustment_set_value(nLastSelNew - (nLastVis - nFirstVis));
}
else
- ScrollToAbsPos( nFirstSelNew );
+ mxTreeView->vadjustment_set_value(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 );
+ mxTreeView->vadjustment_set_value(nFirstSelNew);
}
else if( bMovedUp && nFirstSelOld <= nFirstVis )
{
// A visible entry has moved up out of view; scroll up one.
- ScrollToAbsPos( nFirstVis - 1 );
+ mxTreeView->vadjustment_set_value(nFirstVis - 1);
}
else if( bMovedDown && nLastSelOld >= nLastVis )
{
// An entry has moved down out of view; scroll down one.
- ScrollToAbsPos( nFirstVis + 1 );
+ mxTreeView->vadjustment_set_value(nFirstVis + 1);
}
else if ( nFirstVis != -1 )
{
// The selection is still in view, or it hasn't moved.
- ScrollToAbsPos( nFirstVis );
+ mxTreeView->vadjustment_set_value(nFirstVis);
}
}
mbIgnorePaint = false;
- SetUpdateMode( true );
- Invalidate();
+
+ Select();
}
void CustomAnimationList::append( CustomAnimationEffectPtr pEffect )
{
- // create a ui description
- OUString aDescription;
-
Any aTarget( pEffect->getTarget() );
if( !aTarget.hasValue() )
return;
try
{
- aDescription = getDescription( aTarget, pEffect->getTargetSubItem() != ShapeAnimationSubType::ONLY_BACKGROUND );
+ // create a ui description
+ OUString aDescription = getDescription(aTarget, pEffect->getTargetSubItem() != ShapeAnimationSubType::ONLY_BACKGROUND);
- SvTreeListEntry* pParentEntry = nullptr;
+ std::unique_ptr<weld::TreeIter> xParentEntry;
Reference< XShape > xTargetShape( pEffect->getTargetShape() );
sal_Int32 nGroupId = pEffect->getGroupId();
// if this effect has the same target and group-id as the last root effect,
// the last root effect is also this effects parent
- if( mpLastParentEntry && (nGroupId != -1) && (mxLastTargetShape == xTargetShape) && (mnLastGroupId == nGroupId) )
- pParentEntry = mpLastParentEntry;
+ if (mxLastParentEntry && nGroupId != -1 && mxLastTargetShape == xTargetShape && mnLastGroupId == nGroupId)
+ xParentEntry = mxTreeView->make_iterator(mxLastParentEntry.get());
// create an entry for the effect
- SvTreeListEntry* pEntry = new CustomAnimationListEntry( pEffect );
+ std::unique_ptr<weld::TreeIter> xEntry = mxTreeView->make_iterator();
+
+ mxEntries.emplace_back(std::make_unique<CustomAnimationListEntryItem>(aDescription, pEffect));
- pEntry->AddItem(std::make_unique<SvLBoxContextBmp>(Image(), Image(), false));
- pEntry->AddItem(std::make_unique<CustomAnimationListEntryItem>(aDescription, pEffect, this));
+ OUString sId(OUString::number(reinterpret_cast<sal_Int64>(mxEntries.back().get())));
- if( pParentEntry )
+ if (xParentEntry)
{
// add a subentry
- Insert( pEntry, pParentEntry );
+ mxTreeView->insert(xParentEntry.get(), -1, &aDescription, &sId, nullptr, nullptr, nullptr, false, xEntry.get());
}
else
{
// add a root entry
- Insert( pEntry );
+ mxTreeView->insert(nullptr, -1, &aDescription, &sId, nullptr, nullptr, nullptr, false, xEntry.get());
// and the new root entry becomes the possible next group header
mxLastTargetShape = xTargetShape;
mnLastGroupId = nGroupId;
- mpLastParentEntry = pEntry;
+ mxLastParentEntry = std::move(xEntry);
}
}
- catch( Exception& )
+ catch (const Exception&)
{
OSL_FAIL("sd::CustomAnimationList::append(), exception caught!" );
}
}
-static void selectShape( SvTreeListBox* pTreeList, const Reference< XShape >& xShape )
+static void selectShape(weld::TreeView* pTreeList, const Reference< XShape >& xShape )
{
- CustomAnimationListEntry* pEntry = static_cast< CustomAnimationListEntry* >(pTreeList->First());
- while( pEntry )
+ std::unique_ptr<weld::TreeIter> xEntry = pTreeList->make_iterator();
+ if (pTreeList->get_iter_first(*xEntry))
{
- CustomAnimationEffectPtr pEffect( pEntry->getEffect() );
- if( pEffect.get() )
+ do
{
- if( pEffect->getTarget() == xShape )
- pTreeList->Select( pEntry );
- }
-
- pEntry = static_cast< CustomAnimationListEntry* >(pTreeList->Next( pEntry ));
+ CustomAnimationListEntryItem* pEntry = reinterpret_cast<CustomAnimationListEntryItem*>(pTreeList->get_id(*xEntry).toInt64());
+ CustomAnimationEffectPtr pEffect(pEntry->getEffect());
+ if (pEffect)
+ {
+ if (pEffect->getTarget() == xShape)
+ pTreeList->select(*xEntry);
+ }
+ } while (pTreeList->iter_next(*xEntry));
}
}
@@ -1085,7 +931,7 @@ void CustomAnimationList::onSelectionChanged(const Any& rSelection)
{
try
{
- SelectAll(false);
+ mxTreeView->unselect_all();
if (rSelection.hasValue())
{
@@ -1098,18 +944,18 @@ void CustomAnimationList::onSelectionChanged(const Any& rSelection)
{
Reference< XShape > xShape( xShapes->getByIndex( nIndex ), UNO_QUERY );
if( xShape.is() )
- selectShape( this, xShape );
+ selectShape(mxTreeView.get(), xShape);
}
}
else
{
Reference< XShape > xShape(rSelection, UNO_QUERY);
if( xShape.is() )
- selectShape( this, xShape );
+ selectShape(mxTreeView.get(), xShape);
}
}
- SelectHdl();
+ Select();
}
catch( Exception& )
{
@@ -1117,170 +963,186 @@ void CustomAnimationList::onSelectionChanged(const Any& rSelection)
}
}
-// Notify controller to refresh UI when we are notified of selection change from base class
-void CustomAnimationList::SelectHdl()
+IMPL_LINK_NOARG(CustomAnimationList, SelectHdl, weld::TreeView&, void)
{
- if( mbIgnorePaint )
- return;
- SvTreeListBox::SelectHdl();
- mpController->onSelect();
+ Select();
}
// Notify controller to refresh UI when we are notified of selection change from base class
-void CustomAnimationList::DeselectHdl()
+void CustomAnimationList::Select()
{
if( mbIgnorePaint )
return;
- SvTreeListBox::DeselectHdl();
mpController->onSelect();
}
-
-bool CustomAnimationList::Expand( SvTreeListEntry* pParent )
+IMPL_LINK_NOARG(CustomAnimationList, PostExpandHdl, void*, void)
{
- bool result = SvTreeListBox::Expand( pParent );
-
- // If expanded entry is selected, then select its children too.
- if( IsSelected( pParent )) {
- for( auto pChild = FirstChild( pParent ); pChild; pChild = pChild->NextSibling() )
+ std::unique_ptr<weld::TreeIter> xEntry = mxTreeView->make_iterator();
+ if (mxTreeView->get_selected(xEntry.get()))
+ {
+ for (bool bChild = mxTreeView->iter_children(*xEntry); bChild; bChild = mxTreeView->iter_next_sibling(*xEntry))
{
- if( !IsSelected( pChild ) )
- {
- SelectListEntry( pChild, true );
- }
+ if (!mxTreeView->is_selected(*xEntry))
+ mxTreeView->select(*xEntry);
}
}
// Notify controller that selection has changed (it should update the UI)
mpController->onSelect();
- return result;
+ mnPostExpandEvent = nullptr;
}
-bool CustomAnimationList::Collapse( SvTreeListEntry* pParent )
+IMPL_LINK(CustomAnimationList, ExpandHdl, const weld::TreeIter&, rParent, bool)
{
- // SvTreeListBox::Collapse(..) discards multi-selection state
- // of list entries, so first save current selection state
- std::vector< SvTreeListEntry* > selectedEntries;
- for( auto pEntry = FirstSelected(); pEntry; pEntry = NextSelected( pEntry ))
- {
- selectedEntries.push_back( pEntry );
+ // If expanded entry is selected, then select its children too afterwards.
+ if (mxTreeView->is_selected(rParent) && !mnPostExpandEvent) {
+ mnPostExpandEvent = Application::PostUserEvent(LINK(this, CustomAnimationList, PostExpandHdl));
}
- // Execute collapse on base class
- bool result = SvTreeListBox::Collapse( pParent );
+ return true;
+}
+IMPL_LINK_NOARG(CustomAnimationList, PostCollapseHdl, void*, void)
+{
// Deselect all entries as SvTreeListBox::Collapse selects the last
// entry to have focus (or its parent), which is not desired
- for( auto pEntry = FirstSelected(); pEntry; pEntry = NextSelected( pEntry ))
- {
- SelectListEntry( pEntry, false );
- }
+ mxTreeView->unselect_all();
// Restore selection state for entries which are still visible
- for( auto &pEntry : selectedEntries )
+ for (auto &pEntry : lastSelectedEntries)
{
- if( IsEntryVisible( pEntry ))
- {
- SelectListEntry( pEntry, true );
- }
+ if (weld::IsEntryVisible(*mxTreeView, *pEntry))
+ mxTreeView->select(*pEntry);
}
+ lastSelectedEntries.clear();
+
// Notify controller that selection has changed (it should update the UI)
mpController->onSelect();
- return result;
+ mnPostCollapseEvent = nullptr;
}
-bool CustomAnimationList::isExpanded( const CustomAnimationEffectPtr& pEffect ) const
+IMPL_LINK_NOARG(CustomAnimationList, CollapseHdl, const weld::TreeIter&, bool)
{
- CustomAnimationListEntry* pEntry = static_cast<CustomAnimationListEntry*>(First());
-
- while( pEntry )
+ if (!mnPostCollapseEvent)
{
- if( pEntry->getEffect() == pEffect )
- break;
-
- pEntry = static_cast<CustomAnimationListEntry*>(Next( pEntry ));
+ // weld::TreeView::collapse() discards multi-selection state
+ // of list entries, so first save current selection state
+ mxTreeView->selected_foreach([this](weld::TreeIter& rEntry){
+ lastSelectedEntries.emplace_back(mxTreeView->make_iterator(&rEntry));
+ return false;
+ });
+
+ mnPostCollapseEvent = Application::PostUserEvent(LINK(this, CustomAnimationList, PostCollapseHdl));
}
- if( pEntry )
- pEntry = static_cast<CustomAnimationListEntry*>(GetParent( pEntry ));
-
- return (pEntry == nullptr) || IsExpanded( pEntry );
+ // Execute collapse on base class
+ return true;
}
-bool CustomAnimationList::isVisible( const CustomAnimationEffectPtr& pEffect ) const
+bool CustomAnimationList::isExpanded( const CustomAnimationEffectPtr& pEffect ) const
{
- CustomAnimationListEntry* pEntry = static_cast<CustomAnimationListEntry*>(First());
+ bool bExpanded = true; // we assume expanded by default
- while( pEntry )
+ std::unique_ptr<weld::TreeIter> xEntry = mxTreeView->make_iterator();
+ if (mxTreeView->get_iter_first(*xEntry))
{
- if( pEntry->getEffect() == pEffect )
- break;
-
- pEntry = static_cast<CustomAnimationListEntry*>(Next( pEntry ));
+ do
+ {
+ CustomAnimationListEntryItem* pEntry =
+ reinterpret_cast<CustomAnimationListEntryItem*>(mxTreeView->get_id(*xEntry).toInt64());
+ if (pEntry->getEffect() == pEffect)
+ {
+ if (mxTreeView->get_iter_depth(*xEntry)) // no parent, keep expanded default of true
+ {
+ std::unique_ptr<weld::TreeIter> xParentEntry = mxTreeView->make_iterator(xEntry.get());
+ if (mxTreeView->iter_parent(*xParentEntry))
+ bExpanded = mxTreeView->get_row_expanded(*xParentEntry);
+ }
+ break;
+ }
+ } while (mxTreeView->iter_next(*xEntry));
}
- return (pEntry == nullptr) || IsEntryVisible( pEntry );
+ return bExpanded;
+}
+
+bool CustomAnimationList::isVisible(const CustomAnimationEffectPtr& pEffect) const
+{
+ std::unique_ptr<weld::TreeIter> xEntry = mxTreeView->make_iterator();
+ if (mxTreeView->get_iter_first(*xEntry))
+ {
+ do
+ {
+ CustomAnimationListEntryItem* pTestEntry = reinterpret_cast<CustomAnimationListEntryItem*>(mxTreeView->get_id(*xEntry).toInt64());
+ if (pTestEntry->getEffect() == pEffect)
+ return weld::IsEntryVisible(*mxTreeView, *xEntry);
+ } while (mxTreeView->iter_next(*xEntry));
+ }
+ return true;
}
EffectSequence CustomAnimationList::getSelection() const
{
EffectSequence aSelection;
- CustomAnimationListEntry* pEntry = dynamic_cast< CustomAnimationListEntry* >(FirstSelected());
- while( pEntry )
- {
- CustomAnimationEffectPtr pEffect( pEntry->getEffect() );
- if( pEffect.get() )
- aSelection.push_back( pEffect );
+ mxTreeView->selected_foreach([this, &aSelection](weld::TreeIter& rEntry){
+ CustomAnimationListEntryItem* pEntry = reinterpret_cast<CustomAnimationListEntryItem*>(mxTreeView->get_id(rEntry).toInt64());
+ CustomAnimationEffectPtr pEffect(pEntry->getEffect());
+ if (pEffect)
+ aSelection.push_back(pEffect);
// if the selected effect is not expanded and has children
// we say that the children are automatically selected
- if( !IsExpanded( pEntry ) )
+ if (!mxTreeView->get_row_expanded(rEntry) && mxTreeView->iter_has_child(rEntry))
{
- CustomAnimationListEntry* pChild = dynamic_cast< CustomAnimationListEntry* >( FirstChild( pEntry ) );
- while( pChild )
+ std::unique_ptr<weld::TreeIter> xChild = mxTreeView->make_iterator(&rEntry);
+ mxTreeView->iter_children(*xChild);
+
+ do
{
- if( !IsSelected( pChild ) )
+ if (!mxTreeView->is_selected(*xChild))
{
+ CustomAnimationListEntryItem* pChild = reinterpret_cast<CustomAnimationListEntryItem*>(mxTreeView->get_id(*xChild).toInt64());
const CustomAnimationEffectPtr& pChildEffect( pChild->getEffect() );
if( pChildEffect.get() )
aSelection.push_back( pChildEffect );
}
-
- pChild = dynamic_cast< CustomAnimationListEntry* >( pChild->NextSibling() );
- }
+ } while (mxTreeView->iter_next_sibling(*xChild));
}
- pEntry = static_cast< CustomAnimationListEntry* >(NextSelected( pEntry ));
- }
+ return false;
+ });
return aSelection;
}
-bool CustomAnimationList::DoubleClickHdl()
+IMPL_LINK_NOARG(CustomAnimationList, DoubleClickHdl, weld::TreeView&, bool)
{
mpController->onDoubleClick();
return false;
}
-VclPtr<PopupMenu> CustomAnimationList::CreateContextMenu()
+IMPL_LINK(CustomAnimationList, CommandHdl, const CommandEvent&, rCEvt, bool)
{
- mxMenu.disposeAndClear();
- mxBuilder.reset(new VclBuilder(nullptr, VclBuilderContainer::getUIRootDir(), "modules/simpress/ui/effectmenu.ui", ""));
- mxMenu.set(mxBuilder->get_menu("menu"));
+ if (rCEvt.GetCommand() != CommandEventId::ContextMenu)
+ return false;
+
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(mxTreeView.get(), "modules/simpress/ui/effectmenu.ui"));
+ std::unique_ptr<weld::Menu> xMenu = xBuilder->weld_menu("menu");
sal_Int16 nNodeType = -1;
sal_Int16 nEntries = 0;
- CustomAnimationListEntry* pEntry = static_cast< CustomAnimationListEntry* >(FirstSelected());
- while( pEntry )
- {
+ mxTreeView->selected_foreach([this, &nNodeType, &nEntries](weld::TreeIter& rEntry){
+ CustomAnimationListEntryItem* pEntry = reinterpret_cast<CustomAnimationListEntryItem*>(mxTreeView->get_id(rEntry).toInt64());
+ CustomAnimationEffectPtr pEffect(pEntry->getEffect());
+
nEntries++;
- CustomAnimationEffectPtr pEffect( pEntry->getEffect() );
- if( pEffect.get() )
+ if (pEffect.get())
{
if( nNodeType == -1 )
{
@@ -1291,26 +1153,30 @@ VclPtr<PopupMenu> CustomAnimationList::CreateContextMenu()
if( nNodeType != pEffect->getNodeType() )
{
nNodeType = -1;
- break;
+ return true;
}
}
}
- pEntry = static_cast< CustomAnimationListEntry* >(NextSelected( pEntry ));
- }
+ return false;
+ });
+
+ xMenu->set_active("onclick", nNodeType == EffectNodeType::ON_CLICK);
+ xMenu->set_active("withprev", nNodeType == EffectNodeType::WITH_PREVIOUS);
+ xMenu->set_active("afterprev", nNodeType == EffectNodeType::AFTER_PREVIOUS);
+ xMenu->set_sensitive("options", nEntries == 1);
+ xMenu->set_sensitive("timing", nEntries == 1);
- mxMenu->CheckItem("onclick", nNodeType == EffectNodeType::ON_CLICK);
- mxMenu->CheckItem("withprev", nNodeType == EffectNodeType::WITH_PREVIOUS);
- mxMenu->CheckItem("afterprev", nNodeType == EffectNodeType::AFTER_PREVIOUS);
- mxMenu->EnableItem(mxMenu->GetItemId("options"), nEntries == 1);
- mxMenu->EnableItem(mxMenu->GetItemId("timing"), nEntries == 1);
+ OString sCommand = xMenu->popup_at_rect(mxTreeView.get(), ::tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1,1)));
+ if (!sCommand.isEmpty())
+ ExecuteContextMenuAction(sCommand);
- return mxMenu;
+ return true;
}
-void CustomAnimationList::ExecuteContextMenuAction( sal_uInt16 nSelectedPopupEntry )
+void CustomAnimationList::ExecuteContextMenuAction(const OString& rIdent)
{
- mpController->onContextMenu(mxMenu->GetItemIdent(nSelectedPopupEntry));
+ mpController->onContextMenu(rIdent);
}
void CustomAnimationList::notify_change()
@@ -1319,34 +1185,6 @@ void CustomAnimationList::notify_change()
mpController->onSelect();
}
-void CustomAnimationList::Paint(vcl::RenderContext& rRenderContext, const ::tools::Rectangle& rRect)
-{
- if( mbIgnorePaint )
- return;
-
- SvTreeListBox::Paint(rRenderContext, rRect);
-
- // draw help text if list box is still empty
- if( First() != nullptr )
- return;
-
- Color aOldColor(rRenderContext.GetTextColor());
- rRenderContext.SetTextColor(rRenderContext.GetSettings().GetStyleSettings().GetDisableColor());
- ::Point aOffset(rRenderContext.LogicToPixel(Point(6, 6), MapMode(MapUnit::MapAppFont)));
-
- ::tools::Rectangle aRect(Point(0,0), GetOutputSizePixel());
-
- aRect.AdjustLeft(aOffset.X() );
- aRect.AdjustTop(aOffset.Y() );
- aRect.AdjustRight( -(aOffset.X()) );
- aRect.AdjustBottom( -(aOffset.Y()) );
-
- rRenderContext.DrawText(aRect, SdResId(STR_CUSTOMANIMATION_LIST_HELPTEXT),
- DrawTextFlags::MultiLine | DrawTextFlags::WordBreak | DrawTextFlags::Center | DrawTextFlags::VCenter );
-
- rRenderContext.SetTextColor(aOldColor);
-}
-
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */