Freeciv21
Develop your civilization from humble roots to a global empire
turn_done_button.cpp
Go to the documentation of this file.
1 /*
2  * Code partly from QCommandLinkButton
3  *
4  * SPDX-FileCopyrightText: 2016 The Qt Company Ltd.
5  * SPDX-FileCopyrightText: 2022 Louis Moureaux <m_louis30@yahoo.com>
6  *
7  * SPDX-License-Identifier: GPL-3.0-or-later
8  */
9 
10 #include "turn_done_button.h"
11 
12 #include "client_main.h"
13 #include "fcintl.h"
14 #include "fonts.h"
15 #include "game.h"
16 
17 #include <QDateTime>
18 #include <QShortcut>
19 #include <QStyle>
20 #include <QStyleOptionButton>
21 #include <QStylePainter>
22 
23 namespace {
27 namespace metrics {
29 const int font_increase = 1;
31 const int contents_margin = 10;
33 const int line_separation = 6;
34 } // namespace metrics
35 } // namespace
36 
40 turn_done_button::turn_done_button(QWidget *parent) : QPushButton(parent)
41 {
42  // Set up shortcut (Shift+Enter, both main keyboard and numpad)
43  setShortcut(Qt::Key_Shift + Qt::Key_Enter);
44  connect(new QShortcut(Qt::Key_Shift + Qt::Key_Return, this),
45  &QShortcut::activated, this, [this] { animateClick(); });
46 
47  setText(_("Turn Done"));
48 
49  // FIXME This should come from the style...
50  // Set the font for the title
52  font.setPointSize(font.pointSize() + metrics::font_increase);
53  font.setBold(true);
54  setFont(font);
55 
56  setContentsMargins(metrics::contents_margin, metrics::contents_margin,
57  metrics::contents_margin, metrics::contents_margin);
58 
60 }
61 
66 {
67  auto size = QPushButton::sizeHint(); // Accounts for title width
68 
69  const auto margins = contentsMargins();
70  const auto fm_title = QFontMetrics(font());
71  const auto fm_text =
72  QFontMetrics(fcFont::instance()->getFont(fonts::default_font));
73 
74  size.setHeight(margins.top() + fm_title.height() + metrics::line_separation
75  + fm_text.height() + margins.bottom());
76 
77  return size;
78 }
79 
84 {
85  if (m_timeout_label.isEmpty()) {
86  QPushButton::paintEvent(event);
87  } else {
88  // The code below is adapted from QCommandLinkButton
89  QStylePainter p(this);
90  p.save();
91 
92  QStyleOptionButton option;
93  initStyleOption(&option);
94  option.text = QString();
95  option.icon = QIcon();
96 
97  // Some geometry
98  const int voffset =
99  isDown() ? style()->pixelMetric(QStyle::PM_ButtonShiftVertical) : 0;
100  const int hoffset =
101  isDown() ? style()->pixelMetric(QStyle::PM_ButtonShiftHorizontal)
102  : 0;
103 
104  const auto margins = contentsMargins();
105  auto text_rect = rect().adjusted(0, margins.top(), 0, -margins.bottom());
106  text_rect = text_rect.translated(hoffset, voffset);
107 
108  // Draw the background
109  p.drawControl(QStyle::CE_PushButton, option);
110 
111  // Draw the title
112  int title_flags = Qt::TextShowMnemonic | Qt::AlignHCenter | Qt::AlignTop;
113  if (!style()->styleHint(QStyle::SH_UnderlineShortcut, &option, this)) {
114  title_flags |= Qt::TextHideMnemonic;
115  }
116  p.setFont(font());
117 
118  p.drawItemText(text_rect, title_flags, option.palette, isEnabled(),
119  text(), QPalette::ButtonText);
120 
121  // Draw the timeout text
122  p.setFont(fcFont::instance()->getFont(fonts::default_font));
123  p.drawItemText(
124  text_rect, Qt::AlignHCenter | Qt::AlignBottom | Qt::TextSingleLine,
125  option.palette, isEnabled(), m_timeout_label, QPalette::ButtonText);
126 
127  p.restore();
128  }
129 }
130 
135 QString format_simple_duration(int seconds)
136 {
137  if (seconds < 0) {
138  seconds = 0;
139  }
140 
141  if (seconds < 60) {
142  return QString(Q_("?seconds:%1s")).arg(seconds, 2);
143  } else if (seconds < 5 * 60) { // < 5 minutes
144  return QString(Q_("?mins/secs:%1min %2s"))
145  .arg(seconds / 60, 2)
146  .arg(seconds % 60, 2);
147  } else if (seconds < 3600) { // < one hour
148  // TRANS: Used in "Time left: 10 minutes". Always at least 5 minutes
149  return QString(_("%1 minutes")).arg(seconds / 60);
150  } else {
151  // Hours and minutes
152  const auto minutes = seconds / 60;
153  return QString(_("%1h %2min")).arg(minutes / 60).arg(minutes % 60);
154  }
155 }
156 
162 QString format_duration(int duration)
163 {
164  if (duration < 0) {
165  duration = 0;
166  }
167 
168  const auto now = QDateTime::currentDateTime();
169  const auto turn_change = now.addSecs(duration);
170  const auto days_left = now.daysTo(turn_change);
171 
172  if (duration < 3600) { // < one hour
173  return format_simple_duration(duration);
174  } else if (days_left == 0) { // Same day
175  const auto time =
176  QLocale().toString(turn_change, QStringLiteral("hh:mm"));
177  // TRANS: Used in "Time left: until 17:59", %1 is hours and minutes
178  return QString(_("until %1")).arg(time);
179  } else if (days_left == 1) { // Tomorrow
180  const auto time =
181  QLocale().toString(turn_change, QStringLiteral("hh:mm"));
182  // TRANS: Used in "Time left: until tomorrow 17:59"
183  return QString(_("until tomorrow %1")).arg(time);
184  } else if (days_left < 7) { // This week
185  const auto time =
186  QLocale().toString(turn_change, QStringLiteral("dddd hh:mm"));
187  // TRANS: Used in "Time left: until Monday 17:59"
188  return QString(_("until %1")).arg(time);
189  }
190 
191  // TRANS: Used to indicate a fuzzy duration, always more than 7 days
192  return QString(PL_("%1 day", "%1 days", days_left)).arg(days_left);
193 }
194 
199 {
200  QString tooltip = _("End the current turn");
201 
202  if (is_waiting_turn_change() && game.tinfo.last_turn_change_time >= 1.5) {
203  // TRANS: Processing turn change
204  m_timeout_label = QString(_("Processing... %1"))
206  } else if (current_turn_timeout() > 0) {
207  m_timeout_label = QString(_("Time left: %1"))
209  tooltip += QStringLiteral("\n");
210  // TRANS: Time until turn change in the (). %1 is "5s", "4min", or "6h
211  // 7min".
212  tooltip = QString(_("End the current turn (%1 remaining)"))
214  } else {
215  m_timeout_label = QString();
216  }
217 
218  setToolTip(tooltip);
219 
220  // Redraw
221  update();
222 }
QFont getFont(const QString &name, double zoom=1.0) const
Returns desired font.
Definition: fonts.cpp:57
static fcFont * instance()
Returns instance of fc_font.
Definition: fonts.cpp:34
void paintEvent(QPaintEvent *event) override
Paints the widget.
QSize sizeHint() const override
Returns the size hint for this widget.
void update_timeout_label()
Updates the timeout text according to the current state of the game.
turn_done_button(QWidget *parent=nullptr)
Constructor.
int get_seconds_to_new_turn()
Return the number of seconds until turn-done.
int get_seconds_to_turndone()
Return the number of seconds until turn-done.
bool is_waiting_turn_change()
Are we in turn-change wait state?
enum event_type event
Definition: events.cpp:68
#define Q_(String)
Definition: fcintl.h:53
#define PL_(String1, String2, n)
Definition: fcintl.h:54
#define _(String)
Definition: fcintl.h:50
struct civ_game game
Definition: game.cpp:47
int current_turn_timeout()
Return timeout value for the current turn.
Definition: game.cpp:808
const char *const default_font
Definition: fonts.h:18
Constants used when drawing the button.
size_t size
Definition: specvec.h:64
struct packet_timeout_info tinfo
Definition: game.h:82
The base class for options.
Definition: options.cpp:209
QString format_duration(int duration)
Format the duration until TC, given in seconds, so it comes up in minutes or hours if that would be m...
QString format_simple_duration(int seconds)
Formats a duration without switching to "until hh::mm" when more than one hour in the future.