OpenClonk
C4StartupMainDlg.cpp
Go to the documentation of this file.
1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 2005-2009, RedWolf Design GmbH, http://www.clonk.de/
5  * Copyright (c) 2009-2016, The OpenClonk Team and contributors
6  *
7  * Distributed under the terms of the ISC license; see accompanying file
8  * "COPYING" for details.
9  *
10  * "Clonk" is a registered trademark of Matthes Bender, used with permission.
11  * See accompanying file "TRADEMARK" for details.
12  *
13  * To redistribute this file separately, substitute the full license texts
14  * for the above references.
15  */
16 // Startup screen for non-parameterized engine start (stub)
17 
18 #include "C4Include.h"
19 #include "gui/C4StartupMainDlg.h"
20 
21 #include "C4Version.h"
22 #include "c4group/C4Components.h"
23 #include "game/C4Application.h"
24 #include "graphics/C4Draw.h"
26 #include "gui/C4Startup.h"
27 #include "gui/C4StartupAboutDlg.h"
28 #include "gui/C4StartupNetDlg.h"
29 #include "gui/C4StartupModsDlg.h"
31 #include "gui/C4StartupPlrSelDlg.h"
33 #include "gui/C4UpdateDlg.h"
34 
35 #ifdef _WIN32
36 #include <shellapi.h>
37 #endif
38 
39 
40 C4StartupMainDlg::C4StartupMainDlg() : C4StartupDlg(nullptr) // create w/o title; it is drawn in custom draw proc
41 {
42  // ctor
43  fFirstShown = true;
44  // screen calculations
45  int iButtonPadding = 2;
46  int iButtonHeight = C4GUI_BigButtonHgt;
47  C4GUI::ComponentAligner caMain(rcBounds, 0,0,true);
48  C4GUI::ComponentAligner caRightPanel(caMain.GetFromLeft(rcBounds.Wdt*2/5), rcBounds.Wdt/26, 40+rcBounds.Hgt/5);
49  C4GUI::ComponentAligner caButtons(caRightPanel.GetAll(), 0, iButtonPadding);
50  // main menu buttons
52  AddElement(btn = new C4GUI::CallbackButton<C4StartupMainDlg>(LoadResStr("IDS_BTN_LOCALGAME"), caButtons.GetFromTop(iButtonHeight), &C4StartupMainDlg::OnStartBtn));
53  btn->SetToolTip(LoadResStr("IDS_DLGTIP_STARTGAME"));
54  btn->SetCustomGraphics(&C4Startup::Get()->Graphics.barMainButtons, &C4Startup::Get()->Graphics.barMainButtonsDown);
55  pStartButton = btn;
56  AddElement(btn = new C4GUI::CallbackButton<C4StartupMainDlg>(LoadResStr("IDS_BTN_NETWORKGAME"), caButtons.GetFromTop(iButtonHeight), &C4StartupMainDlg::OnNetJoinBtn));
57  btn->SetToolTip(LoadResStr("IDS_DLGTIP_NETWORKGAME"));
58  btn->SetCustomGraphics(&C4Startup::Get()->Graphics.barMainButtons, &C4Startup::Get()->Graphics.barMainButtonsDown);
59  AddElement(btn = new C4GUI::CallbackButton<C4StartupMainDlg>(LoadResStr("IDS_DLG_PLAYERSELECTION"), caButtons.GetFromTop(iButtonHeight), &C4StartupMainDlg::OnPlayerSelectionBtn));
60  btn->SetToolTip(LoadResStr("IDS_DLGTIP_PLAYERSELECTION"));
61  btn->SetCustomGraphics(&C4Startup::Get()->Graphics.barMainButtons, &C4Startup::Get()->Graphics.barMainButtonsDown);
62  AddElement(btn = new C4GUI::CallbackButton<C4StartupMainDlg>(LoadResStr("IDS_DLG_OPTIONS"), caButtons.GetFromTop(iButtonHeight), &C4StartupMainDlg::OnOptionsBtn));
63  btn->SetToolTip(LoadResStr("IDS_DLGTIP_OPTIONS"));
64  btn->SetCustomGraphics(&C4Startup::Get()->Graphics.barMainButtons, &C4Startup::Get()->Graphics.barMainButtonsDown);
65 #ifdef WITH_QT_EDITOR
66  AddElement(btn = new C4GUI::CallbackButton<C4StartupMainDlg>(LoadResStr("IDS_DLG_EDITOR"), caButtons.GetFromTop(iButtonHeight), &C4StartupMainDlg::OnEditorBtn));
67  btn->SetToolTip(LoadResStr("IDS_DLGTIP_EDITOR"));
68  btn->SetCustomGraphics(&C4Startup::Get()->Graphics.barMainButtons, &C4Startup::Get()->Graphics.barMainButtonsDown);
69 #endif
70  AddElement(btn = new C4GUI::CallbackButton<C4StartupMainDlg>(LoadResStr("IDS_DLG_MODS"), caButtons.GetFromTop(iButtonHeight), &C4StartupMainDlg::OnModsBtn));
71  btn->SetToolTip(LoadResStr("IDS_DLGTIP_MODS"));
72  btn->SetCustomGraphics(&C4Startup::Get()->Graphics.barMainButtons, &C4Startup::Get()->Graphics.barMainButtonsDown);
73  AddElement(btn = new C4GUI::CallbackButton<C4StartupMainDlg>(LoadResStr("IDS_DLG_ABOUT"), caButtons.GetFromTop(iButtonHeight), &C4StartupMainDlg::OnAboutBtn));
74  btn->SetToolTip(LoadResStr("IDS_DLGTIP_ABOUT"));
75  btn->SetCustomGraphics(&C4Startup::Get()->Graphics.barMainButtons, &C4Startup::Get()->Graphics.barMainButtonsDown);
76  AddElement(btn = new C4GUI::CallbackButton<C4StartupMainDlg>(LoadResStr("IDS_DLG_EXIT"), caButtons.GetFromTop(iButtonHeight), &C4StartupMainDlg::OnExitBtn));
77  btn->SetToolTip(LoadResStr("IDS_DLGTIP_EXIT"));
78  btn->SetCustomGraphics(&C4Startup::Get()->Graphics.barMainButtons, &C4Startup::Get()->Graphics.barMainButtonsDown);
79  // list of selected players
80  AddElement(pParticipantsLbl = new C4GUI::Label("test", GetClientRect().Wdt*39/40, GetClientRect().Hgt*9/10, ARight, 0xffffffff, &::GraphicsResource.TitleFont, false));
81  pParticipantsLbl->SetToolTip(LoadResStr("IDS_DLGTIP_SELECTEDPLAYERS"));
82  // player selection shortcut - to be made optional
85  // key bindings
87  keys.emplace_back(K_DOWN); keys.emplace_back(K_RIGHT);
89  {
90  ControllerKeys::Down(keys); // right will be done by Dialog already
91  }
92  pKeyDown = new C4KeyBinding(keys, "StartupMainCtrlNext", KEYSCOPE_Gui,
94  keys.clear(); keys.emplace_back(K_UP); keys.emplace_back(K_LEFT);
96  {
97  ControllerKeys::Up(keys); // left will be done by Dialog already
98  }
99  pKeyUp = new C4KeyBinding(keys, "StartupMainCtrlPrev", KEYSCOPE_Gui,
101  keys.clear(); keys.emplace_back(K_RETURN);
102  pKeyEnter = new C4KeyBinding(keys, "StartupMainOK", KEYSCOPE_Gui,
104 }
105 
107 {
108  // dtor
109  delete pKeyEnter;
110  delete pKeyUp;
111  delete pKeyDown;
112 }
113 
115 {
116  // inherited
117  typedef C4GUI::FullscreenDialog Base;
118  Base::DrawElement(cgo);
119  // draw logo
120  C4FacetID * fctStartupLogo = &C4Startup::Get()->Graphics.fctStartupLogo;
121  float fLogoZoom = 1.0f;
122  fctStartupLogo->DrawX(cgo.Surface, rcBounds.Wdt *1/21, rcBounds.Hgt/28, int32_t(fLogoZoom*fctStartupLogo->Wdt), int32_t(fLogoZoom*fctStartupLogo->Hgt));
123  // draw version info
124  StdStrBuf sVer;
125  sVer.Format(LoadResStr("IDS_DLG_VERSION"), C4VERSION);
126  pDraw->TextOut(sVer.getData(), ::GraphicsResource.TextFont, 1.0f, cgo.Surface, rcBounds.Wdt*1/40, rcBounds.Hgt*38/40, 0xffffffff, ALeft, true);
127 }
128 
130 {
131  // preliminary player selection via simple context menu
134  pCtx->AddItem("Remove", "Remove participant", C4GUI::Ico_None, nullptr, new C4GUI::CBContextHandler<C4StartupMainDlg>(this, &C4StartupMainDlg::OnPlayerSelContextRemove));
135  return pCtx;
136 }
137 
139 {
141  const char *szFn;
142  StdStrBuf sSearchPath(Config.General.UserDataPath);
143 // sSearchPath.Format("%s%s", (const char *) Config.General.ExePath, (const char *) Config.General.PlayerPath);
144  for (DirectoryIterator i(sSearchPath.getData()); (szFn=*i); i++)
145  {
146  szFn = Config.AtRelativePath(szFn);
147  if (*GetFilename(szFn) == '.') continue;
148  if (!WildcardMatch(C4CFN_PlayerFiles, GetFilename(szFn))) continue;
149  if (!SIsModule(Config.General.Participants, szFn, nullptr, false))
150  pCtx->AddItem(GetFilenameOnly(szFn), "Let this player join in next game", C4GUI::Ico_Player,
152  }
153  return pCtx;
154 }
155 
157 {
159  char szPlayer[1024+1];
160  for (int i = 0; SCopySegment(Config.General.Participants, i, szPlayer, ';', 1024, true); i++)
161  if (*szPlayer)
162  pCtx->AddItem(GetFilenameOnly(szPlayer), "Remove this player from participation list", C4GUI::Ico_Player, new C4GUI::CBMenuHandlerEx<C4StartupMainDlg, int>(this, &C4StartupMainDlg::OnPlayerSelContextRemovePlr, i), nullptr);
163  return pCtx;
164 }
165 
167 {
168  // De-select all other players for now (see #1529)
169  SCopy(rsFilename.getData(), Config.General.Participants);
170  //SAddModule(Config.General.Participants, rsFilename.getData());
172 }
173 
175 {
176  char szPlayer[1024+1];
177  if (SCopySegment(Config.General.Participants, iIndex, szPlayer, ';', 1024, true))
178  SRemoveModule(Config.General.Participants, szPlayer, false);
180 }
181 
183 {
184  // First validate all participants (files must exist)
185  std::string strPlayers(Config.General.Participants);
186  std::vector<char> strPlayer(1025);
188  for (int i = 0; SCopySegment(strPlayers.c_str(), i, &strPlayer[0], ';', strPlayer.size() - 1, true); i++)
189  {
190  const char *szPlayer = &strPlayer[0];
191  std::string strPlayerFile(Config.General.UserDataPath);
192  strPlayerFile.append(szPlayer);
193  if (!szPlayer || !*szPlayer) continue;
194  if (!FileExists(strPlayerFile.c_str())) continue;
195  if (!SEqualNoCase(GetExtension(szPlayer), "ocp")) continue; // additional sanity check to clear strange exe-path-only entries in player list?
197  }
198  // Draw selected players - we are currently displaying the players stored in Config.General.Participants.
199  // Existence of the player files is not validated and player filenames are displayed directly
200  // (names are not loaded from the player core).
201  strPlayers = LoadResStr("IDS_DESC_PLRS");
202  if (!Config.General.Participants[0])
203  strPlayers.append(LoadResStr("IDS_DLG_NOPLAYERSSELECTED"));
204  else
205  for (int i = 0; SCopySegment(Config.General.Participants, i, &strPlayer[0], ';', 1024, true); i++)
206  {
207  if (i > 0) strPlayers.append(", ");
208  strPlayers.append(GetFilenameOnly(&strPlayer[0]));
209  }
210  pParticipantsLbl->SetText(strPlayers.c_str());
211 }
212 
214 {
215  // if dlg got aborted (by user), quit startup
216  // if it got closed with OK, the user pressed one of the buttons and dialog switching has been done already
217  if (!fOK) Application.Quit();
218 }
219 
221 {
222  // advance to scenario selection screen
224 }
225 
227 {
228  // advance to player selection screen
230 }
231 
233 {
234  // advanced net join and host dlg!
236 }
237 
238 void C4StartupMainDlg::OnNetJoin(const StdStrBuf &rsHostAddress)
239 {
240  // no IP given: No join
241  if (!rsHostAddress || !*rsHostAddress.getData()) return;
242  // set default startup parameters
244  SCopy("Objects.ocd", Game.DefinitionFilenames);
245  Game.NetworkActive = true;
246  Game.fLobby = true;
247  Game.fObserve = false;
248  SCopy(rsHostAddress.getData(), Game.DirectJoinAddress, sizeof(Game.DirectJoinAddress)-1);
249  // start with this set!
251 }
252 
254 {
255  // launch mod manachement dialogue.
257 }
258 
260 {
261  // advance to options screen
263 }
264 
266 {
267  if (!RestartApplication({"--editor"}))
268  {
269  C4GUI::TheScreen.ShowErrorMessage(LoadResStr("IDS_ERR_STARTEDITOR"));
270  }
271 }
272 
274 {
275  // advance to about screen
277 }
278 
280 {
281  // callback: exit button pressed
282  Application.Quit();
283 }
284 
286 {
287  GetScreen()->ShowMessage("not yet implemented", "2do", C4GUI::Ico_Error);
288 }
289 
291 {
292  // just execute selected button: Re-Send as space
293  return Game.DoKeyboardInput(K_SPACE, KEYEV_Down, false, false, false, false, this);
294 }
295 
297 {
298  // just execute selected button: Re-Send as space
299  return Game.DoKeyboardInput(K_SPACE, KEYEV_Up, false, false, false, false, this);
300 }
301 
303 {
304 #ifdef WITH_AUTOMATIC_UPDATE
305  // Incoming update
306  if (!Application.IncomingUpdate.empty())
307  {
308  C4UpdateDlg::ApplyUpdate(Application.IncomingUpdate.c_str(), false, GetScreen());
309  Application.IncomingUpdate.clear();
310  }
311  // Manual update by command line or url
313  {
314  C4UpdateDlg::CheckForUpdates(GetScreen(), false);
316  }
317  // Automatic update
318  else
319  {
320  if (Config.Network.AutomaticUpdate)
321  C4UpdateDlg::CheckForUpdates(GetScreen(), true);
322  }
323 #endif
324 
325  // first start evaluation
327  {
328  Config.General.FirstStart = false;
329  }
330  // first thing that's needed is a new player, if there's none - independent of first start
331  bool fHasPlayer = false;
332  StdStrBuf sSearchPath(Config.General.UserDataPath);
333  const char *szFn;
334 // sSearchPath.Format("%s%s", (const char *) Config.General.ExePath, (const char *) Config.General.PlayerPath);
335  for (DirectoryIterator i(sSearchPath.getData()); (szFn=*i); i++)
336  {
337  szFn = Config.AtRelativePath(szFn);
338  if (*GetFilename(szFn) == '.') continue; // ignore ".", ".." and private files (".*")
339  if (!WildcardMatch(C4CFN_PlayerFiles, GetFilename(szFn))) continue;
340  fHasPlayer = true;
341  break;
342  }
343  if (!fHasPlayer)
344  {
345  // no player created yet: Create one
346  C4GUI::Dialog *pDlg;
347  GetScreen()->ShowModalDlg(pDlg=new C4StartupPlrPropertiesDlg(nullptr, nullptr), true);
348  }
349  // make sure participants are updated after switching back from player selection
351 
352  // First show
353  if (fFirstShown)
354  {
355  // Activate the application (trying to prevent flickering half-focus in win32...)
357  // Set the focus to the start button (we might still not have the focus after the update-check sometimes... :/)
358  SetFocus(pStartButton, false);
359  }
360  fFirstShown = false;
361 }
#define C4CFN_PlayerFiles
Definition: C4Components.h:168
C4Config Config
Definition: C4Config.cpp:930
C4Draw * pDraw
Definition: C4Draw.cpp:42
C4Game Game
Definition: C4Globals.cpp:52
C4Application Application
Definition: C4Globals.cpp:44
C4GraphicsResource GraphicsResource
#define C4GUI_BigButtonHgt
Definition: C4Gui.h:112
@ KEYSCOPE_Gui
@ KEYEV_Up
@ KEYEV_Down
const char * LoadResStr(const char *id)
Definition: C4Language.h:83
const int ARight
Definition: C4Surface.h:41
const int ALeft
Definition: C4Surface.h:41
bool RestartApplication(std::vector< const char * > parameters)
bool SIsModule(const char *szList, const char *szString, int *ipIndex, bool fCaseSensitive)
Definition: Standard.cpp:547
bool SCopySegment(const char *szString, int iSegment, char *sTarget, char cSeparator, int iMaxL, bool fSkipWhitespace)
Definition: Standard.cpp:279
void SCopy(const char *szSource, char *sTarget, size_t iMaxL)
Definition: Standard.cpp:152
bool SRemoveModule(char *szList, const char *szModule, bool fCaseSensitive)
Definition: Standard.cpp:588
bool SEqualNoCase(const char *szStr1, const char *szStr2, int iLen)
Definition: Standard.cpp:213
bool SAddModule(char *szList, const char *szModule, bool fCaseSensitive)
Definition: Standard.cpp:563
char * GetExtension(char *szFilename)
Definition: StdFile.cpp:118
bool WildcardMatch(const char *szWildcard, const char *szString)
Definition: StdFile.cpp:396
const char * GetFilenameOnly(const char *strFilename)
Definition: StdFile.cpp:57
char * GetFilename(char *szPath)
Definition: StdFile.cpp:42
bool FileExists(const char *szFileName)
std::string IncomingUpdate
Definition: C4Application.h:78
void OpenGame(const char *scenario=nullptr)
void Quit() override
int32_t GamepadGuiControl
Definition: C4Config.h:233
char Participants[CFG_MaxString+1]
Definition: C4Config.h:39
char UserDataPath[CFG_MaxString+1]
Definition: C4Config.h:56
bool FirstStart
Definition: C4Config.h:62
C4ConfigGeneral General
Definition: C4Config.h:255
C4ConfigNetwork Network
Definition: C4Config.h:259
const char * AtRelativePath(const char *filename)
Definition: C4Config.cpp:741
C4ConfigControls Controls
Definition: C4Config.h:263
std::vector< C4KeyCodeEx > CodeList
bool TextOut(const char *szText, CStdFont &rFont, float fZoom, C4Surface *sfcDest, float iTx, float iTy, DWORD dwFCol=0xffffffff, BYTE byForm=ALeft, bool fDoMarkup=true)
Definition: C4Draw.cpp:561
C4Surface * Surface
Definition: C4Facet.h:117
float Hgt
Definition: C4Facet.h:118
float Wdt
Definition: C4Facet.h:118
void DrawX(C4Surface *sfcTarget, float iX, float iY, float iWdt, float iHgt, int32_t iPhaseX=0, int32_t iPhaseY=0) const
Definition: C4Facet.cpp:358
void SetCustomGraphics(DynBarFacet *pCustomGfx, DynBarFacet *pCustomGfxDown)
Definition: C4Gui.h:1129
bool GetFromLeft(int32_t iWdt, int32_t iHgt, C4Rect &rcOut)
Definition: C4Gui.cpp:1076
bool GetFromTop(int32_t iHgt, int32_t iWdt, C4Rect &rcOut)
Definition: C4Gui.cpp:1059
void GetAll(C4Rect &rcOut)
Definition: C4Gui.cpp:1125
void AddElement(Element *pChild)
void AddItem(const char *szText, const char *szToolTip=nullptr, Icons icoIcon=Ico_None, MenuHandler *pMenuHandler=nullptr, ContextHandler *pSubmenuHandler=nullptr)
Definition: C4Gui.h:1874
void SetFocus(Control *pCtrl, bool fByMouse)
bool KeyAdvanceFocus(bool fBackwards)
Definition: C4Gui.h:2139
bool fOK
Definition: C4Gui.h:2083
C4Rect rcBounds
Definition: C4Gui.h:385
virtual Screen * GetScreen()
Definition: C4Gui.cpp:289
void SetToolTip(const char *szNewTooltip, bool is_immediate=false)
Definition: C4Gui.cpp:409
void SetContextHandler(ContextHandler *pNewHd)
Definition: C4Gui.h:465
void SetText(const char *szToText, bool fAllowHotkey=true)
Definition: C4GuiLabels.cpp:74
bool ShowModalDlg(Dialog *pDlg, bool fDestruct=true)
bool ShowErrorMessage(const char *szMessage)
bool ShowMessage(const char *szMessage, const char *szCaption, Icons icoIcon, int32_t *piConfigDontShowAgainSetting=nullptr)
C4Rect & GetClientRect() override
Definition: C4Gui.h:864
char DirectJoinAddress[_MAX_PATH_LEN]
Definition: C4Game.h:106
bool DoKeyboardInput(C4KeyCode vk_code, C4KeyEventType event_type, bool alt, bool ctrl, bool shift, bool repeated, class C4GUI::Dialog *for_dialog=nullptr, bool fPlrCtrlOnly=false, int32_t strength=-1)
Definition: C4Game.cpp:2288
char ScenarioFilename[_MAX_PATH_LEN]
Definition: C4Game.h:102
bool NetworkActive
Definition: C4Game.h:123
bool fObserve
Definition: C4Game.h:121
char DefinitionFilenames[20 *_MAX_PATH_LEN]
Definition: C4Game.h:105
bool fLobby
Definition: C4Game.h:119
int32_t Hgt
Definition: C4Rect.h:30
int32_t Wdt
Definition: C4Rect.h:30
C4FacetID fctStartupLogo
Definition: C4Startup.h:59
C4GUI::DynBarFacet barMainButtonsDown
Definition: C4Startup.h:63
static C4Startup * Get()
Definition: C4Startup.h:147
@ SDID_PlrSel
Definition: C4Startup.h:114
@ SDID_Options
Definition: C4Startup.h:114
@ SDID_NetJoin
Definition: C4Startup.h:114
@ SDID_ScenSel
Definition: C4Startup.h:114
@ SDID_About
Definition: C4Startup.h:114
class C4StartupDlg * SwitchDialog(DialogID eToDlg, bool fFade=true, const char *szSubDialog=nullptr)
Definition: C4Startup.cpp:139
C4StartupGraphics Graphics
Definition: C4Startup.h:112
void OnClosed(bool fOK) override
void OnPlayerSelContextAddPlr(C4GUI::Element *pTarget, const StdCopyStrBuf &rsFilename)
void OnStartBtn(C4GUI::Control *btn)
void DrawElement(C4TargetFacet &cgo) override
void OnNetJoin(const StdStrBuf &rsHostAddress)
~C4StartupMainDlg() override
void OnPlayerSelContextRemovePlr(C4GUI::Element *pTarget, const int &iIndex)
C4GUI::ContextMenu * OnPlayerSelContextAdd(C4GUI::Element *pBtn, int32_t iX, int32_t iY)
void OnEditorBtn(C4GUI::Control *btn)
void OnPlayerSelectionBtn(C4GUI::Control *btn)
void OnExitBtn(C4GUI::Control *btn)
void OnShown() override
void OnAboutBtn(C4GUI::Control *btn)
C4GUI::ContextMenu * OnPlayerSelContext(C4GUI::Element *pBtn, int32_t iX, int32_t iY)
void OnModsBtn(C4GUI::Control *btn)
C4GUI::ContextMenu * OnPlayerSelContextRemove(C4GUI::Element *pBtn, int32_t iX, int32_t iY)
void OnOptionsBtn(C4GUI::Control *btn)
void OnNetJoinBtn(C4GUI::Control *btn)
void OnTODO(C4GUI::Control *btn)
const char * getData() const
Definition: StdBuf.h:442
void Format(const char *szFmt,...) GNUC_FORMAT_ATTRIBUTE_O
Definition: StdBuf.cpp:174
Screen TheScreen
Definition: C4Gui.cpp:1054
@ Ico_None
Definition: C4Gui.h:640
@ Ico_Player
Definition: C4Gui.h:650
@ Ico_Error
Definition: C4Gui.h:652
void Down(T &keys)
void Up(T &keys)