widelands-dev team mailing list archive
-
widelands-dev team
-
Mailing list archive
-
Message #08408
[Merge] lp:~widelands-dev/widelands/notifications_shipwindow into lp:widelands
GunChleoc has proposed merging lp:~widelands-dev/widelands/notifications_shipwindow into lp:widelands.
Commit message:
Ships no longer know about their windows.
- Ships send a NoteShipWindow when window contents need to be changed / the window destroyed.
- Ship windows are now controlled by InteractiveGameBase.
- Made a bunch of functions in Ship const.
Requested reviews:
Widelands Developers (widelands-dev)
For more details, see:
https://code.launchpad.net/~widelands-dev/widelands/notifications_shipwindow/+merge/307048
Another one for Build 20.
I want to remove the dependency from logic to wui, and I think the Notification system is a good way of doing that. I'd like some feedback on the design before I do more of these.
I also made a bunch of functions in Ship const while I was at it.
--
Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands/notifications_shipwindow into lp:widelands.
=== modified file 'ChangeLog'
--- ChangeLog 2016-09-24 09:15:11 +0000
+++ ChangeLog 2016-09-28 15:09:32 +0000
@@ -1,4 +1,4 @@
-### Build 19 until r8110
+### Build 19 until r8119
* Animations, Icons and Overlays
@@ -57,7 +57,7 @@
- New maps: Archipelago Sea, Dolomites, Wide World
- Removed maps: Dry Riverbed, Long long way, War of the Valleys
- Overhauled maps: Comet Islands, Full Moon, Glacier Lake, Kings and Queens,
- Last Bastion, The Nile, Twin Lagoons, Volcanic Winter
+ Last Bastion, River Explorers, The Nile, Twin Lagoons, Volcanic Winter
- Added "hint" to the json file created by wl_map_info for use on the website.
@@ -125,7 +125,6 @@
- Other tribes’ buildings that have been conquered can now be dismantled
- Balancing: Added gold to building cost for Atlantean training sites.
Made Barbarian attack stronger.
- - Trainers now need the same tools as a soldier.
- When an expedition ship places a port, a bit of land is cleared of trees to
make room for a few buildings.
- Ports can be affected by terrain changes up to 3 tiles away from their original
=== modified file 'src/economy/portdock.cc'
--- src/economy/portdock.cc 2016-08-04 15:49:05 +0000
+++ src/economy/portdock.cc 2016-09-28 15:09:32 +0000
@@ -337,8 +337,7 @@
// The expedition goods are now on the ship, so from now on it is independent from the port
// and thus we switch the port to normal, so we could even start a new expedition,
cancel_expedition(game);
- if (upcast(InteractiveGameBase, igb, game.get_ibase()))
- ship.refresh_window(*igb);
+ Notifications::publish(NoteShipWindow(ship, NoteShipWindow::Action::kRefresh));
return fleet_->update(game);
}
}
=== modified file 'src/logic/map_objects/tribes/ship.cc'
--- src/logic/map_objects/tribes/ship.cc 2016-09-07 09:30:49 +0000
+++ src/logic/map_objects/tribes/ship.cc 2016-09-28 15:09:32 +0000
@@ -126,14 +126,13 @@
Ship::Ship(const ShipDescr& gdescr)
: Bob(gdescr),
- window_(nullptr),
fleet_(nullptr),
economy_(nullptr),
ship_state_(ShipStates::kTransport) {
}
Ship::~Ship() {
- close_window();
+ Notifications::publish(NoteShipWindow(*this, NoteShipWindow::Action::kRemove));
}
PortDock* Ship::get_destination(EditorGameBase& egbase) const {
@@ -680,8 +679,7 @@
expedition_.reset(nullptr);
- if (upcast(InteractiveGameBase, igb, game.get_ibase()))
- refresh_window(*igb);
+ Notifications::publish(NoteShipWindow(*this, NoteShipWindow::Action::kRefresh));
return start_task_idle(game, descr().main_animation(), 1500);
}
}
@@ -743,7 +741,7 @@
/**
* Find a path to the dock @p pd, returns its length, and the path optionally.
*/
-uint32_t Ship::calculate_sea_route(Game& game, PortDock& pd, Path* finalpath) {
+uint32_t Ship::calculate_sea_route(Game& game, PortDock& pd, Path* finalpath) const {
Map& map = game.map();
StepEvalAStar se(pd.get_warehouse()->get_position());
se.swim_ = true;
@@ -847,7 +845,7 @@
expedition_->island_exploration = false;
}
-WalkingDir Ship::get_scouting_direction() {
+WalkingDir Ship::get_scouting_direction() const {
if (expedition_ && ship_state_ == ShipStates::kExpeditionScouting &&
!expedition_->island_exploration) {
return expedition_->scouting_direction;
@@ -882,7 +880,7 @@
expedition_->island_exploration = true;
}
-IslandExploreDirection Ship::get_island_explore_direction() {
+IslandExploreDirection Ship::get_island_explore_direction() const {
if (expedition_ && ship_state_ == ShipStates::kExpeditionScouting &&
expedition_->island_exploration) {
return expedition_->island_explore_direction;
@@ -926,8 +924,7 @@
expedition_.reset(nullptr);
// And finally update our ship window
- if (upcast(InteractiveGameBase, igb, game.get_ibase()))
- refresh_window(*igb);
+ Notifications::publish(NoteShipWindow(*this, NoteShipWindow::Action::kRefresh));
}
/// Sinks the ship
@@ -936,10 +933,10 @@
// Running colonization has the highest priority + a sink request is only valid once
if (!state_is_sinkable())
return;
+ Notifications::publish(NoteShipWindow(*this, NoteShipWindow::Action::kRemove));
ship_state_ = ShipStates::kSinkRequest;
// Make sure the ship is active and close possible open windows
ship_wakeup(game);
- close_window();
}
void Ship::draw(const EditorGameBase& game, RenderTarget& dst, const Point& pos) const {
=== modified file 'src/logic/map_objects/tribes/ship.h'
--- src/logic/map_objects/tribes/ship.h 2016-09-07 09:30:49 +0000
+++ src/logic/map_objects/tribes/ship.h 2016-09-28 15:09:32 +0000
@@ -28,11 +28,6 @@
#include "graphic/diranimations.h"
#include "logic/map_objects/bob.h"
-namespace UI {
-class Window;
-}
-class InteractiveGameBase;
-
namespace Widelands {
class Economy;
@@ -59,6 +54,19 @@
}
};
+struct NoteShipWindow {
+ CAN_BE_SENT_AS_NOTE(NoteId::ShipWindow)
+
+ Ship& ship;
+
+ enum class Action { kRefresh, kRemove, kClosed };
+ const Action action;
+
+ NoteShipWindow(Ship& init_ship, const Action& init_action)
+ : ship(init_ship), action(init_action) {
+ }
+};
+
class ShipDescr : public BobDescr {
public:
ShipDescr(const std::string& init_descname, const LuaTable& t);
@@ -119,7 +127,7 @@
void start_task_movetodock(Game&, PortDock&);
void start_task_expedition(Game&);
- uint32_t calculate_sea_route(Game& game, PortDock& pd, Path* finalpath = nullptr);
+ uint32_t calculate_sea_route(Game& game, PortDock& pd, Path* finalpath = nullptr) const;
void log_general_info(const EditorGameBase&) override;
@@ -133,10 +141,6 @@
void withdraw_items(Game& game, PortDock& pd, std::vector<ShippingItem>& items);
void add_item(Game&, const ShippingItem& item);
- void show_window(InteractiveGameBase&, bool avoid_fastclick = false);
- void close_window();
- void refresh_window(InteractiveGameBase&);
-
// A ship with task expedition can be in four states: kExpeditionWaiting, kExpeditionScouting,
// kExpeditionPortspaceFound or kExpeditionColonizing in the first states, the owning player of
// this ship
@@ -169,42 +173,42 @@
};
/// \returns the current state the ship is in
- ShipStates get_ship_state() {
+ ShipStates get_ship_state() const {
return ship_state_;
}
/// \returns the current name of ship
- const std::string& get_shipname() {
+ const std::string& get_shipname() const {
return shipname_;
}
/// \returns whether the ship is currently on an expedition
- bool state_is_expedition() {
+ bool state_is_expedition() const {
return (ship_state_ == ShipStates::kExpeditionScouting ||
ship_state_ == ShipStates::kExpeditionWaiting ||
ship_state_ == ShipStates::kExpeditionPortspaceFound ||
ship_state_ == ShipStates::kExpeditionColonizing);
}
/// \returns whether the ship is in transport mode
- bool state_is_transport() {
+ bool state_is_transport() const {
return (ship_state_ == ShipStates::kTransport);
}
/// \returns whether a sink request for the ship is currently valid
- bool state_is_sinkable() {
+ bool state_is_sinkable() const {
return (ship_state_ != ShipStates::kSinkRequest &&
ship_state_ != ShipStates::kSinkAnimation &&
ship_state_ != ShipStates::kExpeditionColonizing);
}
/// \returns (in expedition mode only!) whether the next field in direction \arg dir is swimmable
- bool exp_dir_swimmable(Direction dir) {
+ bool exp_dir_swimmable(Direction dir) const {
if (!expedition_)
return false;
return expedition_->swimmable[dir - 1];
}
/// \returns whether the expedition ship is close to the coast
- bool exp_close_to_coast() {
+ bool exp_close_to_coast() const {
if (!expedition_)
return false;
for (uint8_t dir = FIRST_DIRECTION; dir <= LAST_DIRECTION; ++dir)
@@ -214,7 +218,7 @@
}
/// \returns (in expedition mode only!) the list of currently seen port build spaces
- const std::vector<Coords>& exp_port_spaces() {
+ const std::vector<Coords>& exp_port_spaces() const {
return expedition_->seen_port_buildspaces;
}
@@ -224,12 +228,12 @@
// Returns integer of direction, or WalkingDir::IDLE if query invalid
// Intended for LUA scripting
- WalkingDir get_scouting_direction();
+ WalkingDir get_scouting_direction() const;
// Returns integer of direction, or IslandExploreDirection::kNotSet
// if query invalid
// Intended for LUA scripting
- IslandExploreDirection get_island_explore_direction();
+ IslandExploreDirection get_island_explore_direction() const;
void exp_cancel(Game&);
void sink_ship(Game&);
@@ -239,7 +243,6 @@
private:
friend struct Fleet;
- friend struct ShipWindow;
void wakeup_neighbours(Game&);
@@ -261,8 +264,6 @@
const std::string& description,
const std::string& picture);
- UI::Window* window_;
-
Fleet* fleet_;
Economy* economy_;
OPtr<PortDock> lastdock_;
=== modified file 'src/notifications/note_ids.h'
--- src/notifications/note_ids.h 2016-03-03 21:46:11 +0000
+++ src/notifications/note_ids.h 2016-09-28 15:09:32 +0000
@@ -35,6 +35,7 @@
ProductionSiteOutOfResources,
TrainingSiteSoldierTrained,
ShipMessage,
+ ShipWindow,
GraphicResolutionChanged,
NoteExpeditionCanceled
};
=== modified file 'src/wui/CMakeLists.txt'
--- src/wui/CMakeLists.txt 2016-04-15 17:23:00 +0000
+++ src/wui/CMakeLists.txt 2016-09-28 15:09:32 +0000
@@ -153,6 +153,7 @@
quicknavigation.cc
quicknavigation.h
shipwindow.cc
+ shipwindow.h
soldiercapacitycontrol.cc
soldiercapacitycontrol.h
soldierlist.cc
=== modified file 'src/wui/interactive_gamebase.cc'
--- src/wui/interactive_gamebase.cc 2016-08-04 15:49:05 +0000
+++ src/wui/interactive_gamebase.cc 2016-09-28 15:09:32 +0000
@@ -34,6 +34,7 @@
#include "logic/player.h"
#include "profile/profile.h"
#include "wui/game_summary.h"
+#include "wui/shipwindow.h"
namespace {
@@ -63,6 +64,53 @@
toggle_buildhelp_(INIT_BTN(
"wui/menus/menu_toggle_buildhelp", "buildhelp", _("Show Building Spaces (on/off)"))) {
toggle_buildhelp_.sigclicked.connect(boost::bind(&InteractiveGameBase::toggle_buildhelp, this));
+
+ shipnotes_subscriber_ = Notifications::subscribe<Widelands::NoteShipWindow>(
+ [this](const Widelands::NoteShipWindow& note) {
+ const Widelands::Serial serial = note.ship.serial();
+ switch (note.action) {
+ // The ship state has changed or the user requested a new window
+ case Widelands::NoteShipWindow::Action::kRefresh: {
+ bool is_refreshing = false;
+ Point pos(0, 0);
+ ShipWindow* shipwindow;
+ if (shipwindows_.count(serial) == 1) {
+ shipwindow = shipwindows_.at(serial);
+ if (shipwindow) {
+ is_refreshing = true;
+ pos = shipwindow->get_pos();
+ delete shipwindow;
+ shipwindow = nullptr;
+ }
+ }
+ shipwindow = new ShipWindow(*this, note.ship, is_refreshing);
+ shipwindows_.insert(std::pair<Widelands::Serial, ShipWindow*>(serial, shipwindow));
+ if (is_refreshing) {
+ shipwindow->set_pos(pos);
+ }
+
+ } break;
+ // The ship has been removed
+ case Widelands::NoteShipWindow::Action::kRemove: {
+ if (shipwindows_.count(serial) == 1) {
+ ShipWindow* shipwindow = shipwindows_.at(serial);
+ if (shipwindow) {
+ delete shipwindow;
+ shipwindow = nullptr;
+ }
+ shipwindows_.erase(serial);
+ }
+
+ } break;
+ // The user closed the window
+ case Widelands::NoteShipWindow::Action::kClosed: {
+ if (shipwindows_.count(serial) == 1) {
+ shipwindows_.erase(serial);
+ }
+
+ } break;
+ }
+ });
}
/// \return a pointer to the running \ref Game instance.
@@ -158,7 +206,8 @@
for (Widelands::Bob* temp_ship : ships) {
if (upcast(Widelands::Ship, ship, temp_ship)) {
if (can_see(ship->get_owner()->player_number())) {
- ship->show_window(*this);
+ Notifications::publish(
+ Widelands::NoteShipWindow(*ship, Widelands::NoteShipWindow::Action::kRefresh));
return true;
}
}
=== modified file 'src/wui/interactive_gamebase.h'
--- src/wui/interactive_gamebase.h 2016-08-04 15:49:05 +0000
+++ src/wui/interactive_gamebase.h 2016-09-28 15:09:32 +0000
@@ -20,19 +20,28 @@
#ifndef WL_WUI_INTERACTIVE_GAMEBASE_H
#define WL_WUI_INTERACTIVE_GAMEBASE_H
+#include <map>
+#include <memory>
+
#include "logic/game.h"
+#include "logic/widelands.h"
+#include "notifications/notifications.h"
#include "profile/profile.h"
#include "wui/general_statistics_menu.h"
#include "wui/interactive_base.h"
struct ChatProvider;
+class ShipWindow;
+
+namespace Widelands {
+struct NoteShipWindow;
+}
enum PlayerType { NONE, OBSERVER, PLAYING, VICTORIOUS, DEFEATED };
class InteractiveGameBase : public InteractiveBase {
public:
- class GameMainMenuWindows {
- public:
+ struct GameMainMenuWindows {
UI::UniqueWindow::Registry loadgame;
UI::UniqueWindow::Registry savegame;
UI::UniqueWindow::Registry readme;
@@ -97,6 +106,11 @@
private:
void on_buildhelp_changed(const bool value) override;
+
+ // Registers all ship windows to avoid duplication
+ std::map<Widelands::Serial, ShipWindow*> shipwindows_;
+ // Handles opening, refreshing and closing of ship windows
+ std::unique_ptr<Notifications::Subscriber<Widelands::NoteShipWindow>> shipnotes_subscriber_;
};
#endif // end of include guard: WL_WUI_INTERACTIVE_GAMEBASE_H
=== modified file 'src/wui/shipwindow.cc'
--- src/wui/shipwindow.cc 2016-09-07 09:30:49 +0000
+++ src/wui/shipwindow.cc 2016-09-28 15:09:32 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011, 2013 by the Widelands Development Team
+ * Copyright (C) 2011 - 2016 by the Widelands Development Team
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -17,7 +17,7 @@
*
*/
-#include "logic/map_objects/tribes/ship.h"
+#include "wui/shipwindow.h"
#include "base/macros.h"
#include "economy/portdock.h"
@@ -29,10 +29,9 @@
#include "ui_basic/box.h"
#include "wui/actionconfirm.h"
#include "wui/game_debug_ui.h"
-#include "wui/interactive_gamebase.h"
#include "wui/interactive_player.h"
-#include "wui/itemwaresdisplay.h"
+namespace {
static const char pic_goto[] = "images/wui/ship/menu_ship_goto.png";
static const char pic_destination[] = "images/wui/ship/menu_ship_destination.png";
static const char pic_sink[] = "images/wui/ship/menu_ship_sink.png";
@@ -47,55 +46,13 @@
static const char pic_scout_sw[] = "images/wui/ship/ship_scout_sw.png";
static const char pic_scout_se[] = "images/wui/ship/ship_scout_se.png";
static const char pic_construct_port[] = "images/wui/editor/fsel_editor_set_port_space.png";
-
-namespace Widelands {
-
-/**
- * Display information about a ship.
- */
-struct ShipWindow : UI::Window {
- ShipWindow(InteractiveGameBase& igb, Ship& ship, const std::string& title);
- virtual ~ShipWindow();
-
- void think() override;
-
- UI::Button* make_button(UI::Panel* parent,
- const std::string& name,
- const std::string& title,
- const std::string& picname,
- boost::function<void()> callback);
-
- void act_goto();
- void act_destination();
- void act_sink();
- void act_debug();
- void act_cancel_expedition();
- void act_scout_towards(WalkingDir);
- void act_construct_port();
- void act_explore_island(IslandExploreDirection);
-
-private:
- InteractiveGameBase& igbase_;
- Ship& ship_;
-
- UI::Button* btn_goto_;
- UI::Button* btn_destination_;
- UI::Button* btn_sink_;
- UI::Button* btn_debug_;
- UI::Button* btn_cancel_expedition_;
- UI::Button* btn_explore_island_cw_;
- UI::Button* btn_explore_island_ccw_;
- UI::Button*
- btn_scout_[LAST_DIRECTION]; // format: DIRECTION - 1, as 0 is normally the current location.
- UI::Button* btn_construct_port_;
- ItemWaresDisplay* display_;
-};
-
-ShipWindow::ShipWindow(InteractiveGameBase& igb, Ship& ship, const std::string& title)
- : Window(&igb, "shipwindow", 0, 0, 0, 0, title), igbase_(igb), ship_(ship) {
- assert(!ship_.window_);
+} // namespace
+
+using namespace Widelands;
+
+ShipWindow::ShipWindow(InteractiveGameBase& igb, Ship& ship, bool avoid_fastclick)
+ : Window(&igb, "shipwindow", 0, 0, 0, 0, ship.get_shipname()), igbase_(igb), ship_(ship) {
assert(ship_.get_owner());
- ship_.window_ = this;
UI::Box* vbox = new UI::Box(this, 0, 0, UI::Box::Vertical);
@@ -190,15 +147,15 @@
}
set_center_panel(vbox);
set_thinks(true);
-
- center_to_parent();
- move_out_of_the_way();
set_fastclick_panel(btn_goto_);
+ if (!avoid_fastclick) {
+ move_out_of_the_way();
+ warp_mouse_to_fastclick_panel();
+ }
}
ShipWindow::~ShipWindow() {
- assert(ship_.window_ == this);
- ship_.window_ = nullptr;
+ Notifications::publish(NoteShipWindow(ship_, NoteShipWindow::Action::kClosed));
}
void ShipWindow::think() {
@@ -335,52 +292,3 @@
return;
igbase_.game().send_player_ship_explore_island(ship_, direction);
}
-
-/**
- * Show the window for this ship as long as it is not sinking:
- * either bring it to the front, or create it.
- */
-void Ship::show_window(InteractiveGameBase& igb, bool avoid_fastclick) {
- // No window, if ship is sinking
- if (ship_state_ == ShipStates::kSinkRequest || ship_state_ == ShipStates::kSinkAnimation)
- return;
-
- if (window_) {
- if (window_->is_minimal())
- window_->restore();
- window_->move_to_top();
- } else {
- const std::string& title = get_shipname();
- new ShipWindow(igb, *this, title);
- if (!avoid_fastclick)
- window_->warp_mouse_to_fastclick_panel();
- }
-}
-
-/**
- * Close the window for this ship.
- */
-void Ship::close_window() {
- if (window_) {
- delete window_;
- window_ = nullptr;
- }
-}
-
-/**
- * refreshes the window of this ship - useful if some ui elements have to be removed or added
- */
-void Ship::refresh_window(InteractiveGameBase& igb) {
- // Only do something if there is actually a window
- if (window_) {
- Point window_position = window_->get_pos();
- close_window();
- show_window(igb, true);
- // show window could theoretically fail if refresh_window was called at the very same moment
- // as the ship begins to sink
- if (window_)
- window_->set_pos(window_position);
- }
-}
-
-} // namespace Widelands
=== added file 'src/wui/shipwindow.h'
--- src/wui/shipwindow.h 1970-01-01 00:00:00 +0000
+++ src/wui/shipwindow.h 2016-09-28 15:09:32 +0000
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2011 - 2016 by the Widelands Development Team
+ *
+ * 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef WL_WUI_SHIPWINDOW_H
+#define WL_WUI_SHIPWINDOW_H
+
+#include "logic/game.h"
+#include "logic/map_objects/tribes/ship.h"
+#include "logic/map_objects/walkingdir.h"
+#include "notifications/notifications.h"
+#include "ui_basic/button.h"
+#include "ui_basic/window.h"
+#include "wui/interactive_gamebase.h"
+#include "wui/itemwaresdisplay.h"
+
+/**
+ * Display information about a ship.
+ */
+class ShipWindow : protected UI::Window {
+protected:
+ ShipWindow(InteractiveGameBase& igb, Widelands::Ship& ship, bool avoid_fastclick = false);
+ virtual ~ShipWindow();
+
+ void think() override;
+
+ UI::Button* make_button(UI::Panel* parent,
+ const std::string& name,
+ const std::string& title,
+ const std::string& picname,
+ boost::function<void()> callback);
+
+ void act_goto();
+ void act_destination();
+ void act_sink();
+ void act_debug();
+ void act_cancel_expedition();
+ void act_scout_towards(Widelands::WalkingDir);
+ void act_construct_port();
+ void act_explore_island(Widelands::IslandExploreDirection);
+
+private:
+ friend class InteractiveGameBase;
+ InteractiveGameBase& igbase_;
+ Widelands::Ship& ship_;
+
+ UI::Button* btn_goto_;
+ UI::Button* btn_destination_;
+ UI::Button* btn_sink_;
+ UI::Button* btn_debug_;
+ UI::Button* btn_cancel_expedition_;
+ UI::Button* btn_explore_island_cw_;
+ UI::Button* btn_explore_island_ccw_;
+ // format: DIRECTION - 1, as 0 is normally the current location.
+ UI::Button* btn_scout_[Widelands::LAST_DIRECTION];
+ UI::Button* btn_construct_port_;
+ ItemWaresDisplay* display_;
+};
+
+#endif // end of include guard: WL_WUI_SHIPWINDOW_H
Follow ups