/* * Copyright (c) 2021-2022, the SerenityOS developers. * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include #include #include #include class MouseCursorModel final : public GUI::Model { public: static NonnullRefPtr create() { return adopt_ref(*new MouseCursorModel); } virtual ~MouseCursorModel() override = default; enum Column { Bitmap, Name, __Count, }; virtual int row_count(const GUI::ModelIndex&) const override { return m_cursors.size(); } virtual int column_count(const GUI::ModelIndex&) const override { return Column::__Count; } virtual DeprecatedString column_name(int column_index) const override { switch (column_index) { case Column::Bitmap: return {}; case Column::Name: return "Name"; } VERIFY_NOT_REACHED(); } virtual GUI::Variant data(const GUI::ModelIndex& index, GUI::ModelRole role) const override { auto& cursor = m_cursors[index.row()]; if (role == GUI::ModelRole::Display) { switch (index.column()) { case Column::Bitmap: if (!cursor.bitmap) return {}; return *cursor.bitmap; case Column::Name: return cursor.name; } VERIFY_NOT_REACHED(); } return {}; } virtual void invalidate() override { m_cursors.clear(); Core::DirIterator iterator(DeprecatedString::formatted("/res/cursor-themes/{}", GUI::ConnectionToWindowServer::the().get_cursor_theme()), Core::DirIterator::Flags::SkipDots); while (iterator.has_next()) { auto path = iterator.next_full_path(); if (path.ends_with(".ini"sv)) continue; if (path.contains("2x"sv)) continue; Cursor cursor; cursor.path = move(path); cursor.name = LexicalPath::basename(cursor.path); // FIXME: Animated cursor bitmaps auto cursor_bitmap = Gfx::Bitmap::load_from_file(cursor.path).release_value_but_fixme_should_propagate_errors(); auto cursor_bitmap_rect = cursor_bitmap->rect(); cursor.params = Gfx::CursorParams::parse_from_filename(cursor.name, cursor_bitmap_rect.center()).constrained(*cursor_bitmap); cursor.bitmap = cursor_bitmap->cropped(Gfx::IntRect(Gfx::FloatRect(cursor_bitmap_rect).scaled(1.0 / cursor.params.frames(), 1.0))).release_value_but_fixme_should_propagate_errors(); m_cursors.append(move(cursor)); } Model::invalidate(); } private: MouseCursorModel() = default; struct Cursor { RefPtr bitmap; DeprecatedString path; DeprecatedString name; Gfx::CursorParams params; }; Vector m_cursors; }; class FileIconsModel final : public GUI::Model { public: static NonnullRefPtr create() { return adopt_ref(*new FileIconsModel); } virtual ~FileIconsModel() override = default; enum Column { BigIcon, LittleIcon, Name, __Count, }; virtual int row_count(const GUI::ModelIndex&) const override { return m_icon_sets.size(); } virtual int column_count(const GUI::ModelIndex&) const override { return Column::__Count; } virtual DeprecatedString column_name(int column_index) const override { switch (column_index) { case Column::BigIcon: return {}; case Column::LittleIcon: return {}; case Column::Name: return "Name"; } VERIFY_NOT_REACHED(); } virtual GUI::Variant data(const GUI::ModelIndex& index, GUI::ModelRole role) const override { auto& icon_set = m_icon_sets[index.row()]; if (role == GUI::ModelRole::Display) { switch (index.column()) { case Column::BigIcon: if (!icon_set.big_icon) return {}; return *icon_set.big_icon; case Column::LittleIcon: if (!icon_set.little_icon) return {}; return *icon_set.little_icon; case Column::Name: return icon_set.name; } VERIFY_NOT_REACHED(); } return {}; } virtual void invalidate() override { m_icon_sets.clear(); Core::DirIterator big_iterator("/res/icons/32x32", Core::DirIterator::Flags::SkipDots); while (big_iterator.has_next()) { auto path = big_iterator.next_full_path(); if (!path.contains("filetype-"sv) && !path.contains("app-"sv)) continue; IconSet icon_set; icon_set.big_icon = Gfx::Bitmap::load_from_file(path).release_value_but_fixme_should_propagate_errors(); icon_set.name = LexicalPath::basename(path); m_icon_sets.append(move(icon_set)); } auto big_icons_found = m_icon_sets.size(); Core::DirIterator little_iterator("/res/icons/16x16", Core::DirIterator::Flags::SkipDots); while (little_iterator.has_next()) { auto path = little_iterator.next_full_path(); if (!path.contains("filetype-"sv) && !path.contains("app-"sv)) continue; IconSet icon_set; icon_set.little_icon = Gfx::Bitmap::load_from_file(path).release_value_but_fixme_should_propagate_errors(); icon_set.name = LexicalPath::basename(path); for (size_t i = 0; i < big_icons_found; i++) { if (icon_set.name == m_icon_sets[i].name) { m_icon_sets[i].little_icon = icon_set.little_icon; goto next_iteration; } } m_icon_sets.append(move(icon_set)); next_iteration: continue; } Model::invalidate(); } private: FileIconsModel() = default; struct IconSet { RefPtr big_icon; RefPtr little_icon; DeprecatedString name; }; Vector m_icon_sets; };