LibGUI+Apps: Convert Statusbar Labels to Segments

Segments inherit from Button and let us add clickable widgets
to status bars. This patch also adds proportional, fixed and
autosized modes for segments and lets the status bar consume
all non-clickable segments for override text.
This commit is contained in:
thankyouverycool 2022-02-22 07:20:05 -05:00 committed by Andreas Kling
parent e113e3ccaa
commit 3aa95dd4d5
7 changed files with 159 additions and 80 deletions

View file

@ -57,6 +57,6 @@
@GUI::Statusbar {
name: "statusbar"
label_count: 2
segment_count: 2
}
}

View file

@ -31,6 +31,6 @@
@GUI::Statusbar {
name: "statusbar"
label_count: 5
segment_count: 5
}
}

View file

@ -106,6 +106,6 @@
@GUI::Statusbar {
name: "statusbar"
label_count: 2
segment_count: 3
}
}

View file

@ -10,6 +10,6 @@
@GUI::Statusbar {
name: "statusbar"
label_count: 3
segment_count: 3
}
}

View file

@ -10,6 +10,6 @@
@GUI::Statusbar {
name: "statusbar"
label_count: 3
segment_count: 3
}
}

View file

@ -5,7 +5,6 @@
*/
#include <LibGUI/BoxLayout.h>
#include <LibGUI/Label.h>
#include <LibGUI/Painter.h>
#include <LibGUI/ResizeCorner.h>
#include <LibGUI/Statusbar.h>
@ -17,7 +16,7 @@ REGISTER_WIDGET(GUI, Statusbar)
namespace GUI {
Statusbar::Statusbar(int label_count)
Statusbar::Statusbar(int count)
{
set_fixed_height(18);
set_layout<HorizontalBoxLayout>();
@ -25,26 +24,76 @@ Statusbar::Statusbar(int label_count)
layout()->set_spacing(2);
m_corner = add<ResizeCorner>();
set_label_count(label_count);
set_segment_count(count);
REGISTER_STRING_PROPERTY("text", text, set_text);
REGISTER_INT_PROPERTY("label_count", label_count, set_label_count);
REGISTER_INT_PROPERTY("segment_count", segment_count, set_segment_count);
}
Statusbar::~Statusbar()
{
}
NonnullRefPtr<Label> Statusbar::create_label()
NonnullRefPtr<Statusbar::Segment> Statusbar::create_segment()
{
auto label = Label::construct();
insert_child_before(*label, *m_corner);
label->set_frame_shadow(Gfx::FrameShadow::Sunken);
label->set_frame_shape(Gfx::FrameShape::Panel);
label->set_frame_thickness(1);
label->set_text_alignment(Gfx::TextAlignment::CenterLeft);
label->set_text_wrapping(Gfx::TextWrapping::DontWrap);
return label;
auto widget = Segment::construct();
insert_child_before(*widget, *m_corner);
return widget;
}
void Statusbar::set_segment_count(size_t count)
{
if (count <= 1)
count = 1;
for (auto i = m_segments.size(); i < count; i++) {
auto segment = create_segment();
m_segments.append(move(segment));
}
}
void Statusbar::update_segment(size_t index)
{
auto& segment = m_segments.at(index);
if (segment.mode() == Segment::Mode::Auto) {
if (segment.restored_text().is_empty())
segment.set_visible(false);
else {
constexpr auto horizontal_padding { 10 };
auto width = font().width(segment.restored_text()) + horizontal_padding;
segment.set_restored_width(width);
segment.set_fixed_width(width);
}
} else if (segment.mode() == Segment::Mode::Fixed) {
if (segment.max_width() != -1)
segment.set_restored_width(segment.max_width());
segment.set_fixed_width(segment.max_width());
}
if (segment.override_text().is_null()) {
for (size_t i = 1; i < m_segments.size(); i++) {
if (!text(i).is_empty())
m_segments[i].set_visible(true);
}
segment.set_text(segment.restored_text());
segment.set_frame_shape(Gfx::FrameShape::Panel);
if (segment.mode() != Segment::Mode::Proportional)
segment.set_fixed_width(segment.restored_width());
} else {
for (size_t i = 1; i < m_segments.size(); i++) {
if (!m_segments[i].is_clickable())
m_segments[i].set_visible(false);
}
segment.set_text(segment.override_text());
segment.set_frame_shape(Gfx::FrameShape::NoFrame);
if (segment.mode() != Segment::Mode::Proportional)
segment.set_fixed_width(-1);
}
}
String Statusbar::text(size_t index) const
{
return m_segments.at(index).text();
}
void Statusbar::set_text(String text)
@ -52,60 +101,16 @@ void Statusbar::set_text(String text)
set_text(0, move(text));
}
String Statusbar::text() const
{
return text(0);
}
void Statusbar::set_text(size_t index, String text)
{
m_segments.at(index).text = move(text);
update_label(index);
}
void Statusbar::set_label_count(size_t label_count)
{
if (label_count <= 1)
label_count = 1;
for (auto i = m_segments.size(); i < label_count; i++) {
m_segments.append(Segment {
.label = create_label(),
.text = {},
.override_text = {},
});
}
}
void Statusbar::update_label(size_t index)
{
auto& segment = m_segments.at(index);
if (segment.override_text.is_null()) {
segment.label->set_frame_shadow(Gfx::FrameShadow::Sunken);
segment.label->set_frame_shape(Gfx::FrameShape::Panel);
segment.label->set_text(segment.text);
} else {
segment.label->set_frame_shadow(Gfx::FrameShadow::Plain);
segment.label->set_frame_shape(Gfx::FrameShape::NoFrame);
segment.label->set_text(segment.override_text);
}
}
String Statusbar::text(size_t index) const
{
return m_segments.at(index).label->text();
m_segments.at(index).m_restored_text = move(text);
update_segment(index);
}
void Statusbar::set_override_text(String override_text)
{
set_override_text(0, move(override_text));
}
void Statusbar::set_override_text(size_t index, String override_text)
{
m_segments.at(index).override_text = move(override_text);
update_label(index);
m_segments.at(0).m_override_text = move(override_text);
update_segment(0);
}
void Statusbar::paint_event(PaintEvent& event)
@ -123,4 +128,40 @@ void Statusbar::resize_event(ResizeEvent& event)
Widget::resize_event(event);
}
Statusbar::Segment::Segment()
{
set_fixed_height(18);
set_focus_policy(GUI::FocusPolicy::NoFocus);
set_button_style(Gfx::ButtonStyle::Tray);
set_text_alignment(Gfx::TextAlignment::CenterLeft);
}
void Statusbar::Segment::paint_event(PaintEvent& event)
{
Painter painter(*this);
painter.add_clip_rect(event.rect());
Gfx::StylePainter::current().paint_frame(painter, rect(), palette(), m_shape, Gfx::FrameShadow::Sunken, m_thickness, spans_entire_window_horizontally());
if (is_clickable())
Button::paint_event(event);
else if (!text().is_empty())
painter.draw_text(rect().shrunken(font().max_glyph_width(), 0), text(), text_alignment(), palette().color(foreground_role()), Gfx::TextElision::Right, Gfx::TextWrapping::DontWrap);
}
void Statusbar::Segment::mousedown_event(MouseEvent& event)
{
if (!is_clickable())
return;
Button::mousedown_event(event);
}
void Statusbar::Segment::mouseup_event(MouseEvent& event)
{
if (!is_clickable())
return;
Button::mouseup_event(event);
}
}

