ManaPlus
charselectdialog.cpp
Go to the documentation of this file.
1 /*
2  * The ManaPlus Client
3  * Copyright (C) 2004-2009 The Mana World Development Team
4  * Copyright (C) 2009-2010 The Mana Developers
5  * Copyright (C) 2011-2018 The ManaPlus Developers
6  *
7  * This file is part of The ManaPlus Client.
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program. If not, see <http://www.gnu.org/licenses/>.
21  */
22 
24 
25 #include "client.h"
26 #include "configuration.h"
27 
30 
33 #include "gui/windows/editdialog.h"
35 #include "gui/windows/okdialog.h"
36 #include "gui/windows/textdialog.h"
37 
38 #include "gui/widgets/button.h"
44 
45 #include "net/character.h"
46 #include "net/charserverhandler.h"
47 #include "net/logindata.h"
48 #ifdef TMWA_SUPPORT
49 #include "net/net.h"
50 #endif // TMWA_SUPPORT
51 #include "net/serverfeatures.h"
52 
53 #include "utils/foreach.h"
54 
55 #include "resources/db/unitsdb.h"
56 
57 #include "debug.h"
58 
59 // Character slots per row in the dialog
60 static const int SLOTS_PER_ROW = 5;
61 
63  // TRANSLATORS: char select dialog name
64  Window(strprintf(_("Account %s (last login time %s)"),
65  data.username.c_str(), data.lastLogin.c_str()),
67  nullptr,
68  "char.xml"),
70  KeyListener(),
71  mLoginData(&data),
72  // TRANSLATORS: char select dialog. button.
73  mSwitchLoginButton(new Button(this, _("Switch"), "switch", this)),
74  // TRANSLATORS: char select dialog. button.
75  mChangePasswordButton(new Button(this, _("Password"),
76  "change_password", this)),
77  // TRANSLATORS: char select dialog. button.
78  mPlayButton(new Button(this, _("Play"), "use", this)),
79  // TRANSLATORS: char select dialog. button.
80  mInfoButton(new Button(this, _("Info"), "info", this)),
81  // TRANSLATORS: char select dialog. button.
82  mDeleteButton(new Button(this, _("Delete"), "delete", this)),
83  // TRANSLATORS: char select dialog. button.
84  mRenameButton(nullptr),
85  mCharacterView(nullptr),
86  mCharacterEntries(0),
87  mCharServerHandler(charServerHandler),
88  mDeleteDialog(nullptr),
89  mDeleteIndex(-1),
90  mLocked(false),
91  mSmallScreen(mainGraphics->getWidth() < 470
92  || mainGraphics->getHeight() < 370)
93 {
94  setCloseButton(true);
95  setFocusable(true);
96 
97  ContainerPlacer placer(nullptr, nullptr);
98  placer = getPlacer(0, 0);
99 
100  placer(0, 0, mSwitchLoginButton, 1, 1);
101 
102  int n = 1;
103  placer(n, 0, mChangePasswordButton, 1, 1);
104  n ++;
105  placer(n, 0, mDeleteButton, 1, 1);
106  n ++;
107 #ifdef TMWA_SUPPORT
109 #endif
110  {
111  mRenameButton = new Button(this,
112  // TRANSLATORS: character rename button
113  _("Rename"),
114  "rename",
115  this);
116  placer(n, 0, mRenameButton, 1, 1);
117  n ++;
118  }
119  placer(n, 0, mInfoButton, 1, 1);
120  n ++;
121 
122  for (int i = 0; i < CAST_S32(mLoginData->characterSlots); i++)
123  {
124  CharacterDisplay *const character = new CharacterDisplay(this, this);
125  character->setVisible(Visible_false);
126  mCharacterEntries.push_back(character);
127  }
128 
129  placer(0, 2, mPlayButton, 1, 1);
130 
131  if (!mSmallScreen)
132  {
134  this, &mCharacterEntries, mPadding);
135  placer(0, 1, mCharacterView, 10, 1);
136  int sz = 410 + 2 * mPadding;
137  if (config.getIntValue("fontSize") > 18)
138  sz = 500 + 2 * mPadding;
139  const int width = mCharacterView->getWidth() + 2 * mPadding;
140  if (sz < width)
141  sz = width;
142  if (sz > mainGraphics->getWidth())
143  sz = mainGraphics->getWidth();
144  reflowLayout(sz, 0);
145  }
146  else
147  {
148  // TRANSLATORS: char select dialog name
149  setCaption(strprintf(_("Account %s"), mLoginData->username.c_str()));
151  this, &mCharacterEntries, mPadding);
153  - 2 * getPadding());
154  placer(0, 1, mCharacterView, 10, 1);
155  reflowLayout(0, 0);
156  }
157  addKeyListener(this);
158  center();
159 
161  mCharacterView->show(0);
162  updateState();
163 }
164 
166 {
167 }
168 
170 {
173  requestFocus();
175  {
176  EditDialog *const dialog = CREATEWIDGETR(EditDialog,
177  // TRANSLATORS: pin code dialog header.
178  _("Please set new pincode"),
179  "",
180  "OK",
181  300,
182  nullptr,
183  Modal_true);
185  }
186 }
187 
189 {
190  // Check if a button of a character was pressed
191  const Widget *const sourceParent = event.getSource()->getParent();
192  int selected = -1;
193  for (unsigned int i = 0, fsz = CAST_U32(
194  mCharacterEntries.size());
195  i < fsz;
196  ++i)
197  {
198  if (mCharacterEntries[i] == sourceParent)
199  {
200  selected = i;
201  mCharacterView->show(i);
202  updateState();
203  break;
204  }
205  }
206  if (selected == -1)
207  selected = mCharacterView->getSelected();
208 
209  const std::string &eventId = event.getId();
210 
211  if (selected >= 0)
212  {
213  if (eventId == "use")
214  {
215  use(selected);
216  return;
217  }
218  else if (eventId == "delete"
219  && (mCharacterEntries[selected]->getCharacter() != nullptr))
220  {
221  CREATEWIDGET(CharDeleteConfirm, this, selected);
222  return;
223  }
224  else if (eventId == "rename"
225  && (mCharacterEntries[selected]->getCharacter() != nullptr))
226  {
227  const LocalPlayer *const player = mCharacterEntries[
228  selected]->getCharacter()->dummy;
229  EditDialog *const dialog = CREATEWIDGETR(EditDialog,
230  // TRANSLATORS: character rename dialog header.
231  _("Please enter new name"),
232  player->getName(),
233  "OK",
234  300,
235  nullptr,
236  Modal_true);
237  charRenameListener.setId(player->getId());
240  }
241  else if (eventId == "info")
242  {
243  Net::Character *const character = mCharacterEntries[
244  selected]->getCharacter();
245  if (character == nullptr)
246  return;
247 
248  const LocalPlayer *const data = character->dummy;
249  if (data == nullptr)
250  return;
251 
252  const std::string strExp = toString(CAST_U64(
254  const std::string msg = strprintf(
255  // TRANSLATORS: char select dialog. player info message.
256  _("Hp: %u/%u\nMp: %u/%u\nLevel: %u\n"
257  "Experience: %s\nMoney: %s"),
258  CAST_U32(
260  CAST_U32(
262  CAST_U32(
264  CAST_U32(
266  CAST_U32(
268  strExp.c_str(),
270  character->data.mAttributes[Attributes::MONEY])).c_str());
271  CREATEWIDGET(OkDialog, data->getName(), msg,
272  // TRANSLATORS: ok dialog button
273  _("OK"),
275  Modal_true,
277  nullptr,
278  260);
279  }
280  }
281  if (eventId == "switch")
282  {
284  close();
285  }
286  else if (eventId == "change_password")
287  {
289  }
290  else if (eventId == "change_email")
291  {
293  }
294  else if (eventId == "try delete character")
295  {
296  if ((mDeleteDialog != nullptr) && mDeleteIndex != -1)
297  {
299  {
301  mDeleteDialog = nullptr;
302  }
304  {
306  mDeleteDialog = nullptr;
307  }
308  else
309  {
311  // TRANSLATORS: error header
312  _("Error"),
313  // TRANSLATORS: error message
314  _("Incorrect password"),
315  // TRANSLATORS: ok dialog button
316  _("OK"),
318  Modal_true,
320  nullptr,
321  260);
322  }
323  }
324  mDeleteIndex = -1;
325  }
326 }
327 
328 void CharSelectDialog::use(const int selected)
329 {
330  if ((mCharacterEntries[selected] != nullptr)
331  && (mCharacterEntries[selected]->getCharacter() != nullptr))
332  {
333  attemptCharacterSelect(selected);
334  }
335  else
336  {
337  CharCreateDialog *const charCreateDialog =
338  CREATEWIDGETR(CharCreateDialog, this, selected);
339  mCharServerHandler->setCharCreateDialog(charCreateDialog);
340  }
341 }
342 
344 {
345  const InputActionT actionId = event.getActionId();
346  PRAGMA45(GCC diagnostic push)
347  PRAGMA45(GCC diagnostic ignored "-Wswitch-enum")
348  switch (actionId)
349  {
351  event.consume();
354  break;
355 
357  {
358  event.consume();
359  int idx = mCharacterView->getSelected();
360  if (idx >= 0)
361  {
362  idx ++;
363  if (idx == SLOTS_PER_ROW)
364  break;
365  mCharacterView->show(idx);
366  updateState();
367  }
368  break;
369  }
370 
372  {
373  event.consume();
374  int idx = mCharacterView->getSelected();
375  if (idx >= 0)
376  {
377  if ((idx == 0) || idx == SLOTS_PER_ROW)
378  break;
379  idx --;
380  mCharacterView->show(idx);
381  updateState();
382  }
383  break;
384  }
385 
386  case InputAction::GUI_UP:
387  {
388  event.consume();
389  int idx = mCharacterView->getSelected();
390  if (idx >= 0)
391  {
392  if (idx < SLOTS_PER_ROW)
393  break;
394  idx -= SLOTS_PER_ROW;
395  mCharacterView->show(idx);
396  updateState();
397  }
398  break;
399  }
400 
402  {
403  event.consume();
404  int idx = mCharacterView->getSelected();
405  if (idx >= 0)
406  {
407  if (idx >= SLOTS_PER_ROW)
408  break;
409  idx += SLOTS_PER_ROW;
410  mCharacterView->show(idx);
411  updateState();
412  }
413  break;
414  }
415 
417  {
418  event.consume();
419  const int idx = mCharacterView->getSelected();
420  if (idx >= 0 && (mCharacterEntries[idx] != nullptr)
421  && (mCharacterEntries[idx]->getCharacter() != nullptr))
422  {
423  CREATEWIDGET(CharDeleteConfirm, this, idx);
424  }
425  break;
426  }
427 
429  {
430  event.consume();
432  break;
433  }
434  default:
435  break;
436  }
437  PRAGMA45(GCC diagnostic pop)
438 }
439 
444  const std::string &email)
445 {
446  if (mLocked)
447  return;
448 
449  if (mCharacterEntries[index] != nullptr)
450  {
452  mCharacterEntries[index]->getCharacter(),
453  email);
454  }
455  lock();
456 }
457 
459 {
460  mDeleteIndex = index;
462  {
464  // TRANSLATORS: char deletion question.
465  _("Enter your email for deleting character"),
466  // TRANSLATORS: email label.
467  _("Enter email:"),
468  this,
469  false);
470  }
471  else
472  {
474  // TRANSLATORS: char deletion question.
475  _("Enter password for deleting character"),
476  // TRANSLATORS: email label.
477  _("Enter password:"),
478  this,
479  true);
480  }
481  mDeleteDialog->setActionEventId("try delete character");
483 }
484 
489 {
490  if (mLocked || (mCharacterEntries[index] == nullptr))
491  return;
492 
494  if (mCharServerHandler != nullptr)
495  {
497  mCharacterEntries[index]->getCharacter());
498  }
499  lock();
500 }
501 
503 {
504  // Reset previous characters
505  FOR_EACH (STD_VECTOR<CharacterDisplay*>::const_iterator,
506  iter, mCharacterEntries)
507  {
508  if (*iter != nullptr)
509  (*iter)->setCharacter(nullptr);
510  }
511 
512  FOR_EACH (Net::Characters::const_iterator, i, characters)
513  setCharacter(*i);
514  updateState();
515 }
516 
518 {
519  if (character == nullptr)
520  return;
521  const int characterSlot = character->slot;
522  if (characterSlot >= CAST_S32(mCharacterEntries.size()))
523  {
524  logger->log("Warning: slot out of range: %d", character->slot);
525  return;
526  }
527 
528  if (mCharacterEntries[characterSlot] != nullptr)
529  mCharacterEntries[characterSlot]->setCharacter(character);
530 }
531 
533 {
534  if (!mLocked)
535  setLocked(true);
536 }
537 
539 {
540  setLocked(false);
541 }
542 
543 void CharSelectDialog::setLocked(const bool locked)
544 {
545  mLocked = locked;
546 
547  if (mSwitchLoginButton != nullptr)
548  mSwitchLoginButton->setEnabled(!locked);
549  if (mChangePasswordButton != nullptr)
551  mPlayButton->setEnabled(!locked);
552  if (mDeleteButton != nullptr)
553  mDeleteButton->setEnabled(!locked);
554 
555  for (size_t i = 0, sz = mCharacterEntries.size(); i < sz; ++i)
556  {
557  if (mCharacterEntries[i] != nullptr)
558  mCharacterEntries[i]->setActive(!mLocked);
559  }
560 }
561 
562 bool CharSelectDialog::selectByName(const std::string &name,
563  const SelectAction selAction)
564 {
565  if (mLocked)
566  return false;
567 
568  for (size_t i = 0, sz = mCharacterEntries.size(); i < sz; ++i)
569  {
570  if (mCharacterEntries[i] != nullptr)
571  {
572  const Net::Character *const character
573  = mCharacterEntries[i]->getCharacter();
574  if (character != nullptr)
575  {
576  if (character->dummy != nullptr &&
577  character->dummy->getName() == name)
578  {
580  updateState();
581  if (selAction == Choose)
583  return true;
584  }
585  }
586  }
587  }
588 
589  return false;
590 }
591 
593 {
595  Window::close();
596 }
597 
599 {
600  Window::widgetResized(event);
602 }
603 
605 {
606  const int idx = mCharacterView->getSelected();
607  if (idx == -1)
608  {
609  mPlayButton->setEnabled(false);
610  return;
611  }
612  mPlayButton->setEnabled(true);
613 
614  if (mCharacterEntries[idx] != nullptr &&
615  mCharacterEntries[idx]->getCharacter() != nullptr)
616  {
617  // TRANSLATORS: char select dialog. button.
618  mPlayButton->setCaption(_("Play"));
619 
620  const LocalPlayer *const player = mCharacterEntries[
621  idx]->getCharacter()->dummy;
622  if ((player != nullptr) && (mRenameButton != nullptr))
623  mRenameButton->setEnabled(player->getRename() ? true : false);
624  }
625  else
626  {
627  // TRANSLATORS: char select dialog. button.
628  mPlayButton->setCaption(_("Create"));
629  }
630 }
631 
632 void CharSelectDialog::setName(const BeingId id, const std::string &newName)
633 {
634  for (unsigned int i = 0, fsz = CAST_U32(
635  mCharacterEntries.size());
636  i < fsz;
637  ++i)
638  {
639  if (mCharacterEntries[i] == nullptr)
640  continue;
641  CharacterDisplay *const character = mCharacterEntries[i];
642  if (character == nullptr)
643  continue;
644  LocalPlayer *const player = character->getCharacter()->dummy;
645  if ((player != nullptr) && player->getId() == id)
646  {
647  player->setName(newName);
648  character->update();
649  return;
650  }
651  }
652 }
uint16_t characterSlots
Definition: logindata.h:76
#define CAST_U32
Definition: cast.h:30
#define FOR_EACH(type, iter, array)
Definition: foreach.h:24
CharSelectDialog(LoginData &data)
#define _(s)
Definition: gettext.h:34
TextDialog * mDeleteDialog
int getWidth() const
Definition: widget.h:220
Button * mSwitchLoginButton
void setWidth(const int width)
Definition: widget.cpp:132
int mPadding
Definition: window.h:617
void setState(const StateT state)
Definition: client.h:65
const bool Visible_true
Definition: visible.h:29
PRAGMA45(GCC diagnostic push) PRAGMA45(GCC diagnostic ignored "-Wunused-result") int TestLauncher
void addActionListener(ActionListener *const actionListener)
Definition: widget.cpp:251
void setVisible(Visible visible)
Definition: widget.cpp:224
BeingId getId() const
Definition: actorsprite.h:63
bool getRename() const
Definition: localplayer.h:421
#define CAST_U64
Definition: cast.h:32
virtual void show(const int i)=0
Definition: window.h:98
Definition: button.h:94
Configuration config
int BeingId
Definition: beingid.h:29
virtual void setCharCreateDialog(CharCreateDialog *const window) const =0
void setId(const BeingId id)
std::string formatCurrency(const int value)
Definition: unitsdb.cpp:323
bool msg(InputEvent &event)
Definition: chat.cpp:38
int getIntValue(const std::string &key) const
const std::string & getActionEventId() const
Definition: widget.h:604
void setActionEventId(const std::string &actionEventId)
Definition: widget.h:595
Client * client
Definition: client.cpp:113
#define CREATEWIDGETV(var, type,...)
Definition: createwidget.h:24
Button * mChangePasswordButton
int getWidth() const
Definition: graphics.cpp:642
virtual void resize()=0
virtual void clear() const =0
void action(const ActionEvent &event)
Logger * logger
Definition: logger.cpp:95
virtual void setCharSelectDialog(CharSelectDialog *const window) const =0
virtual void close()
Definition: window.cpp:897
#define new
Definition: debug_new.h:147
bool selectByName(const std::string &name, const SelectAction action)
void setDialog(EditDialog *const dialog)
void widgetResized(const Event &event)
Definition: window.cpp:650
Net::ServerFeatures * serverFeatures
Definition: net.cpp:94
void setCaption(const std::string &caption)
Definition: button.h:214
const std::string & getText() const
Definition: textdialog.cpp:119
#define CAST_S32
Definition: cast.h:29
virtual bool isNeedCreatePin() const =0
virtual void requestFocus()
Definition: widget.cpp:203
std::string strprintf(const char *const format,...)
Definition: stringutils.cpp:99
uint16_t slot
Definition: character.h:57
const bool Visible_false
Definition: visible.h:29
std::list< Character * > Characters
Definition: character.h:60
uint32_t data
Net::Character * getCharacter() const
virtual void deleteCharacter(Net::Character *const character, const std::string &email) const =0
std::string username
Definition: logindata.h:58
CharRenameListener charRenameListener
AtrIntMap mAttributes
Definition: playerinfo.h:72
InputAction ::T InputActionT
Definition: inputaction.h:714
#define nullptr
Definition: localconsts.h:44
Graphics * mainGraphics
Definition: graphics.cpp:108
const bool ShowCenter_true
Definition: showcenter.h:29
void attemptCharacterSelect(const int index)
void setCloseButton(const bool flag)
Definition: window.cpp:744
static std::string savedPassword
Definition: logindialog.h:79
void addKeyListener(KeyListener *const keyListener)
Definition: widget.cpp:271
void use(const int selected)
const std::string & getName() const
Definition: being.h:231
ContainerPlacer getPlacer(const int x, const int y)
Definition: window.cpp:1386
void setEnabled(const bool enabled)
Definition: widget.h:351
int getSelected() const
void attemptCharacterDelete(const int index, const std::string &email)
void keyPressed(KeyEvent &event)
void setCharacters(const Net::Characters &characters)
ServerTypeT getNetworkType()
Definition: net.cpp:178
Widget * getParent() const
Definition: widget.h:201
void setName(const BeingId id, const std::string &newName)
std::string toString(T const &value)
converts any type to a string
Definition: catch.hpp:1774
void setFocusable(const bool focusable)
Definition: widget.cpp:191
virtual void setVisible(Visible visible)
Definition: window.cpp:773
void center()
Definition: window.cpp:1412
#define CREATEWIDGET(type,...)
Definition: createwidget.h:28
LoginData * mLoginData
Definition: widget.h:97
PincodeListener pincodeListener
void askPasswordForDeletion(const int index)
Definition: event.h:77
void setName(const std::string &name)
Definition: being.cpp:1134
std::vector< CharacterDisplay * > mCharacterEntries
void setCharacter(Net::Character *const character)
CharacterViewBase * mCharacterView
void widgetResized(const Event &event)
PlayerInfoBackend data
Definition: character.h:56
#define CREATEWIDGETR(type,...)
Definition: createwidget.h:35
void log(const char *const log_text,...)
Definition: logger.cpp:243
virtual void chooseCharacter(Net::Character *const character) const =0
Net::CharServerHandler * mCharServerHandler
void setCaption(const std::string &caption)
Definition: window.h:530
virtual bool haveEmailOnDelete() const =0
Net::CharServerHandler * charServerHandler
Definition: net.cpp:79
LocalPlayer * dummy
Definition: character.h:55
int getPadding() const
Definition: window.h:503
static const int SLOTS_PER_ROW
void setLocked(const bool locked)
void reflowLayout(int w, int h)
Definition: window.cpp:1391
void postInit()
Definition: window.cpp:248