Serenity Operating System
at master 150 lines 5.9 kB view raw
1/* 2 * Copyright (c) 2021, Erlend Høier <Erlend@ReasonablePanic.com> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include "AnalogClock.h" 8#include <LibCore/DateTime.h> 9#include <LibGUI/Application.h> 10#include <LibGUI/Window.h> 11#include <LibGfx/Palette.h> 12#include <LibGfx/Path.h> 13 14void AnalogClock::draw_graduations(GUI::Painter& painter, Gfx::IntRect& rect, int x, int y) 15{ 16 rect.set_x(x); 17 rect.set_y(y); 18 19 painter.fill_rect(rect, palette().active_window_border2()); 20 21 painter.draw_line(rect.top_left(), rect.top_right(), palette().threed_highlight()); 22 painter.draw_line(rect.bottom_left(), rect.bottom_right(), palette().active_window_border1().darkened(0.7f)); 23 painter.draw_line(rect.bottom_right(), rect.top_right(), palette().active_window_border1().darkened(0.7f)); 24 painter.draw_line(rect.top_left(), rect.bottom_left(), palette().threed_highlight()); 25} 26 27// To create an even clock face it's necessary to mirror the graduations positions 28void AnalogClock::draw_mirrored_graduations(GUI::Painter& painter, Gfx::IntRect& rect, int x, int y, int rect_center_offset) 29{ 30 auto w = this->rect().center().x() - rect_center_offset; 31 auto h = this->rect().center().y() - rect_center_offset; 32 33 draw_graduations(painter, rect, x + w, y + h); 34 draw_graduations(painter, rect, y + w, x + h); 35 draw_graduations(painter, rect, -x + w, y + h); 36 draw_graduations(painter, rect, -y + w, x + h); 37 draw_graduations(painter, rect, x + w, -y + h); 38 draw_graduations(painter, rect, y + w, -x + h); 39 draw_graduations(painter, rect, -x + w, -y + h); 40 draw_graduations(painter, rect, -y + w, -x + h); 41} 42 43void AnalogClock::draw_face(GUI::Painter& painter) 44{ 45 int x, y; 46 double angle = 2 * M_PI / 60; 47 48 for (int i = 0; i <= 7; ++i) { 49 x = sin(angle * static_cast<double>(i)) * m_clock_face_radius; 50 y = cos(angle * static_cast<double>(i)) * m_clock_face_radius; 51 52 draw_mirrored_graduations(painter, m_small_graduation_square, x, y, 1); 53 54 if (i % 5 == 0) 55 draw_mirrored_graduations(painter, m_big_graduation_square, x, y, 2); 56 } 57} 58 59void AnalogClock::draw_hand(GUI::Painter& painter, double angle, double length, Gfx::Color hand_color) 60{ 61 if (angle >= 2 * M_PI) 62 angle -= 2 * M_PI; 63 64 double cosine = cos(angle); 65 double sine = sin(angle); 66 67 double hand_x = (rect().center().x() + (cosine * length)); 68 double hand_y = (rect().center().y() + (sine * length)); 69 70 Gfx::IntPoint indicator_point(hand_x, hand_y); 71 Gfx::IntPoint tail_point(rect().center().x() + (-cosine * m_hand_tail_length), rect().center().y() + (-sine * m_hand_tail_length)); 72 Gfx::IntPoint right_wing_point(rect().center().x() + (-sine * m_hand_wing_span), rect().center().y() + (cosine * m_hand_wing_span)); 73 Gfx::IntPoint left_wing_point(rect().center().x() + (sine * m_hand_wing_span), rect().center().y() + (-cosine * m_hand_wing_span)); 74 75 Gfx::Path hand_fill; 76 hand_fill.move_to(static_cast<Gfx::FloatPoint>(indicator_point)); 77 hand_fill.line_to(static_cast<Gfx::FloatPoint>(left_wing_point)); 78 hand_fill.line_to(static_cast<Gfx::FloatPoint>(tail_point)); 79 hand_fill.line_to(static_cast<Gfx::FloatPoint>(right_wing_point)); 80 hand_fill.close(); 81 82 painter.fill_path(hand_fill, hand_color, Gfx::Painter::WindingRule::Nonzero); 83 84 // Draw highlight depending on the angle, this creates a subtle 3d effect. 85 // remember the angle value is offset by half pi. 86 if (angle > M_PI_2 - (M_PI / 3) && angle < M_PI + (M_PI / 3)) { 87 painter.draw_line(left_wing_point, indicator_point, hand_color.darkened(0.7f)); 88 painter.draw_line(left_wing_point, tail_point, hand_color.darkened(0.7f)); 89 90 painter.draw_line(right_wing_point, indicator_point, palette().threed_highlight()); 91 painter.draw_line(right_wing_point, tail_point, palette().threed_highlight()); 92 } else { 93 painter.draw_line(right_wing_point, indicator_point, hand_color.darkened(0.7f)); 94 painter.draw_line(right_wing_point, tail_point, hand_color.darkened(0.7f)); 95 96 painter.draw_line(left_wing_point, indicator_point, palette().threed_highlight()); 97 painter.draw_line(left_wing_point, tail_point, palette().threed_highlight()); 98 } 99}; 100 101void AnalogClock::draw_seconds_hand(GUI::Painter& painter, double angle) 102{ 103 double hand_x = (rect().center().x() + (cos(angle)) * (m_clock_face_radius - 10)); 104 double hand_y = (rect().center().y() + (sin(angle)) * (m_clock_face_radius - 10)); 105 106 Gfx::IntPoint indicator_point(hand_x, hand_y); 107 painter.draw_line(rect().center(), indicator_point, palette().base_text()); 108} 109 110void AnalogClock::paint_event(GUI::PaintEvent& event) 111{ 112 GUI::Painter painter(*this); 113 painter.clear_rect(event.rect(), m_show_window_frame ? palette().window() : Gfx::Color::Transparent); 114 115 draw_face(painter); 116 117 auto time = Core::DateTime::now(); 118 auto minute = time.minute() * (2 * M_PI) / 60; 119 auto hour = (minute + (2 * M_PI) * time.hour()) / 12; 120 auto seconds = time.second() * (2 * M_PI) / 60; 121 auto angle_offset = M_PI_2; 122 123 draw_hand(painter, minute - angle_offset, m_minute_hand_length, palette().active_window_border2()); 124 draw_hand(painter, hour - angle_offset, m_hour_hand_length, palette().active_window_border1()); 125 draw_seconds_hand(painter, seconds - angle_offset); 126 127 if (time.hour() == 0) 128 update_title_date(); 129} 130 131void AnalogClock::update_title_date() 132{ 133 window()->set_title(Core::DateTime::now().to_deprecated_string("%Y-%m-%d"sv)); 134} 135 136void AnalogClock::context_menu_event(GUI::ContextMenuEvent& event) 137{ 138 if (on_context_menu_request) 139 on_context_menu_request(event); 140} 141 142void AnalogClock::set_show_window_frame(bool show) 143{ 144 if (show == m_show_window_frame) 145 return; 146 m_show_window_frame = show; 147 auto& w = *window(); 148 w.set_frameless(!m_show_window_frame); 149 w.set_has_alpha_channel(!m_show_window_frame); 150}