Skip to content

Commit 62256b8

Browse files
authored
Add images item (#2223)
* Add images item * Add EOF * Fix compilation * Fix compilation... again * Reposition arrow indicators
1 parent 809ebb8 commit 62256b8

File tree

5 files changed

+217
-12
lines changed

5 files changed

+217
-12
lines changed

src/gui/item_images.cpp

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
// SuperTux
2+
// Copyright (C) 2022 mrkubax10 <[email protected]>
3+
//
4+
// This program is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// This program is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU General Public License
15+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
17+
#include "gui/item_images.hpp"
18+
19+
#include "supertux/resources.hpp"
20+
#include "video/surface.hpp"
21+
#include "video/drawing_context.hpp"
22+
23+
ItemImages::ItemImages(const std::string& image_path, int max_image_width, int max_image_height, int id):
24+
MenuItem("", id),
25+
m_images(),
26+
m_gallery_mode(false),
27+
m_selected_image(0),
28+
m_max_image_width(max_image_width),
29+
m_max_image_height(max_image_height),
30+
m_item_width(0),
31+
m_item_height(0)
32+
{
33+
m_images.push_back(Surface::from_file(image_path));
34+
m_item_width = (m_images[0]->get_width() > max_image_width && max_image_width > 0 ? max_image_width : m_images[0]->get_width()) + 4;
35+
m_item_height = (m_images[0]->get_height() > max_image_height && max_image_height > 0 ? max_image_height : m_images[0]->get_height()) + 4;
36+
}
37+
38+
ItemImages::ItemImages(const std::vector<std::string>& image_paths, int max_image_width, int max_image_height, int id):
39+
MenuItem("", id),
40+
m_images(),
41+
m_gallery_mode(image_paths.size() > 1),
42+
m_selected_image(0),
43+
m_max_image_width(max_image_width),
44+
m_max_image_height(max_image_height),
45+
m_item_width(0),
46+
m_item_height(0)
47+
{
48+
int max_width = 0;
49+
int max_height = 0;
50+
for (unsigned i = 0; i < image_paths.size(); i++)
51+
{
52+
m_images.push_back(Surface::from_file(image_paths[i]));
53+
if(m_images[i]->get_width() > max_width)
54+
max_width = (m_images[i]->get_width() > max_image_width && max_image_width > 0 ? max_image_width : m_images[i]->get_width());
55+
if(m_images[i]->get_height() > max_height)
56+
max_height = (m_images[i]->get_height() > max_image_height && max_image_height > 0 ? max_image_height : m_images[i]->get_height());
57+
}
58+
m_item_width = max_width + 4;
59+
m_item_height = max_height + 4;
60+
}
61+
62+
void
63+
ItemImages::draw(DrawingContext& drawing_context, const Vector& pos, int menu_width, bool active)
64+
{
65+
if (m_images.empty())
66+
return;
67+
SurfacePtr surface = m_images[m_selected_image];
68+
if (m_max_image_width > 0 && m_max_image_height > 0 && (surface->get_width() > m_max_image_width || surface->get_height() > m_max_image_height))
69+
drawing_context.color().draw_surface_scaled(surface, Rectf(pos + Vector((menu_width - m_max_image_width)/2 - 2, -m_max_image_height/2),
70+
Sizef(static_cast<float>(m_max_image_width), static_cast<float>(m_max_image_height))), LAYER_GUI);
71+
else
72+
drawing_context.color().draw_surface(surface, pos + Vector((menu_width - surface->get_width())/2 - 2, -surface->get_height()/2), LAYER_GUI);
73+
if (m_gallery_mode)
74+
{
75+
float left_arrow_width = Resources::big_font->get_text_width("<");
76+
float right_arrow_width = Resources::big_font->get_text_width(">");
77+
float arrow_height = Resources::big_font->get_text_height("<");
78+
drawing_context.color().draw_text(Resources::big_font, "<", pos + Vector(left_arrow_width/2 + 2, -arrow_height/2), FontAlignment::ALIGN_LEFT, LAYER_GUI);
79+
drawing_context.color().draw_text(Resources::big_font, ">", pos + Vector(static_cast<float>(menu_width) - right_arrow_width*1.5f, -arrow_height/2), FontAlignment::ALIGN_LEFT, LAYER_GUI);
80+
}
81+
}
82+
83+
void
84+
ItemImages::process_action(const MenuAction& action)
85+
{
86+
if (!m_gallery_mode)
87+
return;
88+
switch (action)
89+
{
90+
case MenuAction::LEFT:
91+
m_selected_image--;
92+
m_selected_image = (m_selected_image < 0 ? static_cast<int>(m_images.size()) - 1 : m_selected_image);
93+
break;
94+
case MenuAction::RIGHT:
95+
m_selected_image++;
96+
m_selected_image = (m_selected_image >= static_cast<int>(m_images.size()) ? 0 : m_selected_image);
97+
break;
98+
default:
99+
break;
100+
}
101+
}
102+
/* EOF */

src/gui/item_images.hpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// SuperTux
2+
// Copyright (C) 2022 mrkubax10 <[email protected]>
3+
//
4+
// This program is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// This program is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU General Public License
15+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
17+
#ifndef HEADER_SUPERTUX_GUI_ITEM_IMAGES_HPP
18+
#define HEADER_SUPERTUX_GUI_ITEM_IMAGES_HPP
19+
20+
#include "gui/menu_item.hpp"
21+
#include "video/surface_ptr.hpp"
22+
23+
class ItemImages final : public MenuItem
24+
{
25+
public:
26+
ItemImages(const std::string& image_path, int max_image_width = 0, int max_image_height = 0, int id = -1);
27+
ItemImages(const std::vector<std::string>& image_paths, int max_image_width = 0, int max_image_height = 0, int id = -1);
28+
29+
virtual void draw(DrawingContext& drawing_context, const Vector& pos, int menu_width, bool active) override;
30+
virtual int get_width() const override { return m_item_width; }
31+
virtual int get_height() const override { return m_item_height; }
32+
virtual void process_action(const MenuAction& action) override;
33+
34+
private:
35+
std::vector<SurfacePtr> m_images;
36+
bool m_gallery_mode;
37+
int m_selected_image;
38+
int m_max_image_width;
39+
int m_max_image_height;
40+
int m_item_width;
41+
int m_item_height;
42+
43+
private:
44+
ItemImages(const ItemImages&) = delete;
45+
ItemImages& operator=(const ItemImages&) = delete;
46+
};
47+
48+
#endif
49+
/* EOF */

src/gui/menu.cpp

Lines changed: 56 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include "gui/item_textfield.hpp"
3939
#include "gui/item_toggle.hpp"
4040
#include "gui/item_string_array.hpp"
41+
#include "gui/item_images.hpp"
4142
#include "gui/menu_item.hpp"
4243
#include "gui/menu_manager.hpp"
4344
#include "gui/mousecursor.hpp"
@@ -62,6 +63,7 @@ Menu::Menu() :
6263
m_mn_input_char('\0'),
6364
m_menu_repeat_time(),
6465
m_menu_width(),
66+
m_menu_height(),
6567
m_items(),
6668
m_arrange_left(0),
6769
m_active_item(-1)
@@ -97,6 +99,7 @@ Menu::add_item(std::unique_ptr<MenuItem> new_item)
9799
}
98100

