Explorar el Código

Calendar: Implement basic GUI calendar application

rhin123 hace 5 años
padre
commit
39c21f368a

+ 56 - 0
Applications/Calendar/AddEventDialog.cpp

@@ -0,0 +1,56 @@
+#include "AddEventDialog.h"
+#include <LibCore/DateTime.h>
+#include <LibGUI/BoxLayout.h>
+#include <LibGUI/Button.h>
+#include <LibGUI/Label.h>
+#include <LibGUI/Layout.h>
+#include <LibGUI/Painter.h>
+#include <LibGUI/Widget.h>
+#include <LibGUI/Window.h>
+#include <LibGfx/Color.h>
+#include <LibGfx/Font.h>
+
+AddEventDialog::AddEventDialog(Calendar* calendar, Window* parent_window)
+    : Dialog(parent_window)
+    , m_calendar(calendar)
+{
+    resize(230, 120);
+    set_title("Add Event");
+    set_resizable(false);
+
+    auto& widget = set_main_widget<GUI::Widget>();
+    widget.set_fill_with_background_color(true);
+    widget.set_layout<GUI::HorizontalBoxLayout>();
+
+    auto& main_container = widget.add<GUI::Widget>();
+    main_container.set_layout<GUI::VerticalBoxLayout>();
+    main_container.layout()->set_margins({ 4, 4, 4, 4 });
+
+    auto make_label = [&](const StringView& text, bool bold = false) {
+        auto& label = main_container.add<GUI::Label>(text);
+        label.set_text_alignment(Gfx::TextAlignment::CenterLeft);
+        label.set_size_policy(GUI::SizePolicy::Fill, GUI::SizePolicy::Fixed);
+        label.set_preferred_size(0, 14);
+        if (bold)
+            label.set_font(Gfx::Font::default_bold_font());
+    };
+    make_label("TODO: Implement add event dialog", true);
+
+    main_container.layout()->add_spacer();
+
+    auto& button_container = main_container.add<GUI::Widget>();
+    button_container.set_size_policy(GUI::SizePolicy::Fill, GUI::SizePolicy::Fixed);
+    button_container.set_preferred_size(0, 20);
+    button_container.set_layout<GUI::HorizontalBoxLayout>();
+    button_container.layout()->add_spacer();
+    auto& ok_button = button_container.add<GUI::Button>("OK");
+    ok_button.set_size_policy(GUI::SizePolicy::Fixed, GUI::SizePolicy::Fixed);
+    ok_button.set_preferred_size(80, 20);
+    ok_button.on_click = [this] {
+        done(Dialog::ExecOK);
+    };
+}
+
+AddEventDialog::~AddEventDialog()
+{
+}

+ 22 - 0
Applications/Calendar/AddEventDialog.h

@@ -0,0 +1,22 @@
+#pragma once
+
+#include "Calendar.h"
+#include <LibGUI/Dialog.h>
+#include <LibGUI/Window.h>
+
+class AddEventDialog final : public GUI::Dialog {
+    C_OBJECT(AddEventDialog)
+public:
+    virtual ~AddEventDialog() override;
+
+    static void show(Calendar* calendar, Window* parent_window = nullptr)
+    {
+        auto dialog = AddEventDialog::construct(calendar, parent_window);
+        dialog->exec();
+    }
+
+private:
+    AddEventDialog(Calendar* calendar, Window* parent_window = nullptr);
+
+    Calendar* m_calendar;
+};

+ 34 - 0
Applications/Calendar/Calendar.cpp

