widelands-dev team mailing list archive
-
widelands-dev team
-
Mailing list archive
-
Message #00435
[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