Bläddra i källkod

ClockSettings+Taskbar: Add settings for taskbar clock format

cflip 3 år sedan
förälder
incheckning
5bb0b6ba7a

+ 3 - 0
Base/home/anon/.config/Taskbar.ini

@@ -1,3 +1,6 @@
+[Clock]
+TimeFormat=%T
+
 [QuickLaunch]
 Browser=Browser.af
 Terminal=Terminal.af

+ 4 - 0
Userland/Applications/ClockSettings/CMakeLists.txt

@@ -5,12 +5,16 @@ serenity_component(
 )
 
 compile_gml(ClockSettingsWidget.gml ClockSettingsWidgetGML.h clock_settings_widget_gml)
+compile_gml(TimeZoneSettingsWidget.gml TimeZoneSettingsWidgetGML.h time_zone_settings_widget_gml)
 
 set(SOURCES
     main.cpp
     ClockSettingsWidget.cpp
     ClockSettingsWidget.h
     ClockSettingsWidgetGML.h
+    TimeZoneSettingsWidget.cpp
+    TimeZoneSettingsWidget.h
+    TimeZoneSettingsWidgetGML.h
 )
 
 serenity_app(ClockSettings ICON app-analog-clock) # FIXME: Create a ClockSettings icon.

+ 25 - 141
Userland/Applications/ClockSettings/ClockSettingsWidget.cpp

@@ -1,165 +1,49 @@
 /*
- * Copyright (c) 2022, Tim Flynn <trflynn89@serenityos.org>
+ * Copyright (c) 2022, cflip <cflip@cflip.net>
  *
  * SPDX-License-Identifier: BSD-2-Clause
  */
 
 #include "ClockSettingsWidget.h"
-#include <AK/Time.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 <LibUnicode/DateTimeFormat.h>
-#include <LibUnicode/Locale.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;
-
-static constexpr auto TIME_ZONE_TEXT_WIDTH = 210;
-static constexpr auto TIME_ZONE_TEXT_HEIGHT = 40;
-static constexpr auto TIME_ZONE_TEXT_PADDING = 5;
-static constexpr auto TIME_ZONE_TEXT_COLOR = Gfx::Color::from_rgb(0xeaf688);
+#include <LibConfig/Client.h>
+#include <LibGUI/RadioButton.h>
+#include <LibGUI/TextBox.h>
 
 ClockSettingsWidget::ClockSettingsWidget()
 {
     load_from_gml(clock_settings_widget_gml);
 
-    static auto time_zones = TimeZone::all_time_zones();
-    m_time_zone = TimeZone::system_time_zone();
-
-    m_time_zone_combo_box = *find_descendant_of_type_named<GUI::ComboBox>("time_zone_input");
-    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();
+    m_24_hour_radio = *find_descendant_of_type_named<GUI::RadioButton>("24hour_radio");
+    auto& twelve_hour_radio = *find_descendant_of_type_named<GUI::RadioButton>("12hour_radio");
+    auto& custom_radio = *find_descendant_of_type_named<GUI::RadioButton>("custom_radio");
+    custom_radio.set_checked(true);
 
-    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());
+    m_custom_format_input = *find_descendant_of_type_named<GUI::TextBox>("custom_format_input");
+    m_custom_format_input->set_text(Config::read_string("Taskbar", "Clock", "TimeFormat"));
 
-    point = m_time_zone_location->to_type<int>().translated(x, y);
-    point.translate_by(0, -TIME_ZONE_TEXT_HEIGHT / 2);
+    m_24_hour_radio->on_checked = [&](bool) {
+        m_custom_format_input->set_enabled(false);
+        m_custom_format_input->set_text("%T");
+    };
 
-    if (point.x() <= (m_time_zone_map->width() / 2))
-        point.translate_by(m_time_zone_marker->width() / 2 + TIME_ZONE_TEXT_PADDING, 0);
-    else
-        point.translate_by(-m_time_zone_marker->width() / 2 - TIME_ZONE_TEXT_PADDING - TIME_ZONE_TEXT_WIDTH, 0);
+    twelve_hour_radio.on_checked = [&](bool) {
+        m_custom_format_input->set_enabled(false);
+        m_custom_format_input->set_text("%I:%M %p");
+    };
 