View file

@ -6,7 +6,10 @@
#pragma once
#include <LibGUI/Button.h>
#include <LibGUI/Painter.h>
#include <LibGUI/Widget.h>
#include <LibGfx/Palette.h>
namespace GUI {
@ -15,29 +18,64 @@ class Statusbar : public Widget {
public:
virtual ~Statusbar() override;
String text() const;
String text(size_t index) const;
String text(size_t index = 0) const;
void set_text(String);
void set_text(size_t index, String);
void set_override_text(String);
void set_override_text(size_t index, String);
class Segment final : public Button {
C_OBJECT(Segment)
friend class Statusbar;
public:
enum class Mode {
Proportional,
Fixed,
Auto,
};
void set_clickable(bool b) { m_clickable = b; }
bool is_clickable() { return m_clickable; }
void set_mode(Mode mode) { m_mode = mode; }
Mode mode() const { return m_mode; }
protected:
virtual void paint_event(PaintEvent& event) override;
virtual void mousedown_event(MouseEvent& event) override;
virtual void mouseup_event(MouseEvent& event) override;
private:
Segment();
void set_frame_shape(Gfx::FrameShape shape) { m_shape = shape; }
void set_restored_width(int width) { m_restored_width = width; }
int restored_width() const { return m_restored_width; }
String const& override_text() const { return m_override_text; }
String const& restored_text() const { return m_restored_text; }
String m_override_text;
String m_restored_text;
bool m_clickable { false };
int m_restored_width { 0 };
int m_thickness { 1 };
Mode m_mode { Mode::Proportional };
Gfx::FrameShape m_shape { Gfx::FrameShape::Panel };
};
Segment& segment(size_t index) { return m_segments.at(index); }
protected:
explicit Statusbar(int label_count = 1);
explicit Statusbar(int segment_count = 1);
virtual void paint_event(PaintEvent&) override;
virtual void resize_event(ResizeEvent&) override;
private:
size_t label_count() const { return m_segments.size(); }
void set_label_count(size_t label_count);
NonnullRefPtr<Label> create_label();
struct Segment {
NonnullRefPtr<GUI::Label> label;
String text;
String override_text;
};
void update_label(size_t);
Vector<Segment> m_segments;
void set_segment_count(size_t);
size_t segment_count() const { return m_segments.size(); }
void update_segment(size_t);
NonnullRefPtr<Segment> create_segment();
NonnullRefPtrVector<Segment> m_segments;
RefPtr<ResizeCorner> m_corner;
};