1 /*
2 * OpenClonk, http://www.openclonk.org
3 *
4 * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
5 * Copyright (c) 2013, 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
17 /* Editor windows using Qt*/
18
19 #include "C4Include.h"
20 #include "landscape/C4Texture.h"
21 #include "landscape/C4Landscape.h"
22 // Make sure to include landscape/* first. Otherwise, Qt will either include gltypes and that forbids including glew, or, if glew is inlcuded first, QT will undefine glew partially, and then it can't be included again.
23 #include "editor/C4ConsoleQtState.h"
24 #include "editor/C4ConsoleQtDefinitionListViewer.h"
25 #include "editor/C4ConsoleQtObjectListViewer.h"
26 #include "editor/C4ConsoleQtPropListViewer.h"
27 #include "editor/C4ConsoleQtShapes.h"
28 #include "editor/C4ConsoleQtLocalizeOverview.h"
29 #include "editor/C4Console.h"
30 #include "editor/C4ConsoleGUI.h"
31 #include "script/C4AulExec.h"
32 #include "C4Version.h"
33
34 #include "editor/C4ConsoleQt.h"
35
OnStartGame()36 void C4ConsoleGUI::OnStartGame()
37 {
38 // Welcome screen made invisible on first game load
39 state->HideWelcomeScreen();
40 }
41
Execute()42 void C4ConsoleGUI::Execute() { state->Execute(); }
43
SetCursor(C4ConsoleGUI::Cursor cursor)44 void C4ConsoleGUI::SetCursor(C4ConsoleGUI::Cursor cursor)
45 {
46
47 }
48
RecordingEnabled()49 void C4ConsoleGUI::RecordingEnabled()
50 {
51 if (Active) state->SetRecording(true); // TODO this is never reset. Noone uses it anyway...
52 }
53
ShowAboutWithCopyright(StdStrBuf & copyright)54 void C4ConsoleGUI::ShowAboutWithCopyright(StdStrBuf ©right)
55 {
56 QMessageBox::about(state->window.get(), QString(LoadResStr("IDS_MENU_ABOUT")), QString(copyright.getData()));
57 }
58
UpdateModeCtrls(int iMode)59 bool C4ConsoleGUI::UpdateModeCtrls(int iMode)
60 {
61 if (!Active) return false;
62 state->SetEditCursorMode(iMode);
63 return true;
64 }
65
AddNetMenu()66 void C4ConsoleGUI::AddNetMenu()
67 {
68 if (Active) state->SetNetEnabled(true);
69 }
70
ClearNetMenu()71 void C4ConsoleGUI::ClearNetMenu()
72 {
73 if (Active) state->ClearNetMenu();
74 }
75
AddNetMenuItemForPlayer(int32_t client_id,const char * text,C4ConsoleGUI::ClientOperation op)76 void C4ConsoleGUI::AddNetMenuItemForPlayer(int32_t client_id, const char *text, C4ConsoleGUI::ClientOperation op)
77 {
78 if (Active) state->AddNetMenuItem(client_id, text, op);
79 }
80
ClearPlayerMenu()81 void C4ConsoleGUI::ClearPlayerMenu()
82 {
83 if (Active) state->ClearPlayerMenu();
84 }
85
SetInputFunctions(std::list<const char * > & functions)86 void C4ConsoleGUI::SetInputFunctions(std::list<const char*> &functions)
87 {
88 if (Active) state->SetInputFunctions(functions);
89 }
90
CreateConsoleWindow(C4AbstractApp * application)91 bool C4ConsoleGUI::CreateConsoleWindow(C4AbstractApp *application)
92 {
93 if (!state->CreateConsoleWindow(application)) return false;
94 Active = true;
95 EnableControls(fGameOpen);
96 return true;
97 }
98
DeleteConsoleWindow()99 void C4ConsoleGUI::DeleteConsoleWindow()
100 {
101 if (Active)
102 {
103 Active = false;
104 state->DeleteConsoleWindow();
105 }
106 }
107
Out(const char * message)108 void C4ConsoleGUI::Out(const char* message)
109 {
110 // Log text: Add to log window
111 if (state->window.get())
112 {
113 // Append text
114 state->ui.logView->append(QString(message));
115 // Scroll to end to display it
116 QScrollBar *sb = state->ui.logView->verticalScrollBar();
117 if (sb) sb->setValue(sb->maximum());
118 state->Redraw();
119 }
120 }
121
ClearLog()122 bool C4ConsoleGUI::ClearLog()
123 {
124 // Empty log window
125 if (!Active) return false;
126 state->ui.logView->clear();
127 return true;
128 }
129
DisplayInfoText(InfoTextType type,StdStrBuf & text)130 void C4ConsoleGUI::DisplayInfoText(InfoTextType type, StdStrBuf& text)
131 {
132 QLabel *target = nullptr;
133 switch (type)
134 {
135 case CONSOLE_Cursor: target = state->status_cursor; break;
136 case CONSOLE_FrameCounter: target = state->status_framecounter; break;
137 case CONSOLE_TimeFPS: target = state->status_timefps; break;
138 }
139 if (!target) return;
140 target->setText(text.getData());
141 }
142
SetCaptionToFileName(const char * file_name)143 void C4ConsoleGUI::SetCaptionToFileName(const char* file_name) { /* This is never even called? */ }
144
FileSelect(StdStrBuf * sFilename,const char * szFilter,DWORD dwFlags,bool fSave)145 bool C4ConsoleGUI::FileSelect(StdStrBuf *sFilename, const char * szFilter, DWORD dwFlags, bool fSave)
146 {
147 // Prepare filters from double-zero-terminated list to ";;"-separated list in Qt format
148 QString filter="", selected_filter, filename;
149 QStringList filenames; bool has_multi = (dwFlags & OpenFileFlags::OFN_ALLOWMULTISELECT);
150 if (szFilter)
151 {
152 while (*szFilter)
153 {
154 if (filter.length() > 0) filter.append(";;");
155 filter.append(szFilter);
156 szFilter += strlen(szFilter) + 1;
157 if (*szFilter)
158 {
159 filter.append(" (");
160 filter.append(szFilter);
161 filter.append(")");
162 szFilter += strlen(szFilter) + 1;
163 }
164 if (selected_filter.length() <= 0) selected_filter = filter;
165 }
166 }
167 #ifdef USE_WIN32_WINDOWS
168 // cwd backup
169 size_t l = GetCurrentDirectoryW(0, nullptr);
170 std::unique_ptr<wchar_t []> wd(new wchar_t[l]);
171 GetCurrentDirectoryW(l, wd.get());
172 #endif
173 // Show dialogue
174 if (fSave)
175 filename = QFileDialog::getSaveFileName(state->window.get(), LoadResStr("IDS_DLG_SAVE"), QString(sFilename->getData()), filter, &selected_filter);
176 else if (!has_multi)
177 filename = QFileDialog::getOpenFileName(state->window.get(), LoadResStr("IDS_DLG_OPEN"), QString(), filter);
178 else
179 filenames = QFileDialog::getOpenFileNames(state->window.get(), LoadResStr("IDS_DLG_OPEN"), QString(), filter, &selected_filter);
180 #ifdef USE_WIN32_WINDOWS
181 // Restore cwd; may have been changed in open/save dialogue
182 SetCurrentDirectoryW(wd.get());
183 #endif
184 // Process multi vs single file select
185 if (has_multi)
186 {
187 // Multi-select: Return double-zero-terminated string list
188 if (!filenames.length()) return false;
189 for (auto fn : filenames)
190 {
191 sFilename->Append(fn.toUtf8());
192 sFilename->AppendChar('\0');
193 }
194 return true;
195 }
196 // Cancelled?
197 if (filename.length() <= 0) return false;
198 // File selected!
199 sFilename->Copy(filename.toUtf8());
200 sFilename->AppendChar('\0');
201 return true;
202 }
203
AddMenuItemForPlayer(C4Player * player,StdStrBuf & player_text)204 void C4ConsoleGUI::AddMenuItemForPlayer(C4Player *player, StdStrBuf& player_text)
205 {
206 // Add "new viewport for X" to window menu
207 if (Active) state->AddPlayerViewportMenuItem(player->Number, player_text.getData());
208 }
209
AddKickPlayerMenuItem(C4Player * player,StdStrBuf & player_text,bool enabled)210 void C4ConsoleGUI::AddKickPlayerMenuItem(C4Player *player, StdStrBuf& player_text, bool enabled)
211 {
212 // Add "kick X" to player menu
213 if (Active) state->AddKickPlayerMenuItem(player->Number, player_text.getData(), enabled);
214 }
215
ClearViewportMenu()216 void C4ConsoleGUI::ClearViewportMenu()
217 {
218 // Remove all "new viewport for X" entries from window menu
219 if (Active) state->ClearViewportMenu();
220 }
221
Message(const char * message,bool query)222 bool C4ConsoleGUI::Message(const char *message, bool query)
223 {
224 // Show a message through Qt
225 if (query)
226 {
227 auto result = QMessageBox::question(state->window.get(), C4ENGINECAPTION, message, QMessageBox::StandardButton::Ok | QMessageBox::StandardButton::Cancel);
228 return (result == QMessageBox::StandardButton::Ok);
229 }
230 else
231 {
232 QMessageBox::information(state->window.get(), C4ENGINECAPTION, message, QMessageBox::StandardButton::Ok);
233 return true;
234 }
235 }
236
DoEnableControls(bool fEnable)237 void C4ConsoleGUI::DoEnableControls(bool fEnable)
238 {
239 if (!Active) return;
240 state->SetEnabled(fEnable);
241 state->SetLandscapeMode(::Landscape.GetMode(), ::Game.C4S.Landscape.FlatChunkShapes); // initial setting
242 // If disabling controls, also stop translation editing
243 if (!fEnable) state->translation_overview_dialogue.reset();
244 }
245
DoUpdateHaltCtrls(bool fHalt)246 bool C4ConsoleGUI::DoUpdateHaltCtrls(bool fHalt)
247 {
248 // Reflect halt state in play/pause buttons
249 if (!Active) return false;
250 state->ui.actionPlay->setChecked(!fHalt);
251 state->ui.actionPause->setChecked(fHalt);
252 return true;
253 }
254
PropertyDlgOpen()255 bool C4ConsoleGUI::PropertyDlgOpen() { /* Always open */ return true; }
PropertyDlgClose()256 void C4ConsoleGUI::PropertyDlgClose() { /* Always open */ }
257
PropertyDlgUpdate(C4EditCursorSelection & rSelection,bool force_function_update)258 void C4ConsoleGUI::PropertyDlgUpdate(C4EditCursorSelection &rSelection, bool force_function_update)
259 {
260 if (Active) state->PropertyDlgUpdate(rSelection, force_function_update);
261 }
262
ToolsDlgOpen(class C4ToolsDlg * dlg)263 bool C4ConsoleGUI::ToolsDlgOpen(class C4ToolsDlg *dlg) { /* Always open */ return true; }
ToolsDlgClose()264 void C4ConsoleGUI::ToolsDlgClose() { /* Always open */ }
265
ToolsDlgInitMaterialCtrls(class C4ToolsDlg * dlg)266 void C4ConsoleGUI::ToolsDlgInitMaterialCtrls(class C4ToolsDlg *dlg)
267 {
268 // All foreground materials
269 assert(Active);
270 if (!Active) return;
271 if (state->ui.foregroundMatTexComboBox->count()) return; // already initialized
272 state->ui.foregroundMatTexComboBox->clear();
273 state->ui.foregroundMatTexComboBox->addItem(QString(C4TLS_MatSky));
274 QStringList items;
275 const C4TexMapEntry *entry; int32_t i = 0;
276 while ((entry = ::TextureMap.GetEntry(i++)))
277 {
278 if (!entry->isNull())
279 {
280 const char *material_name = entry->GetMaterialName();
281 if (strcmp(material_name, "Vehicle") && strcmp(material_name, "HalfVehicle"))
282 {
283 items.append(QString(FormatString("%s-%s", material_name, entry->GetTextureName()).getData()));
284 }
285 }
286 }
287 items.sort();
288 for (QString &item : items) state->ui.foregroundMatTexComboBox->addItem(item);
289 auto width = 130; /* The ToolBar randomly resizes the control */
290 state->ui.foregroundMatTexComboBox->view()->setMinimumWidth(width);
291 state->ui.foregroundMatTexComboBox->setFixedWidth(width);
292 // Background materials: True background materials first; then the "funny" stuff
293 state->ui.backgroundMatTexComboBox->addItem(QString(C4TLS_MatSky));
294 items.clear();
295 i = 0;
296 while ((entry = ::TextureMap.GetEntry(i++)))
297 {
298 if (!entry->isNull())
299 {
300 const char *material_name = entry->GetMaterialName();
301 C4Material *mat = entry->GetMaterial();
302 if (strcmp(material_name, "Vehicle") && strcmp(material_name, "HalfVehicle") && mat->Density == C4M_Background)
303 {
304 items.append(QString(FormatString("%s-%s", material_name, entry->GetTextureName()).getData()));
305 }
306 }
307 }
308 items.sort();
309 for (QString &item : items) state->ui.backgroundMatTexComboBox->addItem(item);
310 state->ui.backgroundMatTexComboBox->addItem(QString("----------"));
311 items.clear();
312 i = 0;
313 while ((entry = ::TextureMap.GetEntry(i++)))
314 {
315 if (!entry->isNull())
316 {
317 const char *material_name = entry->GetMaterialName();
318 C4Material *mat = entry->GetMaterial();
319 if (strcmp(material_name, "Vehicle") && strcmp(material_name, "HalfVehicle") && mat->Density != C4M_Background)
320 {
321 items.append(QString(FormatString("%s-%s", material_name, entry->GetTextureName()).getData()));
322 }
323 }
324 }
325 items.sort();
326 for (QString &item : items) state->ui.backgroundMatTexComboBox->addItem(item);
327 state->ui.backgroundMatTexComboBox->view()->setMinimumWidth(width);
328 state->ui.backgroundMatTexComboBox->setFixedWidth(width);
329 // Select current materials
330 state->SetMaterial(dlg->Material);
331 state->SetTexture(dlg->Texture);
332 state->SetBackMaterial(dlg->BackMaterial);
333 state->SetBackTexture(dlg->BackTexture);
334 state->UpdateMatTex();
335 state->UpdateBackMatTex();
336 }
337
ToolsDlgSelectTexture(C4ToolsDlg * dlg,const char * texture)338 void C4ConsoleGUI::ToolsDlgSelectTexture(C4ToolsDlg *dlg, const char *texture) { if (!Active) return; state->SetTexture(texture); }
ToolsDlgSelectMaterial(C4ToolsDlg * dlg,const char * material)339 void C4ConsoleGUI::ToolsDlgSelectMaterial(C4ToolsDlg *dlg, const char *material) { if (!Active) return; state->SetMaterial(material); }
ToolsDlgSelectBackTexture(C4ToolsDlg * dlg,const char * texture)340 void C4ConsoleGUI::ToolsDlgSelectBackTexture(C4ToolsDlg *dlg, const char *texture) { if (!Active) return; state->SetBackTexture(texture); }
ToolsDlgSelectBackMaterial(C4ToolsDlg * dlg,const char * material)341 void C4ConsoleGUI::ToolsDlgSelectBackMaterial(C4ToolsDlg *dlg, const char *material) { if (!Active) return; state->SetBackMaterial(material); }
342
343 #ifdef USE_WIN32_WINDOWS
Win32KeepDialogsFloating(HWND hwnd)344 void C4ConsoleGUI::Win32KeepDialogsFloating(HWND hwnd) { /* Dialogues float nicely */ }
Win32DialogMessageHandling(MSG * msg)345 bool C4ConsoleGUI::Win32DialogMessageHandling(MSG *msg) { return false; /* message handling done through Qt (somehow?) */ }
UpdateMenuText(HMENU hMenu)346 void C4ConsoleGUI::UpdateMenuText(HMENU hMenu) { /* Translation done through QTranslator */ }
347 #endif
348
AddViewport(C4ViewportWindow * cvp)349 void C4ConsoleGUI::AddViewport(C4ViewportWindow *cvp)
350 {
351 // Add surrounding widget for viewport
352 state->AddViewport(cvp);
353 }
354
RemoveViewport(C4ViewportWindow * cvp)355 void C4ConsoleGUI::RemoveViewport(C4ViewportWindow *cvp)
356 {
357 // Add surrounding widget for viewport
358 state->RemoveViewport(cvp);
359 }
360
CreateNewScenario(StdStrBuf * out_filename,bool * out_host_as_network)361 bool C4ConsoleGUI::CreateNewScenario(StdStrBuf *out_filename, bool *out_host_as_network)
362 {
363 #ifdef WITH_QT_EDITOR
364 return state->CreateNewScenario(out_filename, out_host_as_network);
365 #else
366 return false
367 #endif
368 }
369
OnObjectSelectionChanged(class C4EditCursorSelection & selection)370 void C4ConsoleGUI::OnObjectSelectionChanged(class C4EditCursorSelection &selection)
371 {
372 // selection changed (through other means than creator or object list view)
373 // reflect selection change in dialogues
374 state->SetObjectSelection(selection);
375 }
376
ClearGamePointers()377 void C4ConsoleGUI::ClearGamePointers()
378 {
379 state->ClearGamePointers();
380 }
381
EnsureDefinitionListInitialized()382 void C4ConsoleGUI::EnsureDefinitionListInitialized()
383 {
384 state->definition_list_model->EnsureInit();
385 }
386
CloseConsoleWindow()387 void C4ConsoleGUI::CloseConsoleWindow()
388 {
389 if (state && state->window) state->window->close();
390 }
391
ClearPointers(class C4Object * obj)392 void C4ConsoleGUI::ClearPointers(class C4Object *obj)
393 {
394 if (state && state->object_list_model) state->object_list_model->Invalidate();
395 }
396
EditGraphControl(const class C4ControlEditGraph * control)397 void C4ConsoleGUI::EditGraphControl(const class C4ControlEditGraph *control)
398 {
399 if (state && state->property_model)
400 {
401 const char *path = control->GetPath();
402 if (path && *path)
403 {
404 // Apply control to value: Resolve value
405 C4Value graph_value = AulExec.DirectExec(::ScriptEngine.GetPropList(), path, "resolve graph edit", false, nullptr);
406 // ...and apply changes (will check for value validity)
407 C4ConsoleQtGraph::EditGraphValue(graph_value, control->GetAction(), control->GetIndex(), control->GetX(), control->GetY());
408 // For remote clients, also update any edited shapes
409 if (!control->LocalControl())
410 {
411 C4ConsoleQtShape *shape = state->property_model->GetShapeByPropertyPath(path);
412 if (shape)
413 {
414 C4ConsoleQtGraph *shape_graph = shape->GetGraphShape();
415 if (shape_graph)
416 {
417 shape_graph->EditGraph(false, control->GetAction(), control->GetIndex(), control->GetX(), control->GetY());
418 }
419 }
420 }
421 }
422 }
423 }
424
UpdateToolCtrls()425 void C4ToolsDlg::UpdateToolCtrls()
426 {
427 // Set selected drawing tool
428 if (::Console.Active) ::Console.state->SetDrawingTool(Tool);
429 }
430
UpdateTextures()431 void C4ToolsDlg::UpdateTextures() { /* Textures are done with materials */ }
NeedPreviewUpdate()432 void C4ToolsDlg::NeedPreviewUpdate() { /* No preview */}
433
InitGradeCtrl()434 void C4ToolsDlg::InitGradeCtrl()
435 {
436 // Update current grade
437 if (::Console.Active) ::Console.state->ui.drawSizeSlider->setValue(Grade);
438 }
439
PopMaterial()440 bool C4ToolsDlg::PopMaterial()
441 {
442 // Show material selection
443 if (!::Console.Active) return false;
444 ::Console.state->ui.foregroundMatTexComboBox->setFocus();
445 ::Console.state->ui.foregroundMatTexComboBox->showPopup();
446 return true;
447 }
448
PopTextures()449 bool C4ToolsDlg::PopTextures()
450 {
451 // Show texture selection
452 if (!::Console.Active) return false;
453 ::Console.state->ui.foregroundMatTexComboBox->setFocus();
454 ::Console.state->ui.foregroundMatTexComboBox->showPopup();
455 return true;
456 }
457
UpdateIFTControls()458 void C4ToolsDlg::UpdateIFTControls() { /* not using IFT */ }
459
UpdateLandscapeModeCtrls()460 void C4ToolsDlg::UpdateLandscapeModeCtrls()
461 {
462 // Update button down states for landscape mode
463 if (::Console.Active) ::Console.state->SetLandscapeMode(::Landscape.GetMode(), ::Game.C4S.Landscape.FlatChunkShapes);
464 }
465
466
EnableControls()467 void C4ToolsDlg::EnableControls() { /* Handled internally by tool selection */ }
468
469 #include "editor/C4ConsoleGUICommon.h"
470