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
_______________________________________________ Mailing list: https://launchpad.net/~widelands-dev Post to : widelands-dev@lists.launchpad.net Unsubscribe : https://launchpad.net/~widelands-dev More help : https://help.launchpad.net/ListHelp