← Back to team overview

widelands-dev team mailing list archive

[Merge] lp:~nomeata/widelands/plot-improvements into lp:widelands

 

Joachim Breitner has proposed merging lp:~nomeata/widelands/plot-improvements into lp:widelands.

Requested reviews:
  Widelands Developers (widelands-dev)
Related bugs:
  Bug #536543 in widelands: "Add "whole game" to the time axis in statistics"
  https://bugs.launchpad.net/widelands/+bug/536543

For more details, see:
https://code.launchpad.net/~nomeata/widelands/plot-improvements/+merge/81360

Plot time slider offers only sensible times, automatically find a good choice of units and xticks, make units translatable and use buttons for the player selection.
-- 
https://code.launchpad.net/~nomeata/widelands/plot-improvements/+merge/81360
Your team Widelands Developers is requested to review the proposed merge of lp:~nomeata/widelands/plot-improvements into lp:widelands.
=== modified file 'src/ui_basic/button.h'
--- src/ui_basic/button.h	2011-11-04 18:22:20 +0000
+++ src/ui_basic/button.h	2011-11-05 14:59:26 +0000
@@ -79,6 +79,7 @@
 
 	// Set the permanently pressed state of the button
 	void set_perm_pressed(bool state);
+	bool get_perm_pressed() const { return m_permpressed;}
 
 	// Set button to flat / not flat
 	void set_flat(bool flat);

