Freeciv21
Develop your civilization from humble roots to a global empire
tileset_debugger.cpp
Go to the documentation of this file.
1 /*
2  Copyright (c) 2021-2023 Freeciv21 contributors. This file is
3  part of Freeciv21. Freeciv21 is free software: you can redistribute it
4  and/or modify it under the terms of the GNU General Public License as
5  published by the Free Software Foundation, either version 3 of the
6  License, or (at your option) any later version. You should have received
7  a copy of the GNU General Public License along with Freeciv21. If not,
8  see https://www.gnu.org/licenses/.
9  */
10 
11 #include "tileset_debugger.h"
12 
13 // client
14 #include "climap.h"
15 #include "editor.h"
16 #include "tileset/tilespec.h"
17 
18 // common
19 #include "map.h"
20 #include "tile.h"
21 
22 // utility
23 #include "fcintl.h"
24 
25 #include <QHeaderView>
26 #include <QLabel>
27 #include <QListWidget>
28 #include <QPainter>
29 #include <QToolBar>
30 #include <QTreeWidget>
31 #include <QVBoxLayout>
32 
33 namespace freeciv {
34 
43 tileset_debugger::tileset_debugger(QWidget *parent) : QDialog(parent)
44 {
45  setWindowTitle(_("Tileset debugger"));
46  resize(600, 500);
47 
48  auto tabs = new QTabWidget;
49 
50  auto layout = new QVBoxLayout;
51  layout->addWidget(tabs);
52  layout->setContentsMargins(0, 0, 0, 0);
53  setLayout(layout);
54 
55  // Log tab
56  {
57  m_messages = new QListWidget;
58  tabs->addTab(m_messages, _("Messages"));
59 
60  m_messages->setEditTriggers(QAbstractItemView::NoEditTriggers);
61  m_messages->setSelectionMode(QAbstractItemView::ContiguousSelection);
62  m_messages->setTextElideMode(Qt::ElideNone);
63  m_messages->setWordWrap(true);
64  m_messages->setSizeAdjustPolicy(
65  QAbstractItemView::AdjustToContentsOnFirstShow);
67  }
68 
69  // Tile inspector tab
70  {
71  auto tab = new QWidget;
72  tabs->addTab(tab, _("Inspector"));
73  auto layout = new QVBoxLayout;
74  tab->setLayout(layout);
75 
76  auto toolbar = new QToolBar;
77  toolbar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
78  layout->addWidget(toolbar);
79 
81  toolbar->addAction(QIcon::fromTheme("pointer"), _("Pick tile"));
82  m_pick_action->setToolTip(_("Pick a tile to inspect on the map"));
83  m_pick_action->setCheckable(true);
84  connect(m_pick_action, &QAction::toggled, this,
86 
87  m_label = new QLabel;
88  layout->addWidget(m_label);
89 
90  m_content = new QTreeWidget;
91  m_content->setHeaderHidden(true);
92  m_content->setSelectionMode(QAbstractItemView::NoSelection);
93  layout->addWidget(m_content, 100);
94 
95  set_tile(nullptr);
96  }
97 }
98 
103 
107 void tileset_debugger::set_tile(const ::tile *t)
108 {
109  m_tile = t;
110  m_pick_action->setChecked(false);
111 
112  // Update the GUI
113  if (!t) {
114  m_label->setText(_("Select a tile to start debugging."));
115  return;
116  }
117 
118  m_label->setText(QString(_("Tile at %1, %2"))
120  .arg(index_to_map_pos_y(tile_index(t))));
121 
122  // Fill tile data
123  m_content->clear();
124 
125  auto maxSize = QSize(); // Max sprite size
126  for (const auto &layer : tileset_get_layers(tileset)) {
127  auto item = new QTreeWidgetItem(m_content);
128 
129  const auto name = mapview_layer_name(layer->type());
130  item->setText(0, name);
131 
132  // Get the list of sprites for this layer
133  ::unit *unit = nullptr;
137  }
138  const auto sprites = layer->fill_sprite_array(t, nullptr, nullptr, unit);
139 
140  if (sprites.empty()) {
141  continue;
142  }
143 
144  // Generate a sprite with this layer only
145  // Geometry
146  auto rectangle = QRect();
147  for (const auto &ds : sprites) {
148  rectangle |= QRect(ds.offset, ds.sprite->size());
149  }
150 
151  // Draw the composite picture
152  auto this_layer = QPixmap(rectangle.size() + QSize(2, 2));
153  this_layer.fill(Qt::transparent);
154  auto p = QPainter();
155  p.begin(&this_layer);
156  // Outline
157  p.setPen(palette().color(QPalette::WindowText));
158  p.drawRect(0, 0, this_layer.width() - 1, this_layer.height() - 1);
159  // If there are negative offsets, the pixmap was extended in the negative
160  // direction. Compensate by offsetting the painter back...
161  p.translate(-rectangle.topLeft() + QPoint(1, 1));
162  for (const auto &ds : sprites) {
163  p.drawPixmap(ds.offset, *ds.sprite);
164  }
165  p.end();
166  item->setIcon(0, QIcon(this_layer));
167 
168  // Add the sprites as children
169  for (const auto &ds : sprites) {
170  auto child = new QTreeWidgetItem(item);
171  auto this_sprite = QPixmap(rectangle.size() + QSize(2, 2));
172  this_sprite.fill(Qt::transparent);
173  p.begin(&this_sprite);
174  // Outline
175  p.resetTransform();
176  p.setPen(palette().color(QPalette::WindowText));
177  p.drawRect(0, 0, this_layer.width() - 1, this_layer.height() - 1);
178  // We inherit the translation set above
179  p.translate(-rectangle.topLeft() + QPoint(1, 1));
180  p.drawPixmap(ds.offset, *ds.sprite);
181  p.end();
182  child->setIcon(0, QIcon(this_sprite));
183  child->setText(0, QString(_("Offset: %1, %2"))
184  .arg(ds.offset.x())
185  .arg(ds.offset.y()));
186  maxSize = maxSize.expandedTo(rectangle.size());
187  }
188  }
189 
190  m_content->setIconSize(maxSize);
191  m_content->expandAll();
192 }
193 
197 void tileset_debugger::refresh(const struct tileset *t)
198 {
199  // Refresh the tile info, if any
200  set_tile(m_tile);
201 
202  // Reload messages
203  refresh_messages(t);
204 }
205 
210 {
211  emit tile_picking_requested(active);
212 }
213 
218 {
219  fc_assert_ret(t != nullptr);
220 
221  m_messages->clear();
222 
223  const auto log = tileset_log(t);
224  for (std::size_t i = 0; i < log.size(); ++i) {
225  auto item = new QListWidgetItem;
226  switch (log[i].level) {
227  case QtFatalMsg:
228  case QtCriticalMsg:
229  item->setIcon(QIcon::fromTheme(QStringLiteral("data-error")));
230  break;
231  case QtWarningMsg:
232  item->setIcon(QIcon::fromTheme(QStringLiteral("data-warning")));
233  break;
234  case QtInfoMsg:
235  case QtDebugMsg:
236  item->setIcon(QIcon::fromTheme(QStringLiteral("data-information")));
237  break;
238  }
239  item->setText(log[i].message);
240  m_messages->addItem(item);
241  }
242 }
243 
244 } // namespace freeciv
A layer when drawing the map.
Definition: layer.h:153
mapview_layer type() const
Definition: layer.h:238
virtual std::vector< drawn_sprite > fill_sprite_array(const tile *ptile, const tile_edge *pedge, const tile_corner *pcorner, const unit *punit) const
Returns the list of sprites drawn by this layer somewhere on the map.
Definition: layer.h:172
void tile_picking_requested(bool active)
void set_tile(const ::tile *t)
Sets the tile being debugged.
void refresh_messages(const struct tileset *t)
Refresh the messages list.
virtual ~tileset_debugger()
Destructor.
tileset_debugger(QWidget *parent=nullptr)
Constructor.
void refresh(const struct tileset *t)
Enters or exits tile picking mode.
void pick_tile(bool active)
Enters or exits tile picking mode.
enum known_type client_tile_get_known(const struct tile *ptile)
A tile's "known" field is used by the server to store whether each player knows the tile.
Definition: climap.cpp:29
bool editor_tile_is_selected(const struct tile *ptile)
Returns TRUE if the given tile is selected.
Definition: editor.cpp:1109
bool editor_is_active()
Returns TRUE if the client is in edit mode.
Definition: editor.cpp:335
#define _(String)
Definition: fcintl.h:50
const char * name
Definition: inputfile.cpp:118
#define fc_assert_ret(condition)
Definition: log.h:112
static int index_to_map_pos_y(int mindex)
Definition: map.h:616
static int index_to_map_pos_x(int mindex)
Definition: map.h:607
Definition: path.cpp:10
struct setting_list * level[OLEVELS_NUM]
Definition: settings.cpp:167
Definition: climisc.h:66
Definition: unit.h:134
#define tile_index(_pt_)
Definition: tile.h:70
@ TILE_UNKNOWN
Definition: tile.h:29
const std::vector< std::unique_ptr< freeciv::layer > > & tileset_get_layers(const struct tileset *t)
Definition: tilespec.cpp:3700
struct unit * get_drawable_unit(const struct tileset *t, const ::tile *ptile)
Find unit that we can display from given tile.
Definition: tilespec.cpp:3246
std::vector< tileset_log_entry > tileset_log(const struct tileset *t)
Get tileset log (warnings, errors, etc.)
Definition: tilespec.cpp:3755