mirror of
https://github.com/luanti-org/luanti.git
synced 2025-06-27 16:36:03 +00:00
Make chat web links clickable (#11092)
If enabled in minetest.conf, provides colored, clickable (middle-mouse or ctrl-left-mouse) weblinks in chat output, to open the OS' default web browser.
This commit is contained in:
parent
e1b297a14b
commit
1805775f3d
8 changed files with 242 additions and 30 deletions
|
@ -41,6 +41,10 @@ inline u32 clamp_u8(s32 value)
|
|||
return (u32) MYMIN(MYMAX(value, 0), 255);
|
||||
}
|
||||
|
||||
inline bool isInCtrlKeys(const irr::EKEY_CODE& kc)
|
||||
{
|
||||
return kc == KEY_LCONTROL || kc == KEY_RCONTROL || kc == KEY_CONTROL;
|
||||
}
|
||||
|
||||
GUIChatConsole::GUIChatConsole(
|
||||
gui::IGUIEnvironment* env,
|
||||
|
@ -91,6 +95,10 @@ GUIChatConsole::GUIChatConsole(
|
|||
|
||||
// set default cursor options
|
||||
setCursor(true, true, 2.0, 0.1);
|
||||
|
||||
// track ctrl keys for mouse event
|
||||
m_is_ctrl_down = false;
|
||||
m_cache_clickable_chat_weblinks = g_settings->getBool("clickable_chat_weblinks");
|
||||
}
|
||||
|
||||
GUIChatConsole::~GUIChatConsole()
|
||||
|
@ -405,8 +413,21 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
|
|||
|
||||
ChatPrompt &prompt = m_chat_backend->getPrompt();
|
||||
|
||||
if(event.EventType == EET_KEY_INPUT_EVENT && event.KeyInput.PressedDown)
|
||||
if (event.EventType == EET_KEY_INPUT_EVENT && !event.KeyInput.PressedDown)
|
||||
{
|
||||
// CTRL up
|
||||
if (isInCtrlKeys(event.KeyInput.Key))
|
||||
{
|
||||
m_is_ctrl_down = false;
|
||||
}
|
||||
}
|
||||
else if(event.EventType == EET_KEY_INPUT_EVENT && event.KeyInput.PressedDown)
|
||||
{
|
||||
// CTRL down
|
||||
if (isInCtrlKeys(event.KeyInput.Key)) {
|
||||
m_is_ctrl_down = true;
|
||||
}
|
||||
|
||||
// Key input
|
||||
if (KeyPress(event.KeyInput) == getKeySetting("keymap_console")) {
|
||||
closeConsole();
|
||||
|
@ -613,11 +634,24 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
|
|||
}
|
||||
else if(event.EventType == EET_MOUSE_INPUT_EVENT)
|
||||
{
|
||||
if(event.MouseInput.Event == EMIE_MOUSE_WHEEL)
|
||||
if (event.MouseInput.Event == EMIE_MOUSE_WHEEL)
|
||||
{
|
||||
s32 rows = myround(-3.0 * event.MouseInput.Wheel);
|
||||
m_chat_backend->scroll(rows);
|
||||
}
|
||||
// Middle click or ctrl-click opens weblink, if enabled in config
|
||||
else if(m_cache_clickable_chat_weblinks && (
|
||||
event.MouseInput.Event == EMIE_MMOUSE_PRESSED_DOWN ||
|
||||
(event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN && m_is_ctrl_down)
|
||||
))
|
||||
{
|
||||
// If clicked within console output region
|
||||
if (event.MouseInput.Y / m_fontsize.Y < (m_height / m_fontsize.Y) - 1 )
|
||||
{
|
||||
// Translate pixel position to font position
|
||||
middleClick(event.MouseInput.X / m_fontsize.X, event.MouseInput.Y / m_fontsize.Y);
|
||||
}
|
||||
}
|
||||
}
|
||||
#if (IRRLICHT_VERSION_MT_REVISION >= 2)
|
||||
else if(event.EventType == EET_STRING_INPUT_EVENT)
|
||||
|
@ -640,3 +674,63 @@ void GUIChatConsole::setVisible(bool visible)
|
|||
}
|
||||
}
|
||||
|
||||
void GUIChatConsole::middleClick(s32 col, s32 row)
|
||||
{
|
||||
// Prevent accidental rapid clicking
|
||||
static u64 s_oldtime = 0;
|
||||
u64 newtime = porting::getTimeMs();
|
||||
|
||||
// 0.6 seconds should suffice
|
||||
if (newtime - s_oldtime < 600)
|
||||
return;
|
||||
s_oldtime = newtime;
|
||||
|
||||
const std::vector<ChatFormattedFragment> &
|
||||
frags = m_chat_backend->getConsoleBuffer().getFormattedLine(row).fragments;
|
||||
std::string weblink = ""; // from frag meta
|
||||
|
||||
// Identify targetted fragment, if exists
|
||||
int indx = frags.size() - 1;
|
||||
if (indx < 0) {
|
||||
// Invalid row, frags is empty
|
||||
return;
|
||||
}
|
||||
// Scan from right to left, offset by 1 font space because left margin
|
||||
while (indx > -1 && (u32)col < frags[indx].column + 1) {
|
||||
--indx;
|
||||
}
|
||||
if (indx > -1) {
|
||||
weblink = frags[indx].weblink;
|
||||
// Note if(indx < 0) then a frag somehow had a corrupt column field
|
||||
}
|
||||
|
||||
/*
|
||||
// Debug help. Please keep this in case adjustments are made later.
|
||||
std::string ws;
|
||||
ws = "Middleclick: (" + std::to_string(col) + ',' + std::to_string(row) + ')' + " frags:";
|
||||
// show all frags <position>(<length>) for the clicked row
|
||||
for (u32 i=0;i<frags.size();++i) {
|
||||
if (indx == int(i))
|
||||
// tag the actual clicked frag
|
||||
ws += '*';
|
||||
ws += std::to_string(frags.at(i).column) + '('
|
||||
+ std::to_string(frags.at(i).text.size()) + "),";
|
||||
}
|
||||
actionstream << ws << std::endl;
|
||||
*/
|
||||
|
||||
// User notification
|
||||
if (weblink.size() != 0) {
|
||||
std::ostringstream msg;
|
||||
msg << " * ";
|
||||
if (porting::open_url(weblink)) {
|
||||
msg << gettext("Opening webpage");
|
||||
}
|
||||
else {
|
||||
msg << gettext("Failed to open webpage");
|
||||
}
|
||||
msg << " '" << weblink << "'";
|
||||
msg.flush();
|
||||
m_chat_backend->addUnparsedMessage(utf8_to_wide(msg.str()));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue