← Back to team overview

widelands-dev team mailing list archive

[Merge] lp:~widelands-dev/widelands/csite_improvement into lp:widelands

 

cghislai has proposed merging lp:~widelands-dev/widelands/csite_improvement into lp:widelands.

Requested reviews:
  Widelands Developers (widelands-dev)
Related bugs:
  Bug #580905 in widelands: "write building status in a different font color for construction sites"
  https://bugs.launchpad.net/widelands/+bug/580905
  Bug #722087 in widelands: "hard to empty warehouse"
  https://bugs.launchpad.net/widelands/+bug/722087
  Bug #803284 in widelands: "While building, show range of the building on construction site"
  https://bugs.launchpad.net/widelands/+bug/803284
  Bug #1108083 in widelands: "Construction site window does not display specific building name"
  https://bugs.launchpad.net/widelands/+bug/1108083
  Bug #1132238 in widelands: "Open buildingwindow after closing of constructionsitewindow when construction has finished"
  https://bugs.launchpad.net/widelands/+bug/1132238

For more details, see:
https://code.launchpad.net/~widelands-dev/widelands/csite_improvement/+merge/174623

This contains a bunch of improvements not all related to construction sites
- Colored string for production efficiency and trends
- Anchored selection for ware selection in warehouses/economy settings
- Range of building shown for construction sites
- Building name shown in construction site windows
- Building window opened when construction site window was open and construction ended
-- 
https://code.launchpad.net/~widelands-dev/widelands/csite_improvement/+merge/174623
Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands/csite_improvement into lp:widelands.
=== modified file 'src/constants.h'
--- src/constants.h	2013-07-13 14:32:49 +0000
+++ src/constants.h	2013-07-14 21:52:24 +0000
@@ -80,9 +80,11 @@
 #define PROSA_FONT_CLR_FG    RGBColor(255, 255,   0)
 
 /// Colors for good/ok/bad
-#define UI_FONT_CLR_BAD_HEX   "ff0000"
-#define UI_FONT_CLR_OK_HEX   "ffff00"
-#define UI_FONT_CLR_GOOD_HEX   "325b1f"
+#define UI_FONT_CLR_BRIGHT_HEX    "fffaaa"
+#define UI_FONT_CLR_DARK_HEX      "a39013"
+#define UI_FONT_CLR_BAD_HEX       "bb0000"
+#define UI_FONT_CLR_OK_HEX        "ffe11e"
+#define UI_FONT_CLR_GOOD_HEX      "00bb00"
 //@}
 
 /** \name Text colors

=== modified file 'src/logic/building.h'
--- src/logic/building.h	2013-07-14 10:38:26 +0000
+++ src/logic/building.h	2013-07-14 21:52:24 +0000
@@ -183,7 +183,7 @@
 	virtual bool burn_on_destroy();
 	virtual void destroy(Editor_Game_Base &);
 
-	void show_options(Interactive_GameBase &, bool avoid_fastclick = false);
+	void show_options(Interactive_GameBase &, bool avoid_fastclick = false, Point pos = Point(- 1, - 1));
 	void hide_options();
 	void refresh_options(Interactive_GameBase &);
 

=== modified file 'src/logic/constructionsite.cc'
--- src/logic/constructionsite.cc	2013-07-14 10:38:26 +0000
+++ src/logic/constructionsite.cc	2013-07-14 21:52:24 +0000
@@ -25,17 +25,20 @@
 #include "upcast.h"
 #include "wexception.h"
 
-#include "graphic/animation.h"
 #include "economy/wares_queue.h"
 #include "game.h"
+#include "graphic/animation.h"
 #include "graphic/graphic.h"
 #include "graphic/rendertarget.h"
 #include "sound/sound_handler.h"
+#include "ui_basic/window.h"
+#include "wui/interactive_gamebase.h"
 #include "tribe.h"
 #include "worker.h"
 
 #include "constructionsite.h"
 
+
 namespace Widelands {
 
 ConstructionSite_Descr::ConstructionSite_Descr
@@ -86,14 +89,9 @@
 std::string ConstructionSite::get_statistics_string()
 {
 	unsigned int percent = (get_built_per64k() * 100) >> 16;
-
-	std::string clr = UI_FONT_CLR_OK_HEX;
-	if (percent <= 25) clr = UI_FONT_CLR_BAD_HEX;
-	else if (percent >= 75) clr = UI_FONT_CLR_GOOD_HEX;
-
-	std::string perc_s = (boost::format("<font color=%s>%i</font>") % clr % percent).str();
-
-	return (boost::format(_("%s%% built")) % perc_s.c_str()).str();
+	std::string perc_s =
+		(boost::format("<font color=%1$s>%2$i%% built</font>") % UI_FONT_CLR_DARK_HEX % percent).str();
+	return perc_s;
 }
 
 /*
@@ -102,9 +100,11 @@
 =======
 */
 WaresQueue & ConstructionSite::waresqueue(Ware_Index const wi) {
-	container_iterate_const(Wares, m_wares, i)
-		if ((*i.current)->get_ware() == wi)
+	container_iterate_const(Wares, m_wares, i) {
+		if ((*i.current)->get_ware() == wi) {
 			return **i.current;
+		}
+	}
 	throw wexception
 		("%s (%u) (building %s) has no WaresQueue for %u",
 		 name().c_str(), serial(), m_building->name().c_str(), wi.value());
@@ -183,6 +183,14 @@
 			builder->reset_tasks(ref_cast<Game, Editor_Game_Base>(egbase));
 			builder->set_location(&b);
 		}
