diff options
author | Andreas Kling <awesomekling@gmail.com> | 2019-07-04 16:16:50 +0200 |
---|---|---|
committer | Andreas Kling <awesomekling@gmail.com> | 2019-07-04 16:16:50 +0200 |
commit | 04b9dc2d30cfc9b383029f6a4b02e2725108b0ae (patch) | |
tree | e117a998173b767f9fd009d49c4f8573d8b85432 /Libraries/LibGUI/GTabWidget.cpp | |
parent | 63814ffebf16291419745cd8ba29a4d2fd888563 (diff) | |
download | serenity-04b9dc2d30cfc9b383029f6a4b02e2725108b0ae.zip |
Libraries: Create top level directory for libraries.
Things were getting a little crowded in the project root, so this patch
moves the Lib*/ directories into Libraries/.
Diffstat (limited to 'Libraries/LibGUI/GTabWidget.cpp')
-rw-r--r-- | Libraries/LibGUI/GTabWidget.cpp | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/Libraries/LibGUI/GTabWidget.cpp b/Libraries/LibGUI/GTabWidget.cpp new file mode 100644 index 0000000000..73b1552d1f --- /dev/null +++ b/Libraries/LibGUI/GTabWidget.cpp @@ -0,0 +1,176 @@ +#include <LibGUI/GBoxLayout.h> +#include <LibGUI/GPainter.h> +#include <LibGUI/GTabWidget.h> +#include <SharedGraphics/StylePainter.h> + +GTabWidget::GTabWidget(GWidget* parent) + : GWidget(parent) +{ + set_fill_with_background_color(true); + set_background_color(Color::WarmGray); +} + +GTabWidget::~GTabWidget() +{ +} + +void GTabWidget::add_widget(const StringView& title, GWidget* widget) +{ + m_tabs.append({ title, widget }); + add_child(*widget); +} + +void GTabWidget::set_active_widget(GWidget* widget) +{ + if (widget == m_active_widget) + return; + + if (m_active_widget) + m_active_widget->set_visible(false); + m_active_widget = widget; + if (m_active_widget) { + m_active_widget->set_relative_rect(child_rect_for_size(size())); + m_active_widget->set_visible(true); + } + + update_bar(); +} + +void GTabWidget::resize_event(GResizeEvent& event) +{ + if (!m_active_widget) + return; + m_active_widget->set_relative_rect(child_rect_for_size(event.size())); +} + +Rect GTabWidget::child_rect_for_size(const Size& size) const +{ + return { { container_padding(), bar_height() + container_padding() }, { size.width() - container_padding() * 2, size.height() - bar_height() - container_padding() * 2 } }; +} + +void GTabWidget::child_event(CChildEvent& event) +{ + if (!event.child() || !is<GWidget>(*event.child())) + return GWidget::child_event(event); + auto& child = to<GWidget>(*event.child()); + if (event.type() == GEvent::ChildAdded) { + if (!m_active_widget) + set_active_widget(&child); + else if (m_active_widget != &child) + child.set_visible(false); + } else if (event.type() == GEvent::ChildRemoved) { + if (m_active_widget == &child) { + GWidget* new_active_widget = nullptr; + for_each_child_widget([&](auto& new_child) { + new_active_widget = &new_child; + return IterationDecision::Break; + }); + set_active_widget(new_active_widget); + } + } + GWidget::child_event(event); +} + +Rect GTabWidget::bar_rect() const +{ + return { 0, 0, width(), bar_height() }; +} + +void GTabWidget::paint_event(GPaintEvent& event) +{ + GPainter painter(*this); + painter.add_clip_rect(event.rect()); + + Rect container_rect { 0, bar_height(), width(), height() - bar_height() }; + auto padding_rect = container_rect; + for (int i = 0; i < container_padding(); ++i) { + painter.draw_rect(padding_rect, background_color()); + padding_rect.shrink(2, 2); + } + + StylePainter::paint_frame(painter, container_rect, FrameShape::Container, FrameShadow::Raised, 2); + + for (int i = 0; i < m_tabs.size(); ++i) { + if (m_tabs[i].widget == m_active_widget) + continue; + bool hovered = i == m_hovered_tab_index; + auto button_rect = this->button_rect(i); + StylePainter::paint_tab_button(painter, button_rect, false, hovered, m_tabs[i].widget->is_enabled()); + painter.draw_text(button_rect.translated(0, 1), m_tabs[i].title, TextAlignment::Center); + } + + for (int i = 0; i < m_tabs.size(); ++i) { + if (m_tabs[i].widget != m_active_widget) + continue; + bool hovered = i == m_hovered_tab_index; + auto button_rect = this->button_rect(i); + StylePainter::paint_tab_button(painter, button_rect, true, hovered, m_tabs[i].widget->is_enabled()); + painter.draw_text(button_rect.translated(0, 1), m_tabs[i].title, TextAlignment::Center); + painter.draw_line(button_rect.bottom_left().translated(1, 1), button_rect.bottom_right().translated(-1, 1), background_color()); + break; + } +} + +Rect GTabWidget::button_rect(int index) const +{ + int x_offset = 2; + for (int i = 0; i < index; ++i) + x_offset += m_tabs[i].width(font()); + Rect rect { x_offset, 0, m_tabs[index].width(font()), bar_height() }; + if (m_tabs[index].widget != m_active_widget) { + rect.move_by(0, 2); + rect.set_height(rect.height() - 2); + } else { + rect.move_by(-2, 0); + rect.set_width(rect.width() + 4); + } + return rect; +} + +int GTabWidget::TabData::width(const Font& font) const +{ + return 16 + font.width(title); +} + +void GTabWidget::mousedown_event(GMouseEvent& event) +{ + for (int i = 0; i < m_tabs.size(); ++i) { + auto button_rect = this->button_rect(i); + if (!button_rect.contains(event.position())) + continue; + set_active_widget(m_tabs[i].widget); + return; + } +} + +void GTabWidget::mousemove_event(GMouseEvent& event) +{ + int hovered_tab = -1; + for (int i = 0; i < m_tabs.size(); ++i) { + auto button_rect = this->button_rect(i); + if (!button_rect.contains(event.position())) + continue; + hovered_tab = i; + if (m_tabs[i].widget == m_active_widget) + break; + } + if (hovered_tab == m_hovered_tab_index) + return; + m_hovered_tab_index = hovered_tab; + update_bar(); +} + +void GTabWidget::leave_event(CEvent&) +{ + if (m_hovered_tab_index != -1) { + m_hovered_tab_index = -1; + update_bar(); + } +} + +void GTabWidget::update_bar() +{ + auto invalidation_rect = bar_rect(); + invalidation_rect.set_height(invalidation_rect.height() + 1); + update(invalidation_rect); +} |