mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-01-24 10:12:25 -05:00
d6a0726302
This resolves #10641.
214 lines
5.2 KiB
C++
214 lines
5.2 KiB
C++
/*
|
|
* Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include <LibGUI/Painter.h>
|
|
#include <LibGUI/Tray.h>
|
|
#include <LibGfx/Font.h>
|
|
#include <LibGfx/Palette.h>
|
|
#include <LibGfx/StylePainter.h>
|
|
|
|
REGISTER_WIDGET(GUI, Tray);
|
|
|
|
namespace GUI {
|
|
|
|
Tray::Tray()
|
|
{
|
|
set_fill_with_background_color(true);
|
|
set_background_role(Gfx::ColorRole::Tray);
|
|
set_focus_policy(GUI::FocusPolicy::TabFocus);
|
|
}
|
|
|
|
Tray::~Tray()
|
|
{
|
|
}
|
|
|
|
Gfx::IntRect Tray::Item::rect(Tray const& tray) const
|
|
{
|
|
static constexpr int item_height = 22;
|
|
return Gfx::IntRect {
|
|
tray.frame_thickness(),
|
|
tray.frame_thickness() + static_cast<int>(index) * item_height,
|
|
tray.frame_inner_rect().width(),
|
|
item_height,
|
|
};
|
|
}
|
|
|
|
size_t Tray::add_item(String text, RefPtr<Gfx::Bitmap> bitmap, String custom_data)
|
|
{
|
|
auto new_index = m_items.size();
|
|
|
|
m_items.append(Item {
|
|
.text = move(text),
|
|
.bitmap = move(bitmap),
|
|
.custom_data = move(custom_data),
|
|
.index = new_index,
|
|
});
|
|
update();
|
|
|
|
return new_index;
|
|
}
|
|
|
|
void Tray::set_item_checked(size_t index, bool checked)
|
|
{
|
|
if (checked) {
|
|
m_checked_item_index = index;
|
|
} else {
|
|
if (m_checked_item_index == index)
|
|
m_checked_item_index = {};
|
|
}
|
|
update();
|
|
}
|
|
|
|
void Tray::paint_event(GUI::PaintEvent& event)
|
|
{
|
|
GUI::Frame::paint_event(event);
|
|
|
|
GUI::Painter painter(*this);
|
|
painter.add_clip_rect(event.rect());
|
|
|
|
for (auto& item : m_items) {
|
|
auto rect = item.rect(*this);
|
|
bool is_pressed = item.index == m_pressed_item_index;
|
|
bool is_hovered = item.index == m_hovered_item_index;
|
|
bool is_checked = item.index == m_checked_item_index;
|
|
Gfx::StylePainter::paint_button(painter, rect, palette(), Gfx::ButtonStyle::Tray, is_pressed && is_hovered, is_hovered, is_checked, is_enabled());
|
|
|
|
Gfx::IntRect icon_rect {
|
|
rect.x() + 4,
|
|
0,
|
|
16,
|
|
16,
|
|
};
|
|
icon_rect.center_vertically_within(rect);
|
|
|
|
Gfx::IntRect text_rect {
|
|
icon_rect.right() + 5,
|
|
rect.y(),
|
|
rect.width(),
|
|
rect.height(),
|
|
};
|
|
text_rect.intersect(rect);
|
|
|
|
if (is_pressed && is_hovered) {
|
|
icon_rect.translate_by(1, 1);
|
|
text_rect.translate_by(1, 1);
|
|
}
|
|
|
|
if (item.bitmap)
|
|
painter.blit(icon_rect.location(), *item.bitmap, item.bitmap->rect());
|
|
|
|
auto const& font = is_checked ? this->font().bold_variant() : this->font();
|
|
painter.draw_text(text_rect, item.text, font, Gfx::TextAlignment::CenterLeft, palette().color(Gfx::ColorRole::TrayText));
|
|
}
|
|
}
|
|
|
|
void Tray::mousemove_event(GUI::MouseEvent& event)
|
|
{
|
|
auto* hovered_item = item_at(event.position());
|
|
if (!hovered_item) {
|
|
if (m_hovered_item_index.has_value())
|
|
update();
|
|
m_hovered_item_index = {};
|
|
return;
|
|
}
|
|
if (m_hovered_item_index != hovered_item->index) {
|
|
m_hovered_item_index = hovered_item->index;
|
|
update();
|
|
}
|
|
}
|
|
|
|
void Tray::mousedown_event(GUI::MouseEvent& event)
|
|
{
|
|
if (event.button() != GUI::MouseButton::Primary)
|
|
return;
|
|
|
|
auto* pressed_item = item_at(event.position());
|
|
if (!pressed_item)
|
|
return;
|
|
|
|
if (m_pressed_item_index != pressed_item->index) {
|
|
m_pressed_item_index = pressed_item->index;
|
|
update();
|
|
}
|
|
}
|
|
|
|
void Tray::mouseup_event(GUI::MouseEvent& event)
|
|
{
|
|
if (event.button() != GUI::MouseButton::Primary)
|
|
return;
|
|
|
|
if (auto* pressed_item = item_at(event.position()); pressed_item && m_pressed_item_index == pressed_item->index) {
|
|
on_item_activation(pressed_item->custom_data);
|
|
}
|
|
|
|
m_pressed_item_index = {};
|
|
update();
|
|
}
|
|
|
|
void Tray::leave_event(Core::Event&)
|
|
{
|
|
m_hovered_item_index = {};
|
|
update();
|
|
}
|
|
|
|
Tray::Item* Tray::item_at(Gfx::IntPoint const& position)
|
|
{
|
|
for (auto& item : m_items) {
|
|
if (item.rect(*this).contains(position))
|
|
return &item;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
void Tray::focusin_event(GUI::FocusEvent&)
|
|
{
|
|
if (m_items.is_empty())
|
|
return;
|
|
m_hovered_item_index = 0;
|
|
update();
|
|
}
|
|
|
|
void Tray::focusout_event(GUI::FocusEvent&)
|
|
{
|
|
if (m_items.is_empty())
|
|
return;
|
|
m_hovered_item_index = {};
|
|
update();
|
|
}
|
|
|
|
void Tray::keydown_event(GUI::KeyEvent& event)
|
|
{
|
|
if (m_items.is_empty() || event.modifiers())
|
|
return Frame::keydown_event(event);
|
|
|
|
if (event.key() == KeyCode::Key_Down) {
|
|
if (!m_hovered_item_index.has_value())
|
|
m_hovered_item_index = 0;
|
|
else
|
|
m_hovered_item_index = (*m_hovered_item_index + 1) % m_items.size();
|
|
update();
|
|
return;
|
|
}
|
|
|
|
if (event.key() == KeyCode::Key_Up) {
|
|
if (!m_hovered_item_index.has_value() || m_hovered_item_index == 0u)
|
|
m_hovered_item_index = m_items.size() - 1;
|
|
else
|
|
m_hovered_item_index = *m_hovered_item_index - 1;
|
|
update();
|
|
return;
|
|
}
|
|
|
|
if (event.key() == KeyCode::Key_Return) {
|
|
if (m_hovered_item_index.has_value())
|
|
on_item_activation(m_items[*m_hovered_item_index].custom_data);
|
|
return;
|
|
}
|
|
|
|
Frame::keydown_event(event);
|
|
}
|
|
|
|
}
|