diff options
author | Andreas Kling <kling@serenityos.org> | 2021-03-25 22:11:12 +0100 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-03-25 22:14:09 +0100 |
commit | 0668b5beef4a30c2d2e95d46c0059151a9ad2d5f (patch) | |
tree | 1f2f6f7952fa9b02784fa1f30f0aaaafe396e546 /Userland/Services/Taskbar | |
parent | fc84076f1841888b8a89f399dd384191de5a9a7d (diff) | |
download | serenity-0668b5beef4a30c2d2e95d46c0059151a9ad2d5f.zip |
Taskbar: Integrate clock widget into taskbar window
Instead of running the clock widget as a separate menu applet,
let's just draw a clock here in the taskbar window.
Diffstat (limited to 'Userland/Services/Taskbar')
-rw-r--r-- | Userland/Services/Taskbar/CMakeLists.txt | 1 | ||||
-rw-r--r-- | Userland/Services/Taskbar/ClockWidget.cpp | 258 | ||||
-rw-r--r-- | Userland/Services/Taskbar/ClockWidget.h | 72 | ||||
-rw-r--r-- | Userland/Services/Taskbar/TaskbarWindow.cpp | 20 | ||||
-rw-r--r-- | Userland/Services/Taskbar/TaskbarWindow.h | 8 | ||||
-rw-r--r-- | Userland/Services/Taskbar/main.cpp | 4 |
6 files changed, 351 insertions, 12 deletions
diff --git a/Userland/Services/Taskbar/CMakeLists.txt b/Userland/Services/Taskbar/CMakeLists.txt index 83de9ee9c8..3b0d10674e 100644 --- a/Userland/Services/Taskbar/CMakeLists.txt +++ b/Userland/Services/Taskbar/CMakeLists.txt @@ -1,5 +1,6 @@ set(SOURCES main.cpp + ClockWidget.cpp TaskbarButton.cpp TaskbarWindow.cpp WindowList.cpp diff --git a/Userland/Services/Taskbar/ClockWidget.cpp b/Userland/Services/Taskbar/ClockWidget.cpp new file mode 100644 index 0000000000..f9b1de5987 --- /dev/null +++ b/Userland/Services/Taskbar/ClockWidget.cpp @@ -0,0 +1,258 @@ +/* + * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ClockWidget.h" +#include <LibGUI/Painter.h> +#include <LibGUI/Window.h> +#include <LibGfx/FontDatabase.h> +#include <LibGfx/Palette.h> +#include <serenity.h> +#include <spawn.h> + +namespace Taskbar { + +ClockWidget::ClockWidget() +{ + set_frame_shape(Gfx::FrameShape::Box); + set_frame_shadow(Gfx::FrameShadow::Sunken); + set_frame_thickness(1); + + m_time_width = font().width("2222-22-22 22:22:22"); + + set_fixed_size(m_time_width + 8, 22); + + m_timer = add<Core::Timer>(1000, [this] { + static time_t last_update_time; + time_t now = time(nullptr); + if (now != last_update_time) { + tick_clock(); + last_update_time = now; + } + }); + + m_calendar_window = add<GUI::Window>(window()); + m_calendar_window->set_frameless(true); + m_calendar_window->set_resizable(false); + m_calendar_window->set_minimizable(false); + m_calendar_window->on_active_input_change = [this](bool is_active_input) { + if (!is_active_input) + close(); + }; + + auto& root_container = m_calendar_window->set_main_widget<GUI::Label>(); + root_container.set_fill_with_background_color(true); + root_container.set_layout<GUI::VerticalBoxLayout>(); + root_container.layout()->set_margins({ 0, 2, 0, 2 }); + root_container.layout()->set_spacing(0); + root_container.set_frame_thickness(2); + root_container.set_frame_shape(Gfx::FrameShape::Container); + root_container.set_frame_shadow(Gfx::FrameShadow::Raised); + + auto& navigation_container = root_container.add<GUI::Widget>(); + navigation_container.set_fixed_height(24); + navigation_container.set_layout<GUI::HorizontalBoxLayout>(); + navigation_container.layout()->set_margins({ 2, 2, 3, 2 }); + + m_prev_date = navigation_container.add<GUI::Button>(); + m_prev_date->set_button_style(Gfx::ButtonStyle::CoolBar); + m_prev_date->set_fixed_size(24, 24); + m_prev_date->set_icon(Gfx::Bitmap::load_from_file("/res/icons/16x16/go-back.png")); + m_prev_date->on_click = [&](auto) { + unsigned int target_month = m_calendar->selected_month(); + unsigned int target_year = m_calendar->selected_year(); + + if (m_calendar->mode() == GUI::Calendar::Month) { + target_month--; + if (m_calendar->selected_month() <= 1) { + target_month = 12; + target_year--; + } + } else { + target_year--; + } + + m_calendar->update_tiles(target_year, target_month); + m_selected_calendar_button->set_text(m_calendar->selected_calendar_text(GUI::Calendar::LongNames)); + }; + + m_selected_calendar_button = navigation_container.add<GUI::Button>(); + m_selected_calendar_button->set_button_style(Gfx::ButtonStyle::CoolBar); + m_selected_calendar_button->set_fixed_height(24); + m_selected_calendar_button->on_click = [&](auto) { + m_calendar->toggle_mode(); + m_selected_calendar_button->set_text(m_calendar->selected_calendar_text(GUI::Calendar::LongNames)); + }; + + m_next_date = navigation_container.add<GUI::Button>(); + m_next_date->set_button_style(Gfx::ButtonStyle::CoolBar); + m_next_date->set_fixed_size(24, 24); + m_next_date->set_icon(Gfx::Bitmap::load_from_file("/res/icons/16x16/go-forward.png")); + m_next_date->on_click = [&](auto) { + unsigned int target_month = m_calendar->selected_month(); + unsigned int target_year = m_calendar->selected_year(); + + if (m_calendar->mode() == GUI::Calendar::Month) { + target_month++; + if (m_calendar->selected_month() >= 12) { + target_month = 1; + target_year++; + } + } else { + target_year++; + } + + m_calendar->update_tiles(target_year, target_month); + m_selected_calendar_button->set_text(m_calendar->selected_calendar_text(GUI::Calendar::LongNames)); + }; + + auto& divider1_container = root_container.add<GUI::Widget>(); + divider1_container.set_fixed_height(2); + divider1_container.set_layout<GUI::HorizontalBoxLayout>(); + divider1_container.layout()->set_margins({ 2, 0, 3, 0 }); + + auto& divider1 = divider1_container.add<GUI::Frame>(); + divider1.set_fixed_height(2); + divider1.set_frame_shape(Gfx::FrameShape::Panel); + + auto& calendar_frame_container = root_container.add<GUI::Widget>(); + calendar_frame_container.set_layout<GUI::HorizontalBoxLayout>(); + calendar_frame_container.layout()->set_margins({ 4, 4, 5, 4 }); + + auto& calendar_frame = calendar_frame_container.add<GUI::Frame>(); + calendar_frame.set_layout<GUI::VerticalBoxLayout>(); + calendar_frame.layout()->set_margins({ 2, 2, 2, 2 }); + + m_calendar = calendar_frame.add<GUI::Calendar>(Core::DateTime::now()); + m_selected_calendar_button->set_text(m_calendar->selected_calendar_text(GUI::Calendar::LongNames)); + + m_calendar->on_calendar_tile_click = [&] { + m_selected_calendar_button->set_text(m_calendar->selected_calendar_text(GUI::Calendar::LongNames)); + }; + + m_calendar->on_month_tile_click = [&] { + m_selected_calendar_button->set_text(m_calendar->selected_calendar_text(GUI::Calendar::LongNames)); + }; + + auto& divider2_container = root_container.add<GUI::Widget>(); + divider2_container.set_fixed_height(2); + divider2_container.set_layout<GUI::HorizontalBoxLayout>(); + divider2_container.layout()->set_margins({ 2, 0, 3, 0 }); + + auto& divider2 = divider2_container.add<GUI::Frame>(); + divider2.set_fixed_height(2); + divider2.set_frame_shape(Gfx::FrameShape::Panel); + + auto& settings_container = root_container.add<GUI::Widget>(); + settings_container.set_fixed_height(24); + settings_container.set_layout<GUI::HorizontalBoxLayout>(); + settings_container.layout()->set_margins({ 2, 2, 3, 2 }); + settings_container.layout()->add_spacer(); + + m_jump_to_button = settings_container.add<GUI::Button>(); + m_jump_to_button->set_button_style(Gfx::ButtonStyle::CoolBar); + m_jump_to_button->set_fixed_size(24, 24); + m_jump_to_button->set_icon(Gfx::Bitmap::load_from_file("/res/icons/16x16/calendar-date.png")); + m_jump_to_button->set_tooltip("Jump to today"); + m_jump_to_button->on_click = [this](auto) { + jump_to_current_date(); + }; + + m_calendar_launcher = settings_container.add<GUI::Button>(); + m_calendar_launcher->set_button_style(Gfx::ButtonStyle::CoolBar); + m_calendar_launcher->set_fixed_size(24, 24); + m_calendar_launcher->set_icon(Gfx::Bitmap::load_from_file("/res/icons/16x16/app-calendar.png")); + m_calendar_launcher->set_tooltip("Calendar"); + m_calendar_launcher->on_click = [](auto) { + pid_t pid; + const char* argv[] = { "Calendar", nullptr }; + if ((errno = posix_spawn(&pid, "/bin/Calendar", nullptr, nullptr, const_cast<char**>(argv), environ))) { + perror("posix_spawn"); + } else { + if (disown(pid) < 0) + perror("disown"); + } + }; +} + +ClockWidget::~ClockWidget() +{ +} + +void ClockWidget::paint_event(GUI::PaintEvent& event) +{ + GUI::Frame::paint_event(event); + auto time_text = Core::DateTime::now().to_string(); + GUI::Painter painter(*this); + painter.add_clip_rect(frame_inner_rect()); + painter.draw_text(event.rect(), time_text, Gfx::FontDatabase::default_font(), Gfx::TextAlignment::Center, palette().window_text()); +} + +void ClockWidget::mousedown_event(GUI::MouseEvent& event) +{ + if (event.button() != GUI::MouseButton::Left) { + return; + } else { + if (!m_calendar_window->is_visible()) + open(); + else + close(); + } +} + +void ClockWidget::open() +{ + jump_to_current_date(); + // FIXME: We position the calendar twice since we don't know the final size the first time. + // Find a way to not do this. + position_calendar_window(); + m_calendar_window->show(); + position_calendar_window(); +} + +void ClockWidget::close() +{ + m_calendar_window->hide(); +} + +void ClockWidget::position_calendar_window() +{ + m_calendar_window->set_rect( + screen_relative_rect().right() - m_calendar_window->width(), + screen_relative_rect().top() - m_calendar_window->height() - 2, + 153, + 180); +} + +void ClockWidget::jump_to_current_date() +{ + if (m_calendar->mode() == GUI::Calendar::Year) + m_calendar->toggle_mode(); + m_calendar->set_selected_date(Core::DateTime::now()); + m_calendar->update_tiles(Core::DateTime::now().year(), Core::DateTime::now().month()); + m_selected_calendar_button->set_text(m_calendar->selected_calendar_text(GUI::Calendar::LongNames)); +} + +} diff --git a/Userland/Services/Taskbar/ClockWidget.h b/Userland/Services/Taskbar/ClockWidget.h new file mode 100644 index 0000000000..99868bac2a --- /dev/null +++ b/Userland/Services/Taskbar/ClockWidget.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include <LibCore/DateTime.h> +#include <LibCore/Timer.h> +#include <LibGUI/Application.h> +#include <LibGUI/BoxLayout.h> +#include <LibGUI/Button.h> +#include <LibGUI/Calendar.h> +#include <LibGUI/Frame.h> +#include <LibGUI/Label.h> +#include <time.h> + +namespace Taskbar { + +class ClockWidget final : public GUI::Frame { + C_OBJECT(ClockWidget); + +public: + virtual ~ClockWidget() override; + +private: + ClockWidget(); + + virtual void paint_event(GUI::PaintEvent&) override; + virtual void mousedown_event(GUI::MouseEvent&) override; + + void tick_clock() { update(); } + + void open(); + void close(); + + void position_calendar_window(); + void jump_to_current_date(); + + RefPtr<GUI::Window> m_calendar_window; + RefPtr<GUI::Calendar> m_calendar; + RefPtr<GUI::Button> m_next_date; + RefPtr<GUI::Button> m_prev_date; + RefPtr<GUI::Button> m_selected_calendar_button; + RefPtr<GUI::Button> m_jump_to_button; + RefPtr<GUI::Button> m_calendar_launcher; + RefPtr<Core::Timer> m_timer; + int m_time_width { 0 }; +}; + +} diff --git a/Userland/Services/Taskbar/TaskbarWindow.cpp b/Userland/Services/Taskbar/TaskbarWindow.cpp index e1de201504..0f9d80ba32 100644 --- a/Userland/Services/Taskbar/TaskbarWindow.cpp +++ b/Userland/Services/Taskbar/TaskbarWindow.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> + * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,6 +25,7 @@ */ #include "TaskbarWindow.h" +#include "ClockWidget.h" #include "TaskbarButton.h" #include <AK/Debug.h> #include <LibCore/ConfigFile.h> @@ -77,14 +78,19 @@ TaskbarWindow::TaskbarWindow() GUI::Desktop::the().on_rect_change = [this](const Gfx::IntRect& rect) { on_screen_rect_change(rect); }; - auto& widget = set_main_widget<TaskbarWidget>(); - widget.set_layout<GUI::HorizontalBoxLayout>(); - widget.layout()->set_margins({ 3, 2, 3, 2 }); - widget.layout()->set_spacing(3); + auto& main_widget = set_main_widget<TaskbarWidget>(); + main_widget.set_layout<GUI::HorizontalBoxLayout>(); + main_widget.layout()->set_margins({ 3, 2, 3, 2 }); + + create_quick_launch_bar(); + + m_task_button_container = main_widget.add<GUI::Widget>(); + m_task_button_container->set_layout<GUI::HorizontalBoxLayout>(); + m_task_button_container->layout()->set_spacing(3); m_default_icon = Gfx::Bitmap::load_from_file("/res/icons/16x16/window.png"); - create_quick_launch_bar(); + main_widget.add<Taskbar::ClockWidget>(); } TaskbarWindow::~TaskbarWindow() @@ -154,7 +160,7 @@ void TaskbarWindow::on_screen_rect_change(const Gfx::IntRect& rect) NonnullRefPtr<GUI::Button> TaskbarWindow::create_button(const WindowIdentifier& identifier) { - auto& button = main_widget()->add<TaskbarButton>(identifier); + auto& button = m_task_button_container->add<TaskbarButton>(identifier); button.set_min_size(20, 23); button.set_max_size(140, 23); button.set_text_alignment(Gfx::TextAlignment::CenterLeft); diff --git a/Userland/Services/Taskbar/TaskbarWindow.h b/Userland/Services/Taskbar/TaskbarWindow.h index be55a00daf..9e0e73878d 100644 --- a/Userland/Services/Taskbar/TaskbarWindow.h +++ b/Userland/Services/Taskbar/TaskbarWindow.h @@ -31,14 +31,15 @@ #include <LibGUI/Window.h> class TaskbarWindow final : public GUI::Window { - C_OBJECT(TaskbarWindow) + C_OBJECT(TaskbarWindow); + public: - TaskbarWindow(); virtual ~TaskbarWindow() override; - int taskbar_height() const { return 28; } + static int taskbar_height() { return 28; } private: + TaskbarWindow(); void create_quick_launch_bar(); void on_screen_rect_change(const Gfx::IntRect&); NonnullRefPtr<GUI::Button> create_button(const WindowIdentifier&); @@ -49,5 +50,6 @@ private: virtual void wm_event(GUI::WMEvent&) override; + RefPtr<GUI::Widget> m_task_button_container; RefPtr<Gfx::Bitmap> m_default_icon; }; diff --git a/Userland/Services/Taskbar/main.cpp b/Userland/Services/Taskbar/main.cpp index f86c0a114b..02cc6a0af8 100644 --- a/Userland/Services/Taskbar/main.cpp +++ b/Userland/Services/Taskbar/main.cpp @@ -51,8 +51,8 @@ int main(int argc, char** argv) return 1; } - TaskbarWindow window; - window.show(); + auto window = TaskbarWindow::construct(); + window->show(); return app->exec(); } |