summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCaolán McNamara <caolanm@redhat.com>2022-04-16 12:30:01 +0100
committerCaolán McNamara <caolanm@redhat.com>2022-04-17 17:35:47 +0200
commit689d1f5dd3dc12d9f85ba98702a66c7af20849dc (patch)
tree920af627a1bf8d7f29d2eb30123e8c6ba13b6ba9
parent7784744b1fbc0e07c1b01addd1043606e8a631da (diff)
Related: tdf#148349 gtk[3|4] use a css effect to draw attention to the widget
Change-Id: I96af6c87d5aeab6513ff782a0bf25554602b4953 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/133105 Tested-by: Jenkins Reviewed-by: Caolán McNamara <caolanm@redhat.com>
-rw-r--r--vcl/unx/gtk3/gtkdata.cxx16
-rw-r--r--vcl/unx/gtk3/gtkinst.cxx114
2 files changed, 40 insertions, 90 deletions
diff --git a/vcl/unx/gtk3/gtkdata.cxx b/vcl/unx/gtk3/gtkdata.cxx
index 53f897420299..cc8535ff2ad2 100644
--- a/vcl/unx/gtk3/gtkdata.cxx
+++ b/vcl/unx/gtk3/gtkdata.cxx
@@ -462,7 +462,7 @@ static GtkStyleProvider* CreateStyleProvider()
#if GTK_CHECK_VERSION(4, 0, 0)
// we basically assumed during dialog design that the frame's were invisible, because
// they used to be in the default theme during gtk3
- "frame { border-style: none; }"
+ "frame { border-style: none; }"
#endif
"notebook.overflow > header.top > tabs > tab:checked { "
"box-shadow: none; padding: 0 0 0 0; margin: 0 0 0 0;"
@@ -470,7 +470,19 @@ static GtkStyleProvider* CreateStyleProvider()
"background-image: none; background-color: transparent;"
"border-radius: 0 0 0 0; border-width: 0 0 0 0;"
"border-style: none; border-color: transparent;"
- "opacity: 0; min-height: 0; min-width: 0; }";
+ "opacity: 0; min-height: 0; min-width: 0; }"
+ // https://css-tricks.com/restart-css-animation/
+ // This animation appears twice with two different names so we can change
+ // the class from "call_attention_1" to "call_attention_2" to restart the
+ // animation
+ "@keyframes shinkandrestore1 { 50% { margin-left: 15px; margin-right: 15px; opacity: 0.5; } }"
+ "@keyframes shinkandrestore2 { 50% { margin-left: 15px; margin-right: 15px; opacity: 0.5; } }"
+ " *.call_attention_1 {"
+ "animation-name: shinkandrestore1; animation-duration: 1s; "
+ "animation-timing-function: linear; animation-iteration-count: 2; }"
+ " *.call_attention_2 {"
+ "animation-name: shinkandrestore2; animation-duration: 1s; "
+ "animation-timing-function: linear; animation-iteration-count: 2; }";
css_provider_load_from_data(pStyleProvider, data, -1);
return GTK_STYLE_PROVIDER(pStyleProvider);
}
diff --git a/vcl/unx/gtk3/gtkinst.cxx b/vcl/unx/gtk3/gtkinst.cxx
index 65c618eeae13..ca8c893d3915 100644
--- a/vcl/unx/gtk3/gtkinst.cxx
+++ b/vcl/unx/gtk3/gtkinst.cxx
@@ -2494,92 +2494,6 @@ 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:
@@ -2875,7 +2789,6 @@ 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;
@@ -4242,7 +4155,32 @@ public:
virtual void call_attention_to() override
{
- m_xFlashAttention.reset(new FlashAttention(m_pWidget));
+ // Change the class name to restart the animation under
+ // its other name: https://css-tricks.com/restart-css-animation/
+#if GTK_CHECK_VERSION(4, 0, 0)
+ if (gtk_widget_has_css_class(m_pWidget, "call_attention_1"))
+ {
+ gtk_widget_remove_css_class(m_pWidget, "call_attention_1");
+ gtk_widget_add_css_class(m_pWidget, "call_attention_2");
+ }
+ else
+ {
+ gtk_widget_remove_css_class(m_pWidget, "call_attention_2");
+ gtk_widget_add_css_class(m_pWidget, "call_attention_1");
+ }
+#else
+ GtkStyleContext *pWidgetContext = gtk_widget_get_style_context(m_pWidget);
+ if (gtk_style_context_has_class(pWidgetContext, "call_attention_1"))
+ {
+ gtk_style_context_remove_class(pWidgetContext, "call_attention_1");
+ gtk_style_context_add_class(pWidgetContext, "call_attention_2");
+ }
+ else
+ {
+ gtk_style_context_remove_class(pWidgetContext, "call_attention_2");
+ gtk_style_context_add_class(pWidgetContext, "call_attention_1");
+ }
+#endif
}
virtual void set_stack_background() override