+		// Open the new building window if needed
+		if (m_optionswindow) {
+			Point window_position = m_optionswindow->get_pos();
+			hide_options();
+			Interactive_GameBase & igbase =
+				ref_cast<Interactive_GameBase, Interactive_Base>(*egbase.get_ibase());
+			b.show_options(igbase, false, window_position);
+		}
 	}
 }
 

=== modified file 'src/logic/productionsite.cc'
--- src/logic/productionsite.cc	2013-05-25 09:30:35 +0000
+++ src/logic/productionsite.cc	2013-07-14 21:52:24 +0000
@@ -18,6 +18,7 @@
  */
 
 #include <libintl.h>
+#include <boost/format.hpp>
 
 #include "helper.h"
 #include "i18n.h"
@@ -242,21 +243,21 @@
 	uint32_t       nr_workers           = 0;
 	for (uint32_t i = nr_working_positions; i;)
 		nr_workers += m_working_positions[--i].worker ? 1 : 0;
-	if (!nr_workers)
-		return _("(not occupied)");
-	else if (uint32_t const nr_requests = nr_working_positions - nr_workers) {
-		char buffer[1000];
-		snprintf
-			(buffer, sizeof(buffer), "%s",
-			 ngettext("Worker missing", "Workers missing", nr_requests));
-		return buffer;
+	if (!nr_workers) {
+		 return
+			(boost::format("<font color=%s>%s</font>") % UI_FONT_CLR_BAD_HEX % _("(not occupied)")).str();
+	} else if (uint32_t const nr_requests = nr_working_positions - nr_workers) {
+		return (boost::format("<font color=%s>%s</font>") % UI_FONT_CLR_BAD_HEX
+			% ngettext(_("Worker missing"), _("Workers missing"), nr_requests)).str();
 	}
 
-	if (m_statistics_changed)
+	if (m_statistics_changed) {
 		calc_statistics();
+	}
 
-	if (m_is_stopped)
-		return _("(stopped)");
+	if (m_is_stopped) {
+		return (boost::format("<font color=%s>%s</font>") % UI_FONT_CLR_BRIGHT_HEX % _("(stopped)")).str();
+	}
 
 	return m_statistics_buffer;
 }
@@ -315,21 +316,43 @@
 				++lastOk;
 		}
 	}
-	uint8_t const percOk = (ok * 100) / STATISTICS_VECTOR_LENGTH;
-	uint8_t const lastPercOk = (lastOk * 100) / (STATISTICS_VECTOR_LENGTH / 2);
-
-	const std::string trend =
-		lastPercOk > percOk ? "+" : lastPercOk < percOk ? "-" : "=";
-
-	if (0 < percOk and percOk < 100)
-		snprintf
-			(m_statistics_buffer, sizeof(m_statistics_buffer),
-			 "%d%% %s", percOk, trend.c_str());
+	// Somehow boost::format doesn't handle correctly uint8_t in this case
+	unsigned int percOk = (ok * 100) / STATISTICS_VECTOR_LENGTH;
+	unsigned int lastPercOk = (lastOk * 100) / (STATISTICS_VECTOR_LENGTH / 2);
+
+	std::string color;
+	if (percOk < 33)
+		color = UI_FONT_CLR_BAD_HEX;
+	else if (percOk < 66)
+		color = UI_FONT_CLR_OK_HEX;
 	else
