1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
|
#include "MultiMeterStatusBar.h"
#include "MeterBrowseWnd.h"
#include <GG/ClrConstants.h>
#include <GG/DrawUtil.h>
#include <GG/Texture.h>
#include <GG/GLClientAndServerBuffer.h>
#include "../util/Logger.h"
#include "../universe/Meter.h"
#include "../universe/UniverseObject.h"
#include "../universe/Enums.h"
#include "../client/human/GGHumanClientApp.h"
#include "ClientUI.h"
namespace {
/** Returns GG::Clr with which to display programatically coloured things
* (such as meter bars) for the indicated \a meter_type */
GG::Clr MeterColor(MeterType meter_type) {
switch (meter_type) {
case MeterType::METER_INDUSTRY:
case MeterType::METER_TARGET_INDUSTRY:
return GG::Clr(240, 90, 0, 255);
break;
case MeterType::METER_RESEARCH:
case MeterType::METER_TARGET_RESEARCH:
return GG::Clr(0, 255, 255, 255);
break;
case MeterType::METER_INFLUENCE:
case MeterType::METER_TARGET_INFLUENCE:
return GG::Clr(255, 200, 0, 255);
break;
case MeterType::METER_SHIELD:
case MeterType::METER_MAX_SHIELD:
return GG::Clr(0, 255, 186, 255);
break;
case MeterType::METER_DEFENSE:
case MeterType::METER_MAX_DEFENSE:
return GG::Clr(255, 0, 0, 255);
break;
case MeterType::METER_TROOPS:
case MeterType::METER_MAX_TROOPS:
case MeterType::METER_REBEL_TROOPS:
return GG::Clr(168, 107, 0, 255);
break;
case MeterType::METER_DETECTION:
return GG::Clr(191, 255, 0, 255);
break;
case MeterType::METER_STEALTH:
return GG::Clr(174, 0, 255, 255);
break;
case MeterType::METER_HAPPINESS:
case MeterType::METER_TARGET_HAPPINESS:
return GG::Clr(255, 255, 0, 255);
case MeterType::METER_SUPPLY:
case MeterType::METER_MAX_SUPPLY:
case MeterType::METER_STOCKPILE:
case MeterType::METER_MAX_STOCKPILE:
case MeterType::METER_CONSTRUCTION:
case MeterType::METER_TARGET_CONSTRUCTION:
case MeterType::METER_POPULATION:
case MeterType::METER_TARGET_POPULATION:
default:
return GG::CLR_WHITE;
}
}
constexpr int EDGE_PAD(3);
constexpr int BAR_PAD(1);
constexpr GG::Y BAR_HEIGHT{10};
constexpr double MULTI_METER_STATUS_BAR_DISPLAYED_METER_RANGE_INCREMENT = 100.0;
}
MultiMeterStatusBar::MultiMeterStatusBar(GG::X w, int object_id, const std::vector<std::pair<MeterType, MeterType>>& meter_types) :
GG::Wnd(GG::X0, GG::Y0, w, GG::Y1, GG::INTERACTIVE),
m_bar_shading_texture(ClientUI::GetTexture(ClientUI::ArtDir() / "misc" / "meter_bar_shading.png")),
m_meter_types(meter_types),
m_object_id(object_id)
{
SetName("MultiMeterStatusBar");
Update();
}
void MultiMeterStatusBar::Render() {
static constexpr GG::Clr DARY_GREY = GG::Clr(44, 44, 44, 255);
static constexpr GG::Clr HALF_GREY = GG::CLR_GRAY;
GG::Pt ul = UpperLeft();
GG::Pt lr = LowerRight();
// outline of whole control
GG::FlatRectangle(ul, lr, ClientUI::WndColor(), ClientUI::WndOuterBorderColor(), 1);
const GG::X BAR_LEFT = ClientUpperLeft().x + EDGE_PAD - 1;
const GG::X BAR_RIGHT = ClientLowerRight().x - EDGE_PAD + 1;
const GG::X BAR_MAX_LENGTH = BAR_RIGHT - BAR_LEFT;
const GG::Y TOP = ClientUpperLeft().y + EDGE_PAD - 1;
GG::Y y = TOP;
for (unsigned int i = 0; i < m_initial_values.size(); ++i) {
// bar grey backgrounds
GG::FlatRectangle(GG::Pt(BAR_LEFT, y), GG::Pt(BAR_RIGHT, y + BAR_HEIGHT), DARY_GREY, DARY_GREY, 0);
y += BAR_HEIGHT + BAR_PAD;
}
// Find the largest value to be displayed to determine the scale factor. Must be greater than
// zero so that there is at least one segment drawn.
double largest_value = 0.1;
for (unsigned int i = 0; i < m_initial_values.size(); ++i) {
if ((m_initial_values[i] != Meter::INVALID_VALUE) && (m_initial_values[i] > largest_value))
largest_value = m_initial_values[i];
if ((m_projected_values[i] != Meter::INVALID_VALUE) && (m_projected_values[i] > largest_value))
largest_value = m_projected_values[i];
if ((m_target_max_values[i] != Meter::INVALID_VALUE) && (m_target_max_values[i] > largest_value))
largest_value = m_target_max_values[i];
}
const double num_full_increments =
std::ceil(largest_value / MULTI_METER_STATUS_BAR_DISPLAYED_METER_RANGE_INCREMENT);
const double MULTI_METER_STATUS_BAR_DISPLAYED_METER_RANGE =
num_full_increments * MULTI_METER_STATUS_BAR_DISPLAYED_METER_RANGE_INCREMENT;
// lines for 20, 40, 60, 80 etc.
GG::GL2DVertexBuffer bar_verts;
unsigned int num_segments = num_full_increments * 5;
bar_verts.reserve(num_segments - 1);
for (unsigned int ii_div_line = 1; ii_div_line <= (num_segments - 1); ++ii_div_line) {
bar_verts.store(Value(BAR_LEFT) + ii_div_line*Value(BAR_MAX_LENGTH)/num_segments, TOP);
bar_verts.store(Value(BAR_LEFT) + ii_div_line*Value(BAR_MAX_LENGTH)/num_segments, y - BAR_PAD);
}
bar_verts.activate();
glColor(HALF_GREY);
glDisable(GL_TEXTURE_2D);
glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS);
glEnableClientState(GL_VERTEX_ARRAY);
glDrawArrays(GL_LINES, 0, bar_verts.size());
glPopClientAttrib();
glEnable(GL_TEXTURE_2D);
// current, initial, and target/max horizontal bars for each pair of MeterType
y = TOP;
for (unsigned int i = 0; i < m_initial_values.size(); ++i) {
const GG::Y BAR_TOP = y;
const GG::Y BAR_BOTTOM = BAR_TOP + BAR_HEIGHT;
const bool SHOW_INITIAL = (m_initial_values[i] != Meter::INVALID_VALUE);
const bool SHOW_PROJECTED = (m_projected_values[i] != Meter::INVALID_VALUE);
const bool SHOW_TARGET_MAX = (m_target_max_values[i] != Meter::INVALID_VALUE);
const GG::X INITIAL_RIGHT(BAR_LEFT + GG::ToX(BAR_MAX_LENGTH * m_initial_values[i] / MULTI_METER_STATUS_BAR_DISPLAYED_METER_RANGE));
const GG::Y INITIAL_TOP(BAR_TOP);
if (SHOW_INITIAL) {
// initial value
glColor(m_bar_colours[i]);
m_bar_shading_texture->OrthoBlit(GG::Pt(BAR_LEFT, INITIAL_TOP), GG::Pt(INITIAL_RIGHT, BAR_BOTTOM));
// black border
GG::FlatRectangle(GG::Pt(BAR_LEFT, INITIAL_TOP), GG::Pt(INITIAL_RIGHT, BAR_BOTTOM), GG::CLR_ZERO, GG::CLR_BLACK, 1);
}
const GG::X PROJECTED_RIGHT(BAR_LEFT + GG::ToX(BAR_MAX_LENGTH * m_projected_values[i] / MULTI_METER_STATUS_BAR_DISPLAYED_METER_RANGE));
const GG::Y PROJECTED_TOP(INITIAL_TOP);
if (SHOW_PROJECTED) {
// projected colour bar with black border
if (PROJECTED_RIGHT > INITIAL_RIGHT) {
GG::FlatRectangle(GG::Pt(INITIAL_RIGHT - 1, PROJECTED_TOP), GG::Pt(PROJECTED_RIGHT, BAR_BOTTOM), ClientUI::StatIncrColor(), GG::CLR_BLACK, 1);
} else if (PROJECTED_RIGHT < INITIAL_RIGHT) {
GG::FlatRectangle(GG::Pt(PROJECTED_RIGHT - 1, PROJECTED_TOP), GG::Pt(INITIAL_RIGHT, BAR_BOTTOM), ClientUI::StatDecrColor(), GG::CLR_BLACK, 1);
}
}
const GG::X TARGET_MAX_RIGHT(BAR_LEFT + GG::ToX(BAR_MAX_LENGTH * m_target_max_values[i] / MULTI_METER_STATUS_BAR_DISPLAYED_METER_RANGE));
if (SHOW_TARGET_MAX && TARGET_MAX_RIGHT > BAR_LEFT) {
// max / target value
//glColor(DarkColor(m_bar_colours[i]));
//m_bar_shading_texture->OrthoBlit(GG::Pt(BAR_LEFT, BAR_TOP), GG::Pt(TARGET_MAX_RIGHT, BAR_BOTTOM));
// black border
GG::FlatRectangle(GG::Pt(BAR_LEFT, BAR_TOP), GG::Pt(TARGET_MAX_RIGHT, BAR_BOTTOM), GG::CLR_ZERO, m_bar_colours[i], 1);
}
// move down position of next bar, if any
y += BAR_HEIGHT + BAR_PAD;
}
}
void MultiMeterStatusBar::MouseWheel(GG::Pt pt, int move, GG::Flags<GG::ModKey> mod_keys)
{ ForwardEventToParent(); }
void MultiMeterStatusBar::Update() {
m_initial_values.clear(); // initial value of .first MeterTypes at the start of this turn
m_projected_values.clear(); // projected current value of .first MeterTypes for the start of next turn
m_target_max_values.clear();// current values of the .second MeterTypes in m_meter_types
auto obj = Objects().get(m_object_id);
if (!obj) {
ErrorLogger() << "MultiMeterStatusBar couldn't get object with id " << m_object_id;
return;
}
int num_bars = 0; // count number of valid bars' data added
for (auto& [actual_meter_type, target_max_meter_type] : m_meter_types) {
const Meter* actual_meter = obj->GetMeter(actual_meter_type);
const Meter* target_max_meter = obj->GetMeter(target_max_meter_type);
if (actual_meter || target_max_meter) {
float initial = actual_meter ? actual_meter->Initial() : Meter::INVALID_VALUE;
float projected = actual_meter ? actual_meter->Current() : Meter::INVALID_VALUE;
float target = target_max_meter ? target_max_meter->Current() : Meter::INVALID_VALUE;
++num_bars;
m_initial_values.push_back(initial);
m_projected_values.push_back(projected);
m_target_max_values.push_back(target);
m_bar_colours.push_back(MeterColor(actual_meter_type));
}
}
// calculate height from number of bars to be shown
const GG::Y HEIGHT = num_bars*BAR_HEIGHT + (num_bars - 1)*BAR_PAD + 2*EDGE_PAD - 2;
Resize(GG::Pt(Width(), HEIGHT));
}
|