Improve StatusBar tooltips, add app.tip

This commit is contained in:
Christian Kaiser 2025-07-31 19:56:31 -03:00
parent 6d89a6bc15
commit 25371727df
4 changed files with 59 additions and 6 deletions

View File

@ -34,10 +34,10 @@
#include "app/tools/tool_loop_manager.h"
#include "app/tx.h"
#include "app/ui/context_bar.h"
#include "app/ui/doc_view.h"
#include "app/ui/editor/editor.h"
#include "app/ui/editor/tool_loop_impl.h"
#include "app/ui/main_window.h"
#include "app/ui/status_bar.h"
#include "app/ui/timeline/timeline.h"
#include "app/ui_context.h"
#include "base/fs.h"
@ -498,6 +498,30 @@ int App_useTool(lua_State* L)
return 0;
}
int App_tip(lua_State* L)
{
const auto* ctx = App::instance()->context();
if (!ctx || !ctx->isUIAvailable() || !StatusBar::instance())
return 0; // No UI to show the tooltip
if (!lua_isstring(L, 1))
return luaL_error(L, "app.tip() message parameter must be a string");
const std::string message = lua_tostring(L, 1);
if (message.empty())
return luaL_error(L, "app.tip() message cannot be empty");
int duration = 2000;
if (lua_isinteger(L, 2)) {
const int durationInput = lua_tointeger(L, 2);
if (durationInput > 0 && durationInput < 30000) // Reasonable limits
duration = lua_tointeger(L, 2);
}
StatusBar::instance()->showTip(duration, message);
return 0;
}
int App_get_events(lua_State* L)
{
push_app_events(L);
@ -820,6 +844,7 @@ const luaL_Reg App_methods[] = {
{ "alert", App_alert },
{ "refresh", App_refresh },
{ "useTool", App_useTool },
{ "tip", App_tip },
{ nullptr, nullptr }
};

View File

@ -549,7 +549,10 @@ private:
class StatusBar::CustomizedTipWindow : public ui::TipWindow {
public:
CustomizedTipWindow(const std::string& text) : ui::TipWindow(text) {}
CustomizedTipWindow(const std::string& text) : ui::TipWindow(text)
{
setClickBehavior(ClickBehavior::CloseOnClick);
}
void setInterval(int msecs)
{
@ -557,9 +560,11 @@ public:
m_timer.reset(new ui::Timer(msecs, this));
else
m_timer->setInterval(msecs);
m_originalInterval = msecs;
}
void startTimer() { m_timer->start(); }
void startTimer() const { m_timer->start(); }
int originalInterval() const { return m_originalInterval; }
protected:
bool onProcessMessage(Message* msg) override
@ -569,12 +574,18 @@ protected:
closeWindow(nullptr);
m_timer->stop();
break;
case kMouseEnterMessage: m_timer->stop(); break;
case kMouseLeaveMessage:
m_timer->setInterval(m_originalInterval);
m_timer->start();
return true; // Avoid PopupWindow closing us.
}
return ui::TipWindow::onProcessMessage(msg);
}
private:
std::unique_ptr<ui::Timer> m_timer;
int m_originalInterval = 0;
};
// TODO Use a ui::TipWindow with rounded borders, when we add support
@ -797,12 +808,21 @@ bool StatusBar::setStatusText(int msecs, const std::string& msg)
void StatusBar::showTip(int msecs, const std::string& msg)
{
ASSERT(msecs > 0);
if (m_tipwindow == NULL) {
m_tipwindow = new CustomizedTipWindow(msg);
}
else {
m_tipwindow->setText(msg);
if (m_tipwindow->isVisible() && m_tipwindow->text() != msg) {
// If the tip window is still visible, append the text on top so
// the old message is still readable (unless it's the exact same text)
m_tipwindow->setText(m_tipwindow->text() + "\n" + msg);
// Always use the longest interval to give the user more time to read.
msecs = m_tipwindow->originalInterval() > msecs ? m_tipwindow->originalInterval() : msecs;
}
else {
m_tipwindow->setText(msg);
}
}
m_tipwindow->setInterval(msecs);

View File

@ -157,6 +157,13 @@ bool PopupWindow::onProcessMessage(Message* msg)
}
break;
}
case ClickBehavior::CloseOnClick: {
if (bounds().contains(mouseMsg->position())) {
closeWindow(nullptr);
}
break;
}
}
}
break;

View File

@ -18,7 +18,8 @@ public:
enum class ClickBehavior {
DoNothingOnClick,
CloseOnClickInOtherWindow,
CloseOnClickOutsideHotRegion
CloseOnClickOutsideHotRegion,
CloseOnClick
};
enum class EnterBehavior {