-		snprintf
-			(m_statistics_buffer, sizeof(m_statistics_buffer),
-			 "%d%%",    percOk);
-
+		color = UI_FONT_CLR_GOOD_HEX;
+	const std::string perc_str =
+		(boost::format("<font color=%1$s>%2$i%%</font>") % color % percOk).str();
+
+	std::string trend;
+	if (lastPercOk > percOk) {
+		color = UI_FONT_CLR_GOOD_HEX;
+		trend = "+";
+	} else if (lastPercOk < percOk) {
+		color = UI_FONT_CLR_BAD_HEX;
+		trend = "-";
+	} else {
+		color = UI_FONT_CLR_BRIGHT_HEX;
+		trend = "=";
+	}
+	const std::string trend_str =
+		(boost::format("<font color=%s>%s</font>") % color % trend).str();
+
+	if (0 < percOk and percOk < 100) {
+		snprintf
+			(m_statistics_buffer, sizeof(m_statistics_buffer),
+			 "%s %s", perc_str.c_str(), trend_str.c_str());
+	} else {
+		snprintf
+			(m_statistics_buffer, sizeof(m_statistics_buffer),
+			 "%s", perc_str.c_str());
+	}
 	m_last_stat_percent = percOk;
 
 	m_statistics_changed = false;

=== modified file 'src/logic/productionsite.h'
--- src/logic/productionsite.h	2013-04-22 20:15:00 +0000
+++ src/logic/productionsite.h	2013-07-14 21:52:24 +0000
@@ -256,7 +256,7 @@
 	Input_Queues m_input_queues; ///< input queues for all inputs
 	std::vector<bool>        m_statistics;
 	bool                     m_statistics_changed;
-	char                     m_statistics_buffer[40];
+	char                     m_statistics_buffer[128];
 	char                     m_result_buffer   [213];
 	uint8_t                  m_last_stat_percent;
 	bool                     m_is_stopped;

=== modified file 'src/wui/building_ui.cc'
--- src/wui/building_ui.cc	2013-07-09 05:53:39 +0000
+++ src/wui/building_ui.cc	2013-07-14 21:52:24 +0000
@@ -28,7 +28,7 @@
  * Create the building's options window if necessary and bring it to
  * the top to be seen by the player.
  */
