summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJim Raykowski <raykowj@gmail.com>2022-12-03 20:11:07 -0900
committerJim Raykowski <raykowj@gmail.com>2022-12-06 21:47:49 +0000
commit3cb654972ba204efb5dd35a44f95c7d509414400 (patch)
tree9229dbfed1c7c7352c64aad50df9d3a50b4adbb7
parent968242fe3220bc3df8104c163bc3a17eee5916c1 (diff)
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>
-rw-r--r--include/vcl/weld.hxx4
-rw-r--r--sw/source/uibase/inc/conttree.hxx10
-rw-r--r--sw/source/uibase/utlui/content.cxx170
-rw-r--r--vcl/inc/salvtables.hxx4
-rw-r--r--vcl/inc/treeglue.hxx25
-rw-r--r--vcl/source/app/salvtables.cxx6
-rw-r--r--vcl/unx/gtk3/gtkinst.cxx41
7 files changed, 224 insertions, 36 deletions
diff --git a/include/vcl/weld.hxx b/include/vcl/weld.hxx
index 4b4ea74f13b3..3bcbc0a7a08d 100644
--- a/include/vcl/weld.hxx
+++ b/include/vcl/weld.hxx
@@ -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
diff --git a/sw/source/uibase/inc/conttree.hxx b/sw/source/uibase/inc/conttree.hxx
index cf7c383f81e4..77358b9edb30 100644
--- a/sw/source/uibase/inc/conttree.hxx
+++ b/sw/source/uibase/inc/conttree.hxx
@@ -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);
diff --git a/sw/source/uibase/utlui/content.cxx b/sw/source/uibase/utlui/content.cxx
index 32a9e8ab63ce..cb7f96ec3b23 100644
--- a/sw/source/uibase/utlui/content.cxx
+++ b/sw/source/uibase/utlui/content.cxx
@@ -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: */
diff --git a/vcl/inc/salvtables.hxx b/vcl/inc/salvtables.hxx
index 7ad7a145e8af..d6968e36d00c 100644
--- a/vcl/inc/salvtables.hxx
+++ b/vcl/inc/salvtables.hxx
@@ -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;
diff --git a/vcl/inc/treeglue.hxx b/vcl/inc/treeglue.hxx
index 4cb120d81f7f..d445a533b43f 100644
--- a/vcl/inc/treeglue.hxx
+++ b/vcl/inc/treeglue.hxx
@@ -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);
+ }
}
}
diff --git a/vcl/source/app/salvtables.cxx b/vcl/source/app/salvtables.cxx
index 39ee33de947f..733d78179500 100644
--- a/vcl/source/app/salvtables.cxx
+++ b/vcl/source/app/salvtables.cxx
@@ -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)
{
diff --git a/vcl/unx/gtk3/gtkinst.cxx b/vcl/unx/gtk3/gtkinst.cxx
index e523e871290d..61d3f001c6d5 100644
--- a/vcl/unx/gtk3/gtkinst.cxx
+++ b/vcl/unx/gtk3/gtkinst.cxx
@@ -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;