@@ -0,0 +1,34 @@
+#include "Calendar.h"
+
+const String name_of_month(int month)
+{
+    const String month_names[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+    return month_names[month - 1];
+}
+
+Calendar::Calendar(Core::DateTime date_time)
+    : m_date_time(date_time)
+    , m_selected_year(date_time.year())
+    , m_selected_month(date_time.month())
+{
+}
+
+Calendar::~Calendar()
+{
+}
+
+const String Calendar::selected_date_text()
+{
+    return String::format("%s %d", name_of_month(m_selected_month).characters(), m_selected_year);
+}
+
+void Calendar::set_selected_date(int year, int month)
+{
+    m_selected_year = year;
+    m_selected_month = month;
+}
+
+bool Calendar::is_today(Core::DateTime date_time) const
+{
+    return date_time.day() == m_date_time.day() && date_time.month() == m_date_time.month() && date_time.year() == m_date_time.year();
+}

+ 23 - 0
Applications/Calendar/Calendar.h

@@ -0,0 +1,23 @@
+#pragma once
+
+#include <AK/String.h>
+#include <LibCore/DateTime.h>
+
+const String name_of_month(int month);
+
+class Calendar final {
+public:
+    Calendar(Core::DateTime date_time);
+    ~Calendar();
+
+    const String selected_date_text();
+    void set_selected_date(int year, int month);
+    int selected_year() const { return m_selected_year; }
+    int selected_month() const { return m_selected_month; }
+    bool is_today(Core::DateTime date_time) const;
+
+private:
+    Core::DateTime m_date_time;
+    int m_selected_year { 0 };
+    int m_selected_month { 0 };
+};

+ 177 - 0
Applications/Calendar/CalendarWidget.cpp

@@ -0,0 +1,177 @@
+#include "CalendarWidget.h"
+#include "AddEventDialog.h"
+#include "Calendar.h"
+#include <LibCore/DateTime.h>
+#include <LibGUI/BoxLayout.h>
+#include <LibGUI/Button.h>
+#include <LibGUI/Painter.h>
+#include <LibGUI/Window.h>
+#include <LibGfx/Font.h>
+
+CalendarWidget::CalendarWidget()
+{
+    set_fill_with_background_color(true);
+    m_calendar = make<Calendar>(Core::DateTime::now());
+
+    m_selected_date_label = add<GUI::Label>();
+    m_selected_date_label->set_relative_rect(20, 13, 100, 25);
+    m_selected_date_label->set_text_alignment(Gfx::TextAlignment::CenterLeft);
+    m_selected_date_label->set_font(Gfx::Font::default_bold_font());
+    m_selected_date_label->set_text(m_calendar->selected_date_text());
+
+    m_prev_month_button = add<GUI::Button>();
+    m_prev_month_button->set_text("<");
+    m_prev_month_button->set_font(Gfx::Font::default_bold_font());
+    m_prev_month_button->set_relative_rect(90, 5, 40, 40);
+    m_prev_month_button->on_click = [this] {
+        int m_target_month = m_calendar->selected_month() - 1;
+        int m_target_year = m_calendar->selected_year();
+
+        if (m_calendar->selected_month() <= 1) {
+            m_target_month = 12;
+            m_target_year--;
+        }
+        update_calendar_tiles(m_target_year, m_target_month);
+    };
+
+    m_next_month_button = add<GUI::Button>();
+    m_next_month_button->set_text(">");
+    m_next_month_button->set_font(Gfx::Font::default_bold_font());
+    m_next_month_button->set_relative_rect(131, 5, 40, 40);
+    m_next_month_button->on_click = [this] {
+        int m_target_month = m_calendar->selected_month() + 1;
+        int m_target_year = m_calendar->selected_year();
+
+        if (m_calendar->selected_month() >= 12) {
+            m_target_month = 1;
+            m_target_year++;
+        }
+        update_calendar_tiles(m_target_year, m_target_month);
+    };
+
+    m_prev_month_button = add<GUI::Button>();
+    m_prev_month_button->set_text("Add Event");
+    m_prev_month_button->set_relative_rect(475, 13, 100, 25);
+    m_prev_month_button->on_click = [this] {
+        AddEventDialog::show(m_calendar, window());
+    };
+
+    update_calendar_tiles(m_calendar->selected_year(), m_calendar->selected_month());
+}
+
+CalendarWidget::~CalendarWidget()
+{
+}
+
+void CalendarWidget::update_calendar_tiles(int target_year, int target_month)
+{
+    unsigned int i = 0;
+    //TODO: Modify m_tile_height if the end of the month doesn't fit onto the current tile array
+    for (int y = 0; y < 5; y++)
+        for (int x = 0; x < 7; x++) {
+            auto date_time = Core::DateTime::create(target_year, target_month, 1);
+            int x_offset = x * m_tile_width;
+            int y_offset = (y * m_tile_height) + 50;
+
+            unsigned int start_of_month = date_time.weekday();
+            unsigned int year;
+            unsigned int month;
+            unsigned int day;
+
+            if (start_of_month > i) {
+                month = (target_month - 1 == 0) ? 12 : target_month - 1;
+                year = (month == 12) ? target_year - 1 : target_year;
+                date_time.set_time(year, month, 1);
+                day = (date_time.days_in_month() - (start_of_month) + i) + 1;
+                date_time.set_time(year, month, day);
+
+            } else if ((i - start_of_month) + 1 > date_time.days_in_month()) {
+                month = (target_month + 1) > 12 ? 1 : target_month + 1;
+                year = (month == 1) ? target_year + 1 : target_year;
+                day = ((i - start_of_month) + 1) - date_time.days_in_month();
+                date_time.set_time(year, month, day);
+            } else {
+                month = target_month;
+                year = target_year;
+                day = (i - start_of_month) + 1;
+                date_time.set_time(year, month, day);
+            }
+
+            if (!m_calendar_tiles[i]) {
+                m_calendar_tiles[i] = add<CalendarTile>(*m_calendar, i, date_time);
+                m_calendar_tiles[i]->set_frame_thickness(0);
+                m_calendar_tiles[i]->set_relative_rect(x_offset, y_offset, 85, 85);
+            } else {
+                m_calendar_tiles[i]->update_values(*m_calendar, i, date_time);
+                m_calendar_tiles[i]->update();
+            }
+            i++;
+        }
+
+    m_calendar->set_selected_date(target_year, target_month);
+    m_selected_date_label->set_text(m_calendar->selected_date_text());
+}
+
+CalendarWidget::CalendarTile::CalendarTile(Calendar& calendar, int index, Core::DateTime date_time)
+    : m_index(index)
+    , m_date_time(date_time)
+    , m_calendar(calendar)
+{
+    update_values(calendar, index, date_time);
+}
+
+void CalendarWidget::CalendarTile::update_values(Calendar& calendar, int index, Core::DateTime date_time)
+{
+    m_calendar = calendar;
+    m_index = index;
+    m_date_time = date_time;
+    m_display_weekday_name = index < 7;
+
+    if (m_display_weekday_name) {
+        const String m_day_names[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
+        m_weekday_name = m_day_names[index];
+    }
+
+    m_display_date = (m_date_time.day() == 1) ? String::format("%s %d", name_of_month(m_date_time.month()).characters(), m_date_time.day()) : String::number(m_date_time.day());
+}
+
+CalendarWidget::CalendarTile::~CalendarTile()
+{
+}
+
+void CalendarWidget::CalendarTile::paint_event(GUI::PaintEvent& event)
+{
+    GUI::Frame::paint_event(event);
+
+    GUI::Painter painter(*this);
+    painter.fill_rect(frame_inner_rect(), Color::NamedColor::White);
+
+    painter.draw_line(frame_inner_rect().top_right(), frame_inner_rect().bottom_right(), Color::NamedColor::Black);
+    if (m_index == 0 || m_index % 7 == 0)
+        painter.draw_line(frame_inner_rect().top_left(), frame_inner_rect().bottom_left(), Color::NamedColor::Black);
+
+    if (m_index < 7)
+        painter.draw_line(frame_inner_rect().top_left(), frame_inner_rect().top_right(), Color::NamedColor::Black);
+    painter.draw_line(frame_inner_rect().bottom_left(), frame_inner_rect().bottom_right(), Color::NamedColor::Black);
+
+    Gfx::Rect day_rect;
+
+    if (m_display_weekday_name) {
+        auto weekday_rect = frame_inner_rect().shrunken(0, frame_inner_rect().height() / 1.2);
+        weekday_rect.set_top(frame_inner_rect().y() + 2);
+        painter.draw_text(weekday_rect, m_weekday_name, Gfx::Font::default_bold_font(), Gfx::TextAlignment::Center, Color::Black);
+
+        day_rect = frame_inner_rect().shrunken(0, frame_inner_rect().height() / 1.2);
+        day_rect.set_top(frame_inner_rect().y() + 15);
+    } else {
+        day_rect = frame_inner_rect().shrunken(0, frame_inner_rect().height() / 1.2);
+        day_rect.set_top(frame_inner_rect().y() + 4);
+    }
+
+    if (m_calendar.is_today(m_date_time)) {
+        auto highlight_rect = day_rect.shrunken(day_rect.width() - (font().glyph_width('x') * (m_display_date.length() + 1)) - 4, 0);
+        painter.draw_rect(highlight_rect, Color::NamedColor::Blue);
+        painter.draw_text(day_rect, m_display_date, Gfx::Font::default_bold_font(), Gfx::TextAlignment::Center, Color::Black);
+    } else
+        painter.draw_text(day_rect, m_display_date, Gfx::TextAlignment::Center, Color::Black);
+}

+ 46 - 0
Applications/Calendar/CalendarWidget.h

@@ -0,0 +1,46 @@
+#pragma once
+
+#include "Calendar.h"
+#include <LibGUI/Frame.h>
+#include <LibGUI/Label.h>
+#include <LibGUI/Widget.h>
+
+class CalendarWidget final : public GUI::Widget {
+    C_OBJECT(CalendarWidget)
+
+public:
+    CalendarWidget();
+    virtual ~CalendarWidget() override;
+
+private:
+    void update_calendar_tiles(int target_year, int target_month);
+    void show_add_event_window(Calendar* calendar);
+
+    OwnPtr<Calendar> m_calendar;
+    RefPtr<GUI::Label> m_selected_date_label;
+    RefPtr<GUI::Button> m_prev_month_button;
+    RefPtr<GUI::Button> m_next_month_button;
+
+    class CalendarTile final : public GUI::Frame {
+        C_OBJECT(CalendarTile)
+    public:
+        CalendarTile(Calendar& calendar, int index, Core::DateTime m_date_time);
+        void update_values(Calendar& calendar, int index, Core::DateTime date_time);
+        virtual ~CalendarTile() override;
+
+    private:
+        virtual void paint_event(GUI::PaintEvent&) override;
+
+        int m_index { 0 };
+        bool m_display_weekday_name { false };
+
+        String m_weekday_name;
+        String m_display_date;
+        Core::DateTime m_date_time;
+        Calendar& m_calendar;
+    };
+
+    RefPtr<CalendarTile> m_calendar_tiles[35];
+    int m_tile_width { 85 };
+    int m_tile_height { 85 };
+};

+ 12 - 0
Applications/Calendar/Makefile

@@ -0,0 +1,12 @@
+OBJS = \
+       Calendar.o \
+       CalendarWidget.o \
+       AddEventDialog.o \
+       main.o
+
+PROGRAM = Calendar
+
+LIB_DEPS = GUI Gfx IPC Core
+
+include ../../Makefile.common
+

+ 54 - 0
Applications/Calendar/main.cpp

@@ -0,0 +1,54 @@
+#include "CalendarWidget.h"
+#include <LibGUI/AboutDialog.h>
+#include <LibGUI/Action.h>
+#include <LibGUI/Application.h>
+#include <LibGUI/Menu.h>
+#include <LibGUI/MenuBar.h>
+#include <LibGUI/Window.h>
+#include <LibGfx/Bitmap.h>
+#include <stdio.h>
+
+int main(int argc, char** argv)
+{
+
+    if (pledge("stdio shared_buffer rpath accept unix cpath fattr", nullptr) < 0) {
+        perror("pledge");
+        return 1;
+    }
+
+    GUI::Application app(argc, argv);
+
+    if (pledge("stdio shared_buffer rpath accept", nullptr) < 0) {
+        perror("pledge");
+        return 1;
+    }
+
+    if (unveil("/res", "r") < 0) {
+        perror("unveil");
+        return 1;
+    }
+
+    unveil(nullptr, nullptr);
+
+    auto window = GUI::Window::construct();
+    window->set_title("Calendar");
+    window->set_rect(20, 200, 596, 476);
+    //TODO: Allow proper resize
+    window->set_resizable(false);
+
+    window->set_main_widget<CalendarWidget>();
+
+    window->show();
+
+    auto menubar = make<GUI::MenuBar>();
+
+    auto app_menu = GUI::Menu::construct("Calendar");
+    app_menu->add_action(GUI::CommonActions::make_quit_action([](auto&) {
+        GUI::Application::the().quit(0);
+        return;
+    }));
+    menubar->add_menu(move(app_menu));
+    app.set_menubar(move(menubar));
+
+    app.exec();
+}

+ 2 - 0
Kernel/build-root-filesystem.sh

@@ -135,6 +135,7 @@ cp ../Applications/Piano/Piano mnt/bin/Piano
 cp ../Applications/SystemMenu/SystemMenu mnt/bin/SystemMenu
 cp ../Applications/ChanViewer/ChanViewer mnt/bin/ChanViewer
 cp ../Applications/Calculator/Calculator mnt/bin/Calculator
+cp ../Applications/Calendar/Calendar mnt/bin/Calendar
 cp ../Applications/SoundPlayer/SoundPlayer mnt/bin/SoundPlayer
 cp ../Applications/DisplayProperties/DisplayProperties mnt/bin/DisplayProperties
 cp ../Applications/Welcome/Welcome mnt/bin/Welcome
@@ -189,6 +190,7 @@ ln -s Piano mnt/bin/pi
 ln -s SystemDialog mnt/bin/sd
 ln -s ChanViewer mnt/bin/cv
 ln -s Calculator mnt/bin/calc
+ln -s Calendar mnt/bin/calendar
 ln -s Inspector mnt/bin/ins
 ln -s SoundPlayer mnt/bin/sp
 ln -s Help mnt/bin/help