-    auto text_area = Gfx::IntRect { point.x(), point.y(), TIME_ZONE_TEXT_WIDTH, TIME_ZONE_TEXT_HEIGHT };
-    painter.draw_rect(text_area, palette().active_window_border1());
-
-    text_area.shrink(2, 2);
-    painter.fill_rect(text_area, TIME_ZONE_TEXT_COLOR);
-    painter.draw_text(text_area, m_time_zone_text, Gfx::TextAlignment::Center);
-}
-
-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();
+    custom_radio.on_checked = [&](bool) {
+        m_custom_format_input->set_enabled(true);
+    };
 }
 
 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();
-
-    auto locale = Unicode::default_locale();
-    auto now = AK::Time::now_realtime();
-
-    auto name = Unicode::format_time_zone(locale, m_time_zone, Unicode::CalendarPatternStyle::Long, now);
-    auto offset = Unicode::format_time_zone(locale, m_time_zone, Unicode::CalendarPatternStyle::LongOffset, now);
-
-    m_time_zone_text = String::formatted("{}\n({})", name, offset);
+    Config::write_string("Taskbar", "Clock", "TimeFormat", m_custom_format_input->text());
 }
 
-// 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
+void ClockSettingsWidget::reset_default_values()
 {
-    pid_t child_pid = 0;
-    char const* argv[] = { "/bin/timezone", m_time_zone.characters(), nullptr };
-
-    if ((errno = posix_spawn(&child_pid, "/bin/timezone", nullptr, nullptr, const_cast<char**>(argv), environ))) {
-        perror("posix_spawn");
-        exit(1);
-    }
+    m_24_hour_radio->set_checked(true);
+    Config::write_string("Taskbar", "Clock", "TimeFormat", "%T");
 }

+ 20 - 15
Userland/Applications/ClockSettings/ClockSettingsWidget.gml

