diff --git a/Userland/Libraries/LibGUI/CMakeLists.txt b/Userland/Libraries/LibGUI/CMakeLists.txt index 0b33fb1d11..0f92ea9d3a 100644 --- a/Userland/Libraries/LibGUI/CMakeLists.txt +++ b/Userland/Libraries/LibGUI/CMakeLists.txt @@ -1,6 +1,7 @@ compile_gml(DynamicWidgetContainerControls.gml DynamicWidgetContainerControls.cpp) stringify_gml(AboutDialog.gml AboutDialogGML.h about_dialog_gml) +stringify_gml(DatePickerDialog.gml DatePickerDialogGML.h date_picker_dialog_gml) stringify_gml(EmojiInputDialog.gml EmojiInputDialogGML.h emoji_input_dialog_gml) stringify_gml(FontPickerDialog.gml FontPickerDialogGML.h font_picker_dialog_gml) stringify_gml(FilePickerDialog.gml FilePickerDialogGML.h file_picker_dialog_gml) @@ -36,6 +37,7 @@ set(SOURCES CommonMenus.cpp ConnectionToWindowManagerServer.cpp ConnectionToWindowServer.cpp + DatePicker.cpp Desktop.cpp Dialog.cpp DisplayLink.cpp @@ -144,6 +146,7 @@ set(GENERATED_SOURCES ../../Services/WindowServer/WindowManagerServerEndpoint.h ../../Services/WindowServer/WindowServerEndpoint.h AboutDialogGML.h + DatePickerDialogGML.h EmojiInputDialogGML.h FilePickerDialogGML.h FontPickerDialogGML.h diff --git a/Userland/Libraries/LibGUI/DatePicker.cpp b/Userland/Libraries/LibGUI/DatePicker.cpp new file mode 100644 index 0000000000..3e385f992b --- /dev/null +++ b/Userland/Libraries/LibGUI/DatePicker.cpp @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2023, David Ganz + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace GUI { + +DatePicker::DatePicker(Window* parent_window, String const& title, Core::DateTime focused_date) + : Dialog(parent_window) + , m_selected_date(focused_date) +{ + if (parent_window) + set_icon(parent_window->icon()); + + set_resizable(false); + set_title(title.to_byte_string()); + + auto widget = set_main_widget(); + widget->load_from_gml(date_picker_dialog_gml).release_value_but_fixme_should_propagate_errors(); + + auto& calendar = *widget->find_descendant_of_type_named("calendar_view"); + calendar.on_tile_click = [&]() { + m_selected_date = calendar.selected_date(); + m_month_box->set_selected_index(m_selected_date.month() - 1, AllowCallback::No); + m_year_box->set_value(static_cast(m_selected_date.year()), AllowCallback::No); + }; + calendar.on_tile_doubleclick = [&]() { + m_selected_date = calendar.selected_date(); + done(ExecResult::OK); + }; + calendar.set_selected_date(focused_date); + calendar.update_tiles(focused_date.year(), focused_date.month()); + + m_month_box = widget->find_descendant_of_type_named("month_box"); + m_month_box->set_model(GUI::MonthListModel::create(GUI::MonthListModel::DisplayMode::Long)); + m_month_box->set_selected_index(focused_date.month() - 1, AllowCallback::No); + m_month_box->on_change = [&](ByteString const&, ModelIndex const& index) { + m_selected_date.set_time(static_cast(m_selected_date.year()), index.row() + 1); + calendar.set_selected_date(m_selected_date); + calendar.update_tiles(m_selected_date.year(), m_selected_date.month()); + calendar.update(); + }; + + m_year_box = widget->find_descendant_of_type_named("year_box"); + m_year_box->set_value(static_cast(focused_date.year()), AllowCallback::No); + m_year_box->on_change = [&](int year) { + m_selected_date.set_time(year, static_cast(m_selected_date.month())); + calendar.set_selected_date(m_selected_date); + calendar.update_tiles(m_selected_date.year(), m_selected_date.month()); + calendar.update(); + }; + + auto& ok_button = *widget->find_descendant_of_type_named("ok_button"); + ok_button.on_click = [&](auto) { + dbgln("GUI::DatePicker: OK button clicked"); + m_selected_date = calendar.selected_date(); + done(ExecResult::OK); + }; + + auto& cancel_button = *widget->find_descendant_of_type_named("cancel_button"); + cancel_button.on_click = [this](auto) { + dbgln("GUI::DatePicker: Cancel button clicked"); + done(ExecResult::Cancel); + }; +} + +Optional DatePicker::show(Window* parent_window, String title, Core::DateTime focused_date) +{ + auto box = DatePicker::construct(parent_window, title, focused_date); + if (box->exec() == ExecResult::OK) { + return box->m_selected_date; + } + + return {}; +} + +} diff --git a/Userland/Libraries/LibGUI/DatePickerDialog.gml b/Userland/Libraries/LibGUI/DatePickerDialog.gml new file mode 100644 index 0000000000..100aad5ede --- /dev/null +++ b/Userland/Libraries/LibGUI/DatePickerDialog.gml @@ -0,0 +1,56 @@ +@GUI::Widget { + shrink_to_fit: true + fill_with_background_color: true + layout: @GUI::VerticalBoxLayout {} + + @GUI::Widget { + fixed_height: 20 + fill_with_background_color: true + layout: @GUI::HorizontalBoxLayout {} + + @GUI::ComboBox { + name: "month_box" + model_only: true + } + + @GUI::SpinBox { + name: "year_box" + fixed_size: [55, 20] + min: 0 + max: 9999 + } + + @GUI::Layout::Spacer {} + } + + @GUI::Widget { + fixed_width: 200 + fixed_height: 200 + layout: @GUI::VerticalBoxLayout {} + + @GUI::Calendar { + name: "calendar_view" + } + } + + @GUI::Widget { + fixed_height: 20 + fill_with_background_color: true + layout: @GUI::HorizontalBoxLayout {} + + @GUI::Layout::Spacer {} + + @GUI::Button { + name: "cancel_button" + text: "Cancel" + fixed_size: [80, 20] + } + + @GUI::Button { + name: "ok_button" + text: "OK" + fixed_size: [80, 20] + default: true + } + } +} diff --git a/Userland/Libraries/LibGUI/Forward.h b/Userland/Libraries/LibGUI/Forward.h index a7d7f67a37..4877fab721 100644 --- a/Userland/Libraries/LibGUI/Forward.h +++ b/Userland/Libraries/LibGUI/Forward.h @@ -26,6 +26,7 @@ class CheckBox; class ComboBox; class Command; class CommandPalette; +class DatePicker; class Dialog; class DialogButton; class DragEvent;