widelands-dev team mailing list archive
-
widelands-dev team
-
Mailing list archive
-
Message #00453
[Merge] lp:~borim/widelands/economyChart into lp:widelands
Borim has proposed merging lp:~borim/widelands/economyChart into lp:widelands.
Requested reviews:
Widelands Developers (widelands-dev)
For more details, see:
https://code.launchpad.net/~borim/widelands/economyChart/+merge/81408
* collect ware consumption data for new charts
* add two new charts to the ware statistics menu
1. Consumption Chart: display the consumed wares
2. Economy Health Chart: display the difference between production and consumption
the work for this feature is not completed, some fine tuning is still needed.
e.g.: replace the tab icon place holder
--
https://code.launchpad.net/~borim/widelands/economyChart/+merge/81408
Your team Widelands Developers is requested to review the proposed merge of lp:~borim/widelands/economyChart into lp:widelands.
=== modified file 'src/game_io/game_player_info_data_packet.cc'
--- src/game_io/game_player_info_data_packet.cc 2011-09-24 20:41:50 +0000
+++ src/game_io/game_player_info_data_packet.cc 2011-11-06 17:03:27 +0000
@@ -30,7 +30,7 @@
namespace Widelands {
-#define CURRENT_PACKET_VERSION 13
+#define CURRENT_PACKET_VERSION 14
void Game_Player_Info_Data_Packet::Read
@@ -111,7 +111,9 @@
if (packet_version >= 6)
player.setAI(fr.CString());
- if (packet_version >= 12)
+ if (packet_version >= 14)
+ player.ReadStatistics(fr, 2);
+ else if (packet_version >= 12)
player.ReadStatistics(fr, 1);
else
player.ReadStatistics(fr, 0);
=== modified file 'src/logic/constructionsite.cc'
--- src/logic/constructionsite.cc 2011-11-05 21:17:47 +0000
+++ src/logic/constructionsite.cc 2011-11-06 17:03:27 +0000
@@ -284,6 +284,9 @@
wq.set_filled(wq.get_filled() - 1);
wq.set_max_size(wq.get_max_size() - 1);
+ //update consumption statistic
+ owner().ware_consumed(wq.get_ware(), 1);
+
m_working = true;
m_work_steptime = game.get_gametime() + CONSTRUCTIONSITE_STEP_TIME;
=== modified file 'src/logic/player.cc'
--- src/logic/player.cc 2011-11-05 18:19:37 +0000
+++ src/logic/player.cc 2011-11-06 17:03:27 +0000
@@ -91,8 +91,10 @@
m_allowed_worker_types (tribe_descr.get_nrworkers (), false),
m_allowed_building_types(tribe_descr.get_nrbuildings(), true),
m_ai(""),
- m_current_statistics(tribe_descr.get_nrwares ()),
- m_ware_productions (tribe_descr.get_nrwares ())
+ m_current_produced_statistics(tribe_descr.get_nrwares ()),
+ m_current_consumed_statistics(tribe_descr.get_nrwares ()),
+ m_ware_productions (tribe_descr.get_nrwares ()),
+ m_ware_consumptions (tribe_descr.get_nrwares ())
{
set_name(name);
}
@@ -1013,10 +1015,14 @@
void Player::sample_statistics()
{
assert (m_ware_productions.size() == tribe().get_nrwares().value());
+ assert (m_ware_consumptions.size() == tribe().get_nrwares().value());
for (uint32_t i = 0; i < m_ware_productions.size(); ++i) {
- m_ware_productions[i].push_back(m_current_statistics[i]);
- m_current_statistics[i] = 0;
+ m_ware_productions[i].push_back(m_current_produced_statistics[i]);
+ m_current_produced_statistics[i] = 0;
+
+ m_ware_consumptions[i].push_back(m_current_consumed_statistics[i]);
+ m_current_consumed_statistics[i] = 0;
}
}
@@ -1028,7 +1034,22 @@
assert (m_ware_productions.size() == tribe().get_nrwares().value());
assert(wareid.value() < tribe().get_nrwares().value());
- ++m_current_statistics[wareid];
+ ++m_current_produced_statistics[wareid];
+}
+
+
+/**
+ * Some units from one kind of ware were consumed.
+ * Update the corresponding statistics
+ *
+ * \param wareid the ID of the consumed wares
+ * \param count the number of consumed wares
+ */
+void Player::ware_consumed(Ware_Index const wareid, uint8_t const count) {
+ assert (m_ware_consumptions.size() == tribe().get_nrwares().value());
+ assert(wareid.value() < tribe().get_nrwares().value());
+
+ m_current_consumed_statistics[wareid] += count;
}
@@ -1045,6 +1066,18 @@
/**
+ * Get current ware consumption statistics
+ */
+const std::vector<uint32_t> * Player::get_ware_consumption_statistics
+ (Ware_Index const ware) const {
+
+ assert(ware.value() < m_ware_consumptions.size());
+
+ return &m_ware_consumptions[ware];
+}
+
+
+/**
* Add or remove the given building from building statistics.
* Only to be called by \ref receive
*/
@@ -1118,14 +1151,17 @@
* \param version indicates the kind of statistics file, which may be
* 0 - old style statistics (before WiHack 2010)
* 1 - statistics with ware names
+ * 2 - with consumption statistics
*/
void Player::ReadStatistics(FileRead & fr, uint32_t const version)
{
- if (version == 1) {
+ //version 1 and 2 only differs in an additional statistic.
+ //Use version 1 code for both
+ if ((version == 2) || (version == 1)) {
uint16_t nr_wares = fr.Unsigned16();
uint16_t nr_entries = fr.Unsigned16();
- for (uint32_t i = 0; i < m_current_statistics.size(); ++i)
+ for (uint32_t i = 0; i < m_current_produced_statistics.size(); ++i)
m_ware_productions[i].resize(nr_entries);
for (uint16_t i = 0; i < nr_wares; ++i) {
@@ -1138,11 +1174,36 @@
continue;
}
- m_current_statistics[idx] = fr.Unsigned32();
+ m_current_produced_statistics[idx] = fr.Unsigned32();
for (uint32_t j = 0; j < nr_entries; ++j)
m_ware_productions[idx][j] = fr.Unsigned32();
}
+
+ //read consumption statistics if it exists
+ if (version == 2) {
+ nr_wares = fr.Unsigned16();
+ nr_entries = fr.Unsigned16();
+
+ for (uint32_t i = 0; i < m_current_consumed_statistics.size(); ++i)
+ m_ware_consumptions[i].resize(nr_entries);
+
+ for (uint16_t i = 0; i < nr_wares; ++i) {
+ std::string name = fr.CString();
+ Ware_Index idx = tribe().ware_index(name);
+ if (!idx) {
+ log
+ ("Player %u statistics: unknown ware name %s",
+ player_number(), name.c_str());
+ continue;
+ }
+
+ m_current_consumed_statistics[idx] = fr.Unsigned32();
+
+ for (uint32_t j = 0; j < nr_entries; ++j)
+ m_ware_consumptions[idx][j] = fr.Unsigned32();
+ }
+ }
} else if (version == 0) {
uint16_t nr_wares = fr.Unsigned16();
uint16_t nr_entries = fr.Unsigned16();
@@ -1150,10 +1211,10 @@
if (nr_wares > 0) {
if (nr_wares == tribe().get_nrwares().value()) {
assert(m_ware_productions.size() == nr_wares);
- assert(m_current_statistics.size() == nr_wares);
+ assert(m_current_produced_statistics.size() == nr_wares);
- for (uint32_t i = 0; i < m_current_statistics.size(); ++i) {
- m_current_statistics[i] = fr.Unsigned32();
+ for (uint32_t i = 0; i < m_current_produced_statistics.size(); ++i) {
+ m_current_produced_statistics[i] = fr.Unsigned32();
m_ware_productions[i].resize(nr_entries);
for (uint32_t j = 0; j < m_ware_productions[i].size(); ++j)
@@ -1177,6 +1238,22 @@
}
} else
throw wexception("Unsupported version %i", version);
+
+ //create empty consumption statistic if it is missing
+ if (version < 2) {
+ uint16_t nr_entries = m_ware_productions[0].size();
+
+ for (uint32_t i = 0; i < m_current_consumed_statistics.size(); ++i) {
+ m_ware_consumptions[i].resize(nr_entries);
+ m_current_consumed_statistics[i] = 0;
+
+ for (uint32_t j = 0; j < nr_entries; ++j)
+ m_ware_consumptions[i][j] = 0;
+ }
+ }
+
+ assert(m_ware_productions.size() == m_ware_consumptions.size());
+ assert(m_ware_productions[0].size() == m_ware_consumptions[0].size());
}
@@ -1184,17 +1261,31 @@
* Write statistics data to the give file
*/
void Player::WriteStatistics(FileWrite & fw) const {
- fw.Unsigned16(m_current_statistics.size());
+ //write produce statistics
+ fw.Unsigned16(m_current_produced_statistics.size());
fw.Unsigned16(m_ware_productions[0].size());
- for (uint8_t i = 0; i < m_current_statistics.size(); ++i) {
+ for (uint8_t i = 0; i < m_current_produced_statistics.size(); ++i) {
fw.CString
(tribe().get_ware_descr
(Ware_Index(static_cast<Ware_Index::value_t>(i)))->name());
- fw.Unsigned32(m_current_statistics[i]);
+ fw.Unsigned32(m_current_produced_statistics[i]);
for (uint32_t j = 0; j < m_ware_productions[i].size(); ++j)
fw.Unsigned32(m_ware_productions[i][j]);
}
+
+ //write consume statistics
+ fw.Unsigned16(m_current_consumed_statistics.size());
+ fw.Unsigned16(m_ware_consumptions[0].size());
+
+ for (uint8_t i = 0; i < m_current_consumed_statistics.size(); ++i) {
+ fw.CString
+ (tribe().get_ware_descr
+ (Ware_Index(static_cast<Ware_Index::value_t>(i)))->name());
+ fw.Unsigned32(m_current_consumed_statistics[i]);
+ for (uint32_t j = 0; j < m_ware_consumptions[i].size(); ++j)
+ fw.Unsigned32(m_ware_consumptions[i][j]);
+ }
}
}
=== modified file 'src/logic/player.h'
--- src/logic/player.h 2011-11-05 18:19:37 +0000
+++ src/logic/player.h 2011-11-06 17:03:27 +0000
@@ -521,13 +521,19 @@
{
return m_building_stats[i];
}
+
std::vector<uint32_t> const * get_ware_production_statistics
(Ware_Index const) const;
+ std::vector<uint32_t> const * get_ware_consumption_statistics
+ (Ware_Index const) const;
+
void ReadStatistics(FileRead &, uint32_t version);
void WriteStatistics(FileWrite &) const;
void sample_statistics();
void ware_produced(Ware_Index);
+
+ void ware_consumed(Ware_Index, uint8_t);
void next_ware_production_period();
void receive(NoteImmovable const &);
@@ -589,13 +595,25 @@
/**
* Wares produced (by ware id) since the last call to @ref sample_statistics
*/
- std::vector<uint32_t> m_current_statistics;
+ std::vector<uint32_t> m_current_produced_statistics;
+
+ /**
+ * Wares consumed (by ware id) since the last call to @ref sample_statistics
+ */
+ std::vector<uint32_t> m_current_consumed_statistics;
/**
* Statistics of wares produced over the life of the game, indexed as
* m_ware_productions[ware id][time index]
*/
std::vector< std::vector<uint32_t> > m_ware_productions;
+
+ /**
+ * Statistics of wares consumed over the life of the game, indexed as
+ * m_ware_consumptions[ware_id][time_index]
+ */
+ std::vector< std::vector<uint32_t> > m_ware_consumptions;
+
BuildingStats m_building_stats;
};
=== modified file 'src/logic/production_program.cc'
--- src/logic/production_program.cc 2011-10-09 17:39:13 +0000
+++ src/logic/production_program.cc 2011-11-06 17:03:27 +0000
@@ -806,6 +806,9 @@
if (uint8_t const q = consumption_quantities[i]) {
assert(q <= warequeues[i]->get_filled());
warequeues[i]->set_filled(warequeues[i]->get_filled() - q);
+
+ //update consumption statistic
+ ps.owner().ware_consumed(warequeues[i]->get_ware(), q);
}
return ps.program_step(game);
}
=== modified file 'src/logic/worker.cc'
--- src/logic/worker.cc 2011-10-09 17:39:13 +0000
+++ src/logic/worker.cc 2011-11-06 17:03:27 +0000
@@ -1012,6 +1012,9 @@
return true;
}
+ //update consumption statistic
+ owner().ware_consumed(wareindex, 1);
+
item = fetch_carried_item(game);
item->remove(game);
=== added file 'src/ui_basic/wsm_checkbox.cc'
--- src/ui_basic/wsm_checkbox.cc 1970-01-01 00:00:00 +0000
+++ src/ui_basic/wsm_checkbox.cc 2011-11-06 17:03:27 +0000
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2011 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "graphic/rendertarget.h"
+#include "logic/item_ware_descr.h"
+#include "compile_assert.h"
+#include "checkbox.h"
+
+#include "wsm_checkbox.h"
+
+
+#define COLOR_BOX_HEIGHT 7
+#define WARES_DISPLAY_BG "pics/ware_list_bg.png"
+
+
+WSM_Checkbox::WSM_Checkbox
+ (UI::Panel * const parent,
+ Point const p,
+ int32_t const id,
+ PictureID const picid,
+ RGBColor const color)
+:
+UI::Checkbox(parent, p, g_gr->get_picture(PicMod_Game, WARES_DISPLAY_BG)),
+m_pic (picid),
+m_color (color)
+{
+ set_id(id);
+}
+
+/**
+ * draw the normal checkbox, the picture and the color rectangle
+ */
+void WSM_Checkbox::draw(RenderTarget & dst) {
+ // First, draw normal.
+ UI::Checkbox::draw(dst);
+
+ // Now, draw a small box with the color.
+ assert(1 <= get_inner_w());
+ compile_assert(2 <= COLOR_BOX_HEIGHT);
+ dst.fill_rect
+ (Rect(Point(1, 1), get_inner_w() - 1, COLOR_BOX_HEIGHT - 2), m_color);
+
+ // and the item
+ dst.blit
+ (Point((get_inner_w() - WARE_MENU_PIC_WIDTH) / 2, COLOR_BOX_HEIGHT),
+ m_pic);
+}
=== added file 'src/ui_basic/wsm_checkbox.h'
--- src/ui_basic/wsm_checkbox.h 1970-01-01 00:00:00 +0000
+++ src/ui_basic/wsm_checkbox.h 2011-11-06 17:03:27 +0000
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2011 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef WSM_CHECKBOX_H
+#define WSM_CHECKBOX_H
+
+/**
+ * This class is the same as an ordinary
+ * checkbox, the only difference is, it has
+ * a small rectangle on it with the color
+ * of the graph and it needs a picture
+ */
+struct WSM_Checkbox : public UI::Checkbox {
+ WSM_Checkbox(UI::Panel *, Point, int32_t id, PictureID picid, RGBColor);
+
+ virtual void draw(RenderTarget &);
+
+private:
+ PictureID m_pic;
+ RGBColor m_color;
+};
+
+
+#endif
=== added file 'src/wui/differential_plot_area.cc'
--- src/wui/differential_plot_area.cc 1970-01-01 00:00:00 +0000
+++ src/wui/differential_plot_area.cc 2011-11-06 17:03:27 +0000
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2011 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "differential_plot_area.h"
+#include "graphic/rendertarget.h"
+
+#define ZERO_LINE_COLOR RGBColor(255, 255, 255)
+
+DifferentialPlot_Area::DifferentialPlot_Area
+ (UI::Panel * const parent,
+ int32_t const x, int32_t const y, int32_t const w, int32_t const h)
+:
+WUIPlot_Area (parent, x, y, w, h)
+{}
+
+void DifferentialPlot_Area::draw(RenderTarget & dst) {
+ float const xline_length = get_inner_w() - space_at_right - spacing;
+ float const yline_length = get_inner_h() - space_at_bottom - spacing;
+ //yoffset of the zero line
+ float const yoffset = spacing + ((get_inner_h() - space_at_bottom) - spacing) / 2;
+
+ uint32_t time_in_ms_ = draw_diagram(dst, xline_length, yline_length);
+
+ //draw zero line
+ dst.draw_line
+ (get_inner_w() - space_at_right,
+ yoffset,
+ get_inner_w() - space_at_right - xline_length,
+ yoffset,
+ ZERO_LINE_COLOR);
+
+ //find max and min value
+ int32_t max = 0;
+ int32_t min = 0;
+
+ if (m_plotmode == PLOTMODE_ABSOLUTE) {
+ for (uint32_t i = 0; i < m_plotdata.size(); ++i)
+ if (m_plotdata[i].showplot) {
+ for (uint32_t l = 0; l < m_plotdata[i].dataset->size(); ++l) {
+ int32_t temp = (*m_plotdata[i].dataset)[l] -
+ (*m_negative_plotdata[i].dataset)[l];
+ if (max < temp) max = temp;
+ if (min > temp) min = temp;
+ }
+ }
+ } else {
+ for (uint32_t plot = 0; plot < m_plotdata.size(); ++plot)
+ if (m_plotdata[plot].showplot) {
+
+ std::vector<uint32_t> const & dataset = *m_plotdata[plot].dataset;
+ std::vector<uint32_t> const & ndataset = *m_negative_plotdata[plot].dataset;
+
+ // How many do we take together
+ int32_t const how_many =
+ static_cast<int32_t>
+ ((static_cast<float>(time_in_ms_)
+ /
+ static_cast<float>(nr_samples))
+ /
+ static_cast<float>(m_sample_rate));
+
+ int32_t add = 0;
+ // Relative data, first entry is always zero.
+ for (uint32_t i = 0; i < dataset.size(); ++i) {
+ add += dataset[i] - ndataset[i];
+ if (0 == ((i + 1) % how_many)) {
+ if (max < add) max = add;
+ if (min > add) min = add;
+
+ add = 0;
+ }
+ }
+ }
+ }
+
+ //use equal positive and negative range
+ min = abs(min);
+ uint32_t highest_scale = 0;
+ if (min > max) {
+ highest_scale = min;
+ } else {
+ highest_scale = max;
+ }
+ //print the min and max values
+ char buffer[200];
+
+ sprintf(buffer, "%u", highest_scale);
+ draw_value
+ (dst, buffer, RGBColor(60, 125, 0),
+ Point(get_inner_w() - space_at_right - 2, spacing + 2));
+
+ sprintf(buffer, "-%u", highest_scale);
+ draw_value
+ (dst, buffer, RGBColor(125, 0, 0),
+ Point(get_inner_w() - space_at_right - 2, get_inner_h() - spacing - 15));
+
+ // plot the pixels
+ float sub =
+ xline_length
+ /
+ (static_cast<float>(time_in_ms_)
+ /
+ static_cast<float>(m_sample_rate));
+ for (uint32_t plot = 0; plot < m_plotdata.size(); ++plot)
+ if (m_plotdata[plot].showplot) {
+
+ RGBColor color = m_plotdata[plot].plotcolor;
+ std::vector<uint32_t> const * dataset = m_plotdata[plot].dataset;
+ std::vector<uint32_t> const * ndataset = m_negative_plotdata[plot].dataset;
+
+ std::vector<int32_t> m_data;
+ 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_)
+ /
+ static_cast<float>(nr_samples))
+ /
+ static_cast<float>(m_sample_rate));
+
+ int32_t add = 0;
+ // Relative data, first entry is always zero
+ m_data.push_back(0);
+ for (uint32_t i = 0; i < dataset->size(); ++i) {
+ add += (*dataset)[i] - (*ndataset)[i];
+ if (0 == ((i + 1) % how_many)) {
+ m_data.push_back(add);
+ add = 0;
+ }
+ }
+
+ sub = xline_length / static_cast<float>(nr_samples);
+ }
+
+ float posx = get_inner_w() - space_at_right;
+
+ int32_t lx = get_inner_w() - space_at_right;
+ //raise y zero point to middle of plot
+ int32_t ly = yoffset;
+ for (int32_t i = m_data.size() - 1; i > 0 and posx > spacing; --i) {
+ int32_t const curx = static_cast<int32_t>(posx);
+ int32_t cury = yoffset;
+ if (int32_t value = m_data[i]) {
+ const float length_y =
+ yline_length
+ /
+ (static_cast<float>(highest_scale) / static_cast<float>(value))
+ //highest_scale represent the space between zero line and top.
+ //-> half of the whole differential plot area
+ / static_cast<float>(2);
+ cury -= static_cast<int32_t>(length_y);
+ }
+ dst.draw_line(lx, ly, curx, cury, color);
+
+ posx -= sub;
+
+ lx = curx;
+ ly = cury;
+ }
+ }
+}
+
+/**
+ * Register a new negative plot data stream. This stream is
+ * used as subtrahend for calculating the plot data.
+ */
+void DifferentialPlot_Area::register_negative_plot_data
+ (uint32_t const id, std::vector<uint32_t> const * const data) {
+
+ if (id >= m_negative_plotdata.size())
+ m_negative_plotdata.resize(id + 1);
+
+ m_negative_plotdata[id].dataset = data;
+}
=== added file 'src/wui/differential_plot_area.h'
--- src/wui/differential_plot_area.h 1970-01-01 00:00:00 +0000
+++ src/wui/differential_plot_area.h 2011-11-06 17:03:27 +0000
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2011 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef WUI_DIFFERENTIAL_PLOT_AREA_H
+#define WUI_DIFFERENTIAL_PLOT_AREA_H
+
+#include "plot_area.h"
+
+/**
+ * A Plot Area is a simple 2D Plot, with the
+ * X Axis as time (actually Minus Time)
+ * and the Y Axis as the difference between two data vectors
+ */
+struct DifferentialPlot_Area : public WUIPlot_Area {
+public:
+ DifferentialPlot_Area
+ (UI::Panel * parent, int32_t x, int32_t y, int32_t w, int32_t h);
+
+ virtual void draw(RenderTarget &);
+
+ void register_negative_plot_data
+ (uint32_t id, const std::vector<uint32_t> * data);
+
+private:
+ /**
+ * for the negative plotdata only the values matter.
+ * The color and visibillity is determined by the normal
+ * plotdata
+ */
+ struct __reduced_plotdata {
+ const std::vector<uint32_t> * dataset;
+ };
+ std::vector<__reduced_plotdata> m_negative_plotdata;
+};
+
+#endif
=== modified file 'src/wui/plot_area.cc'
--- src/wui/plot_area.cc 2011-11-06 10:23:32 +0000
+++ src/wui/plot_area.cc 2011-11-06 17:03:27 +0000
@@ -36,7 +36,7 @@
static const uint32_t hours = 60 * 60 * 1000;
static const uint32_t days = 24 * 60 * 60 * 1000;
-static const uint32_t time_in_ms[] = {
+const uint32_t WUIPlot_Area::time_in_ms[] = {
15 * minutes,
30 * minutes,
1 * hours,
@@ -46,8 +46,6 @@
30 * hours
};
-#define NR_SAMPLES 30 // How many samples per diagramm when relative plotting
-
#define BG_PIC "pics/plot_area_bg.png"
#define LINE_COLOR RGBColor(0, 0, 0)
@@ -57,6 +55,9 @@
int32_t const x, int32_t const y, int32_t const w, int32_t const h)
:
UI::Panel (parent, x, y, w, h),
+spacing(5),
+space_at_bottom(15),
+space_at_right(5),
m_time (TIME_GAME),
m_plotmode(PLOTMODE_ABSOLUTE),
m_game_time_id(0)
@@ -154,7 +155,129 @@
* Draw this. This is the main function
*/
void WUIPlot_Area::draw(RenderTarget & dst) {
+
+ uint32_t time_in_ms_;
+
+ float const xline_length = get_inner_w() - space_at_right - spacing;
+ float const yline_length = get_inner_h() - space_at_bottom - spacing;
+
+ time_in_ms_ = draw_diagram(dst, xline_length, yline_length);
+
+ uint32_t max = 0;
+ // Find the maximum value.
+ if (m_plotmode == PLOTMODE_ABSOLUTE) {
+ for (uint32_t i = 0; i < m_plotdata.size(); ++i)
+ if (m_plotdata[i].showplot) {
+ for (uint32_t l = 0; l < m_plotdata[i].dataset->size(); ++l)
+ if (max < (*m_plotdata[i].dataset)[l])
+ max = (*m_plotdata[i].dataset)[l];
+ }
+ } else {
+ for (uint32_t plot = 0; plot < m_plotdata.size(); ++plot)
+ if (m_plotdata[plot].showplot) {
+
+ std::vector<uint32_t> const & dataset = *m_plotdata[plot].dataset;
+
+ // How many do we take together
+ int32_t const how_many =
+ static_cast<int32_t>
+ ((static_cast<float>(time_in_ms_)
+ /
+ static_cast<float>(nr_samples))
+ /
+ static_cast<float>(m_sample_rate));
+
+ uint32_t add = 0;
+ // Relative data, first entry is always zero.
+ for (uint32_t i = 0; i < dataset.size(); ++i) {
+ add += dataset[i];
+ if (0 == ((i + 1) % how_many)) {
+ if (max < add)
+ max = add;
+ add = 0;
+ }
+ }
+ }
+ }
+
+ // print the maximal value into the top right corner
+ char buffer[200];
+ sprintf(buffer, "%u", max);
+
+ draw_value
+ (dst, buffer, RGBColor(60, 125, 0),
+ Point(get_inner_w() - space_at_right - 2, spacing + 2));
+
+ // plot the pixels
+ float sub =
+ xline_length
+ /
+ (static_cast<float>(time_in_ms_)
+ /
+ static_cast<float>(m_sample_rate));
+ for (uint32_t plot = 0; plot < m_plotdata.size(); ++plot)
+ if (m_plotdata[plot].showplot) {
+
+ RGBColor color = m_plotdata[plot].plotcolor;
+ std::vector<uint32_t> const * dataset = m_plotdata[plot].dataset;
+
+ std::vector<uint32_t> m_data;
+ 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_)
+ /
+ static_cast<float>(nr_samples))
+ /
+ static_cast<float>(m_sample_rate));
+
+ uint32_t add = 0;
+ // Relative data, first entry is always zero
+ m_data.push_back(0);
+ for (uint32_t i = 0; i < dataset->size(); ++i) {
+ add += (*dataset)[i];
+ if (0 == ((i + 1) % how_many)) {
+ m_data.push_back(add);
+ add = 0;
+ }
+ }
+
+ dataset = &m_data;
+ sub = xline_length / static_cast<float>(nr_samples);
+ }
+
+ float posx = get_inner_w() - space_at_right;
+
+ int32_t lx = get_inner_w() - space_at_right;
+ int32_t ly = get_inner_h() - space_at_bottom;
+ for (int32_t i = dataset->size() - 1; i > 0 and posx > spacing; --i) {
+ int32_t const curx = static_cast<int32_t>(posx);
+ int32_t cury = get_inner_h() - space_at_bottom;
+ if (int32_t value = (*dataset)[i]) {
+ const float length_y =
+ yline_length
+ /
+ (static_cast<float>(max) / static_cast<float>(value));
+ cury -= static_cast<int32_t>(length_y);
+ }
+ dst.draw_line(lx, ly, curx, cury, color);
+
+ posx -= sub;
+
+ lx = curx;
+ ly = cury;
+ }
+ }
+}
+
+/**
+ * draw the background and the axis of the diagram
+ */
+uint32_t WUIPlot_Area::draw_diagram
+ (RenderTarget & dst, float const xline_length, float const yline_length) {
+
uint32_t time_in_ms_, how_many_ticks, max_x;
+ char buffer[200];
time_in_ms_ = get_plot_time();
UNIT unit = get_suggested_unit(time_in_ms_);
@@ -188,13 +311,6 @@
(Rect(Point(0, 0), get_inner_w(), get_inner_h()),
g_gr->get_picture(PicMod_Game, BG_PIC), Point(0, 0));
- int32_t const spacing = 5;
- int32_t const space_at_bottom = 15;
- int32_t const space_at_right = 5;
-
- float const xline_length = get_inner_w() - space_at_right - spacing;
- float const yline_length = get_inner_h() - space_at_bottom - spacing;
-
// Draw coordinate system
// X Axis
dst.draw_line
@@ -224,7 +340,7 @@
float sub = xline_length / how_many_ticks;
float posx = get_inner_w() - space_at_right;
- char buffer[200];
+
for (uint32_t i = 0; i <= how_many_ticks; ++i) {
dst.draw_line
(static_cast<int32_t>(posx), get_inner_h() - space_at_bottom,
@@ -257,119 +373,29 @@
spacing + ((get_inner_h() - space_at_bottom) - spacing) / 2,
LINE_COLOR);
- uint32_t max = 0;
- // Find the maximum value.
- if (m_plotmode == PLOTMODE_ABSOLUTE) {
- for (uint32_t i = 0; i < m_plotdata.size(); ++i)
- if (m_plotdata[i].showplot) {
- for (uint32_t l = 0; l < m_plotdata[i].dataset->size(); ++l)
- if (max < (*m_plotdata[i].dataset)[l])
- max = (*m_plotdata[i].dataset)[l];
- }
- } else {
- for (uint32_t plot = 0; plot < m_plotdata.size(); ++plot)
- if (m_plotdata[plot].showplot) {
-
- std::vector<uint32_t> const & dataset = *m_plotdata[plot].dataset;
-
- // How many do we take together
- int32_t const how_many =
- static_cast<int32_t>
- ((static_cast<float>(time_in_ms_)
- /
- static_cast<float>(NR_SAMPLES))
- /
- static_cast<float>(m_sample_rate));
-
- uint32_t add = 0;
- // Relative data, first entry is always zero.
- for (uint32_t i = 0; i < dataset.size(); ++i) {
- add += dataset[i];
- if (0 == ((i + 1) % how_many)) {
- if (max < add)
- max = add;
- add = 0;
- }
- }
- }
- }
-
- // print the maximal value
- sprintf(buffer, "%u", max);
- UI::TextStyle ymarkstyle(UI::TextStyle::ui_small());
- ymarkstyle.fg = RGBColor(60, 125, 0);
-
- UI::g_fh->draw_text
- (dst, ymarkstyle,
- 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_)
- /
- static_cast<float>(m_sample_rate));
- for (uint32_t plot = 0; plot < m_plotdata.size(); ++plot)
- if (m_plotdata[plot].showplot) {
-
- RGBColor color = m_plotdata[plot].plotcolor;
- std::vector<uint32_t> const * dataset = m_plotdata[plot].dataset;
-
- std::vector<uint32_t> m_data;
- 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_)
- /
- static_cast<float>(NR_SAMPLES))
- /
- static_cast<float>(m_sample_rate));
-
- uint32_t add = 0;
- // Relative data, first entry is always zero
- m_data.push_back(0);
- for (uint32_t i = 0; i < dataset->size(); ++i) {
- add += (*dataset)[i];
- if (0 == ((i + 1) % how_many)) {
- m_data.push_back(add);
- add = 0;
- }
- }
-
- dataset = &m_data;
- sub = xline_length / static_cast<float>(NR_SAMPLES);
- }
-
- posx = get_inner_w() - space_at_right;
-
- int32_t lx = get_inner_w() - space_at_right;
- int32_t ly = get_inner_h() - space_at_bottom;
- for (int32_t i = dataset->size() - 1; i > 0 and posx > spacing; --i) {
- int32_t const curx = static_cast<int32_t>(posx);
- int32_t cury = get_inner_h() - space_at_bottom;
- if (int32_t value = (*dataset)[i]) {
- const float length_y =
- yline_length
- /
- (static_cast<float>(max) / static_cast<float>(value));
- cury -= static_cast<int32_t>(length_y);
- }
- dst.draw_line(lx, ly, curx, cury, color);
-
- posx -= sub;
-
- lx = curx;
- ly = cury;
- }
- }
+ return time_in_ms_;
+}
+
+/**
+ * print the string into the RenderTarget.
+ */
+void WUIPlot_Area::draw_value
+ (RenderTarget & dst, const char * value, RGBColor color, Point pos)
+{
+
+ UI::TextStyle ymarkstyle(UI::TextStyle::ui_small());
+ ymarkstyle.fg = color;
+
+ UI::g_fh->draw_text
+ (dst, ymarkstyle,
+ pos,
+ value, UI::Align_CenterRight);
}
/*
=== modified file 'src/wui/plot_area.h'
--- src/wui/plot_area.h 2011-11-06 10:23:32 +0000
+++ src/wui/plot_area.h 2011-11-06 17:03:27 +0000
@@ -83,13 +83,18 @@
std::vector<std::string> get_labels();
-private:
- uint32_t get_game_time();
- uint32_t get_plot_time();
- void calc_game_time_id();
- 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);
+protected:
+ uint32_t draw_diagram
+ (RenderTarget & dst, float const xline_length, float const yline_length);
+ void draw_value
+ (RenderTarget & dst, const char * value, RGBColor color, Point pos);
+
+ int32_t const spacing;
+ int32_t const space_at_bottom;
+ int32_t const space_at_right;
+
+ static const uint32_t time_in_ms[];
+ static const uint32_t nr_samples = 30; // How many samples per diagramm when relative plotting
struct __plotdata {
const std::vector<uint32_t> * dataset;
@@ -97,9 +102,18 @@
RGBColor plotcolor;
};
std::vector<__plotdata> m_plotdata;
+
TIME m_time; // How much do you want to list
int32_t m_sample_rate;
int32_t m_plotmode;
+
+private:
+ uint32_t get_game_time();
+ uint32_t get_plot_time();
+ void calc_game_time_id();
+ 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);
int32_t m_game_time_id; // what label is used for TIME_GAME
};
=== modified file 'src/wui/ware_statistics_menu.cc'
--- src/wui/ware_statistics_menu.cc 2011-11-06 12:38:07 +0000
+++ src/wui/ware_statistics_menu.cc 2011-11-06 17:03:27 +0000
@@ -27,22 +27,26 @@
#include "logic/tribe.h"
#include "logic/warelist.h"
#include "plot_area.h"
+#include "differential_plot_area.h"
#include "waresdisplay.h"
#include "ui_basic/button.h"
#include "ui_basic/checkbox.h"
#include "ui_basic/textarea.h"
+#include "ui_basic/wsm_checkbox.h"
+#include "ui_basic/tabpanel.h"
#include "ui_basic/slider.h"
-#define WARES_DISPLAY_BG "pics/ware_list_bg.png"
#define MIN_WARES_PER_LINE 7
#define MAX_WARES_PER_LINE 11
-
#define PLOT_HEIGHT 100
-#define COLOR_BOX_HEIGHT 7
+//TODO place holder, need to be changed
+static const char pic_tab_production[] = "pics/menu_tab_wares.png";
+static const char pic_tab_consumption[] = "pics/menu_tab_wares.png";
+static const char pic_tab_economy[] = "pics/menu_tab_wares.png";
static const RGBColor colors[] = {
RGBColor (0, 210, 254),
@@ -316,7 +320,6 @@
}
};
-
Ware_Statistics_Menu::Ware_Statistics_Menu
(Interactive_Player & parent, UI::UniqueWindow::Registry & registry)
:
@@ -326,24 +329,87 @@
{
set_cache(false);
+ // First, we must decide about the size.
UI::Box * box = new UI::Box(this, 0, 0, UI::Box::Vertical, 0, 0, 5);
box->set_border(5, 5, 5, 5);
set_center_panel(box);
- m_plot = new WUIPlot_Area
- (box, 0, 0, 100, PLOT_HEIGHT);
- m_plot->set_sample_rate(STATISTICS_SAMPLE_TIME);
- m_plot->set_plotmode(WUIPlot_Area::PLOTMODE_RELATIVE);
-
- box->add(m_plot, UI::Box::AlignLeft, true);
-
uint8_t const nr_wares = parent.get_player()->tribe().get_nrwares().value();
+
+ //setup plot widgets
+ //create a tabbed environment for the different plots
+ uint8_t const tab_offset = 30;
+ uint8_t const spacing = 5;
+ uint8_t const plot_width = get_inner_w() - 2 * spacing;
+ uint8_t const plot_height = PLOT_HEIGHT + tab_offset + spacing;
+
+ UI::Tab_Panel * tabs =
+ new UI::Tab_Panel
+ (box, spacing, 0, g_gr->get_picture(PicMod_UI, "pics/but1.png"));
+
+
+ m_plot_production =
+ new WUIPlot_Area
+ (tabs,
+ 0, 0, plot_width, plot_height);
+ m_plot_production->set_sample_rate(STATISTICS_SAMPLE_TIME);
+ m_plot_production->set_plotmode(WUIPlot_Area::PLOTMODE_RELATIVE);
+
+ tabs->add
+ ("production", g_gr->get_picture(PicMod_UI, pic_tab_production),
+ m_plot_production, _("Production"));
+
+ m_plot_consumption =
+ new WUIPlot_Area
+ (tabs,
+ 0, 0, plot_width, plot_height);
+ m_plot_consumption->set_sample_rate(STATISTICS_SAMPLE_TIME);
+ m_plot_consumption->set_plotmode(WUIPlot_Area::PLOTMODE_RELATIVE);
+
+ tabs->add
+ ("consumption", g_gr->get_picture(PicMod_UI, pic_tab_consumption),
+ m_plot_consumption, _("Consumption"));
+
+ m_plot_economy =
+ new DifferentialPlot_Area
+ (tabs,
+ 0, 0, plot_width, plot_height);
+ m_plot_economy->set_sample_rate(STATISTICS_SAMPLE_TIME);
+ m_plot_economy->set_plotmode(WUIPlot_Area::PLOTMODE_RELATIVE);
+
+ tabs->add
+ ("economy_health", g_gr->get_picture(PicMod_UI, pic_tab_production),
+ m_plot_economy, _("Economy Health"));
+
+ tabs->activate(0);
+
+ //add tabbed environment to box
+ box->add(tabs, UI::Box::AlignLeft, true);
+
+ //register statistics data
for (Widelands::Ware_Index::value_t cur_ware = 0; cur_ware < nr_wares; ++cur_ware) {
- m_plot->register_plot_data
- (cur_ware,
- parent.get_player()->get_ware_production_statistics
- (Widelands::Ware_Index(cur_ware)),
- colors[cur_ware]);
+ m_plot_production->register_plot_data
+ (cur_ware,
+ parent.get_player()->get_ware_production_statistics
+ (Widelands::Ware_Index(cur_ware)),
+ colors[cur_ware]);
+
+ m_plot_consumption->register_plot_data
+ (cur_ware,
+ parent.get_player()->get_ware_consumption_statistics
+ (Widelands::Ware_Index(cur_ware)),
+ colors[cur_ware]);
+
+ m_plot_economy->register_plot_data
+ (cur_ware,
+ parent.get_player()->get_ware_production_statistics
+ (Widelands::Ware_Index(cur_ware)),
+ colors[cur_ware]);
+
+ m_plot_economy->register_negative_plot_data
+ (cur_ware,
+ parent.get_player()->get_ware_consumption_statistics
+ (Widelands::Ware_Index(cur_ware)));
}
box->add
@@ -352,25 +418,32 @@
boost::bind(&Ware_Statistics_Menu::cb_changed_to, boost::ref(*this), _1, _2)),
UI::Box::AlignLeft, true);
-
box->add
- (new WUIPlot_Area_Slider
- (box, *m_plot, 0, 0, 100, 45,
- g_gr->get_picture(PicMod_UI, "pics/but1.png")),
- UI::Box::AlignLeft, true);
+ (new WUIPlot_Generic_Area_Slider
+ (this, *m_plot_production, this,
+ 0, 0, 100, 45,
+ g_gr->get_picture(PicMod_UI, "pics/but1.png")),
+ UI::Box::AlignLeft, true);
+
}
-
/**
- * Called when the ok button has been clicked
- * \todo Implement help
-*/
-void Ware_Statistics_Menu::clicked_help() {}
-
-/*
- * Cb has been changed to this state
+ * Callback for the ware buttons. Change the state of all ware statistics
+ * simultaneously.
*/
void Ware_Statistics_Menu::cb_changed_to(Widelands::Ware_Index id, bool what) {
- m_plot->show_plot(static_cast<size_t>(id), what);
+ m_plot_production->show_plot(static_cast<size_t>(id), what);
+ m_plot_consumption->show_plot(static_cast<size_t>(id), what);
+ m_plot_economy->show_plot(static_cast<size_t>(id), what);
+}
+
+/**
+ * Callback for the time buttons. Change the time axis of all ware
+ * statistics simultaneously.
+ */
+void Ware_Statistics_Menu::set_time(int32_t timescale) {
+ m_plot_production->set_time_id(timescale);
+ m_plot_consumption->set_time_id(timescale);
+ m_plot_economy->set_time_id(timescale);
}
=== modified file 'src/wui/ware_statistics_menu.h'
--- src/wui/ware_statistics_menu.h 2011-11-05 18:25:27 +0000
+++ src/wui/ware_statistics_menu.h 2011-11-06 17:03:27 +0000
@@ -21,19 +21,56 @@
#define WARE_STATISTICS_MENU_H
#include "ui_basic/unique_window.h"
+#include "plot_area.h"
+#include "differential_plot_area.h"
struct Interactive_Player;
struct WUIPlot_Area;
struct Ware_Statistics_Menu : public UI::UniqueWindow {
+public:
Ware_Statistics_Menu(Interactive_Player &, UI::UniqueWindow::Registry &);
+ void set_time(int32_t);
private:
Interactive_Player * m_parent;
- WUIPlot_Area * m_plot;
+ WUIPlot_Area * m_plot_production;
+ WUIPlot_Area * m_plot_consumption;
+ DifferentialPlot_Area * m_plot_economy;
void clicked_help();
void cb_changed_to(Widelands::Ware_Index, bool);
};
+
+
+/**
+ * A discrete slider with plot time steps preconfigured, automatic signal
+ * setup and the set_time callback function from Ware_Statistics_Menu.
+ *
+ */
+struct WUIPlot_Generic_Area_Slider : public UI::DiscreteSlider {
+ WUIPlot_Generic_Area_Slider
+ (Panel * const parent,
+ WUIPlot_Area & plot_area,
+ Ware_Statistics_Menu * signal_listener,
+ const int32_t x, const int32_t y, const uint32_t w, const uint32_t h,
+ const PictureID background_picture_id,
+ const std::string & tooltip_text = std::string(),
+ const uint32_t cursor_size = 20,
+ const bool enabled = true)
+ : DiscreteSlider
+ (parent,
+ x, y, w, h,
+ plot_area.get_labels(),
+ plot_area.get_time(),
+ background_picture_id,
+ tooltip_text,
+ cursor_size,
+ enabled)
+ {
+ changedto->set(signal_listener, &Ware_Statistics_Menu::set_time);
+ }
+};
+
#endif
Follow ups