@@ -6,37 +6,42 @@
     }
 
     @GUI::GroupBox {
-        title: "Time Zone Settings"
+        title: "Time Format"
+        shrink_to_fit: false
+        fixed_height: 160
         layout: @GUI::VerticalBoxLayout {
             margins: [16, 8, 8]
-            spacing: 16
         }
 
         @GUI::Label {
-            text: "Change the system's time zone used for the clock and other applications."
+            text: "Set the date/time format used by the taskbar clock."
             text_alignment: "TopLeft"
         }
 
         @GUI::Widget {
-            layout: @GUI::HorizontalBoxLayout {
+            shrink_to_fit: true
+            layout: @GUI::VerticalBoxLayout {
                 spacing: 4
             }
 
-            @GUI::Label {
-                text: "Time Zone:"
-                fixed_width: 80
-                name: "time_zone_label"
-                text_alignment: "CenterLeft"
+            @GUI::RadioButton {
+                name: "24hour_radio"
+                text: "24-hour (12:34:56)"
             }
 
-            @GUI::ComboBox {
-                name: "time_zone_input"
+            @GUI::RadioButton {
+                name: "12hour_radio"
+                text: "12-hour (12:34 a.m)"
+            }
+
+            @GUI::RadioButton {
+                name: "custom_radio"
+                text: "Custom:"
             }
-        }
 
-        @GUI::ImageWidget {
-            name: "time_zone_map"
-            auto_resize: true
+            @GUI::TextBox {
+                name: "custom_format_input"
+            }
         }
     }
 }

+ 4 - 17
Userland/Applications/ClockSettings/ClockSettingsWidget.h

@@ -1,17 +1,13 @@
 /*
- * Copyright (c) 2022, Tim Flynn <trflynn89@serenityos.org>
+ * Copyright (c) 2022, cflip <cflip@cflip.net>
  *
  * SPDX-License-Identifier: BSD-2-Clause
  */
 
 #pragma once
 
-#include <AK/Optional.h>
 #include <AK/RefPtr.h>
-#include <AK/String.h>
 #include <LibGUI/SettingsWindow.h>
-#include <LibGUI/TextEditor.h>
-#include <LibGUI/Window.h>
 
 class ClockSettingsWidget final : public GUI::SettingsWindow::Tab {
     C_OBJECT(ClockSettingsWidget)
@@ -19,20 +15,11 @@ 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;
+    RefPtr<GUI::RadioButton> m_24_hour_radio;
+    RefPtr<GUI::TextBox> m_custom_format_input;
 
-    Optional<Gfx::FloatPoint> m_time_zone_location;
-    String m_time_zone_text;
+    String m_date_format;
 };

+ 165 - 0
Userland/Applications/ClockSettings/TimeZoneSettingsWidget.cpp

@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2022, Tim Flynn <trflynn89@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include "TimeZoneSettingsWidget.h"
+#include <AK/Time.h>
+#include <Applications/ClockSettings/TimeZoneSettingsWidgetGML.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 <LibUnicode/DateTimeFormat.h>
+#include <LibUnicode/Locale.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;
+
+static constexpr auto TIME_ZONE_TEXT_WIDTH = 210;
+static constexpr auto TIME_ZONE_TEXT_HEIGHT = 40;
+static constexpr auto TIME_ZONE_TEXT_PADDING = 5;
+static constexpr auto TIME_ZONE_TEXT_COLOR = Gfx::Color::from_rgb(0xeaf688);
+
+TimeZoneSettingsWidget::TimeZoneSettingsWidget()
+{
+    load_from_gml(time_zone_settings_widget_gml);
+
+    static auto time_zones = TimeZone::all_time_zones();
+    m_time_zone = TimeZone::system_time_zone();
+
+    m_time_zone_combo_box = *find_descendant_of_type_named<GUI::ComboBox>("time_zone_input");
+    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 TimeZoneSettingsWidget::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());
+
+    point = m_time_zone_location->to_type<int>().translated(x, y);
+    point.translate_by(0, -TIME_ZONE_TEXT_HEIGHT / 2);
+
+    if (point.x() <= (m_time_zone_map->width() / 2))
+        point.translate_by(m_time_zone_marker->width() / 2 + TIME_ZONE_TEXT_PADDING, 0);
+    else
+        point.translate_by(-m_time_zone_marker->width() / 2 - TIME_ZONE_TEXT_PADDING - TIME_ZONE_TEXT_WIDTH, 0);
+
+    auto text_area = Gfx::IntRect { point.x(), point.y(), TIME_ZONE_TEXT_WIDTH, TIME_ZONE_TEXT_HEIGHT };
+    painter.draw_rect(text_area, palette().active_window_border1());
+
+    text_area.shrink(2, 2);
+    painter.fill_rect(text_area, TIME_ZONE_TEXT_COLOR);
+    painter.draw_text(text_area, m_time_zone_text, Gfx::TextAlignment::Center);
+}
+
+void TimeZoneSettingsWidget::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 TimeZoneSettingsWidget::apply_settings()
+{
+    m_time_zone = m_time_zone_combo_box->text();
+
+    set_time_zone_location();
+    set_time_zone();
+    update();
+}
+
+void TimeZoneSettingsWidget::set_time_zone_location()
+{
+    m_time_zone_location = compute_time_zone_location();
+
+    auto locale = Unicode::default_locale();
+    auto now = AK::Time::now_realtime();
+
+    auto name = Unicode::format_time_zone(locale, m_time_zone, Unicode::CalendarPatternStyle::Long, now);
+    auto offset = Unicode::format_time_zone(locale, m_time_zone, Unicode::CalendarPatternStyle::LongOffset, now);
+
+    m_time_zone_text = String::formatted("{}\n({})", name, offset);
+}
+
+// https://en.wikipedia.org/wiki/Mercator_projection#Derivation
+Optional<Gfx::FloatPoint> TimeZoneSettingsWidget::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 TimeZoneSettingsWidget::set_time_zone() const
+{
+    pid_t child_pid = 0;
+    char const* argv[] = { "/bin/timezone", m_time_zone.characters(), nullptr };
+
+    if ((errno = posix_spawn(&child_pid, "/bin/timezone", nullptr, nullptr, const_cast<char**>(argv), environ))) {
+        perror("posix_spawn");
+        exit(1);
+    }
+}

+ 42 - 0
Userland/Applications/ClockSettings/TimeZoneSettingsWidget.gml

@@ -0,0 +1,42 @@
+@GUI::Frame {
+    fill_with_background_color: true
+    layout: @GUI::VerticalBoxLayout {
+        margins: [10]
+        spacing: 5
+    }
+
+    @GUI::GroupBox {
+        title: "Time Zone Settings"
+        layout: @GUI::VerticalBoxLayout {
+            margins: [16, 8, 8]
+            spacing: 16
+        }
+
+        @GUI::Label {
+            text: "Change the system's time zone used for the clock and other applications."
+            text_alignment: "TopLeft"
+        }
+
+        @GUI::Widget {
+            layout: @GUI::HorizontalBoxLayout {
+                spacing: 4
+            }
+
+            @GUI::Label {
+                text: "Time Zone:"
+                fixed_width: 80
+                name: "time_zone_label"
+                text_alignment: "CenterLeft"
+            }
+
+            @GUI::ComboBox {
+                name: "time_zone_input"
+            }
+        }
+
+        @GUI::ImageWidget {
+            name: "time_zone_map"
+            auto_resize: true
+        }
+    }
+}

+ 38 - 0
Userland/Applications/ClockSettings/TimeZoneSettingsWidget.h

@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2022, Tim Flynn <trflynn89@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/Optional.h>
+#include <AK/RefPtr.h>
+#include <AK/String.h>
+#include <LibGUI/SettingsWindow.h>
+#include <LibGUI/TextEditor.h>
+#include <LibGUI/Window.h>
+
+class TimeZoneSettingsWidget final : public GUI::SettingsWindow::Tab {
+    C_OBJECT(TimeZoneSettingsWidget)
+
+private:
+    TimeZoneSettingsWidget();
+
+    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;
+    String m_time_zone_text;
+};

+ 4 - 0
Userland/Applications/ClockSettings/main.cpp

@@ -5,6 +5,8 @@
  */
 
 #include "ClockSettingsWidget.h"
+#include "TimeZoneSettingsWidget.h"
+#include <LibConfig/Client.h>
 #include <LibCore/System.h>
 #include <LibGUI/Application.h>
 #include <LibGUI/Icon.h>
@@ -17,6 +19,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
 
     auto app = TRY(GUI::Application::try_create(arguments));
 
+    Config::pledge_domain("Taskbar");
     TRY(Core::System::pledge("stdio rpath recvfd sendfd proc exec"));
     TRY(Core::System::unveil("/res", "r"));
     TRY(Core::System::unveil("/bin/timezone", "x"));
@@ -27,6 +30,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"));
+    (void)TRY(window->add_tab<TimeZoneSettingsWidget>("Time Zone"));
     window->set_icon(app_icon.bitmap_for_size(16));
     window->resize(540, 570);
 

+ 10 - 4
Userland/Services/Taskbar/ClockWidget.cpp

@@ -5,6 +5,7 @@
  */
 
 #include "ClockWidget.h"
+#include <LibConfig/Client.h>
 #include <LibCore/Process.h>
 #include <LibGUI/Painter.h>
 #include <LibGUI/SeparatorWidget.h>
@@ -20,9 +21,7 @@ ClockWidget::ClockWidget()
     set_frame_shadow(Gfx::FrameShadow::Sunken);
     set_frame_thickness(1);
 
-    m_time_width = font().width("22:22:22");
-
-    set_fixed_size(m_time_width + 20, 21);
+    update_format(Config::read_string("Taskbar", "Clock", "TimeFormat", "%T"));
 
     m_timer = add<Core::Timer>(1000, [this] {
         static time_t last_update_time;
@@ -159,10 +158,17 @@ ClockWidget::ClockWidget()
     };
 }
 
+void ClockWidget::update_format(String const& format)
+{
+    m_time_format = format;
+    m_time_width = font().width(Core::DateTime::create(122, 2, 22, 22, 22, 22).to_string(format));
+    set_fixed_size(m_time_width + 20, 21);
+}
+
 void ClockWidget::paint_event(GUI::PaintEvent& event)
 {
     GUI::Frame::paint_event(event);
-    auto time_text = Core::DateTime::now().to_string("%T");
+    auto time_text = Core::DateTime::now().to_string(m_time_format);
     GUI::Painter painter(*this);
     painter.add_clip_rect(frame_inner_rect());
 

+ 3 - 0
Userland/Services/Taskbar/ClockWidget.h

@@ -24,6 +24,8 @@ class ClockWidget final : public GUI::Frame {
 public:
     virtual ~ClockWidget() override = default;
 
+    void update_format(String const&);
+
 private:
     ClockWidget();
 
@@ -42,6 +44,7 @@ private:
     void position_calendar_window();
     void jump_to_current_date();
 
+    String m_time_format;
     RefPtr<GUI::Window> m_calendar_window;
     RefPtr<GUI::Calendar> m_calendar;
     RefPtr<GUI::Button> m_next_date;

+ 10 - 1
Userland/Services/Taskbar/TaskbarWindow.cpp

@@ -85,7 +85,7 @@ TaskbarWindow::TaskbarWindow(NonnullRefPtr<GUI::Menu> start_menu)
     m_applet_area_container->set_frame_shape(Gfx::FrameShape::Box);
     m_applet_area_container->set_frame_shadow(Gfx::FrameShadow::Sunken);
 
-    main_widget.add<Taskbar::ClockWidget>();
+    m_clock_widget = main_widget.add<Taskbar::ClockWidget>();
 
     m_show_desktop_button = GUI::Button::construct();
     m_show_desktop_button->set_tooltip("Show Desktop");
@@ -99,6 +99,15 @@ TaskbarWindow::TaskbarWindow(NonnullRefPtr<GUI::Menu> start_menu)
     m_assistant_app_file = Desktop::AppFile::open(af_path);
 }
 
+void TaskbarWindow::config_string_did_change(String const& domain, String const& group, String const& key, String const& value)
+{
+    VERIFY(domain == "Taskbar");
+    if (group == "Clock" && key == "TimeFormat") {
+        m_clock_widget->update_format(value);
+        update_applet_area();
+    }
+}
+
 void TaskbarWindow::show_desktop_button_clicked(unsigned)
 {
     GUI::ConnectionToWindowMangerServer::the().async_toggle_show_desktop();

+ 6 - 1
Userland/Services/Taskbar/TaskbarWindow.h

@@ -6,6 +6,7 @@
 
 #pragma once
 
+#include "ClockWidget.h"
 #include "WindowList.h"
 #include <LibConfig/Listener.h>
 #include <LibDesktop/AppFile.h>
@@ -14,7 +15,8 @@
 #include <LibGfx/ShareableBitmap.h>
 #include <Services/WindowServer/ScreenLayout.h>
 
-class TaskbarWindow final : public GUI::Window {
+class TaskbarWindow final : public GUI::Window
+    , public Config::Listener {
     C_OBJECT(TaskbarWindow);
 
 public:
@@ -23,6 +25,8 @@ public:
     static int taskbar_height() { return 27; }
     static int taskbar_icon_size() { return 16; }
 
+    virtual void config_string_did_change(String const&, String const&, String const&, String const&) override;
+
 private:
     explicit TaskbarWindow(NonnullRefPtr<GUI::Menu> start_menu);
     static void show_desktop_button_clicked(unsigned);
@@ -53,6 +57,7 @@ private:
     RefPtr<GUI::Frame> m_applet_area_container;
     RefPtr<GUI::Button> m_start_button;
     RefPtr<GUI::Button> m_show_desktop_button;
+    RefPtr<Taskbar::ClockWidget> m_clock_widget;
 
     RefPtr<Desktop::AppFile> m_assistant_app_file;