mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-04-22 20:45:14 +00:00
LibGUI: Start adding an automatic widget layout system.
My needs are really quite simple, so I'm just going to add what I need as I go along. The first thing I needed was a simple box layout with widgets being able to say whether they prefer fixed or fill for both their vertical and horizontal sizes. I also made a simple GStatusBar so FileManager can show how many bytes worth of files are in the current directory.
This commit is contained in:
parent
2cf1dd5b6f
commit
2def3d8d3f
Notes:
sideshowbarker
2024-07-19 15:48:23 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/2def3d8d3ff
22 changed files with 411 additions and 29 deletions
|
@ -23,7 +23,7 @@ LDFLAGS = -static --strip-debug -melf_i386 -e _start --gc-sections
|
|||
all: $(APP)
|
||||
|
||||
$(APP): $(OBJS)
|
||||
$(LD) -o $(APP) $(LDFLAGS) $(OBJS) ../LibGUI/LibGUI.a ../LibC/LibC.a
|
||||
$(LD) -o $(APP) $(LDFLAGS) $(OBJS) ../../LibGUI/LibGUI.a ../../LibC/LibC.a
|
||||
|
||||
.cpp.o:
|
||||
@echo "CXX $<"; $(CXX) $(CXXFLAGS) -o $@ -c $<
|
||||
|
|
|
@ -53,6 +53,8 @@ void DirectoryView::reload()
|
|||
}
|
||||
m_directories.clear();
|
||||
m_files.clear();
|
||||
|
||||
size_t bytes_in_files = 0;
|
||||
while (auto* de = readdir(dirp)) {
|
||||
Entry entry;
|
||||
entry.name = de->d_name;
|
||||
|
@ -66,10 +68,21 @@ void DirectoryView::reload()
|
|||
entry.mode = st.st_mode;
|
||||
auto& entries = S_ISDIR(st.st_mode) ? m_directories : m_files;
|
||||
entries.append(move(entry));
|
||||
|
||||
if (S_ISREG(entry.mode))
|
||||
bytes_in_files += st.st_size;
|
||||
}
|
||||
closedir(dirp);
|
||||
int excess_height = max(0, (item_count() * item_height()) - height());
|
||||
m_scrollbar->set_range(0, excess_height);
|
||||
|
||||
|
||||
|
||||
set_status_message(String::format("%d item%s (%u byte%s)",
|
||||
item_count(),
|
||||
item_count() != 1 ? "s" : "",
|
||||
bytes_in_files,
|
||||
bytes_in_files != 1 ? "s" : ""));
|
||||
}
|
||||
|
||||
const GraphicsBitmap& DirectoryView::icon_for(const Entry& entry) const
|
||||
|
@ -128,7 +141,7 @@ void DirectoryView::paint_event(GPaintEvent&)
|
|||
Rect icon_rect(horizontal_padding, y, icon_size, item_height());
|
||||
Rect name_rect(icon_rect.right() + horizontal_padding, y, 100, item_height());
|
||||
Rect size_rect(name_rect.right() + horizontal_padding, y, 64, item_height());
|
||||
painter.fill_rect(row_rect(painted_item_index), i % 2 ? Color::LightGray : Color::White);
|
||||
painter.fill_rect(row_rect(painted_item_index), i % 2 ? Color(210, 210, 210) : Color::White);
|
||||
painter.blit_with_alpha(icon_rect.location(), icon_for(entry), { 0, 0, icon_size, icon_size });
|
||||
painter.draw_text(name_rect, entry.name, Painter::TextAlignment::CenterLeft, Color::Black);
|
||||
if (should_show_size_for(entry))
|
||||
|
@ -143,3 +156,9 @@ void DirectoryView::paint_event(GPaintEvent&)
|
|||
unpainted_rect.intersect(rect());
|
||||
painter.fill_rect(unpainted_rect, Color::White);
|
||||
}
|
||||
|
||||
void DirectoryView::set_status_message(String&& message)
|
||||
{
|
||||
if (on_status_message)
|
||||
on_status_message(move(message));
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ public:
|
|||
void reload();
|
||||
|
||||
Function<void(const String&)> on_path_change;
|
||||
Function<void(String)> on_status_message;
|
||||
|
||||
int item_height() const { return 16; }
|
||||
int item_count() const { return m_directories.size() + m_files.size(); }
|
||||
|
@ -24,6 +25,8 @@ private:
|
|||
virtual void resize_event(GResizeEvent&) override;
|
||||
virtual void mousedown_event(GMouseEvent&) override;
|
||||
|
||||
void set_status_message(String&&);
|
||||
|
||||
Rect row_rect(int item_index) const;
|
||||
|
||||
struct Entry {
|
||||
|
|
|
@ -23,7 +23,7 @@ LDFLAGS = -static --strip-debug -melf_i386 -e _start --gc-sections
|
|||
all: $(APP)
|
||||
|
||||
$(APP): $(OBJS)
|
||||
$(LD) -o $(APP) $(LDFLAGS) $(OBJS) ../LibGUI/LibGUI.a ../LibC/LibC.a
|
||||
$(LD) -o $(APP) $(LDFLAGS) $(OBJS) ../../LibGUI/LibGUI.a ../../LibC/LibC.a
|
||||
|
||||
.cpp.o:
|
||||
@echo "CXX $<"; $(CXX) $(CXXFLAGS) -o $@ -c $<
|
||||
|
|
|
@ -1,14 +1,10 @@
|
|||
#include <SharedGraphics/GraphicsBitmap.h>
|
||||
#include <LibGUI/GWindow.h>
|
||||
#include <LibGUI/GWidget.h>
|
||||
#include <LibGUI/GButton.h>
|
||||
#include <LibGUI/GListBox.h>
|
||||
#include <LibGUI/GBoxLayout.h>
|
||||
#include <LibGUI/GEventLoop.h>
|
||||
#include <sys/wait.h>
|
||||
#include <signal.h>
|
||||
#include <LibGUI/GStatusBar.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include "DirectoryView.h"
|
||||
|
||||
static GWindow* make_window();
|
||||
|
@ -33,13 +29,21 @@ GWindow* make_window()
|
|||
auto* widget = new GWidget;
|
||||
window->set_main_widget(widget);
|
||||
|
||||
widget->set_layout(make<GBoxLayout>(Orientation::Vertical));
|
||||
|
||||
auto* directory_view = new DirectoryView(widget);
|
||||
directory_view->set_relative_rect({ 0, 0, 240, 300 });
|
||||
|
||||
auto* statusbar = new GStatusBar(widget);
|
||||
statusbar->set_text("Welcome!");
|
||||
|
||||
directory_view->on_path_change = [window] (const String& new_path) {
|
||||
window->set_title(String::format("FileManager: %s", new_path.characters()));
|
||||
};
|
||||
|
||||
directory_view->on_status_message = [statusbar] (String message) {
|
||||
statusbar->set_text(move(message));
|
||||
};
|
||||
|
||||
directory_view->open("/");
|
||||
|
||||
return window;
|
||||
|
|
|
@ -23,7 +23,7 @@ LDFLAGS = -static --strip-debug -melf_i386 -e _start --gc-sections
|
|||
all: $(APP)
|
||||
|
||||
$(APP): $(OBJS)
|
||||
$(LD) -o $(APP) $(LDFLAGS) $(OBJS) ../LibGUI/LibGUI.a ../LibC/LibC.a
|
||||
$(LD) -o $(APP) $(LDFLAGS) $(OBJS) ../../LibGUI/LibGUI.a ../../LibC/LibC.a
|
||||
|
||||
.cpp.o:
|
||||
@echo "CXX $<"; $(CXX) $(CXXFLAGS) -o $@ -c $<
|
||||
|
|
|
@ -22,7 +22,7 @@ LDFLAGS = -static --strip-debug -melf_i386 -e _start --gc-sections
|
|||
all: $(APP)
|
||||
|
||||
$(APP): $(OBJS)
|
||||
$(LD) -o $(APP) $(LDFLAGS) $(OBJS) ../LibGUI/LibGUI.a ../LibC/LibC.a
|
||||
$(LD) -o $(APP) $(LDFLAGS) $(OBJS) ../../LibGUI/LibGUI.a ../../LibC/LibC.a
|
||||
|
||||
.cpp.o:
|
||||
@echo "CXX $<"; $(CXX) $(CXXFLAGS) -o $@ -c $<
|
||||
|
|
|
@ -23,7 +23,7 @@ LDFLAGS = -static --strip-debug -melf_i386 -e _start --gc-sections
|
|||
all: $(APP)
|
||||
|
||||
$(APP): $(OBJS)
|
||||
$(LD) -o $(APP) $(LDFLAGS) $(OBJS) ../LibC/LibC.a
|
||||
$(LD) -o $(APP) $(LDFLAGS) $(OBJS) ../../LibC/LibC.a
|
||||
|
||||
.cpp.o:
|
||||
@echo "CXX $<"; $(CXX) $(CXXFLAGS) -o $@ -c $<
|
||||
|
|
|
@ -8,16 +8,16 @@ make -C ../LibGUI clean && \
|
|||
make -C ../LibGUI && \
|
||||
make -C ../Userland clean && \
|
||||
make -C ../Userland && \
|
||||
make -C ../Application/Terminal clean && \
|
||||
make -C ../Application/Terminal && \
|
||||
make -C ../Application/FontEditor clean && \
|
||||
make -C ../Application/FontEditor && \
|
||||
make -C ../Application/Clock clean && \
|
||||
make -C ../Application/Clock && \
|
||||
make -C ../Application/Launcher clean && \
|
||||
make -C ../Application/Launcher && \
|
||||
make -C ../Application/FileManager clean && \
|
||||
make -C ../Application/FileManager && \
|
||||
make -C ../Applications/Terminal clean && \
|
||||
make -C ../Applications/Terminal && \
|
||||
make -C ../Applications/FontEditor clean && \
|
||||
make -C ../Applications/FontEditor && \
|
||||
make -C ../Applications/Clock clean && \
|
||||
make -C ../Applications/Clock && \
|
||||
make -C ../Applications/Launcher clean && \
|
||||
make -C ../Applications/Launcher && \
|
||||
make -C ../Applications/FileManager clean && \
|
||||
make -C ../Applications/FileManager && \
|
||||
make clean &&\
|
||||
make && \
|
||||
sudo ./sync.sh
|
||||
|
|
|
@ -38,3 +38,9 @@ epilogue:
|
|||
// Birger's birthday <3
|
||||
return 20150614;
|
||||
}
|
||||
|
||||
extern "C" void __cxa_pure_virtual() NORETURN;
|
||||
extern "C" void __cxa_pure_virtual()
|
||||
{
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
|
89
LibGUI/GBoxLayout.cpp
Normal file
89
LibGUI/GBoxLayout.cpp
Normal file
|
@ -0,0 +1,89 @@
|
|||
#include <LibGUI/GBoxLayout.h>
|
||||
#include <LibGUI/GWidget.h>
|
||||
|
||||
GBoxLayout::GBoxLayout(Orientation orientation)
|
||||
: m_orientation(orientation)
|
||||
{
|
||||
}
|
||||
|
||||
GBoxLayout::~GBoxLayout()
|
||||
{
|
||||
}
|
||||
|
||||
#if 0
|
||||
Size GLayout::compute_preferred_size() const
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
static Size compute_preferred_size(GLayout::Entry& entry)
|
||||
{
|
||||
if (entry.layout)
|
||||
return entry.layout->compute_preferred_size();
|
||||
else {
|
||||
return entry.widget->preferred_size();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void GBoxLayout::run(GWidget& widget)
|
||||
{
|
||||
if (m_entries.is_empty())
|
||||
return;
|
||||
|
||||
Size available_size = widget.size();
|
||||
int number_of_entries_with_fixed_size = 0;
|
||||
|
||||
for (auto& entry : m_entries) {
|
||||
if (entry.widget && entry.widget->size_policy(orientation()) == SizePolicy::Fixed) {
|
||||
available_size -= entry.widget->preferred_size();
|
||||
++number_of_entries_with_fixed_size;
|
||||
}
|
||||
}
|
||||
|
||||
int number_of_entries_with_automatic_size = m_entries.size() - number_of_entries_with_fixed_size;
|
||||
|
||||
dbgprintf("GBoxLayout: available_size=%d, fixed=%d, fill=%d\n", available_size.height(), number_of_entries_with_fixed_size, number_of_entries_with_automatic_size);
|
||||
|
||||
Size automatic_size;
|
||||
|
||||
if (m_orientation == Orientation::Horizontal) {
|
||||
automatic_size.set_width(available_size.width() / number_of_entries_with_automatic_size);
|
||||
automatic_size.set_height(widget.height());
|
||||
} else {
|
||||
automatic_size.set_width(widget.width());
|
||||
automatic_size.set_height(available_size.height() / number_of_entries_with_automatic_size);
|
||||
}
|
||||
|
||||
dbgprintf("GBoxLayout: automatic_size=%s\n", automatic_size.to_string().characters());
|
||||
|
||||
int current_x = 0;
|
||||
int current_y = 0;
|
||||
for (auto& entry : m_entries) {
|
||||
Rect rect(current_x, current_y, 0, 0);
|
||||
if (entry.layout) {
|
||||
// FIXME: Implement recursive layout.
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
ASSERT(entry.widget);
|
||||
if (entry.widget->size_policy(orientation()) == SizePolicy::Fixed) {
|
||||
rect.set_size(automatic_size);
|
||||
if (orientation() == Orientation::Vertical) {
|
||||
rect.set_height(entry.widget->preferred_size().height());
|
||||
} else {
|
||||
rect.set_width(entry.widget->preferred_size().height());
|
||||
}
|
||||
} else {
|
||||
rect.set_size(automatic_size);
|
||||
}
|
||||
|
||||
dbgprintf("GBoxLayout: apply, %s{%p} <- %s\n", entry.widget->class_name(), entry.widget.ptr(), rect.to_string().characters());
|
||||
entry.widget->set_relative_rect(rect);
|
||||
|
||||
if (orientation() == Orientation::Horizontal)
|
||||
current_x += rect.width();
|
||||
else
|
||||
current_y += rect.height();
|
||||
}
|
||||
}
|
18
LibGUI/GBoxLayout.h
Normal file
18
LibGUI/GBoxLayout.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
#pragma once
|
||||
|
||||
#include <LibGUI/GLayout.h>
|
||||
#include <LibGUI/GWidget.h>
|
||||
|
||||
class GBoxLayout final : public GLayout {
|
||||
public:
|
||||
explicit GBoxLayout(Orientation);
|
||||
virtual ~GBoxLayout() override;
|
||||
|
||||
Orientation orientation() const { return m_orientation; }
|
||||
|
||||
virtual void run(GWidget&) override;
|
||||
|
||||
private:
|
||||
Orientation m_orientation;
|
||||
};
|
||||
|
41
LibGUI/GLayout.cpp
Normal file
41
LibGUI/GLayout.cpp
Normal file
|
@ -0,0 +1,41 @@
|
|||
#include <LibGUI/GLayout.h>
|
||||
#include <LibGUI/GWidget.h>
|
||||
|
||||
GLayout::GLayout()
|
||||
{
|
||||
}
|
||||
|
||||
GLayout::~GLayout()
|
||||
{
|
||||
}
|
||||
|
||||
void GLayout::notify_adopted(Badge<GWidget>, GWidget& widget)
|
||||
{
|
||||
if (m_owner.ptr() == &widget)
|
||||
return;
|
||||
m_owner = widget.make_weak_ptr();
|
||||
}
|
||||
|
||||
void GLayout::notify_disowned(Badge<GWidget>, GWidget& widget)
|
||||
{
|
||||
ASSERT(m_owner.ptr() == &widget);
|
||||
m_owner.clear();
|
||||
}
|
||||
|
||||
void GLayout::add_layout(OwnPtr<GLayout>&& layout)
|
||||
{
|
||||
Entry entry;
|
||||
entry.layout = move(layout);
|
||||
m_entries.append(move(entry));
|
||||
if (m_owner)
|
||||
m_owner->notify_layout_changed(Badge<GLayout>());
|
||||
}
|
||||
|
||||
void GLayout::add_widget(GWidget& widget)
|
||||
{
|
||||
Entry entry;
|
||||
entry.widget = widget.make_weak_ptr();
|
||||
m_entries.append(move(entry));
|
||||
if (m_owner)
|
||||
m_owner->notify_layout_changed(Badge<GLayout>());
|
||||
}
|
31
LibGUI/GLayout.h
Normal file
31
LibGUI/GLayout.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
#pragma once
|
||||
|
||||
#include <AK/Badge.h>
|
||||
#include <AK/OwnPtr.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <AK/WeakPtr.h>
|
||||
|
||||
class GWidget;
|
||||
|
||||
class GLayout {
|
||||
public:
|
||||
GLayout();
|
||||
virtual ~GLayout();
|
||||
|
||||
void add_widget(GWidget&);
|
||||
void add_layout(OwnPtr<GLayout>&&);
|
||||
|
||||
virtual void run(GWidget&) = 0;
|
||||
|
||||
void notify_adopted(Badge<GWidget>, GWidget&);
|
||||
void notify_disowned(Badge<GWidget>, GWidget&);
|
||||
|
||||
protected:
|
||||
struct Entry {
|
||||
WeakPtr<GWidget> widget;
|
||||
OwnPtr<GLayout> layout;
|
||||
};
|
||||
WeakPtr<GWidget> m_owner;
|
||||
Vector<Entry> m_entries;
|
||||
};
|
||||
|
35
LibGUI/GStatusBar.cpp
Normal file
35
LibGUI/GStatusBar.cpp
Normal file
|
@ -0,0 +1,35 @@
|
|||
#include <LibGUI/GStatusBar.h>
|
||||
#include <LibGUI/GLabel.h>
|
||||
#include <LibGUI/GBoxLayout.h>
|
||||
#include <SharedGraphics/Painter.h>
|
||||
|
||||
GStatusBar::GStatusBar(GWidget* parent)
|
||||
: GWidget(parent)
|
||||
{
|
||||
set_size_policy(SizePolicy::Fill, SizePolicy::Fixed);
|
||||
set_preferred_size({ 0, 16 });
|
||||
set_layout(make<GBoxLayout>(Orientation::Horizontal));
|
||||
m_label = new GLabel(this);
|
||||
m_label->set_fill_with_background_color(false);
|
||||
}
|
||||
|
||||
GStatusBar::~GStatusBar()
|
||||
{
|
||||
}
|
||||
|
||||
void GStatusBar::set_text(String&& text)
|
||||
{
|
||||
m_label->set_text(move(text));
|
||||
}
|
||||
|
||||
String GStatusBar::text() const
|
||||
{
|
||||
return m_label->text();
|
||||
}
|
||||
|
||||
void GStatusBar::paint_event(GPaintEvent&)
|
||||
{
|
||||
Painter painter(*this);
|
||||
painter.fill_rect({ 0, 1, width(), height() - 1 }, Color::LightGray);
|
||||
painter.draw_line({ 0, 0 }, { width() - 1, 0 }, Color::DarkGray);
|
||||
}
|
20
LibGUI/GStatusBar.h
Normal file
20
LibGUI/GStatusBar.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
#pragma once
|
||||
|
||||
#include <LibGUI/GWidget.h>
|
||||
|
||||
class GLabel;
|
||||
|
||||
class GStatusBar : public GWidget {
|
||||
public:
|
||||
explicit GStatusBar(GWidget* parent);
|
||||
virtual ~GStatusBar() override;
|
||||
|
||||
String text() const;
|
||||
void set_text(String&&);
|
||||
|
||||
private:
|
||||
virtual const char* class_name() const override { return "GStatusBar"; }
|
||||
virtual void paint_event(GPaintEvent&) override;
|
||||
|
||||
GLabel* m_label { nullptr };
|
||||
};
|
|
@ -2,6 +2,7 @@
|
|||
#include "GEvent.h"
|
||||
#include "GEventLoop.h"
|
||||
#include "GWindow.h"
|
||||
#include <LibGUI/GLayout.h>
|
||||
#include <AK/Assertions.h>
|
||||
#include <SharedGraphics/GraphicsBitmap.h>
|
||||
#include <SharedGraphics/Painter.h>
|
||||
|
@ -12,6 +13,9 @@ GWidget::GWidget(GWidget* parent)
|
|||
set_font(nullptr);
|
||||
m_background_color = Color::LightGray;
|
||||
m_foreground_color = Color::Black;
|
||||
|
||||
if (parent && parent->layout())
|
||||
parent->layout()->add_widget(*this);
|
||||
}
|
||||
|
||||
GWidget::~GWidget()
|
||||
|
@ -42,7 +46,7 @@ void GWidget::event(GEvent& event)
|
|||
m_has_pending_paint_event = false;
|
||||
return handle_paint_event(static_cast<GPaintEvent&>(event));
|
||||
case GEvent::Resize:
|
||||
return resize_event(static_cast<GResizeEvent&>(event));
|
||||
return handle_resize_event(static_cast<GResizeEvent&>(event));
|
||||
case GEvent::FocusIn:
|
||||
return focusin_event(event);
|
||||
case GEvent::FocusOut:
|
||||
|
@ -87,6 +91,41 @@ void GWidget::handle_paint_event(GPaintEvent& event)
|
|||
}
|
||||
}
|
||||
|
||||
void GWidget::set_layout(OwnPtr<GLayout>&& layout)
|
||||
{
|
||||
if (m_layout.ptr() == layout.ptr())
|
||||
return;
|
||||
if (m_layout)
|
||||
m_layout->notify_disowned(Badge<GWidget>(), *this);
|
||||
m_layout = move(layout);
|
||||
if (m_layout) {
|
||||
m_layout->notify_adopted(Badge<GWidget>(), *this);
|
||||
do_layout();
|
||||
} else {
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void GWidget::do_layout()
|
||||
{
|
||||
if (!m_layout)
|
||||
return;
|
||||
m_layout->run(*this);
|
||||
update();
|
||||
}
|
||||
|
||||
void GWidget::notify_layout_changed(Badge<GLayout>)
|
||||
{
|
||||
do_layout();
|
||||
}
|
||||
|
||||
void GWidget::handle_resize_event(GResizeEvent& event)
|
||||
{
|
||||
if (layout())
|
||||
do_layout();
|
||||
return resize_event(event);
|
||||
}
|
||||
|
||||
void GWidget::resize_event(GResizeEvent&)
|
||||
{
|
||||
}
|
||||
|
@ -216,3 +255,30 @@ bool GWidget::global_cursor_tracking() const
|
|||
return false;
|
||||
return win->global_cursor_tracking_widget() == this;
|
||||
}
|
||||
|
||||
void GWidget::set_preferred_size(const Size& size)
|
||||
{
|
||||
if (m_preferred_size == size)
|
||||
return;
|
||||
m_preferred_size = size;
|
||||
invalidate_layout();
|
||||
}
|
||||
|
||||
void GWidget::set_size_policy(SizePolicy horizontal_policy, SizePolicy vertical_policy)
|
||||
{
|
||||
if (m_horizontal_size_policy == horizontal_policy && m_vertical_size_policy == vertical_policy)
|
||||
return;
|
||||
m_horizontal_size_policy = horizontal_policy;
|
||||
m_vertical_size_policy = vertical_policy;
|
||||
invalidate_layout();
|
||||
}
|
||||
|
||||
void GWidget::invalidate_layout()
|
||||
{
|
||||
auto* w = window();
|
||||
if (!w)
|
||||
return;
|
||||
if (!w->main_widget())
|
||||
return;
|
||||
w->main_widget()->do_layout();
|
||||
}
|
||||
|
|
|
@ -5,16 +5,32 @@
|
|||
#include <SharedGraphics/Rect.h>
|
||||
#include <SharedGraphics/Color.h>
|
||||
#include <SharedGraphics/Font.h>
|
||||
#include <AK/Badge.h>
|
||||
#include <AK/AKString.h>
|
||||
|
||||
class GraphicsBitmap;
|
||||
class GLayout;
|
||||
class GWindow;
|
||||
|
||||
enum class SizePolicy { Fixed, Fill };
|
||||
enum class Orientation { Horizontal, Vertical };
|
||||
|
||||
class GWidget : public GObject {
|
||||
public:
|
||||
explicit GWidget(GWidget* parent = nullptr);
|
||||
virtual ~GWidget() override;
|
||||
|
||||
GLayout* layout() { return m_layout.ptr(); }
|
||||
void set_layout(OwnPtr<GLayout>&&);
|
||||
|
||||
SizePolicy horizontal_size_policy() const { return m_horizontal_size_policy; }
|
||||
SizePolicy vertical_size_policy() const { return m_vertical_size_policy; }
|
||||
SizePolicy size_policy(Orientation orientation) { return orientation == Orientation::Horizontal ? m_horizontal_size_policy : m_vertical_size_policy; }
|
||||
void set_size_policy(SizePolicy horizontal_policy, SizePolicy vertical_policy);
|
||||
|
||||
Size preferred_size() const { return m_preferred_size; }
|
||||
void set_preferred_size(const Size&);
|
||||
|
||||
virtual void event(GEvent&) override;
|
||||
virtual void paint_event(GPaintEvent&);
|
||||
virtual void resize_event(GResizeEvent&);
|
||||
|
@ -100,16 +116,26 @@ public:
|
|||
void set_global_cursor_tracking(bool);
|
||||
bool global_cursor_tracking() const;
|
||||
|
||||
void notify_layout_changed(Badge<GLayout>);
|
||||
|
||||
private:
|
||||
void handle_paint_event(GPaintEvent&);
|
||||
void handle_resize_event(GResizeEvent&);
|
||||
void do_layout();
|
||||
void invalidate_layout();
|
||||
|
||||
GWindow* m_window { nullptr };
|
||||
OwnPtr<GLayout> m_layout;
|
||||
|
||||
Rect m_relative_rect;
|
||||
Color m_background_color { 0xffffff };
|
||||
Color m_foreground_color { 0x000000 };
|
||||
RetainPtr<Font> m_font;
|
||||
|
||||
SizePolicy m_horizontal_size_policy { SizePolicy::Fill };
|
||||
SizePolicy m_vertical_size_policy { SizePolicy::Fill };
|
||||
Size m_preferred_size;
|
||||
|
||||
bool m_has_pending_paint_event { false };
|
||||
bool m_fill_with_background_color { true };
|
||||
};
|
||||
|
|
|
@ -15,8 +15,11 @@ LIBGUI_OBJS = \
|
|||
GObject.o \
|
||||
GTextBox.o \
|
||||
GScrollBar.o \
|
||||
GStatusBar.o \
|
||||
GWidget.o \
|
||||
GStyle.o \
|
||||
GLayout.o \
|
||||
GBoxLayout.o \
|
||||
GWindow.o
|
||||
|
||||
OBJS = $(SHAREDGRAPHICS_OBJS) $(LIBGUI_OBJS)
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#include <AK/Assertions.h>
|
||||
#include <AK/StdLibExtras.h>
|
||||
|
||||
#ifdef LIBGUI
|
||||
#ifdef USERLAND
|
||||
#include <LibGUI/GWidget.h>
|
||||
#include <LibGUI/GWindow.h>
|
||||
#include <LibC/gui.h>
|
||||
|
@ -20,7 +20,7 @@ Painter::Painter(GraphicsBitmap& bitmap)
|
|||
m_clip_rect = { { 0, 0 }, bitmap.size() };
|
||||
}
|
||||
|
||||
#ifdef LIBGUI
|
||||
#ifdef USERLAND
|
||||
Painter::Painter(GWidget& widget)
|
||||
: m_font(&widget.font())
|
||||
{
|
||||
|
@ -34,9 +34,9 @@ Painter::Painter(GWidget& widget)
|
|||
m_target = GraphicsBitmap::create_wrapper(backing.size, backing.pixels);
|
||||
ASSERT(m_target);
|
||||
m_window = widget.window();
|
||||
m_translation.move_by(widget.relative_position());
|
||||
m_translation.move_by(widget.window_relative_rect().location());
|
||||
// NOTE: m_clip_rect is in Window coordinates since we are painting into its backing store.
|
||||
m_clip_rect = widget.relative_rect();
|
||||
m_clip_rect = widget.window_relative_rect();
|
||||
m_clip_rect.intersect(m_target->rect());
|
||||
|
||||
#ifdef DEBUG_WIDGET_UNDERDRAW
|
||||
|
@ -49,7 +49,7 @@ Painter::Painter(GWidget& widget)
|
|||
|
||||
Painter::~Painter()
|
||||
{
|
||||
#ifdef LIBGUI
|
||||
#ifdef USERLAND
|
||||
m_target = nullptr;
|
||||
int rc = gui_release_window_backing_store(m_backing_store_id);
|
||||
ASSERT(rc == 0);
|
||||
|
|
|
@ -52,6 +52,16 @@ public:
|
|||
return { x() + width() / 2, y() + height() / 2 };
|
||||
}
|
||||
|
||||
void set_location(const Point& location)
|
||||
{
|
||||
m_location = location;
|
||||
}
|
||||
|
||||
void set_size(const Size& size)
|
||||
{
|
||||
m_size = size;
|
||||
}
|
||||
|
||||
void inflate(int w, int h)
|
||||
{
|
||||
set_x(x() - w / 2);
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <AK/AKString.h>
|
||||
|
||||
struct GUI_Size;
|
||||
|
||||
class Size {
|
||||
|
@ -29,8 +31,17 @@ public:
|
|||
return !(*this == other);
|
||||
}
|
||||
|
||||
Size& operator-=(const Size& other)
|
||||
{
|
||||
m_width -= other.m_width;
|
||||
m_height -= other.m_height;
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator GUI_Size() const;
|
||||
|
||||
String to_string() const { return String::format("[%d,%d]", m_width, m_height); }
|
||||
|
||||
private:
|
||||
int m_width { 0 };
|
||||
int m_height { 0 };
|
||||
|
|
Loading…
Add table
Reference in a new issue