From 03c576acc54af4527887b8390e2a4dcb6c9b4dc9 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sun, 23 Aug 2020 23:39:27 +0200 Subject: [PATCH] LibGUI+LibGfx: Implement upside-down appearance for bottom-side tabs GUI::TabWidget has long has a TabPosition::Bottom option, but we still rendered the tab buttons the same as TabPosition::Top. This patch implements a custom look for bottom-side tabs. I've done my best to match the look of the top-side ones, but there might be some improvements we can make here. :^) --- Libraries/LibGUI/TabWidget.cpp | 18 ++++--- Libraries/LibGfx/ClassicStylePainter.cpp | 68 +++++++++++++++--------- Libraries/LibGfx/ClassicStylePainter.h | 2 +- Libraries/LibGfx/Painter.h | 1 + Libraries/LibGfx/StylePainter.cpp | 4 +- Libraries/LibGfx/StylePainter.h | 4 +- 6 files changed, 61 insertions(+), 36 deletions(-) diff --git a/Libraries/LibGUI/TabWidget.cpp b/Libraries/LibGUI/TabWidget.cpp index 8426e087a43..ee7d46c952c 100644 --- a/Libraries/LibGUI/TabWidget.cpp +++ b/Libraries/LibGUI/TabWidget.cpp @@ -178,8 +178,8 @@ void TabWidget::paint_event(PaintEvent& event) continue; bool hovered = static_cast(i) == m_hovered_tab_index; auto button_rect = this->button_rect(i); - Gfx::StylePainter::paint_tab_button(painter, button_rect, palette(), false, hovered, m_tabs[i].widget->is_enabled()); - auto text_rect = button_rect.translated(0, 1); + Gfx::StylePainter::paint_tab_button(painter, button_rect, palette(), false, hovered, m_tabs[i].widget->is_enabled(), m_tab_position == TabPosition::Top); + auto text_rect = button_rect.translated(0, m_tab_position == TabPosition::Top ? 1 : 0); paint_tab_icon_if_needed(m_tabs[i].icon, button_rect, text_rect); painter.draw_text(text_rect, m_tabs[i].title, m_text_alignment, palette().button_text(), Gfx::TextElision::Right); } @@ -189,11 +189,17 @@ void TabWidget::paint_event(PaintEvent& event) continue; bool hovered = static_cast(i) == m_hovered_tab_index; auto button_rect = this->button_rect(i); - Gfx::StylePainter::paint_tab_button(painter, button_rect, palette(), true, hovered, m_tabs[i].widget->is_enabled()); - auto text_rect = button_rect.translated(0, 1); + Gfx::StylePainter::paint_tab_button(painter, button_rect, palette(), true, hovered, m_tabs[i].widget->is_enabled(), m_tab_position == TabPosition::Top); + auto text_rect = button_rect.translated(0, m_tab_position == TabPosition::Top ? 1 : 0); paint_tab_icon_if_needed(m_tabs[i].icon, button_rect, text_rect); painter.draw_text(text_rect, m_tabs[i].title, m_text_alignment, palette().button_text(), Gfx::TextElision::Right); - painter.draw_line(button_rect.bottom_left().translated(1, 1), button_rect.bottom_right().translated(-1, 1), palette().button()); + if (m_tab_position == TabPosition::Top) { + painter.draw_line(button_rect.bottom_left().translated(1, 1), button_rect.bottom_right().translated(-1, 1), palette().button()); + } else if (m_tab_position == TabPosition::Bottom) { + painter.set_pixel(button_rect.top_left().translated(0, -1), palette().threed_highlight()); + painter.draw_line(button_rect.top_left().translated(1, -1), button_rect.top_right().translated(-2, -1), palette().button()); + painter.draw_line(button_rect.top_left().translated(1, -2), button_rect.top_right().translated(-2, -2), palette().button()); + } break; } } @@ -226,7 +232,7 @@ Gfx::IntRect TabWidget::button_rect(int index) const } Gfx::IntRect rect { x_offset, 0, m_uniform_tabs ? uniform_tab_width() : m_tabs[index].width(font()), bar_height() }; if (m_tabs[index].widget != m_active_widget) { - rect.move_by(0, 2); + rect.move_by(0, m_tab_position == TabPosition::Top ? 2 : 0); rect.set_height(rect.height() - 2); } else { rect.move_by(-2, 0); diff --git a/Libraries/LibGfx/ClassicStylePainter.cpp b/Libraries/LibGfx/ClassicStylePainter.cpp index 1b35e0e8c35..ef9de466d9f 100644 --- a/Libraries/LibGfx/ClassicStylePainter.cpp +++ b/Libraries/LibGfx/ClassicStylePainter.cpp @@ -25,6 +25,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include #include #include #include @@ -32,7 +33,7 @@ namespace Gfx { -void ClassicStylePainter::paint_tab_button(Painter& painter, const IntRect& rect, const Palette& palette, bool active, bool hovered, bool enabled) +void ClassicStylePainter::paint_tab_button(Painter& painter, const IntRect& rect, const Palette& palette, bool active, bool hovered, bool enabled, bool top) { Color base_color = palette.button(); Color highlight_color2 = palette.threed_highlight(); @@ -45,32 +46,50 @@ void ClassicStylePainter::paint_tab_button(Painter& painter, const IntRect& rect PainterStateSaver saver(painter); painter.translate(rect.location()); - // Base - painter.fill_rect({ 1, 1, rect.width() - 2, rect.height() - 1 }, base_color); + if (top) { + // Base + painter.fill_rect({ 1, 1, rect.width() - 2, rect.height() - 1 }, base_color); - // Top line - painter.draw_line({ 2, 0 }, { rect.width() - 3, 0 }, highlight_color2); + // Top line + painter.draw_line({ 2, 0 }, { rect.width() - 3, 0 }, highlight_color2); - // Left side - painter.draw_line({ 0, 2 }, { 0, rect.height() - 1 }, highlight_color2); - painter.set_pixel({ 1, 1 }, highlight_color2); + // Left side + painter.draw_line({ 0, 2 }, { 0, rect.height() - 1 }, highlight_color2); + painter.set_pixel({ 1, 1 }, highlight_color2); - // Right side - painter.draw_line({ - rect.width() - 1, - 2, - }, - { rect.width() - 1, rect.height() - 1 }, shadow_color2); - painter.draw_line({ - rect.width() - 2, - 2, - }, - { rect.width() - 2, rect.height() - 1 }, shadow_color1); - painter.set_pixel({ - rect.width() - 2, - 1, - }, - shadow_color2); + // Right side + + IntPoint top_right_outer { rect.width() - 1, 2 }; + IntPoint bottom_right_outer { rect.width() - 1, rect.height() - 1 }; + painter.draw_line(top_right_outer, bottom_right_outer, shadow_color2); + + IntPoint top_right_inner { rect.width() - 2, 2 }; + IntPoint bottom_right_inner { rect.width() - 2, rect.height() - 1 }; + painter.draw_line(top_right_inner, bottom_right_inner, shadow_color1); + + painter.set_pixel(rect.width() - 2, 1, shadow_color2); + } else { + // Base + painter.fill_rect({ 0, 0, rect.width() - 1, rect.height() }, base_color); + + // Bottom line + painter.draw_line({ 2, rect.height() - 1 }, { rect.width() - 3, rect.height() - 1 }, shadow_color2); + + // Left side + painter.draw_line({ 0, 0 }, { 0, rect.height() - 3 }, highlight_color2); + painter.set_pixel({ 1, rect.height() - 2 }, highlight_color2); + + // Right side + IntPoint top_right_outer { rect.width() - 1, 0 }; + IntPoint bottom_right_outer { rect.width() - 1, rect.height() - 3 }; + painter.draw_line(top_right_outer, bottom_right_outer, shadow_color2); + + IntPoint top_right_inner { rect.width() - 2, 0 }; + IntPoint bottom_right_inner { rect.width() - 2, rect.height() - 3 }; + painter.draw_line(top_right_inner, bottom_right_inner, shadow_color1); + + painter.set_pixel(rect.width() - 2, rect.height() - 2, shadow_color2); + } } static void paint_button_new(Painter& painter, const IntRect& rect, const Palette& palette, bool pressed, bool checked, bool hovered, bool enabled) @@ -326,5 +345,4 @@ void ClassicStylePainter::paint_radio_button(Painter& painter, const IntRect& re auto& bitmap = circle_bitmap(is_checked, is_being_pressed); painter.blit(rect.location(), bitmap, bitmap.rect()); } - } diff --git a/Libraries/LibGfx/ClassicStylePainter.h b/Libraries/LibGfx/ClassicStylePainter.h index 7cdbf9cd393..6eea5f9a903 100644 --- a/Libraries/LibGfx/ClassicStylePainter.h +++ b/Libraries/LibGfx/ClassicStylePainter.h @@ -36,7 +36,7 @@ namespace Gfx { class ClassicStylePainter : public BaseStylePainter { public: void paint_button(Painter&, const IntRect&, const Palette&, ButtonStyle, bool pressed, bool hovered = false, bool checked = false, bool enabled = true) override; - void paint_tab_button(Painter&, const IntRect&, const Palette&, bool active, bool hovered, bool enabled) override; + void paint_tab_button(Painter&, const IntRect&, const Palette&, bool active, bool hovered, bool enabled, bool top) override; void paint_surface(Painter&, const IntRect&, const Palette&, bool paint_vertical_lines = true, bool paint_top_line = true) override; void paint_frame(Painter&, const IntRect&, const Palette&, FrameShape, FrameShadow, int thickness, bool skip_vertical_lines = false) override; void paint_window_frame(Painter&, const IntRect&, const Palette&) override; diff --git a/Libraries/LibGfx/Painter.h b/Libraries/LibGfx/Painter.h index ee84db265af..1febfd20680 100644 --- a/Libraries/LibGfx/Painter.h +++ b/Libraries/LibGfx/Painter.h @@ -64,6 +64,7 @@ public: void draw_triangle(const IntPoint&, const IntPoint&, const IntPoint&, Color); void draw_ellipse_intersecting(const IntRect&, Color, int thickness = 1); void set_pixel(const IntPoint&, Color); + void set_pixel(int x, int y, Color color) { set_pixel({ x, y }, color); } void draw_line(const IntPoint&, const IntPoint&, Color, int thickness = 1, LineStyle style = LineStyle::Solid); void draw_quadratic_bezier_curve(const IntPoint& control_point, const IntPoint&, const IntPoint&, Color, int thickness = 1, LineStyle style = LineStyle::Solid); void draw_elliptical_arc(const IntPoint& p1, const IntPoint& p2, const IntPoint& center, const FloatPoint& radii, float x_axis_rotation, float theta_1, float theta_delta, Color, int thickness = 1, LineStyle style = LineStyle::Solid); diff --git a/Libraries/LibGfx/StylePainter.cpp b/Libraries/LibGfx/StylePainter.cpp index f73b2204dcb..9625e6f47d5 100644 --- a/Libraries/LibGfx/StylePainter.cpp +++ b/Libraries/LibGfx/StylePainter.cpp @@ -38,9 +38,9 @@ BaseStylePainter& StylePainter::current() return style; } -void StylePainter::paint_tab_button(Painter& painter, const IntRect& rect, const Palette& palette, bool active, bool hovered, bool enabled) +void StylePainter::paint_tab_button(Painter& painter, const IntRect& rect, const Palette& palette, bool active, bool hovered, bool enabled, bool top) { - current().paint_tab_button(painter, rect, palette, active, hovered, enabled); + current().paint_tab_button(painter, rect, palette, active, hovered, enabled, top); } void StylePainter::paint_button(Painter& painter, const IntRect& rect, const Palette& palette, ButtonStyle button_style, bool pressed, bool hovered, bool checked, bool enabled) diff --git a/Libraries/LibGfx/StylePainter.h b/Libraries/LibGfx/StylePainter.h index 56391a1150f..d143f4dd760 100644 --- a/Libraries/LibGfx/StylePainter.h +++ b/Libraries/LibGfx/StylePainter.h @@ -55,7 +55,7 @@ public: virtual ~BaseStylePainter() { } virtual void paint_button(Painter&, const IntRect&, const Palette&, ButtonStyle, bool pressed, bool hovered = false, bool checked = false, bool enabled = true) = 0; - virtual void paint_tab_button(Painter&, const IntRect&, const Palette&, bool active, bool hovered, bool enabled) = 0; + virtual void paint_tab_button(Painter&, const IntRect&, const Palette&, bool active, bool hovered, bool enabled, bool top) = 0; virtual void paint_surface(Painter&, const IntRect&, const Palette&, bool paint_vertical_lines = true, bool paint_top_line = true) = 0; virtual void paint_frame(Painter&, const IntRect&, const Palette&, FrameShape, FrameShadow, int thickness, bool skip_vertical_lines = false) = 0; virtual void paint_window_frame(Painter&, const IntRect&, const Palette&) = 0; @@ -72,7 +72,7 @@ public: // FIXME: These are here for API compatibility, we should probably remove them and move BaseStylePainter into here static void paint_button(Painter&, const IntRect&, const Palette&, ButtonStyle, bool pressed, bool hovered = false, bool checked = false, bool enabled = true); - static void paint_tab_button(Painter&, const IntRect&, const Palette&, bool active, bool hovered, bool enabled); + static void paint_tab_button(Painter&, const IntRect&, const Palette&, bool active, bool hovered, bool enabled, bool top); static void paint_surface(Painter&, const IntRect&, const Palette&, bool paint_vertical_lines = true, bool paint_top_line = true); static void paint_frame(Painter&, const IntRect&, const Palette&, FrameShape, FrameShadow, int thickness, bool skip_vertical_lines = false); static void paint_window_frame(Painter&, const IntRect&, const Palette&);