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>
This commit is contained in:
parent
fbfda267e8
commit
d1da1c59d1
@ -320,6 +320,9 @@ public:
|
||||
|
||||
virtual VclPtr<VirtualDevice> create_virtual_device() const = 0;
|
||||
|
||||
//do something transient to attract the attention of the user to the widget
|
||||
virtual void call_attention_to() = 0;
|
||||
|
||||
//make this widget look like a page in a notebook
|
||||
virtual void set_stack_background() = 0;
|
||||
//make this widget look like it has a highlighted background
|
||||
|
@ -295,22 +295,29 @@ IMPL_LINK(FindTextFieldControl, KeyInputHdl, const KeyEvent&, rKeyEvent, bool)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Select text in the search box when Ctrl-F pressed
|
||||
else if ( bMod1 && nCode == KEY_F )
|
||||
m_xWidget->select_entry_region(0, -1);
|
||||
|
||||
// Execute the search when Ctrl-G, F3 and Shift-RETURN pressed (in addition to ActivateHdl condition which handles bare RETURN)
|
||||
else if ( (bMod1 && KEY_G == nCode) || (bShift && KEY_RETURN == nCode) || (KEY_F3 == nCode) )
|
||||
{
|
||||
ActivateFind(bShift);
|
||||
bRet = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto awtKey = svt::AcceleratorExecute::st_VCLKey2AWTKey(rKeyEvent.GetKeyCode());
|
||||
const OUString aCommand(m_pAcc->findCommand(awtKey));
|
||||
if (aCommand == ".uno:SearchDialog")
|
||||
|
||||
// Select text in the search box when Ctrl-F pressed
|
||||
if ( bMod1 && nCode == KEY_F )
|
||||
m_xWidget->select_entry_region(0, -1);
|
||||
// Execute the search when Ctrl-G, F3 and Shift-RETURN pressed (in addition to ActivateHdl condition which handles bare RETURN)
|
||||
else if ( (bMod1 && KEY_G == nCode) || (bShift && KEY_RETURN == nCode) || (KEY_F3 == nCode) )
|
||||
{
|
||||
ActivateFind(bShift);
|
||||
bRet = true;
|
||||
}
|
||||
else if (aCommand == ".uno:SearchDialog")
|
||||
bRet = m_pAcc->execute(awtKey);
|
||||
|
||||
// find-shortcut called with focus already in find
|
||||
if (aCommand == "vnd.sun.star.findbar:FocusToFindbar")
|
||||
{
|
||||
m_xWidget->call_attention_to();
|
||||
bRet = true;
|
||||
}
|
||||
}
|
||||
|
||||
return bRet || ChildKeyInput(rKeyEvent);
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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());
|
||||
|
Loading…
x
Reference in New Issue
Block a user