Skip to content

Commit

Permalink
Refactored overlay_widget.cpp to improve lifetime management (#1935)
Browse files Browse the repository at this point in the history
Co-authored-by: Semphris <semphris@protonmail.com>
  • Loading branch information
Semphriss and Semphris committed Dec 15, 2021
1 parent b84f4d4 commit 458ba0e
Show file tree
Hide file tree
Showing 7 changed files with 145 additions and 26 deletions.
2 changes: 1 addition & 1 deletion src/editor/editor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ class Editor final : public Screen,

bool is_level_loaded() const { return m_levelloaded; }

void edit_path(Path* path, GameObject* new_marked_object) {
void edit_path(PathGameObject* path, GameObject* new_marked_object) {
m_overlay_widget->edit_path(path, new_marked_object);
}

Expand Down
4 changes: 2 additions & 2 deletions src/editor/layers_widget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -175,11 +175,11 @@ EditorLayersWidget::on_mouse_button_down(const SDL_MouseButtonEvent& button)
}
m_selected_tilemap = static_cast<TileMap*>(m_layer_icons[m_hovered_layer]->get_layer());
m_selected_tilemap->m_editor_active = true;
m_editor.edit_path(m_selected_tilemap->get_path(), m_selected_tilemap);
m_editor.edit_path(m_selected_tilemap->get_path_gameobject(), m_selected_tilemap);
} else {
auto cam = dynamic_cast<Camera*>(m_layer_icons[m_hovered_layer]->get_layer());
if (cam) {
m_editor.edit_path(cam->get_path(), cam);
m_editor.edit_path(cam->get_path_gameobject(), cam);
}
}
return true;
Expand Down
32 changes: 16 additions & 16 deletions src/editor/overlay_widget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -471,7 +471,7 @@ EditorOverlayWidget::hover_object()
}

void
EditorOverlayWidget::edit_path(Path* path, GameObject* new_marked_object)
EditorOverlayWidget::edit_path(PathGameObject* path, GameObject* new_marked_object)
{
if (!path) return;
delete_markers();
Expand All @@ -481,7 +481,7 @@ EditorOverlayWidget::edit_path(Path* path, GameObject* new_marked_object)
return;
}
m_edited_path = path;
m_edited_path->edit_path();
m_edited_path->get_path().edit_path();
if (new_marked_object) {
m_selected_object = new_marked_object;
}
Expand Down Expand Up @@ -509,10 +509,10 @@ EditorOverlayWidget::select_object()
return;
}

auto path_obj = dynamic_cast<PathObject*>(m_dragged_object);
if (path_obj && path_obj->get_path())
auto path_obj = dynamic_cast<PathObject*>(m_dragged_object.get());
if (path_obj && path_obj->get_path_gameobject())
{
edit_path(path_obj->get_path(), m_dragged_object);
edit_path(path_obj->get_path_gameobject(), m_dragged_object.get());
}
}

Expand All @@ -529,7 +529,7 @@ EditorOverlayWidget::grab_object()
m_dragged_object = m_hovered_object;
m_obj_mouse_desync = m_sector_pos - m_hovered_object->get_pos();

auto* pm = dynamic_cast<MarkerObject*>(m_hovered_object);
auto* pm = dynamic_cast<MarkerObject*>(m_hovered_object.get());
if (!pm) {
select_object();
}
Expand Down Expand Up @@ -560,7 +560,7 @@ EditorOverlayWidget::clone_object()
return;
}

