Quellcode durchsuchen

LibVT: Don't commit to opening a hyperlink until mouseup

It felt too rushed to open links when simply mousedown'ing on them.
Improve this by implementing basic "click" semantics instead.

This patch also introduces the ability to prevent link opening if you
want to force selection instead. Hold shift and we will not open links.
Andreas Kling vor 5 Jahren
Ursprung
Commit
ab7de41c7b
2 geänderte Dateien mit 50 neuen und 11 gelöschten Zeilen
  1. 47 11
      Libraries/LibVT/TerminalWidget.cpp
  2. 3 0
      Libraries/LibVT/TerminalWidget.h

+ 47 - 11
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));
                     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);
-
-                bool should_paint_dotted_underline = !attribute.href.is_empty() && m_hovered_href_id != attribute.href_id;
+                enum class UnderlineStyle {
+                    None,
+                    Dotted,
+                    Solid,
+                };
+
+                auto underline_style = UnderlineStyle::None;
+
+                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 (should_paint_dotted_underline) {
+                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);
                     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 x1 = cell_rect.bottom_left().x();
                     int x2 = cell_rect.bottom_right().x();
                     int x2 = cell_rect.bottom_right().x();
@@ -402,8 +418,6 @@ void TerminalWidget::paint_event(GUI::PaintEvent& event)
                         if ((x % 3) == 0)
                         if ((x % 3) == 0)
                             painter.set_pixel({ x, y }, color);
                             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());
         GUI::Clipboard::the().set_data(selected_text());
 }
 }
 
 
-void TerminalWidget::mousedown_event(GUI::MouseEvent& event)
+void TerminalWidget::mouseup_event(GUI::MouseEvent& event)
 {
 {
     if (event.button() == GUI::MouseButton::Left) {
     if (event.button() == GUI::MouseButton::Left) {
         auto attribute = m_terminal.attribute_at(buffer_position_at(event.position()));
         auto attribute = m_terminal.attribute_at(buffer_position_at(event.position()));
-        if (!attribute.href.is_empty()) {
+        if (!m_active_href_id.is_null() && attribute.href_id == m_active_href_id) {
             dbg() << "Open hyperlinked URL: _" << attribute.href << "_";
             dbg() << "Open hyperlinked URL: _" << attribute.href << "_";
             Desktop::Launcher::open(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 (!(event.modifiers() & Mod_Shift) && !attribute.href.is_empty()) {
+            m_active_href_id = attribute.href_id;
             return;
             return;
         }
         }
+        m_active_href_id = {};
 
 
         if (m_triple_click_timer.is_valid() && m_triple_click_timer.elapsed() < 250) {
         if (m_triple_click_timer.is_valid() && m_triple_click_timer.elapsed() < 250) {
             int start_column = 0;
             int start_column = 0;
@@ -651,9 +678,15 @@ void TerminalWidget::mousemove_event(GUI::MouseEvent& event)
     auto position = buffer_position_at(event.position());
     auto position = buffer_position_at(event.position());
 
 
     auto attribute = m_terminal.attribute_at(position);
     auto attribute = m_terminal.attribute_at(position);
+
     if (attribute.href_id != m_hovered_href_id) {
     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())
         if (!m_hovered_href.is_empty())
             window()->set_override_cursor(GUI::StandardCursor::Hand);
             window()->set_override_cursor(GUI::StandardCursor::Hand);
         else
         else
@@ -664,6 +697,9 @@ void TerminalWidget::mousemove_event(GUI::MouseEvent& event)
     if (!(event.buttons() & GUI::MouseButton::Left))
     if (!(event.buttons() & GUI::MouseButton::Left))
         return;
         return;
 
 
+    if (!m_active_href_id.is_null())
+        return;
+
     auto old_selection_end = m_selection_end;
     auto old_selection_end = m_selection_end;
     m_selection_end = position;
     m_selection_end = position;
     if (old_selection_end != m_selection_end)
     if (old_selection_end != m_selection_end)

+ 3 - 0
Libraries/LibVT/TerminalWidget.h

@@ -94,6 +94,7 @@ private:
     virtual void keydown_event(GUI::KeyEvent&) override;
     virtual void keydown_event(GUI::KeyEvent&) override;
     virtual void keyup_event(GUI::KeyEvent&) override;
     virtual void keyup_event(GUI::KeyEvent&) override;
     virtual void mousedown_event(GUI::MouseEvent&) override;
     virtual void mousedown_event(GUI::MouseEvent&) override;
+    virtual void mouseup_event(GUI::MouseEvent&) override;
     virtual void mousemove_event(GUI::MouseEvent&) override;
     virtual void mousemove_event(GUI::MouseEvent&) override;
     virtual void mousewheel_event(GUI::MouseEvent&) override;
     virtual void mousewheel_event(GUI::MouseEvent&) override;
     virtual void doubleclick_event(GUI::MouseEvent&) override;
     virtual void doubleclick_event(GUI::MouseEvent&) override;
@@ -133,6 +134,8 @@ private:
     String m_hovered_href;
     String m_hovered_href;
     String m_hovered_href_id;
     String m_hovered_href_id;
 
 
+    String m_active_href_id;
+
     // Snapshot of m_hovered_href when opening a context menu for a hyperlink.
     // Snapshot of m_hovered_href when opening a context menu for a hyperlink.
     String m_context_menu_href;
     String m_context_menu_href;