1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 06:18:14 +00:00

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. :^)
This commit is contained in:
Andreas Kling 2019-03-28 15:30:29 +01:00
parent b6c5bd3d28
commit cb296ffede
7 changed files with 110 additions and 12 deletions

43
LibGUI/GFrame.cpp Normal file
View file

@ -0,0 +1,43 @@
#include <LibGUI/GFrame.h>
#include <LibGUI/GStyle.h>
#include <SharedGraphics/Painter.h>
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);
}

33
LibGUI/GFrame.h Normal file
View file

@ -0,0 +1,33 @@
#pragma once
#include <LibGUI/GWidget.h>
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 };
};

View file

@ -3,12 +3,12 @@
#include <SharedGraphics/GraphicsBitmap.h>
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()

View file

@ -1,12 +1,11 @@
#pragma once
#include "GWidget.h"
#include <AK/AKString.h>
#include <SharedGraphics/Painter.h>
#include <LibGUI/GFrame.h>
#include <SharedGraphics/TextAlignment.h>
class GraphicsBitmap;
class GLabel final : public GWidget {
class GLabel final : public GFrame {
public:
explicit GLabel(GWidget* parent);
GLabel(const String& text, GWidget* parent);

View file

@ -12,6 +12,9 @@ GStatusBar::GStatusBar(GWidget* parent)
set_layout(make<GBoxLayout>(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);
}

View file

@ -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(),

View file

@ -52,6 +52,7 @@ LIBGUI_OBJS = \
GItemView.o \
GIcon.o \
GElapsedTimer.o \
GFrame.o \
GWindow.o
OBJS = $(SHAREDGRAPHICS_OBJS) $(LIBGUI_OBJS)