-void Building::show_options(Interactive_GameBase & igbase, bool avoid_fastclick)
+void Building::show_options(Interactive_GameBase & igbase, bool avoid_fastclick, Point pos)
 {
 	if (m_optionswindow) {
 		if (m_optionswindow->is_minimal())
@@ -42,6 +42,9 @@
 		// get properly initialized
 		m_optionswindow->think();
 	}
+	if (pos.x >= 0 && pos.y >= 0) {
+		m_optionswindow->set_pos(pos);
+	}
 }
 
 /**

=== modified file 'src/wui/buildingwindow.cc'
--- src/wui/buildingwindow.cc	2013-07-13 15:58:52 +0000
+++ src/wui/buildingwindow.cc	2013-07-14 21:52:24 +0000
@@ -23,6 +23,7 @@
 #include "graphic/image.h"
 #include "graphic/rendertarget.h"
 #include "interactive_player.h"
+#include "logic/constructionsite.h"
 #include "logic/dismantlesite.h"
 #include "logic/maphollowregion.h"
 #include "logic/militarysite.h"
@@ -36,7 +37,6 @@
 #include "waresqueuedisplay.h"
 
 #include "buildingwindow.h"
-#include "logic/militarysite.h"
 
 static const char * pic_bulldoze           = "pics/menu_bld_bulldoze.png";
 static const char * pic_dismantle          = "pics/menu_bld_dismantle.png";
@@ -78,17 +78,25 @@
 
 	set_center_panel(vbox);
 	set_think(true);
+	set_fastclick_panel(this);
 
+	// Work area
 	char filename[] = "pics/workarea0cumulative.png";
 	compile_assert(NUMBER_OF_WORKAREA_PICS <= 9);
 	for (Workarea_Info::size_type i = 0; i < NUMBER_OF_WORKAREA_PICS; ++i) {
 		++filename[13];
 		workarea_cumulative_pic[i] = g_gr->images().get(filename);
 	}
-
 	show_workarea();
 
-	set_fastclick_panel(this);
+	// Title for construction site
+	upcast(Widelands::ConstructionSite, csite, &m_building);
+	if (csite != NULL) {
+		char cs_title[256];
+		// Show name in parenthesis as it may take all width already
+		sprintf(cs_title, _("(%s)"), csite->building().descname().c_str());
+		set_title(cs_title);
+	}
 }
 
 
@@ -512,12 +520,20 @@
  */
 void Building_Window::show_workarea()
 {
-	if (m_workarea_job_id)
+	if (m_workarea_job_id) {
 		return; // already shown, nothing to be done
+	}
 
-	const Workarea_Info & workarea_info = m_building.descr().m_workarea_info;
-	if (workarea_info.size() == 0)
+	Workarea_Info workarea_info;
+	upcast(Widelands::ConstructionSite, csite, &m_building);
+	if (csite != NULL) {
+		workarea_info = csite->building().m_workarea_info;
+	} else {
+		workarea_info = m_building.descr().m_workarea_info;
+	}
+	if (workarea_info.size() == 0) {
 		return; // building has no workarea
+	}
 
 	Widelands::Map & map =
 		ref_cast<const Interactive_GameBase, UI::Panel>(*get_parent()).egbase()

=== modified file 'src/wui/waresdisplay.cc'
--- src/wui/waresdisplay.cc	2013-03-01 23:12:08 +0000
+++ src/wui/waresdisplay.cc	2013-07-14 21:52:24 +0000
@@ -63,8 +63,12 @@
 	m_hidden
 		(m_type == Widelands::wwWORKER ? m_tribe.get_nrworkers()
 	                          : m_tribe.get_nrwares(), false),
+	m_in_selection
+		(m_type == Widelands::wwWORKER ? m_tribe.get_nrworkers()
+	                          : m_tribe.get_nrwares(), false),
 	m_selectable(selectable),
 	m_horizontal(horizontal),
+	m_selection_anchor(Widelands::Ware_Index::Null()),
 	m_callback_function(callback_function)
 {
 	//resize the configuration of our wares if they won't fit in the current window
@@ -104,6 +108,9 @@
 		 .c_str()
 		 :
 		 "");
+	if (m_selection_anchor) {
+		update_anchor_selection(x, y);
+	}
 	return true;
 }
 
@@ -117,6 +124,12 @@
 
 		if (m_selectable) {
 			toggle_ware(ware);
+			// Mouserelase may be skipped sometimes here, so
+			// only anchor if needed.
+			if (!m_selection_anchor) {
+				// Anchor needs to be toggled for code consistency
+				m_selection_anchor = ware;
+			}
 		}
 		return true;
 	}
@@ -124,6 +137,32 @@
 	return UI::Panel::handle_mousepress(btn, x, y);
 }
 
