summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrhin123 <ryanrhin@gmail.com>2020-03-10 16:41:48 -0500
committerAndreas Kling <kling@serenityos.org>2020-03-18 08:17:01 +0100
commit39c21f368a14f1df81b858b3a1ca8907d68a0616 (patch)
tree57e311a261b171b5a0e11ec1cb0d066956832cbb
parent08a30a49617956c63d62e8196c3c574a2317f7c8 (diff)
downloadserenity-39c21f368a14f1df81b858b3a1ca8907d68a0616.zip
Calendar: Implement basic GUI calendar application
-rw-r--r--Applications/Calendar/AddEventDialog.cpp56
-rw-r--r--Applications/Calendar/AddEventDialog.h22
-rw-r--r--Applications/Calendar/Calendar.cpp34
-rw-r--r--Applications/Calendar/Calendar.h23
-rw-r--r--Applications/Calendar/CalendarWidget.cpp177
-rw-r--r--Applications/Calendar/CalendarWidget.h46
-rw-r--r--Applications/Calendar/Makefile12
-rw-r--r--Applications/Calendar/main.cpp54
-rwxr-xr-xKernel/build-root-filesystem.sh2
9 files changed, 426 insertions, 0 deletions
diff --git a/Applications/Calendar/AddEventDialog.cpp b/Applications/Calendar/AddEventDialog.cpp
new file mode 100644
index 0000000000..6d1d8b9800
--- /dev/null
+++ b/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()
+{
+}
diff --git a/Applications/Calendar/AddEventDialog.h b/Applications/Calendar/AddEventDialog.h
new file mode 100644
index 0000000000..5e0883b46d
--- /dev/null
+++ b/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;
+};
diff --git a/Applications/Calendar/Calendar.cpp b/Applications/Calendar/Calendar.cpp
new file mode 100644
index 0000000000..7f731c7443
--- /dev/null
+++ b/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();
+}
diff --git a/Applications/Calendar/Calendar.h b/Applications/Calendar/Calendar.h
new file mode 100644
index 0000000000..6ec5d84a1d
--- /dev/null
+++ b/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 };
+};
diff --git a/Applications/Calendar/CalendarWidget.cpp b/Applications/Calendar/CalendarWidget.cpp
new file mode 100644
index 0000000000..821c0551dd
--- /dev/null
+++ b/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);
+}
diff --git a/Applications/Calendar/CalendarWidget.h b/Applications/Calendar/CalendarWidget.h
new file mode 100644
index 0000000000..5dd60a0f53
--- /dev/null
+++ b/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 };
+};
diff --git a/Applications/Calendar/Makefile b/Applications/Calendar/Makefile
new file mode 100644
index 0000000000..9e8444cb37
--- /dev/null
+++ b/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
+
diff --git a/Applications/Calendar/main.cpp b/Applications/Calendar/main.cpp
new file mode 100644
index 0000000000..c7fbc43187
--- /dev/null
+++ b/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();
+}
diff --git a/Kernel/build-root-filesystem.sh b/Kernel/build-root-filesystem.sh
index 695b44d4c0..21c0f52ebb 100755
--- a/Kernel/build-root-filesystem.sh
+++ b/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