tdf#152029 Visually draw attention to in-view bookmark
when mouse pointer is over bookmark entry in the Navigator content tree This patch brings attention to in-view bookmarks when the mouse pointer is positioned over bookmark content entries in the Navigator content tree. All in-view bookmarks are brought to attention by placing the mouse pointer over the bookmark content type (category) entry. The patch adds a parameter to the weld::get_dest_row_at_pos function to give the option not to auto scroll. It is needed to prevent auto scrolling when used in the the mouse move handler. Additional use can be made in the content tree CommandHdl to make the tree not jump when the context popup menu is activated for entries near the top and bottom of the the visible tree. Change-Id: I04e306286ca58ab6c8ae7e5c02b25a0592c4a9d3 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/143628 Tested-by: Jenkins Reviewed-by: Jim Raykowski <raykowj@gmail.com>
This commit is contained in:
parent
968242fe32
commit
3cb654972b
7 changed files with 224 additions and 36 deletions
|
@ -1352,7 +1352,9 @@ public:
|
|||
* after the row
|
||||
* b) dnd highlight the dest row
|
||||
*/
|
||||
virtual bool get_dest_row_at_pos(const Point& rPos, weld::TreeIter* pResult, bool bDnDMode) = 0;
|
||||
virtual bool get_dest_row_at_pos(const Point& rPos, weld::TreeIter* pResult, bool bDnDMode,
|
||||
bool bAutoScroll = true)
|
||||
= 0;
|
||||
virtual void unset_drag_dest_row() = 0;
|
||||
virtual tools::Rectangle get_row_area(const weld::TreeIter& rIter) const = 0;
|
||||
// for dragging and dropping between TreeViews, return the active source
|
||||
|
|
|
@ -32,6 +32,8 @@
|
|||
#include <o3tl/enumarray.hxx>
|
||||
#include <o3tl/typed_flags_set.hxx>
|
||||
|
||||
#include <svx/sdr/overlay/overlayobject.hxx>
|
||||
|
||||
class SwWrtShell;
|
||||
class SwContentType;
|
||||
class SwNavigationPI;
|
||||
|
@ -91,6 +93,7 @@ class SwContentTree final : public SfxListener
|
|||
SwNavigationPI* m_pDialog;
|
||||
OUString m_sSpace;
|
||||
AutoTimer m_aUpdTimer;
|
||||
AutoTimer m_aOverlayObjectDelayTimer;
|
||||
|
||||
o3tl::enumarray<ContentTypeId,std::unique_ptr<SwContentType>> m_aActiveContentArr;
|
||||
o3tl::enumarray<ContentTypeId,std::unique_ptr<SwContentType>> m_aHiddenContentArr;
|
||||
|
@ -129,6 +132,11 @@ class SwContentTree final : public SfxListener
|
|||
bool m_bDocHasChanged = true;
|
||||
bool m_bIgnoreDocChange = false; // used to prevent tracking update
|
||||
|
||||
std::unique_ptr<weld::TreeIter> m_xOverlayCompareEntry;
|
||||
std::unique_ptr<sdr::overlay::OverlayObject> m_xOverlayObject;
|
||||
|
||||
void BringBookmarksToAttention(const std::vector<OUString>& rNames);
|
||||
|
||||
/**
|
||||
* Before any data will be deleted, the last active entry has to be found.
|
||||
* After this the UserData will be deleted
|
||||
|
@ -183,6 +191,8 @@ class SwContentTree final : public SfxListener
|
|||
DECL_LINK(QueryTooltipHdl, const weld::TreeIter&, OUString);
|
||||
DECL_LINK(DragBeginHdl, bool&, bool);
|
||||
DECL_LINK(TimerUpdate, Timer *, void);
|
||||
DECL_LINK(m_aOverlayObjectDelayTimerHdl, Timer *, void);
|
||||
DECL_LINK(MouseMoveHdl, const MouseEvent&, bool);
|
||||
|
||||
public:
|
||||
SwContentTree(std::unique_ptr<weld::TreeView> xTreeView, SwNavigationPI* pDialog);
|
||||
|
|
|
@ -102,6 +102,12 @@
|
|||
#include <txtftn.hxx>
|
||||
#include <fmtftn.hxx>
|
||||
|
||||
#include <txtfrm.hxx>
|
||||
#include <svx/sdr/overlay/overlayselection.hxx>
|
||||
#include <svx/sdr/overlay/overlayobject.hxx>
|
||||
#include <svx/sdr/overlay/overlaymanager.hxx>
|
||||
#include <svx/sdrpaintwindow.hxx>
|
||||
|
||||
#define CTYPE_CNT 0
|
||||
#define CTYPE_CTT 1
|
||||
|
||||
|
@ -1066,6 +1072,7 @@ SwContentTree::SwContentTree(std::unique_ptr<weld::TreeView> xTreeView, SwNaviga
|
|||
, m_pDialog(pDialog)
|
||||
, m_sSpace(OUString(" "))
|
||||
, m_aUpdTimer("SwContentTree m_aUpdTimer")
|
||||
, m_aOverlayObjectDelayTimer("SwContentTree m_aOverlayObjectDelayTimer")
|
||||
, m_sInvisible(SwResId(STR_INVISIBLE))
|
||||
, m_pHiddenShell(nullptr)
|
||||
, m_pActiveShell(nullptr)
|
||||
|
@ -1082,6 +1089,7 @@ SwContentTree::SwContentTree(std::unique_ptr<weld::TreeView> xTreeView, SwNaviga
|
|||
, m_bIsLastReadOnly(false)
|
||||
, m_bIsOutlineMoveable(true)
|
||||
, m_bViewHasChanged(false)
|
||||
, m_xOverlayCompareEntry(m_xTreeView->make_iterator())
|
||||
{
|
||||
m_xTreeView->set_size_request(m_xTreeView->get_approximate_digit_width() * 30,
|
||||
m_xTreeView->get_text_height() * 14);
|
||||
|
@ -1097,6 +1105,7 @@ SwContentTree::SwContentTree(std::unique_ptr<weld::TreeView> xTreeView, SwNaviga
|
|||
m_xTreeView->connect_popup_menu(LINK(this, SwContentTree, CommandHdl));
|
||||
m_xTreeView->connect_query_tooltip(LINK(this, SwContentTree, QueryTooltipHdl));
|
||||
m_xTreeView->connect_drag_begin(LINK(this, SwContentTree, DragBeginHdl));
|
||||
m_xTreeView->connect_mouse_move(LINK(this, SwContentTree, MouseMoveHdl));
|
||||
|
||||
for (ContentTypeId i : o3tl::enumrange<ContentTypeId>())
|
||||
{
|
||||
|
@ -1121,6 +1130,8 @@ SwContentTree::SwContentTree(std::unique_ptr<weld::TreeView> xTreeView, SwNaviga
|
|||
|
||||
m_aUpdTimer.SetInvokeHandler(LINK(this, SwContentTree, TimerUpdate));
|
||||
m_aUpdTimer.SetTimeout(1000);
|
||||
m_aOverlayObjectDelayTimer.SetInvokeHandler(LINK(this, SwContentTree, m_aOverlayObjectDelayTimerHdl));
|
||||
m_aOverlayObjectDelayTimer.SetTimeout(500);
|
||||
}
|
||||
|
||||
SwContentTree::~SwContentTree()
|
||||
|
@ -1135,6 +1146,74 @@ SwContentTree::~SwContentTree()
|
|||
SetActiveShell(nullptr);
|
||||
}
|
||||
|
||||
IMPL_LINK(SwContentTree, MouseMoveHdl, const MouseEvent&, rMEvt, bool)
|
||||
{
|
||||
if (rMEvt.IsEnterWindow())
|
||||
{
|
||||
m_xTreeView->get_iter_first(*m_xOverlayCompareEntry);
|
||||
return false;
|
||||
}
|
||||
bool bRemoveOverlayObject = false;
|
||||
if (rMEvt.IsLeaveWindow())
|
||||
{
|
||||
bRemoveOverlayObject = true;
|
||||
}
|
||||
else if (std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
|
||||
m_xTreeView->get_dest_row_at_pos(rMEvt.GetPosPixel(), xEntry.get(), false, false))
|
||||
{
|
||||
if (lcl_IsContent(*xEntry, *m_xTreeView)) // content entry
|
||||
{
|
||||
SwContent* pCnt = weld::fromId<SwContent*>(m_xTreeView->get_id(*xEntry));
|
||||
const ContentTypeId nType = pCnt->GetParent()->GetType();
|
||||
bRemoveOverlayObject = nType != ContentTypeId::BOOKMARK;
|
||||
if (!bRemoveOverlayObject &&
|
||||
m_xTreeView->iter_compare(*xEntry, *m_xOverlayCompareEntry) != 0)
|
||||
{
|
||||
m_xTreeView->copy_iterator(*xEntry, *m_xOverlayCompareEntry);
|
||||
if (nType == ContentTypeId::BOOKMARK)
|
||||
{
|
||||
BringBookmarksToAttention(std::vector<OUString> {pCnt->GetName()});
|
||||
}
|
||||
}
|
||||
}
|
||||
else // content type entry
|
||||
{
|
||||
const ContentTypeId nType =
|
||||
weld::fromId<SwContentType*>(m_xTreeView->get_id(*xEntry))->GetType();
|
||||
bRemoveOverlayObject = nType != ContentTypeId::BOOKMARK;
|
||||
if (!bRemoveOverlayObject &&
|
||||
m_xTreeView->iter_compare(*xEntry, *m_xOverlayCompareEntry) != 0)
|
||||
{
|
||||
m_xTreeView->copy_iterator(*xEntry, *m_xOverlayCompareEntry);
|
||||
if (nType == ContentTypeId::BOOKMARK)
|
||||
{
|
||||
Reference<frame::XModel> xModel =
|
||||
m_pActiveShell->GetView().GetDocShell()->GetBaseModel();
|
||||
Reference<text::XBookmarksSupplier> xBkms(xModel, uno::UNO_QUERY);
|
||||
Reference<container::XNameAccess> xNames = xBkms->getBookmarks();
|
||||
if (xNames.is())
|
||||
{
|
||||
auto aNames(comphelper::sequenceToContainer<std::vector<OUString>>(
|
||||
xNames->getElementNames()));
|
||||
BringBookmarksToAttention(aNames);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bRemoveOverlayObject)
|
||||
{
|
||||
m_aOverlayObjectDelayTimer.Stop();
|
||||
if (m_xOverlayObject && m_xOverlayObject->getOverlayManager())
|
||||
{
|
||||
m_xOverlayObject->getOverlayManager()->remove(*m_xOverlayObject);
|
||||
m_xOverlayObject.reset();
|
||||
}
|
||||
m_xTreeView->get_iter_first(*m_xOverlayCompareEntry);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Drag&Drop methods
|
||||
IMPL_LINK(SwContentTree, DragBeginHdl, bool&, rUnsetDragIcon, bool)
|
||||
{
|
||||
|
@ -4836,6 +4915,23 @@ void SwContentTree::ShowActualView()
|
|||
GetParentWindow()->UpdateListBox();
|
||||
}
|
||||
|
||||
IMPL_LINK_NOARG(SwContentTree, m_aOverlayObjectDelayTimerHdl, Timer *, void)
|
||||
{
|
||||
m_aOverlayObjectDelayTimer.Stop();
|
||||
if (m_xOverlayObject)
|
||||
{
|
||||
if (SdrView* pView = m_pActiveShell->GetDrawView())
|
||||
{
|
||||
if (SdrPaintWindow* pPaintWindow = pView->GetPaintWindow(0))
|
||||
{
|
||||
const rtl::Reference<sdr::overlay::OverlayManager>& xOverlayManager =
|
||||
pPaintWindow->GetOverlayManager();
|
||||
xOverlayManager->add(*m_xOverlayObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IMPL_LINK_NOARG(SwContentTree, SelectHdl, weld::TreeView&, void)
|
||||
{
|
||||
if (m_pConfig->IsNavigateOnSelect())
|
||||
|
@ -5407,4 +5503,78 @@ void SwContentTree::SelectContentType(std::u16string_view rContentTypeName)
|
|||
} while (m_xTreeView->iter_next_sibling(*xIter));
|
||||
}
|
||||
|
||||
void SwContentTree::BringBookmarksToAttention(const std::vector<OUString>& rNames)
|
||||
{
|
||||
std::vector<basegfx::B2DRange> aRanges;
|
||||
IDocumentMarkAccess* const pMarkAccess = m_pActiveShell->getIDocumentMarkAccess();
|
||||
for (const auto& rName : rNames)
|
||||
{
|
||||
IDocumentMarkAccess::const_iterator_t ppBkmk = pMarkAccess->findBookmark(rName);
|
||||
if (ppBkmk != pMarkAccess->getBookmarksEnd())
|
||||
{
|
||||
SwPosition aMarkStart = (*ppBkmk)->GetMarkStart();
|
||||
if (const SwTextNode* pMarkStartTextNode = aMarkStart.GetNode().GetTextNode())
|
||||
{
|
||||
if (const SwTextFrame* pMarkStartFrame = static_cast<const SwTextFrame*>(
|
||||
pMarkStartTextNode->getLayoutFrame(m_pActiveShell->GetLayout())))
|
||||
{
|
||||
SwPosition aMarkEnd = (*ppBkmk)->GetMarkEnd();
|
||||
if (const SwTextNode* pMarkEndTextNode = aMarkEnd.GetNode().GetTextNode())
|
||||
{
|
||||
if (const SwTextFrame* pMarkEndFrame = static_cast<const SwTextFrame*>(
|
||||
pMarkEndTextNode->getLayoutFrame(
|
||||
m_pActiveShell->GetLayout())))
|
||||
{
|
||||
// adjust span when mark start equals mark end
|
||||
if (aMarkStart == aMarkEnd)
|
||||
{
|
||||
if (aMarkEnd.GetContentIndex() < pMarkEndTextNode->Len() - 1)
|
||||
aMarkEnd.AdjustContent(+1);
|
||||
else if (aMarkStart.GetContentIndex() > 0)
|
||||
aMarkStart.AdjustContent(-1);
|
||||
}
|
||||
SwRect aStartCharRect;
|
||||
pMarkStartFrame->GetCharRect(aStartCharRect, aMarkStart);
|
||||
SwRect aEndCharRect;
|
||||
pMarkEndFrame->GetCharRect(aEndCharRect, aMarkEnd);
|
||||
if (aStartCharRect.Top() == aEndCharRect.Top())
|
||||
{
|
||||
// single line range
|
||||
aRanges.emplace_back(aStartCharRect.Left(),
|
||||
aStartCharRect.Top(),
|
||||
aEndCharRect.Right() + 1,
|
||||
aEndCharRect.Bottom() + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// multi line range
|
||||
SwRect aMarkStartFrameRect = pMarkStartFrame->getFrameArea();
|
||||
aRanges.emplace_back(aStartCharRect.Left(),
|
||||
aStartCharRect.Top(),
|
||||
aMarkStartFrameRect.Right(),
|
||||
aStartCharRect.Bottom() + 1);
|
||||
if (aStartCharRect.Bottom() + 1 != aEndCharRect.Top())
|
||||
aRanges.emplace_back(aMarkStartFrameRect.Left(),
|
||||
aStartCharRect.Bottom() + 1,
|
||||
aMarkStartFrameRect.Right(),
|
||||
aEndCharRect.Top() + 1);
|
||||
aRanges.emplace_back(aMarkStartFrameRect.Left(),
|
||||
aEndCharRect.Top() + 1,
|
||||
aEndCharRect.Right() + 1,
|
||||
aEndCharRect.Bottom() + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (m_xOverlayObject && m_xOverlayObject->getOverlayManager())
|
||||
m_xOverlayObject->getOverlayManager()->remove(*m_xOverlayObject);
|
||||
m_xOverlayObject.reset(new sdr::overlay::OverlaySelection(sdr::overlay::OverlayType::Invert,
|
||||
Color(), std::move(aRanges),
|
||||
true /*unused for Invert type*/));
|
||||
m_aOverlayObjectDelayTimer.Start();
|
||||
}
|
||||
|
||||
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|
||||
|
|
|
@ -1716,8 +1716,8 @@ public:
|
|||
|
||||
SvTabListBox& getTreeView();
|
||||
|
||||
virtual bool get_dest_row_at_pos(const Point& rPos, weld::TreeIter* pResult,
|
||||
bool bDnDMode) override;
|
||||
virtual bool get_dest_row_at_pos(const Point& rPos, weld::TreeIter* pResult, bool bDnDMode,
|
||||
bool bAutoScroll = true) override;
|
||||
|
||||
virtual void unset_drag_dest_row() override;
|
||||
|
||||
|
|
|
@ -121,26 +121,29 @@ public:
|
|||
m_aModelChangedHdl.Call(this);
|
||||
}
|
||||
|
||||
SvTreeListEntry* GetTargetAtPoint(const Point& rPos, bool bHighLightTarget)
|
||||
SvTreeListEntry* GetTargetAtPoint(const Point& rPos, bool bHighLightTarget, bool bScroll = true)
|
||||
{
|
||||
SvTreeListEntry* pOldTargetEntry = pTargetEntry;
|
||||
pTargetEntry = PosOverBody(rPos) ? pImpl->GetEntry(rPos) : nullptr;
|
||||
if (pOldTargetEntry != pTargetEntry)
|
||||
ImplShowTargetEmphasis(pOldTargetEntry, false);
|
||||
|
||||
// scroll
|
||||
if (rPos.Y() < 12)
|
||||
if (bScroll)
|
||||
{
|
||||
ImplShowTargetEmphasis(pTargetEntry, false);
|
||||
ScrollOutputArea(+1);
|
||||
}
|
||||
else
|
||||
{
|
||||
Size aSize(pImpl->GetOutputSize());
|
||||
if (rPos.Y() > aSize.Height() - 12)
|
||||
// scroll
|
||||
if (rPos.Y() < 12)
|
||||
{
|
||||
ImplShowTargetEmphasis(pTargetEntry, false);
|
||||
ScrollOutputArea(-1);
|
||||
ScrollOutputArea(+1);
|
||||
}
|
||||
else
|
||||
{
|
||||
Size aSize(pImpl->GetOutputSize());
|
||||
if (rPos.Y() > aSize.Height() - 12)
|
||||
{
|
||||
ImplShowTargetEmphasis(pTargetEntry, false);
|
||||
ScrollOutputArea(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5154,12 +5154,12 @@ void SalInstanceTreeView::set_sort_column(int nColumn)
|
|||
SvTabListBox& SalInstanceTreeView::getTreeView() { return *m_xTreeView; }
|
||||
|
||||
bool SalInstanceTreeView::get_dest_row_at_pos(const Point& rPos, weld::TreeIter* pResult,
|
||||
bool bDnDMode)
|
||||
bool bDnDMode, bool bAutoScroll)
|
||||
{
|
||||
LclTabListBox* pTreeView
|
||||
= !bDnDMode ? dynamic_cast<LclTabListBox*>(m_xTreeView.get()) : nullptr;
|
||||
SvTreeListEntry* pTarget
|
||||
= pTreeView ? pTreeView->GetTargetAtPoint(rPos, false) : m_xTreeView->GetDropTarget(rPos);
|
||||
SvTreeListEntry* pTarget = pTreeView ? pTreeView->GetTargetAtPoint(rPos, false, bAutoScroll)
|
||||
: m_xTreeView->GetDropTarget(rPos);
|
||||
|
||||
if (pTarget && pResult)
|
||||
{
|
||||
|
|
|
@ -16240,7 +16240,7 @@ public:
|
|||
weld::TreeView::connect_popup_menu(rLink);
|
||||
}
|
||||
|
||||
virtual bool get_dest_row_at_pos(const Point &rPos, weld::TreeIter* pResult, bool bDnDMode) override
|
||||
virtual bool get_dest_row_at_pos(const Point &rPos, weld::TreeIter* pResult, bool bDnDMode, bool bAutoScroll) override
|
||||
{
|
||||
if (rPos.X() < 0 || rPos.Y() < 0)
|
||||
{
|
||||
|
@ -16311,28 +16311,31 @@ public:
|
|||
gtk_tree_path_free(path);
|
||||
gtk_tree_path_free(lastpath);
|
||||
|
||||
// auto scroll if we're close to the edges
|
||||
GtkAdjustment* pVAdjustment = gtk_scrollable_get_vadjustment(GTK_SCROLLABLE(m_pTreeView));
|
||||
double fStep = gtk_adjustment_get_step_increment(pVAdjustment);
|
||||
if (rPos.Y() < fStep)
|
||||
if (bAutoScroll)
|
||||
{
|
||||
double fValue = gtk_adjustment_get_value(pVAdjustment) - fStep;
|
||||
if (fValue < 0)
|
||||
fValue = 0.0;
|
||||
gtk_adjustment_set_value(pVAdjustment, fValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
GdkRectangle aRect;
|
||||
gtk_tree_view_get_visible_rect(m_pTreeView, &aRect);
|
||||
if (rPos.Y() > aRect.height - fStep)
|
||||
// auto scroll if we're close to the edges
|
||||
GtkAdjustment* pVAdjustment = gtk_scrollable_get_vadjustment(GTK_SCROLLABLE(m_pTreeView));
|
||||
double fStep = gtk_adjustment_get_step_increment(pVAdjustment);
|
||||
if (rPos.Y() < fStep)
|
||||
{
|
||||
double fValue = gtk_adjustment_get_value(pVAdjustment) + fStep;
|
||||
double fMax = gtk_adjustment_get_upper(pVAdjustment);
|
||||
if (fValue > fMax)
|
||||
fValue = fMax;
|
||||
double fValue = gtk_adjustment_get_value(pVAdjustment) - fStep;
|
||||
if (fValue < 0)
|
||||
fValue = 0.0;
|
||||
gtk_adjustment_set_value(pVAdjustment, fValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
GdkRectangle aRect;
|
||||
gtk_tree_view_get_visible_rect(m_pTreeView, &aRect);
|
||||
if (rPos.Y() > aRect.height - fStep)
|
||||
{
|
||||
double fValue = gtk_adjustment_get_value(pVAdjustment) + fStep;
|
||||
double fMax = gtk_adjustment_get_upper(pVAdjustment);
|
||||
if (fValue > fMax)
|
||||
fValue = fMax;
|
||||
gtk_adjustment_set_value(pVAdjustment, fValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
Loading…
Reference in a new issue