From cb296ffede47d04c80870d1ccbba41efc03e0a8d Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Thu, 28 Mar 2019 15:30:29 +0100 Subject: [PATCH] LibGUI: Add a GFrame class that can be inherited by framey widgets. This will gather the code for painting sunken/raised frames etc in a single place and make it easier add a bit of pleasant shading to UI's. :^) --- LibGUI/GFrame.cpp | 43 ++++++++++++++++++++++++++++++++++++++++++ LibGUI/GFrame.h | 33 ++++++++++++++++++++++++++++++++ LibGUI/GLabel.cpp | 23 ++++++++++++++-------- LibGUI/GLabel.h | 7 +++---- LibGUI/GStatusBar.cpp | 3 +++ LibGUI/GTextEditor.cpp | 12 ++++++++++++ LibGUI/Makefile | 1 + 7 files changed, 110 insertions(+), 12 deletions(-) create mode 100644 LibGUI/GFrame.cpp create mode 100644 LibGUI/GFrame.h diff --git a/LibGUI/GFrame.cpp b/LibGUI/GFrame.cpp new file mode 100644 index 0000000000..d4f0eeed7a --- /dev/null +++ b/LibGUI/GFrame.cpp @@ -0,0 +1,43 @@ +#include +#include +#include + +GFrame::GFrame(GWidget* parent) + : GWidget(parent) +{ +} + +GFrame::~GFrame() +{ +} + +void GFrame::paint_event(GPaintEvent& event) +{ + if (m_shape == Shape::NoFrame) + return; + + Painter painter(*this); + painter.set_clip_rect(event.rect()); + + auto rect = this->rect(); + + Color top_left_color; + Color bottom_right_color; + + if (m_shadow == Shadow::Raised) { + top_left_color = Color::White; + bottom_right_color = Color::MidGray; + } else if (m_shadow == Shadow::Sunken) { + top_left_color = Color::MidGray; + bottom_right_color = Color::White; + } else if (m_shadow == Shadow::Plain) { + top_left_color = Color::MidGray; + bottom_right_color = Color::MidGray; + } + + painter.draw_line(rect.top_left(), rect.top_right(), top_left_color); + painter.draw_line(rect.bottom_left(), rect.bottom_right(), bottom_right_color); + + painter.draw_line(rect.top_left().translated(0, 1), rect.bottom_left().translated(0, -1), top_left_color); + painter.draw_line(rect.top_right(), rect.bottom_right().translated(0, -1), bottom_right_color); +} diff --git a/LibGUI/GFrame.h b/LibGUI/GFrame.h new file mode 100644 index 0000000000..c33b53cbbd --- /dev/null +++ b/LibGUI/GFrame.h @@ -0,0 +1,33 @@ +#pragma once + +#include + +class GFrame : public GWidget { +public: + explicit GFrame(GWidget* parent); + virtual ~GFrame() override; + + enum Shadow { Plain, Raised, Sunken }; + enum Shape { NoFrame, Box, Panel, VerticalLine, HorizontalLine }; + + int frame_thickness() const { return m_thickness; } + void set_frame_thickness(int thickness) { m_thickness = thickness; } + + Shadow frame_shadow() const { return m_shadow; } + void set_frame_shadow(Shadow shadow) { m_shadow = shadow; } + + Shape frame_shape() const { return m_shape; } + void set_frame_shape(Shape shape) { m_shape = shape; } + + Rect frame_inner_rect() const { return rect().shrunken(m_thickness * 2, m_thickness * 2); } + + virtual const char* class_name() const override { return "GFrame"; } + +protected: + void paint_event(GPaintEvent&) override; + +private: + int m_thickness { 0 }; + Shadow m_shadow { Plain }; + Shape m_shape { NoFrame }; +}; diff --git a/LibGUI/GLabel.cpp b/LibGUI/GLabel.cpp index 6b4769dd5e..bb6da3abaf 100644 --- a/LibGUI/GLabel.cpp +++ b/LibGUI/GLabel.cpp @@ -3,12 +3,12 @@ #include GLabel::GLabel(GWidget* parent) - : GWidget(parent) + : GFrame(parent) { } GLabel::GLabel(const String& text, GWidget* parent) - : GWidget(parent) + : GFrame(parent) , m_text(text) { } @@ -32,21 +32,28 @@ void GLabel::set_text(const String& text) void GLabel::paint_event(GPaintEvent& event) { + GFrame::paint_event(event); + Painter painter(*this); painter.set_clip_rect(event.rect()); - if (fill_with_background_color()) - painter.fill_rect({ 0, 0, width(), height() }, background_color()); if (m_icon) { if (m_should_stretch_icon) { - painter.draw_scaled_bitmap(rect(), *m_icon, m_icon->rect()); + painter.draw_scaled_bitmap(frame_inner_rect(), *m_icon, m_icon->rect()); } else { - auto icon_location = rect().center().translated(-(m_icon->width() / 2), -(m_icon->height() / 2)); + auto icon_location = frame_inner_rect().center().translated(-(m_icon->width() / 2), -(m_icon->height() / 2)); painter.blit(icon_location, *m_icon, m_icon->rect()); } } - if (!text().is_empty()) - painter.draw_text({ 0, 0, width(), height() }, text(), m_text_alignment, foreground_color()); + if (!text().is_empty()) { + int indent = 0; + if (frame_thickness() > 0) + indent = font().glyph_width('x') / 2; + auto text_rect = frame_inner_rect(); + text_rect.move_by(indent, 0); + text_rect.set_width(text_rect.width() - indent * 2); + painter.draw_text(text_rect, text(), m_text_alignment, foreground_color()); + } } void GLabel::size_to_fit() diff --git a/LibGUI/GLabel.h b/LibGUI/GLabel.h index bb8c43ddd1..4e62b5c10f 100644 --- a/LibGUI/GLabel.h +++ b/LibGUI/GLabel.h @@ -1,12 +1,11 @@ #pragma once -#include "GWidget.h" -#include -#include +#include +#include class GraphicsBitmap; -class GLabel final : public GWidget { +class GLabel final : public GFrame { public: explicit GLabel(GWidget* parent); GLabel(const String& text, GWidget* parent); diff --git a/LibGUI/GStatusBar.cpp b/LibGUI/GStatusBar.cpp index 982e2d565b..a1d6d7e1bd 100644 --- a/LibGUI/GStatusBar.cpp +++ b/LibGUI/GStatusBar.cpp @@ -12,6 +12,9 @@ GStatusBar::GStatusBar(GWidget* parent) set_layout(make(Orientation::Horizontal)); layout()->set_margins({ 4, 2, 4, 2 }); m_label = new GLabel(this); + m_label->set_frame_shadow(GFrame::Shadow::Sunken); + m_label->set_frame_shape(GFrame::Shape::Panel); + m_label->set_frame_thickness(1); m_label->set_text_alignment(TextAlignment::CenterLeft); } diff --git a/LibGUI/GTextEditor.cpp b/LibGUI/GTextEditor.cpp index b8f0b15cb0..597721e64b 100644 --- a/LibGUI/GTextEditor.cpp +++ b/LibGUI/GTextEditor.cpp @@ -492,6 +492,11 @@ Rect GTextEditor::cursor_content_rect() const return { }; ASSERT(!m_lines.is_empty()); ASSERT(m_cursor.column() <= (current_line().length() + 1)); + if (is_single_line()) { + Rect cursor_rect = { m_horizontal_content_padding + m_cursor.column() * glyph_width(), 0, 1, line_height() }; + cursor_rect.center_vertically_within(rect()); + return cursor_rect; + } return { m_horizontal_content_padding + m_cursor.column() * glyph_width(), m_cursor.line() * line_height(), 1, line_height() }; } @@ -518,6 +523,13 @@ void GTextEditor::scroll_cursor_into_view() Rect GTextEditor::line_content_rect(int line_index) const { + if (is_single_line()) { + Rect line_rect = { m_horizontal_content_padding, 0, content_width(), font().glyph_height() }; + line_rect.center_vertically_within(rect()); + // FIXME: This would not be necessary if we knew more about the font and could center it based on baseline and x-height. + line_rect.move_by(0, 1); + return line_rect; + } return { m_horizontal_content_padding, line_index * line_height(), diff --git a/LibGUI/Makefile b/LibGUI/Makefile index 72bf1f4c11..d004387557 100644 --- a/LibGUI/Makefile +++ b/LibGUI/Makefile @@ -52,6 +52,7 @@ LIBGUI_OBJS = \ GItemView.o \ GIcon.o \ GElapsedTimer.o \ + GFrame.o \ GWindow.o OBJS = $(SHAREDGRAPHICS_OBJS) $(LIBGUI_OBJS)