diff --git a/Libraries/LibVT/TerminalWidget.cpp b/Libraries/LibVT/TerminalWidget.cpp index 402ce83eaf..bbb73681f8 100644 --- a/Libraries/LibVT/TerminalWidget.cpp +++ b/Libraries/LibVT/TerminalWidget.cpp @@ -388,12 +388,28 @@ void TerminalWidget::paint_event(GUI::PaintEvent& event) painter.clear_rect(cell_rect, color_from_rgb(should_reverse_fill_for_cursor_or_selection ? attribute.foreground_color : attribute.background_color).with_alpha(m_opacity)); } - bool should_paint_underline = attribute.flags & VT::Attribute::Underline - || (!m_hovered_href.is_empty() && m_hovered_href_id == attribute.href_id); + enum class UnderlineStyle { + None, + Dotted, + Solid, + }; - bool should_paint_dotted_underline = !attribute.href.is_empty() && m_hovered_href_id != attribute.href_id; + auto underline_style = UnderlineStyle::None; - if (should_paint_dotted_underline) { + if (attribute.flags & VT::Attribute::Underline) { + // Content has specified underline + underline_style = UnderlineStyle::Solid; + } else if (!attribute.href.is_empty()) { + // We're hovering a hyperlink + if (m_hovered_href_id == attribute.href_id) + underline_style = UnderlineStyle::Solid; + else + underline_style = UnderlineStyle::Dotted; + } + + if (underline_style == UnderlineStyle::Solid) { + painter.draw_line(cell_rect.bottom_left(), cell_rect.bottom_right(), color_from_rgb(should_reverse_fill_for_cursor_or_selection ? attribute.background_color : attribute.foreground_color)); + } else if (underline_style == UnderlineStyle::Dotted) { auto color = color_from_rgb(should_reverse_fill_for_cursor_or_selection ? attribute.background_color : attribute.foreground_color).darkened(0.6f); int x1 = cell_rect.bottom_left().x(); int x2 = cell_rect.bottom_right().x(); @@ -402,8 +418,6 @@ void TerminalWidget::paint_event(GUI::PaintEvent& event) if ((x % 3) == 0) painter.set_pixel({ x, y }, color); } - } else if (should_paint_underline) { - painter.draw_line(cell_rect.bottom_left(), cell_rect.bottom_right(), color_from_rgb(should_reverse_fill_for_cursor_or_selection ? attribute.background_color : attribute.foreground_color)); } } @@ -616,15 +630,28 @@ void TerminalWidget::copy() GUI::Clipboard::the().set_data(selected_text()); } +void TerminalWidget::mouseup_event(GUI::MouseEvent& event) +{ + if (event.button() == GUI::MouseButton::Left) { + auto attribute = m_terminal.attribute_at(buffer_position_at(event.position())); + if (!m_active_href_id.is_null() && attribute.href_id == m_active_href_id) { + dbg() << "Open hyperlinked URL: _" << attribute.href << "_"; + Desktop::Launcher::open(attribute.href); + } + m_active_href_id = {}; + } + return; +} + void TerminalWidget::mousedown_event(GUI::MouseEvent& event) { if (event.button() == GUI::MouseButton::Left) { auto attribute = m_terminal.attribute_at(buffer_position_at(event.position())); - if (!attribute.href.is_empty()) { - dbg() << "Open hyperlinked URL: _" << attribute.href << "_"; - Desktop::Launcher::open(attribute.href); + if (!(event.modifiers() & Mod_Shift) && !attribute.href.is_empty()) { + m_active_href_id = attribute.href_id; return; } + m_active_href_id = {}; if (m_triple_click_timer.is_valid() && m_triple_click_timer.elapsed() < 250) { int start_column = 0; @@ -651,9 +678,15 @@ void TerminalWidget::mousemove_event(GUI::MouseEvent& event) auto position = buffer_position_at(event.position()); auto attribute = m_terminal.attribute_at(position); + if (attribute.href_id != m_hovered_href_id) { - m_hovered_href_id = attribute.href_id; - m_hovered_href = attribute.href; + if (m_active_href_id.is_null() || m_active_href_id == attribute.href_id) { + m_hovered_href_id = attribute.href_id; + m_hovered_href = attribute.href; + } else { + m_hovered_href_id = {}; + m_hovered_href = {}; + } if (!m_hovered_href.is_empty()) window()->set_override_cursor(GUI::StandardCursor::Hand); else @@ -664,6 +697,9 @@ void TerminalWidget::mousemove_event(GUI::MouseEvent& event) if (!(event.buttons() & GUI::MouseButton::Left)) return; + if (!m_active_href_id.is_null()) + return; + auto old_selection_end = m_selection_end; m_selection_end = position; if (old_selection_end != m_selection_end) diff --git a/Libraries/LibVT/TerminalWidget.h b/Libraries/LibVT/TerminalWidget.h index d13fdb2d30..64d63d82c8 100644 --- a/Libraries/LibVT/TerminalWidget.h +++ b/Libraries/LibVT/TerminalWidget.h @@ -94,6 +94,7 @@ private: virtual void keydown_event(GUI::KeyEvent&) override; virtual void keyup_event(GUI::KeyEvent&) override; virtual void mousedown_event(GUI::MouseEvent&) override; + virtual void mouseup_event(GUI::MouseEvent&) override; virtual void mousemove_event(GUI::MouseEvent&) override; virtual void mousewheel_event(GUI::MouseEvent&) override; virtual void doubleclick_event(GUI::MouseEvent&) override; @@ -133,6 +134,8 @@ private: String m_hovered_href; String m_hovered_href_id; + String m_active_href_id; + // Snapshot of m_hovered_href when opening a context menu for a hyperlink. String m_context_menu_href;