diff options
author | sin-ack <sin-ack@users.noreply.github.com> | 2021-08-16 22:09:58 +0000 |
---|---|---|
committer | Ali Mohammad Pur <Ali.mpfard@gmail.com> | 2021-08-23 12:25:26 +0430 |
commit | b30b7de2d2df940a864c028786325d606916feea (patch) | |
tree | 7e8d6d013b2aee5bcb90feb30985674be0663f9e /Userland/Demos | |
parent | a8967388d3b6986dd10fab193c0b1fef287a4e18 (diff) | |
download | serenity-b30b7de2d2df940a864c028786325d606916feea.zip |
ModelGallery: Add the new Model Gallery application :^)
This is an application analogous to WidgetGallery, in that it tests
various capabilities of LibGUI models. Right now it is pretty bare, but
as more work towards LibGUI models is done regarding persistent model
indices, more demos will be added.
Diffstat (limited to 'Userland/Demos')
-rw-r--r-- | Userland/Demos/CMakeLists.txt | 1 | ||||
-rw-r--r-- | Userland/Demos/ModelGallery/BasicModel.cpp | 68 | ||||
-rw-r--r-- | Userland/Demos/ModelGallery/BasicModel.h | 41 | ||||
-rw-r--r-- | Userland/Demos/ModelGallery/BasicModelTab.gml | 44 | ||||
-rw-r--r-- | Userland/Demos/ModelGallery/CMakeLists.txt | 17 | ||||
-rw-r--r-- | Userland/Demos/ModelGallery/GalleryWidget.cpp | 75 | ||||
-rw-r--r-- | Userland/Demos/ModelGallery/GalleryWidget.h | 38 | ||||
-rw-r--r-- | Userland/Demos/ModelGallery/main.cpp | 39 |
8 files changed, 323 insertions, 0 deletions
diff --git a/Userland/Demos/CMakeLists.txt b/Userland/Demos/CMakeLists.txt index 3fe8445740..f75aa4adc7 100644 --- a/Userland/Demos/CMakeLists.txt +++ b/Userland/Demos/CMakeLists.txt @@ -5,6 +5,7 @@ add_subdirectory(Fire) add_subdirectory(LibGfxDemo) add_subdirectory(LibGfxScaleDemo) add_subdirectory(Mandelbrot) +add_subdirectory(ModelGallery) add_subdirectory(Mouse) add_subdirectory(Screensaver) add_subdirectory(Starfield) diff --git a/Userland/Demos/ModelGallery/BasicModel.cpp b/Userland/Demos/ModelGallery/BasicModel.cpp new file mode 100644 index 0000000000..10b76e37af --- /dev/null +++ b/Userland/Demos/ModelGallery/BasicModel.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2021, sin-ack <sin-ack@protonmail.com> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "BasicModel.h" + +GUI::Variant BasicModel::data(GUI::ModelIndex const& index, GUI::ModelRole role) const +{ + if (role != GUI::ModelRole::Display) + return {}; + if (!is_within_range(index)) + return {}; + + return m_items.at(index.row()); +} + +TriState BasicModel::data_matches(GUI::ModelIndex const& index, GUI::Variant const& data) const +{ + if (!is_within_range(index)) + return TriState::False; + if (!data.is_string()) + return TriState::False; + + auto& value = m_items.at(index.row()); + return value.contains(data.as_string()) ? TriState::True : TriState::False; +} + +void BasicModel::invalidate() +{ + Model::invalidate(); + if (on_invalidate) + on_invalidate(); +} + +GUI::ModelIndex BasicModel::index(int row, int column, GUI::ModelIndex const& parent) const +{ + if (column != 0) + return {}; + if (parent.is_valid()) + return {}; + if (row < 0 || row >= static_cast<int>(m_items.size())) + return {}; + + return create_index(row, column); +} + +void BasicModel::add_item(String const& item) +{ + begin_insert_rows({}, m_items.size(), m_items.size()); + m_items.append(item); + end_insert_rows(); + + did_update(UpdateFlag::DontInvalidateIndices); +} + +void BasicModel::remove_item(GUI::ModelIndex const& index) +{ + if (!index.is_valid() || !is_within_range(index)) + return; + + begin_delete_rows({}, index.row(), index.row()); + m_items.remove(index.row()); + end_delete_rows(); + + did_update(UpdateFlag::DontInvalidateIndices); +} diff --git a/Userland/Demos/ModelGallery/BasicModel.h b/Userland/Demos/ModelGallery/BasicModel.h new file mode 100644 index 0000000000..e0dfd1ed4c --- /dev/null +++ b/Userland/Demos/ModelGallery/BasicModel.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2021, sin-ack <sin-ack@protonmail.com> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include <AK/Function.h> +#include <AK/NonnullRefPtr.h> +#include <AK/Vector.h> +#include <LibGUI/Model.h> + +class BasicModel final : public GUI::Model { +public: + static NonnullRefPtr<BasicModel> create() + { + return adopt_ref(*new BasicModel()); + } + + virtual int row_count(GUI::ModelIndex const& = GUI::ModelIndex()) const override { return m_items.size(); } + virtual int column_count(GUI::ModelIndex const& = GUI::ModelIndex()) const override { return 1; } + virtual String column_name(int) const override { return "Item"; } + + virtual GUI::Variant data(GUI::ModelIndex const&, GUI::ModelRole = GUI::ModelRole::Display) const override; + virtual TriState data_matches(GUI::ModelIndex const&, GUI::Variant const&) const override; + virtual void invalidate() override; + virtual GUI::ModelIndex index(int row, int column = 0, GUI::ModelIndex const& parent = GUI::ModelIndex()) const override; + + Function<void()> on_invalidate; + + void add_item(String const& item); + void remove_item(GUI::ModelIndex const&); + +private: + BasicModel() + { + } + + Vector<String> m_items; +}; diff --git a/Userland/Demos/ModelGallery/BasicModelTab.gml b/Userland/Demos/ModelGallery/BasicModelTab.gml new file mode 100644 index 0000000000..f645563a52 --- /dev/null +++ b/Userland/Demos/ModelGallery/BasicModelTab.gml @@ -0,0 +1,44 @@ +@GUI::Widget { + name: "basic_model_tab" + layout: @GUI::VerticalBoxLayout { + margins: [4] + } + + @GUI::Label { + text: "Here is a basic model, displayed on a table widget. Its clients are updated via granular updates. You can add or remove items with the widgets below." + text_alignment: "CenterLeft" + + thickness: 2 + fixed_height: 34 + } + + @GUI::TableView { + name: "model_table" + } + + @GUI::Widget { + layout: @GUI::HorizontalBoxLayout { + } + + fixed_height: 30 + + @GUI::TextBox { + name: "new_item_name" + placeholder: "Enter some text to be added..." + } + + @GUI::Button { + name: "add_new_item" + fixed_width: 22 + fixed_height: 22 + tooltip: "Add the text as an item to the model" + } + + @GUI::Button { + name: "remove_selected_item" + fixed_width: 22 + fixed_height: 22 + tooltip: "Remove the selected item from the model" + } + } +} diff --git a/Userland/Demos/ModelGallery/CMakeLists.txt b/Userland/Demos/ModelGallery/CMakeLists.txt new file mode 100644 index 0000000000..cf9f7f9c96 --- /dev/null +++ b/Userland/Demos/ModelGallery/CMakeLists.txt @@ -0,0 +1,17 @@ +serenity_component( + ModelGallery + TARGETS ModelGallery +) + +compile_gml(./BasicModelTab.gml BasicModelTabGML.h basic_model_tab_gml) + +set(SOURCES + main.cpp + GalleryWidget.cpp + BasicModel.cpp + BasicModelTabGML.h +) + +serenity_app(ModelGallery ICON app-model-gallery) + +target_link_libraries(ModelGallery LibGUI LibGfx) diff --git a/Userland/Demos/ModelGallery/GalleryWidget.cpp b/Userland/Demos/ModelGallery/GalleryWidget.cpp new file mode 100644 index 0000000000..28c77ce1f4 --- /dev/null +++ b/Userland/Demos/ModelGallery/GalleryWidget.cpp @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2021, sin-ack <sin-ack@protonmail.com> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "GalleryWidget.h" +#include <Demos/ModelGallery/BasicModelTabGML.h> + +GalleryWidget::GalleryWidget() +{ + set_fill_with_background_color(true); + set_layout<GUI::VerticalBoxLayout>(); + + auto& inner_widget = add<GUI::Widget>(); + auto& inner_layout = inner_widget.set_layout<GUI::VerticalBoxLayout>(); + inner_layout.set_margins({ 4 }); + + m_tab_widget = inner_widget.add<GUI::TabWidget>(); + m_statusbar = add<GUI::Statusbar>(); + + load_basic_model_tab(); + load_sorting_filtering_tab(); +} + +void GalleryWidget::load_basic_model_tab() +{ + auto& tab = m_tab_widget->add_tab<GUI::Widget>("Basic Model"); + tab.load_from_gml(basic_model_tab_gml); + + m_basic_model = BasicModel::create(); + m_basic_model_table = *tab.find_descendant_of_type_named<GUI::TableView>("model_table"); + m_basic_model_table->set_model(m_basic_model); + + m_basic_model->on_invalidate = [&] { + m_invalidation_count++; + m_statusbar->set_text(String::formatted("Times invalidated: {}", m_invalidation_count)); + }; + + m_statusbar->set_text(String::formatted("Times invalidated: {}", m_invalidation_count)); + + m_basic_model->add_item("Well..."); + m_basic_model->add_item("...hello..."); + m_basic_model->add_item("...friends! :^)"); + + m_new_item_name = *tab.find_descendant_of_type_named<GUI::TextBox>("new_item_name"); + m_add_new_item = *tab.find_descendant_of_type_named<GUI::Button>("add_new_item"); + m_remove_selected_item = *tab.find_descendant_of_type_named<GUI::Button>("remove_selected_item"); + + m_add_new_item->set_icon(Gfx::Bitmap::try_load_from_file("/res/icons/16x16/plus.png")); + m_remove_selected_item->set_icon(Gfx::Bitmap::try_load_from_file("/res/icons/16x16/minus.png")); + + m_new_item_name->on_return_pressed = [&] { add_textbox_contents_to_basic_model(); }; + m_add_new_item->on_click = [&](auto) { add_textbox_contents_to_basic_model(); }; + + m_remove_selected_item->on_click = [&](auto) { + auto index = m_basic_model_table->cursor_index(); + if (index.is_valid()) { + m_basic_model->remove_item(index); + } + }; +} + +void GalleryWidget::load_sorting_filtering_tab() +{ + // TODO: Add the SortingFilteringProxyModel here. +} + +void GalleryWidget::add_textbox_contents_to_basic_model() +{ + if (!m_new_item_name->current_line().is_empty()) { + m_basic_model->add_item(m_new_item_name->current_line().to_utf8()); + m_new_item_name->set_text(""); + } +} diff --git a/Userland/Demos/ModelGallery/GalleryWidget.h b/Userland/Demos/ModelGallery/GalleryWidget.h new file mode 100644 index 0000000000..ddb7a3c0b6 --- /dev/null +++ b/Userland/Demos/ModelGallery/GalleryWidget.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2021, sin-ack <sin-ack@protonmail.com> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include "BasicModel.h" +#include <LibGUI/BoxLayout.h> +#include <LibGUI/Button.h> +#include <LibGUI/Statusbar.h> +#include <LibGUI/TabWidget.h> +#include <LibGUI/TableView.h> +#include <LibGUI/TextBox.h> +#include <LibGUI/Widget.h> + +class GalleryWidget final : public GUI::Widget { + C_OBJECT(GalleryWidget) + +private: + GalleryWidget(); + + void load_basic_model_tab(); + void load_sorting_filtering_tab(); + + void add_textbox_contents_to_basic_model(); + + RefPtr<GUI::TabWidget> m_tab_widget; + RefPtr<GUI::Statusbar> m_statusbar; + + size_t m_invalidation_count { 0 }; + RefPtr<BasicModel> m_basic_model; + RefPtr<GUI::TableView> m_basic_model_table; + RefPtr<GUI::TextBox> m_new_item_name; + RefPtr<GUI::Button> m_add_new_item; + RefPtr<GUI::Button> m_remove_selected_item; +}; diff --git a/Userland/Demos/ModelGallery/main.cpp b/Userland/Demos/ModelGallery/main.cpp new file mode 100644 index 0000000000..acdf0c5876 --- /dev/null +++ b/Userland/Demos/ModelGallery/main.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2021, sin-ack <sin-ack@protonmail.com> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "GalleryWidget.h" +#include <LibGUI/Application.h> +#include <LibGUI/BoxLayout.h> +#include <LibGUI/Button.h> +#include <LibGUI/Frame.h> +#include <LibGUI/MessageBox.h> +#include <unistd.h> + +int main(int argc, char** argv) +{ + if (pledge("stdio recvfd sendfd rpath wpath cpath unix", nullptr) < 0) { + perror("pledge"); + return 1; + } + + auto app = GUI::Application::construct(argc, argv); + + if (pledge("stdio recvfd sendfd rpath", nullptr) < 0) { + perror("pledge"); + return 1; + } + + auto app_icon = GUI::Icon::default_icon("app-model-gallery"); + + auto window = GUI::Window::construct(); + window->set_title("Model Gallery"); + window->set_icon(app_icon.bitmap_for_size(16)); + window->resize(430, 480); + window->set_main_widget<GalleryWidget>(); + + window->show(); + return app->exec(); +} |