summaryrefslogtreecommitdiff
path: root/vcl
diff options
context:
space:
mode:
authorCaolán McNamara <caolanm@redhat.com>2022-04-14 20:13:17 +0100
committerCaolán McNamara <caolanm@redhat.com>2022-04-15 20:44:49 +0200
commitd1da1c59d196b7f6037b7e0820b81fc527d56a4c (patch)
treee5ee0df76dceb2f43a7d0a83db525978d5f95c7d /vcl
parentfbfda267e8f4b55dff30a3827bff760565f36fdb (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.hxx7
-rw-r--r--vcl/source/app/salvtables.cxx81
-rw-r--r--vcl/unx/gtk3/gtkinst.cxx92
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());