Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Display world screenshot previews and progress #2349

Open
wants to merge 34 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
19b45a5
Display world screenshot previews and progress
Vankata453 Dec 4, 2022
058899e
Move preview functionality to menus and menu items
Vankata453 Dec 12, 2022
692d5a0
Merge branch 'master' into world-previews
Vankata453 Apr 29, 2023
c38af90
FileSystemMenu now shows previews of images
Vankata453 Apr 29, 2023
78094b3
Cast integers to floats when generating preview rect
Vankata453 Apr 29, 2023
24dc82f
Cast world entries vector size to int
Vankata453 Apr 29, 2023
5cd4f74
Merge remote-tracking branch 'supertux/master' into world-previews
Vankata453 May 20, 2023
9be8c3d
Don't fade in/out previews when transitions are disabled
Vankata453 May 20, 2023
bbd65fe
Merge branch 'master' into world-previews
Vankata453 May 24, 2023
9a9d115
Merge remote-tracking branch 'supertux/master' into world-previews
Vankata453 Jul 27, 2023
c0ba8e5
Remove some header includes
Vankata453 Jul 27, 2023
3c5ecec
Show progress percentage for worlds
Vankata453 Aug 2, 2023
7cdf956
General code improvements
Vankata453 Aug 5, 2023
062c452
Get level progress from savefile level tables
Vankata453 Aug 5, 2023
827d922
Allow toggling world previews functionality
Vankata453 Aug 5, 2023
1149313
Use unsigned integers for storing progress
Vankata453 Aug 6, 2023
8a23ab0
Add `<sstream>` include
Vankata453 Aug 6, 2023
91ea207
Do not draw menu item previews, if preview overlaps the menu
Vankata453 Aug 6, 2023
17e2259
`WorldMapState` now loads/saves state for all sectors
Vankata453 Aug 6, 2023
08efd94
Merge branch 'master' into world-previews
Vankata453 Oct 27, 2023
3c421d5
Fix macro `;` warning
Vankata453 Nov 18, 2023
41bed28
Merge remote-tracking branch 'supertux/master' into world-previews
Vankata453 Jul 13, 2024
492395c
Fix issues displaying world previews
Vankata453 Jul 14, 2024
78df407
Code fixes [ci skip]
Vankata453 Jul 14, 2024
d8a7c73
Align menu help text to screen center
Vankata453 Jul 15, 2024
9612857
Menu item image preview size is now relative to screen size
Vankata453 Jul 15, 2024
610a448
Calculate world progress percentage using perfect level states
Vankata453 Jul 16, 2024
8763b68
Draw white border around previews
Vankata453 Jul 16, 2024
026573e
Merge remote-tracking branch 'supertux/master' into world-previews
Vankata453 Nov 23, 2024
7a2edb1
Use `std::max` and `DrawingContext` size functions
Vankata453 Nov 23, 2024
82ef7a9
Fix compilation error with `std::max`
Vankata453 Nov 23, 2024
82564d4
Resize menu item preview by preserving its original aspect ratio
Vankata453 Nov 24, 2024
4006ed8
Minor code improvements
Vankata453 Nov 24, 2024
7030989
More minor code improvements
Vankata453 Nov 24, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 105 additions & 9 deletions src/gui/menu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,17 @@
#include "gui/menu_manager.hpp"
#include "gui/mousecursor.hpp"
#include "math/util.hpp"
#include "supertux/error_handler.hpp"
#include "supertux/gameconfig.hpp"
#include "supertux/globals.hpp"
#include "supertux/resources.hpp"
#include "video/drawing_context.hpp"
#include "video/renderer.hpp"
#include "video/surface.hpp"
#include "video/video_system.hpp"
#include "video/viewport.hpp"

#include "supertux/error_handler.hpp"
const float Menu::s_preview_fade_time = 0.1f;

