src/graph_gui.cpp
changeset 6505 abcb0580d976
parent 6417 26acff62d001
child 6518 c7ac357020e3
equal deleted inserted replaced
6504:5578f2fa1a73 6505:abcb0580d976
     1 /* $Id$ */
     1 /* $Id$ */
       
     2 
       
     3 /** @file graph_gui.cpp */
     2 
     4 
     3 #include "stdafx.h"
     5 #include "stdafx.h"
     4 #include "openttd.h"
     6 #include "openttd.h"
     5 #include "table/strings.h"
     7 #include "table/strings.h"
     6 #include "table/sprites.h"
     8 #include "table/sprites.h"
    26 enum {
    28 enum {
    27 	GRAPH_MAX_DATASETS = 16,
    29 	GRAPH_MAX_DATASETS = 16,
    28 	GRAPH_AXIS_LABEL_COLOUR = 16,
    30 	GRAPH_AXIS_LABEL_COLOUR = 16,
    29 	GRAPH_AXIS_LINE_COLOUR  = 215,
    31 	GRAPH_AXIS_LINE_COLOUR  = 215,
    30 
    32 
    31 	GRAPH_X_POSITION_BEGINNING  = 44,  // Start the graph 44 pixels from gw->left
    33 	GRAPH_X_POSITION_BEGINNING  = 44,  ///< Start the graph 44 pixels from gw->left
    32 	GRAPH_X_POSITION_SEPARATION = 22,  // There are 22 pixels between each X value
    34 	GRAPH_X_POSITION_SEPARATION = 22,  ///< There are 22 pixels between each X value
    33 
    35 
    34 	/* How many horizontal lines to draw. 9 is convenient as that means the
    36 	GRAPH_NUM_LINES_Y = 9, ///< How many horizontal lines to draw.
    35 	 * distance between them is the height of the graph / 8, which is the same
    37 	/* 9 is convenient as that means the distance between them is the height of the graph / 8,
       
    38 	 * which is the same
    36 	 * as height >> 3. */
    39 	 * as height >> 3. */
    37 	GRAPH_NUM_LINES_Y = 9,
       
    38 };
    40 };
    39 
    41 
    40 /* Apparently these don't play well with enums. */
    42 /* Apparently these don't play well with enums. */
    41 static const int64 INVALID_DATAPOINT     = INT64_MAX; // Value used for a datapoint that shouldn't be drawn.
    43 static const int64 INVALID_DATAPOINT     = INT64_MAX; // Value used for a datapoint that shouldn't be drawn.
    42 static const uint  INVALID_DATAPOINT_POS = UINT_MAX;  // Used to determine if the previous point was drawn.
    44 static const uint  INVALID_DATAPOINT_POS = UINT_MAX;  // Used to determine if the previous point was drawn.
    43 
    45 
    44 typedef struct GraphDrawer {
    46 typedef struct GraphDrawer {
    45 	uint excluded_data; // bitmask of the datasets that shouldn't be displayed.
    47 	uint excluded_data; ///< bitmask of the datasets that shouldn't be displayed.
    46 	byte num_dataset;
    48 	byte num_dataset;
    47 	byte num_on_x_axis;
    49 	byte num_on_x_axis;
    48 	bool has_negative_values;
    50 	bool has_negative_values;
    49 	byte num_vert_lines;
    51 	byte num_vert_lines;
    50 
    52 
    56 	/* These values are used if the graph is being plotted against values
    58 	/* These values are used if the graph is being plotted against values
    57 	 * rather than the dates specified by month and year. */
    59 	 * rather than the dates specified by month and year. */
    58 	uint16 x_values_start;
    60 	uint16 x_values_start;
    59 	uint16 x_values_increment;
    61 	uint16 x_values_increment;
    60 
    62 
    61 	int left, top;  // Where to start drawing the graph, in pixels.
    63 	int left, top;  ///< Where to start drawing the graph, in pixels.
    62 	uint height;    // The height of the graph in pixels.
    64 	uint height;    ///< The height of the graph in pixels.
    63 	StringID format_str_y_axis;
    65 	StringID format_str_y_axis;
    64 	byte colors[GRAPH_MAX_DATASETS];
    66 	byte colors[GRAPH_MAX_DATASETS];
    65 	int64 cost[GRAPH_MAX_DATASETS][24]; // last 2 years
    67 	int64 cost[GRAPH_MAX_DATASETS][24]; ///< last 2 years
    66 } GraphDrawer;
    68 } GraphDrawer;
    67 
    69 
    68 static void DrawGraph(const GraphDrawer *gw)
    70 static void DrawGraph(const GraphDrawer *gw)
    69 {
    71 {
    70 	uint x, y;            // Reused whenever x and y coordinates are needed.
    72 	uint x, y;            ///< Reused whenever x and y coordinates are needed.
    71 	int64 highest_value;  // Highest value to be drawn.
    73 	int64 highest_value;  ///< Highest value to be drawn.
    72 	int x_axis_offset;    // Distance from the top of the graph to the x axis.
    74 	int x_axis_offset;    ///< Distance from the top of the graph to the x axis.
    73 
    75 
    74 	/* the colors and cost array of GraphDrawer must accomodate
    76 	/* the colors and cost array of GraphDrawer must accomodate
    75 	 * both values for cargo and players. So if any are higher, quit */
    77 	 * both values for cargo and players. So if any are higher, quit */
    76 	assert(GRAPH_MAX_DATASETS >= (int)NUM_CARGO && GRAPH_MAX_DATASETS >= (int)MAX_PLAYERS);
    78 	assert(GRAPH_MAX_DATASETS >= (int)NUM_CARGO && GRAPH_MAX_DATASETS >= (int)MAX_PLAYERS);
    77 	assert(gw->num_vert_lines > 0);
    79 	assert(gw->num_vert_lines > 0);
   328 	const Player* p;
   330 	const Player* p;
   329 	uint excluded_players = _legend_excluded_players;
   331 	uint excluded_players = _legend_excluded_players;
   330 	byte nums;
   332 	byte nums;
   331 	int mo,yr;
   333 	int mo,yr;
   332 
   334 
   333 	// Exclude the players which aren't valid
   335 	/* Exclude the players which aren't valid */
   334 	FOR_ALL_PLAYERS(p) {
   336 	FOR_ALL_PLAYERS(p) {
   335 		if (!p->is_active) SETBIT(excluded_players, p->index);
   337 		if (!p->is_active) SETBIT(excluded_players, p->index);
   336 	}
   338 	}
   337 	gd->excluded_data = excluded_players;
   339 	gd->excluded_data = excluded_players;
   338 	gd->num_vert_lines = 24;
   340 	gd->num_vert_lines = 24;
   918 			byte x;
   920 			byte x;
   919 			uint16 y = 14;
   921 			uint16 y = 14;
   920 			int total_score = 0;
   922 			int total_score = 0;
   921 			int color_done, color_notdone;
   923 			int color_done, color_notdone;
   922 
   924 
   923 			// Draw standard stuff
   925 			/* Draw standard stuff */
   924 			DrawWindowWidgets(w);
   926 			DrawWindowWidgets(w);
   925 
   927 
   926 			/* Check if the currently selected player is still active. */
   928 			/* Check if the currently selected player is still active. */
   927 			if (_performance_rating_detail_player == INVALID_PLAYER || !GetPlayer(_performance_rating_detail_player)->is_active) {
   929 			if (_performance_rating_detail_player == INVALID_PLAYER || !GetPlayer(_performance_rating_detail_player)->is_active) {
   928 				if (_performance_rating_detail_player != INVALID_PLAYER) {
   930 				if (_performance_rating_detail_player != INVALID_PLAYER) {
   947 			}
   949 			}
   948 
   950 
   949 			/* If there are no active players, don't display anything else. */
   951 			/* If there are no active players, don't display anything else. */
   950 			if (_performance_rating_detail_player == INVALID_PLAYER) break;
   952 			if (_performance_rating_detail_player == INVALID_PLAYER) break;
   951 
   953 
   952 			// Paint the player icons
   954 			/* Paint the player icons */
   953 			for (PlayerID i = PLAYER_FIRST; i < MAX_PLAYERS; i++) {
   955 			for (PlayerID i = PLAYER_FIRST; i < MAX_PLAYERS; i++) {
   954 				if (!GetPlayer(i)->is_active) {
   956 				if (!GetPlayer(i)->is_active) {
   955 					// Check if we have the player as an active player
   957 					/* Check if we have the player as an active player */
   956 					if (!IsWindowWidgetDisabled(w, i + 13)) {
   958 					if (!IsWindowWidgetDisabled(w, i + 13)) {
   957 						// Bah, player gone :(
   959 						/* Bah, player gone :( */
   958 						DisableWindowWidget(w, i + 13);
   960 						DisableWindowWidget(w, i + 13);
   959 
   961 
   960 						// We need a repaint
   962 						/* We need a repaint */
   961 						SetWindowDirty(w);
   963 						SetWindowDirty(w);
   962 					}
   964 					}
   963 					continue;
   965 					continue;
   964 				}
   966 				}
   965 
   967 
   966 				// Check if we have the player marked as inactive
   968 				/* Check if we have the player marked as inactive */
   967 				if (IsWindowWidgetDisabled(w, i + 13)) {
   969 				if (IsWindowWidgetDisabled(w, i + 13)) {
   968 					// New player! Yippie :p
   970 					/* New player! Yippie :p */
   969 					EnableWindowWidget(w, i + 13);
   971 					EnableWindowWidget(w, i + 13);
   970 					// We need a repaint
   972 					/* We need a repaint */
   971 					SetWindowDirty(w);
   973 					SetWindowDirty(w);
   972 				}
   974 				}
   973 
   975 
   974 				x = (i == _performance_rating_detail_player) ? 1 : 0;
   976 				x = (i == _performance_rating_detail_player) ? 1 : 0;
   975 				DrawPlayerIcon(i, i * 37 + 13 + x, 16 + x);
   977 				DrawPlayerIcon(i, i * 37 + 13 + x, 16 + x);
   976 			}
   978 			}
   977 
   979 
   978 			// The colors used to show how the progress is going
   980 			/* The colors used to show how the progress is going */
   979 			color_done = _colour_gradient[COLOUR_GREEN][4];
   981 			color_done = _colour_gradient[COLOUR_GREEN][4];
   980 			color_notdone = _colour_gradient[COLOUR_RED][4];
   982 			color_notdone = _colour_gradient[COLOUR_RED][4];
   981 
   983 
   982 			// Draw all the score parts
   984 			/* Draw all the score parts */
   983 			for (ScoreID i = SCORE_BEGIN; i < SCORE_END; i++) {
   985 			for (ScoreID i = SCORE_BEGIN; i < SCORE_END; i++) {
   984 				int val    = _score_part[_performance_rating_detail_player][i];
   986 				int val    = _score_part[_performance_rating_detail_player][i];
   985 				int needed = _score_info[i].needed;
   987 				int needed = _score_info[i].needed;
   986 				int score  = _score_info[i].score;
   988 				int score  = _score_info[i].score;
   987 
   989 
   988 				y += 20;
   990 				y += 20;
   989 				// SCORE_TOTAL has his own rulez ;)
   991 				/* SCORE_TOTAL has his own rulez ;) */
   990 				if (i == SCORE_TOTAL) {
   992 				if (i == SCORE_TOTAL) {
   991 					needed = total_score;
   993 					needed = total_score;
   992 					score = SCORE_MAX;
   994 					score = SCORE_MAX;
   993 				} else {
   995 				} else {
   994 					total_score += score;
   996 					total_score += score;
   995 				}
   997 				}
   996 
   998 
   997 				DrawString(7, y, STR_PERFORMANCE_DETAIL_VEHICLES + i, 0);
   999 				DrawString(7, y, STR_PERFORMANCE_DETAIL_VEHICLES + i, 0);
   998 
  1000 
   999 				// Draw the score
  1001 				/* Draw the score */
  1000 				SetDParam(0, score);
  1002 				SetDParam(0, score);
  1001 				DrawStringRightAligned(107, y, SET_PERFORMANCE_DETAIL_INT, 0);
  1003 				DrawStringRightAligned(107, y, SET_PERFORMANCE_DETAIL_INT, 0);
  1002 
  1004 
  1003 				// Calculate the %-bar
  1005 				/* Calculate the %-bar */
  1004 				if (val > needed) {
  1006 				if (val > needed) {
  1005 					x = 50;
  1007 					x = 50;
  1006 				} else if (val == 0) {
  1008 				} else if (val == 0) {
  1007 					x = 0;
  1009 					x = 0;
  1008 				} else {
  1010 				} else {
  1009 					x = val * 50 / needed;
  1011 					x = val * 50 / needed;
  1010 				}
  1012 				}
  1011 
  1013 
  1012 				// SCORE_LOAN is inversed
  1014 				/* SCORE_LOAN is inversed */
  1013 				if (val < 0 && i == SCORE_LOAN) x = 0;
  1015 				if (val < 0 && i == SCORE_LOAN) x = 0;
  1014 
  1016 
  1015 				// Draw the bar
  1017 				/* Draw the bar */
  1016 				if (x !=  0) GfxFillRect(112,     y - 2, 112 + x,  y + 10, color_done);
  1018 				if (x !=  0) GfxFillRect(112,     y - 2, 112 + x,  y + 10, color_done);
  1017 				if (x != 50) GfxFillRect(112 + x, y - 2, 112 + 50, y + 10, color_notdone);
  1019 				if (x != 50) GfxFillRect(112 + x, y - 2, 112 + 50, y + 10, color_notdone);
  1018 
  1020 
  1019 				// Calculate the %
  1021 				/* Calculate the % */
  1020 				x = (val <= needed) ? val * 100 / needed : 100;
  1022 				x = (val <= needed) ? val * 100 / needed : 100;
  1021 
  1023 
  1022 				// SCORE_LOAN is inversed
  1024 				/* SCORE_LOAN is inversed */
  1023 				if (val < 0 && i == SCORE_LOAN) x = 0;
  1025 				if (val < 0 && i == SCORE_LOAN) x = 0;
  1024 
  1026 
  1025 				// Draw it
  1027 				/* Draw it */
  1026 				SetDParam(0, x);
  1028 				SetDParam(0, x);
  1027 				DrawStringCentered(137, y, STR_PERFORMANCE_DETAIL_PERCENT, 0);
  1029 				DrawStringCentered(137, y, STR_PERFORMANCE_DETAIL_PERCENT, 0);
  1028 
  1030 
  1029 				// SCORE_LOAN is inversed
  1031 				/* SCORE_LOAN is inversed */
  1030 				if (i == SCORE_LOAN) val = needed - val;
  1032 				if (i == SCORE_LOAN) val = needed - val;
  1031 
  1033 
  1032 				// Draw the amount we have against what is needed
  1034 				/* Draw the amount we have against what is needed
  1033 				//  For some of them it is in currency format
  1035 				 * For some of them it is in currency format */
  1034 				SetDParam(0, val);
  1036 				SetDParam(0, val);
  1035 				SetDParam(1, needed);
  1037 				SetDParam(1, needed);
  1036 				switch (i) {
  1038 				switch (i) {
  1037 					case SCORE_MIN_PROFIT:
  1039 					case SCORE_MIN_PROFIT:
  1038 					case SCORE_MIN_INCOME:
  1040 					case SCORE_MIN_INCOME:
  1048 
  1050 
  1049 			break;
  1051 			break;
  1050 		}
  1052 		}
  1051 
  1053 
  1052 		case WE_CLICK:
  1054 		case WE_CLICK:
  1053 			// Check which button is clicked
  1055 			/* Check which button is clicked */
  1054 			if (IS_INT_INSIDE(e->we.click.widget, 13, 21)) {
  1056 			if (IS_INT_INSIDE(e->we.click.widget, 13, 21)) {
  1055 				// Is it no on disable?
  1057 				/* Is it no on disable? */
  1056 				if (!IsWindowWidgetDisabled(w, e->we.click.widget)) {
  1058 				if (!IsWindowWidgetDisabled(w, e->we.click.widget)) {
  1057 					RaiseWindowWidget(w, _performance_rating_detail_player + 13);
  1059 					RaiseWindowWidget(w, _performance_rating_detail_player + 13);
  1058 					_performance_rating_detail_player = (PlayerID)(e->we.click.widget - 13);
  1060 					_performance_rating_detail_player = (PlayerID)(e->we.click.widget - 13);
  1059 					LowerWindowWidget(w, _performance_rating_detail_player + 13);
  1061 					LowerWindowWidget(w, _performance_rating_detail_player + 13);
  1060 					SetWindowDirty(w);
  1062 					SetWindowDirty(w);
  1084 
  1086 
  1085 			break;
  1087 			break;
  1086 		}
  1088 		}
  1087 
  1089 
  1088 		case WE_TICK: {
  1090 		case WE_TICK: {
  1089 			// Update the player score every 5 days
  1091 			/* Update the player score every 5 days */
  1090 			if (--w->custom[0] == 0) {
  1092 			if (--w->custom[0] == 0) {
  1091 				w->custom[0] = DAY_TICKS;
  1093 				w->custom[0] = DAY_TICKS;
  1092 				if (--w->custom[1] == 0) {
  1094 				if (--w->custom[1] == 0) {
  1093 					Player *p2;
  1095 					Player *p2;
  1094 
  1096 
  1095 					w->custom[1] = 5;
  1097 					w->custom[1] = 5;
  1096 					FOR_ALL_PLAYERS(p2) {
  1098 					FOR_ALL_PLAYERS(p2) {
  1097 						// Skip if player is not active
  1099 						/* Skip if player is not active */
  1098 						if (p2->is_active) UpdateCompanyRatingAndValue(p2, false);
  1100 						if (p2->is_active) UpdateCompanyRatingAndValue(p2, false);
  1099 					}
  1101 					}
  1100 					SetWindowDirty(w);
  1102 					SetWindowDirty(w);
  1101 				}
  1103 				}
  1102 			}
  1104 			}