Freeciv21
Develop your civilization from humble roots to a global empire
mapctrl.cpp
Go to the documentation of this file.
1 /*
2  Copyright (c) 1996-2023 Freeciv21 and Freeciv 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 // Qt
12 #include <QApplication>
13 #include <QMouseEvent>
14 // common
15 #include "control.h"
16 #include "goto.h"
17 #include "map.h"
18 // client
19 #include "chatline_common.h"
20 #include "citydlg.h"
21 #include "citydlg_common.h"
22 #include "client_main.h"
23 #include "fc_client.h"
24 #include "mapctrl.h"
25 #include "mapctrl_common.h"
26 #include "messagewin.h"
27 #include "page_game.h"
28 #include "shortcuts.h"
29 #include "themes_common.h"
30 #include "tile.h"
31 #include "tileset/tilespec.h"
32 #include "unit.h"
33 #include "unitselect.h"
34 #include "views/view_map.h"
35 #include "views/view_map_common.h"
36 
37 extern void qload_lua_script();
38 extern void qreload_lua_script();
39 
44 void popup_newcity_dialog(struct unit *punit, const char *suggestname)
45 {
46  hud_input_box *ask = new hud_input_box(king()->central_wdg);
47  int index = tile_index(unit_tile(punit));
48 
49  ask->set_text_title_definput(_("What should we call our new city?"),
50  _("Build New City"), suggestname);
51  ask->setAttribute(Qt::WA_DeleteOnClose);
52  QObject::connect(ask, &hud_input_box::finished, [=](int result) {
53  if (result == QDialog::Accepted) {
54  QByteArray ask_bytes;
55 
56  ask_bytes = ask->input_edit.text().toLocal8Bit();
57  finish_city(index_to_tile(&(wld.map), index), ask_bytes.data());
58  } else {
59  cancel_city(index_to_tile(&(wld.map), index));
60  }
61  });
62  ask->show();
63 }
64 
69 {
70  QPoint global_pos, local_pos;
71  int x, y;
72 
73  global_pos = QCursor::pos();
74  local_pos = queen()->mapview_wdg->mapFromGlobal(global_pos)
75  / queen()->mapview_wdg->scale();
76  x = local_pos.x();
77  y = local_pos.y();
78 
79  if (x >= 0 && y >= 0 && x < mapview.width && y < mapview.width) {
80  update_line(x, y);
81  }
82 }
83 
89 { // PLS DONT PORT IT
90 }
91 
96 {
97  Qt::KeyboardModifiers key_mod = QApplication::keyboardModifiers();
98  bool is_shift = key_mod.testFlag(Qt::ShiftModifier);
99 
100  if (C_S_RUNNING == client_state()) {
101  if (is_shift) {
102  switch (event->key()) {
103  case Qt::Key_Return:
104  case Qt::Key_Enter:
105  key_end_turn();
106  return;
107  default:
108  break;
109  }
110  }
111 
112  switch (event->key()) {
113  case Qt::Key_Up:
114  case Qt::Key_8:
115  if (is_shift) {
116  recenter_button_pressed(width() / 2 / scale(), 0);
117  } else {
118  key_unit_move(DIR8_NORTH);
119  }
120  return;
121  case Qt::Key_Left:
122  case Qt::Key_4:
123  if (is_shift) {
124  recenter_button_pressed(0, height() / 2 / scale());
125  } else {
126  key_unit_move(DIR8_WEST);
127  }
128  return;
129  case Qt::Key_Right:
130  case Qt::Key_6:
131  if (is_shift) {
132  recenter_button_pressed(width() / scale(), height() / 2 / scale());
133  } else {
134  key_unit_move(DIR8_EAST);
135  }
136  return;
137  case Qt::Key_Down:
138  case Qt::Key_2:
139  if (is_shift) {
140  recenter_button_pressed(width() / 2 / scale(), height() / scale());
141  } else {
142  key_unit_move(DIR8_SOUTH);
143  }
144  return;
145  case Qt::Key_PageUp:
146  case Qt::Key_9:
147  key_unit_move(DIR8_NORTHEAST);
148  return;
149  case Qt::Key_PageDown:
150  case Qt::Key_3:
151  key_unit_move(DIR8_SOUTHEAST);
152  return;
153  case Qt::Key_Home:
154  case Qt::Key_7:
155  key_unit_move(DIR8_NORTHWEST);
156  return;
157  case Qt::Key_End:
158  case Qt::Key_1:
159  key_unit_move(DIR8_SOUTHWEST);
160  return;
161  case Qt::Key_5:
162  case Qt::Key_Clear:
164  return;
165  case Qt::Key_Escape:
167  return;
168  case Qt::Key_Enter:
169  case Qt::Key_Return:
170  // Ensure chat is visible
171  queen()->chat->take_focus();
172  return;
173  default:
174  break;
175  }
176  }
177 }
178 
183 {
184  // FIXME mouse handling
185  auto pos = mapFromGlobal(QCursor::pos()) / scale();
186 
187  auto ptile = canvas_pos_to_tile(pos.x(), pos.y());
188  auto pcity = ptile ? tile_city(ptile) : nullptr;
189 
190  if (pcity && pcity->owner != client_player()) {
191  pcity = nullptr;
192  }
193 
194  switch (id) {
195  case SC_SELECT_BUTTON:
196  // Trade Generator - skip
197  if (king()->trade_gen.hover_city) {
198  king()->trade_gen.add_tile(ptile);
199  queen()->mapview_wdg->repaint();
200  return;
201  }
202 
203  // Rally point - select city - skip
204  if (king()->rallies.hover_city) {
205  char text[1024];
206 
207  if (ptile && tile_city(ptile)) {
208  king()->rallies.hover_tile = true;
209  king()->rallies.rally_city = tile_city(ptile);
210 
211  fc_snprintf(text, sizeof(text),
212  _("Selected city %s. Now choose rally point."),
213  city_link(tile_city(ptile)));
215  } else {
216  output_window_append(ftc_client, _("No city selected. Aborted"));
217  }
218  return;
219  }
220 
221  // Rally point - select tile - skip
222  if (king()->rallies.hover_tile && ptile != nullptr) {
223  char text[1024];
224 
225  struct city *pcity = king()->rallies.rally_city;
226  fc_assert_ret(pcity != nullptr);
227 
228  if (send_rally_tile(pcity, ptile)) {
229  fc_snprintf(text, sizeof(text),
230  _("Tile %s set as rally point from city %s."),
231  tile_link(ptile), city_link(pcity));
233  } else {
234  fc_snprintf(text, sizeof(text),
235  _("Could not set rally point for city %s."),
236  city_link(pcity));
238  }
239 
240  king()->rallies.rally_city = nullptr;
241  king()->rallies.hover_tile = false;
242  return;
243  }
244 
245  if (king()->menu_bar->delayed_order && ptile) {
246  king()->menu_bar->set_tile_for_order(ptile);
248  exit_goto_state();
249  king()->menu_bar->delayed_order = false;
250  return;
251  }
252 
253  if (king()->menu_bar->quick_airlifting && ptile) {
254  if (tile_city(ptile)) {
255  multiairlift(tile_city(ptile), king()->menu_bar->airlift_type_id);
256  } else {
257  output_window_append(ftc_client, "No city selected for airlift");
258  }
259  king()->menu_bar->quick_airlifting = false;
260  return;
261  }
262 
263  if (!goto_is_active()) {
265  action_button_pressed(pos.x(), pos.y(), SELECT_FOCUS);
266  return;
267  }
268  break;
269 
270  case SC_QUICK_SELECT:
271  if (pcity != nullptr && !king()->menu_bar->delayed_order) {
272  auto pw = new production_widget(this, pcity, false, 0, 0, true);
273  pw->show();
274  }
275  break;
276 
277  case SC_SHOW_UNITS:
278  if (ptile != nullptr && unit_list_size(ptile->units) > 0) {
279  toggle_unit_sel_widget(ptile);
280  }
281  break;
282 
283  case SC_COPY_PROD:
284  if (ptile != nullptr) {
286  }
287  break;
288 
289  case SC_POPUP_COMB_INF:
290  if (queen()->battlelog_wdg != nullptr) {
291  queen()->battlelog_wdg->show();
292  }
293  break;
294 
295  case SC_PASTE_PROD:
296  if (pcity != nullptr) {
298  }
299  break;
300 
301  case SC_RELOAD_THEME:
303  break;
304 
305  case SC_RELOAD_TILESET:
306  QPixmapCache::clear();
308  break;
309 
310  case SC_LOAD_LUA:
312  break;
313 
314  case SC_RELOAD_LUA:
316  break;
317 
318  case SC_HIDE_WORKERS:
319  key_city_overlay(pos.x(), pos.y());
320  break;
321 
322  case SC_MAKE_LINK:
323  if (ptile != nullptr) {
324  queen()->chat->make_link(ptile);
325  }
326  break;
327 
328  case SC_BUY_MAP:
329  if (pcity != nullptr) {
330  city_buy_production(pcity);
331  }
332  break;
333 
334  case SC_QUICK_BUY:
335  if (pcity != nullptr) {
336  auto pw = new production_widget(this, pcity, false, 0, 0, true, true);
337  pw->show();
338  }
339  break;
340 
341  case SC_APPEND_FOCUS:
342  action_button_pressed(pos.x(), pos.y(), SELECT_APPEND);
343  break;
344 
345  case SC_ADJUST_WORKERS:
346  adjust_workers_button_pressed(pos.x(), pos.y());
347  break;
348 
349  case SC_SCROLL_MAP:
350  recenter_button_pressed(pos.x(), pos.y());
351  break;
352 
353  case SC_POPUP_INFO:
354  if (ptile != nullptr) {
355  popup_tile_info(ptile);
356  }
357  break;
358 
359  case SC_WAKEUP_SENTRIES:
360  wakeup_button_pressed(pos.x(), pos.y());
361  break;
362 
363  default:
364  // Many actions aren't handled here
365  break;
366  }
367 }
368 
372 void map_view::shortcut_released(Qt::MouseButton bt)
373 {
374  auto md = QApplication::keyboardModifiers();
375  auto pos = mapFromGlobal(QCursor::pos()) / scale();
376 
377  if (info_tile::shown()) {
379  }
380 
382  if (bt == sc.buttons && md == sc.modifiers) {
383  if (king()->trade_gen.hover_city || king()->rallies.hover_city) {
384  king()->trade_gen.hover_city = false;
385  king()->rallies.hover_city = false;
386  return;
387  }
389  action_button_pressed(pos.x(), pos.y(), SELECT_POPUP);
390  }
392  release_goto_button(pos.x(), pos.y());
393  return;
394  }
395 }
396 
401 {
403 }
404 
409 {
410  shortcut_released(event->button());
411 }
412 
416 void map_view::mouseMoveEvent(QMouseEvent *event)
417 {
418  update_line(event->pos().x() / scale(), event->pos().y() / scale());
421  event->pos().y() / scale());
422  }
424  event->pos().y() / scale()));
425 }
void output_window_append(const struct ft_color color, const char *featured_text)
Add a line of text to the output ("chatline") window, like puts() would do it in the console.
int city_buy_production(struct city *pcity)
Buy the current production item in a given city.
void take_focus()
Shows the chat and ensures the chat line has focus.
Definition: chatline.cpp:513
void make_link(struct tile *ptile)
Makes link to tile/unit or city.
Definition: chatline.cpp:690
trade_generator trade_gen
Definition: fc_client.h:129
mr_menu * menu_bar
Definition: fc_client.h:127
qfc_rally_list rallies
Definition: fc_client.h:128
fc_shortcut get_shortcut(shortcut_id id) const
Returns shortcut for given id.
Definition: shortcuts.cpp:247
static fc_shortcuts * sc()
Returns given instance.
Definition: shortcuts.cpp:354
void maybe_route_mouse_shortcut(QMouseEvent *event, map_view *mapview)
If the mouse event corresponds to a registered shortcut, fire the corresponding action.
Definition: shortcuts.cpp:328
void set_text_title_definput(const QString &s1, const QString &s2, const QString &def_input)
Sets text, title and default text and shows input box.
Definition: hudwidget.cpp:372
QLineEdit input_edit
Definition: hudwidget.h:118
static bool shown()
Check if the info tile is currently shown.
Definition: view_map.cpp:666
void mouseReleaseEvent(QMouseEvent *event) override
Mouse release event for map_view.
Definition: mapctrl.cpp:408
void mousePressEvent(QMouseEvent *event) override
Mouse buttons handler for map_view.
Definition: mapctrl.cpp:400
void keyPressEvent(QKeyEvent *event) override
Keyboard handler for map_view.
Definition: mapctrl.cpp:95
void mouseMoveEvent(QMouseEvent *event) override
Mouse movement handler for map_view.
Definition: mapctrl.cpp:416
void shortcut_pressed(shortcut_id key)
Pressed mouse or keyboard.
Definition: mapctrl.cpp:182
double scale
Definition: view_map.h:48
void shortcut_released(Qt::MouseButton mb)
Released mouse buttons.
Definition: mapctrl.cpp:372
void set_tile_for_order(struct tile *ptile)
Sets given tile for delayed order.
Definition: menu.cpp:1288
bool delayed_order
Definition: menu.h:192
bool quick_airlifting
Definition: menu.h:193
map_view * mapview_wdg
Definition: page_game.h:81
chat_widget * chat
Definition: page_game.h:80
hud_battle_log * battlelog_wdg
Definition: page_game.h:76
bool hover_city
Definition: menu.h:84
bool hover_tile
Definition: menu.h:83
struct city * rally_city
Definition: menu.h:85
void add_tile(struct tile *ptile)
Adds/removes tile to trade generator.
enum client_states client_state()
Return current client state.
struct player * client_player()
Either controlling or observing.
@ C_S_RUNNING
Definition: client_main.h:43
void set_auto_center_enabled(bool enabled)
Allows disabling automatic map recentering.
Definition: control.cpp:417
void key_cancel_action()
The 'Escape' key.
Definition: control.cpp:2709
void key_unit_move(enum direction8 gui_dir)
Move the focus unit in the given direction.
Definition: control.cpp:2790
void key_recall_previous_focus_unit()
Recall the previous focus unit(s).
Definition: control.cpp:2767
enum cursor_hover_state hover_state
Definition: control.cpp:82
void key_end_turn()
Handle user 'end turn' input.
Definition: control.cpp:2762
void finish_city(struct tile *ptile, const char *name)
All units ready to build city to the tile should now proceed.
Definition: control.cpp:3208
void clear_hover_state()
Clear current hover state (go to HOVER_NONE).
Definition: control.cpp:308
void control_mouse_cursor(struct tile *ptile)
Determines which mouse cursor should be used, according to hover_state, and the information gathered ...
Definition: control.cpp:1067
void cancel_city(struct tile *ptile)
Do not build city after all.
Definition: control.cpp:3228
@ SELECT_APPEND
Definition: control.h:34
@ SELECT_POPUP
Definition: control.h:31
@ SELECT_FOCUS
Definition: control.h:35
@ HOVER_NONE
Definition: control.h:19
enum event_type event
Definition: events.cpp:68
class fc_client * king()
Return fc_client instance.
Definition: gui_main.cpp:58
#define _(String)
Definition: fcintl.h:50
const char * tile_link(const struct tile *ptile)
Get a text link to a tile.
const struct ft_color ftc_client
const char * city_link(const struct city *pcity)
Get a text link to a city.
struct world wld
Definition: game.cpp:48
bool goto_is_active()
Is goto state active?
Definition: goto.cpp:302
bool send_rally_tile(struct city *pcity, struct tile *ptile)
Send rally orders for the city to move new units to the arbitrary tile.
Definition: goto.cpp:652
void exit_goto_state()
Tidy up and deactivate goto state.
Definition: goto.cpp:269
#define fc_assert_ret(condition)
Definition: log.h:112
struct tile * index_to_tile(const struct civ_map *imap, int mindex)
Return the tile for the given index position.
Definition: map.cpp:429
void popup_newcity_dialog(struct unit *punit, const char *suggestname)
Popup a dialog to ask for the name of a new city.
Definition: mapctrl.cpp:44
void qload_lua_script()
Load and execute lua script.
Definition: luaconsole.cpp:57
void create_line_at_mouse_pos(void)
Draw a goto or patrol line at the current mouse position.
Definition: mapctrl.cpp:68
void update_rect_at_mouse_pos(void)
The Area Selection rectangle.
Definition: mapctrl.cpp:88
void qreload_lua_script()
Reload last lua script.
Definition: luaconsole.cpp:72
void update_line(int canvas_x, int canvas_y)
Update the goto/patrol line to the given map canvas location.
void maybe_activate_keyboardless_goto(int canvas_x, int canvas_y)
The goto hover state is only activated when the mouse pointer moves beyond the tile where the button ...
void adjust_workers_button_pressed(int canvas_x, int canvas_y)
Adjust the position of city workers from the mapview.
void release_goto_button(int canvas_x, int canvas_y)
Goto button has been released.
void recenter_button_pressed(int canvas_x, int canvas_y)
Recenter the map on the canvas location, on user request.
void action_button_pressed(int canvas_x, int canvas_y, enum quickselect_type qtype)
Do some appropriate action when the "main" mouse button (usually left-click) is pressed.
void wakeup_button_pressed(int canvas_x, int canvas_y)
Wakeup sentried units on the tile of the specified location.
bool keyboardless_goto_button_down
void key_city_overlay(int canvas_x, int canvas_y)
The user pressed the overlay-city button (t) while the mouse was at the given canvas position.
bool keyboardless_goto_active
void clipboard_paste_production(struct city *pcity)
If City tiles are hilited, paste into all those cities.
bool clipboard_copy_production(struct tile *ptile)
Shift-Left-Click on owned city or any visible unit to copy.
void multiairlift(struct city *acity, Unit_type_id ut)
Airlift unit type to city acity from each city.
Definition: menu.cpp:2937
client_options * gui_options
Definition: options.cpp:74
pageGame * queen()
Return game instandce.
Definition: page_game.cpp:557
shortcut_id
Definition: shortcuts.h:33
@ SC_POPUP_COMB_INF
Definition: shortcuts.h:82
@ SC_HIDE_WORKERS
Definition: shortcuts.h:51
@ SC_POPUP_INFO
Definition: shortcuts.h:46
@ SC_RELOAD_LUA
Definition: shortcuts.h:89
@ SC_SHOW_UNITS
Definition: shortcuts.h:52
@ SC_PASTE_PROD
Definition: shortcuts.h:49
@ SC_WAKEUP_SENTRIES
Definition: shortcuts.h:47
@ SC_MAKE_LINK
Definition: shortcuts.h:48
@ SC_APPEND_FOCUS
Definition: shortcuts.h:45
@ SC_QUICK_BUY
Definition: shortcuts.h:41
@ SC_RELOAD_THEME
Definition: shortcuts.h:83
@ SC_RELOAD_TILESET
Definition: shortcuts.h:84
@ SC_BUY_MAP
Definition: shortcuts.h:78
@ SC_SCROLL_MAP
Definition: shortcuts.h:34
@ SC_QUICK_SELECT
Definition: shortcuts.h:42
@ SC_ADJUST_WORKERS
Definition: shortcuts.h:44
@ SC_SELECT_BUTTON
Definition: shortcuts.h:43
@ SC_COPY_PROD
Definition: shortcuts.h:50
@ SC_LOAD_LUA
Definition: shortcuts.h:88
Definition: city.h:291
char gui_qt_default_theme_name[512]
Definition: options.h:168
Definition: unit.h:134
int width
struct civ_map map
Definition: world_object.h:21
int fc_snprintf(char *str, size_t n, const char *format,...)
See also fc_utf8_snprintf_trunc(), fc_utf8_snprintf_rep().
Definition: support.cpp:537
bool load_theme(const QString &theme_name)
Loads a theme with the given name.
struct city * tile_city(const struct tile *ptile)
Return the city on this tile (or nullptr), checking for city center.
Definition: tile.cpp:72
#define tile_index(_pt_)
Definition: tile.h:70
bool tilespec_reread(const QString &name, bool game_fully_initialized)
Read a new tilespec in from scratch.
Definition: tilespec.cpp:916
const char * tileset_basename(const struct tileset *t)
Return the name of the given tileset.
Definition: tilespec.cpp:331
#define unit_tile(_pu)
Definition: unit.h:371
void toggle_unit_sel_widget(struct tile *ptile)
Shows/closes unit selection widget.
Definition: unitselect.cpp:389
void popup_tile_info(struct tile *ptile)
Popups information label tile.
Definition: view_map.cpp:682
void popdown_tile_info()
Popdowns information label tile.
Definition: view_map.cpp:702
struct tile * canvas_pos_to_tile(float canvas_x, float canvas_y)
Finds the tile corresponding to pixel coordinates.
struct view mapview