mirror of
https://github.com/zhenyan121/Cubed.git
synced 2026-08-09 02:07:04 +08:00
Compare commits
5 Commits
f397143e30
...
0919faa3e4
| Author | SHA1 | Date | |
|---|---|---|---|
| 0919faa3e4 | |||
| d9b4b42f74 | |||
| d7cb178c2b | |||
| 4fef8e195a | |||
| 5f60910aeb |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -14,6 +14,7 @@
|
|||||||
*.pch
|
*.pch
|
||||||
*.sbr
|
*.sbr
|
||||||
build/
|
build/
|
||||||
|
build_debug/
|
||||||
Build/
|
Build/
|
||||||
bin/
|
bin/
|
||||||
Debug/
|
Debug/
|
||||||
|
|||||||
@@ -48,5 +48,9 @@
|
|||||||
"item.stone.name": "stone",
|
"item.stone.name": "stone",
|
||||||
"item.water.name": "water",
|
"item.water.name": "water",
|
||||||
"item.pig_spawn_egg.name": "pig spawn egg",
|
"item.pig_spawn_egg.name": "pig spawn egg",
|
||||||
"screenshot.no_screenshot": "No Screenshot"
|
"screenshot.no_screenshot": "No Screenshot",
|
||||||
|
"button.show_in_file_manager": "Show In File Manager",
|
||||||
|
"file.sort_type": "File Sort Type: {type}",
|
||||||
|
"file.newest_first": "Newest First",
|
||||||
|
"file.oldest_first": "Oldest First"
|
||||||
}
|
}
|
||||||
@@ -48,5 +48,9 @@
|
|||||||
"item.stone.name": "石头",
|
"item.stone.name": "石头",
|
||||||
"item.water.name": "水",
|
"item.water.name": "水",
|
||||||
"item.pig_spawn_egg.name": "猪猪刷怪蛋",
|
"item.pig_spawn_egg.name": "猪猪刷怪蛋",
|
||||||
"screenshot.no_screenshot": "没有截图"
|
"screenshot.no_screenshot": "没有截图",
|
||||||
|
"button.show_in_file_manager": "在文件管理器中显示",
|
||||||
|
"file.sort_type": "文件排序方式:{type}",
|
||||||
|
"file.newest_first": "最新在前",
|
||||||
|
"file.oldest_first": "最旧在前"
|
||||||
}
|
}
|
||||||
@@ -7,6 +7,7 @@
|
|||||||
#include <tbb/concurrent_hash_map.h>
|
#include <tbb/concurrent_hash_map.h>
|
||||||
#include <tbb/concurrent_queue.h>
|
#include <tbb/concurrent_queue.h>
|
||||||
#include <tbb/concurrent_vector.h>
|
#include <tbb/concurrent_vector.h>
|
||||||
|
#include <variant>
|
||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
class ServerWorld;
|
class ServerWorld;
|
||||||
class Session;
|
class Session;
|
||||||
|
|||||||
66
include/Cubed/tools/file_utils.hpp
Normal file
66
include/Cubed/tools/file_utils.hpp
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "Cubed/tools/log.hpp"
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
// clang-format off
|
||||||
|
#include <windows.h>
|
||||||
|
#include <shellapi.h>
|
||||||
|
// clang-format on
|
||||||
|
#elif __linux__
|
||||||
|
#include <cstdlib>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Cubed::Tools {
|
||||||
|
|
||||||
|
inline void open_file_manager(const std::filesystem::path& path) {
|
||||||
|
#ifdef _WIN32
|
||||||
|
auto abs_path = std::filesystem::absolute(path);
|
||||||
|
if (!std::filesystem::exists(abs_path)) {
|
||||||
|
Logger::warn("Path does not exist: {}", abs_path.string());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
HINSTANCE result =
|
||||||
|
ShellExecuteW(nullptr, L"open", abs_path.wstring().c_str(), nullptr,
|
||||||
|
nullptr, SW_SHOWNORMAL);
|
||||||
|
if ((INT_PTR)result <= 32) {
|
||||||
|
Logger::warn("ShellExecuteW failed for path: {}, error code: {}",
|
||||||
|
path.string(), (int)(INT_PTR)result);
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif __linux__
|
||||||
|
|
||||||
|
constexpr const char* FILE_MANAGERS[] = {"nautilus", "dolphin", "thunar",
|
||||||
|
"nemo", "pcmanfm"};
|
||||||
|
|
||||||
|
auto is_available = [](const char* exe) {
|
||||||
|
std::string cmd = std::string("command -v ") + exe + " >/dev/null 2>&1";
|
||||||
|
return std::system(cmd.c_str()) == 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
const std::string QUOTED = "\"" + path.string() + "\"";
|
||||||
|
for (const char* fm : FILE_MANAGERS) {
|
||||||
|
if (!is_available(fm)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
std::string cmd = std::string(fm) + " " + QUOTED + " >/dev/null 2>&1 &";
|
||||||
|
if (std::system(cmd.c_str()) == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback: let the system choose a handler.
|
||||||
|
if (is_available("xdg-open")) {
|
||||||
|
std::string cmd = "xdg-open " + QUOTED + " >/dev/null 2>&1 &";
|
||||||
|
if (std::system(cmd.c_str()) == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger::warn("Failed to open file manager for {}", path.string());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Cubed::Tools
|
||||||
@@ -1,8 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <rapidjson/document.h>
|
#include <rapidjson/document.h>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
class SensitiveFilter {
|
class SensitiveFilter {
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ public:
|
|||||||
Button& set_background_image(const std::string& path,
|
Button& set_background_image(const std::string& path,
|
||||||
TextureManager& texture_manager);
|
TextureManager& texture_manager);
|
||||||
Button& set_default_image(TextureManager& texture_manager);
|
Button& set_default_image(TextureManager& texture_manager);
|
||||||
|
Button& set_texture(const Texture* texture, bool change_button_size);
|
||||||
virtual Button& set_text(const std::string& text);
|
virtual Button& set_text(const std::string& text);
|
||||||
|
|
||||||
Button& set_auto_scale(bool auto_scale);
|
Button& set_auto_scale(bool auto_scale);
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "Cubed/ui/image.hpp"
|
||||||
#include "Cubed/ui/ui_manager.hpp"
|
#include "Cubed/ui/ui_manager.hpp"
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
|
class Texture;
|
||||||
class ScreenshotScene;
|
class ScreenshotScene;
|
||||||
class ScreenshotUI : public UIManager {
|
class ScreenshotUI : public UIManager {
|
||||||
public:
|
public:
|
||||||
@@ -17,9 +21,29 @@ public:
|
|||||||
|
|
||||||
void update_layout(int width, int height);
|
void update_layout(int width, int height);
|
||||||
|
|
||||||
|
void open_lightbox(const Texture* image);
|
||||||
|
void update(float dt) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool handle_window_resize_event(const WindowResizeEvent& e) override;
|
struct ImageInfo {
|
||||||
|
const Texture* texture = nullptr;
|
||||||
|
int width = 0;
|
||||||
|
int height = 0;
|
||||||
|
std::chrono::nanoseconds time{0};
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class SortType { NEWEST_FIRST, OLDEST_FIRST };
|
||||||
|
|
||||||
ScreenshotScene& m_scene;
|
ScreenshotScene& m_scene;
|
||||||
|
std::vector<ImageInfo> m_image_infos;
|
||||||
|
SortType m_sort_type = SortType::NEWEST_FIRST;
|
||||||
|
bool m_need_rebuild = false;
|
||||||
|
Widget* m_lightbox = nullptr;
|
||||||
|
Image* m_lightbox_image = nullptr;
|
||||||
|
bool handle_window_resize_event(const WindowResizeEvent& e) override;
|
||||||
|
bool handle_key_event(const KeyEvent& e) override;
|
||||||
|
bool handle_mouse_button_event(const MouseButtonEvent& e) override;
|
||||||
|
bool handle_mouse_move_event(const MouseMoveEvent& e) override;
|
||||||
|
bool handle_mouse_wheel_event(const MouseWheelEvent& e) override;
|
||||||
};
|
};
|
||||||
} // namespace Cubed
|
} // namespace Cubed
|
||||||
@@ -28,6 +28,11 @@ public:
|
|||||||
Widget& operator=(Widget&&) = delete;
|
Widget& operator=(Widget&&) = delete;
|
||||||
|
|
||||||
Widget(Widget* parent);
|
Widget(Widget* parent);
|
||||||
|
|
||||||
|
static void set_window_size(int width, int height);
|
||||||
|
static int get_window_height();
|
||||||
|
static int get_window_width();
|
||||||
|
|
||||||
virtual ~Widget() = default;
|
virtual ~Widget() = default;
|
||||||
virtual void update(float dt);
|
virtual void update(float dt);
|
||||||
virtual void render(Renderer& renderer);
|
virtual void render(Renderer& renderer);
|
||||||
@@ -35,7 +40,7 @@ public:
|
|||||||
virtual Widget& set_offset(glm::vec2 offset);
|
virtual Widget& set_offset(glm::vec2 offset);
|
||||||
virtual Widget& add_offset(glm::vec2 offset);
|
virtual Widget& add_offset(glm::vec2 offset);
|
||||||
virtual glm::vec2 get_offset() const;
|
virtual glm::vec2 get_offset() const;
|
||||||
static void set_window_size(int width, int height);
|
|
||||||
virtual Widget& set_visible(bool visible);
|
virtual Widget& set_visible(bool visible);
|
||||||
// Returns the final display size
|
// Returns the final display size
|
||||||
|
|
||||||
@@ -58,6 +63,8 @@ public:
|
|||||||
virtual bool handle_window_resize_event(const WindowResizeEvent& e);
|
virtual bool handle_window_resize_event(const WindowResizeEvent& e);
|
||||||
virtual bool handle_mouse_move_event(const MouseMoveEvent& e);
|
virtual bool handle_mouse_move_event(const MouseMoveEvent& e);
|
||||||
virtual bool handle_text_input_event(const TextInputEvent& e);
|
virtual bool handle_text_input_event(const TextInputEvent& e);
|
||||||
|
|
||||||
|
virtual bool is_visible() const;
|
||||||
void set_order(TraversalOrder order);
|
void set_order(TraversalOrder order);
|
||||||
|
|
||||||
template <typename T, typename... Args> T& add_child(Args&&... args) {
|
template <typename T, typename... Args> T& add_child(Args&&... args) {
|
||||||
|
|||||||
@@ -187,7 +187,7 @@ void App::handle_argument(int argc, char** argv) {
|
|||||||
}},
|
}},
|
||||||
{"--enable-filelog",
|
{"--enable-filelog",
|
||||||
[&](ArgParser&) { m_argument.enable_filelog = true; }},
|
[&](ArgParser&) { m_argument.enable_filelog = true; }},
|
||||||
{"--enale-consolelog",
|
{"--enable-consolelog",
|
||||||
[&](ArgParser&) { m_argument.enable_consolelog = true; }},
|
[&](ArgParser&) { m_argument.enable_consolelog = true; }},
|
||||||
{"--direct-enter",
|
{"--direct-enter",
|
||||||
[&](ArgParser&) { m_argument.direct_enter = true; }}
|
[&](ArgParser&) { m_argument.direct_enter = true; }}
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ ModelManager::Handle ModelManager::load_model(std::string_view model_name) {
|
|||||||
auto model = m_loader.load(path);
|
auto model = m_loader.load(path);
|
||||||
fs::path anim_path = path;
|
fs::path anim_path = path;
|
||||||
anim_path = anim_path.parent_path() / "animation.json";
|
anim_path = anim_path.parent_path() / "animation.json";
|
||||||
load_anim_config(model, anim_path);
|
load_anim_config(model, anim_path.string());
|
||||||
ModelMap::accessor acc;
|
ModelMap::accessor acc;
|
||||||
if (m_models.insert(acc, m_next++)) {
|
if (m_models.insert(acc, m_next++)) {
|
||||||
acc->second = std::move(model);
|
acc->second = std::move(model);
|
||||||
|
|||||||
@@ -311,11 +311,11 @@ void Renderer::handle_screenshot() {
|
|||||||
fs::create_directories(path);
|
fs::create_directories(path);
|
||||||
fs::path image =
|
fs::path image =
|
||||||
path / std::format("screenshot {}.png", Tools::get_time_date_str());
|
path / std::format("screenshot {}.png", Tools::get_time_date_str());
|
||||||
if (!stbi_write_png(image.c_str(), width, height, 4, flipped_pixels.data(),
|
if (!stbi_write_png(image.string().c_str(), width, height, 4,
|
||||||
width * 4)) {
|
flipped_pixels.data(), width * 4)) {
|
||||||
Logger::error("Failed to write {} image", image.c_str());
|
Logger::error("Failed to write {} image", image.string());
|
||||||
} else {
|
} else {
|
||||||
Logger::info("save {} success!", image.c_str());
|
Logger::info("save {} success!", image.string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -184,7 +184,7 @@ ImageData load_image_data(const std::string& tex_image_path, bool check_exist,
|
|||||||
path = ASSETS_PATH + tex_image_path;
|
path = ASSETS_PATH + tex_image_path;
|
||||||
}
|
}
|
||||||
if (check_exist) {
|
if (check_exist) {
|
||||||
ASSERT_MSG(fs::is_regular_file(path), path.c_str());
|
ASSERT_MSG(fs::is_regular_file(path), path.string().c_str());
|
||||||
}
|
}
|
||||||
unsigned char* data = nullptr;
|
unsigned char* data = nullptr;
|
||||||
int width, height, channels;
|
int width, height, channels;
|
||||||
|
|||||||
@@ -103,7 +103,18 @@ Button& Button::set_background_image(const std::string& path,
|
|||||||
Button& Button::set_default_image(TextureManager& texture_manager) {
|
Button& Button::set_default_image(TextureManager& texture_manager) {
|
||||||
return set_background_image(DEFAULT_BUTTON_IMAGE, texture_manager);
|
return set_background_image(DEFAULT_BUTTON_IMAGE, texture_manager);
|
||||||
}
|
}
|
||||||
|
Button& Button::set_texture(const Texture* texture, bool change_button_size) {
|
||||||
|
if (!texture) {
|
||||||
|
Logger::error("Button Background Image is nullptr");
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
m_background->set_texture(texture, false);
|
||||||
|
if (change_button_size) {
|
||||||
|
set_width(texture->width());
|
||||||
|
set_height(texture->height());
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
Button& Button::set_text(const std::string& text) {
|
Button& Button::set_text(const std::string& text) {
|
||||||
m_foreground->set_text(text);
|
m_foreground->set_text(text);
|
||||||
update_text_scale();
|
update_text_scale();
|
||||||
|
|||||||
@@ -41,7 +41,16 @@ void PauseMenuUIManager::init() {
|
|||||||
});
|
});
|
||||||
m_pending_enable.emplace_back(&button);
|
m_pending_enable.emplace_back(&button);
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
auto& button = layout.add_child<Button>();
|
||||||
|
button.set_default_image(texture_manager);
|
||||||
|
button.set_text(tr("menu.screenshot"));
|
||||||
|
button.set_clicked([this, &button]() {
|
||||||
|
button.set_enable(false);
|
||||||
|
m_scene.scene_manager().request_push(SceneType::SCREENSHOT);
|
||||||
|
});
|
||||||
|
m_pending_enable.emplace_back(&button);
|
||||||
|
}
|
||||||
{
|
{
|
||||||
auto& back_main = layout.add_child<Button>();
|
auto& back_main = layout.add_child<Button>();
|
||||||
|
|
||||||
|
|||||||
@@ -4,14 +4,17 @@
|
|||||||
#include "Cubed/localization.hpp"
|
#include "Cubed/localization.hpp"
|
||||||
#include "Cubed/render/renderer.hpp"
|
#include "Cubed/render/renderer.hpp"
|
||||||
#include "Cubed/scene/screenshot_scene.hpp"
|
#include "Cubed/scene/screenshot_scene.hpp"
|
||||||
|
#include "Cubed/tools/file_utils.hpp"
|
||||||
#include "Cubed/ui/button.hpp"
|
#include "Cubed/ui/button.hpp"
|
||||||
#include "Cubed/ui/column_layout.hpp"
|
#include "Cubed/ui/column_layout.hpp"
|
||||||
|
#include "Cubed/ui/combo_button.hpp"
|
||||||
#include "Cubed/ui/row_layout.hpp"
|
#include "Cubed/ui/row_layout.hpp"
|
||||||
#include "Cubed/ui/scroll_view.hpp"
|
#include "Cubed/ui/scroll_view.hpp"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
namespace {
|
namespace {
|
||||||
constexpr std::array<std::string_view, 4> IMAGE_EXT{".jpg", ".jpeg", ".png",
|
constexpr std::array<std::string_view, 4> IMAGE_EXT{".jpg", ".jpeg", ".png",
|
||||||
@@ -27,6 +30,9 @@ void ScreenshotUI::init() {
|
|||||||
update_layout(renderer.window_width(), renderer.window_height());
|
update_layout(renderer.window_width(), renderer.window_height());
|
||||||
}
|
}
|
||||||
void ScreenshotUI::update_layout(int width, int height) {
|
void ScreenshotUI::update_layout(int width, int height) {
|
||||||
|
|
||||||
|
m_image_infos.clear();
|
||||||
|
|
||||||
auto& texture_manager = m_scene.scene_manager().app().texture_manager();
|
auto& texture_manager = m_scene.scene_manager().app().texture_manager();
|
||||||
m_root_widget.reset();
|
m_root_widget.reset();
|
||||||
auto bg = std::make_unique<Rect>(nullptr);
|
auto bg = std::make_unique<Rect>(nullptr);
|
||||||
@@ -37,40 +43,39 @@ void ScreenshotUI::update_layout(int width, int height) {
|
|||||||
|
|
||||||
title.set_text(tr("menu.screenshot")).set_anchor(Anchor::TOP_CENTER);
|
title.set_text(tr("menu.screenshot")).set_anchor(Anchor::TOP_CENTER);
|
||||||
title.set_offset({0, 5});
|
title.set_offset({0, 5});
|
||||||
struct ImageInfo {
|
|
||||||
const Texture* texture = nullptr;
|
|
||||||
int width = 0;
|
|
||||||
int height = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
auto& return_button = bg->add_child<Button>();
|
|
||||||
return_button.set_default_image(texture_manager);
|
|
||||||
return_button.set_anchor(Anchor::BOTTOM_CENTER);
|
|
||||||
return_button.set_offset({0, -30});
|
|
||||||
return_button.set_text(tr("button.return"));
|
|
||||||
return_button.set_clicked(
|
|
||||||
[this]() { m_scene.scene_manager().request_pop(); });
|
|
||||||
|
|
||||||
fs::path path = Renderer::SCREENSHOT_PATH;
|
fs::path path = Renderer::SCREENSHOT_PATH;
|
||||||
|
|
||||||
std::vector<ImageInfo> image_infos;
|
|
||||||
constexpr float IMAGE_SCALE = 0.25;
|
constexpr float IMAGE_SCALE = 0.25;
|
||||||
|
ScrollView* sv = nullptr;
|
||||||
|
fs::create_directories(path);
|
||||||
if (fs::exists(path)) {
|
if (fs::exists(path)) {
|
||||||
for (auto& entry : fs::recursive_directory_iterator(path)) {
|
for (auto& entry : fs::recursive_directory_iterator(path)) {
|
||||||
if (!fs::is_regular_file(entry)) {
|
if (!fs::is_regular_file(entry)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!std::ranges::find(IMAGE_EXT, entry.path().extension())) {
|
if (std::ranges::find(IMAGE_EXT, entry.path().extension()) ==
|
||||||
|
IMAGE_EXT.end()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ImageInfo info;
|
ImageInfo info;
|
||||||
Logger::info("Path: {}", entry.path().string());
|
|
||||||
info.texture =
|
info.texture =
|
||||||
texture_manager.get_image_texture(entry.path().string(), true);
|
texture_manager.get_image_texture(entry.path().string(), true);
|
||||||
|
info.texture->set_linear();
|
||||||
info.height = info.texture->height() * IMAGE_SCALE;
|
info.height = info.texture->height() * IMAGE_SCALE;
|
||||||
info.width = info.texture->width() * IMAGE_SCALE;
|
info.width = info.texture->width() * IMAGE_SCALE;
|
||||||
image_infos.emplace_back(std::move(info));
|
std::error_code ec;
|
||||||
|
auto ftime = fs::last_write_time(entry, ec);
|
||||||
|
if (!ec) {
|
||||||
|
auto sys_time =
|
||||||
|
std::chrono::clock_cast<std::chrono::system_clock>(ftime);
|
||||||
|
info.time =
|
||||||
|
std::chrono::time_point_cast<std::chrono::nanoseconds>(
|
||||||
|
sys_time)
|
||||||
|
.time_since_epoch();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_image_infos.emplace_back(std::move(info));
|
||||||
}
|
}
|
||||||
constexpr int PADDING = 50;
|
constexpr int PADDING = 50;
|
||||||
constexpr int SPACING = 10;
|
constexpr int SPACING = 10;
|
||||||
@@ -81,14 +86,11 @@ void ScreenshotUI::update_layout(int width, int height) {
|
|||||||
|
|
||||||
auto& scroll = bg->add_child<ScrollView>();
|
auto& scroll = bg->add_child<ScrollView>();
|
||||||
|
|
||||||
|
sv = &scroll;
|
||||||
|
|
||||||
scroll.set_anchor(Anchor::TOP_CENTER)
|
scroll.set_anchor(Anchor::TOP_CENTER)
|
||||||
.set_offset({0, 10 + title.height()});
|
.set_offset({0, 10 + title.height()});
|
||||||
|
|
||||||
float scroll_height = height - scroll.get_offset().y +
|
|
||||||
return_button.get_offset().y -
|
|
||||||
return_button.height();
|
|
||||||
|
|
||||||
scroll.set_height(std::max(0.0f, scroll_height));
|
|
||||||
auto root_column = std::make_unique<ColumnLayout>(&scroll);
|
auto root_column = std::make_unique<ColumnLayout>(&scroll);
|
||||||
root_column->set_child_anchor(ColumnLayoutAnchor::LEFT)
|
root_column->set_child_anchor(ColumnLayoutAnchor::LEFT)
|
||||||
.set_spacing(10)
|
.set_spacing(10)
|
||||||
@@ -100,7 +102,19 @@ void ScreenshotUI::update_layout(int width, int height) {
|
|||||||
row->set_spacing(SPACING);
|
row->set_spacing(SPACING);
|
||||||
};
|
};
|
||||||
|
|
||||||
for (auto& image : image_infos) {
|
std::sort(m_image_infos.begin(), m_image_infos.end(),
|
||||||
|
[this](const ImageInfo& a, const ImageInfo& b) {
|
||||||
|
switch (m_sort_type) {
|
||||||
|
case SortType::NEWEST_FIRST:
|
||||||
|
return a.time > b.time;
|
||||||
|
case SortType::OLDEST_FIRST:
|
||||||
|
return a.time < b.time;
|
||||||
|
default:
|
||||||
|
return a.time > b.time;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
for (auto& image : m_image_infos) {
|
||||||
if (!row) {
|
if (!row) {
|
||||||
create_row();
|
create_row();
|
||||||
}
|
}
|
||||||
@@ -110,24 +124,154 @@ void ScreenshotUI::update_layout(int width, int height) {
|
|||||||
create_row();
|
create_row();
|
||||||
}
|
}
|
||||||
cur_width += image.width;
|
cur_width += image.width;
|
||||||
auto& im = row->add_child<Image>();
|
auto& button = row->add_child<Button>();
|
||||||
im.set_texture(image.texture, true).set_scale(IMAGE_SCALE);
|
button.set_texture(image.texture, true).set_scale(IMAGE_SCALE);
|
||||||
|
button.set_clicked(
|
||||||
|
[image, this]() { open_lightbox(image.texture); });
|
||||||
}
|
}
|
||||||
scroll.set_child(std::move(root_column));
|
scroll.set_child(std::move(root_column));
|
||||||
}
|
}
|
||||||
if (!fs::exists(path) || image_infos.empty()) {
|
if (!fs::exists(path) || m_image_infos.empty()) {
|
||||||
auto& label = bg->add_child<Label>();
|
auto& label = bg->add_child<Label>();
|
||||||
label.set_text(tr("screenshot.no_screenshot"))
|
label.set_text(tr("screenshot.no_screenshot"))
|
||||||
.set_color(Color::WHITE)
|
.set_color(Color::WHITE)
|
||||||
.set_anchor(Anchor::CENTER);
|
.set_anchor(Anchor::CENTER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto& combo = bg->add_child<ComboButton>();
|
||||||
|
combo.set_anchor(Anchor::TOP_RIGHT);
|
||||||
|
combo.set_offset(title.get_offset());
|
||||||
|
|
||||||
|
switch (m_sort_type) {
|
||||||
|
case SortType::NEWEST_FIRST:
|
||||||
|
combo.set_index(0);
|
||||||
|
break;
|
||||||
|
case SortType::OLDEST_FIRST:
|
||||||
|
combo.set_index(1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
combo.set_index(0);
|
||||||
|
}
|
||||||
|
combo.set_combo_text("file.sort_type", "type");
|
||||||
|
std::vector<ComboPair> combos;
|
||||||
|
|
||||||
|
combos.emplace_back(tr("file.newest_first"), [this]() {
|
||||||
|
m_sort_type = SortType::NEWEST_FIRST;
|
||||||
|
m_need_rebuild = true;
|
||||||
|
});
|
||||||
|
combos.emplace_back(tr("file.oldest_first"), [this]() {
|
||||||
|
m_sort_type = SortType::OLDEST_FIRST;
|
||||||
|
m_need_rebuild = true;
|
||||||
|
});
|
||||||
|
combo.set_default_image(texture_manager);
|
||||||
|
combo.set_combos(combos);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& bottom_row = bg->add_child<RowLayout>();
|
||||||
|
bottom_row.set_spacing(10);
|
||||||
|
bottom_row.set_anchor(Anchor::BOTTOM_CENTER).set_offset({0, -30});
|
||||||
|
|
||||||
|
auto& open_file = bottom_row.add_child<Button>();
|
||||||
|
open_file.set_default_image(texture_manager)
|
||||||
|
.set_text(tr("button.show_in_file_manager"))
|
||||||
|
.set_clicked(
|
||||||
|
[]() { Tools::open_file_manager(Renderer::SCREENSHOT_PATH); });
|
||||||
|
|
||||||
|
auto& return_button = bottom_row.add_child<Button>();
|
||||||
|
return_button.set_default_image(texture_manager);
|
||||||
|
return_button.set_text(tr("button.return"));
|
||||||
|
return_button.set_clicked(
|
||||||
|
[this]() { m_scene.scene_manager().request_pop(); });
|
||||||
|
if (sv) {
|
||||||
|
float scroll_height = height - sv->get_offset().y +
|
||||||
|
bottom_row.get_offset().y -
|
||||||
|
return_button.height();
|
||||||
|
|
||||||
|
sv->set_height(std::max(0.0f, scroll_height));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& rect = bg->add_child<Rect>();
|
||||||
|
rect.set_fill_parent(true);
|
||||||
|
rect.set_color(Color::BLACK).set_alpha(0.5f);
|
||||||
|
m_lightbox = ▭
|
||||||
|
auto& lightbox_image = rect.add_child<Image>();
|
||||||
|
m_lightbox_image = &lightbox_image;
|
||||||
|
m_lightbox->set_visible(false);
|
||||||
m_root_widget = std::move(bg);
|
m_root_widget = std::move(bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ScreenshotUI::open_lightbox(const Texture* image) {
|
||||||
|
if (image) {
|
||||||
|
constexpr float PADDING = 50.0f;
|
||||||
|
m_lightbox_image->set_texture(image, true);
|
||||||
|
|
||||||
|
float target_height =
|
||||||
|
std::max(50.0f, Widget::get_window_height() - PADDING * 2);
|
||||||
|
float target_width =
|
||||||
|
std::max(50.0f, Widget::get_window_width() - PADDING * 2);
|
||||||
|
|
||||||
|
float image_width = image->width();
|
||||||
|
float image_height = image->height();
|
||||||
|
|
||||||
|
float scale_w = target_width / image_width;
|
||||||
|
float scale_h = target_height / image_height;
|
||||||
|
float scale = std::min(scale_h, scale_w);
|
||||||
|
m_lightbox_image->set_scale(scale);
|
||||||
|
m_lightbox_image->set_anchor(Anchor::CENTER);
|
||||||
|
}
|
||||||
|
m_lightbox->set_visible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScreenshotUI::update(float dt) {
|
||||||
|
|
||||||
|
if (m_need_rebuild) {
|
||||||
|
m_need_rebuild = false;
|
||||||
|
update_layout(Widget::get_window_width(), Widget::get_window_height());
|
||||||
|
}
|
||||||
|
UIManager::update(dt);
|
||||||
|
}
|
||||||
|
|
||||||
bool ScreenshotUI::handle_window_resize_event(const WindowResizeEvent& e) {
|
bool ScreenshotUI::handle_window_resize_event(const WindowResizeEvent& e) {
|
||||||
update_layout(e.width, e.height);
|
update_layout(e.width, e.height);
|
||||||
return UIManager::handle_window_resize_event(e);
|
return UIManager::handle_window_resize_event(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ScreenshotUI::handle_key_event(const KeyEvent& e) {
|
||||||
|
if (UIManager::handle_key_event(e)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (e.key == Key::ESCAPE && e.action == KeyAction::PRESS) {
|
||||||
|
if (m_lightbox && m_lightbox->is_visible()) {
|
||||||
|
m_lightbox->set_visible(false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
m_scene.scene_manager().request_pop();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ScreenshotUI::handle_mouse_button_event(const MouseButtonEvent& e) {
|
||||||
|
if (m_lightbox && m_lightbox->is_visible()) {
|
||||||
|
if (e.key == MouseKey::LEFT_BUTTON && e.action == KeyAction::PRESS) {
|
||||||
|
m_lightbox->set_visible(false);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return UIManager::handle_mouse_button_event(e);
|
||||||
|
}
|
||||||
|
bool ScreenshotUI::handle_mouse_move_event(const MouseMoveEvent& e) {
|
||||||
|
if (m_lightbox && m_lightbox->is_visible()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return UIManager::handle_mouse_move_event(e);
|
||||||
|
}
|
||||||
|
bool ScreenshotUI::handle_mouse_wheel_event(const MouseWheelEvent& e) {
|
||||||
|
if (m_lightbox && m_lightbox->is_visible()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return UIManager::handle_mouse_wheel_event(e);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Cubed
|
} // namespace Cubed
|
||||||
@@ -174,6 +174,9 @@ void Widget::set_window_size(int width, int height) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Widget::get_window_height() { return m_window_height; }
|
||||||
|
int Widget::get_window_width() { return m_window_width; }
|
||||||
|
|
||||||
Widget& Widget::set_visible(bool visible) {
|
Widget& Widget::set_visible(bool visible) {
|
||||||
m_visible = visible;
|
m_visible = visible;
|
||||||
return *this;
|
return *this;
|
||||||
@@ -335,4 +338,5 @@ bool Widget::handle_text_input_event(const TextInputEvent& e) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
void Widget::set_order(TraversalOrder order) { m_order = order; }
|
void Widget::set_order(TraversalOrder order) { m_order = order; }
|
||||||
|
bool Widget::is_visible() const { return m_visible; }
|
||||||
} // namespace Cubed
|
} // namespace Cubed
|
||||||
Reference in New Issue
Block a user