opuntiaOS - an operating system targeting x86 and ARMv7
at master 231 lines 7.5 kB view raw
1/* 2 * Copyright (C) 2020-2022 The opuntiaOS Project Authors. 3 * + Contributed by Nikita Melekhin <nimelehin@gmail.com> 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9#include "WindowFrame.h" 10#include "../../Components/Elements/Button.h" 11#include "../../Managers/WindowManager.h" 12#include "Window.h" 13#include <libg/Font.h> 14#include <libg/ImageLoaders/PNGLoader.h> 15#include <libg/Rect.h> 16#include <utility> 17 18#define CONTROL_PANEL_CLOSE 0x0 19#define CONTROL_PANEL_MAXIMIZE 0x1 20#define CONTROL_PANEL_MINIMIZE 0x2 21 22namespace WinServer::Desktop { 23 24static const uint32_t s_close_button_glyph_data[10] = { 25 0b1100000011, 26 0b1110000111, 27 0b0111001110, 28 0b0011111100, 29 0b0001111000, 30 0b0001111000, 31 0b0011111100, 32 0b0111001110, 33 0b1110000111, 34 0b1100000011, 35}; 36 37static const uint32_t s_maximise_button_glyph_data[10] = { 38 0b1111100000, 39 0b1111000000, 40 0b1110000000, 41 0b1100000000, 42 0b1000000000, 43 0b0000000001, 44 0b0000000011, 45 0b0000000111, 46 0b0000001111, 47 0b0000011111 48}; 49 50static const uint32_t s_minimise_button_glyph_data[10] = { 51 0b0000000000, 52 0b0000000000, 53 0b0000000000, 54 0b0000000000, 55 0b0000000000, 56 0b0000000000, 57 0b0000000000, 58 0b0000000000, 59 0b1111111111, 60 0b1111111111 61}; 62 63WindowFrame::WindowFrame(Window& window) 64 : m_window(window) 65 , m_window_control_buttons() 66 , m_control_panel_buttons() 67{ 68 set_style(StatusBarStyle::StandardLight); 69 70 auto* close = new Button(); 71 close->set_icon(LG::GlyphBitmap(s_close_button_glyph_data, 10, 10)); 72 auto* maximize = new Button(); 73 maximize->set_icon(LG::GlyphBitmap(s_maximise_button_glyph_data, 10, 10)); 74 auto* minimize = new Button(); 75 minimize->set_icon(LG::GlyphBitmap(s_minimise_button_glyph_data, 10, 10)); 76 77 close->set_title_color(LG::Color(196, 128, 128)); 78 79 m_window_control_buttons.push_back(close); 80 m_window_control_buttons.push_back(maximize); 81 m_window_control_buttons.push_back(minimize); 82} 83 84WindowFrame::WindowFrame(Window& window, std::vector<Button*>&& control_panel_buttons, std::vector<Button*>&& window_control_buttons) 85 : m_window(window) 86 , m_window_control_buttons(std::move(window_control_buttons)) 87 , m_control_panel_buttons(std::move(control_panel_buttons)) 88{ 89} 90 91void WindowFrame::on_set_app_title() 92{ 93 m_app_title_width = Helpers::text_width(m_window.app_title(), LG::Font::system_font()); 94 if (style().show_text()) { 95 WinServer::Compositor::the().invalidate(bounds()); 96 } 97} 98 99void WindowFrame::add_control(const std::string& title) 100{ 101 auto* new_control = new Button(); 102 new_control->set_title(title); 103 m_control_panel_buttons.push_back(new_control); 104 WinServer::Compositor::the().invalidate(bounds()); 105} 106 107void WindowFrame::draw(LG::Context& ctx) 108{ 109 if (!visible()) { 110 return; 111 } 112 int x = m_window.bounds().min_x(); 113 int y = m_window.bounds().min_y(); 114 size_t width = m_window.bounds().width(); 115 size_t height = m_window.bounds().height(); 116 117 int left_x = x + left_border_size(); 118 int right_x = x + width - right_border_size(); 119 int bottom_y = y + height - bottom_border_size(); 120 121 // Drawing frame and shadings 122 int shadow_spread = LG::Shading::SystemSpread; 123 ctx.set_fill_color(style().color()); 124 ctx.fill_rounded(LG::Rect(x + left_border_size(), y + std_top_border_frame_size(), width - 2 * left_border_size(), top_border_size() - std_top_border_frame_size()), LG::CornerMask(4, true, false)); 125 ctx.set_fill_color(Color::Shadow); 126 const auto shading_rect = LG::Rect(x + left_border_size(), y + std_top_border_frame_size(), width - 2 * left_border_size(), height - std_top_border_frame_size() - std_bottom_border_size()); 127 ctx.draw_box_shading(shading_rect, LG::Shading(LG::Shading::Type::Box, 0, shadow_spread), LG::CornerMask(LG::CornerMask::SystemRadius)); 128 129 // Drawing labels, icons. 130 // Drawing positions are calculated using a start of the frame. 131 ctx.set_fill_color(m_text_colors[(int)active()]); 132 if (style().show_text()) { 133 Helpers::draw_text(ctx, { left_x + spacing(), y + text_y_offset() }, m_window.app_title(), LG::Font::system_font()); 134 } 135 136 int start_controls_offset = m_app_title_width + 2 * spacing(); 137 int start_controls = left_x + start_controls_offset; 138 for (int i = 0; i < m_control_panel_buttons.size(); i++) { 139 m_control_panel_buttons[i]->display(ctx, { start_controls, y + text_y_offset() }); 140 start_controls += spacing() + m_control_panel_buttons[i]->bounds().width(); 141 } 142 143 int start_buttons = right_x - spacing() - m_window_control_buttons[0]->bounds().width(); 144 for (int i = 0; i < m_window_control_buttons.size(); i++) { 145 if (active() && i == 0) { 146 ctx.set_fill_color(m_window_control_buttons[i]->title_color()); 147 } else { 148 ctx.set_fill_color(m_text_colors[(int)active()]); 149 } 150 151 m_window_control_buttons[i]->display(ctx, { start_buttons, y + button_y_offset() }); 152 start_buttons += -spacing() - m_window_control_buttons[i]->bounds().width(); 153 } 154} 155 156void WindowFrame::invalidate(WinServer::Compositor& compositor) const 157{ 158 if (!visible()) { 159 return; 160 } 161 int x = m_window.bounds().min_x(); 162 int y = m_window.bounds().min_y(); 163 size_t width = m_window.bounds().width(); 164 size_t height = m_window.bounds().height(); 165 int right_x = x + width - right_border_size(); 166 int bottom_y = y + height - bottom_border_size(); 167 compositor.invalidate(LG::Rect(x, y, width, top_border_size())); 168 compositor.invalidate(LG::Rect(x, y, left_border_size(), height)); 169 compositor.invalidate(LG::Rect(right_x, y, right_border_size(), height)); 170 compositor.invalidate(LG::Rect(x, bottom_y, width, bottom_border_size())); 171} 172 173void WindowFrame::receive_tap_event(const LG::Point<int>& tap) 174{ 175 // Calculating buttons' positions 176 size_t width = m_window.bounds().width(); 177 int right_x = width - right_border_size(); 178 int start_buttons = right_x - spacing() - m_window_control_buttons[0]->bounds().width(); 179 for (int button_id = 0; button_id < m_window_control_buttons.size(); button_id++) { 180 auto button_frame = m_window_control_buttons[button_id]->bounds(); 181 button_frame.offset_by(start_buttons, button_y_offset()); 182 if (button_frame.contains(tap)) { 183 handle_control_panel_tap(button_id); 184 return; 185 } 186 start_buttons += -spacing() - button_frame.width(); 187 } 188} 189 190const LG::Rect WindowFrame::bounds() const 191{ 192 const auto& bounds = m_window.bounds(); 193 return LG::Rect(bounds.min_x(), bounds.min_y(), bounds.width(), top_border_size()); 194} 195 196void WindowFrame::handle_control_panel_tap(int button_id) 197{ 198 auto& wm = WindowManager::the(); 199 switch (button_id) { 200 case CONTROL_PANEL_CLOSE: 201 wm.close_window(m_window); 202 break; 203 case CONTROL_PANEL_MAXIMIZE: 204 wm.maximize_window(m_window); 205 break; 206 case CONTROL_PANEL_MINIMIZE: 207 wm.minimize_window(m_window); 208 break; 209 default: 210 break; 211 } 212} 213 214void WindowFrame::set_style(StatusBarStyle ts) 215{ 216 m_style = ts; 217 218 if (m_style.dark_text()) { 219 m_text_colors[0] = Color::InactiveText; 220 m_text_colors[1] = LG::Color::DarkSystemText; 221 } else { 222 m_text_colors[0] = Color::InactiveText; 223 m_text_colors[1] = LG::Color::LightSystemText; 224 } 225} 226 227void WindowFrame::on_set_icon() 228{ 229} 230 231} // namespace WinServer