99101
calculate_width();
102+
calculate_height();
100103

101104
return item;
102105
}
@@ -116,6 +119,7 @@ Menu::add_item(std::unique_ptr<MenuItem> new_item, int pos_)
116119
}
117120

118121
calculate_width();
122+
calculate_height();
119123

120124
return item;
121125
}
@@ -353,6 +357,24 @@ Menu::add_string_array(const std::string& text, std::vector<std::string>& items,
353357
return *item_ptr;
354358
}
355359

360+
ItemImages&
361+
Menu::add_images(const std::string& image_path, int max_image_width, int max_image_height, int id)
362+
{
363+
auto item = std::make_unique<ItemImages>(image_path, max_image_width, max_image_height, id);
364+
auto item_ptr = item.get();
365+
add_item(std::move(item));
366+
return *item_ptr;
367+
}
368+
369+
ItemImages&
370+
Menu::add_images(const std::vector<std::string>& image_paths, int max_image_width, int max_image_height, int id)
371+
{
372+
auto item = std::make_unique<ItemImages>(image_paths, max_image_width, max_image_height, id);
373+
auto item_ptr = item.get();
374+
add_item(std::move(item));
375+
return *item_ptr;
376+
}
377+
356378
void
357379
Menu::clear()
358380
{
@@ -547,28 +569,26 @@ Menu::process_action(const MenuAction& menuaction)
547569
}
548570

