瀏覽代碼

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. :^)
Andreas Kling 6 年之前
父節點
當前提交
cb296ffede
共有 7 個文件被更改,包括 110 次插入12 次删除
  1. 43 0
      LibGUI/GFrame.cpp
  2. 33 0
      LibGUI/GFrame.h
  3. 15 8
      LibGUI/GLabel.cpp
  4. 3 4
      LibGUI/GLabel.h
  5. 3 0
      LibGUI/GStatusBar.cpp
  6. 12 0
      LibGUI/GTextEditor.cpp
  7. 1 0
      LibGUI/Makefile

+ 43 - 0
LibGUI/GFrame.cpp

@@ -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 - 0
LibGUI/GFrame.h

@@ -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 };
+};

+ 15 - 8
LibGUI/GLabel.cpp

@@ -3,12 +3,12 @@
 #include <SharedGraphics/GraphicsBitmap.h>
 #include <SharedGraphics/GraphicsBitmap.h>
 
 
 GLabel::GLabel(GWidget* parent)
 GLabel::GLabel(GWidget* parent)
-    : GWidget(parent)
+    : GFrame(parent)
 {
 {
 }
 }
 
 
 GLabel::GLabel(const String& text, GWidget* parent)
 GLabel::GLabel(const String& text, GWidget* parent)
-    : GWidget(parent)
+    : GFrame(parent)
     , m_text(text)
     , m_text(text)
 {
 {
 }
 }
@@ -32,21 +32,28 @@ void GLabel::set_text(const String& text)
 
 
 void GLabel::paint_event(GPaintEvent& event)
 void GLabel::paint_event(GPaintEvent& event)
 {
 {
+    GFrame::paint_event(event);
+
     Painter painter(*this);
     Painter painter(*this);
     painter.set_clip_rect(event.rect());
     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_icon) {
         if (m_should_stretch_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 {
         } 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());
             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()
 void GLabel::size_to_fit()

+ 3 - 4
LibGUI/GLabel.h

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

+ 3 - 0
LibGUI/GStatusBar.cpp

@@ -12,6 +12,9 @@ GStatusBar::GStatusBar(GWidget* parent)
     set_layout(make<GBoxLayout>(Orientation::Horizontal));
     set_layout(make<GBoxLayout>(Orientation::Horizontal));
     layout()->set_margins({ 4, 2, 4, 2 });
     layout()->set_margins({ 4, 2, 4, 2 });
     m_label = new GLabel(this);
     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);
     m_label->set_text_alignment(TextAlignment::CenterLeft);
 }
 }
 
 

+ 12 - 0
LibGUI/GTextEditor.cpp

@@ -492,6 +492,11 @@ Rect GTextEditor::cursor_content_rect() const
         return { };
         return { };
     ASSERT(!m_lines.is_empty());
     ASSERT(!m_lines.is_empty());
     ASSERT(m_cursor.column() <= (current_line().length() + 1));
     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() };
     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
 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 {
     return {
         m_horizontal_content_padding,
         m_horizontal_content_padding,
         line_index * line_height(),
         line_index * line_height(),

+ 1 - 0
LibGUI/Makefile

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