AnalogClock.cpp 5.8 KB

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