+bool AbstractWaresDisplay::handle_mouserelease(Uint8 btn, int32_t x, int32_t y)
+{
+	if (btn != SDL_BUTTON_LEFT || !m_selection_anchor) {
+		return UI::Panel::handle_mouserelease(btn, x, y);
+	}
+	Widelands::Ware_Index const number = 
+		m_type == Widelands::wwWORKER ? m_tribe.get_nrworkers() : m_tribe.get_nrwares();
+
+	for (Widelands::Ware_Index i = Widelands::Ware_Index::First();
+			i < number; ++i) {
+		if (!m_in_selection[i]) {
+			continue;
+		}
+		if (ware_selected(m_selection_anchor)) {
+			select_ware(i);
+		} else {
+			unselect_ware(i);
+		}
+	}
+	// Release anchor, empty selection
+	m_selection_anchor = Widelands::Ware_Index::Null();
+	std::fill(m_in_selection.begin(), m_in_selection.end(), false);
+	return true;
+}
+
+
 /**
  * Returns the index of the ware under the given coordinates, or
  * WareIndex::Null() if the given point is outside the range.
@@ -151,6 +190,63 @@
 	return Widelands::Ware_Index::Null();
 }
 
+void AbstractWaresDisplay::update_anchor_selection(int32_t x, int32_t y)
+{
+	if (!m_selection_anchor || x < 0 || y < 0) {
+		return;
+	}
+
+	std::fill(m_in_selection.begin(), m_in_selection.end(), false);
+	Point pos0 = ware_position(m_selection_anchor);
+	// Add an offset to make sure the anchor line and column will be
+	// selected when selecting in topleft direction
+	int32_t x0 = pos0.x + 3;
+	int32_t y0 = pos0.y + 3;
+
+	unsigned int i0 = x0 / (WARE_MENU_PIC_WIDTH + 4);
+	unsigned int j0 = y0 / (WARE_MENU_PIC_HEIGHT + WARE_MENU_INFO_SIZE + 3);
+	unsigned int i = x / (WARE_MENU_PIC_WIDTH + 4);
+	unsigned int j = y / (WARE_MENU_PIC_HEIGHT + WARE_MENU_INFO_SIZE + 3);
+	unsigned int s;
+	// Reverse col/row and anchor/endpoint if needed
+	if (m_horizontal) {
+		s = i0;
+		i0 = j0;
+		j0 = s;
+		s = i;
+		i = j;
+		j = s;
+	}
+	if (i0 > i) {
+		s = i0;
+		i0 = i;
+		i = s;
+	}
+	if (j0 > j) {
+		s = j0;
+		j0 = j;
+		j = s;
+	}
+
+	for (unsigned int cur_i = i0; cur_i <= i; cur_i++) {
+		if (cur_i >= icons_order().size()) {
+			continue;
+		}
+		for (unsigned cur_j = j0; cur_j <= j; cur_j++) {
+			if (cur_j >= icons_order()[cur_i].size()) {
+				continue;
+			}
+			Widelands::Ware_Index ware = icons_order()[cur_i][cur_j];
+			if (m_hidden[ware]) {
+				continue;
+			}
+			m_in_selection[ware] = true;
+		}
+	}
+	update();
+}
+
+
 
 void AbstractWaresDisplay::layout()
 {
@@ -241,9 +337,18 @@
 {
 	Point p = ware_position(id);
 
+	bool draw_selected = m_selected[id];
+	if (m_selection_anchor) {
+		if (ware_selected(m_selection_anchor)) {
+			draw_selected |= m_in_selection[id];
+		} else {
+			draw_selected &= !m_in_selection[id];
+		}
+	}
+	
 	//  draw a background
 	const Image* bgpic =
-		g_gr->images().get(ware_selected(id) ?  "pics/ware_list_bg_selected.png" :  "pics/ware_list_bg.png");
+		g_gr->images().get(draw_selected ?  "pics/ware_list_bg_selected.png" :  "pics/ware_list_bg.png");
 	uint16_t w = bgpic->width();
 
 	dst.blit(p, bgpic);

=== modified file 'src/wui/waresdisplay.h'
--- src/wui/waresdisplay.h	2013-02-09 22:51:15 +0000
+++ src/wui/waresdisplay.h	2013-07-14 21:52:24 +0000
@@ -56,9 +56,8 @@
 
 	bool handle_mousemove
 		(uint8_t state, int32_t x, int32_t y, int32_t xdiff, int32_t ydiff);
-
 	bool handle_mousepress(uint8_t btn, int32_t x, int32_t y);
-
+	bool handle_mouserelease(Uint8 btn, int32_t x, int32_t y);
 
 	// Wares may be selected (highlighted)
 	void select_ware(Widelands::Ware_Index);
@@ -100,13 +99,18 @@
 	typedef std::vector<const Widelands::WareList *> vector_type;
 	typedef std::vector<bool> selection_type;
 
+	// Temporary achored selection
+	void update_anchor_selection(int32_t x, int32_t y);
+
 	const Widelands::Tribe_Descr & m_tribe;
 	Widelands::WareWorker m_type;
 	UI::Textarea        m_curware;
 	selection_type      m_selected;
 	selection_type      m_hidden;
+	selection_type      m_in_selection;  //Wares in temporary achored selection
 	bool                m_selectable;
 	bool                m_horizontal;
+	Widelands::Ware_Index m_selection_anchor; 
 	boost::function<void(Widelands::Ware_Index, bool)> m_callback_function;
 };
 


Follow ups