playersdiagram.cpp
1 // playerdiagram.cpp
2 //------------------------------------------------------------------------------
3 //------------------------------------------------------------------------------
4 //
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation; either
8 // version 2.1 of the License, or (at your option) any later version.
9 //
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 // 02110-1301 USA
19 //
20 //------------------------------------------------------------------------------
21 // Copyright (C) 2010 Braden "Blzut3" Obrzut <admin@maniacsvault.net>
22 //------------------------------------------------------------------------------
23 #include "playersdiagram.h"
24 
25 #include "serverapi/playerslist.h"
26 #include "serverapi/server.h"
27 #include "datapaths.h"
28 #include "log.h"
29 #include "strings.hpp"
30 #include <QDir>
31 #include <QPainter>
32 #include <QResource>
33 #include <cassert>
34 
35 QImage PlayersDiagram::openImage;
36 QImage PlayersDiagram::openSpecImage;
37 QImage PlayersDiagram::botImage;
38 QImage PlayersDiagram::playerImage;
39 QImage PlayersDiagram::spectatorImage;
40 
41 const QString PlayersDiagram::DEFAULT_STYLE = "blocks";
42 QString PlayersDiagram::currentlyLoadedStyle;
43 
44 PlayersDiagram::PlayersDiagram(ServerCPtr server)
45 : server(server)
46 {
47  if(openImage.isNull())
48  {
49  return;
50  }
51 
52  obtainPlayerNumbers();
53  draw();
54 }
55 
56 PlayersDiagram::~PlayersDiagram()
57 {
58 }
59 
60 QList<PlayersDiagramStyle> PlayersDiagram::availableSlotStyles()
61 {
62  QList<PlayersDiagramStyle> list;
63 
64  // Built-ins.
65  list << PlayersDiagramStyle("numeric", tr("Numeric"));
66  list << PlayersDiagramStyle("blocks", tr("Blocks"));
67 
68  // Extra.
69  QStringList knownNames;
70  foreach (QDir dir, stylePaths())
71  {
72  QStringList extraSlots = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
73  foreach (QString slotsName, extraSlots)
74  {
75  if (!knownNames.contains(slotsName, Qt::CaseInsensitive))
76  {
77  knownNames << slotsName;
78  list << PlayersDiagramStyle(slotsName);
79  }
80  }
81  }
82 
83  return list;
84 }
85 
86 QImage PlayersDiagram::colorizePlayer(QImage image, const QColor &color)
87 {
88  QVector<QRgb> colors = image.colorTable();
89  QColor destinationColor = color.toHsv();
90  for(int i = 0; i < colors.size(); ++i)
91  {
92  // Cyan has no red so move on if this color has red.
93  if(qRed(colors[i]) != 0 || qAlpha(colors[i]) == 0)
94  {
95  continue;
96  }
97 
98  int hue = 0;
99  int saturation = 0;
100  int value = 0;
101  destinationColor.getHsv(&hue, &saturation, &value);
102  destinationColor.setHsv(hue, saturation, QColor(colors[i]).toHsv().value());
103  colors[i] = destinationColor.rgb();
104  }
105  image.setColorTable(colors);
106 
107  return image;
108 }
109 
110 void PlayersDiagram::draw()
111 {
112  // Don't bother trying to draw an empty image.
113  if(server->numTotalSlots() == 0)
114  return;
115 
116  diagram = QPixmap(server->numTotalSlots() * playerImage.width(), playerImage.height());
117  diagram.fill(Qt::transparent);
118 
119  slotSize = playerImage.width();
120  position = diagram.width() - slotSize;
121  painter = new QPainter(&diagram);
122 
123  for (int team = 0; team < MAX_TEAMS; ++team)
124  {
125  drawTeam(Human, team, numHumansOnTeam[team]);
126  drawTeam(Bot, team, numBotsOnTeam[team]);
127  }
128 
129  drawTeam(Human, Player::TEAM_NONE, numHumansWithoutTeam);
130  drawTeam(Bot, Player::TEAM_NONE, numBotsWithoutTeam);
131 
132  if (numSpectators > 0)
133  {
134  drawPictures(spectatorImage, numSpectators);
135  }
136 
137  if (numFreeJoinSlots > 0)
138  {
139  drawPictures(openImage, numFreeJoinSlots);
140  }
141 
142  if (numFreeSpectatorSlots > 0)
143  {
144  drawPictures(openSpecImage, numFreeSpectatorSlots);
145  }
146 
147  delete painter;
148 }
149 
150 void PlayersDiagram::drawTeam(PlayerType playerType, int team, int howMany)
151 {
152  if (howMany > 0)
153  {
154  QImage baseImage;
155 
156  switch(playerType)
157  {
158  case Bot:
159  baseImage = botImage;
160  break;
161 
162  case Human:
163  baseImage = playerImage;
164  break;
165 
166  default:
167  gLog << "Error inside PlayersDiagram::drawTeam(): unknown PlayerType";
168  return;
169  }
170 
171  const QImage picture = colorizePlayer(baseImage, QColor(server->teamColor(team)));
172  drawPictures(picture, howMany);
173  }
174 }
175 
176 void PlayersDiagram::drawPictures(const QImage &image, int howMany)
177 {
178  for (; howMany > 0; --howMany)
179  {
180  painter->drawImage(position, 0, image);
181  position -= slotSize;
182  }
183 }
184 
185 bool PlayersDiagram::isNumericStyle(const QString &style)
186 {
187  return style == "numeric";
188 }
189 
190 void PlayersDiagram::loadImages(const QString &style)
191 {
192  if (style == currentlyLoadedStyle)
193  return;
194  if (isNumericStyle(style))
195  return;
196 
197  openImage = loadImage(style, "open");
198  openSpecImage = loadImage(style, "specopen");
199  botImage = loadImage(style, "bot");
200  playerImage = loadImage(style, "player");
201  spectatorImage = loadImage(style, "spectator");
202  currentlyLoadedStyle = style;
203 }
204 
205 QImage PlayersDiagram::loadImage(const QString &style, const QString &name)
206 {
207  QImage image;
208  if (style != DEFAULT_STYLE)
209  {
210  QString resourcePath;
211  foreach(const QString &dir, stylePaths())
212  {
213  image = QImage(Strings::combinePaths(dir, style + "/" + name + ".png"));
214  if (!image.isNull())
215  return image;
216  }
217  }
218  if (image.isNull())
219  {
220  image = QImage(":/slots/" + DEFAULT_STYLE + "/" + name);
221  }
222  return image;
223 }
224 
225 void PlayersDiagram::obtainPlayerNumbers()
226 {
227  memset(numBotsOnTeam, 0, sizeof(int) * MAX_TEAMS);
228  memset(numHumansOnTeam, 0, sizeof(int) * MAX_TEAMS);
229 
230  const PlayersList &players = server->players();
231 
232  numBotsWithoutTeam = players.numBotsWithoutTeam();
233  numFreeJoinSlots = server->numFreeJoinSlots();
234  numFreeSpectatorSlots = server->numFreeSpectatorSlots();
235  numHumansWithoutTeam = players.numHumansWithoutTeam();
236  numSpectators = players.numSpectators();
237 
238  for(int i = 0; i < MAX_TEAMS; ++i)
239  {
240  numBotsOnTeam[i] = players.numBotsOnTeam(i);
241  numHumansOnTeam[i] = players.numHumansOnTeam(i);
242  }
243 }
244 
245 QStringList PlayersDiagram::stylePaths()
246 {
247  return gDefaultDataPaths->staticDataSearchDirs("theme/slots");
248 }
static QString combinePaths(QString pathFront, QString pathEnd)
Definition: strings.cpp:147
static void loadImages(const QString &style)
QImage colorizePlayer(QImage image, const QColor &color)