Skip to content

Commit 40f45f6

Browse files
authored
Editor comment (#3181)
The editor comment allows level designers to leave a note for themselves or other level designers collaborating on the same level. Similar to a code comment, it can be used to write to-do lists, fixmes, or notes. This feature supports info box formatting, like what you'd see in the info block or the text scroller.
1 parent 149a2ce commit 40f45f6

File tree

8 files changed

+241
-14
lines changed

8 files changed

+241
-14
lines changed
1.18 KB
Loading

data/images/engine/editor/objects.stoi

+4-1
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@
177177
(icon "images/engine/editor/stalactite_ice_yeti.png"))
178178
(object
179179
(class "dart")
180-
(icon "images/creatures/darttrap/granito/root_dart_left.png"))
180+
(icon "images/creatures/darttrap/granito/root_dart_left.png"))
181181
(object
182182
(class "bigsnowball")
183183
(icon "images/objects/big_snowball/big_snowball.png"))
@@ -339,6 +339,9 @@
339339
(object
340340
(class "text-area")
341341
(icon "images/engine/editor/textarray.png"))
342+
(object
343+
(class "editor-comment")
344+
(icon "images/engine/editor/editor-comment.png"))
342345
)
343346

344347
(layers

src/editor/editor_comment.cpp

+121
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
// SuperTux
2+
// Copyright (C) 2025 MatusGuy <[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 "editor_comment.hpp"
18+
19+
#include "editor/editor.hpp"
20+
#include "supertux/info_box_line.hpp"
21+
#include "util/reader_mapping.hpp"
22+
#include "video/drawing_context.hpp"
23+
24+
EditorComment::EditorComment(const ReaderMapping& reader):
25+
MovingObject(reader),
26+
m_comment(""),
27+
m_lines()
28+
{
29+
parse_type(reader);
30+
31+
float w,h;
32+
reader.get("width", w, 32.f * 3);
33+
reader.get("height", h, 32.f * 3);
34+
m_col.m_bbox.set_size(w, h);
35+
36+
reader.get("comment", m_comment);
37+
refresh_comment();
38+
}
39+
40+
void
41+
EditorComment::draw(DrawingContext& context)
42+
{
43+
// TODO: There should be an object factory param
44+
// for objects that only exist when testing in editor.
45+
if (!Editor::current())
46+
return;
47+
48+
float y = get_y();
49+
for (std::unique_ptr<InfoBoxLine>& line : m_lines)
50+
{
51+
if (y >= get_bbox().get_bottom())
52+
break;
53+
54+
line->draw(context, Rectf(Vector(get_x(), y), Sizef(get_width() / 2, y)), get_layer() + 1, InfoBoxLine::LEFT);
55+
y += line->get_height();
56+
}
57+
58+
context.color().draw_filled_rect(get_bbox(), get_color(), 0.f, get_layer());
59+
}
60+
61+
void
62+
EditorComment::check_state()
63+
{
64+
refresh_comment();
65+
}
66+
67+
GameObjectTypes
68+
EditorComment::get_types() const
69+
{
70+
return {
71+
/* l10n: A note refers to a reminder left for future
72+
level designers to read in order to better understand
73+
the usage of certain features in a level, for example. */
74+
{ "note", _("Note") },
75+
76+
/* l10n: A to-do refers to a reminder left for the
77+
author of the comment to finish designing something in
78+
a level. */
79+
{ "todo", _("To-do") },
80+
81+
/* l10n: A fix-me refers to a reminder left for the
82+
author of the comment to fix a flaw with the level
83+
design. */
84+
{ "fixme", _("Fix-me") },
85+
86+
/* l10n: A hack refers to usage of an unintended or
87+
non-ideal way of implementing a level design idea. */
88+
{ "hack", _("Hack") }
89+
};
90+
}
91+
92+
ObjectSettings
93+
EditorComment::get_settings()
94+
{
95+
ObjectSettings result = MovingObject::get_settings();
96+
97+
result.add_multiline_text(_("Comment"), &m_comment, "comment");
98+
99+
return result;
100+
}
101+
102+
void
103+
EditorComment::refresh_comment()
104+
{
105+
m_lines = InfoBoxLine::split(m_comment, get_width(), true);
106+
}
107+
108+
Color
109+
EditorComment::get_color() const
110+
{
111+
switch (m_type)
112+
{
113+
case NOTE: return Color(0.19f, 0.65f, 0.32f, 0.6f);
114+
case TODO: return Color(0.26f, 0.53f, 0.96f, 0.6f);
115+
case FIXME: return Color(1.f, 0.44f, 0.11f, 0.6f);
116+
case HACK: return Color(0.96f, 0.23f, 0.23f, 0.6f);
117+
default: return Color();
118+
}
119+
}
120+
121+
/* EOF */

src/editor/editor_comment.hpp

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// SuperTux
2+
// Copyright (C) 2025 MatusGuy <[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_EDITOR_EDITOR_COMMENT_HPP
18+
#define HEADER_SUPERTUX_EDITOR_EDITOR_COMMENT_HPP
19+
20+
#include "supertux/moving_object.hpp"
21+
#include "video/layer.hpp"
22+
23+
class ReaderMapping;
24+
class InfoBoxLine;
25+
26+
class EditorComment : public MovingObject
27+
{
28+
public:
29+
enum Type
30+
{
31+
NOTE,
32+
TODO,
33+
FIXME,
34+
HACK
35+
};
36+
37+
public:
38+
EditorComment(const ReaderMapping& reader);
39+
40+
virtual void draw(DrawingContext& context) override;
41+
virtual void update(float dt_sec) override { MovingObject::update(dt_sec); }
42+
virtual HitResponse collision(MovingObject&, const CollisionHit&) override { return ABORT_MOVE; }
43+
virtual void check_state() override;
44+
45+
virtual bool has_variable_size() const override { return true; }
46+
static std::string class_name() { return "editor-comment"; }
47+
virtual std::string get_class_name() const override { return class_name(); }
48+
static std::string display_name() { return _("Editor Comment"); }
49+
virtual std::string get_display_name() const override { return display_name(); }
50+
virtual GameObjectClasses get_class_types() const override { return MovingObject::get_class_types().add(typeid(EditorComment)); }
51+
52+
virtual GameObjectTypes get_types() const override;
53+
virtual ObjectSettings get_settings() override;
54+
55+
virtual int get_layer() const override { return LAYER_FOREGROUND1 - 5; }
56+
57+
private:
58+
void refresh_comment();
59+
Color get_color() const;
60+
61+
private:
62+
std::string m_comment;
63+
std::vector<std::unique_ptr<InfoBoxLine>> m_lines;
64+
65+
private:
66+
EditorComment(const EditorComment&) = delete;
67+
EditorComment& operator=(const EditorComment&) = delete;
68+
};
69+
70+
#endif // HEADER_SUPERTUX_EDITOR_EDITOR_COMMENT_HPP

src/editor/overlay_widget.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -1023,7 +1023,7 @@ EditorOverlayWidget::on_mouse_button_up(const SDL_MouseButtonEvent& button)
10231023

10241024
m_editor.get_selected_tilemap()->check_state();
10251025
}
1026-
else if (m_editor.get_tileselect_input_type() == EditorTilebox::InputType::OBJECT)
1026+
else
10271027
{
10281028
if (m_dragging && m_dragged_object) {
10291029
m_dragged_object->check_state();

src/supertux/game_object_factory.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@
7979
#include "badguy/yeti.hpp"
8080
#include "badguy/yeti_stalactite.hpp"
8181
#include "badguy/zeekling.hpp"
82+
#include "editor/editor_comment.hpp"
8283
#include "math/vector.hpp"
8384
#include "object/ambient_light.hpp"
8485
#include "object/ambient_sound.hpp"
@@ -317,6 +318,7 @@ GameObjectFactory::init_factories()
317318

318319
// Editor stuff.
319320
add_factory<SpawnPointMarker>("spawnpoint");
321+
add_factory<EditorComment>("editor-comment");
320322

321323
// Worldmap objects.
322324
add_factory<worldmap::LevelTile>("level", OBJ_PARAM_WORLDMAP);

src/supertux/info_box_line.cpp

+39-11
Original file line numberDiff line numberDiff line change
@@ -102,13 +102,13 @@ InfoBoxLine::InfoBoxLine(char format_char, const std::string& text_) :
102102
}
103103

104104
std::vector<std::unique_ptr<InfoBoxLine> >
105-
InfoBoxLine::split(const std::string& text, float width)
105+
InfoBoxLine::split(const std::string& text, float width, bool small)
106106
{
107107
std::vector<std::unique_ptr<InfoBoxLine> > lines;
108108

109109
std::string::size_type i = 0;
110110
std::string::size_type l;
111-
char format_char = '#';
111+
char format_char = small ? ' ' : '#';
112112
while (i < text.size()) {
113113
// take care of empty lines - represent them as blank lines of normal text
114114
if (text[i] == '\n') {
@@ -125,7 +125,7 @@ InfoBoxLine::split(const std::string& text, float width)
125125
}
126126
else
127127
{
128-
format_char = '#';
128+
format_char = small ? ' ' : '#';
129129
}
130130
if (i >= text.size()) break;
131131

@@ -155,22 +155,50 @@ InfoBoxLine::split(const std::string& text, float width)
155155
return lines;
156156
}
157157

158+
Vector
159+
InfoBoxLine::calc_text_pos(const Rectf& bbox, float textwidth, LineAlignment alignment) const
160+
{
161+
float x = 0.f;
162+
switch (alignment)
163+
{
164+
case LineAlignment::LEFT:
165+
x = bbox.get_left();
166+
break;
167+
168+
case LineAlignment::RIGHT:
169+
x = bbox.get_right() - textwidth;
170+
break;
171+
172+
case LineAlignment::CENTER:
173+
x = ((bbox.get_left() + bbox.get_right()) / 2 - (textwidth / 2));
174+
break;
175+
176+
default:
177+
break;
178+
}
179+
180+
return Vector(x, bbox.get_top());
181+
}
182+
158183
void
159184
InfoBoxLine::draw(DrawingContext& context, const Rectf& bbox, int layer, LineAlignment alignment)
160185
{
161-
Vector position = bbox.p1();
162-
switch (lineType) {
186+
Vector pos;
187+
188+
switch (lineType)
189+
{
163190
case IMAGE:
164-
context.color().draw_surface(image, Vector(((bbox.get_left() + bbox.get_right() - static_cast<float>(image->get_width())) * 0.5f)
165-
+ (static_cast<float>(image->get_width()) * (alignment == LineAlignment::LEFT ? 0.5f : alignment == LineAlignment::RIGHT ? -0.5f : 0.f)), position.y), layer);
191+
pos = calc_text_pos(bbox, static_cast<float>(image->get_width()), alignment);
192+
context.color().draw_surface(image, pos, layer);
166193
break;
194+
167195
case NORMAL_LEFT:
168-
context.color().draw_text(font, text, Vector(position.x, position.y), ALIGN_LEFT, layer, color);
196+
context.color().draw_text(font, text, bbox.p1(), ALIGN_LEFT, layer, color);
169197
break;
198+
170199
default:
171-
context.color().draw_text(font, text, Vector((bbox.get_left() + bbox.get_right()) / 2.f, position.y),
172-
alignment == LineAlignment::LEFT ? ALIGN_LEFT :
173-
alignment == LineAlignment::RIGHT ? ALIGN_RIGHT : ALIGN_CENTER, layer, color);
200+
pos = calc_text_pos(bbox, font->get_text_width(text), alignment);
201+
context.color().draw_text(font, text, pos, ALIGN_LEFT, layer, color);
174202
break;
175203
}
176204
}

src/supertux/info_box_line.hpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <vector>
2222
#include <memory>
2323

24+
#include "math/vector.hpp"
2425
#include "video/color.hpp"
2526
#include "video/font_ptr.hpp"
2627
#include "video/surface_ptr.hpp"
@@ -42,7 +43,7 @@ class InfoBoxLine final
4243
void draw(DrawingContext& context, const Rectf& bbox, int layer, LineAlignment alignment = CENTER);
4344
float get_height() const;
4445

45-
static std::vector<std::unique_ptr<InfoBoxLine> > split(const std::string& text, float width);
46+
static std::vector<std::unique_ptr<InfoBoxLine>> split(const std::string& text, float width, bool small = false);
4647

4748
static bool is_valid_format_char(char format_char)
4849
{
@@ -60,6 +61,8 @@ class InfoBoxLine final
6061
}
6162
}
6263

64+
private:
65+
Vector calc_text_pos(const Rectf& bbox, float textwidth, LineAlignment alignment) const;
6366
private:
6467
InfoBoxLine::LineType lineType;
6568
FontPtr font;

0 commit comments

Comments
 (0)