diff options
author | Timothy Flynn <trflynn89@pm.me> | 2022-02-02 14:38:43 -0500 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2022-02-03 16:11:15 +0100 |
commit | 4d2ea773dbcd6f18fac3f91c624c0581d0051fc8 (patch) | |
tree | b1787870c39b340992bbc4849892cb16c600a710 /Userland/Applications | |
parent | 35cacb850a25bcec59dd6936fa74ebd776890674 (diff) | |
download | serenity-4d2ea773dbcd6f18fac3f91c624c0581d0051fc8.zip |
ClockSettings: Display a map to show the current time zone's location
Diffstat (limited to 'Userland/Applications')
4 files changed, 97 insertions, 1 deletions
diff --git a/Userland/Applications/ClockSettings/ClockSettingsWidget.cpp b/Userland/Applications/ClockSettings/ClockSettingsWidget.cpp index b34512ac2c..e65c5d08d7 100644 --- a/Userland/Applications/ClockSettings/ClockSettingsWidget.cpp +++ b/Userland/Applications/ClockSettings/ClockSettingsWidget.cpp @@ -7,14 +7,30 @@ #include "ClockSettingsWidget.h" #include <Applications/ClockSettings/ClockSettingsWidgetGML.h> #include <LibGUI/ComboBox.h> +#include <LibGUI/Event.h> +#include <LibGUI/ImageWidget.h> #include <LibGUI/ItemListModel.h> #include <LibGUI/Label.h> +#include <LibGUI/Layout.h> +#include <LibGUI/Margins.h> +#include <LibGUI/Painter.h> +#include <LibGfx/Palette.h> #include <LibTimeZone/TimeZone.h> +#include <math.h> #include <spawn.h> #include <unistd.h> using StringViewListModel = GUI::ItemListModel<StringView, Span<StringView const>>; +static constexpr auto PI_OVER_180 = M_PIf32 / 180.0f; +static constexpr auto PI_OVER_4 = M_PIf32 / 4.0f; +static constexpr auto TAU = M_PIf32 * 2.0f; + +// The map as stored on disk is a valid Mercadian projected map. But it has quite a bit of dead space that +// we can remove. This makes the map non-Mercadian, so we need to adjust our math based on what we removed. +static constexpr auto TIME_ZONE_MAP_NORTHERN_TRIM = 78; +static constexpr auto TIME_ZONE_MAP_SOUTHERN_TRIM = 50; + ClockSettingsWidget::ClockSettingsWidget() { load_from_gml(clock_settings_widget_gml); @@ -26,19 +42,84 @@ ClockSettingsWidget::ClockSettingsWidget() m_time_zone_combo_box->set_only_allow_values_from_model(true); m_time_zone_combo_box->set_model(*StringViewListModel::create(time_zones)); m_time_zone_combo_box->set_text(m_time_zone); + + auto time_zone_map_bitmap = Gfx::Bitmap::try_load_from_file("/res/graphics/map.png"sv).release_value_but_fixme_should_propagate_errors(); + auto time_zone_rect = time_zone_map_bitmap->rect().shrunken(TIME_ZONE_MAP_NORTHERN_TRIM, 0, TIME_ZONE_MAP_SOUTHERN_TRIM, 0); + time_zone_map_bitmap = time_zone_map_bitmap->cropped(time_zone_rect).release_value_but_fixme_should_propagate_errors(); + + m_time_zone_map = *find_descendant_of_type_named<GUI::ImageWidget>("time_zone_map"); + m_time_zone_map->set_bitmap(time_zone_map_bitmap); + + auto time_zone_marker = Gfx::Bitmap::try_load_from_file("/res/icons/32x32/ladyball.png").release_value_but_fixme_should_propagate_errors(); + m_time_zone_marker = time_zone_marker->scaled(0.75f, 0.75f).release_value_but_fixme_should_propagate_errors(); + + set_time_zone_location(); +} + +void ClockSettingsWidget::second_paint_event(GUI::PaintEvent& event) +{ + GUI::Widget::second_paint_event(event); + + if (!m_time_zone_location.has_value()) + return; + + GUI::Painter painter(*this); + painter.add_clip_rect(event.rect()); + painter.add_clip_rect(m_time_zone_map->relative_rect()); + + auto x = m_time_zone_map->x() + m_time_zone_map->parent_widget()->layout()->margins().left(); + auto y = m_time_zone_map->y() + m_time_zone_map->parent_widget()->layout()->margins().top(); + + auto point = m_time_zone_location->to_type<int>().translated(x, y); + point.translate_by(-m_time_zone_marker->width() / 2, -m_time_zone_marker->height() / 2); + painter.blit(point, *m_time_zone_marker, rect()); } void ClockSettingsWidget::reset_default_values() { m_time_zone = "UTC"sv; m_time_zone_combo_box->set_text(m_time_zone); + m_time_zone_location.clear(); + set_time_zone(); + update(); } void ClockSettingsWidget::apply_settings() { m_time_zone = m_time_zone_combo_box->text(); + + set_time_zone_location(); set_time_zone(); + update(); +} + +void ClockSettingsWidget::set_time_zone_location() +{ + m_time_zone_location = compute_time_zone_location(); +} + +// https://en.wikipedia.org/wiki/Mercator_projection#Derivation +Optional<Gfx::FloatPoint> ClockSettingsWidget::compute_time_zone_location() const +{ + auto location = TimeZone::get_time_zone_location(m_time_zone); + if (!location.has_value()) + return {}; + + auto latitude = location->latitude.decimal_coordinate(); + auto longitude = location->longitude.decimal_coordinate(); + + auto rect = m_time_zone_map->bitmap()->rect().to_type<float>(); + + latitude = logf(tanf(PI_OVER_4 + (latitude * PI_OVER_180 / 2.0f))); + + auto mercadian_x = (longitude + 180.0f) * (rect.width() / 360.0f); + auto mercadian_y = (rect.height() / 2.0f) - (rect.width() * latitude / TAU); + + mercadian_y -= TIME_ZONE_MAP_NORTHERN_TRIM / 2; + mercadian_y += TIME_ZONE_MAP_SOUTHERN_TRIM / 2; + + return Gfx::FloatPoint { mercadian_x, mercadian_y }; } void ClockSettingsWidget::set_time_zone() const diff --git a/Userland/Applications/ClockSettings/ClockSettingsWidget.gml b/Userland/Applications/ClockSettings/ClockSettingsWidget.gml index 3772d49899..1c4c5aa790 100644 --- a/Userland/Applications/ClockSettings/ClockSettingsWidget.gml +++ b/Userland/Applications/ClockSettings/ClockSettingsWidget.gml @@ -8,7 +8,6 @@ @GUI::GroupBox { title: "Time Zone Settings" - fixed_height: 120 layout: @GUI::VerticalBoxLayout { margins: [16, 8, 8] @@ -36,5 +35,10 @@ name: "time_zone_input" } } + + @GUI::ImageWidget { + name: "time_zone_map" + auto_resize: true + } } } diff --git a/Userland/Applications/ClockSettings/ClockSettingsWidget.h b/Userland/Applications/ClockSettings/ClockSettingsWidget.h index 623890e1b7..0605a0dbf8 100644 --- a/Userland/Applications/ClockSettings/ClockSettingsWidget.h +++ b/Userland/Applications/ClockSettings/ClockSettingsWidget.h @@ -6,6 +6,7 @@ #pragma once +#include <AK/Optional.h> #include <AK/RefPtr.h> #include <AK/String.h> #include <LibGUI/SettingsWindow.h> @@ -18,10 +19,19 @@ class ClockSettingsWidget final : public GUI::SettingsWindow::Tab { private: ClockSettingsWidget(); + virtual void second_paint_event(GUI::PaintEvent&) override; + virtual void apply_settings() override; virtual void reset_default_values() override; + + void set_time_zone_location(); + Optional<Gfx::FloatPoint> compute_time_zone_location() const; void set_time_zone() const; String m_time_zone; RefPtr<GUI::ComboBox> m_time_zone_combo_box; + RefPtr<GUI::ImageWidget> m_time_zone_map; + RefPtr<Gfx::Bitmap> m_time_zone_marker; + + Optional<Gfx::FloatPoint> m_time_zone_location; }; diff --git a/Userland/Applications/ClockSettings/main.cpp b/Userland/Applications/ClockSettings/main.cpp index 2620ca3740..7463e3547c 100644 --- a/Userland/Applications/ClockSettings/main.cpp +++ b/Userland/Applications/ClockSettings/main.cpp @@ -28,6 +28,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments) auto window = TRY(GUI::SettingsWindow::create("Clock Settings", GUI::SettingsWindow::ShowDefaultsButton::Yes)); (void)TRY(window->add_tab<ClockSettingsWidget>("Clock")); window->set_icon(app_icon.bitmap_for_size(16)); + window->resize(540, 570); window->show(); return app->exec(); |