Arrows/Whiteboard: big and hopefully final refactoring;...
...got rid of observer pattern and settled on a lifecycle management strategy.
This commit is contained in:
parent
d3da33b68b
commit
1c7c79a2c3
11 changed files with 94 additions and 147 deletions
|
@ -18,11 +18,11 @@
|
|||
*/
|
||||
|
||||
#include "arrow.hpp"
|
||||
#include "arrow_observer.hpp"
|
||||
|
||||
#include "foreach.hpp"
|
||||
#include "log.hpp"
|
||||
#include "map_location.hpp"
|
||||
#include "resources.hpp"
|
||||
|
||||
static lg::log_domain log_arrows("arrows");
|
||||
#define ERR_ARR LOG_STREAM(err, log_arrows)
|
||||
|
@ -30,8 +30,8 @@ static lg::log_domain log_arrows("arrows");
|
|||
#define LOG_ARR LOG_STREAM(info, log_arrows)
|
||||
#define DBG_ARR LOG_STREAM(debug, log_arrows)
|
||||
|
||||
arrow::arrow(display* screen)
|
||||
: screen_(screen)
|
||||
arrow::arrow()
|
||||
: screen_((display*&) resources::screen)
|
||||
, layer_(display::LAYER_ARROWS)
|
||||
, color_("red")
|
||||
, style_("")
|
||||
|
@ -39,12 +39,15 @@ arrow::arrow(display* screen)
|
|||
, path_()
|
||||
, previous_path_()
|
||||
, symbols_map_()
|
||||
, observers_()
|
||||
{
|
||||
}
|
||||
|
||||
arrow::~arrow()
|
||||
{
|
||||
if (screen_)
|
||||
{
|
||||
screen_->remove_arrow(*this);
|
||||
}
|
||||
}
|
||||
|
||||
bool arrow::set_path(const arrow_path_t &path)
|
||||
|
@ -62,6 +65,15 @@ bool arrow::set_path(const arrow_path_t &path)
|
|||
}
|
||||
}
|
||||
|
||||
void arrow::clear_path()
|
||||
{
|
||||
invalidate_arrow_path(path_);
|
||||
path_.clear();
|
||||
previous_path_.clear();
|
||||
symbols_map_.clear();
|
||||
notify_arrow_changed();
|
||||
}
|
||||
|
||||
void arrow::set_color(const std::string& color)
|
||||
{
|
||||
color_ = color;
|
||||
|
@ -111,6 +123,8 @@ const arrow_path_t & arrow::get_previous_path() const
|
|||
|
||||
void arrow::draw_hex(const map_location & loc)
|
||||
{
|
||||
if(!screen_) return;
|
||||
|
||||
screen_->render_image(screen_->get_location_x(loc), screen_->get_location_y(loc), layer_,
|
||||
loc, image::get_image(symbols_map_[loc], image::SCALED_TO_ZOOM), false, false, alpha_);
|
||||
}
|
||||
|
@ -123,16 +137,6 @@ bool arrow::valid_path(arrow_path_t path) const
|
|||
return false;
|
||||
}
|
||||
|
||||
void arrow::add_observer(arrow_observer & observer)
|
||||
{
|
||||
observers_.push_back(&observer);
|
||||
}
|
||||
|
||||
void arrow::remove_observer(arrow_observer & observer)
|
||||
{
|
||||
observers_.remove(&observer);
|
||||
}
|
||||
|
||||
void arrow::update_symbols(arrow_path_t old_path)
|
||||
{
|
||||
if (!valid_path(path_))
|
||||
|
@ -250,6 +254,8 @@ void arrow::update_symbols(arrow_path_t old_path)
|
|||
|
||||
void arrow::invalidate_arrow_path(arrow_path_t path)
|
||||
{
|
||||
if(!screen_) return;
|
||||
|
||||
foreach(const map_location& loc, path)
|
||||
{
|
||||
screen_->invalidate(loc);
|
||||
|
@ -258,8 +264,7 @@ void arrow::invalidate_arrow_path(arrow_path_t path)
|
|||
|
||||
void arrow::notify_arrow_changed()
|
||||
{
|
||||
foreach(arrow_observer* observer, observers_)
|
||||
{
|
||||
observer->arrow_changed(*this);
|
||||
}
|
||||
if(!screen_) return;
|
||||
|
||||
screen_->update_arrow(*this);
|
||||
}
|
||||
|
|
|
@ -26,34 +26,32 @@
|
|||
#include <list>
|
||||
#include <map>
|
||||
|
||||
typedef std::map<map_location, image::locator> arrow_symbols_map_t;
|
||||
|
||||
typedef std::vector<map_location> arrow_path_t;
|
||||
|
||||
class arrow_observer;
|
||||
|
||||
/**
|
||||
* Arrows destined to be drawn on the map. Created for the whiteboard system.
|
||||
*/
|
||||
class arrow {
|
||||
|
||||
typedef std::map<map_location, image::locator> arrow_symbols_map_t;
|
||||
|
||||
public:
|
||||
//operations
|
||||
|
||||
arrow(display* screen);
|
||||
|
||||
|
||||
arrow();
|
||||
virtual ~arrow();
|
||||
|
||||
/// returns false if the received path is invalid
|
||||
virtual bool set_path(const arrow_path_t &path);
|
||||
|
||||
virtual void clear_path();
|
||||
|
||||
/**
|
||||
* The string color parameter is in the same format expected by the
|
||||
* image::locator modifiers parameter. Examples: red is "red" or "FF0000" or "255,0,0".
|
||||
* Feel free to add another method that accepts an Uint32 as a parameter instead.
|
||||
*/
|
||||
void set_color(const std::string& color);
|
||||
virtual void set_color(const std::string& color);
|
||||
|
||||
/**
|
||||
* The style is simply the name of a subdirectory under images/arrows,
|
||||
|
@ -73,14 +71,12 @@ public:
|
|||
|
||||
const arrow_path_t & get_previous_path() const;
|
||||
|
||||
void draw_hex(const map_location & hex);
|
||||
virtual void draw_hex(const map_location & hex);
|
||||
|
||||
/// Checks that the path is not of length 0 or 1
|
||||
bool valid_path(arrow_path_t path) const;
|
||||
virtual bool valid_path(arrow_path_t path) const;
|
||||
|
||||
void add_observer(arrow_observer & observer);
|
||||
|
||||
void remove_observer(arrow_observer & observer);
|
||||
virtual void notify_arrow_changed();
|
||||
|
||||
protected:
|
||||
//operations
|
||||
|
@ -88,19 +84,14 @@ protected:
|
|||
/**
|
||||
* @param old_path : the path to erase and replace with the new symbols
|
||||
*/
|
||||
void update_symbols(arrow_path_t old_path);
|
||||
virtual void update_symbols(arrow_path_t old_path);
|
||||
|
||||
void invalidate_arrow_path(arrow_path_t path);
|
||||
|
||||
private:
|
||||
//operations
|
||||
|
||||
void notify_arrow_changed();
|
||||
virtual void invalidate_arrow_path(arrow_path_t path);
|
||||
|
||||
protected:
|
||||
//properties
|
||||
|
||||
display* screen_;
|
||||
display*& screen_;
|
||||
|
||||
display::tdrawing_layer layer_;
|
||||
|
||||
|
@ -115,10 +106,5 @@ protected:
|
|||
arrow_path_t previous_path_;
|
||||
|
||||
arrow_symbols_map_t symbols_map_;
|
||||
|
||||
private:
|
||||
//properties
|
||||
std::list<arrow_observer*> observers_;
|
||||
|
||||
};
|
||||
#endif
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
/* $Id$ */
|
||||
/*
|
||||
Copyright (C) 2010 by Gabriel Morin <gabrielmorin (at) gmail (dot) org>
|
||||
Part of the Battle for Wesnoth Project http://www.wesnoth.org
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2
|
||||
or at your option any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file arrow_observer.hpp
|
||||
*/
|
||||
|
||||
#ifndef ARROW_OBSERVER_HPP_
|
||||
#define ARROW_OBSERVER_HPP_
|
||||
|
||||
/**
|
||||
* Interface implemented by any code interested of tracking an arrow's
|
||||
* changes (currently, only display implements it).
|
||||
*/
|
||||
class arrow_observer {
|
||||
public:
|
||||
|
||||
virtual ~arrow_observer() {}
|
||||
|
||||
virtual void arrow_changed(arrow & a) = 0;
|
||||
|
||||
};
|
||||
|
||||
#endif /* ARROW_OBSERVER_HPP_ */
|
|
@ -2339,7 +2339,6 @@ void display::add_arrow(arrow& arrow)
|
|||
{
|
||||
arrows_map_[loc].push_back(&arrow);
|
||||
}
|
||||
arrow.add_observer(*this);
|
||||
}
|
||||
|
||||
void display::remove_arrow(arrow& arrow)
|
||||
|
@ -2349,19 +2348,18 @@ void display::remove_arrow(arrow& arrow)
|
|||
{
|
||||
arrows_map_[loc].remove(&arrow);
|
||||
}
|
||||
arrow.remove_observer(*this);
|
||||
}
|
||||
|
||||
void display::arrow_changed(arrow & changed)
|
||||
void display::update_arrow(arrow & arrow)
|
||||
{
|
||||
const arrow_path_t & previous_path = changed.get_previous_path();
|
||||
const arrow_path_t & previous_path = arrow.get_previous_path();
|
||||
foreach (const map_location& loc, previous_path)
|
||||
{
|
||||
arrows_map_[loc].remove(&changed);
|
||||
arrows_map_[loc].remove(&arrow);
|
||||
}
|
||||
const arrow_path_t & arrow_path = changed.get_path();
|
||||
const arrow_path_t & arrow_path = arrow.get_path();
|
||||
foreach (const map_location& loc, arrow_path)
|
||||
{
|
||||
arrows_map_[loc].push_back(&changed);
|
||||
arrows_map_[loc].push_back(&arrow);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,7 +49,6 @@ class arrow;
|
|||
#include "theme.hpp"
|
||||
#include "video.hpp"
|
||||
#include "widgets/button.hpp"
|
||||
#include "arrow_observer.hpp"
|
||||
|
||||
#include "SDL.h"
|
||||
|
||||
|
@ -61,13 +60,13 @@ class arrow;
|
|||
#include <boost/function.hpp>
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
|
||||
typedef std::list<arrow*> arrows_list_t;
|
||||
typedef std::map<map_location, arrows_list_t > arrows_map_t;
|
||||
|
||||
class gamemap;
|
||||
|
||||
class display: public arrow_observer
|
||||
class display
|
||||
{
|
||||
typedef std::list<arrow*> arrows_list_t;
|
||||
typedef std::map<map_location, arrows_list_t > arrows_map_t;
|
||||
|
||||
public:
|
||||
display(CVideo& video, const gamemap* map, const config& theme_cfg,
|
||||
const config& level);
|
||||
|
@ -792,7 +791,7 @@ public: //operations for the arrow framework
|
|||
void remove_arrow(arrow&);
|
||||
|
||||
/** Called by arrow objects when they change. You should not need to call this directly. */
|
||||
virtual void arrow_changed(arrow & a);
|
||||
void update_arrow(arrow & a);
|
||||
|
||||
private:
|
||||
/** Handle for the label which displays frames per second. */
|
||||
|
|
|
@ -34,24 +34,20 @@ manager::manager():
|
|||
active_(false),
|
||||
mapbuilder_(NULL),
|
||||
route_(),
|
||||
move_arrow_(NULL),
|
||||
fake_unit_(NULL),
|
||||
move_arrow_(),
|
||||
fake_unit_(),
|
||||
selected_unit_(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
manager::~manager()
|
||||
{
|
||||
if (resources::screen != NULL)
|
||||
if (resources::screen)
|
||||
{
|
||||
if (fake_unit_.get() != NULL)
|
||||
if (fake_unit_)
|
||||
{
|
||||
resources::screen->remove_temporary_unit(fake_unit_.get());
|
||||
}
|
||||
if (move_arrow_.get() != NULL)
|
||||
{
|
||||
resources::screen->remove_arrow(*move_arrow_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -78,7 +74,6 @@ void manager::remove_temp_modifiers()
|
|||
{
|
||||
DBG_WB << "Removing temporary modifiers.\n";
|
||||
mapbuilder_.reset();
|
||||
DBG_WB << "Removed temporary modifiers.\n";
|
||||
}
|
||||
|
||||
void manager::select_unit(unit& unit)
|
||||
|
@ -89,8 +84,11 @@ void manager::select_unit(unit& unit)
|
|||
|
||||
void manager::deselect_unit()
|
||||
{
|
||||
DBG_WB << "Deselecting unit " << selected_unit_->name() << " [" << selected_unit_->id() << "]\n";
|
||||
selected_unit_ = NULL;
|
||||
if (selected_unit_)
|
||||
{
|
||||
DBG_WB << "Deselecting unit " << selected_unit_->name() << " [" << selected_unit_->id() << "]\n";
|
||||
selected_unit_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void manager::create_temp_move(const std::vector<map_location> &steps)
|
||||
|
@ -100,21 +98,20 @@ void manager::create_temp_move(const std::vector<map_location> &steps)
|
|||
{
|
||||
bool show_ghosted_unit_bars = false;
|
||||
|
||||
if (move_arrow_.get() == NULL)
|
||||
if (!move_arrow_)
|
||||
{
|
||||
// Create temp arrow
|
||||
game_display *screen = resources::screen;
|
||||
move_arrow_.reset(new arrow((display*) screen));
|
||||
move_arrow_.reset(new arrow());
|
||||
int current_side = resources::controller->current_side();
|
||||
move_arrow_->set_color(team::get_side_color_index(current_side));
|
||||
move_arrow_->set_alpha(2.0);
|
||||
screen->add_arrow(*move_arrow_);
|
||||
resources::screen->add_arrow(*move_arrow_);
|
||||
|
||||
// Create temp ghost unit
|
||||
fake_unit_.reset(new unit(*selected_unit_));
|
||||
fake_unit_->set_location(route_.back());
|
||||
fake_unit_->set_ghosted(show_ghosted_unit_bars);
|
||||
screen->place_temporary_unit(fake_unit_.get());
|
||||
resources::screen->place_temporary_unit(fake_unit_.get());
|
||||
}
|
||||
|
||||
move_arrow_->set_path(route_);
|
||||
|
@ -125,10 +122,9 @@ void manager::create_temp_move(const std::vector<map_location> &steps)
|
|||
|
||||
void manager::erase_temp_move()
|
||||
{
|
||||
if (move_arrow_.get() != NULL)
|
||||
if (move_arrow_)
|
||||
{
|
||||
resources::screen->remove_arrow(*move_arrow_);
|
||||
move_arrow_.reset();
|
||||
move_arrow_.reset(); //auto-removes itself from display
|
||||
resources::screen->remove_temporary_unit(fake_unit_.get());
|
||||
fake_unit_.reset();
|
||||
}
|
||||
|
@ -137,17 +133,17 @@ void manager::erase_temp_move()
|
|||
void manager::save_temp_move()
|
||||
{
|
||||
//If selected unit already has a move defined, erase it first
|
||||
|
||||
// TODO: implement a find_and_erase method in find_visitor to avoid iterating twice over actions
|
||||
{ // scope-limiting block
|
||||
find_visitor finder;
|
||||
action_ptr action = finder.find_first_action_of(*selected_unit_, get_current_side_actions().actions());
|
||||
if (action)
|
||||
{
|
||||
LOG_WB << "Previous action found for unit " << selected_unit_->name() << " [" << selected_unit_->id() << "]"
|
||||
<< ", erasing action.\n";
|
||||
get_current_side_actions().remove_action(action);
|
||||
}
|
||||
} // end scope-limiting block
|
||||
|
||||
find_visitor finder;
|
||||
action_ptr action = finder.find_first_action_of(*selected_unit_, get_current_side_actions().actions());
|
||||
if (action)
|
||||
{
|
||||
LOG_WB << "Previous action found for unit " << selected_unit_->name() << " [" << selected_unit_->id() << "]"
|
||||
<< ", erasing action.\n";
|
||||
get_current_side_actions().remove_action(action);
|
||||
}
|
||||
|
||||
//Define the new move
|
||||
LOG_WB << "Creating move for unit " << selected_unit_->name() << " [" << selected_unit_->id() << "]"
|
||||
|
@ -156,9 +152,9 @@ void manager::save_temp_move()
|
|||
|
||||
move_arrow_->set_alpha(0.6);
|
||||
|
||||
get_current_side_actions().queue_move(*selected_unit_, route_.back(),
|
||||
*(move_arrow_.release()) /* ownership of the arrow transferred to the new move action */,
|
||||
*(fake_unit_.release()) /* ownership of the fake unit transferred to the new move action */);
|
||||
get_current_side_actions().queue_move(*selected_unit_, route_.back(), move_arrow_, fake_unit_);
|
||||
move_arrow_.reset();
|
||||
fake_unit_.reset();
|
||||
}
|
||||
|
||||
} // end namespace wb
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "map_location.hpp"
|
||||
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
@ -81,8 +82,8 @@ private:
|
|||
|
||||
std::vector<map_location> route_;
|
||||
|
||||
std::auto_ptr<arrow> move_arrow_;
|
||||
std::auto_ptr<unit> fake_unit_;
|
||||
boost::shared_ptr<arrow> move_arrow_;
|
||||
boost::shared_ptr<unit> fake_unit_;
|
||||
|
||||
unit* selected_unit_;
|
||||
};
|
||||
|
|
|
@ -28,27 +28,24 @@
|
|||
|
||||
namespace wb {
|
||||
|
||||
move::move(unit& subject, const map_location& target_hex, arrow& arrow, unit& fake_unit)
|
||||
move::move(unit& subject, const map_location& target_hex, boost::shared_ptr<arrow> arrow,
|
||||
boost::shared_ptr<unit> fake_unit)
|
||||
: unit_(subject),
|
||||
orig_hex_(subject.get_location()),
|
||||
dest_hex_(target_hex),
|
||||
arrow_(&arrow),
|
||||
fake_unit_(&fake_unit)
|
||||
arrow_(arrow),
|
||||
fake_unit_(fake_unit)
|
||||
{
|
||||
}
|
||||
|
||||
move::~move()
|
||||
{
|
||||
if (resources::screen != NULL)
|
||||
if (resources::screen)
|
||||
{
|
||||
if (fake_unit_.get() != NULL)
|
||||
if (fake_unit_)
|
||||
{
|
||||
resources::screen->remove_temporary_unit(fake_unit_.get());
|
||||
}
|
||||
if (arrow_.get() != NULL)
|
||||
{
|
||||
resources::screen->remove_arrow(*arrow_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,8 +22,6 @@
|
|||
#include "action.hpp"
|
||||
#include "map_location.hpp"
|
||||
|
||||
#include <memory>
|
||||
|
||||
class arrow;
|
||||
class config;
|
||||
class unit;
|
||||
|
@ -38,8 +36,8 @@ namespace wb {
|
|||
class move: public action
|
||||
{
|
||||
public:
|
||||
/// Takes ownership of arrow and fake_unit
|
||||
move(unit& subject, const map_location& target_hex, arrow& arrow, unit& fake_unit);
|
||||
move(unit& subject, const map_location& target_hex, boost::shared_ptr<arrow> arrow,
|
||||
boost::shared_ptr<unit> fake_unit);
|
||||
virtual ~move();
|
||||
|
||||
virtual void accept(visitor& v);
|
||||
|
@ -58,8 +56,8 @@ private:
|
|||
map_location orig_hex_;
|
||||
map_location dest_hex_;
|
||||
|
||||
std::auto_ptr<arrow> arrow_;
|
||||
std::auto_ptr<unit> fake_unit_;
|
||||
boost::shared_ptr<arrow> arrow_;
|
||||
boost::shared_ptr<unit> fake_unit_;
|
||||
};
|
||||
|
||||
} // end namespace wb
|
||||
|
|
|
@ -38,14 +38,16 @@ const action_set& side_actions::actions() const
|
|||
return actions_;
|
||||
}
|
||||
|
||||
void side_actions::insert_move(unit& subject, const map_location& target_hex, arrow& arrow, size_t index, unit& fake_unit)
|
||||
void side_actions::insert_move(unit& subject, const map_location& target_hex, size_t index, boost::shared_ptr<arrow> arrow,
|
||||
boost::shared_ptr<unit> fake_unit)
|
||||
{
|
||||
action_ptr action(new move(subject, target_hex, arrow, fake_unit));
|
||||
assert(index < end());
|
||||
actions_.insert(actions_.begin() + index, action);
|
||||
}
|
||||
|
||||
void side_actions::queue_move(unit& subject, const map_location& target_hex, arrow& arrow, unit& fake_unit)
|
||||
void side_actions::queue_move(unit& subject, const map_location& target_hex, boost::shared_ptr<arrow> arrow,
|
||||
boost::shared_ptr<unit> fake_unit)
|
||||
{
|
||||
action_ptr action(new move(subject, target_hex, arrow, fake_unit));
|
||||
actions_.push_back(action);
|
||||
|
|
|
@ -57,15 +57,15 @@ public:
|
|||
|
||||
/**
|
||||
* Inserts a move at the specified index. The begin() and end() functions might prove useful here.
|
||||
* Gives ownership of the arrow and fake_unit to the new move object
|
||||
*/
|
||||
void insert_move(unit& subject, const map_location& target_hex, arrow& arrow, size_t index, unit& fake_unit);
|
||||
void insert_move(unit& subject, const map_location& target_hex, size_t index, boost::shared_ptr<arrow> arrow,
|
||||
boost::shared_ptr<unit> fake_unit);
|
||||
|
||||
/**
|
||||
* Inserts a move to be executed last (i.e. at the back of the queue)
|
||||
* Gives ownership of the arrow and fake_unit to the new move object
|
||||
*/
|
||||
void queue_move(unit& subject, const map_location& target_hex, arrow& arrow, unit& fake_unit);
|
||||
void queue_move(unit& subject, const map_location& target_hex, boost::shared_ptr<arrow> arrow,
|
||||
boost::shared_ptr<unit> fake_unit);
|
||||
|
||||
/**
|
||||
* Moves an action earlier in the execution order (i.e. at the front of the queue),
|
||||
|
|
Loading…
Add table
Reference in a new issue