Serenity Operating System
at master 128 lines 3.1 kB view raw
1/* 2 * Copyright (c) 2020, Alex McGrath <amk@amk.ie> 3 * Copyright (c) 2022, the SerenityOS developers. 4 * 5 * SPDX-License-Identifier: BSD-2-Clause 6 */ 7 8#include <LibGUI/Action.h> 9#include <LibGUI/Clipboard.h> 10#include <LibGUI/Event.h> 11#include <LibGUI/LinkLabel.h> 12#include <LibGUI/Menu.h> 13#include <LibGUI/Painter.h> 14#include <LibGUI/Window.h> 15#include <LibGfx/Font/Font.h> 16#include <LibGfx/Palette.h> 17 18REGISTER_WIDGET(GUI, LinkLabel) 19 20namespace GUI { 21 22LinkLabel::LinkLabel(DeprecatedString text) 23 : Label(move(text)) 24{ 25 set_foreground_role(Gfx::ColorRole::Link); 26 set_focus_policy(FocusPolicy::TabFocus); 27 setup_actions(); 28} 29 30void LinkLabel::setup_actions() 31{ 32 m_open_action = GUI::Action::create( 33 "Show in File Manager", Gfx::Bitmap::load_from_file("/res/icons/16x16/app-file-manager.png"sv).release_value_but_fixme_should_propagate_errors(), [&](const GUI::Action&) { 34 if (on_click) 35 on_click(); 36 }, 37 this); 38 39 m_copy_action = CommonActions::make_copy_action([this](auto&) { Clipboard::the().set_plain_text(text()); }, this); 40} 41 42void LinkLabel::set_hovered(bool hover) 43{ 44 if (hover == m_hovered) 45 return; 46 47 m_hovered = hover; 48 set_override_cursor(hover ? Gfx::StandardCursor::Hand : Gfx::StandardCursor::None); 49 update(); 50} 51 52void LinkLabel::mousemove_event(MouseEvent& event) 53{ 54 constexpr int extra_target_width = 3; 55 set_hovered(event.position().x() <= font().width(text()) + extra_target_width); 56} 57 58void LinkLabel::mousedown_event(MouseEvent& event) 59{ 60 if (event.button() != MouseButton::Primary) 61 return; 62 63 Label::mousedown_event(event); 64 if (m_hovered && on_click) { 65 on_click(); 66 } 67} 68 69void LinkLabel::keydown_event(KeyEvent& event) 70{ 71 Label::keydown_event(event); 72 if (event.key() == KeyCode::Key_Return || event.key() == KeyCode::Key_Space) { 73 if (on_click) 74 on_click(); 75 } 76} 77 78void LinkLabel::paint_event(PaintEvent& event) 79{ 80 Label::paint_event(event); 81 GUI::Painter painter(*this); 82 83 if (m_hovered) 84 painter.draw_line({ 0, rect().bottom() }, { static_cast<int>(ceilf(font().width(text()))), rect().bottom() }, palette().link()); 85 86 if (is_focused()) 87 painter.draw_focus_rect(text_rect(), palette().focus_outline()); 88} 89 90void LinkLabel::leave_event(Core::Event& event) 91{ 92 Label::leave_event(event); 93 set_hovered(false); 94} 95 96void LinkLabel::did_change_text() 97{ 98 Label::did_change_text(); 99 update_tooltip_if_needed(); 100} 101 102void LinkLabel::update_tooltip_if_needed() 103{ 104 if (width() < font().width(text())) { 105 set_tooltip(text()); 106 } else { 107 set_tooltip({}); 108 } 109} 110 111void LinkLabel::resize_event(ResizeEvent& event) 112{ 113 Label::resize_event(event); 114 update_tooltip_if_needed(); 115} 116 117void LinkLabel::context_menu_event(ContextMenuEvent& event) 118{ 119 if (!m_context_menu) { 120 m_context_menu = Menu::construct(); 121 m_context_menu->add_action(*m_open_action); 122 m_context_menu->add_separator(); 123 m_context_menu->add_action(*m_copy_action); 124 } 125 m_context_menu->popup(event.screen_position(), m_open_action); 126} 127 128}