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.
This commit is contained in:
sin-ack 2021-08-16 22:09:58 +00:00 committed by Ali Mohammad Pur
parent a8967388d3
commit b30b7de2d2
Notes: sideshowbarker 2024-07-18 05:21:07 +09:00
11 changed files with 327 additions and 0 deletions

View File

@ -0,0 +1,4 @@
[App]
Name=Model Gallery
Executable=/bin/ModelGallery
Category=Demos

Binary file not shown.

After

Width:  |  Height:  |  Size: 694 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 740 B

View File

@ -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)

View File

@ -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);
}

View File

@ -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;
};

View File

@ -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"
}
}
}

View File

@ -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)

View File

@ -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("");
}
}

View File

@ -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;
};

View File

@ -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();
}