=== modified file 'src/ui_basic/slider.cc'
--- src/ui_basic/slider.cc	2011-11-04 21:42:45 +0000
+++ src/ui_basic/slider.cc	2011-11-05 14:59:26 +0000
@@ -380,18 +380,20 @@
 {
 	RGBAColor black(0, 0, 0, 255);
 
-	dst.brighten_rect //  bottom edge
-		(Rect(Point(get_x_gap(), get_h() / 2), get_bar_size(), 2),
-		 BUTTON_EDGE_BRIGHT_FACTOR);
-	dst.brighten_rect //  right edge
-		(Rect(Point(get_x_gap() + get_bar_size() - 2, get_y_gap()), 2, 2),
-		 BUTTON_EDGE_BRIGHT_FACTOR);
+	if (get_bar_size() > 0) {
+		dst.brighten_rect //  bottom edge
+			(Rect(Point(get_x_gap(), get_h() / 2), get_bar_size(), 2),
+			 BUTTON_EDGE_BRIGHT_FACTOR);
+		dst.brighten_rect //  right edge
+			(Rect(Point(get_x_gap() + get_bar_size() - 2, get_y_gap()), 2, 2),
+			 BUTTON_EDGE_BRIGHT_FACTOR);
 
-	//  top edge
-	dst.fill_rect
-		(Rect(Point(get_x_gap(), get_y_gap()),     get_bar_size() - 1, 1), black);
-	dst.fill_rect
-		(Rect(Point(get_x_gap(), get_y_gap() + 1), get_bar_size() - 2, 1), black);
+		//  top edge
+		dst.fill_rect
+			(Rect(Point(get_x_gap(), get_y_gap()),     get_bar_size() - 1, 1), black);
+		dst.fill_rect
+			(Rect(Point(get_x_gap(), get_y_gap() + 1), get_bar_size() - 2, 1), black);
+	}
 
 	//  left edge
 	dst.fill_rect(Rect(Point(get_x_gap(),     get_y_gap()), 1, 4), black);

=== modified file 'src/wui/general_statistics_menu.cc'
--- src/wui/general_statistics_menu.cc	2011-11-04 22:07:49 +0000
+++ src/wui/general_statistics_menu.cc	2011-11-05 14:59:26 +0000
@@ -129,28 +129,30 @@
 	iterate_players_existing_const(p, nr_players, game, player) ++plr_in_game;
 
 	pos.x = spacing;
-	int32_t button_size =
-		(get_inner_w() - (spacing * (plr_in_game + 1))) / plr_in_game;
 	iterate_players_existing_const(p, nr_players, game, player) {
 		char buffer[36];
 		snprintf(buffer, sizeof(buffer), "pics/genstats_enable_plr_%02u.png", p);
-		UI::Checkbox & cb =
-			*new UI::Checkbox
-				(this, pos, g_gr->get_picture(PicMod_Game, buffer));
-		cb.set_size(button_size, 25);
-		cb.set_id(p);
-		cb.set_state(1);
-		cb.set_tooltip(player->get_name().c_str());
-		cb.changedtoid.set(this, &General_Statistics_Menu::cb_changed_to);
+		UI::Callback_Button & cb =
+			*new UI::Callback_Button
+				(this, "playerbutton",
+				 pos.x, pos.y, 25, 25,
+				 g_gr->get_picture(PicMod_UI, "pics/but4.png"),
+				 g_gr->get_picture(PicMod_Game, buffer),
+				 boost::bind
+				 	(&General_Statistics_Menu::cb_changed_to,
+					 boost::ref(*this),
+					p),
+				 player->get_name().c_str());
+		cb.set_perm_pressed(true);
 		m_cbs[p - 1] = &cb;
-		pos.x += button_size + spacing;
+		pos.x += 25 + spacing;
 	} else //  player nr p does not exist
 		m_cbs[p - 1] = 0;
 
 	pos.x  = spacing;
 	pos.y += 25 + spacing + spacing;
 
-	button_size =
+	int32_t button_size =
 		(get_inner_w() - spacing * (m_ndatasets + 1))
 		/
 		m_ndatasets;
@@ -257,11 +259,14 @@
 /*
  * Cb has been changed to this state
  */
-void General_Statistics_Menu::cb_changed_to(int32_t const id, bool const what)
+void General_Statistics_Menu::cb_changed_to(int32_t const id)
 {
 	// This represents our player number
+	m_cbs[id - 1]->set_perm_pressed(not m_cbs[id - 1]->get_perm_pressed());	
+	
 	m_plot.show_plot
-		((id - 1) * m_ndatasets + m_selected_information, what);
+		((id - 1) * m_ndatasets + m_selected_information,
+		 m_cbs[id - 1]->get_perm_pressed());
 }
 
 /*
@@ -274,7 +279,7 @@
 	for (uint32_t i = 0; i < statistics_size; ++i)
 		if (m_cbs[i]) {
 			m_plot.show_plot
-				(i * m_ndatasets + id, m_cbs[i]->get_state());
+				(i * m_ndatasets + id, m_cbs[i]->get_perm_pressed());
 			m_plot.show_plot
 				(i * m_ndatasets + m_selected_information, false);
 		}

=== modified file 'src/wui/general_statistics_menu.h'
--- src/wui/general_statistics_menu.h	2010-09-04 13:50:09 +0000
+++ src/wui/general_statistics_menu.h	2011-11-05 14:59:26 +0000
@@ -25,11 +25,11 @@
 #include "plot_area.h"
 
 #include "ui_basic/radiobutton.h"
+#include "ui_basic/button.h"
 #include "ui_basic/unique_window.h"
 
 struct Interactive_GameBase;
 namespace UI {
-struct Checkbox;
 struct Radiogroup;
 }
 
@@ -41,11 +41,11 @@
 	WUIPlot_Area         m_plot;
 	UI::Radiogroup       m_radiogroup;
 	int32_t              m_selected_information;
-	UI::Checkbox       * m_cbs[MAX_PLAYERS];
+	UI::Callback_Button * m_cbs[MAX_PLAYERS];
 	uint32_t             m_ndatasets;
 
 	void clicked_help();
-	void cb_changed_to(int32_t, bool);
+	void cb_changed_to(int32_t);
 	void radiogroup_changed(int32_t);
 };
 

=== modified file 'src/wui/plot_area.cc'
--- src/wui/plot_area.cc	2011-11-04 22:07:49 +0000
+++ src/wui/plot_area.cc	2011-11-05 14:59:26 +0000
@@ -19,48 +19,31 @@
 
 #include "plot_area.h"
 
+#include "i18n.h"
 #include "constants.h"
 #include "graphic/font.h"
 #include "graphic/font_handler.h"
 #include "graphic/graphic.h"
 #include "graphic/rendertarget.h"
 
+
 #include "ui_basic/panel.h"
 
 #include <cstdio>
-
-
-/*
- * Where to draw tics
- */
-static const int32_t how_many_ticks[] = {
-	5,  // 15 Mins
-	3,  // 30 Mins
-	6,  // 1  H
-	4,  // 2  H
-	4,  // 4  H
-	4,  // 8  H
-	4,  // 16 H
-};
-
-static const int32_t max_x[] = {
-	15,
-	30,
-	60,
-	120,
-	4,
-	8,
-	16
-};
+#include <boost/lexical_cast.hpp>
+
+static const uint32_t minutes = 60 * 1000;
+static const uint32_t hours = 60 * 60 * 1000;
+static const uint32_t days = 24 * 60 * 60 * 1000;
 
 static const uint32_t time_in_ms[] = {
-	15      * 60 * 1000,
-	30      * 60 * 1000,
-	1  * 60 * 60 * 1000,
-	2  * 60 * 60 * 1000,
-	4  * 60 * 60 * 1000,
-	8  * 60 * 60 * 1000,
-	16 * 60 * 60 * 1000,
+	15 * minutes,
+	30 * minutes,
+	1  * hours,
+	2  * hours,
+	5  * hours,
+	10 * hours,
+	30 * hours
 };
 
 #define NR_SAMPLES 30   // How many samples per diagramm when relative plotting
@@ -74,16 +57,128 @@
 	 int32_t const x, int32_t const y, int32_t const w, int32_t const h)
 :
 UI::Panel (parent, x, y, w, h),
