diff options
author | Caolán McNamara <caolanm@redhat.com> | 2022-04-14 20:13:17 +0100 |
---|---|---|
committer | Caolán McNamara <caolanm@redhat.com> | 2022-04-15 20:44:49 +0200 |
commit | d1da1c59d196b7f6037b7e0820b81fc527d56a4c (patch) | |
tree | e5ee0df76dceb2f43a7d0a83db525978d5f95c7d /vcl | |
parent | fbfda267e8f4b55dff30a3827bff760565f36fdb (diff) |
tdf#148349 add a way to call the user's attention to a widget
Change-Id: I2846155a44f3e51ddd8cc1acd81e84a38b4d3934
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/133030
Tested-by: Jenkins
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
Diffstat (limited to 'vcl')
-rw-r--r-- | vcl/inc/salvtables.hxx | 7 | ||||
-rw-r--r-- | vcl/source/app/salvtables.cxx | 81 | ||||
-rw-r--r-- | vcl/unx/gtk3/gtkinst.cxx | 92 |
3 files changed, 180 insertions, 0 deletions
diff --git a/vcl/inc/salvtables.hxx b/vcl/inc/salvtables.hxx index 5f8ceb6b9ae3..3f574237444b 100644 --- a/vcl/inc/salvtables.hxx +++ b/vcl/inc/salvtables.hxx @@ -167,10 +167,13 @@ public: virtual ~SalInstanceMenu() override; }; +class SalFlashAttention; + class SalInstanceWidget : public virtual weld::Widget { protected: VclPtr<vcl::Window> m_xWidget; + std::unique_ptr<SalFlashAttention> m_xFlashAttention; SalInstanceBuilder* m_pBuilder; private: @@ -367,6 +370,8 @@ public: virtual void get_property_tree(tools::JsonWriter& rJsonWriter) override; + virtual void call_attention_to() override; + virtual void set_stack_background() override; virtual void set_title_background() override; @@ -1000,6 +1005,8 @@ public: virtual void HandleEventListener(VclWindowEvent& rEvent) override; + virtual void call_attention_to() override; + virtual ~SalInstanceComboBoxWithEdit() override; }; diff --git a/vcl/source/app/salvtables.cxx b/vcl/source/app/salvtables.cxx index 263c29ff5eea..a8fdaf2a7978 100644 --- a/vcl/source/app/salvtables.cxx +++ b/vcl/source/app/salvtables.cxx @@ -559,6 +559,79 @@ VclPtr<VirtualDevice> SalInstanceWidget::create_virtual_device() const DeviceFormat::DEFAULT); } +class SalFlashAttention +{ +private: + VclPtr<vcl::Window> m_xWidget; + Timer m_aFlashTimer; + Color m_aOrigControlBackground; + Wallpaper m_aOrigBackground; + bool m_bOrigControlBackground; + int m_nFlashCount; + + void SetFlash() + { + Color aColor(Application::GetSettings().GetStyleSettings().GetHighlightColor()); + m_xWidget->SetControlBackground(aColor); + } + + void ClearFlash() + { + if (m_bOrigControlBackground) + m_xWidget->SetControlBackground(m_aOrigControlBackground); + else + m_xWidget->SetControlBackground(); + } + + void Flash() + { + constexpr int FlashesWanted = 1; + + if (m_nFlashCount % 2 == 0) + ClearFlash(); + else + SetFlash(); + + if (m_nFlashCount == FlashesWanted * 2) + return; + + ++m_nFlashCount; + + m_aFlashTimer.Start(); + } + + DECL_LINK(FlashTimeout, Timer*, void); + +public: + SalFlashAttention(VclPtr<vcl::Window> xWidget) + : m_xWidget(xWidget) + , m_aFlashTimer("SalFlashAttention") + , m_bOrigControlBackground(false) + , m_nFlashCount(1) + { + m_aFlashTimer.SetTimeout(150); + m_aFlashTimer.SetInvokeHandler(LINK(this, SalFlashAttention, FlashTimeout)); + } + + void Start() + { + m_bOrigControlBackground = m_xWidget->IsControlBackground(); + if (m_bOrigControlBackground) + m_aOrigControlBackground = m_xWidget->GetControlBackground(); + m_aFlashTimer.Start(); + } + + ~SalFlashAttention() { ClearFlash(); } +}; + +IMPL_LINK_NOARG(SalFlashAttention, FlashTimeout, Timer*, void) { Flash(); } + +void SalInstanceWidget::call_attention_to() +{ + m_xFlashAttention.reset(new SalFlashAttention(m_xWidget)); + m_xFlashAttention->Start(); +} + css::uno::Reference<css::datatransfer::dnd::XDropTarget> SalInstanceWidget::get_drop_target() { return m_xWidget->GetDropTarget(); @@ -6356,6 +6429,14 @@ SalInstanceComboBoxWithEdit::SalInstanceComboBoxWithEdit(::ComboBox* pComboBox, bool SalInstanceComboBoxWithEdit::has_entry() const { return true; } +void SalInstanceComboBoxWithEdit::call_attention_to() +{ + Edit* pEdit = m_xComboBox->GetSubEdit(); + assert(pEdit); + m_xFlashAttention.reset(new SalFlashAttention(pEdit)); + m_xFlashAttention->Start(); +} + bool SalInstanceComboBoxWithEdit::changed_by_direct_pick() const { return m_bInSelect && !m_xComboBox->IsModifyByKeyboard() && !m_xComboBox->IsTravelSelect(); diff --git a/vcl/unx/gtk3/gtkinst.cxx b/vcl/unx/gtk3/gtkinst.cxx index 50e3b7949877..65c618eeae13 100644 --- a/vcl/unx/gtk3/gtkinst.cxx +++ b/vcl/unx/gtk3/gtkinst.cxx @@ -2494,6 +2494,92 @@ void set_buildable_id(GtkBuildable* pWidget, const OString& rId) namespace { +class FlashAttention +{ +private: + GtkWidget* m_pWidget; + int m_nFlashCount; + gint m_nFlashTimeout; + + static gboolean signalDraw(GtkWidget* pWidget, cairo_t* cr, gpointer self) + { + FlashAttention* pThis = static_cast<FlashAttention*>(self); + if (pThis->m_nFlashCount % 2 == 0) + return false; + + GtkAllocation alloc {0, 0, + gtk_widget_get_allocated_width(pWidget), + gtk_widget_get_allocated_height(pWidget)}; + + Color aColor(Application::GetSettings().GetStyleSettings().GetHighlightColor()); + cairo_set_source_rgba(cr, aColor.GetRed() / 255.0, aColor.GetGreen() / 255.0, aColor.GetBlue() / 255.0, 0.5); + cairo_rectangle(cr, alloc.x + 0.5, alloc.y + 0.5, alloc.width - 1, alloc.height - 1); + cairo_fill(cr); + + return false; + } + + static void signalUnmap(gpointer self) + { + FlashAttention* pThis = static_cast<FlashAttention*>(self); + pThis->ClearFlash(); + } + + void ClearFlash() + { + if (m_nFlashTimeout != 0) + { + g_source_remove(m_nFlashTimeout); + m_nFlashTimeout = 0; + } + if (m_pWidget) + { + gtk_widget_queue_draw(m_pWidget); + g_signal_handlers_disconnect_by_func(m_pWidget, reinterpret_cast<void*>(signalDraw), this); + g_signal_handlers_disconnect_by_func(m_pWidget, reinterpret_cast<void*>(signalUnmap), this); + m_pWidget = nullptr; + } + } + + bool QueueFlash() + { + constexpr int FlashesWanted = 1; + + gtk_widget_queue_draw(m_pWidget); + m_nFlashCount++; + + if (m_nFlashCount == FlashesWanted * 2) + { + ClearFlash(); + return false; + } + + return true; + } + + static gboolean FlashTimeout(FlashAttention* pThis) + { + return pThis->QueueFlash(); + } + +public: + FlashAttention(GtkWidget* pWidget) + : m_pWidget(pWidget) + , m_nFlashCount(1) + { + g_signal_connect_after(m_pWidget, "draw", G_CALLBACK(signalDraw), this); + g_signal_connect_swapped(m_pWidget, "unmap", G_CALLBACK(signalUnmap), this); + gtk_widget_queue_draw(m_pWidget); + + m_nFlashTimeout = g_timeout_add(250, reinterpret_cast<GSourceFunc>(FlashTimeout), this); + } + + ~FlashAttention() + { + ClearFlash(); + } +}; + class GtkInstanceWidget : public virtual weld::Widget { protected: @@ -2789,6 +2875,7 @@ private: #if !GTK_CHECK_VERSION(4, 0, 0) GdkDragAction m_eDragAction; #endif + std::unique_ptr<FlashAttention> m_xFlashAttention; gulong m_nFocusInSignalId; gulong m_nMnemonicActivateSignalId; gulong m_nFocusOutSignalId; @@ -4153,6 +4240,11 @@ public: //not implemented for the gtk variant } + virtual void call_attention_to() override + { + m_xFlashAttention.reset(new FlashAttention(m_pWidget)); + } + virtual void set_stack_background() override { do_set_background(Application::GetSettings().GetStyleSettings().GetWindowColor()); |