Menu::Menu() :
m_pos(Vector(static_cast<float>(SCREEN_WIDTH) / 2.0f,
Expand All @@ -65,8 +67,14 @@ Menu::Menu() :
m_menu_help_height(0.0f),
m_items(),
m_arrange_left(0),
m_active_item(-1)
m_active_item(-1),
m_has_previews(false),
m_last_preview_item(-1),
m_preview_fade_timer(),
m_preview_fade_active(false),
m_preview_fading_out(false)
{
m_preview_fade_timer.start(g_config->transitions_enabled ? s_preview_fade_time : 0);
}

Menu::~Menu()
Expand All @@ -80,6 +88,23 @@ Menu::set_center_pos(float x, float y)
m_pos.y = y;
}

void
Menu::align_for_previews(float x_offset)
{
for (const auto& item : m_items)
{
if (item->get_preview())
{
// Adjust center position to give space for displaying previews.
set_center_pos(static_cast<float>(SCREEN_WIDTH) / 2 - get_width() / 2 - x_offset,
static_cast<float>(SCREEN_HEIGHT) / 2);
m_has_previews = true;
return;
}
}
m_has_previews = false;
}

/* Add an item to a menu */
MenuItem&
Menu::add_item(std::unique_ptr<MenuItem> new_item)
Expand Down Expand Up @@ -499,6 +524,7 @@ Menu::on_window_resize()

calculate_width();
calculate_height();
align_for_previews();

for (auto& item : m_items)
item->on_window_resize();
Expand All @@ -521,13 +547,12 @@ Menu::draw(DrawingContext& context)
const int text_width = static_cast<int>(Resources::normal_font->get_text_width(m_items[m_active_item]->get_help()));
const int text_height = static_cast<int>(Resources::normal_font->get_text_height(m_items[m_active_item]->get_help()));

const Rectf text_rect(m_pos.x - static_cast<float>(text_width) / 2.0f - 8.0f,
static_cast<float>(SCREEN_HEIGHT) - 48.0f - static_cast<float>(text_height) / 2.0f - 4.0f,
m_pos.x + static_cast<float>(text_width) / 2.0f + 8.0f,
static_cast<float>(SCREEN_HEIGHT) - 48.0f + static_cast<float>(text_height) / 2.0f + 4.0f);
const Rectf text_rect(context.get_width() / 2 - static_cast<float>(text_width) / 2.0f - 8.0f,
context.get_height() - 48.0f - static_cast<float>(text_height) / 2.0f - 4.0f,
context.get_width() / 2 + static_cast<float>(text_width) / 2.0f + 8.0f,
context.get_height() - 48.0f + static_cast<float>(text_height) / 2.0f + 4.0f);

context.color().draw_filled_rect(Rectf(text_rect.p1() - Vector(4,4),
text_rect.p2() + Vector(4,4)),
context.color().draw_filled_rect(text_rect.grown(4),
g_config->menuhelpbackcolor,
g_config->menuroundness + 4.f,
LAYER_GUI);
Expand All @@ -538,9 +563,80 @@ Menu::draw(DrawingContext& context)
LAYER_GUI);

context.color().draw_text(Resources::normal_font, m_items[m_active_item]->get_help(),
Vector(m_pos.x, static_cast<float>(SCREEN_HEIGHT) - 48.0f - static_cast<float>(text_height) / 2.0f),
Vector(context.get_width() / 2, context.get_height() - 48.0f - static_cast<float>(text_height) / 2.0f),
ALIGN_CENTER, LAYER_GUI);
}

if (m_has_previews) draw_preview(context);
}