auto* pm = dynamic_cast<MarkerObject*>(m_hovered_object);
auto* pm = dynamic_cast<MarkerObject*>(m_hovered_object.get());
if (!pm)
{
m_obj_mouse_desync = m_sector_pos - m_hovered_object->get_pos();
Expand Down Expand Up @@ -612,7 +612,7 @@ EditorOverlayWidget::move_object()
auto& snap_grid_size = snap_grid_sizes[g_config->editor_selected_snap_grid_size];
new_pos = glm::floor(new_pos / static_cast<float>(snap_grid_size)) * static_cast<float>(snap_grid_size);

auto pm = dynamic_cast<MarkerObject*>(m_dragged_object);
auto pm = dynamic_cast<MarkerObject*>(m_dragged_object.get());
if (pm) {
new_pos -= pm->get_offset();
}
Expand Down Expand Up @@ -685,10 +685,10 @@ EditorOverlayWidget::add_path_node()
new_node.bezier_before = new_node.position;
new_node.bezier_after = new_node.position;
new_node.time = 1;
m_edited_path->m_nodes.insert(m_last_node_marker->m_node + 1, new_node);
auto& bezier_before = Sector::get().add<BezierMarker>(&(*(m_edited_path->m_nodes.end() - 1)), &((m_edited_path->m_nodes.end() - 1)->bezier_before));
auto& bezier_after = Sector::get().add<BezierMarker>(&(*(m_edited_path->m_nodes.end() - 1)), &((m_edited_path->m_nodes.end() - 1)->bezier_after));
auto& new_marker = Sector::get().add<NodeMarker>(m_edited_path, m_edited_path->m_nodes.end() - 1, m_edited_path->m_nodes.size() - 1, bezier_before.get_uid(), bezier_after.get_uid());
m_edited_path->get_path().m_nodes.insert(m_last_node_marker->m_node + 1, new_node);
auto& bezier_before = Sector::get().add<BezierMarker>(&(*(m_edited_path->get_path().m_nodes.end() - 1)), &((m_edited_path->get_path().m_nodes.end() - 1)->bezier_before));
auto& bezier_after = Sector::get().add<BezierMarker>(&(*(m_edited_path->get_path().m_nodes.end() - 1)), &((m_edited_path->get_path().m_nodes.end() - 1)->bezier_after));
auto& new_marker = Sector::get().add<NodeMarker>(&(m_edited_path.get()->get_path()), m_edited_path->get_path().m_nodes.end() - 1, m_edited_path->get_path().m_nodes.size() - 1, bezier_before.get_uid(), bezier_after.get_uid());
bezier_before.set_parent(new_marker.get_uid());
bezier_after.set_parent(new_marker.get_uid());
//last_node_marker = dynamic_cast<NodeMarker*>(marker.get());
Expand Down Expand Up @@ -1206,14 +1206,14 @@ EditorOverlayWidget::draw_path(DrawingContext& context)
if (!m_selected_object->is_valid()) return;
if (!m_edited_path->is_valid()) return;

for (auto i = m_edited_path->m_nodes.begin(); i != m_edited_path->m_nodes.end(); ++i) {
for (auto i = m_edited_path->get_path().m_nodes.begin(); i != m_edited_path->get_path().m_nodes.end(); ++i) {
auto j = i+1;
Path::Node* node1 = &(*i);
Path::Node* node2;
if (j == m_edited_path->m_nodes.end()) {
if (m_edited_path->m_mode == WalkMode::CIRCULAR) {
if (j == m_edited_path->get_path().m_nodes.end()) {
if (m_edited_path->get_path().m_mode == WalkMode::CIRCULAR) {
//loop to the first node
node2 = &(*m_edited_path->m_nodes.begin());
node2 = &(*m_edited_path->get_path().m_nodes.begin());
} else {
// Just draw the bezier lines
auto cam_translation = m_editor.get_sector()->get_camera().get_translation();
Expand Down
13 changes: 7 additions & 6 deletions src/editor/overlay_widget.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "editor/widget.hpp"
#include "math/vector.hpp"
#include "object/tilemap.hpp"
#include "util/typed_uid.hpp"

class Color;
class DrawingContext;
Expand Down Expand Up @@ -62,7 +63,7 @@ class EditorOverlayWidget final : public Widget
void update_node_iterators();
void on_level_change();

void edit_path(Path* path, GameObject* new_marked_object = nullptr);
void edit_path(PathGameObject* path, GameObject* new_marked_object = nullptr);
void reset_action_press();

private:
Expand Down Expand Up @@ -124,12 +125,12 @@ class EditorOverlayWidget final : public Widget
bool m_dragging;
bool m_dragging_right;
Vector m_drag_start;
MovingObject* m_dragged_object;
TypedUID<MovingObject> m_dragged_object;

MovingObject* m_hovered_object;
GameObject* m_selected_object;
Path* m_edited_path;
NodeMarker* m_last_node_marker;
TypedUID<MovingObject> m_hovered_object;
TypedUID<GameObject> m_selected_object;
TypedUID<PathGameObject> m_edited_path;
TypedUID<NodeMarker> m_last_node_marker;

std::unique_ptr<Tip> m_object_tip;
Vector m_obj_mouse_desync;
Expand Down
11 changes: 11 additions & 0 deletions src/object/path_gameobject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,17 @@ PathGameObject::remove_me()
handle.remove_me(); // Removing a node handle also removes its bezier handles
}

const auto& path_objects = Sector::get().get_objects_by_type<PathObject>();

for (const auto& path_obj : path_objects)
{
if (path_obj.get_path_gameobject() == this)
{
log_warning << "Attempt to delete path " << get_name() << " while bound to object" << std::endl;
return;
}
}

GameObject::remove_me();
}

Expand Down
107 changes: 107 additions & 0 deletions src/util/typed_uid.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// SuperTux
// Copyright (C) 2021 A. Semphris <semphris@protonmail.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

#ifndef HEADER_SUPERTUX_UTIL_TYPED_UID_HPP
#define HEADER_SUPERTUX_UTIL_TYPED_UID_HPP

#include "util/uid.hpp"

#include "supertux/sector.hpp"

/**
* Typed UIDs allows storing GameObjects as UID while offering to option to use
* the object either as if it was a pointer or as if it was an UID. This helps
* staying resilient against the objects' variable lifetime.
*/
template<class T>
class TypedUID : public UID
{
public:
TypedUID() : UID() {}
TypedUID(const T* object) : UID() { if (object) *this = object->get_uid(); }
TypedUID(const TypedUID& other) = default;
TypedUID& operator=(const TypedUID& other) = default;

inline T* get() const
{
if (m_value == 0 || !Sector::current())
return nullptr;

auto* object = Sector::get().get_object_by_uid<T>(*this);

if (!object)
{
//*this = UID(); // Would break const correctness
throw std::runtime_error("Attempt to dereference invalid TypedUID");
}

return object;
}

inline TypedUID& operator=(const T* object)
{
*this = object ? object->get_uid() : UID();
return *this;
}

inline TypedUID& operator=(const UID& other)
{
UID::operator=(other);
return *this;
}

inline T* operator->() const
{
return get();
}

inline T& operator*() const
{
T* t = get();
if (!t)
throw std::runtime_error("Attempt to dereference invalid TypedUID");

return *t;
}

inline bool operator==(const T* object) const
{
return (!object && m_value == 0) || object->get_uid() == *this;
}

inline bool operator!=(const T* object) const
{
return object ? object->get_uid() != *this : m_value == 0;
}

inline operator bool() const {
return m_value != 0 && Sector::current() && Sector::get().get_object_by_uid<T>(*this);
}
};

template<class T>
inline bool operator==(const T* object, const TypedUID<T>& typed_uid) {
return typed_uid == object;
}

template<class T>
inline bool operator!=(const T* object, const TypedUID<T>& typed_uid) {
return typed_uid != object;
}

#endif

/* EOF */
2 changes: 1 addition & 1 deletion src/util/uid.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ class UID

inline Magic get_magic() const { return static_cast<Magic>((m_value & 0xffff0000u) >> 16); }

private:
protected:
uint32_t m_value;
};

Expand Down

0 comments on commit 458ba0e

Please sign in to comment.