549571
void
550-
Menu::draw_item(DrawingContext& context, int index)
572+
Menu::draw_item(DrawingContext& context, int index, float y_pos)
551573
{
552-
const float menu_height = get_height();
553574
const float menu_width = get_width();
554575

555576
MenuItem* pitem = m_items[index].get();
556577

557578
const float x_pos = m_pos.x - menu_width / 2.0f;
558-
const float y_pos = m_pos.y + 24.0f * static_cast<float>(index) - menu_height / 2.0f + 12.0f;
559579

560580
pitem->draw(context, Vector(x_pos, y_pos), static_cast<int>(menu_width), m_active_item == index);
561581

562582
if (m_active_item == index)
563583
{
564584
float blink = (sinf(g_real_time * math::PI * 1.0f)/2.0f + 0.5f) * 0.5f + 0.25f;
565-
context.color().draw_filled_rect(Rectf(Vector(m_pos.x - menu_width/2 + 10 - 2, y_pos - 12 - 2),
566-
Vector(m_pos.x + menu_width/2 - 10 + 2, y_pos + 12 + 2)),
585+
context.color().draw_filled_rect(Rectf(Vector(m_pos.x - menu_width/2 + 10 - 2, y_pos - static_cast<float>(pitem->get_height())/2 - 2),
586+
Vector(m_pos.x + menu_width/2 - 10 + 2, y_pos + static_cast<float>(pitem->get_height())/2 + 2)),
567587
Color(1.0f, 1.0f, 1.0f, blink),
568588
std::max(0.f, g_config->menuroundness - 2.f),
569589
LAYER_GUI-10);
570-
context.color().draw_filled_rect(Rectf(Vector(m_pos.x - menu_width/2 + 10, y_pos - 12),
571-
Vector(m_pos.x + menu_width/2 - 10, y_pos + 12)),
590+
context.color().draw_filled_rect(Rectf(Vector(m_pos.x - menu_width/2 + 10, y_pos - static_cast<float>(pitem->get_height())/2),
591+
Vector(m_pos.x + menu_width/2 - 10, y_pos + static_cast<float>(pitem->get_height())/2)),
572592
Color(1.0f, 1.0f, 1.0f, 0.5f),
573593
std::max(0.f, g_config->menuroundness - 4.f),
574594
LAYER_GUI-10);
@@ -590,6 +610,17 @@ Menu::calculate_width()
590610
m_menu_width = max_width;
591611
}
592612

613+
void
614+
Menu::calculate_height()
615+
{
616+
float height = 0;
617+
for (unsigned i = 0; i < m_items.size(); i++)
618+
{
619+
height += static_cast<float>(m_items[i]->get_height());
620+
}
621+
m_menu_height = height;
622+
}
623+
593624
float
594625
Menu::get_width() const
595626
{
@@ -599,7 +630,7 @@ Menu::get_width() const
599630
float
600631
Menu::get_height() const
601632
{
602-
return static_cast<float>(m_items.size() * 24);
633+
return m_menu_height;
603634
}
604635

605636
void
@@ -612,9 +643,12 @@ Menu::on_window_resize()
612643
void
613644
Menu::draw(DrawingContext& context)
614645
{
646+
const float menu_height = get_height();
647+
float y_pos = m_pos.y - menu_height / 2.0f;
615648
for (unsigned int i = 0; i < m_items.size(); ++i)
616649
{
617-
draw_item(context, i);
650+
draw_item(context, i, y_pos + static_cast<float>(m_items[i]->get_height())/2);
651+
y_pos += static_cast<float>(m_items[i]->get_height());
618652
}
619653

620654
if (!m_items[m_active_item]->get_help().empty())
@@ -719,8 +753,19 @@ Menu::event(const SDL_Event& ev)
719753
y > m_pos.y - get_height()/2 &&
720754
y < m_pos.y + get_height()/2)
721755
{
722-
int new_active_item
723-
= static_cast<int> ((y - (m_pos.y - get_height()/2)) / 24);
756+
int new_active_item = 0;
757+
// This is probably not the most efficient way of finding active item
758+
// but I can't think of something better right now ~ mrkubax10
759+
float item_y = m_pos.y - get_height()/2;
760+
for (unsigned i = 0; i < m_items.size(); i++)
761+
{
762+
if (y >= item_y && y <= item_y + static_cast<float>(m_items[i]->get_height()))
763+
{
764+
new_active_item = i;
765+
break;
766+
}
767+
item_y += static_cast<float>(m_items[i]->get_height());
768+
}
724769

725770
/* only change the mouse focus to a selectable item */
726771
if (!m_items[new_active_item]->skippable() &&

src/gui/menu.hpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ class ItemStringSelect;
4949
class ItemTextField;
5050
class ItemToggle;
5151
class ItemStringArray;
52+
class ItemImages;
5253
class MenuItem;
5354
class PathObject;
5455

@@ -98,6 +99,8 @@ class Menu
9899
ItemColorChannelOKLab& add_color_channel_oklab(Color* color, int channel);
99100
ItemPaths& add_path_settings(const std::string& text, PathObject& target, const std::string& path_ref);
100101
ItemStringArray& add_string_array(const std::string& text, std::vector<std::string>& items, int id = -1);
102+
ItemImages& add_images(const std::string& image_path, int max_image_width = 0, int max_image_height = 0, int id = -1);
103+
ItemImages& add_images(const std::vector<std::string>& image_paths, int max_image_width = 0, int max_image_height = 0, int id = -1);
101104

102105
void process_input(const Controller& controller);
103106

@@ -132,9 +135,11 @@ class Menu
132135
private:
133136
void process_action(const MenuAction& menuaction);
134137
void check_controlfield_change_event(const SDL_Event& event);
135-
void draw_item(DrawingContext& context, int index);
138+
void draw_item(DrawingContext& context, int index, float y_pos);
136139
/** Recalculates the width for this menu */
137140
void calculate_width();
141+
/** Recalculates the height for this menu */
142+
void calculate_height();
138143

139144
private:
140145
/** position of the menu (ie. center of the menu, not top/left) */
@@ -145,6 +150,7 @@ class Menu
145150
char m_mn_input_char;
146151
float m_menu_repeat_time;
147152
float m_menu_width;
153+
float m_menu_height;
148154

149155
public:
150156
std::vector<std::unique_ptr<MenuItem> > m_items;

src/gui/menu_item.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ class MenuItem
4646
/** Returns the minimum width of the menu item. */
4747
virtual int get_width() const;
4848

49+
/** Returns height of menu item. */
50+
virtual int get_height() const { return 24; }
51+
4952
/** Processes the menu action. */
5053
virtual void process_action(const MenuAction& action) { }
5154

0 commit comments

Comments
 (0)