-m_time    (TIME_ONE_HOUR),
+m_time    (TIME_GAME),
 m_plotmode(PLOTMODE_ABSOLUTE)
 {}
 
 
+uint32_t WUIPlot_Area::get_game_time() {
+	uint32_t game_time = 0;
+
+	// Find running time of the game, based on the plot data
+	for (uint32_t plot = 0; plot < m_plotdata.size(); ++plot)
+		if (game_time < m_plotdata[plot].dataset->size() * m_sample_rate)
+			game_time = m_plotdata[plot].dataset->size() * m_sample_rate;
+	return game_time;
+}
+
+uint32_t WUIPlot_Area::get_plot_time() {
+	if (m_time == TIME_GAME) {
+		// Start with the game time
+		uint32_t time_in_ms_ = get_game_time();
+
+		// Round up to a nice nearest multiple.
+		// Either a multiple of 4 min
+		// Either a multiple of 20 min
+		// or a multiple of 2h
+		// or a multiple of 20h
+		// or a multiple of 4 days
+		if (time_in_ms_ > 8 * days) {
+			time_in_ms_ += - (time_in_ms_ % (4 * days)) + 4 * days;
+		} else if (time_in_ms_ > 40 * hours) {
+			time_in_ms_ += - (time_in_ms_ % (20 * hours)) + 20 * hours;
+		} else if (time_in_ms_ > 4 * hours) {
+			time_in_ms_ += - (time_in_ms_ % (2 * hours)) + 2 * hours;
+		} else if (time_in_ms_ > 40 * minutes) {
+			time_in_ms_ += - (time_in_ms_ % (20 * minutes)) + 20 * minutes;
+		} else {
+			time_in_ms_ += - (time_in_ms_ % (4 * minutes)) + 5 * minutes;
+		}
+		return time_in_ms_;
+	} else {
+		return time_in_ms[m_time];
+	}
+}
+
+WUIPlot_Area::UNIT WUIPlot_Area::get_suggested_unit(uint32_t game_time) {
+	// Find a nice unit for max_x
+	if (game_time > 4 * days) {
+		return UNIT_DAY;
+	} else if (game_time > 4 * hours) {
+		return UNIT_HOUR;
+	} else {
+		return UNIT_MIN;
+	}
+}
+
+std::string WUIPlot_Area::get_unit_name(UNIT unit) {
+	switch (unit) {
+		case UNIT_DAY:  return _("d");
+		case UNIT_HOUR: return _("h");
+		case UNIT_MIN:  return _("min");
+	}
+}
+
+uint32_t WUIPlot_Area::ms_to_unit(UNIT unit, uint32_t ms) {
+	switch (unit) {
+		case UNIT_DAY: return ms / days;
+		case UNIT_HOUR: return ms / hours;
+		case UNIT_MIN: return ms / minutes;
+	}
+}
+
+std::vector<std::string> WUIPlot_Area::get_labels() {
+	std::vector<std::string> labels;
+	uint32_t game_time = get_game_time();
+	uint32_t i = 0;
+
+	for (i = 0; i < 7; i++) {
+		if (time_in_ms[i] < game_time) {
+			UNIT unit = get_suggested_unit(time_in_ms[i]);
+			uint32_t val = ms_to_unit(unit, time_in_ms[i]);
+			labels.push_back(boost::lexical_cast<std::string>(val) + get_unit_name(unit));
+		}
+	}
+	labels.push_back(_("game"));
+	m_game_label = i;
+	return labels;
+}
+
+
 /*
  * Draw this. This is the main function
  */
 void WUIPlot_Area::draw(RenderTarget & dst) {
 
+	uint32_t time_in_ms_, how_many_ticks, max_x;
+
+	time_in_ms_ = get_plot_time();
+	UNIT unit = get_suggested_unit(time_in_ms_);
+	max_x = ms_to_unit(unit, time_in_ms_);
+
+	// Find a nice division of max_x
+	if (max_x % 5 == 0) {
+		if (max_x <= 10) {
+			how_many_ticks = 5;
+		} else {
+			how_many_ticks = max_x / 5;
+			while (how_many_ticks > 7 && how_many_ticks % 2 == 0) {
+				how_many_ticks /= 2;
+			}
+			while (how_many_ticks > 7 && how_many_ticks % 3 == 0) {
+				how_many_ticks /= 3;
+			}
+			while (how_many_ticks > 7 && how_many_ticks % 5 == 0) {
+				how_many_ticks /= 5;
+			}
+			while (how_many_ticks > 7 && how_many_ticks % 7 == 0) {
+				how_many_ticks /= 7;
+			}
+		}
+	} else {
+		how_many_ticks = 4;
+	}
+
 	// first, tile the background
 	dst.tile
 		(Rect(Point(0, 0), get_inner_w(), get_inner_h()),
@@ -123,10 +218,10 @@
 	UI::TextStyle xtickstyle(UI::TextStyle::ui_small());
 	xtickstyle.fg = RGBColor(255, 0, 0);
 
-	float sub = xline_length / how_many_ticks[m_time];
+	float sub = xline_length / how_many_ticks;
 	float posx = get_inner_w() - space_at_right;
 	char buffer[200];
-	for (int32_t i = 0; i <= how_many_ticks[m_time]; ++i) {
+	for (uint32_t i = 0; i <= how_many_ticks; ++i) {
 		dst.draw_line
 			(static_cast<int32_t>(posx), get_inner_h() - space_at_bottom,
 			 static_cast<int32_t>(posx), get_inner_h() - space_at_bottom + 3,
@@ -134,7 +229,7 @@
 
 		snprintf
 			(buffer, sizeof(buffer),
-			 "%u", max_x[m_time] / how_many_ticks[m_time] * i);
+			 "%u", max_x / how_many_ticks * i);
 
 		UI::g_fh->draw_text
 			(dst, xtickstyle,
@@ -176,7 +271,7 @@
 				// How many do we take together
 				int32_t const how_many =
 					static_cast<int32_t>
-					((static_cast<float>(time_in_ms[m_time])
+					((static_cast<float>(time_in_ms_)
 					  /
 					  static_cast<float>(NR_SAMPLES))
 					 /
@@ -205,11 +300,17 @@
 		 Point(get_inner_w() - space_at_right - 2, spacing + 2),
 		 buffer, UI::Align_CenterRight);
 
+	//  print the used unit
+	UI::g_fh->draw_text
+		(dst, xtickstyle,
+		 Point(2, spacing + 2),
+		 get_unit_name(unit), UI::Align_CenterLeft);
+
 	//  plot the pixels
 	sub =
 		xline_length
 		/
-		(static_cast<float>(time_in_ms[m_time])
+		(static_cast<float>(time_in_ms_)
 		 /
 		 static_cast<float>(m_sample_rate));
 	for (uint32_t plot = 0; plot < m_plotdata.size(); ++plot)
@@ -222,7 +323,7 @@
 			if (m_plotmode == PLOTMODE_RELATIVE) {
 				//  How many do we take together.
 				const int32_t how_many = static_cast<int32_t>
-				((static_cast<float>(time_in_ms[m_time])
+				((static_cast<float>(time_in_ms_)
 				  /
 				  static_cast<float>(NR_SAMPLES))
 				 /
@@ -292,17 +393,9 @@
 };
 
 /*
- * set time
- */
-void WUIPlot_Area::set_time(TIME const id) {m_time = id;}
-
-/*
  * Set sample rate the data uses
  */
 void WUIPlot_Area::set_sample_rate(uint32_t const id) {
 	m_sample_rate = id;
 }
 
-std::string WUIPlot_Area::time_labels[WUIPlot_Area::TIME_LAST] =
-	{"15m", "30m", "1h", "2h", "4h", "8h", "16h"};
-

=== modified file 'src/wui/plot_area.h'
--- src/wui/plot_area.h	2011-11-04 22:07:49 +0000
+++ src/wui/plot_area.h	2011-11-05 14:59:26 +0000
@@ -41,9 +41,14 @@
 		TIME_FOUR_HOURS,
 		TIME_EIGHT_HOURS,
 		TIME_16_HOURS,
+		TIME_GAME,
 		TIME_LAST,
 	};
-	static std::string time_labels[TIME_LAST];
+	enum UNIT {
+		UNIT_MIN,
+		UNIT_HOUR,
+		UNIT_DAY,
+	};
 	enum PLOTMODE {
 		//  Always take the samples of some times together, so that the graph is
 		//  not completely zigg-zagged.
@@ -57,8 +62,16 @@
 
 	virtual void draw(RenderTarget &);
 
-	void set_time(TIME);
-	void set_time_int(int32_t time) {set_time(static_cast<TIME>(time)); };
+	void set_time(TIME id) {
+		m_time = id;
+	}
+
+	void set_time_int(int32_t time) {
+		if (time == m_game_label) 
+			set_time(TIME_GAME);
+		else 
+			set_time(static_cast<TIME>(time));
+	};
 	TIME get_time() {return static_cast<TIME>(m_time); };
 	void set_sample_rate(uint32_t id); // in milliseconds
 
@@ -68,7 +81,15 @@
 
 	void set_plotmode(int32_t id) {m_plotmode = id;}
 
+	std::vector<std::string> get_labels();
+
 private:
+	uint32_t get_game_time();
+	uint32_t get_plot_time();
+	UNIT get_suggested_unit(uint32_t game_time);
+	std::string get_unit_name(UNIT unit);
+	uint32_t ms_to_unit(UNIT unit, uint32_t ms);
+
 	struct __plotdata {
 		const std::vector<uint32_t> * dataset;
 		bool                          showplot;
@@ -78,6 +99,7 @@
 	int32_t                 m_time;  // How much do you want to list
 	int32_t                 m_sample_rate;
 	int32_t                 m_plotmode;
+	int32_t			m_game_label; // what label is used for TIME_GAME
 };
 
 /**
@@ -96,9 +118,7 @@
 	: DiscreteSlider
 		(parent,
 		 x, y, w, h,
-		 std::vector<std::string>
-		 	(WUIPlot_Area::time_labels,
-		 	 WUIPlot_Area::time_labels + WUIPlot_Area::TIME_LAST),
+		 plot_area.get_labels(),
 		 plot_area.get_time(),
 		 background_picture_id,
 		 tooltip_text,


Follow ups