mirror of
https://github.com/zhenyan121/Cubed.git
synced 2026-08-08 17:57:02 +08:00
feat(ui): add lightbox viewer for screenshots
Add a lightbox to preview screenshots on click. Introduce Button::set_texture for image-backed buttons, add widget getters for window size and visibility, and block background input while the lightbox is open. Close the lightbox with Escape or a left-click.
This commit is contained in:
@@ -28,6 +28,7 @@ public:
|
||||
Button& set_background_image(const std::string& path,
|
||||
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);
|
||||
|
||||
Button& set_auto_scale(bool auto_scale);
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "Cubed/ui/image.hpp"
|
||||
#include "Cubed/ui/ui_manager.hpp"
|
||||
namespace Cubed {
|
||||
class Texture;
|
||||
class ScreenshotScene;
|
||||
class ScreenshotUI : public UIManager {
|
||||
public:
|
||||
@@ -17,9 +19,23 @@ public:
|
||||
|
||||
void update_layout(int width, int height);
|
||||
|
||||
void open_lightbox(const Texture* image);
|
||||
|
||||
private:
|
||||
bool handle_window_resize_event(const WindowResizeEvent& e) override;
|
||||
struct ImageInfo {
|
||||
const Texture* texture = nullptr;
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
};
|
||||
|
||||
ScreenshotScene& m_scene;
|
||||
std::vector<ImageInfo> m_image_infos;
|
||||
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
|
||||
@@ -28,6 +28,11 @@ public:
|
||||
Widget& operator=(Widget&&) = delete;
|
||||
|
||||
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 void update(float dt);
|
||||
virtual void render(Renderer& renderer);
|
||||
@@ -35,7 +40,7 @@ public:
|
||||
virtual Widget& set_offset(glm::vec2 offset);
|
||||
virtual Widget& add_offset(glm::vec2 offset);
|
||||
virtual glm::vec2 get_offset() const;
|
||||
static void set_window_size(int width, int height);
|
||||
|
||||
virtual Widget& set_visible(bool visible);
|
||||
// Returns the final display size
|
||||
|
||||
@@ -58,6 +63,8 @@ public:
|
||||
virtual bool handle_window_resize_event(const WindowResizeEvent& e);
|
||||
virtual bool handle_mouse_move_event(const MouseMoveEvent& e);
|
||||
virtual bool handle_text_input_event(const TextInputEvent& e);
|
||||
|
||||
virtual bool is_visible() const;
|
||||
void set_order(TraversalOrder order);
|
||||
|
||||
template <typename T, typename... Args> T& add_child(Args&&... args) {
|
||||
|
||||
@@ -103,7 +103,18 @@ Button& Button::set_background_image(const std::string& path,
|
||||
Button& Button::set_default_image(TextureManager& 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) {
|
||||
m_foreground->set_text(text);
|
||||
update_text_scale();
|
||||
|
||||
@@ -27,6 +27,9 @@ void ScreenshotUI::init() {
|
||||
update_layout(renderer.window_width(), renderer.window_height());
|
||||
}
|
||||
void ScreenshotUI::update_layout(int width, int height) {
|
||||
|
||||
m_image_infos.clear();
|
||||
|
||||
auto& texture_manager = m_scene.scene_manager().app().texture_manager();
|
||||
m_root_widget.reset();
|
||||
auto bg = std::make_unique<Rect>(nullptr);
|
||||
@@ -37,25 +40,11 @@ void ScreenshotUI::update_layout(int width, int height) {
|
||||
|
||||
title.set_text(tr("menu.screenshot")).set_anchor(Anchor::TOP_CENTER);
|
||||
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;
|
||||
|
||||
std::vector<ImageInfo> image_infos;
|
||||
constexpr float IMAGE_SCALE = 0.25;
|
||||
|
||||
ScrollView* sv = nullptr;
|
||||
if (fs::exists(path)) {
|
||||
for (auto& entry : fs::recursive_directory_iterator(path)) {
|
||||
if (!fs::is_regular_file(entry)) {
|
||||
@@ -65,12 +54,11 @@ void ScreenshotUI::update_layout(int width, int height) {
|
||||
continue;
|
||||
}
|
||||
ImageInfo info;
|
||||
Logger::info("Path: {}", entry.path().string());
|
||||
info.texture =
|
||||
texture_manager.get_image_texture(entry.path().string(), true);
|
||||
info.height = info.texture->height() * IMAGE_SCALE;
|
||||
info.width = info.texture->width() * IMAGE_SCALE;
|
||||
image_infos.emplace_back(std::move(info));
|
||||
m_image_infos.emplace_back(std::move(info));
|
||||
}
|
||||
constexpr int PADDING = 50;
|
||||
constexpr int SPACING = 10;
|
||||
@@ -81,14 +69,11 @@ void ScreenshotUI::update_layout(int width, int height) {
|
||||
|
||||
auto& scroll = bg->add_child<ScrollView>();
|
||||
|
||||
sv = &scroll;
|
||||
|
||||
scroll.set_anchor(Anchor::TOP_CENTER)
|
||||
.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);
|
||||
root_column->set_child_anchor(ColumnLayoutAnchor::LEFT)
|
||||
.set_spacing(10)
|
||||
@@ -100,7 +85,7 @@ void ScreenshotUI::update_layout(int width, int height) {
|
||||
row->set_spacing(SPACING);
|
||||
};
|
||||
|
||||
for (auto& image : image_infos) {
|
||||
for (auto& image : m_image_infos) {
|
||||
if (!row) {
|
||||
create_row();
|
||||
}
|
||||
@@ -110,24 +95,105 @@ void ScreenshotUI::update_layout(int width, int height) {
|
||||
create_row();
|
||||
}
|
||||
cur_width += image.width;
|
||||
auto& im = row->add_child<Image>();
|
||||
im.set_texture(image.texture, true).set_scale(IMAGE_SCALE);
|
||||
auto& button = row->add_child<Button>();
|
||||
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));
|
||||
}
|
||||
if (!fs::exists(path) || image_infos.empty()) {
|
||||
if (!fs::exists(path) || m_image_infos.empty()) {
|
||||
auto& label = bg->add_child<Label>();
|
||||
label.set_text(tr("screenshot.no_screenshot"))
|
||||
.set_color(Color::WHITE)
|
||||
.set_anchor(Anchor::CENTER);
|
||||
}
|
||||
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(); });
|
||||
if (sv) {
|
||||
float scroll_height = height - sv->get_offset().y +
|
||||
return_button.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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
bool ScreenshotUI::handle_window_resize_event(const WindowResizeEvent& e) {
|
||||
update_layout(e.width, e.height);
|
||||
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
|
||||
@@ -174,6 +174,9 @@ void Widget::set_window_size(int width, int height) {
|
||||
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) {
|
||||
m_visible = visible;
|
||||
return *this;
|
||||
@@ -335,4 +338,5 @@ bool Widget::handle_text_input_event(const TextInputEvent& e) {
|
||||
return false;
|
||||
}
|
||||
void Widget::set_order(TraversalOrder order) { m_order = order; }
|
||||
bool Widget::is_visible() const { return m_visible; }
|
||||
} // namespace Cubed
|
||||
Reference in New Issue
Block a user