Serenity Operating System
at master 176 lines 5.4 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * Copyright (c) 2022, the SerenityOS developers. 4 * 5 * SPDX-License-Identifier: BSD-2-Clause 6 */ 7 8#include <LibGUI/BoxLayout.h> 9#include <LibGUI/Painter.h> 10#include <LibGUI/ResizeCorner.h> 11#include <LibGUI/Statusbar.h> 12#include <LibGUI/Window.h> 13#include <LibGfx/Palette.h> 14#include <LibGfx/StylePainter.h> 15 16REGISTER_WIDGET(GUI, Statusbar) 17 18namespace GUI { 19 20Statusbar::Statusbar(int count) 21{ 22 set_fixed_height(18); 23 set_layout<HorizontalBoxLayout>(0, 2); 24 25 m_corner = add<ResizeCorner>(); 26 set_segment_count(count); 27 28 REGISTER_STRING_PROPERTY("text", text, set_text); 29 REGISTER_INT_PROPERTY("segment_count", segment_count, set_segment_count); 30} 31 32NonnullRefPtr<Statusbar::Segment> Statusbar::create_segment() 33{ 34 auto widget = Segment::construct(); 35 insert_child_before(*widget, *m_corner); 36 return widget; 37} 38 39void Statusbar::child_event(Core::ChildEvent& event) 40{ 41 auto& event_to_forward = event; 42 // To ensure that the ResizeCorner is always the last widget, and thus stays in the corner, 43 // we replace ChildAdded events that do not request specific placement with events that request placement before the corner 44 if (event.type() == Event::ChildAdded && is<Widget>(*event.child()) && !event.insertion_before_child()) { 45 Core::ChildEvent new_event(Event::ChildAdded, *event.child(), m_corner.ptr()); 46 event_to_forward = new_event; 47 } 48 49 return Widget::child_event(event_to_forward); 50} 51 52void Statusbar::set_segment_count(size_t count) 53{ 54 if (count <= 1) 55 count = 1; 56 57 for (auto i = m_segments.size(); i < count; i++) { 58 auto segment = create_segment(); 59 m_segments.append(move(segment)); 60 } 61} 62 63void Statusbar::update_segment(size_t index) 64{ 65 auto& segment = m_segments.at(index); 66 if (segment->mode() == Segment::Mode::Auto) { 67 if (segment->restored_text().is_empty()) 68 segment->set_visible(false); 69 else { 70 constexpr auto horizontal_padding { 10 }; 71 auto width = font().width(segment->restored_text()) + horizontal_padding; 72 segment->set_restored_width(width); 73 segment->set_fixed_width(width); 74 } 75 } else if (segment->mode() == Segment::Mode::Fixed) { 76 if (segment->max_width().is_int()) { 77 segment->set_restored_width(segment->max_width().as_int()); 78 segment->set_fixed_width(segment->max_width()); 79 } 80 } 81 82 if (segment->override_text().is_null()) { 83 for (size_t i = 1; i < m_segments.size(); i++) { 84 if (!text(i).is_empty()) 85 m_segments[i]->set_visible(true); 86 } 87 segment->set_text(String::from_utf8(segment->restored_text()).release_value_but_fixme_should_propagate_errors()); 88 segment->set_frame_shape(Gfx::FrameShape::Panel); 89 if (segment->mode() != Segment::Mode::Proportional) 90 segment->set_fixed_width(segment->restored_width()); 91 } else { 92 for (size_t i = 1; i < m_segments.size(); i++) { 93 if (!m_segments[i]->is_clickable()) 94 m_segments[i]->set_visible(false); 95 } 96 segment->set_text(String::from_utf8(segment->override_text()).release_value_but_fixme_should_propagate_errors()); 97 segment->set_frame_shape(Gfx::FrameShape::NoFrame); 98 if (segment->mode() != Segment::Mode::Proportional) 99 segment->set_fixed_width(SpecialDimension::Grow); 100 } 101} 102 103DeprecatedString Statusbar::text(size_t index) const 104{ 105 return m_segments[index]->text().to_deprecated_string(); 106} 107 108void Statusbar::set_text(DeprecatedString text) 109{ 110 set_text(0, move(text)); 111} 112 113void Statusbar::set_text(size_t index, DeprecatedString text) 114{ 115 m_segments[index]->m_restored_text = move(text); 116 update_segment(index); 117} 118 119void Statusbar::set_override_text(DeprecatedString override_text) 120{ 121 m_segments[0]->m_override_text = move(override_text); 122 update_segment(0); 123} 124 125void Statusbar::paint_event(PaintEvent& event) 126{ 127 Painter painter(*this); 128 painter.add_clip_rect(event.rect()); 129 painter.fill_rect(rect(), palette().button()); 130} 131 132void Statusbar::resize_event(ResizeEvent& event) 133{ 134 if (auto* window = this->window()) { 135 m_corner->set_visible(window->is_resizable() && !window->is_maximized()); 136 } 137 138 Widget::resize_event(event); 139} 140 141Statusbar::Segment::Segment() 142{ 143 set_fixed_height(18); 144 set_focus_policy(GUI::FocusPolicy::NoFocus); 145 set_button_style(Gfx::ButtonStyle::Tray); 146 set_text_alignment(Gfx::TextAlignment::CenterLeft); 147} 148 149void Statusbar::Segment::paint_event(PaintEvent& event) 150{ 151 Painter painter(*this); 152 painter.add_clip_rect(event.rect()); 153 154 Gfx::StylePainter::current().paint_frame(painter, rect(), palette(), m_shape, Gfx::FrameShadow::Sunken, m_thickness, spans_entire_window_horizontally()); 155 156 if (is_clickable()) 157 Button::paint_event(event); 158 else if (!text().is_empty()) 159 painter.draw_text(rect().shrunken(font().max_glyph_width(), 0), text(), text_alignment(), palette().color(foreground_role()), Gfx::TextElision::Right, Gfx::TextWrapping::DontWrap); 160} 161 162void Statusbar::Segment::mousedown_event(MouseEvent& event) 163{ 164 if (!is_clickable()) 165 return; 166 Button::mousedown_event(event); 167} 168 169void Statusbar::Segment::mouseup_event(MouseEvent& event) 170{ 171 if (!is_clickable()) 172 return; 173 Button::mouseup_event(event); 174} 175 176}