void
Menu::draw_preview(DrawingContext& context)
{
bool valid_last_index = last_preview_index_valid();

// Update fade.
if (m_active_item != m_last_preview_item && !m_preview_fade_active) // Index has changed, there is no current fade.
{
if (valid_last_index) // Fade out only if the last index is valid.
m_preview_fade_timer.start(g_config->transitions_enabled ? s_preview_fade_time : 0.f);
m_preview_fading_out = true;
m_preview_fade_active = true;
}
float timeleft = m_preview_fade_timer.get_timeleft();
if (timeleft < 0 && m_preview_fade_active) // Current fade is over.
{
m_last_preview_item = m_active_item;
valid_last_index = last_preview_index_valid(); // Repeat valid last index check
if (m_preview_fading_out) // After a fade-out, a fade-in should follow up.
{
m_preview_fade_timer.start(g_config->transitions_enabled ? s_preview_fade_time : 0.f);
timeleft = m_preview_fade_timer.get_timeleft();
m_preview_fading_out = false;
}
else
{
m_preview_fade_active = false;
}
}

// Set alpha according to fade.
float alpha = 1.f;
if (timeleft > 0)
{
const float alpha_val = timeleft * (1.f / s_preview_fade_time);
alpha = m_preview_fading_out ? alpha_val : 1.f - alpha_val;
}

// Perform actions only if current index is a valid preview index.
if (valid_last_index)
{
// Draw progress preview of current item.
const Sizef preview_size(context.get_width() / 2.5f, context.get_height() / 2.5f);
SurfacePtr preview = m_items[m_last_preview_item]->get_preview();
Rectf preview_rect(Vector(context.get_width() * 0.73f - preview_size.width / 2,
context.get_height() / 2 - preview_size.height / 2),
Sizef(static_cast<float>(preview->get_width()),
static_cast<float>(preview->get_height())));
preview_rect.fit_centered(preview_size);

PaintStyle style;
style.set_alpha(alpha);
context.color().draw_surface_scaled(preview, preview_rect, LAYER_GUI + 1, style);

// Draw a border around the preview.
context.color().draw_filled_rect(preview_rect.grown(2.f),
Color(1.f, 1.f, 1.f, alpha), 2.f, LAYER_GUI);

// Draw other data, alongside the preview, if available.
draw_preview_data(context, preview_rect, alpha);
}
}

bool
Menu::last_preview_index_valid() const
{
return m_last_preview_item > -1 && m_items[m_last_preview_item]->get_preview();
}

MenuItem&
Expand Down
20 changes: 20 additions & 0 deletions src/gui/menu.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@
#include <SDL.h>

#include "gui/menu_action.hpp"
#include "math/rectf.hpp"
#include "math/vector.hpp"
#include "supertux/timer.hpp"
#include "video/color.hpp"
#include "video/drawing_context.hpp"

Expand Down Expand Up @@ -54,6 +56,9 @@ class PathObject;

class Menu
{
protected:
static const float s_preview_fade_time;

public:
Menu();
virtual ~Menu();
Expand Down Expand Up @@ -113,6 +118,9 @@ class Menu
/** Remove all entries from the menu */
void clear();

/** Align the menu to the left side, if any previews are available. */
void align_for_previews(float x_offset = 30.f);

MenuItem& get_item(int index) { return *(m_items[index]); }

MenuItem& get_item_by_id(int id);
Expand Down Expand Up @@ -148,9 +156,14 @@ class Menu
/** Recalculates the height for this menu */
void calculate_height();

/** Draw additional data to accompany item previews. */
virtual void draw_preview_data(DrawingContext& context, const Rectf& preview_rect, float alpha) {}

private:
void check_controlfield_change_event(const SDL_Event& event);
void draw_item(DrawingContext& context, int index, float y_pos);
void draw_preview(DrawingContext& context);
bool last_preview_index_valid() const;

private:
/** position of the menu (ie. center of the menu, not top/left) */
Expand All @@ -172,6 +185,13 @@ class Menu
protected:
int m_active_item;

/* Preview implementation variables. */
bool m_has_previews;
int m_last_preview_item;
Timer m_preview_fade_timer;
bool m_preview_fade_active;
bool m_preview_fading_out;

private:
Menu(const Menu&) = delete;
Menu& operator=(const Menu&) = delete;
Expand Down
31 changes: 26 additions & 5 deletions src/gui/menu_filesystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
#include "util/gettext.hpp"
#include "util/string_util.hpp"

static const size_t MAX_TITLE_CHARS = 30;
static const std::vector<std::string> IMAGE_EXTENSIONS = { ".jpg", ".png", ".surface" };

FileSystemMenu::FileSystemMenu(std::string* filename, const std::vector<std::string>& extensions,
const std::string& basedir, bool path_relative_to_basedir, std::function<void(const std::string&)> callback,
const std::function<void (MenuItem&)>& item_processor) :
Expand Down Expand Up @@ -65,7 +68,13 @@ FileSystemMenu::refresh_items()
m_files.clear();
m_directory = FileSystem::normalize(m_directory);

add_label(m_directory);
// Make sure label doesn't get too long.
std::string title = m_directory;
const bool title_large = title.size() > MAX_TITLE_CHARS;
while (title.size() > MAX_TITLE_CHARS)
title = title.substr(title.size() - MAX_TITLE_CHARS);

add_label((title_large ? "..." : "") + title);
add_hl();

int item_id = 0;
Expand Down Expand Up @@ -108,8 +117,11 @@ FileSystemMenu::refresh_items()
for (const auto& item : m_files)
{
MenuItem& menu_item = add_entry(item_id, item);

if (in_basedir && m_item_processor)
m_item_processor(menu_item);
if (is_image(item))
menu_item.set_preview(FileSystem::join(m_directory, item));

item_id++;
}
Expand All @@ -123,6 +135,7 @@ FileSystemMenu::refresh_items()

// Re-center menu
on_window_resize();
align_for_previews(25.f);
}

