OpenClonk
C4StartupOptionsDlg.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: Options dialog
17 
18 #include "C4Include.h"
21 
22 #include "game/C4Application.h"
23 #include "graphics/C4Draw.h"
25 #include "gui/C4MouseControl.h"
26 #include "gui/C4KeyboardInput.h"
27 #include "gui/C4StartupMainDlg.h"
28 #include "network/C4Network2.h"
29 #include "platform/C4GamePadCon.h"
30 
31 #include "graphics/C4DrawGL.h"
32 
33 // ------------------------------------------------
34 // --- C4StartupOptionsDlg::SmallButton
35 
36 void C4StartupOptionsDlg::SmallButton::DrawElement(C4TargetFacet &cgo)
37 {
38  // draw the button
40  // get text pos
41  float x0 = cgo.TargetX + rcBounds.x, y0 = cgo.TargetY + rcBounds.y, x1 = cgo.TargetX + rcBounds.x + rcBounds.Wdt, y1 = cgo.TargetY + rcBounds.y + rcBounds.Hgt;
42  int32_t iTextHgt = rUseFont.GetLineHeight();
43  // draw frame
44  uint32_t dwClrHigh = C4StartupBtnBorderColor1, dwClrLow = C4StartupBtnBorderColor2;
45  if (fDown) std::swap(dwClrHigh, dwClrLow);
46  int32_t iIndent = Clamp<int32_t>((rcBounds.Hgt-iTextHgt)/3, 2, 5);
47  float iDrawQuadTop[8] = { x0,y0, x1,y0, x1-iIndent,y0+iIndent, x0,y0+iIndent };
48  float iDrawQuadLeft[8] = { x0,y0, x0+iIndent,y0, x0+iIndent,y1-iIndent, x0,y1 };
49  float iDrawQuadRight[8] = { x1,y0, x1,y1, x1-iIndent,y1, x1-iIndent,y0+iIndent };
50  float iDrawQuadBottom[8] = { x1,y1, x0,y1, x0+iIndent,y1-iIndent, x1,y1-iIndent };
51  // TODO: Switch to PerformMultiTris
52  pDraw->DrawQuadDw(cgo.Surface, iDrawQuadTop, dwClrHigh,dwClrHigh,dwClrHigh,dwClrHigh, nullptr);
53  pDraw->DrawQuadDw(cgo.Surface, iDrawQuadLeft, dwClrHigh,dwClrHigh,dwClrHigh,dwClrHigh, nullptr);
54  pDraw->DrawQuadDw(cgo.Surface, iDrawQuadRight, dwClrLow,dwClrLow,dwClrLow,dwClrLow, nullptr);
55  pDraw->DrawQuadDw(cgo.Surface, iDrawQuadBottom, dwClrLow,dwClrLow,dwClrLow,dwClrLow, nullptr);
56  // draw selection highlight
57  int32_t iTxtOff = fDown ? iIndent : 0;
58  if (fEnabled) if (HasDrawFocus() || (fMouseOver && IsInActiveDlg(false)))
59  {
61  ::GraphicsResource.fctButtonHighlight.DrawX(cgo.Surface, x0+5+iTxtOff, y0+3+iTxtOff, rcBounds.Wdt-10, rcBounds.Hgt-6);
63  }
64  // draw button text
65  pDraw->TextOut(sText.getData(), rUseFont, 1.0f, cgo.Surface, (x0+x1)/2 + iTxtOff, (y0+y1-iTextHgt)/2 + iTxtOff, C4StartupBtnFontClr, ACenter, true);
66 }
67 
68 int32_t C4StartupOptionsDlg::SmallButton::GetDefaultButtonHeight()
69 {
70  // button height is used font height plus a small indent
71  CStdFont *pUseFont = &(C4Startup::Get()->Graphics.BookFont);
72  return pUseFont->GetLineHeight()*6/5+6;
73 }
74 
75 
76 // ------------------------------------------------
77 // --- C4StartupOptionsDlg::ResChangeConfirmDlg
78 
79 C4StartupOptionsDlg::ResChangeConfirmDlg::ResChangeConfirmDlg()
80  : C4GUI::Dialog(C4GUI_MessageDlgWdt, 100 /* will be resized */, LoadResStr("IDS_MNU_SWITCHRESOLUTION"), false)
81 {
82  // update-timer
83  Application.Add(this);
84  // An independant group of fourteen highly trained apes and one blind lawnmower have determined
85  // that twelve seconds is just right for normal people
86  iResChangeSwitchTime = 12;
87  // However, some people need more time
88  // Those can be identified by their configuration settings
89  if (SEqualNoCase(Config.GetRegistrationData("Nick"), "flgr")) iResChangeSwitchTime *= 10;
90  // get positions
91  C4GUI::ComponentAligner caMain(GetClientRect(), C4GUI_DefDlgIndent, C4GUI_DefDlgIndent, true);
92  // place icon
93  C4Rect rcIcon = caMain.GetFromLeft(C4GUI_IconWdt); rcIcon.Hgt = C4GUI_IconHgt;
94  C4GUI::Icon *pIcon = new C4GUI::Icon(rcIcon, C4GUI::Ico_Confirm); AddElement(pIcon);
95  // place message labels
96  // use text with line breaks
97  StdStrBuf sMsgBroken;
98  int iMsgHeight = ::GraphicsResource.TextFont.BreakMessage(LoadResStr("IDS_MNU_SWITCHRESOLUTION_LIKEIT"), caMain.GetInnerWidth(), &sMsgBroken, true);
99  C4GUI::Label *pLblMessage = new C4GUI::Label(sMsgBroken.getData(), caMain.GetFromTop(iMsgHeight), ACenter, C4GUI_MessageFontClr, &::GraphicsResource.TextFont, false);
100  AddElement(pLblMessage);
101  iMsgHeight = ::GraphicsResource.TextFont.BreakMessage(FormatString(LoadResStr("IDS_MNU_SWITCHRESOLUTION_UNDO"),
102  (int)iResChangeSwitchTime).getData(),
103  caMain.GetInnerWidth(), &sMsgBroken, true);
104  pOperationCancelLabel = new C4GUI::Label(sMsgBroken.getData(), caMain.GetFromTop(iMsgHeight), ACenter, C4GUI_MessageFontClr, &::GraphicsResource.TextFont, false, false);
105  AddElement(pOperationCancelLabel);
106  // place buttons
107  C4GUI::ComponentAligner caButtonArea(caMain.GetFromTop(C4GUI_ButtonAreaHgt), 0,0);
108  int32_t iButtonCount = 2;
109  C4Rect rcBtn = caButtonArea.GetCentered(iButtonCount*C4GUI_DefButton2Wdt+(iButtonCount-1)*C4GUI_DefButton2HSpace, C4GUI_ButtonHgt);
110  rcBtn.Wdt = C4GUI_DefButton2Wdt;
111  // Yes
112  C4GUI::Button *pBtnYes = new C4GUI::YesButton(rcBtn);
113  AddElement(pBtnYes);
115  // No
116  C4GUI::Button *pBtnNo = new C4GUI::NoButton(rcBtn);
117  AddElement(pBtnNo);
118  // initial focus on abort button, to prevent accidental acceptance of setting by "blind" users
119  SetFocus(pBtnNo, false);
120  // resize to actually needed size
121  SetClientSize(GetClientRect().Wdt, GetClientRect().Hgt - caMain.GetHeight());
122 }
123 
124 C4StartupOptionsDlg::ResChangeConfirmDlg::~ResChangeConfirmDlg()
125 {
126  Application.Remove(this);
127 }
128 
129 void C4StartupOptionsDlg::ResChangeConfirmDlg::OnSec1Timer()
130 {
131  // timer ran out? Then cancel dlg
132  if (!--iResChangeSwitchTime)
133  {
134  Close(false); return;
135  }
136  // update timer label
137  StdStrBuf sTimerText;
138  ::GraphicsResource.TextFont.BreakMessage(FormatString(LoadResStr("IDS_MNU_SWITCHRESOLUTION_UNDO"),
139  (int)iResChangeSwitchTime).getData(),
140  pOperationCancelLabel->GetBounds().Wdt, &sTimerText, true);
141  pOperationCancelLabel->SetText(sTimerText.getData());
142 }
143 
144 // ------------------------------------------------
145 // --- C4StartupOptionsDlg::KeySelDialog
146 
147 C4StartupOptionsDlg::KeySelDialog::KeySelDialog(const C4PlayerControlAssignment *assignment, const C4PlayerControlAssignmentSet *assignment_set)
148  : C4GUI::MessageDialog(GetDlgMessage(assignment, assignment_set).getData(), LoadResStr("IDS_MSG_DEFINEKEY"), C4GUI::MessageDialog::btnAbort | C4GUI::MessageDialog::btnReset, GetDlgIcon(assignment_set), C4GUI::MessageDialog::dsRegular),
149  key(KEY_Undefined), assignment(assignment), assignment_set(assignment_set)
150 {
151  const uint32_t KEYS_Allmod = KEYS_Shift | KEYS_Control | KEYS_Alt;
153  static_assert(KEYS_None == 0, "");
154  for (uint32_t k = KEYS_None; k <= KEYS_Allmod; k++) {
155  if (~KEYS_Allmod & k) // There is some efficient bit-twiddling (k = KEYS_Allmod & (k - KEYS_Allmod) instead of k++), but I figure that's overkill. (Relies on (defined) unsigned overflow)
156  continue;
157  keys.emplace_back(KEY_Any, k);
158  }
159  KeyListeners = std::make_unique<C4KeyBinding>(
160  keys,
161  "DefineKey",
162  KEYSCOPE_Gui,
164  *this,
165  &C4StartupOptionsDlg::KeySelDialog::KeyDown,
166  &C4StartupOptionsDlg::KeySelDialog::KeyUp
167  ),
169  );
170 }
171 
172 StdStrBuf C4StartupOptionsDlg::KeySelDialog::GetDlgMessage(const C4PlayerControlAssignment *assignment, const C4PlayerControlAssignmentSet *assignment_set)
173 {
174  // compose message asking for key, gamepad button and/or mouse button depending on used control set
175  if (!assignment || !assignment_set) return StdStrBuf("err");
176  StdStrBuf result_string;
177  if (assignment_set->HasGamepad())
178  result_string.Take(FormatString(LoadResStr("IDS_MSG_PRESSBTN"), assignment->GetGUIName(Game.PlayerControlDefs)));
179  else
180  result_string.Take(FormatString(LoadResStr("IDS_MSG_PRESSKEY"), assignment->GetGUIName(Game.PlayerControlDefs)));
181  const char *ctrl_desc = assignment->GetGUIDesc(Game.PlayerControlDefs);
182 
183  if (ctrl_desc && *ctrl_desc)
184  {
185  result_string.Append("||");
186  result_string.Append(ctrl_desc);
187  }
188  return result_string;
189 }
190 
191 C4GUI::Icons C4StartupOptionsDlg::KeySelDialog::GetDlgIcon(const C4PlayerControlAssignmentSet *assignment_set)
192 {
193  if (!assignment_set) return C4GUI::Ico_Error;
194  if (assignment_set->HasGamepad()) return C4GUI::Ico_Gamepad;
195  return C4GUI::Ico_Keyboard;
196 }
197 
198 void C4StartupOptionsDlg::KeySelDialog::MouseInput(C4GUI::CMouse& rMouse, int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam)
199 {
200  // Original action
201  C4GUI::MessageDialog::MouseInput(rMouse, iButton, iX, iY, dwKeyParam);
202 
203  // Find out to where the input was made (code duplication with C4GUI::Window::MouseInput)
204  // get client pos
205  C4Rect &rcClientRect = GetClientRect(), &rcBounds = GetBounds();
206  iX -= rcClientRect.x - rcBounds.x; iY -= rcClientRect.y - rcBounds.y;
207  // forward to topmost child element
208  for (Element *pChild = pLast; pChild; pChild = pChild->GetPrev())
209  if (pChild->fVisible && pChild->GetBounds().Contains(iX, iY))
210  {
211  if (dynamic_cast<C4GUI::Label*>(pChild))
212  break;
213  else
214  return;
215  }
216  // Only process the input event if the user certainly didn't click a button or anything...
217 
218  if (iButton == C4MC_Button_None) // mouse got moved
219  return;
220  bool down;
221  auto key = C4KeyCodeEx::FromC4MC(0 /* FIXME: more mice! */, iButton, dwKeyParam, &down);
222  KeyPress(key, down);
223 }
224 
225 bool C4StartupOptionsDlg::KeySelDialog::KeyPress(const C4KeyCodeEx &key, bool fDown)
226 {
227  // safety
228  if (!assignment || !assignment_set) return false;
229  // check if key is valid for this set
230  if (Key_IsGamepad(key.Key))
231  {
232  if (!assignment_set->HasGamepad()) return false;
233  }
234  else if (Key_IsMouse(key.Key))
235  {
236  if (!assignment_set->HasMouse()) return false;
237  }
238  else
239  {
240  if (!assignment_set->HasKeyboard()) return false;
241  }
242  // FIXME: There doesn't seem to be any kind of KEY_IsModifier function…
243  if ((KEY_IsModifier(key.Key) && fDown) ||
244  (!KEY_IsModifier(key.Key) && !fDown))
245  return false;
246  // okay, use it
247  this->key=key;
248  Close(true);
249  return true;
250 }
251 
252 
253 // ------------------------------------------------
254 // --- C4StartupOptionsDlg::ControlConfigListBox::ControlAssignmentLabel
255 
256 C4StartupOptionsDlg::ControlConfigListBox::ControlAssignmentLabel::ControlAssignmentLabel(class C4PlayerControlAssignment *assignment, class C4PlayerControlAssignmentSet *assignment_set, const C4Rect &bounds)
257  : C4GUI::Label("", bounds, ALeft, 0xffffffff, nullptr, false, false, true), assignment(assignment), assignment_set(assignment_set)
258 {
259  UpdateAssignmentString();
260 }
261 
262 void C4StartupOptionsDlg::ControlConfigListBox::ControlAssignmentLabel::MouseInput(C4GUI::CMouse &rMouse, int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam)
263  {
264  // left-click to change key
265  if (iButton == C4MC_Button_LeftDown && assignment)
266  {
267  if(!assignment->IsGUIDisabled())
268  {
269  KeySelDialog *dlg = new KeySelDialog(assignment, assignment_set);
270  dlg->SetDelOnClose(false);
271  bool success = GetScreen()->ShowModalDlg(dlg, false);
272  C4KeyCodeEx key = dlg->GetKeyCode();
273  delete dlg;
274  if (success)
275  {
276  // dialog closed by pressing a key or by the Reset button (in which case, key==KEY_Undefined)
277  // assign new config
278  C4StartupOptionsDlg::ControlConfigListBox::SetUserKey(assignment_set, assignment, key);
279  UpdateAssignmentString();
280  }
281  }
282  }
283  // inherited
284  Element::MouseInput(rMouse, iButton, iX, iY, dwKeyParam);
285  }
286 
287 void C4StartupOptionsDlg::ControlConfigListBox::ControlAssignmentLabel::UpdateAssignmentString()
288 {
289  // assignment label text from assigned key
290  StdStrBuf strKey;
291  C4KeyCodeEx key(0);
292  if (assignment)
293  {
294  SetText(assignment->GetKeysAsString(true, false).getData());
295  }
296  else
297  {
298  SetText("");
299  }
300  DWORD color = C4GUI_CaptionFontClr;
301  if (assignment)
302  {
303  if(assignment->IsGUIDisabled())
305  else if(assignment->IsKeyChanged())
306  color = C4GUI_Caption2FontClr;
307  }
308  SetColor(color);
309 }
310 
311 // ------------------------------------------------
312 // --- C4StartupOptionsDlg::ControlConfigListBox::ListItem
313 
314 C4StartupOptionsDlg::ControlConfigListBox::ListItem::ListItem(ControlConfigListBox *parent_list, class C4PlayerControlAssignment *assignment, class C4PlayerControlAssignmentSet *assignment_set, bool has_extra_spacing)
315  : C4GUI::Window(), assignment_label(nullptr), has_extra_spacing(has_extra_spacing)
316 {
317  int32_t margin = 2;
318  // adding to listbox will size the element horizontally and move to proper position
319  int32_t height = ::GraphicsResource.TextFont.GetLineHeight() + 2 * margin;
320  SetBounds(C4Rect(0,0,42,height));
321  parent_list->InsertElement(this, nullptr);
322  int32_t name_col_width = GetBounds().Wdt * 2/3;
323  // child elements: two labels for two columns
324  const char *gui_name = assignment->GetGUIName(Game.PlayerControlDefs);
325  const char *gui_desc = assignment->GetGUIDesc(Game.PlayerControlDefs);
326  C4GUI::Label *name_label = new C4GUI::Label(gui_name ? gui_name : "?undefined?", margin, margin);
327  C4Rect assignment_label_bounds = C4Rect(name_col_width + margin, margin, GetBounds().Wdt - name_col_width - margin, GetBounds().Hgt - 2 * margin);
328  assignment_label = new ControlAssignmentLabel(assignment, assignment_set, assignment_label_bounds);
329  AddElement(name_label);
330  AddElement(assignment_label);
331  if (gui_desc && *gui_desc) SetToolTip(gui_desc);
332 }
333 
334 
335 // ------------------------------------------------
336 // --- C4StartupOptionsDlg::ControlConfigListBox
337 
338 C4StartupOptionsDlg::ControlConfigListBox::ControlConfigListBox(const C4Rect &rcBounds, class C4PlayerControlAssignmentSet *set)
339  : C4GUI::ListBox(rcBounds), set(nullptr)
340 {
341  SetAssignmentSet(set);
342 }
343 
344 void C4StartupOptionsDlg::ControlConfigListBox::SetAssignmentSet(class C4PlayerControlAssignmentSet *new_set)
345 {
346  set = new_set;
347  // clear previous elements
348  if (pClientWindow) pClientWindow->ClearChildren();
349  // populate with new assignments
350  if (set)
351  {
352  C4PlayerControlAssignment *assignment;
353 
354  std::vector<C4PlayerControlAssignment *> grouped_assignments;
355  for (int32_t i=0; (assignment = set->GetAssignmentByIndex(i)); ++i)
356  grouped_assignments.push_back(assignment);
357 
358  std::stable_sort(grouped_assignments.begin(),grouped_assignments.end(),&C4StartupOptionsDlg::ControlConfigListBox::sort_by_group);
359 
360  int32_t current_group = 0;
361  for (auto & grouped_assignment : grouped_assignments)
362  {
363  assignment = grouped_assignment;
364  bool first_element_of_group = assignment->GetGUIGroup() > current_group;
365  current_group = assignment->GetGUIGroup();
366  // only show assignments of GUI-named controls
367  const char *gui_name = assignment->GetGUIName(Game.PlayerControlDefs);
368  if (gui_name && *gui_name)
369  {
370  ListItem *element = new ListItem(this, assignment, set, first_element_of_group);
371  AddElement(element);
372  }
373  }
374  }
375 }
376 
377 void C4StartupOptionsDlg::ControlConfigListBox::SetUserKey(class C4PlayerControlAssignmentSet *assignment_set, class C4PlayerControlAssignment *assignment, C4KeyCodeEx &key)
378 {
379  // change key in the specified assignment set to the specified value
380  // also changes config values so change is kept after restart
381  // safety
382  if (!assignment || !assignment_set) return;
383  class C4PlayerControlAssignmentSet *config_set = Config.Controls.UserSets.GetSetByName(assignment_set->GetName());
384  // change key
385  if (key.Key == KEY_Undefined)
386  {
387  // reset to default
388  assignment->ResetKeyToInherited();
389  // also reset in config
390  if (config_set)
391  {
392  config_set->RemoveAssignmentByControlName(assignment->GetControlName());
393  if (!config_set->GetAssignmentByIndex(0))
394  {
395  // if config set is empty, no overrides exist and the set can be deleted (unless it's a custom config set)
397  {
398  Config.Controls.UserSets.RemoveSetByName(assignment_set->GetName());
399  }
400  }
401  }
402  }
403  else
404  {
405  // set to specified value
406  assignment->SetKey(key);
407  // also set in config
408  if (!config_set) config_set = Config.Controls.UserSets.CreateEmptySetByTemplate(*assignment_set);
409  C4PlayerControlAssignment *config_assignment = config_set->GetAssignmentByControlName(assignment->GetControlName());
410  if (!config_assignment) config_assignment = config_set->CreateAssignmentForControl(assignment->GetControlName());
411  config_assignment->SetKey(key);
412  // check for duplicates. Allow them in principle because they can be used with priorities
413  // however, do warn because usually it may be unintended
414  // Just deleting the old assignments is also usually undesirable, because half of the time a newbi changes a control and creates a conflict,
415  // they may want to change the key they just assigned to something else instead
416  C4PlayerControlAssignment *other_assignment;
417  for (int32_t i = 0; (other_assignment = assignment_set->GetAssignmentByIndex(i)); ++i)
418  if (other_assignment != assignment)
419  if (other_assignment->GetTriggerKey() == key)
420  {
421  const char *gui_name = other_assignment->GetGUIName(Game.PlayerControlDefs);
422  // only warn for assignable keys, because other keys are typically derived from the settable keys
423  if (gui_name && *gui_name)
424  {
425  C4GUI::TheScreen.ShowMessage(FormatString(LoadResStr("IDS_MSG_DEFINEKEYDUPLICATE"), key.ToString(true, false).getData(), gui_name).getData(), LoadResStr("IDS_MSG_DEFINEKEY"), C4GUI::Ico_Error);
426  }
427  }
428 
429  }
430 }
431 
432 // ------------------------------------------------
433 // --- C4StartupOptionsDlg::ControlConfigArea
434 
435 C4StartupOptionsDlg::ControlConfigArea::ControlConfigArea(const C4Rect &rcArea, int32_t iHMargin, int32_t iVMargin, bool fGamepad, C4StartupOptionsDlg *pOptionsDlg)
436  : C4GUI::Window(), fGamepad(fGamepad), pOptionsDlg(pOptionsDlg), pGUICtrl(nullptr)
437 {
438  CStdFont *pUseFontSmall = &(C4Startup::Get()->Graphics.BookSmallFont);
439  SetBounds(rcArea);
440  C4GUI::ComponentAligner caArea(rcArea, iHMargin, iVMargin, true);
441  // get number of control sets to be configured
443  iMaxControlSets = std::max<size_t>(assignment_sets.GetSetCount(),1u); // do not devide by zero
444  ppKeyControlSetBtns = new C4GUI::IconButton *[iMaxControlSets];
445  // top line buttons to select control configuration
446  C4Facet fctCtrlDefPic = ::GraphicsResource.fctKeyboard; //
447  int32_t iCtrlSetWdt = caArea.GetWidth() - caArea.GetHMargin()*2;
448  int32_t iCtrlSetHMargin = 5, iCtrlSetVMargin = 5;
449  int32_t iCtrlSetBtnWdt = Clamp<int32_t>((iCtrlSetWdt - iMaxControlSets*iCtrlSetHMargin*2) / iMaxControlSets, 5, fctCtrlDefPic.Wdt);
450  int32_t iCtrlSetBtnHgt = fctCtrlDefPic.GetHeightByWidth(iCtrlSetBtnWdt);
451  iCtrlSetHMargin = (iCtrlSetWdt - iCtrlSetBtnWdt*iMaxControlSets) / (iMaxControlSets*2);
452  C4GUI::ComponentAligner caKeyboardSetSel(caArea.GetFromTop(2*iCtrlSetVMargin+iCtrlSetBtnHgt), iCtrlSetHMargin, iCtrlSetVMargin);
453  const char *szCtrlSetHotkeys = "1234567890"; /* 2do */
454  uint32_t i;
455  for (i = 0; i < assignment_sets.GetSetCount(); ++i)
456  {
457  C4PlayerControlAssignmentSet *assignment_set = assignment_sets.GetSetByIndex(i);
458  char cCtrlSetHotkey = 0;
459  if (i <= strlen(szCtrlSetHotkeys)) cCtrlSetHotkey = szCtrlSetHotkeys[i];
460  C4GUI::CallbackButton<C4StartupOptionsDlg::ControlConfigArea, C4GUI::IconButton> *pBtn = new C4GUI::CallbackButton<C4StartupOptionsDlg::ControlConfigArea, C4GUI::IconButton>(C4GUI::Ico_None, caKeyboardSetSel.GetFromLeft(iCtrlSetBtnWdt), cCtrlSetHotkey, &C4StartupOptionsDlg::ControlConfigArea::OnCtrlSetBtn, this);
461  C4Facet fctCtrlPic = assignment_set->GetPicture();
462  pBtn->SetFacet(fctCtrlPic);
463  AddElement(ppKeyControlSetBtns[i] = pBtn);
464  pBtn->SetText(assignment_set->GetGUIName());
465  pBtn->SetFont(pUseFontSmall, C4StartupFontClr);
466  pBtn->SetToolTip(LoadResStr("IDS_DLGTIP_CHANGECTRL"));
467  }
468  iSelectedCtrlSet = 0;
469  caArea.ExpandTop(caArea.GetVMargin());
470  AddElement(new C4GUI::HorizontalLine(caArea.GetFromTop(2)));
471  caArea.ExpandTop(caArea.GetVMargin());
472  control_list = new ControlConfigListBox(caArea.GetFromLeft(caArea.GetInnerWidth()), nullptr);
473  AddElement(control_list);
474 
475  UpdateCtrlSet();
476 }
477 
478 C4StartupOptionsDlg::ControlConfigArea::~ControlConfigArea()
479 {
480  delete [] ppKeyControlSetBtns;
481 }
482 
483 void C4StartupOptionsDlg::ControlConfigArea::OnCtrlSetBtn(C4GUI::Control *btn)
484 {
485  // select Ctrl set of pressed btn
486  int i;
487  for (i = 0; i < iMaxControlSets; ++i)
488  if (btn == ppKeyControlSetBtns[i])
489  {
490  iSelectedCtrlSet = i;
491  break;
492  }
493  // update shown keys
494  UpdateCtrlSet();
495 }
496 
497 void C4StartupOptionsDlg::ControlConfigArea::UpdateCtrlSet()
498 {
499  // selected keyboard set btn gets a highlight
500  int i;
501  for (i = 0; i < iMaxControlSets; ++i)
502  ppKeyControlSetBtns[i]->SetHighlight(i == iSelectedCtrlSet);
503  // update list
504  control_list->SetAssignmentSet(Game.PlayerControlUserAssignmentSets.GetSetByIndex(iSelectedCtrlSet));
505 }
506 
507 void C4StartupOptionsDlg::ControlConfigArea::OnResetKeysBtn(C4GUI::Control *btn)
508 {
509  // default keys and axis reset
511  UpdateCtrlSet();
512 }
513 
514 void C4StartupOptionsDlg::ControlConfigArea::OnGUIGamepadCheckChange(C4GUI::Element *pCheckBox)
515 {
516  // same as before?
517  bool fChecked = ((C4GUI::CheckBox *)(pCheckBox))->GetChecked();
518  if (fChecked == !!Config.Controls.GamepadGuiControl) return;
519  // reflect change
520  Config.Controls.GamepadGuiControl = fChecked;
522  pOptionsDlg->RecreateDialog(false);
523 }
524 
525 
526 
527 // ------------------------------------------------
528 // --- C4StartupOptionsDlg::NetworkPortConfig
529 
530 C4StartupOptionsDlg::NetworkPortConfig::NetworkPortConfig(const C4Rect &rcBounds, const char *szName, int32_t *pConfigValue, int32_t iDefault)
531  : C4GUI::Window(), pConfigValue(pConfigValue)
532 {
533  // ctor
534  CStdFont *pUseFont = &(C4Startup::Get()->Graphics.BookFont);
535  SetBounds(rcBounds);
536  C4GUI::ComponentAligner caMain(GetClientRect(), 0,2, true);
537  bool fEnabled = (*pConfigValue != -1);
538  C4GUI::Label *pLbl = new C4GUI::Label(szName, caMain.GetFromTop(pUseFont->GetLineHeight()), ALeft, C4StartupFontClr, pUseFont, false);
539  AddElement(pLbl);
540  C4GUI::ComponentAligner caBottomLine(caMain.GetAll(), 2,0, false);
541  const char *szText = LoadResStr("IDS_CTL_ACTIVE");
542  int iWdt=100, iHgt=12;
543  C4GUI::CheckBox::GetStandardCheckBoxSize(&iWdt, &iHgt, szText, pUseFont);
544  pEnableCheck = new C4GUI::CheckBox(caBottomLine.GetFromLeft(iWdt, iHgt), szText, fEnabled);
545  pEnableCheck->SetFont(pUseFont, C4StartupFontClr, C4StartupFontClrDisabled);
546  pEnableCheck->SetOnChecked(new C4GUI::CallbackHandler<C4StartupOptionsDlg::NetworkPortConfig>(this, &C4StartupOptionsDlg::NetworkPortConfig::OnEnabledCheckChange));
547  AddElement(pEnableCheck);
548  pPortEdit = new C4GUI::Edit(caBottomLine.GetAll(), true);
550  pPortEdit->SetFont(pUseFont);
551  pPortEdit->InsertText(FormatString("%d", fEnabled ? ((int) *pConfigValue) : (int) iDefault).getData(), false);
552  pPortEdit->SetMaxText(10); // 65535 is five characters long - but allow some more for easier editing
553  pPortEdit->SetVisibility(fEnabled);
554  AddElement(pPortEdit);
555 }
556 
557 void C4StartupOptionsDlg::NetworkPortConfig::OnEnabledCheckChange(C4GUI::Element *pCheckBox)
558 {
559  pPortEdit->SetVisibility(pEnableCheck->GetChecked());
560 }
561 
562 void C4StartupOptionsDlg::NetworkPortConfig::SavePort()
563 {
564  *pConfigValue=GetPort();
565 }
566 
567 int32_t C4StartupOptionsDlg::NetworkPortConfig::GetPort()
568 {
569  // controls to config
570  if (!pEnableCheck->GetChecked())
571  return -1;
572  else
573  return atoi(pPortEdit->GetText());
574 }
575 
576 bool C4StartupOptionsDlg::NetworkPortConfig::GetControlSize(int *piWdt, int *piHgt)
577 {
578  CStdFont *pUseFont = &(C4Startup::Get()->Graphics.BookFont);
579  // get size needed for control
580  if (piWdt)
581  {
582  const char *szText = LoadResStr("IDS_CTL_ACTIVE");
583  if (!C4GUI::CheckBox::GetStandardCheckBoxSize(piWdt, piHgt, szText, pUseFont)) return false;
584  *piWdt *= 2;
585  }
586  if (piHgt) *piHgt = C4GUI::Edit::GetCustomEditHeight(pUseFont) + pUseFont->GetLineHeight()+2*4;
587  return true;
588 }
589 
590 
591 // ------------------------------------------------
592 // --- C4StartupOptionsDlg::NetworkServerAddressConfig
593 
594 C4StartupOptionsDlg::NetworkServerAddressConfig::NetworkServerAddressConfig(const C4Rect &rcBounds, const char *szName, int32_t *piConfigEnableValue, char *szConfigAddressValue, int iTabWidth)
595  : C4GUI::Window(), piConfigEnableValue(piConfigEnableValue), szConfigAddressValue(szConfigAddressValue)
596 {
597  // ctor
598  CStdFont *pUseFont = &(C4Startup::Get()->Graphics.BookFont);
599  SetBounds(rcBounds);
600  C4GUI::ComponentAligner caMain(GetClientRect(), 0,2, true);
601  pEnableCheck = new C4GUI::CheckBox(caMain.GetFromLeft(iTabWidth, pUseFont->GetLineHeight()), szName, !!*piConfigEnableValue);
602  pEnableCheck->SetFont(pUseFont, C4StartupFontClr, C4StartupFontClrDisabled);
603  pEnableCheck->SetOnChecked(new C4GUI::CallbackHandler<C4StartupOptionsDlg::NetworkServerAddressConfig>(this, &C4StartupOptionsDlg::NetworkServerAddressConfig::OnEnabledCheckChange));
604  AddElement(pEnableCheck);
605  caMain.ExpandLeft(-2);
606  pAddressEdit = new C4GUI::Edit(caMain.GetAll(), true);
608  pAddressEdit->SetFont(pUseFont);
609  pAddressEdit->InsertText(szConfigAddressValue, false);
610  pAddressEdit->SetMaxText(CFG_MaxString);
611  pAddressEdit->SetVisibility(!!*piConfigEnableValue);
612  AddElement(pAddressEdit);
613 }
614 
615 void C4StartupOptionsDlg::NetworkServerAddressConfig::OnEnabledCheckChange(C4GUI::Element *pCheckBox)
616 {
617  // warn about using alternate servers
618  if (pEnableCheck->GetChecked())
619  {
620  GetScreen()->ShowMessage(LoadResStr("IDS_NET_NOOFFICIALLEAGUE"), LoadResStr("IDS_NET_QUERY_MASTERSRV"), C4GUI::Ico_Notify, &Config.Startup.HideMsgNoOfficialLeague);
621  }
622  // callback when checkbox is ticked
623  pAddressEdit->SetVisibility(pEnableCheck->GetChecked());
624 }
625 
626 void C4StartupOptionsDlg::NetworkServerAddressConfig::Save2Config()
627 {
628  // controls to config
629  *piConfigEnableValue = pEnableCheck->GetChecked();
630  SCopy(pAddressEdit->GetText(), szConfigAddressValue, CFG_MaxString);
631 }
632 
633 bool C4StartupOptionsDlg::NetworkServerAddressConfig::GetControlSize(int *piWdt, int *piHgt, int *piTabPos, const char *szForText)
634 {
635  CStdFont *pUseFont = &(C4Startup::Get()->Graphics.BookFont);
636  int iWdt=120;
637  C4GUI::CheckBox::GetStandardCheckBoxSize(&iWdt, piHgt, szForText, pUseFont);
638  int32_t iEdtWdt=120, iEdtHgt=24;
639  pUseFont->GetTextExtent("sorgentelefon@treffpunktclonk.net", iEdtWdt, iEdtHgt, false);
640  if (piWdt) *piWdt = iWdt+iEdtWdt+2;
641  if (piTabPos) *piTabPos = iWdt+2;
642  if (piHgt) *piHgt = C4GUI::Edit::GetCustomEditHeight(pUseFont)+2*2;
643  return true;
644 }
645 
646 C4StartupOptionsDlg::NetworkModDatabaseServerAddressConfig::NetworkModDatabaseServerAddressConfig(const C4Rect &rcBounds, const char *szName, int32_t *piConfigEnableValue, char *szConfigAddressValue, int iTabWidth)
647  : NetworkServerAddressConfig(rcBounds, szName, piConfigEnableValue, szConfigAddressValue, iTabWidth)
648 {
649 
650 }
651 
652 void C4StartupOptionsDlg::NetworkModDatabaseServerAddressConfig::OnEnabledCheckChange(C4GUI::Element *pCheckBox)
653 {
654  // callback when checkbox is ticked
655  pAddressEdit->SetVisibility(pEnableCheck->GetChecked());
656 }
657 
658 // ------------------------------------------------
659 // --- C4StartupOptionsDlg::BoolConfig
660 
661 C4StartupOptionsDlg::BoolConfig::BoolConfig(const C4Rect &rcBounds, const char *szName, bool *pbVal, int32_t *piVal, bool fInvert, int32_t *piRestartChangeCfgVal)
662  : C4GUI::CheckBox(rcBounds, szName, fInvert != (pbVal ? *pbVal : !!*piVal)), pbVal(pbVal), fInvert(fInvert), piVal(piVal), piRestartChangeCfgVal(piRestartChangeCfgVal)
663 {
664  SetOnChecked(new C4GUI::CallbackHandler<BoolConfig>(this, &BoolConfig::OnCheckChange));
665 }
666 
667 void C4StartupOptionsDlg::BoolConfig::OnCheckChange(C4GUI::Element *pCheckBox)
668 {
669  if (pbVal) *pbVal = (GetChecked() != fInvert);
670  if (piVal) *piVal = (GetChecked() != fInvert);
671  if (piRestartChangeCfgVal) GetScreen()->ShowMessage(LoadResStr("IDS_MSG_RESTARTCHANGECFG"), GetText(),
672  C4GUI::Ico_Notify, piRestartChangeCfgVal);
673 }
674 
675 // ------------------------------------------------
676 // --- C4StartupOptionsDlg::EditConfig
677 
678 C4StartupOptionsDlg::EditConfig::EditConfig(const C4Rect &rcBounds, const char *szName, ValidatedStdCopyStrBufBase *psConfigVal, int32_t *piConfigVal, bool fMultiline)
679  : C4GUI::LabeledEdit(rcBounds, szName, fMultiline, psConfigVal ? psConfigVal->getData() : nullptr, &(C4Startup::Get()->Graphics.BookFont), C4StartupFontClr), psConfigVal(psConfigVal), piConfigVal(piConfigVal)
680 {
681  // ctor
683  if (piConfigVal) SetIntVal(*piConfigVal);
684  GetEdit()->SetMaxText(CFG_MaxString);
685 }
686 
687 void C4StartupOptionsDlg::EditConfig::Save2Config()
688 {
689  // controls to config
690  if (psConfigVal)
691  psConfigVal->CopyValidated(GetEdit()->GetText());
692  if (piConfigVal)
693  *piConfigVal = GetIntVal();
694 }
695 
696 bool C4StartupOptionsDlg::EditConfig::GetControlSize(int *piWdt, int *piHgt, const char *szForText, bool fMultiline)
697 {
698  CStdFont *pUseFont = &(C4Startup::Get()->Graphics.BookFont);
699  typedef C4GUI::LabeledEdit BaseEdit;
700  return BaseEdit::GetControlSize(piWdt, piHgt, szForText, pUseFont, fMultiline);
701 }
702 
703 // ------------------------------------------------
704 // --- C4StartupOptionsDlg
705 
707 {
708  // ctor
709  UpdateSize();
710  bool fSmall = (GetClientRect().Wdt < 750);
711  CStdFont *pUseFont = &(C4Startup::Get()->Graphics.BookFont);
712 
713  // key bindings
715  keys.emplace_back(K_BACK); keys.emplace_back(K_LEFT);
716  pKeyBack = new C4KeyBinding(keys, "StartupOptionsBack", KEYSCOPE_Gui,
718  keys.clear();
719  keys.emplace_back(K_F3); // overloading global toggle with higher priority here, so a new name is required
720  pKeyToggleMusic = new C4KeyBinding(keys, "OptionsMusicToggle", KEYSCOPE_Gui,
722 
723  // screen calculations
724  int32_t iButtonWidth,iCaptionFontHgt;
725  int32_t iButtonHeight = C4GUI_ButtonHgt;
726  ::GraphicsResource.CaptionFont.GetTextExtent("<< BACK", iButtonWidth, iCaptionFontHgt, true);
727  iButtonWidth *= 3;
728  int iIndentX1, iIndentY1, iIndentY2;
729  if (fSmall)
730  {
731  iIndentX1=20;
732  }
733  else
734  {
735  iIndentX1 = GetClientRect().Wdt/40;
736  }
737  if (fSmall)
738  {
739  iIndentY1=1; iIndentY2=1;
740  }
741  else
742  {
743  iIndentY1 = GetClientRect().Hgt/200;
744  iIndentY2 = std::max<int32_t>(1, iIndentY1/2);
745  }
746  C4GUI::ComponentAligner caMain(GetClientRect(), 0,0, true);
747  C4GUI::ComponentAligner caButtonArea(caMain.GetFromBottom(caMain.GetHeight()/(fSmall ? 20 : 7)),0,0);
748  C4GUI::ComponentAligner caButtons(caButtonArea.GetCentered(caMain.GetWidth()*7/8, iButtonHeight),0,0);
749  C4GUI::ComponentAligner caConfigArea(caMain.GetAll(), fSmall ? 0 : (caMain.GetWidth()*69/1730), fSmall ? 0 : (caMain.GetHeight()/200));
750 
751  // back button
754  btn->SetToolTip(LoadResStr("IDS_DLGTIP_BACKMAIN"));
755 
756  // main config area tabular
757  pOptionsTabular = new C4GUI::Tabular(caConfigArea.GetAll(), C4GUI::Tabular::tbLeft);
759  AddElement(pOptionsTabular);
760  C4GUI::Tabular::Sheet *pSheetGeneral = pOptionsTabular->AddSheet(LoadResStr("IDS_DLG_PROGRAM") , 0);
761  C4GUI::Tabular::Sheet *pSheetGraphics = pOptionsTabular->AddSheet(LoadResStr("IDS_DLG_GRAPHICS"), 1);
762  C4GUI::Tabular::Sheet *pSheetSound = pOptionsTabular->AddSheet(LoadResStr("IDS_DLG_SOUND") , 2);
763  C4GUI::Tabular::Sheet *pSheetControls= pOptionsTabular->AddSheet(LoadResStr("IDS_DLG_CONTROLS"), 3);
764  C4GUI::Tabular::Sheet *pSheetNetwork = pOptionsTabular->AddSheet(LoadResStr("IDS_DLG_NETWORK") , 5);
765 
766  C4GUI::CheckBox *pCheck; C4GUI::Label *pLbl;
767  int iCheckWdt=100, iCheckHgt=20, iEdit2Wdt=100, iEdit2Hgt=40;
768  BoolConfig::GetStandardCheckBoxSize(&iCheckWdt, &iCheckHgt, "Default text", pUseFont);
769  EditConfig::GetControlSize(&iEdit2Wdt, &iEdit2Hgt, "Default text", false);
770 
771  // --- page program
772  C4GUI::ComponentAligner caSheetProgram(pSheetGeneral->GetClientRect(), caMain.GetWidth()/20, caMain.GetHeight()/20, true);
773  // language
774  const char *szLangTip = LoadResStr("IDS_MSG_SELECTLANG");
775  C4GUI::ComponentAligner caLanguage(caSheetProgram.GetGridCell(0,1,0,7,-1,-1,true,1,2), 0, C4GUI_DefDlgSmallIndent, false);
776  C4GUI::ComponentAligner caLanguageBox(caLanguage.GetFromTop(C4GUI::ComboBox::GetDefaultHeight()), 0, 0, false);
777  StdStrBuf sLangStr; sLangStr.Copy(LoadResStr("IDS_CTL_LANGUAGE")); sLangStr.AppendChar(':');
778  int32_t w,q;
779  pUseFont->GetTextExtent(sLangStr.getData(), w,q,true);
780  pLbl = new C4GUI::Label(sLangStr.getData(), caLanguageBox.GetFromLeft(w+C4GUI_DefDlgSmallIndent), ALeft, C4StartupFontClr, pUseFont, false);
781  pLbl->SetToolTip(szLangTip);
782  pSheetGeneral->AddElement(pLbl);
783  pUseFont->GetTextExtent("XX: Top Secret Language", w,q,true);
784  pLangCombo = new C4GUI::ComboBox(caLanguageBox.GetFromLeft(std::min(w, caLanguageBox.GetWidth())));
785  pLangCombo->SetToolTip(szLangTip);
786  pLangCombo->SetComboCB(new C4GUI::ComboBox_FillCallback<C4StartupOptionsDlg>(this, &C4StartupOptionsDlg::OnLangComboFill, &C4StartupOptionsDlg::OnLangComboSelChange));
788  pLangCombo->SetFont(pUseFont);
789  pLangCombo->SetDecoration(&(C4Startup::Get()->Graphics.fctContext));
790  pSheetGeneral->AddElement(pLangCombo);
791  pLangInfoLabel = new C4GUI::Label(nullptr, caLanguage.GetFromTop(::GraphicsResource.TextFont.GetLineHeight()*3), ALeft, C4StartupFontClr, pUseFont, false);
792  pLangInfoLabel->SetToolTip(szLangTip);
793  pSheetGeneral->AddElement(pLangInfoLabel);
794  UpdateLanguage();
795  // font
796  const char *szFontTip = LoadResStr("IDS_DESC_SELECTFONT");
797  C4GUI::ComponentAligner caFontBox(caSheetProgram.GetGridCell(0,1,2,7,-1,C4GUI::ComboBox::GetDefaultHeight(), true), 0, 0, false);
798  StdStrBuf sFontStr; sFontStr.Copy(LoadResStr("IDS_CTL_FONT")); sFontStr.AppendChar(':');
799  pUseFont->GetTextExtent(sFontStr.getData(), w,q,true);
800  pLbl = new C4GUI::Label(sFontStr.getData(), caFontBox.GetFromLeft(w+C4GUI_DefDlgSmallIndent), ALeft, C4StartupFontClr, pUseFont, false);
801  pLbl->SetToolTip(szFontTip);
802  pSheetGeneral->AddElement(pLbl);
803  pUseFont->GetTextExtent("Comic Sans MS", w,q,true);
804  pFontFaceCombo = new C4GUI::ComboBox(caFontBox.GetFromLeft(std::min<int32_t>(caFontBox.GetInnerWidth()*3/4, w*3)));
805  pFontFaceCombo->SetToolTip(szFontTip);
806  pFontFaceCombo->SetComboCB(new C4GUI::ComboBox_FillCallback<C4StartupOptionsDlg>(this, &C4StartupOptionsDlg::OnFontFaceComboFill, &C4StartupOptionsDlg::OnFontComboSelChange));
808  pFontFaceCombo->SetFont(pUseFont);
809  pFontFaceCombo->SetDecoration(&(C4Startup::Get()->Graphics.fctContext));
811  pSheetGeneral->AddElement(pFontFaceCombo);
812  pFontSizeCombo = new C4GUI::ComboBox(caFontBox.GetFromLeft(std::min<int32_t>(caFontBox.GetInnerWidth(), w)));
813  pFontSizeCombo->SetToolTip(LoadResStr("IDS_DESC_FONTSIZE"));
814  pFontSizeCombo->SetComboCB(new C4GUI::ComboBox_FillCallback<C4StartupOptionsDlg>(this, &C4StartupOptionsDlg::OnFontSizeComboFill, &C4StartupOptionsDlg::OnFontComboSelChange));
816  pFontSizeCombo->SetFont(pUseFont);
817  pFontSizeCombo->SetDecoration(&(C4Startup::Get()->Graphics.fctContext));
818  pSheetGeneral->AddElement(pFontSizeCombo);
819  UpdateFontControls();
820  // MM timer
821  pCheck = new BoolConfig(caSheetProgram.GetGridCell(0,1,3,7,-1,iCheckHgt, true), LoadResStr("IDS_CTL_MMTIMER"), nullptr, &Config.General.MMTimer, true, &Config.Startup.HideMsgMMTimerChange);
822  pCheck->SetToolTip(LoadResStr("IDS_MSG_MMTIMER_DESC"));
824  pSheetGeneral->AddElement(pCheck);
825  // reset configuration
826  const char *szBtnText = LoadResStr("IDS_BTN_RESETCONFIG");
828  ::GraphicsResource.CaptionFont.GetTextExtent(szBtnText, iButtonWidth, iButtonHeight, true);
829  C4Rect rcResetBtn = caSheetProgram.GetGridCell(1,2,6,7, std::min<int32_t>(iButtonWidth+iButtonHeight*4, caSheetProgram.GetInnerWidth()*2/5), SmallButton::GetDefaultButtonHeight(), true);
830  pSmallBtn = new C4GUI::CallbackButton<C4StartupOptionsDlg, SmallButton>(szBtnText, rcResetBtn, &C4StartupOptionsDlg::OnResetConfigBtn, this);
831  pSheetGeneral->AddElement(pSmallBtn);
832  pSmallBtn->SetToolTip(LoadResStr("IDS_DESC_RESETCONFIG"));
833 
834  // --- page graphics
835  C4GUI::ComponentAligner caSheetGraphics(pSheetGraphics->GetClientRect(), iIndentX1, iIndentY1, true);
836  // --subgroup display
837  C4GUI::GroupBox *pGroupResolution = new C4GUI::GroupBox(caSheetGraphics.GetGridCell(0,1,0,2));
838  pGroupResolution->SetTitle(LoadResStrNoAmp("IDS_CTL_DISPLAY"));
839  pGroupResolution->SetFont(pUseFont);
841  pSheetGraphics->AddElement(pGroupResolution);
842  C4GUI::ComponentAligner caGroupResolution(pGroupResolution->GetClientRect(), iIndentX1, iIndentY2, true);
843  int32_t iNumGfxOptions = 3, iOpt = 0;
844  // resolution combobox
845  C4GUI::ComponentAligner resBox(caGroupResolution.GetGridCell(0,1,iOpt++,iNumGfxOptions), 0, 0, false);
846  w=20; q=12; pUseFont->GetTextExtent(LoadResStr("IDS_CTL_RESOLUTION"), w,q, true);
847  pGroupResolution->AddElement(new C4GUI::Label(LoadResStr("IDS_CTL_RESOLUTION"), resBox.GetFromLeft(w+C4GUI_DefDlgSmallIndent,q), ALeft, C4StartupFontClr, pUseFont, false, false));
848  pUseFont->GetTextExtent("1600 x 1200", w,q,true); w = std::min<int32_t>(caGroupResolution.GetInnerWidth(), w+40);
850  pGfxResCombo->SetToolTip(LoadResStr("IDS_MSG_RESOLUTION_DESC"));
851  pGfxResCombo->SetComboCB(new C4GUI::ComboBox_FillCallback<C4StartupOptionsDlg>(this, &C4StartupOptionsDlg::OnGfxResComboFill, &C4StartupOptionsDlg::OnGfxResComboSelChange));
853  pGfxResCombo->SetFont(pUseFont);
854  pGfxResCombo->SetDecoration(&(C4Startup::Get()->Graphics.fctContext));
855  pGfxResCombo->SetText(GetGfxResString(Config.Graphics.ResX, Config.Graphics.ResY).getData());
856  pGroupResolution->AddElement(pGfxResCombo);
857  // fullscreen combobox
858  C4GUI::ComponentAligner fsBox(caGroupResolution.GetGridCell(0,1,iOpt++,iNumGfxOptions), 0, 0, false);
859  w=20; q=12; pUseFont->GetTextExtent(LoadResStr("IDS_CTL_FULLSCREENMODE"), w,q, true);
860  pGroupResolution->AddElement(new C4GUI::Label(LoadResStr("IDS_CTL_FULLSCREENMODE"), fsBox.GetFromLeft(w+C4GUI_DefDlgSmallIndent,q), ALeft, C4StartupFontClr, pUseFont, false, false));
861  uint32_t wmax = 0;
862  for(int i = 0; i < 3; ++i)
863  {
864  pUseFont->GetTextExtent(GetWindowedName(i),w,q,true);
865  wmax = std::max<int32_t>(w, wmax);
866  }
868  pCombo->SetComboCB(new C4GUI::ComboBox_FillCallback<C4StartupOptionsDlg>(this, &C4StartupOptionsDlg::OnWindowedModeComboFill, &C4StartupOptionsDlg::OnWindowedModeComboSelChange));
869  pCombo->SetToolTip(LoadResStr("IDS_MSG_FULLSCREEN_DESC"));
871  pCombo->SetFont(pUseFont);
872  pCombo->SetDecoration(&(C4Startup::Get()->Graphics.fctContext));
873  pCombo->SetText(GetWindowedName());
874  pGroupResolution->AddElement(pCombo);
875  // --subgroup options
876  iNumGfxOptions = 5, iOpt=0;
877  C4GUI::GroupBox *pGroupOptions = new C4GUI::GroupBox(caSheetGraphics.GetGridCell(0,1,1,2));
878  pGroupOptions->SetTitle(LoadResStrNoAmp("IDS_DLG_OPTIONS"));
879  pGroupOptions->SetFont(pUseFont);
881  pSheetGraphics->AddElement(pGroupOptions);
882  C4GUI::ComponentAligner caGroupOptions(pGroupOptions->GetClientRect(), iIndentX1, iIndentY2, true);
883  // multisampling
884  C4GUI::ComponentAligner msBox(caGroupOptions.GetFromTop(C4GUI::ComboBox::GetDefaultHeight()), 0, 0, false);
885  w=20; q=12; pUseFont->GetTextExtent(LoadResStr("IDS_CTL_ANTIALIASING"), w,q, true);
886  pGroupOptions->AddElement(new C4GUI::Label(LoadResStr("IDS_CTL_ANTIALIASING"), msBox.GetFromLeft(w+C4GUI_DefDlgSmallIndent), ALeft, C4StartupFontClr, pUseFont, false, false));
887 
888  pUseFont->GetTextExtent("Off", w, q, true);
890  pGfxMSCombo->SetToolTip(LoadResStr("IDS_MSG_ANTIALIASING_DESC"));
891  pGfxMSCombo->SetComboCB(new C4GUI::ComboBox_FillCallback<C4StartupOptionsDlg>(this, &C4StartupOptionsDlg::OnGfxMSComboFill, &C4StartupOptionsDlg::OnGfxMSComboSelChange));
893  pGfxMSCombo->SetFont(pUseFont);
894  pGfxMSCombo->SetDecoration(&(C4Startup::Get()->Graphics.fctContext));
895  // Pre-Select current setting
896  StdStrBuf Current;
898  else Current.Copy("Off");
899  pGfxMSCombo->SetText(Current.getData());
900  // Set control read only if multisampling is not available
901  std::vector<int> multisamples;
903  pGfxMSCombo->SetReadOnly(multisamples.empty());
904  pGroupOptions->AddElement(pGfxMSCombo);
905  // automatic gfx frame skip
906  pCheck = new BoolConfig(caGroupOptions.GetGridCell(0,1,iOpt++,iNumGfxOptions,-1,iCheckHgt,true), LoadResStr("IDS_MSG_AUTOFRAMESKIP"), nullptr, &Config.Graphics.AutoFrameSkip);
907  pCheck->SetToolTip(LoadResStr("IDS_DESC_AUTOFRAMESKIP"));
909  pGroupOptions->AddElement(pCheck);
910 
911  // --- page sound
912  C4GUI::ComponentAligner caSheetSound(pSheetSound->GetClientRect(), iIndentX1, iIndentY1, true);
913  if (!C4GUI::CheckBox::GetStandardCheckBoxSize(&iCheckWdt, &iCheckHgt, "Lorem ipsum", pUseFont)) { iCheckWdt=100; iCheckHgt=20; }
914  int32_t iGridWdt = iCheckWdt * 2, iGridHgt = iCheckHgt * 5/2;
915  // --subgroup menu system sound
916  C4GUI::GroupBox *pGroupFESound = new C4GUI::GroupBox(caSheetSound.GetGridCell(0,2,0,5, iGridWdt, iGridHgt, false, 1,2));
917  pGroupFESound->SetTitle(LoadResStrNoAmp("IDS_CTL_FRONTEND"));
918  pGroupFESound->SetFont(pUseFont);
920  pSheetSound->AddElement(pGroupFESound);
921  C4GUI::ComponentAligner caGroupFESound(pGroupFESound->GetClientRect(), iIndentX1, iIndentY2, true);
922  // menu system music
923  pCheck = pFEMusicCheck = new C4GUI::CheckBox(caGroupFESound.GetGridCell(0,1,0,2,-1,iCheckHgt,true), LoadResStr("IDS_CTL_MUSIC"), !!Config.Sound.FEMusic);
924  pCheck->SetToolTip(LoadResStr("IDS_DESC_MENUMUSIC"));
926  pCheck->SetOnChecked(new C4GUI::CallbackHandler<C4StartupOptionsDlg>(this, &C4StartupOptionsDlg::OnFEMusicCheck));
927  pGroupFESound->AddElement(pCheck);
928  // menu system sound effects
929  pCheck = pFESoundCheck = new BoolConfig(caGroupFESound.GetGridCell(0,1,1,2,-1,iCheckHgt,true), LoadResStr("IDS_CTL_SOUNDFX"), nullptr, &Config.Sound.FESamples);
930  pCheck->SetToolTip(LoadResStr("IDS_DESC_MENUSOUND"));
932  pGroupFESound->AddElement(pCheck);
933  // --subgroup game sound
934  C4GUI::GroupBox *pGroupRXSound = new C4GUI::GroupBox(caSheetSound.GetGridCell(1,2,0,5, iGridWdt, iGridHgt, false, 1,2));
935  pGroupRXSound->SetTitle(LoadResStrNoAmp("IDS_CTL_GAME"));
936  pGroupRXSound->SetFont(pUseFont);
938  pSheetSound->AddElement(pGroupRXSound);
939  C4GUI::ComponentAligner caGroupRXSound(pGroupRXSound->GetClientRect(), iIndentX1, iIndentY2, true);
940  // game music
941  pCheck = new BoolConfig(caGroupRXSound.GetGridCell(0,1,0,2,-1,iCheckHgt,true), LoadResStr("IDS_CTL_MUSIC"), nullptr, &Config.Sound.RXMusic);
942  pCheck->SetToolTip(LoadResStr("IDS_DESC_GAMEMUSIC"));
944  pGroupRXSound->AddElement(pCheck);
945  // game sound effects
946  pCheck = new C4GUI::CheckBox(caGroupRXSound.GetGridCell(0,1,1,2,-1,iCheckHgt,true), LoadResStr("IDS_CTL_SOUNDFX"), !!Config.Sound.RXSound);
947  pCheck->SetToolTip(LoadResStr("IDS_DESC_GAMESOUND"));
949  pCheck->SetOnChecked(new C4GUI::CallbackHandler<C4StartupOptionsDlg>(this, &C4StartupOptionsDlg::OnRXSoundCheck));
950  pGroupRXSound->AddElement(pCheck);
951  // -- subgroup volume
952  C4GUI::GroupBox *pGroupVolume = new C4GUI::GroupBox(caSheetSound.GetGridCell(0,2,2,5, iGridWdt, iGridHgt, false, 2,3));
953  pGroupVolume->SetTitle(LoadResStrNoAmp("IDS_BTN_VOLUME"));
954  pGroupVolume->SetFont(pUseFont);
956  pSheetSound->AddElement(pGroupVolume);
957  C4GUI::ComponentAligner caGroupVolume(pGroupVolume->GetClientRect(), iIndentX1, iIndentY2, true);
958  // volume sliders
959  int32_t i;
960  for (i=0; i<2; ++i)
961  {
962  StdStrBuf sLabelTxt;
963  C4GUI::ComponentAligner caVolumeSlider(caGroupVolume.GetGridCell(0,1,i,2, -1, pUseFont->GetLineHeight()+iIndentY2*2+C4GUI_ScrollBarHgt, true), 1,0,false);
964  pGroupVolume->AddElement(new C4GUI::Label(FormatString("%s:", LoadResStr(i ? "IDS_CTL_SOUNDFX" : "IDS_CTL_MUSIC")).getData(), caVolumeSlider.GetFromTop(pUseFont->GetLineHeight()), ALeft, C4StartupFontClr, pUseFont, false, false));
965  sLabelTxt.Copy(LoadResStr("IDS_CTL_SILENT"));
966  w=20; q=12; pUseFont->GetTextExtent(sLabelTxt.getData(), w,q, true);
967  pGroupVolume->AddElement(new C4GUI::Label(sLabelTxt.getData(), caVolumeSlider.GetFromLeft(w,q), ACenter, C4StartupFontClr, pUseFont, false, false));
968  sLabelTxt.Copy(LoadResStr("IDS_CTL_LOUD"));
969  pUseFont->GetTextExtent(sLabelTxt.getData(), w,q, true);
970  pGroupVolume->AddElement(new C4GUI::Label(sLabelTxt.getData(), caVolumeSlider.GetFromRight(w,q), ACenter, C4StartupFontClr, pUseFont, false, false));
971  auto *pCB = new C4GUI::ParCallbackHandler<C4StartupOptionsDlg, int32_t>(this, i ? &C4StartupOptionsDlg::OnSoundVolumeSliderChange : &C4StartupOptionsDlg::OnMusicVolumeSliderChange);
972  auto *pSlider = new C4GUI::ScrollBar(caVolumeSlider.GetCentered(caVolumeSlider.GetInnerWidth(), C4GUI_ScrollBarHgt), true, pCB, 101);
973  pSlider->SetDecoration(&C4Startup::Get()->Graphics.sfctBookScroll, false);
974  pSlider->SetToolTip(i ? LoadResStr("IDS_DESC_VOLUMESOUND") : LoadResStr("IDS_DESC_VOLUMEMUSIC"));
975  pSlider->SetScrollPos(i ? Config.Sound.SoundVolume : Config.Sound.MusicVolume);
976  pGroupVolume->AddElement(pSlider);
977  }
978 
979  // --- page controls
980  pSheetControls->AddElement(pControlConfigArea = new ControlConfigArea(pSheetControls->GetClientRect(), caMain.GetWidth()/20, caMain.GetHeight()/40, false, this));
981 
982  // --- page network
983  int iPortCfgWdt=200, iPortCfgHgt=48; NetworkPortConfig::GetControlSize(&iPortCfgWdt, &iPortCfgHgt);
984  int iServerCfgWdt = 120, iServerCfgHgt = 20, iServerCfgWdtMid = 0;
985  StdStrBuf sServerText; sServerText.Copy(LoadResStr("IDS_CTL_USEOTHERSERVER"));
986  NetworkServerAddressConfig::GetControlSize(&iServerCfgWdt, &iServerCfgHgt, &iServerCfgWdtMid, sServerText.getData());
987  int32_t net_component_hgt = iPortCfgHgt * 4 + 2 * iServerCfgHgt + 3 * pUseFont->GetLineHeight();
988  C4GUI::ComponentAligner caSheetNetwork(pSheetNetwork->GetClientRect(), caMain.GetWidth() / 20, std::max<int32_t>(0, (caMain.GetHeight() - net_component_hgt)/20), true);
989  pPortCfgTCP = new NetworkPortConfig(caSheetNetwork.GetGridCell(0,2,0,2, iPortCfgWdt, iPortCfgHgt), LoadResStr("IDS_NET_PORT_TCP"), &(Config.Network.PortTCP), C4NetStdPortTCP);
990  pPortCfgUDP = new NetworkPortConfig(caSheetNetwork.GetGridCell(1,2,0,2, iPortCfgWdt, iPortCfgHgt), LoadResStr("IDS_NET_PORT_UDP"), &(Config.Network.PortUDP), C4NetStdPortUDP);
991  pPortCfgRef = new NetworkPortConfig(caSheetNetwork.GetGridCell(0,2,1,2, iPortCfgWdt, iPortCfgHgt), LoadResStr("IDS_NET_PORT_REFERENCE"), &(Config.Network.PortRefServer), C4NetStdPortRefServer);
992  pPortCfgDsc = new NetworkPortConfig(caSheetNetwork.GetGridCell(1,2,1,2, iPortCfgWdt, iPortCfgHgt), LoadResStr("IDS_NET_PORT_DISCOVERY"), &(Config.Network.PortDiscovery), C4NetStdPortDiscovery);
993  pPortCfgTCP->SetToolTip(LoadResStr("IDS_NET_PORT_TCP_DESC"));
994  pPortCfgUDP->SetToolTip(LoadResStr("IDS_NET_PORT_UDP_DESC"));
995  pPortCfgRef->SetToolTip(LoadResStr("IDS_NET_PORT_REFERENCE_DESC"));
996  pPortCfgDsc->SetToolTip(LoadResStr("IDS_NET_PORT_DISCOVERY_DESC"));
997  pSheetNetwork->AddElement(pPortCfgTCP);
998  pSheetNetwork->AddElement(pPortCfgUDP);
999  pSheetNetwork->AddElement(pPortCfgRef);
1000  pSheetNetwork->AddElement(pPortCfgDsc);
1001  int iNetHgt0=pPortCfgDsc->GetBounds().GetBottom();
1002  caSheetNetwork.ExpandTop(-iNetHgt0);
1003  pLeagueServerCfg = new NetworkServerAddressConfig(caSheetNetwork.GetFromTop(iServerCfgHgt), sServerText.getData(), &(Config.Network.UseAlternateServer), Config.Network.AlternateServerAddress, iServerCfgWdtMid);
1004  pLeagueServerCfg->SetToolTip(LoadResStr("IDS_NET_MASTERSRV_DESC"));
1005  pSheetNetwork->AddElement(pLeagueServerCfg);
1006  pModDatabaseServerCfg = new NetworkModDatabaseServerAddressConfig(caSheetNetwork.GetFromTop(iServerCfgHgt), LoadResStr("IDS_CTL_USEOTHERMODSDATABASESERVER"), &(Config.Network.UseAlternateModDatabaseServer), Config.Network.AlternateModDatabaseServerAddress, iServerCfgWdtMid);
1007  pModDatabaseServerCfg->SetToolTip(LoadResStr("IDS_NET_USEOTHERMODSDATABASESERVER_DESC"));
1008  pSheetNetwork->AddElement(pModDatabaseServerCfg);
1009 #ifdef WITH_AUTOMATIC_UPDATE
1010  pCheck = new BoolConfig(caSheetNetwork.GetFromTop(pUseFont->GetLineHeight()), LoadResStr("IDS_CTL_AUTOMATICUPDATES"), nullptr, &Config.Network.AutomaticUpdate, false);
1011  pCheck->SetToolTip(LoadResStr("IDS_DESC_AUTOMATICUPDATES"));
1013  pSheetNetwork->AddElement(pCheck);
1014 #endif
1015  pCheck = new BoolConfig(caSheetNetwork.GetFromTop(pUseFont->GetLineHeight()), LoadResStr("IDS_CTL_UPNP"), nullptr, &Config.Network.EnableUPnP, false);
1016  pCheck->SetToolTip(LoadResStr("IDS_DESC_UPNP"));
1018  pSheetNetwork->AddElement(pCheck);
1019  pCheck = new BoolConfig(caSheetNetwork.GetFromTop(pUseFont->GetLineHeight()), LoadResStr("IDS_CTL_PACKETLOGGING"), nullptr, &Config.Network.PacketLogging, false);
1020  pCheck->SetToolTip(LoadResStr("IDS_DESC_PACKETLOGGING"));
1022  pSheetNetwork->AddElement(pCheck);
1023  const char *szNameCfgText = LoadResStr("IDS_NET_USERNAME");
1024  int iNameCfgWdt=200, iNameCfgHgt=48; C4StartupOptionsDlg::EditConfig::GetControlSize(&iNameCfgWdt, &iNameCfgHgt, szNameCfgText, false);
1025  iNameCfgWdt += 5;
1026  pNetworkNickEdit = new EditConfig(caSheetNetwork.GetFromTop(iNameCfgHgt), szNameCfgText, &Config.Network.Nick, nullptr, false);
1027  pNetworkNickEdit->SetToolTip(LoadResStr("IDS_NET_USERNAME_DESC"));
1028  pSheetNetwork->AddElement(pNetworkNickEdit);
1029 
1030  StdCopyStrBuf NickBuf(Config.Network.Nick);
1031  if (!NickBuf.getLength()) NickBuf.Copy(Config.GetRegistrationData("Nick"));
1032  pNetworkNickEdit->GetEdit()->SetText(NickBuf.getData(), false);
1033 
1034  // initial focus is on tab selection
1035  SetFocus(pOptionsTabular, false);
1036 }
1037 
1039 {
1040  delete pKeyToggleMusic;
1041  delete pKeyBack;
1042 }
1043 
1045 {
1046  // callback when dlg got closed - save config
1047  SaveConfig(true, false);
1049 }
1050 
1051 void C4StartupOptionsDlg::OnResetConfigBtn(C4GUI::Control *btn)
1052 {
1053  // confirmation
1054  StdStrBuf sWarningText; sWarningText.Copy(LoadResStr("IDS_MSG_PROMPTRESETCONFIG"));
1055  sWarningText.AppendChar('|');
1056  sWarningText.Append(LoadResStr("IDS_MSG_RESTARTCHANGECFG"));
1057  if (!GetScreen()->ShowMessageModal(sWarningText.getData(), LoadResStr("IDS_BTN_RESETCONFIG"), C4GUI::MessageDialog::btnYesNo, C4GUI::Ico_Notify))
1058  // user cancelled
1059  return;
1060  // reset cfg
1061  Config.Default();
1062  Config.ConfigLoaded = true;
1063  // engine must be restarted now, because some crucial fields such as resolution and used gfx engine do not match their initialization
1064  Application.Quit();
1065 }
1066 
1067 void C4StartupOptionsDlg::OnGfxMSComboFill(C4GUI::ComboBox_FillCB *pFiller)
1068 {
1069  // clear all old entries first to allow a clean refill
1070  pFiller->ClearEntries();
1071 
1072  pFiller->AddEntry("Off", 0);
1073 
1074  std::vector<int> multisamples;
1075  Application.pWindow->EnumerateMultiSamples(multisamples);
1076 
1077  std::sort(multisamples.begin(), multisamples.end());
1078  for(int multisample : multisamples)
1079  {
1080  StdStrBuf text;
1081  text.Format("%dx", multisample);
1082  pFiller->AddEntry(text.getData(), multisample);
1083  }
1084 }
1085 
1086 bool C4StartupOptionsDlg::OnGfxMSComboSelChange(C4GUI::ComboBox *pForCombo, int32_t idNewSelection)
1087 {
1088  if(pTexMgr) pTexMgr->IntLock();
1089 #ifndef USE_CONSOLE
1091  // Note: This assumes there is only one GL context (the main context). This
1092  // is true in fullscreen mode, and since the startup dlg is only shown in
1093  // fullscreen mode we are safe this way.
1094  if(pGL) pGL->pMainCtx->Clear(true);
1095 #endif
1096  int32_t PrevMultiSampling = Config.Graphics.MultiSampling;
1097  Config.Graphics.MultiSampling = idNewSelection;
1098  bool success = Application.pWindow->ReInit(&Application);
1099 
1100 #ifndef USE_CONSOLE
1104 #endif
1105  if(pTexMgr) pTexMgr->IntUnlock();
1106  if(!success) Config.Graphics.MultiSampling = PrevMultiSampling;
1107  return !success;
1108 }
1109 
1110 void C4StartupOptionsDlg::OnGfxResComboFill(C4GUI::ComboBox_FillCB *pFiller)
1111 {
1112  // clear all old entries first to allow a clean refill
1113  pFiller->ClearEntries();
1114  pFiller->AddEntry(LoadResStr("IDS_MNU_DEFAULTRESOLUTION"), -1);
1115  // fill with all possible resolutions
1116  int32_t idx = 0, iXRes, iYRes, iBitDepth, iRefreshRate;
1117  while (Application.GetIndexedDisplayMode(idx++, &iXRes, &iYRes, &iBitDepth, &iRefreshRate, Config.Graphics.Monitor))
1118 #ifdef _WIN32 // why only WIN32?
1119  if (iBitDepth == C4Draw::COLOR_DEPTH)
1120 #endif
1121  {
1122  StdStrBuf sGfxString = GetGfxResString(iXRes, iYRes);
1123  if (!pFiller->FindEntry(sGfxString.getData()))
1124  pFiller->AddEntry(sGfxString.getData(), iXRes + (uint32_t(iYRes) << 12) + (uint32_t(iRefreshRate) << 24));
1125  }
1126 }
1127 
1128 bool C4StartupOptionsDlg::OnGfxResComboSelChange(C4GUI::ComboBox *pForCombo, int32_t idNewSelection)
1129 {
1130  // get new resolution from string
1131  int iResX=(idNewSelection & 0xfff), iResY=(uint32_t(idNewSelection) >> 12) & 0xfff, iRefreshRate = (uint32_t(idNewSelection) >> 24) & 0xff;
1132  if (idNewSelection == -1)
1133  {
1134  iResX = iResY = -1;
1135  iRefreshRate = 0;
1136  }
1137 
1138  // different than current?
1139  if (iResX == Config.Graphics.ResX && iResY == Config.Graphics.ResY && iRefreshRate == Config.Graphics.RefreshRate) return true;
1140 
1141  // try setting it
1142  if (!TryNewResolution(iResX, iResY, iRefreshRate))
1143  {
1144  // didn't work or declined by user
1145  return true; // do not change label, because dialog might hae been recreated!
1146  }
1147  // dialog has been recreated; so do not change the combo label
1148  return true;
1149 }
1150 
1151 bool C4StartupOptionsDlg::TryNewResolution(int32_t iResX, int32_t iResY, int32_t iRefreshRate)
1152 {
1153  int32_t iOldResX = Config.Graphics.ResX, iOldResY = Config.Graphics.ResY;
1154  int32_t iOldRefreshRate = Config.Graphics.RefreshRate;
1155  int32_t iOldFontSize = Config.General.RXFontSize;
1156  C4GUI::Screen *pScreen = GetScreen();
1157  // resolution change may imply font size change
1158  int32_t iNewFontSize = 14; // default (at 800x600)
1159  if (iResY >= 0 && iResY < 600)
1160  iNewFontSize = 12;
1161  else if (iResY > 800)
1162  iNewFontSize = 16;
1163  // call application to set it
1164  if (!Application.SetVideoMode(iResX, iResY, iRefreshRate, Config.Graphics.Monitor, !Config.Graphics.Windowed))
1165  {
1166  StdCopyStrBuf strChRes(LoadResStr("IDS_MNU_SWITCHRESOLUTION"));
1167  pScreen->ShowMessage(FormatString(LoadResStr("IDS_ERR_SWITCHRES"), Application.GetLastError()).getData(), strChRes.getData(), C4GUI::Ico_Clonk, nullptr);
1168  return false;
1169  }
1170  // implied font change
1171  if (iNewFontSize != iOldFontSize)
1172  if (!Application.SetGameFont(Config.General.RXFontName, iNewFontSize))
1173  {
1174  // not changing font size is not fatal - just keep old size
1175  iNewFontSize = iOldFontSize;
1176  }
1177  // Set new resolution in config before dialog recreation so that the initial combo box value is correct (#230)
1178  Config.Graphics.ResX = iResX;
1179  Config.Graphics.ResY = iResY;
1180  Config.Graphics.RefreshRate = iRefreshRate;
1181  // since the resolution was changed, everything needs to be moved around a bit
1182  RecreateDialog(false);
1183  // Now set old resolution again to make sure config is restored even if the program is closed during the confirmation dialog
1184  Config.Graphics.ResX = iOldResX;
1185  Config.Graphics.ResY = iOldResY;
1186  Config.Graphics.RefreshRate = iOldRefreshRate;
1187  // Show confirmation dialog
1188  ResChangeConfirmDlg *pConfirmDlg = new ResChangeConfirmDlg();
1189  if (!pScreen->ShowModalDlg(pConfirmDlg, true))
1190  {
1191  // abort: Restore screen, if this was not some program abort
1192  if (Application.SetVideoMode(iOldResX, iOldResY, iOldRefreshRate, Config.Graphics.Monitor, !Config.Graphics.Windowed))
1193  {
1194  if (iNewFontSize != iOldFontSize) Application.SetGameFont(Config.General.RXFontName, iOldFontSize);
1195  RecreateDialog(false);
1196  }
1197 
1198  return false;
1199  }
1200  // resolution may be kept!
1201  Config.Graphics.ResX = iResX;
1202  Config.Graphics.ResY = iResY;
1203  Config.Graphics.RefreshRate = iRefreshRate;
1206  return true;
1207 }
1208 
1209 StdStrBuf C4StartupOptionsDlg::GetGfxResString(int32_t iResX, int32_t iResY)
1210 {
1211  // Display in format like "640 x 480"
1212  if (iResX == -1)
1213  return StdStrBuf(LoadResStr("IDS_MNU_DEFAULTRESOLUTION"));
1214  return FormatString("%d x %d", (int)iResX, (int)iResY);
1215 }
1216 
1217 const char * C4StartupOptionsDlg::GetWindowedName(int32_t mode /* = -1*/)
1218 {
1219  if(mode == -1)
1220  mode = Config.Graphics.Windowed;
1221  if(mode == 0) return LoadResStr("IDS_MSG_FULLSCREEN");
1222  else if(mode == 1) return LoadResStr("IDS_MSG_WINDOWED");
1223  else if(mode == 2) return LoadResStr("IDS_MSG_AUTOWINDOWED");
1224  assert(!"Requested name for config value which does not exist");
1225  return "ERR: Unknown";
1226 }
1227 
1228 void C4StartupOptionsDlg::OnWindowedModeComboFill(C4GUI::ComboBox_FillCB *pFiller)
1229 {
1230  pFiller->ClearEntries();
1231  for(int32_t i = 0; i < 3; ++i)
1232  pFiller->AddEntry(GetWindowedName(i), i);
1233 }
1234 
1235 bool C4StartupOptionsDlg::OnWindowedModeComboSelChange(C4GUI::ComboBox *pForCombo, int32_t idNewSelection)
1236 {
1237  Config.Graphics.Windowed = idNewSelection;
1239  pForCombo->SetText(GetWindowedName(idNewSelection));
1240  return true;
1241 }
1242 
1243 bool C4StartupOptionsDlg::SaveConfig(bool fForce, bool fKeepOpen)
1244 {
1245  // prevent double save
1246  if (fConfigSaved) return true;
1247  // save any config fields that are not stored directly; return whether all values are OK
1248  // check port validity
1249  if (!fForce)
1250  {
1251  StdCopyStrBuf strError(LoadResStr("IDS_ERR_CONFIG"));
1252  if (pPortCfgTCP->GetPort()>0 && pPortCfgTCP->GetPort() == pPortCfgRef->GetPort())
1253  {
1254  GetScreen()->ShowMessage(LoadResStr("IDS_NET_ERR_PORT_TCPREF"), strError.getData(), C4GUI::Ico_Error);
1255  return false;
1256  }
1257  if (pPortCfgUDP->GetPort()>0 && pPortCfgUDP->GetPort() == pPortCfgDsc->GetPort())
1258  {
1259  GetScreen()->ShowMessage(LoadResStr("IDS_NET_ERR_PORT_UDPDISC"), strError.getData(), C4GUI::Ico_Error);
1260  return false;
1261  }
1262  }
1263  // store some config values
1264  pPortCfgTCP->SavePort();
1265  pPortCfgUDP->SavePort();
1266  pPortCfgRef->SavePort();
1267  pPortCfgDsc->SavePort();
1268  pLeagueServerCfg->Save2Config();
1269  pModDatabaseServerCfg->Save2Config();
1270  pNetworkNickEdit->Save2Config();
1271  // if nick is same as default by registry, don't save in config
1272  // so regkey updates will change the nick as well
1273  const char *szRegNick = Config.GetRegistrationData("Nick");
1274  if (SEqual(Config.Network.Nick.getData(), szRegNick)) Config.Network.Nick.Clear();
1275  // make sure config is saved, in case the game crashes later on or another instance is started
1276  Config.Save();
1277  if (!fKeepOpen) fConfigSaved = true;
1278  // done; config OK
1279  return true;
1280 }
1281 
1283 {
1284  if (!SaveConfig(false, false)) return;
1285  // back 2 main
1287 }
1288 
1289 bool C4StartupOptionsDlg::SetSubscreen(const char *szToScreen)
1290 {
1291  // go to specified property sheet
1292  // option sheets do not have a good identifier associated to them - just lookup from a static array
1293  const char *page_names[] = { "general", "graphics", "sound", "controls", "network", nullptr };
1294  int32_t i = 0;
1295  while (page_names[i])
1296  {
1297  if (SEqualNoCase(szToScreen, page_names[i])) break;
1298  ++i;
1299  }
1300  // page name does not match?
1301  if (!page_names[i]) return false;
1302  // page name OK; switch it
1303  pOptionsTabular->SelectSheet(i, false);
1304  return true;
1305 }
1306 
1307 void C4StartupOptionsDlg::UpdateLanguage()
1308 {
1309  // find currently specified language in language list and display its info
1311  if (pNfo)
1312  {
1313  pLangCombo->SetText(FormatString("%s - %s", pNfo->Code, pNfo->Name).getData());
1314  pLangInfoLabel->SetText(pNfo->Info);
1315  }
1316  else
1317  {
1318  pLangCombo->SetText(FormatString("unknown (%s)", Config.General.Language).getData());
1319  pLangInfoLabel->SetText(LoadResStr("IDS_CTL_NOLANGINFO"));
1320  return; // no need to mess with fallbacks
1321  }
1322  // update language fallbacks
1323  char *szLang = Config.General.LanguageEx;
1324  SCopy(pNfo->Code, szLang);
1325  if (*(pNfo->Fallback))
1326  {
1327  SAppend(",", szLang);
1328  Config.General.GetLanguageSequence(pNfo->Fallback, szLang + SLen(szLang));
1329  }
1330  // internal fallbacks
1331  if (!SSearch(Config.General.LanguageEx, "US"))
1332  {
1333  if (*szLang) SAppendChar(',', szLang);
1334  SAppend("US", szLang);
1335  }
1336  if (!SSearch(Config.General.LanguageEx, "DE"))
1337  {
1338  if (*szLang) SAppendChar(',', szLang);
1339  SAppend("DE", szLang);
1340  }
1341 }
1342 
1343 void C4StartupOptionsDlg::OnLangComboFill(C4GUI::ComboBox_FillCB *pFiller)
1344 {
1345  // fill with all possible languages
1346  C4LanguageInfo *pNfo;
1347  for (int i=0; i<Languages.GetInfoCount(); ++i)
1348  if ((pNfo = Languages.GetInfo(i)))
1349  pFiller->AddEntry(FormatString("%s - %s", pNfo->Code, pNfo->Name).getData(), (unsigned char)(pNfo->Code[0]) + ((unsigned char)(pNfo->Code[1])<<8));
1350 }
1351 
1352 bool C4StartupOptionsDlg::OnLangComboSelChange(C4GUI::ComboBox *pForCombo, int32_t idNewSelection)
1353 {
1354  // set new language by two-character-code
1355  Config.General.Language[0] = idNewSelection & 0xff;
1356  Config.General.Language[1] = (idNewSelection & 0xff00) >> 8;
1357  Config.General.Language[2] = '\0';
1358  UpdateLanguage();
1360  Game.UpdateLanguage();
1361  // recreate everything to reflect language changes
1362  RecreateDialog(true);
1363  return true;
1364 }
1365 
1366 void C4StartupOptionsDlg::UpdateFontControls()
1367 {
1368  // display current language and size in comboboxes
1369  pFontFaceCombo->SetText(Config.General.RXFontName);
1370  StdStrBuf sSize; sSize.Format("%d", (int) Config.General.RXFontSize);
1371  pFontSizeCombo->SetText(sSize.getData());
1372 }
1373 
1374 #ifdef _WIN32
1375 const char *DefaultFonts[] = { "Arial Unicode MS", "Comic Sans MS", C4DEFAULT_FONT_NAME, "Verdana", nullptr };
1376 #else
1377 const char *DefaultFonts[] = { C4DEFAULT_FONT_NAME, nullptr };
1378 #endif
1379 
1380 void C4StartupOptionsDlg::OnFontFaceComboFill(C4GUI::ComboBox_FillCB *pFiller)
1381 {
1382  // 2do: enumerate Fonts.txt fonts; then enumerate system fonts
1383  for (int32_t i=0; DefaultFonts[i]; ++i) pFiller->AddEntry(DefaultFonts[i], i);
1384 }
1385 
1386 void C4StartupOptionsDlg::OnFontSizeComboFill(C4GUI::ComboBox_FillCB *pFiller)
1387 {
1388  // 2do: enumerate possible font sizes by the font here
1389  // 2do: Hide font sizes that would be too large for the selected resolution
1390  pFiller->AddEntry("10", 10);
1391  pFiller->AddEntry("12", 12);
1392  pFiller->AddEntry("14", 14);
1393  pFiller->AddEntry("16", 16);
1394  pFiller->AddEntry("18", 18);
1395  pFiller->AddEntry("20", 20);
1396  pFiller->AddEntry("22", 22);
1397  pFiller->AddEntry("24", 24);
1398  pFiller->AddEntry("26", 26);
1399  pFiller->AddEntry("28", 28);
1400 }
1401 
1402 bool C4StartupOptionsDlg::OnFontComboSelChange(C4GUI::ComboBox *pForCombo, int32_t idNewSelection)
1403 {
1404  // set new value
1405  const char *szNewFontFace = Config.General.RXFontName;
1406  int32_t iNewFontSize = Config.General.RXFontSize;
1407  if (pForCombo == pFontFaceCombo)
1408  szNewFontFace = DefaultFonts[idNewSelection];
1409  else if (pForCombo == pFontSizeCombo)
1410  iNewFontSize = idNewSelection;
1411  else
1412  // can't happen
1413  return true;
1414  // set new fonts
1415  if (!Application.SetGameFont(szNewFontFace, iNewFontSize))
1416  {
1417  GetScreen()->ShowErrorMessage(LoadResStr("IDS_ERR_INITFONTS"));
1418  return true;
1419  }
1420  // recreate everything to reflect font changes
1421  RecreateDialog(true);
1422  return true;
1423 }
1424 
1426 {
1427  // MUST fade for now, or calling function will fail because dialog is deleted immediately
1428  fFade = true;
1429  // this actually breaks the possibility to go back :(
1430  int32_t iPage = pOptionsTabular->GetActiveSheetIndex();
1432  pNewDlg->pOptionsTabular->SelectSheet(iPage, false);
1433  pNewDlg->fCanGoBack = false;
1434 }
1435 
1436 void C4StartupOptionsDlg::OnFEMusicCheck(C4GUI::Element *pCheckBox)
1437 {
1438  // option change is reflected immediately
1439  bool fIsOn = static_cast<C4GUI::CheckBox *>(pCheckBox)->GetChecked();
1440  if ((Config.Sound.FEMusic = fIsOn))
1442  else
1444 }
1445 
1446 void C4StartupOptionsDlg::OnMusicVolumeSliderChange(int32_t iNewVal)
1447 {
1448  // option change is reflected immediately;
1449  Config.Sound.MusicVolume = iNewVal;
1451 }
1452 
1453 void C4StartupOptionsDlg::OnSoundVolumeSliderChange(int32_t iNewVal)
1454 {
1455  // sound system reads this value directly
1456  Config.Sound.SoundVolume = iNewVal;
1457  // test sound
1458  StartSoundEffect("Objects::Arrow::HitGround", false, 100, nullptr);
1459 }
1460 
1461 void C4StartupOptionsDlg::OnRXSoundCheck(C4GUI::Element *pCheckBox)
1462 {
1463  // toggling sounds on off must init/deinit sound system
1464  bool fIsOn = static_cast<C4GUI::CheckBox *>(pCheckBox)->GetChecked();
1465  if (fIsOn == !!Config.Sound.RXSound) return;
1466  if (fIsOn)
1467  {
1468  Config.Sound.RXSound = true;
1469  if (!Application.SoundSystem.Init())
1470  {
1471  GetScreen()->ShowMessage(StdCopyStrBuf(LoadResStr("IDS_PRC_NOSND")).getData(), StdCopyStrBuf(LoadResStr("IDS_DLG_LOG")).getData(), C4GUI::Ico_Error);
1473  Config.Sound.RXSound = false;
1474  static_cast<C4GUI::CheckBox *>(pCheckBox)->SetChecked(false);
1475  fIsOn = false;
1476  }
1477  }
1478  else
1479  {
1481  Config.Sound.RXSound = false;
1482  }
1483  // FE sound only enabled if global sound is enabled
1484  pFESoundCheck->SetEnabled(fIsOn);
1485  pFESoundCheck->SetChecked(fIsOn ? !!Config.Sound.FESamples : false);
1486 }
1487 
1489 {
1490  // do toggle
1492  // reflect in checkbox
1493  pFEMusicCheck->SetChecked(!!Config.Sound.FEMusic);
1494  // key processed
1495  return true;
1496 }
1497 
1499 {
1500  // keyboard layout changed and thus some keys might have been updated from scan codes
1501  // update display in control set
1502  pControlConfigArea->UpdateCtrlSet();
1503 }
C4Config Config
Definition: C4Config.cpp:930
@ CFG_MaxString
Definition: C4Config.h:28
#define C4DEFAULT_FONT_NAME
Definition: C4Config.h:27
C4Draw * pDraw
Definition: C4Draw.cpp:42
CStdGL * pGL
Definition: C4DrawGL.cpp:907
C4Game Game
Definition: C4Globals.cpp:52
C4Application Application
Definition: C4Globals.cpp:44
C4GraphicsResource GraphicsResource
C4GUIScreen * pGUI
Definition: C4Gui.cpp:1191
#define C4GUI_IconHgt
Definition: C4Gui.h:94
#define C4GUI_ButtonAreaHgt
Definition: C4Gui.h:113
#define C4GUI_DefDlgIndent
Definition: C4Gui.h:132
#define C4GUI_InactCaptionFontClr
Definition: C4Gui.h:39
#define C4GUI_DefButton2Wdt
Definition: C4Gui.h:115
#define C4GUI_CaptionFontClr
Definition: C4Gui.h:37
#define C4GUI_DefDlgSmallIndent
Definition: C4Gui.h:133
#define C4GUI_MessageFontClr
Definition: C4Gui.h:43
#define C4GUI_ScrollBarHgt
Definition: C4Gui.h:104
#define C4GUI_IconWdt
Definition: C4Gui.h:93
#define C4GUI_MessageDlgWdt
Definition: C4Gui.h:127
#define C4GUI_ButtonHgt
Definition: C4Gui.h:111
#define C4GUI_DefButton2HSpace
Definition: C4Gui.h:116
#define C4GUI_Caption2FontClr
Definition: C4Gui.h:38
bool KEY_IsModifier(C4KeyCode k)
const C4KeyCode KEY_Any
@ KEYSCOPE_Gui
@ KEYS_Shift
@ KEYS_Control
@ KEYS_None
@ KEYS_Alt
const C4KeyCode KEY_Undefined
bool Key_IsGamepad(C4KeyCode key)
bool Key_IsMouse(C4KeyCode key)
C4Language Languages
Definition: C4Language.cpp:42
const char * LoadResStrNoAmp(const char *id)
Definition: StdResStr2.cpp:23
const char * LoadResStr(const char *id)
Definition: C4Language.h:83
const int32_t C4MC_Button_None
const int32_t C4MC_Button_LeftDown
const int16_t C4NetStdPortRefServer
Definition: C4Network2.h:32
const int16_t C4NetStdPortDiscovery
Definition: C4Network2.h:31
const int16_t C4NetStdPortUDP
Definition: C4Network2.h:30
const int16_t C4NetStdPortTCP
Definition: C4Network2.h:29
C4SoundInstance * StartSoundEffect(const char *szSndName, bool fLoop, int32_t iVolume, C4Object *pObj, int32_t iCustomFalloffDistance, int32_t iPitch, C4SoundModifier *modifier)
const int32_t C4StartupFontClrDisabled
Definition: C4Startup.h:28
const int32_t C4StartupBtnBorderColor2
Definition: C4Startup.h:33
const int32_t C4StartupEditBorderColor
Definition: C4Startup.h:30
const int32_t C4StartupEditBGColor
Definition: C4Startup.h:29
const int32_t C4StartupFontClr
Definition: C4Startup.h:27
const int32_t C4StartupBtnFontClr
Definition: C4Startup.h:31
const int32_t C4StartupBtnBorderColor1
Definition: C4Startup.h:32
const char * DefaultFonts[]
C4TexMgr * pTexMgr
Definition: C4Surface.cpp:879
const int ALeft
Definition: C4Surface.h:41
#define C4GFXBLIT_ADDITIVE
Definition: C4Surface.h:26
const int ACenter
Definition: C4Surface.h:41
uint32_t DWORD
const char * SSearch(const char *szString, const char *szIndex)
Definition: Standard.cpp:369
void SCopy(const char *szSource, char *sTarget, size_t iMaxL)
Definition: Standard.cpp:152
bool SEqualNoCase(const char *szStr1, const char *szStr2, int iLen)
Definition: Standard.cpp:213
void SAppendChar(char cChar, char *szStr)
Definition: Standard.cpp:271
void SAppend(const char *szSource, char *szTarget, int iMaxL)
Definition: Standard.cpp:263
bool SEqual(const char *szStr1, const char *szStr2)
Definition: Standard.h:93
size_t SLen(const char *sptr)
Definition: Standard.h:74
StdStrBuf FormatString(const char *szFmt,...)
Definition: StdBuf.cpp:270
bool SetVideoMode(int iXRes, int iYRes, unsigned int iRefreshRate, unsigned int iMonitor, bool fFullScreen)
Definition: C4AppSDL.cpp:354
bool GetIndexedDisplayMode(int32_t iIndex, int32_t *piXRes, int32_t *piYRes, int32_t *piBitDepth, int32_t *piRefreshRate, uint32_t iMonitor)
Definition: C4AppSDL.cpp:335
C4Window * pWindow
Definition: C4App.h:80
const char * GetLastError()
Definition: C4App.h:98
C4MusicSystem MusicSystem
Definition: C4Application.h:41
int GetConfigWidth()
Definition: C4Application.h:83
int GetConfigHeight()
Definition: C4Application.h:84
void Quit() override
C4SoundSystem SoundSystem
Definition: C4Application.h:42
bool SetGameFont(const char *szFontFace, int32_t iFontSize)
C4PlayerControlAssignmentSets UserSets
Definition: C4Config.h:235
int32_t GamepadGuiControl
Definition: C4Config.h:233
char LanguageEx[CFG_MaxString+1]
Definition: C4Config.h:38
char Language[CFG_MaxString+1]
Definition: C4Config.h:37
int32_t MMTimer
Definition: C4Config.h:50
char RXFontName[CFG_MaxString+1]
Definition: C4Config.h:42
int32_t RXFontSize
Definition: C4Config.h:43
static int GetLanguageSequence(const char *source, char *target)
Definition: C4Config.cpp:817
int32_t ResX
Definition: C4Config.h:104
int32_t ResY
Definition: C4Config.h:104
int32_t RefreshRate
Definition: C4Config.h:106
int32_t AutoFrameSkip
Definition: C4Config.h:116
int32_t MultiSampling
Definition: C4Config.h:115
int32_t Windowed
Definition: C4Config.h:107
int32_t Monitor
Definition: C4Config.h:112
const char * GetRegistrationData(const char *field)
Definition: C4Config.h:285
C4ConfigGeneral General
Definition: C4Config.h:255
C4ConfigNetwork Network
Definition: C4Config.h:259
C4ConfigStartup Startup
Definition: C4Config.h:264
bool Save()
Definition: C4Config.cpp:439
C4ConfigControls Controls
Definition: C4Config.h:263
void Default()
Definition: C4Config.cpp:296
bool ConfigLoaded
Definition: C4Config.h:266
C4ConfigGraphics Graphics
Definition: C4Config.h:257
C4ConfigSound Sound
Definition: C4Config.h:258
int32_t UseAlternateModDatabaseServer
Definition: C4Config.h:163
int32_t PortUDP
Definition: C4Config.h:153
char AlternateModDatabaseServerAddress[CFG_MaxString+1]
Definition: C4Config.h:164
int32_t PacketLogging
Definition: C4Config.h:171
int32_t EnableUPnP
Definition: C4Config.h:154
int32_t PortRefServer
Definition: C4Config.h:153
int32_t PortDiscovery
Definition: C4Config.h:153
int32_t UseAlternateServer
Definition: C4Config.h:152
char AlternateServerAddress[CFG_MaxString+1]
Definition: C4Config.h:159
ValidatedStdCopyStrBuf< C4InVal::VAL_NameAllowEmpty > Nick
Definition: C4Config.h:156
int32_t PortTCP
Definition: C4Config.h:153
int32_t RXSound
Definition: C4Config.h:126
int32_t FEMusic
Definition: C4Config.h:128
int32_t FESamples
Definition: C4Config.h:129
int32_t SoundVolume
Definition: C4Config.h:132
int32_t MusicVolume
Definition: C4Config.h:131
int32_t RXMusic
Definition: C4Config.h:127
int32_t HideMsgNoOfficialLeague
Definition: C4Config.h:191
int32_t HideMsgMMTimerChange
Definition: C4Config.h:187
std::vector< C4KeyCodeEx > CodeList
virtual bool InvalidateDeviceObjects()=0
void DrawQuadDw(C4Surface *sfcTarget, float *ipVtx, DWORD dwClr1, DWORD dwClr2, DWORD dwClr3, DWORD dwClr4, C4ShaderCall *shader_call)
Definition: C4Draw.cpp:653
void SetBlitMode(DWORD dwBlitMode)
Definition: C4Draw.h:191
virtual bool RestoreDeviceObjects()=0
static constexpr int COLOR_DEPTH
Definition: C4Draw.h:89
void ResetBlitMode()
Definition: C4Draw.h:192
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 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
int32_t GetHeightByWidth(int32_t iWidth)
Definition: C4Facet.h:155
void SetFont(CStdFont *pFont, DWORD dwCustomFontClr=C4GUI_CaptionFontClr)
Definition: C4Gui.h:1132
void SetText(const char *szToText)
Definition: C4GuiButton.cpp:55
void SetFont(CStdFont *pFont, uint32_t dwEnabledClr, uint32_t dwDisabledClr)
Definition: C4Gui.h:1484
void SetOnChecked(BaseCallbackHandler *pCB)
void SetChecked(bool fToVal)
Definition: C4Gui.h:1477
static bool GetStandardCheckBoxSize(int *piWdt, int *piHgt, const char *szForCaptionText, CStdFont *pUseFont)
void AddEntry(const char *szText, int32_t id)
bool FindEntry(const char *szText)
static int32_t GetDefaultHeight()
void SetComboCB(ComboBox_FillCB *pNewFillCallback)
void SetColors(uint32_t dwFontClr, uint32_t dwBGClr, uint32_t dwBorderClr)
Definition: C4Gui.h:2019
void SetFont(CStdFont *pToFont)
Definition: C4Gui.h:2018
void SetReadOnly(bool fToVal)
Definition: C4Gui.h:2015
void SetDecoration(C4Facet *pFctSideArrow)
Definition: C4Gui.h:2021
void SetText(const char *szToText)
int32_t GetWidth() const
Definition: C4Gui.h:2803
bool GetFromLeft(int32_t iWdt, int32_t iHgt, C4Rect &rcOut)
Definition: C4Gui.cpp:1076
void ExpandLeft(int32_t iByWdt)
Definition: C4Gui.h:2812
bool GetCentered(int32_t iWdt, int32_t iHgt, C4Rect &rcOut)
Definition: C4Gui.cpp:1133
int32_t GetHeight() const
Definition: C4Gui.h:2804
int32_t GetInnerWidth() const
Definition: C4Gui.h:2808
bool GetFromRight(int32_t iWdt, int32_t iHgt, C4Rect &rcOut)
Definition: C4Gui.cpp:1093
void ExpandTop(int32_t iByHgt)
Definition: C4Gui.h:2811
bool GetFromTop(int32_t iHgt, int32_t iWdt, C4Rect &rcOut)
Definition: C4Gui.cpp:1059
C4Rect & GetGridCell(int32_t iSectX, int32_t iSectXMax, int32_t iSectY, int32_t iSectYMax, int32_t iSectSizeX=-1, int32_t iSectSizeY=-1, bool fCenterPos=false, int32_t iSectNumX=1, int32_t iSectNumY=1)
Definition: C4Gui.cpp:1148
void GetAll(C4Rect &rcOut)
Definition: C4Gui.cpp:1125
bool GetFromBottom(int32_t iHgt, int32_t iWdt, C4Rect &rcOut)
Definition: C4Gui.cpp:1109
void AddElement(Element *pChild)
void SetFocus(Control *pCtrl, bool fByMouse)
void MouseInput(CMouse &rMouse, int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam) override
bool fOK
Definition: C4Gui.h:2083
void UpdateSize() override
virtual void OnClosed(bool fOK)
static int32_t GetCustomEditHeight(CStdFont *pUseFont)
Definition: C4GuiEdit.cpp:119
virtual Screen * GetScreen()
Definition: C4Gui.cpp:289
void SetToolTip(const char *szNewTooltip, bool is_immediate=false)
Definition: C4Gui.cpp:409
void SetColors(uint32_t dwFrameClr, uint32_t dwTitleClr, uint32_t dwBackClr=0xffffffff)
Definition: C4Gui.h:1017
void SetTitle(const char *szToTitle)
Definition: C4Gui.h:1018
void SetFont(CStdFont *pToFont)
Definition: C4Gui.h:1016
void SetText(const char *szToText, bool fAllowHotkey=true)
Definition: C4GuiLabels.cpp:74
static bool GetControlSize(int *piWdt, int *piHgt, const char *szForText, CStdFont *pForFont, bool fMultiline)
Definition: C4GuiEdit.cpp:812
bool ShowModalDlg(Dialog *pDlg, bool fDestruct=true)
bool ShowErrorMessage(const char *szMessage)
void UpdateGamepadGUIControlEnabled()
Definition: C4Gui.cpp:1049
bool ShowMessage(const char *szMessage, const char *szCaption, Icons icoIcon, int32_t *piConfigDontShowAgainSetting=nullptr)
Sheet * AddSheet(const char *szTitle, int32_t icoTitle=Ico_None)
void SelectSheet(int32_t iIndex, bool fByUser)
int32_t GetActiveSheetIndex()
void SetGfx(C4Facet *pafctBack, C4Facet *pafctClip, C4Facet *pafctIcons, CStdFont *paSheetCaptionFont, bool fResizeByAspect)
C4Rect & GetClientRect() override
Definition: C4Gui.h:864
void UpdateLanguage()
Definition: C4Game.cpp:3719
C4PlayerControlAssignmentSets PlayerControlDefaultAssignmentSets
Definition: C4Game.h:93
C4PlayerControlAssignmentSets PlayerControlUserAssignmentSets
Definition: C4Game.h:93
C4PlayerControlDefs PlayerControlDefs
Definition: C4Game.h:92
C4LanguageInfo * FindInfo(const char *strCode)
Definition: C4Language.cpp:353
int GetInfoCount()
Definition: C4Language.cpp:138
C4LanguageInfo * GetInfo(int iIndex)
Definition: C4Language.cpp:343
bool LoadLanguage(const char *strLanguages)
Definition: C4Language.cpp:361
char Name[C4MaxLanguageInfo+1]
Definition: C4Language.h:33
char Code[2+1]
Definition: C4Language.h:32
char Fallback[C4MaxLanguageInfo+1]
Definition: C4Language.h:35
char Info[C4MaxLanguageInfo+1]
Definition: C4Language.h:34
bool Play(const char *szSongname=nullptr, bool fLoop=false, int fadetime_ms=0, double max_resume_time=0.0, bool allow_break=false)
void SetKey(const C4KeyCodeEx &key)
const char * GetControlName() const
const char * GetGUIName(const C4PlayerControlDefs &defs) const
StdStrBuf GetKeysAsString(bool human_readable, bool short_name) const
const char * GetGUIDesc(const C4PlayerControlDefs &defs) const
const C4KeyCodeEx & GetTriggerKey() const
C4PlayerControlAssignment * GetAssignmentByControlName(const char *szControlName)
void RemoveAssignmentByControlName(const char *control_name)
const char * GetGUIName() const
C4PlayerControlAssignment * GetAssignmentByIndex(int32_t index)
C4PlayerControlAssignment * CreateAssignmentForControl(const char *control_name)
const char * GetName() const
C4PlayerControlAssignmentSet * GetSetByName(const char *szName)
C4PlayerControlAssignmentSet * CreateEmptySetByTemplate(const C4PlayerControlAssignmentSet &template_set)
void RemoveSetByName(const char *set_name)
C4PlayerControlAssignmentSet * GetSetByIndex(int32_t index)
Definition: C4Rect.h:28
int32_t y
Definition: C4Rect.h:30
int32_t Hgt
Definition: C4Rect.h:30
int32_t Wdt
Definition: C4Rect.h:30
int32_t x
Definition: C4Rect.h:30
C4FacetID fctOptionsTabClip
Definition: C4Startup.h:83
C4FacetID fctOptionsIcons
Definition: C4Startup.h:83
CStdFont BookFont
Definition: C4Startup.h:77
CStdFont BookSmallFont
Definition: C4Startup.h:77
static C4Startup * Get()
Definition: C4Startup.h:147
@ SDID_Options
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
bool SetSubscreen(const char *szToScreen) override
void RecreateDialog(bool fFade)
void OnClosed(bool fOK) override
void OnKeyboardLayoutChanged() override
bool SaveConfig(bool fForce, bool fKeepOpen)
void OnBackBtn(C4GUI::Control *btn)
int Wdt
Definition: C4Surface.h:65
float TargetY
Definition: C4Facet.h:165
float TargetX
Definition: C4Facet.h:165
void IntUnlock()
Definition: C4Surface.cpp:863
void IntLock()
Definition: C4Surface.cpp:839
virtual void EnumerateMultiSamples(std::vector< int > &samples, int min_expected=0) const
Definition: C4AppT.cpp:105
virtual bool ReInit(C4AbstractApp *pApp)
Definition: C4AppT.cpp:110
int GetLineHeight() const
Definition: C4FontLoader.h:125
std::tuple< std::string, int > BreakMessage(const char *szMsg, int iWdt, bool fCheckMarkup, float fZoom=1.0f)
bool GetTextExtent(const char *szText, int32_t &rsx, int32_t &rsy, bool fCheckMarkup=true)
virtual bool Init(C4Window *pWindow, C4AbstractApp *pApp)
virtual void Clear(bool multisample_change=false)
bool InitShaders(C4GroupSet *pGroups)
Definition: C4DrawGL.cpp:714
CStdGLCtx * pMainCtx
Definition: C4DrawGL.h:179
void Remove(StdSchedulerProc *pProc)
void Add(StdSchedulerProc *pProc)
const char * getData() const
Definition: StdBuf.h:442
void AppendChar(char cChar)
Definition: StdBuf.h:588
void Copy()
Definition: StdBuf.h:467
void Append(const char *pnData, size_t iChars)
Definition: StdBuf.h:519
void Clear()
Definition: StdBuf.h:466
size_t getLength() const
Definition: StdBuf.h:445
void Take(char *pnData)
Definition: StdBuf.h:457
void Format(const char *szFmt,...) GNUC_FORMAT_ATTRIBUTE_O
Definition: StdBuf.cpp:174
Screen TheScreen
Definition: C4Gui.cpp:1054
Icons
Definition: C4Gui.h:638
@ Ico_Notify
Definition: C4Gui.h:642
@ Ico_None
Definition: C4Gui.h:640
@ Ico_Gamepad
Definition: C4Gui.h:669
@ Ico_Clonk
Definition: C4Gui.h:641
@ Ico_Keyboard
Definition: C4Gui.h:668
@ Ico_Confirm
Definition: C4Gui.h:661
@ Ico_Error
Definition: C4Gui.h:652
static C4KeyCodeEx FromC4MC(int8_t mouse_id, int32_t button, DWORD param, bool *is_down=nullptr)
StdStrBuf ToString(bool fHumanReadable, bool fShort) const
C4KeyCode Key
void CopyValidated(const char *szFromVal)