bool
Expand All @@ -131,12 +144,20 @@ FileSystemMenu::has_right_suffix(const std::string& file) const
if (m_extensions.empty())
return true;

for (const auto& extension : m_extensions) {
for (const auto& extension : m_extensions)
if (StringUtil::has_suffix(file, extension))
{
return true;
}
}

return false;
}

bool
FileSystemMenu::is_image(const std::string& file) const
{
for (const auto& extension : IMAGE_EXTENSIONS)
if (StringUtil::has_suffix(file, extension))
return true;

return false;
}

Expand Down
1 change: 1 addition & 0 deletions src/gui/menu_filesystem.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class FileSystemMenu final : public Menu
private:
void refresh_items();
bool has_right_suffix(const std::string& file) const;
bool is_image(const std::string& file) const;

private:
std::string* m_filename;
Expand Down
10 changes: 9 additions & 1 deletion src/gui/menu_item.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,16 @@
#include "supertux/globals.hpp"
#include "supertux/resources.hpp"
#include "video/drawing_context.hpp"
#include "video/surface.hpp"

//static const float FLICK_CURSOR_TIME = 0.5f;

MenuItem::MenuItem(const std::string& text, int id) :
m_id(id),
m_text(text),
m_help(),
m_font(Resources::normal_font)
m_font(Resources::normal_font),
m_preview()
{
}

Expand All @@ -49,6 +51,12 @@ MenuItem::set_help(const std::string& help_text)
}
}

void
MenuItem::set_preview(const std::string& preview_file)
{
m_preview = Surface::from_file(preview_file);
}

void
MenuItem::draw(DrawingContext& context, const Vector& pos, int menu_width, bool active)
{
Expand Down
7 changes: 7 additions & 0 deletions src/gui/menu_item.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@

#include "gui/menu.hpp"

#include "video/surface_ptr.hpp"

class MenuItem
{
public:
Expand All @@ -37,6 +39,10 @@ class MenuItem
void set_font(const FontPtr font) { m_font = font; }
const FontPtr& get_font() const { return m_font; }

void set_preview(const std::string& preview_file);
inline void set_preview(SurfacePtr preview) { m_preview = preview; }
inline SurfacePtr get_preview() const { return m_preview; }

/** Draws the menu item. */
virtual void draw(DrawingContext&, const Vector& pos, int menu_width, bool active);

Expand Down Expand Up @@ -86,6 +92,7 @@ class MenuItem
std::string m_text;
std::string m_help;
FontPtr m_font;
SurfacePtr m_preview;

private:
MenuItem(const MenuItem&) = delete;
Expand Down
23 changes: 23 additions & 0 deletions src/math/rectf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,29 @@ Rectf::Rectf(const Rect& rect) :
{
}

void
Rectf::fit(const Sizef& target_size)
{
const float ratio = m_size.width / m_size.height;
const float target_ratio = target_size.width / target_size.height;

m_size = target_size;

if (ratio > target_ratio)
m_size.height = target_size.width / ratio;
else if (ratio < target_ratio)
m_size.width = target_size.height * ratio;
}

void
Rectf::fit_centered(const Sizef& target_size)
{
fit(target_size);

m_p1 += Vector((target_size.width - m_size.width) / 2.f,
(target_size.height - m_size.height) / 2.f);
}

Rect
Rectf::to_rect() const
{
Expand Down
Loading
Loading