1/*
2 * LegacyClonk
3 *
4 * Copyright (c) 1998-2000, Matthes Bender (RedWolf Design)
5 * Copyright (c) 2017-2022, The LegacyClonk 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/* Drawing tools dialog for landscape editing in console mode */
18
19#include <C4ToolsDlg.h>
20#include <C4Console.h>
21#include <C4Application.h>
22#ifndef USE_CONSOLE
23#include <StdGL.h>
24#endif
25
26#include "C4Wrappers.h"
27
28#ifdef _WIN32
29#include "StdRegistry.h"
30#include "StdStringEncodingConverter.h"
31#include "res/engine_resource.h"
32#endif
33
34#ifdef WITH_DEVELOPER_MODE
35
36#include <C4DevmodeDlg.h>
37
38#include <gtk/gtk.h>
39
40#include <res/Brush.h>
41#include <res/Line.h>
42#include <res/Rect.h>
43#include <res/Fill.h>
44#include <res/Picker.h>
45
46#include <res/Dynamic.h>
47#include <res/Static.h>
48#include <res/Exact.h>
49
50#include <res/Ift.h>
51#include <res/NoIft.h>
52
53namespace
54{
55 void SelectComboBoxText(GtkComboBox *combobox, const char *text)
56 {
57 GtkTreeModel *model = gtk_combo_box_get_model(combo_box: combobox);
58
59 GtkTreeIter iter;
60 for (gboolean ret = gtk_tree_model_get_iter_first(tree_model: model, iter: &iter); ret; ret = gtk_tree_model_iter_next(tree_model: model, iter: &iter))
61 {
62 gchar *col_text;
63 gtk_tree_model_get(tree_model: model, iter: &iter, 0, &col_text, -1);
64
65 if (SEqualNoCase(szStr1: text, szStr2: col_text))
66 {
67 g_free(mem: col_text);
68 gtk_combo_box_set_active_iter(combo_box: combobox, iter: &iter);
69 return;
70 }
71
72 g_free(mem: col_text);
73 }
74 }
75
76 gboolean RowSeparatorFunc(GtkTreeModel *model, GtkTreeIter *iter, void *user_data)
77 {
78 gchar *text;
79 gtk_tree_model_get(tree_model: model, iter, 0, &text, -1);
80
81 if (SEqual(szStr1: text, szStr2: "------")) { g_free(mem: text); return TRUE; }
82 g_free(mem: text);
83 return FALSE;
84 }
85
86 GtkWidget *CreateImageFromInlinedPixbuf(const guint8 *pixbuf_data)
87 {
88 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_inline(data_length: -1, data: pixbuf_data, FALSE, error: nullptr);
89 GtkWidget *image = gtk_image_new_from_pixbuf(pixbuf);
90 g_object_unref(object: pixbuf);
91 return image;
92 }
93}
94
95#endif
96
97#ifdef _WIN32
98
99#include <commctrl.h>
100
101INT_PTR CALLBACK ToolsDlgProc(HWND hDlg, UINT Msg, WPARAM wParam, LPARAM lParam)
102{
103 int32_t iValue;
104 switch (Msg)
105 {
106 case WM_CLOSE:
107 Console.ToolsDlg.Clear();
108 break;
109
110 case WM_DESTROY:
111 StoreWindowPosition(hDlg, "Property", Config.GetSubkeyPath("Console"), false);
112 break;
113
114 case WM_INITDIALOG:
115 return TRUE;
116
117 case WM_PAINT:
118 PostMessage(hDlg, WM_USER, 0, 0); // For user paint
119 return FALSE;
120
121 case WM_USER:
122 Console.ToolsDlg.UpdatePreview();
123 return TRUE;
124
125 case WM_VSCROLL:
126 switch (LOWORD(wParam))
127 {
128 case SB_THUMBTRACK: case SB_THUMBPOSITION:
129 iValue = HIWORD(wParam);
130 Console.ToolsDlg.SetGrade(C4TLS_GradeMax - iValue);
131 break;
132 case SB_PAGEUP: case SB_PAGEDOWN:
133 case SB_LINEUP: case SB_LINEDOWN:
134 iValue = SendDlgItemMessage(hDlg, IDC_SLIDERGRADE, TBM_GETPOS, 0, 0);
135 Console.ToolsDlg.SetGrade(C4TLS_GradeMax - iValue);
136 break;
137 }
138 return TRUE;
139
140 case WM_COMMAND:
141 // Evaluate command
142 switch (LOWORD(wParam))
143 {
144 case IDOK:
145 return TRUE;
146
147 case IDC_BUTTONMODEDYNAMIC:
148 Console.ToolsDlg.SetLandscapeMode(C4LSC_Dynamic);
149 return TRUE;
150
151 case IDC_BUTTONMODESTATIC:
152 Console.ToolsDlg.SetLandscapeMode(C4LSC_Static);
153 return TRUE;
154
155 case IDC_BUTTONMODEEXACT:
156 Console.ToolsDlg.SetLandscapeMode(C4LSC_Exact);
157 return TRUE;
158
159 case IDC_BUTTONBRUSH:
160 Console.ToolsDlg.SetTool(C4TLS_Brush, false);
161 return TRUE;
162
163 case IDC_BUTTONLINE:
164 Console.ToolsDlg.SetTool(C4TLS_Line, false);
165 return TRUE;
166
167 case IDC_BUTTONRECT:
168 Console.ToolsDlg.SetTool(C4TLS_Rect, false);
169 return TRUE;
170
171 case IDC_BUTTONFILL:
172 Console.ToolsDlg.SetTool(C4TLS_Fill, false);
173 return TRUE;
174
175 case IDC_BUTTONPICKER:
176 Console.ToolsDlg.SetTool(C4TLS_Picker, false);
177 return TRUE;
178
179 case IDC_BUTTONIFT:
180 Console.ToolsDlg.SetIFT(true);
181 return TRUE;
182
183 case IDC_BUTTONNOIFT:
184 Console.ToolsDlg.SetIFT(false);
185 return TRUE;
186
187 case IDC_COMBOMATERIAL:
188 switch (HIWORD(wParam))
189 {
190 case CBN_SELCHANGE:
191 int32_t cursel = SendDlgItemMessage(hDlg, IDC_COMBOMATERIAL, CB_GETCURSEL, 0, 0);
192 std::wstring material;
193 const LRESULT textSize{SendDlgItemMessage(hDlg, IDC_COMBOMATERIAL, CB_GETLBTEXTLEN, cursel, 0)};
194
195 material.resize_and_overwrite(textSize, [cursel, hDlg, &material](wchar_t *const ptr, const std::size_t size)
196 {
197 return SendDlgItemMessage(hDlg, IDC_COMBOMATERIAL, CB_GETLBTEXT, cursel, reinterpret_cast<LPARAM>(material.data()));
198 });
199
200 Console.ToolsDlg.SetMaterial(StdStringEncodingConverter::Utf16ToWinAcp(material).c_str());
201 break;
202 }
203 return TRUE;
204
205 case IDC_COMBOTEXTURE:
206 switch (HIWORD(wParam))
207 {
208 case CBN_SELCHANGE:
209 int32_t cursel = SendDlgItemMessage(hDlg, IDC_COMBOTEXTURE, CB_GETCURSEL, 0, 0);
210 std::wstring texture;
211 const LRESULT textSize{SendDlgItemMessage(hDlg, IDC_COMBOTEXTURE, CB_GETLBTEXTLEN, cursel, 0)};
212
213 texture.resize_and_overwrite(textSize, [cursel, hDlg, &texture](wchar_t *const ptr, const std::size_t size)
214 {
215 return SendDlgItemMessage(hDlg, IDC_COMBOTEXTURE, CB_GETLBTEXT, cursel, reinterpret_cast<LPARAM>(texture.data()));
216 });
217
218 Console.ToolsDlg.SetTexture(StdStringEncodingConverter::Utf16ToWinAcp(texture).c_str());
219 break;
220 }
221 return TRUE;
222 }
223 return FALSE;
224 }
225 return FALSE;
226}
227
228#endif
229
230C4ToolsDlg::C4ToolsDlg()
231{
232 Default();
233#ifdef _WIN32
234 hbmBrush = hbmLine = hbmRect = hbmFill = nullptr;
235 hbmIFT = hbmNoIFT = nullptr;
236#endif
237}
238
239C4ToolsDlg::~C4ToolsDlg()
240{
241 Clear();
242#ifdef WITH_DEVELOPER_MODE
243 if (hbox != nullptr)
244 {
245 g_signal_handler_disconnect(G_OBJECT(C4DevmodeDlg::GetWindow()), handler_id: handlerHide);
246 C4DevmodeDlg::RemovePage(widget: hbox);
247 hbox = nullptr;
248 }
249#endif // WITH_DEVELOPER_MODE
250
251 // Unload bitmaps
252#ifdef _WIN32
253 if (hbmBrush) DeleteObject(hbmBrush);
254 if (hbmLine) DeleteObject(hbmLine);
255 if (hbmRect) DeleteObject(hbmRect);
256 if (hbmFill) DeleteObject(hbmFill);
257 if (hbmIFT) DeleteObject(hbmIFT);
258 if (hbmNoIFT) DeleteObject(hbmNoIFT);
259#endif
260}
261
262bool C4ToolsDlg::Open()
263{
264 // Create dialog window
265#ifdef _WIN32
266 if (hDialog) return true;
267 hDialog = CreateDialog(Application.hInstance,
268 MAKEINTRESOURCE(IDD_TOOLS),
269 Console.hWindow,
270 ToolsDlgProc);
271 if (!hDialog) return false;
272 // Set text
273 SetWindowText(hDialog, StdStringEncodingConverter::WinAcpToUtf16(LoadResStr(C4ResStrTableKey::IDS_DLG_TOOLS)).c_str());
274 SetDlgItemText(hDialog, IDC_STATICMATERIAL, StdStringEncodingConverter::WinAcpToUtf16(LoadResStr(C4ResStrTableKey::IDS_CTL_MATERIAL)).c_str());
275 SetDlgItemText(hDialog, IDC_STATICTEXTURE, StdStringEncodingConverter::WinAcpToUtf16(LoadResStr(C4ResStrTableKey::IDS_CTL_TEXTURE)).c_str());
276 // Load bitmaps if necessary
277 LoadBitmaps();
278 // create target ctx for OpenGL rendering
279#ifndef USE_CONSOLE
280 if (lpDDraw && !pGLCtx) pGLCtx = lpDDraw->CreateContext(GetDlgItem(hDialog, IDC_PREVIEW), &Application);
281#endif
282 // Show window
283 RestoreWindowPosition(hDialog, "Property", Config.GetSubkeyPath("Console"));
284 SetWindowPos(hDialog, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
285 ShowWindow(hDialog, SW_SHOWNORMAL | SW_SHOWNA);
286#elif defined(WITH_DEVELOPER_MODE)
287 if (hbox == nullptr)
288 {
289 hbox = gtk_box_new(orientation: GTK_ORIENTATION_HORIZONTAL, spacing: 12);
290 GtkWidget *vbox = gtk_box_new(orientation: GTK_ORIENTATION_VERTICAL, spacing: 6);
291
292 GtkWidget *image_brush = CreateImageFromInlinedPixbuf(pixbuf_data: brush_pixbuf_data);
293 GtkWidget *image_line = CreateImageFromInlinedPixbuf(pixbuf_data: line_pixbuf_data);
294 GtkWidget *image_rect = CreateImageFromInlinedPixbuf(pixbuf_data: rect_pixbuf_data);
295 GtkWidget *image_fill = CreateImageFromInlinedPixbuf(pixbuf_data: fill_pixbuf_data);
296 GtkWidget *image_picker = CreateImageFromInlinedPixbuf(pixbuf_data: picker_pixbuf_data);
297
298 GtkWidget *image_dynamic = CreateImageFromInlinedPixbuf(pixbuf_data: dynamic_pixbuf_data);
299 GtkWidget *image_static = CreateImageFromInlinedPixbuf(pixbuf_data: static_pixbuf_data);
300 GtkWidget *image_exact = CreateImageFromInlinedPixbuf(pixbuf_data: exact_pixbuf_data);
301
302 GtkWidget *image_ift = CreateImageFromInlinedPixbuf(pixbuf_data: ift_pixbuf_data);
303 GtkWidget *image_no_ift = CreateImageFromInlinedPixbuf(pixbuf_data: no_ift_pixbuf_data);
304
305 landscape_dynamic = gtk_toggle_button_new();
306 landscape_static = gtk_toggle_button_new();
307 landscape_exact = gtk_toggle_button_new();
308
309 gtk_container_add(GTK_CONTAINER(landscape_dynamic), widget: image_dynamic);
310 gtk_container_add(GTK_CONTAINER(landscape_static), widget: image_static);
311 gtk_container_add(GTK_CONTAINER(landscape_exact), widget: image_exact);
312
313 gtk_box_pack_start(GTK_BOX(vbox), child: landscape_dynamic, FALSE, FALSE, padding: 0);
314 gtk_box_pack_start(GTK_BOX(vbox), child: landscape_static, FALSE, FALSE, padding: 0);
315 gtk_box_pack_start(GTK_BOX(vbox), child: landscape_exact, FALSE, FALSE, padding: 0);
316
317 gtk_box_pack_start(GTK_BOX(hbox), child: vbox, FALSE, FALSE, padding: 0);
318 vbox = gtk_box_new(orientation: GTK_ORIENTATION_VERTICAL, spacing: 12);
319 gtk_box_pack_start(GTK_BOX(hbox), child: vbox, TRUE, TRUE, padding: 0);
320 GtkWidget *local_hbox = gtk_box_new(orientation: GTK_ORIENTATION_HORIZONTAL, spacing: 6);
321
322 brush = gtk_toggle_button_new();
323 line = gtk_toggle_button_new();
324 rect = gtk_toggle_button_new();
325 fill = gtk_toggle_button_new();
326 picker = gtk_toggle_button_new();
327
328 gtk_container_add(GTK_CONTAINER(brush), widget: image_brush);
329 gtk_container_add(GTK_CONTAINER(line), widget: image_line);
330 gtk_container_add(GTK_CONTAINER(rect), widget: image_rect);
331 gtk_container_add(GTK_CONTAINER(fill), widget: image_fill);
332 gtk_container_add(GTK_CONTAINER(picker), widget: image_picker);
333
334 gtk_box_pack_start(GTK_BOX(local_hbox), child: brush, FALSE, FALSE, padding: 0);
335 gtk_box_pack_start(GTK_BOX(local_hbox), child: line, FALSE, FALSE, padding: 0);
336 gtk_box_pack_start(GTK_BOX(local_hbox), child: rect, FALSE, FALSE, padding: 0);
337 gtk_box_pack_start(GTK_BOX(local_hbox), child: fill, FALSE, FALSE, padding: 0);
338 gtk_box_pack_start(GTK_BOX(local_hbox), child: picker, FALSE, FALSE, padding: 0);
339
340 gtk_box_pack_start(GTK_BOX(vbox), child: local_hbox, FALSE, FALSE, padding: 0);
341 local_hbox = gtk_box_new(orientation: GTK_ORIENTATION_HORIZONTAL, spacing: 12);
342 gtk_box_pack_start(GTK_BOX(vbox), child: local_hbox, TRUE, TRUE, padding: 0);
343
344 preview = gtk_image_new();
345 gtk_box_pack_start(GTK_BOX(local_hbox), child: preview, FALSE, FALSE, padding: 0);
346
347 scale = gtk_scale_new(orientation: GTK_ORIENTATION_VERTICAL, adjustment: nullptr);
348 gtk_box_pack_start(GTK_BOX(local_hbox), child: scale, FALSE, FALSE, padding: 0);
349
350 vbox = gtk_box_new(orientation: GTK_ORIENTATION_VERTICAL, spacing: 6);
351
352 ift = gtk_toggle_button_new();
353 no_ift = gtk_toggle_button_new();
354
355 gtk_container_add(GTK_CONTAINER(ift), widget: image_ift);
356 gtk_container_add(GTK_CONTAINER(no_ift), widget: image_no_ift);
357
358 gtk_box_pack_start(GTK_BOX(vbox), child: ift, FALSE, FALSE, padding: 0);
359 gtk_box_pack_start(GTK_BOX(vbox), child: no_ift, FALSE, FALSE, padding: 0);
360
361 gtk_box_pack_start(GTK_BOX(local_hbox), child: vbox, FALSE, FALSE, padding: 0);
362
363 vbox = gtk_box_new(orientation: GTK_ORIENTATION_VERTICAL, spacing: 6);
364
365 materials = gtk_combo_box_text_new();
366 textures = gtk_combo_box_text_new();
367
368 gtk_combo_box_set_row_separator_func(GTK_COMBO_BOX(materials), func: RowSeparatorFunc, data: nullptr, destroy: nullptr);
369 gtk_combo_box_set_row_separator_func(GTK_COMBO_BOX(textures), func: RowSeparatorFunc, data: nullptr, destroy: nullptr);
370
371 gtk_box_pack_start(GTK_BOX(vbox), child: materials, TRUE, FALSE, padding: 0);
372 gtk_box_pack_start(GTK_BOX(vbox), child: textures, TRUE, FALSE, padding: 0);
373
374 gtk_box_pack_start(GTK_BOX(local_hbox), child: vbox, TRUE, TRUE, padding: 0); // ???
375 gtk_widget_show_all(widget: hbox);
376
377 C4DevmodeDlg::AddPage(widget: hbox, GTK_WINDOW(Console.window), title: LoadResStrGtk(id: C4ResStrTableKey::IDS_DLG_TOOLS).c_str());
378
379 handlerDynamic = g_signal_connect(G_OBJECT(landscape_dynamic), "toggled", G_CALLBACK(OnButtonModeDynamic), this);
380 handlerStatic = g_signal_connect(G_OBJECT(landscape_static), "toggled", G_CALLBACK(OnButtonModeStatic), this);
381 handlerExact = g_signal_connect(G_OBJECT(landscape_exact), "toggled", G_CALLBACK(OnButtonModeExact), this);
382 handlerBrush = g_signal_connect(G_OBJECT(brush), "toggled", G_CALLBACK(OnButtonBrush), this);
383 handlerLine = g_signal_connect(G_OBJECT(line), "toggled", G_CALLBACK(OnButtonLine), this);
384 handlerRect = g_signal_connect(G_OBJECT(rect), "toggled", G_CALLBACK(OnButtonRect), this);
385 handlerFill = g_signal_connect(G_OBJECT(fill), "toggled", G_CALLBACK(OnButtonFill), this);
386 handlerPicker = g_signal_connect(G_OBJECT(picker), "toggled", G_CALLBACK(OnButtonPicker), this);
387 handlerIft = g_signal_connect(G_OBJECT(ift), "toggled", G_CALLBACK(OnButtonIft), this);
388 handlerNoIft = g_signal_connect(G_OBJECT(no_ift), "toggled", G_CALLBACK(OnButtonNoIft), this);
389 handlerMaterials = g_signal_connect(G_OBJECT(materials), "changed", G_CALLBACK(OnComboMaterial), this);
390 handlerTextures = g_signal_connect(G_OBJECT(textures), "changed", G_CALLBACK(OnComboTexture), this);
391 handlerScale = g_signal_connect(G_OBJECT(scale), "value-changed", G_CALLBACK(OnGrade), this);
392
393 handlerHide = g_signal_connect(G_OBJECT(C4DevmodeDlg::GetWindow()), "hide", G_CALLBACK(OnWindowHide), this);
394 }
395
396 C4DevmodeDlg::SwitchPage(widget: hbox);
397#endif
398
399 Active = true;
400 // Update contols
401 InitGradeCtrl();
402 UpdateLandscapeModeCtrls();
403 UpdateToolCtrls();
404 UpdateIFTControls();
405 InitMaterialCtrls();
406 EnableControls();
407 return true;
408}
409
410void C4ToolsDlg::Default()
411{
412#ifdef _WIN32
413 hDialog = nullptr;
414#ifndef USE_CONSOLE
415 pGLCtx = nullptr;
416#endif
417#elif defined(WITH_DEVELOPER_MODE)
418 hbox = nullptr;
419#endif
420 Active = false;
421 Tool = SelectedTool = C4TLS_Brush;
422 Grade = C4TLS_GradeDefault;
423 ModeIFT = true;
424 SCopy(szSource: "Earth", sTarget: Material);
425 SCopy(szSource: "Rough", sTarget: Texture);
426}
427
428void C4ToolsDlg::Clear()
429{
430#ifdef _WIN32
431#ifndef USE_CONSOLE
432 delete pGLCtx; pGLCtx = nullptr;
433#endif
434 if (hDialog) DestroyWindow(hDialog); hDialog = nullptr;
435#endif
436 Active = false;
437}
438
439bool C4ToolsDlg::SetTool(int32_t iTool, bool fTemp)
440{
441 Tool = iTool;
442 if (!fTemp) SelectedTool = Tool;
443 UpdateToolCtrls();
444 UpdatePreview();
445 return true;
446}
447
448void C4ToolsDlg::UpdateToolCtrls()
449{
450#ifdef _WIN32
451 SendDlgItemMessage(hDialog, IDC_BUTTONBRUSH, BM_SETSTATE, (Tool == C4TLS_Brush), 0);
452 UpdateWindow(GetDlgItem(hDialog, IDC_BUTTONBRUSH));
453 SendDlgItemMessage(hDialog, IDC_BUTTONLINE, BM_SETSTATE, (Tool == C4TLS_Line), 0);
454 UpdateWindow(GetDlgItem(hDialog, IDC_BUTTONLINE));
455 SendDlgItemMessage(hDialog, IDC_BUTTONRECT, BM_SETSTATE, (Tool == C4TLS_Rect), 0);
456 UpdateWindow(GetDlgItem(hDialog, IDC_BUTTONRECT));
457 SendDlgItemMessage(hDialog, IDC_BUTTONFILL, BM_SETSTATE, (Tool == C4TLS_Fill), 0);
458 UpdateWindow(GetDlgItem(hDialog, IDC_BUTTONFILL));
459 SendDlgItemMessage(hDialog, IDC_BUTTONPICKER, BM_SETSTATE, (Tool == C4TLS_Picker), 0);
460 UpdateWindow(GetDlgItem(hDialog, IDC_BUTTONPICKER));
461#elif defined(WITH_DEVELOPER_MODE)
462 g_signal_handler_block(instance: brush, handler_id: handlerBrush);
463 g_signal_handler_block(instance: line, handler_id: handlerLine);
464 g_signal_handler_block(instance: rect, handler_id: handlerRect);
465 g_signal_handler_block(instance: fill, handler_id: handlerFill);
466 g_signal_handler_block(instance: picker, handler_id: handlerPicker);
467
468 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(brush), is_active: Tool == C4TLS_Brush);
469 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(line), is_active: Tool == C4TLS_Line);
470 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rect), is_active: Tool == C4TLS_Rect);
471 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fill), is_active: Tool == C4TLS_Fill);
472 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(picker), is_active: Tool == C4TLS_Picker);
473
474 g_signal_handler_unblock(instance: brush, handler_id: handlerBrush);
475 g_signal_handler_unblock(instance: line, handler_id: handlerLine);
476 g_signal_handler_unblock(instance: rect, handler_id: handlerRect);
477 g_signal_handler_unblock(instance: fill, handler_id: handlerFill);
478 g_signal_handler_unblock(instance: picker, handler_id: handlerPicker);
479#endif
480}
481
482void C4ToolsDlg::InitMaterialCtrls()
483{
484 // Materials
485#ifdef _WIN32
486 SendDlgItemMessage(hDialog, IDC_COMBOMATERIAL, CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(_CRT_WIDE(C4TLS_MatSky)));
487 for (int32_t cnt = 0; cnt < Game.Material.Num; cnt++)
488 SendDlgItemMessage(hDialog, IDC_COMBOMATERIAL, CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(StdStringEncodingConverter::WinAcpToUtf16(Game.Material.Map[cnt].Name).c_str()));
489 SendDlgItemMessage(hDialog, IDC_COMBOMATERIAL, CB_SELECTSTRING, 0, reinterpret_cast<LPARAM>(StdStringEncodingConverter::WinAcpToUtf16(Material).c_str()));
490#elif defined(WITH_DEVELOPER_MODE)
491 GtkListStore *list = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(materials)));
492
493 g_signal_handler_block(instance: materials, handler_id: handlerMaterials);
494 gtk_list_store_clear(list_store: list);
495
496 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(materials), C4TLS_MatSky);
497 for (int32_t cnt = 0; cnt < Game.Material.Num; cnt++)
498 {
499 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(materials), text: Game.Material.Map[cnt].Name);
500 }
501 g_signal_handler_unblock(instance: materials, handler_id: handlerMaterials);
502 SelectComboBoxText(GTK_COMBO_BOX(materials), text: Material);
503#endif
504 // Textures
505 UpdateTextures();
506}
507
508void C4ToolsDlg::UpdateTextures()
509{
510 // Refill dlg
511#ifdef _WIN32
512 SendDlgItemMessage(hDialog, IDC_COMBOTEXTURE, CB_RESETCONTENT, 0, 0);
513#elif defined(WITH_DEVELOPER_MODE)
514 GtkListStore *list = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(textures)));
515 gtk_list_store_clear(list_store: list);
516#endif
517 // bottom-most: any invalid textures
518 bool fAnyEntry = false; int32_t cnt; const char *szTexture;
519 if (Game.Landscape.Mode != C4LSC_Exact)
520 for (cnt = 0; (szTexture = Game.TextureMap.GetTexture(iIndex: cnt)); cnt++)
521 {
522 if (!Game.TextureMap.GetIndex(szMaterial: Material, szTexture, fAddIfNotExist: false))
523 {
524 fAnyEntry = true;
525#ifdef _WIN32
526 SendDlgItemMessage(hDialog, IDC_COMBOTEXTURE, CB_INSERTSTRING, 0, reinterpret_cast<LPARAM>(StdStringEncodingConverter::WinAcpToUtf16(szTexture).c_str()));
527#elif defined(WITH_DEVELOPER_MODE)
528 gtk_combo_box_text_prepend_text(GTK_COMBO_BOX_TEXT(textures), text: szTexture);
529#endif
530 }
531 }
532 // separator
533 if (fAnyEntry)
534 {
535#ifdef _WIN32
536 SendDlgItemMessage(hDialog, IDC_COMBOTEXTURE, CB_INSERTSTRING, 0, reinterpret_cast<LPARAM>(L"-------"));
537#elif defined(WITH_DEVELOPER_MODE)
538 gtk_combo_box_text_prepend_text(GTK_COMBO_BOX_TEXT(textures), text: "-------");
539#endif
540 }
541
542 // atop: valid textures
543 for (cnt = 0; (szTexture = Game.TextureMap.GetTexture(iIndex: cnt)); cnt++)
544 {
545 // Current material-texture valid? Always valid for exact mode
546 if (Game.TextureMap.GetIndex(szMaterial: Material, szTexture, fAddIfNotExist: false) || Game.Landscape.Mode == C4LSC_Exact)
547 {
548#ifdef _WIN32
549 SendDlgItemMessage(hDialog, IDC_COMBOTEXTURE, CB_INSERTSTRING, 0, reinterpret_cast<LPARAM>(StdStringEncodingConverter::WinAcpToUtf16(szTexture).c_str()));
550#elif defined(WITH_DEVELOPER_MODE)
551 gtk_combo_box_text_prepend_text(GTK_COMBO_BOX_TEXT(textures), text: szTexture);
552#endif
553 }
554 }
555 // reselect current
556#ifdef _WIN32
557 SendDlgItemMessage(hDialog, IDC_COMBOTEXTURE, CB_SELECTSTRING, 0, reinterpret_cast<LPARAM>(StdStringEncodingConverter::WinAcpToUtf16(Texture).c_str()));
558#elif defined(WITH_DEVELOPER_MODE)
559 g_signal_handler_block(instance: textures, handler_id: handlerTextures);
560 SelectComboBoxText(GTK_COMBO_BOX(textures), text: Texture);
561 g_signal_handler_unblock(instance: textures, handler_id: handlerTextures);
562#endif
563}
564
565void C4ToolsDlg::SetMaterial(const char *szMaterial)
566{
567 SCopy(szSource: szMaterial, sTarget: Material, iMaxL: C4M_MaxName);
568 AssertValidTexture();
569 EnableControls();
570 if (Game.Landscape.Mode == C4LSC_Static) UpdateTextures();
571 UpdatePreview();
572}
573
574void C4ToolsDlg::SetTexture(const char *szTexture)
575{
576 // assert valid (for separator selection)
577 if (!Game.TextureMap.GetTexture(szTexture))
578 {
579 // ensure correct texture is in dlg
580#ifdef _WIN32
581 SendDlgItemMessage(hDialog, IDC_COMBOTEXTURE, CB_SELECTSTRING, 0, reinterpret_cast<LPARAM>(StdStringEncodingConverter::WinAcpToUtf16(Texture).c_str()));
582#elif defined(WITH_DEVELOPER_MODE)
583 g_signal_handler_block(instance: textures, handler_id: handlerTextures);
584 SelectComboBoxText(GTK_COMBO_BOX(textures), text: Texture);
585 g_signal_handler_unblock(instance: textures, handler_id: handlerTextures);
586#endif
587 return;
588 }
589 SCopy(szSource: szTexture, sTarget: Texture, iMaxL: C4M_MaxName);
590 UpdatePreview();
591}
592
593bool C4ToolsDlg::SetIFT(bool fIFT)
594{
595 if (fIFT) ModeIFT = 1; else ModeIFT = 0;
596 UpdateIFTControls();
597 UpdatePreview();
598 return true;
599}
600
601void C4ToolsDlg::UpdatePreview()
602{
603 // TODO: Set size request for image to read size from image's size request?
604 std::int32_t left{0}, top{0}, previewWidth{64}, previewHeight{64};
605
606#ifdef _WIN32
607 if (!hDialog) return;
608 const auto previewHandle = GetDlgItem(hDialog, IDC_PREVIEW);
609 if (!previewHandle) return;
610 RECT clientRect;
611 if (!GetClientRect(previewHandle, &clientRect)) return;
612 left = clientRect.left;
613 top = clientRect.top;
614 previewWidth = clientRect.right - clientRect.left;
615 previewHeight = clientRect.bottom - clientRect.top;
616
617#ifndef USE_CONSOLE
618 if (pGL && pGLCtx)
619 {
620 if (!pGLCtx->Select())
621 {
622 return;
623 }
624 }
625#endif
626#elif defined(WITH_DEVELOPER_MODE)
627 if (!hbox) return;
628#endif
629
630 const auto surfacePreview = std::make_unique<C4Surface>(args&: previewWidth, args&: previewHeight);
631
632 // fill bg
633#ifdef _WIN32
634 Application.DDraw->DrawBox(surfacePreview.get(), 0, 0, previewWidth - 1, previewHeight - 1, CGray4);
635#endif
636 uint8_t bCol = 0;
637 CPattern Pattern1;
638 CPattern Pattern2;
639 // Sky material: sky as pattern only
640 if (SEqual(szStr1: Material, C4TLS_MatSky))
641 {
642 Pattern1.SetColors(pClrs: nullptr, pAlpha: nullptr);
643 Pattern1.Set(sfcSource: Game.Landscape.Sky.Surface, iZoom: 0, fMonochrome: false);
644 }
645 // Material-Texture
646 else
647 {
648 bCol = Mat2PixColDefault(mat: Game.Material.Get(szMaterial: Material));
649 // Get/Create TexMap entry
650 uint8_t iTex = Game.TextureMap.GetIndex(szMaterial: Material, szTexture: Texture, fAddIfNotExist: true);
651 if (iTex)
652 {
653 // Define texture pattern
654 const C4TexMapEntry *pTex = Game.TextureMap.GetEntry(iIndex: iTex);
655 // Security
656 if (pTex)
657 {
658 // Set drawing pattern
659 Pattern2 = pTex->getPattern();
660 // get and set extended texture of material
661 C4Material *pMat = pTex->GetMaterial();
662 if (pMat && !(pMat->OverlayType & C4MatOv_None))
663 {
664 Pattern1 = pMat->MatPattern;
665 }
666 }
667 }
668 }
669#ifdef _WIN32
670 if (IsWindowEnabled(GetDlgItem(hDialog, IDC_PREVIEW)))
671#elif defined(WITH_DEVELOPER_MODE)
672 if (gtk_widget_get_sensitive(widget: preview))
673#endif
674 Application.DDraw->DrawPatternedCircle(sfcDest: surfacePreview.get(),
675 x: previewWidth / 2, y: previewHeight / 2,
676 r: Grade,
677 col: bCol, Pattern1, Pattern2, rPal&: *Game.Landscape.GetPal());
678
679 Application.DDraw->AttachPrimaryPalette(sfcSurface: surfacePreview.get());
680
681#ifdef _WIN32
682#ifndef USE_CONSOLE
683 if (pGL && pGLCtx)
684 {
685 pGL->Blit(surfacePreview.get(), 0, 0, static_cast<float>(previewWidth), static_cast<float>(previewHeight), pGL->lpPrimary, left, top, previewWidth, previewHeight);
686 pGL->PageFlip();
687 pGL->GetMainCtx().Select();
688 }
689#endif
690#elif defined(WITH_DEVELOPER_MODE)
691 // TODO: Can we optimize this?
692 GdkPixbuf *pixbuf = gdk_pixbuf_new(colorspace: GDK_COLORSPACE_RGB, TRUE, bits_per_sample: 8, width: 64, height: 64);
693 guchar *data = gdk_pixbuf_get_pixels(pixbuf);
694 surfacePreview->Lock();
695 for (int x = 0; x < 64; ++x) for (int y = 0; y < 64; ++y)
696 {
697 uint32_t dw = surfacePreview->GetPixDw(iX: x, iY: y, fApplyModulation: true);
698 *data = (dw >> 16) & 0xff; ++data;
699 *data = (dw >> 8) & 0xff; ++data;
700 *data = (dw) & 0xff; ++data;
701 *data = 0xff - ((dw >> 24) & 0xff); ++data;
702 }
703
704 surfacePreview->Unlock();
705 gtk_image_set_from_pixbuf(GTK_IMAGE(preview), pixbuf);
706 g_object_unref(object: pixbuf);
707#endif
708}
709
710void C4ToolsDlg::InitGradeCtrl()
711{
712#ifdef _WIN32
713 if (!hDialog) return;
714 HWND hwndTrack = GetDlgItem(hDialog, IDC_SLIDERGRADE);
715 SendMessage(hwndTrack, TBM_SETPAGESIZE, 0, 5);
716 SendMessage(hwndTrack, TBM_SETLINESIZE, 0, 1);
717 SendMessage(hwndTrack, TBM_SETRANGE, FALSE,
718 MAKELONG(C4TLS_GradeMin, C4TLS_GradeMax));
719 SendMessage(hwndTrack, TBM_SETPOS, TRUE, C4TLS_GradeMax - Grade);
720 UpdateWindow(hwndTrack);
721#elif defined(WITH_DEVELOPER_MODE)
722 if (!hbox) return;
723 g_signal_handler_block(instance: scale, handler_id: handlerScale);
724 gtk_range_set_increments(GTK_RANGE(scale), step: 1, page: 5);
725 gtk_range_set_range(GTK_RANGE(scale), min: C4TLS_GradeMin, max: C4TLS_GradeMax);
726 gtk_scale_set_draw_value(GTK_SCALE(scale), FALSE);
727 gtk_range_set_value(GTK_RANGE(scale), value: C4TLS_GradeMax - Grade);
728 g_signal_handler_unblock(instance: scale, handler_id: handlerScale);
729#endif
730}
731
732bool C4ToolsDlg::SetGrade(int32_t iGrade)
733{
734 Grade = BoundBy(bval: iGrade, lbound: C4TLS_GradeMin, rbound: C4TLS_GradeMax);
735 UpdatePreview();
736 return true;
737}
738
739bool C4ToolsDlg::ChangeGrade(int32_t iChange)
740{
741 Grade = BoundBy(bval: Grade + iChange, lbound: C4TLS_GradeMin, rbound: C4TLS_GradeMax);
742 UpdatePreview();
743 InitGradeCtrl();
744 return true;
745}
746
747bool C4ToolsDlg::PopMaterial()
748{
749#ifdef _WIN32
750 if (!hDialog) return false;
751 SetFocus(GetDlgItem(hDialog, IDC_COMBOMATERIAL));
752 SendDlgItemMessage(hDialog, IDC_COMBOMATERIAL, CB_SHOWDROPDOWN, TRUE, 0);
753#elif defined(WITH_DEVELOPER_MODE)
754 if (!hbox) return false;
755 gtk_widget_grab_focus(widget: materials);
756 gtk_combo_box_popup(GTK_COMBO_BOX(materials));
757#endif
758 return true;
759}
760
761bool C4ToolsDlg::PopTextures()
762{
763#ifdef _WIN32
764 if (!hDialog) return false;
765 SetFocus(GetDlgItem(hDialog, IDC_COMBOTEXTURE));
766 SendDlgItemMessage(hDialog, IDC_COMBOTEXTURE, CB_SHOWDROPDOWN, TRUE, 0);
767#elif defined(WITH_DEVELOPER_MODE)
768 if (!hbox) return false;
769 gtk_widget_grab_focus(widget: textures);
770 gtk_combo_box_popup(GTK_COMBO_BOX(textures));
771#endif
772 return true;
773}
774
775void C4ToolsDlg::UpdateIFTControls()
776{
777#ifdef _WIN32
778 if (!hDialog) return;
779 SendDlgItemMessage(hDialog, IDC_BUTTONNOIFT, BM_SETSTATE, (ModeIFT == 0), 0);
780 UpdateWindow(GetDlgItem(hDialog, IDC_BUTTONNOIFT));
781 SendDlgItemMessage(hDialog, IDC_BUTTONIFT, BM_SETSTATE, (ModeIFT == 1), 0);
782 UpdateWindow(GetDlgItem(hDialog, IDC_BUTTONIFT));
783#elif defined(WITH_DEVELOPER_MODE)
784 if (!hbox) return;
785 g_signal_handler_block(instance: no_ift, handler_id: handlerNoIft);
786 g_signal_handler_block(instance: ift, handler_id: handlerIft);
787
788 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(no_ift), is_active: ModeIFT == 0);
789 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ift), is_active: ModeIFT == 1);
790
791 g_signal_handler_unblock(instance: no_ift, handler_id: handlerNoIft);
792 g_signal_handler_unblock(instance: ift, handler_id: handlerIft);
793#endif
794}
795
796void C4ToolsDlg::UpdateLandscapeModeCtrls()
797{
798 int32_t iMode = Game.Landscape.Mode;
799#ifdef _WIN32
800 // Dynamic: enable only if dynamic anyway
801 SendDlgItemMessage(hDialog, IDC_BUTTONMODEDYNAMIC, BM_SETSTATE, (iMode == C4LSC_Dynamic), 0);
802 EnableWindow(GetDlgItem(hDialog, IDC_BUTTONMODEDYNAMIC), (iMode == C4LSC_Dynamic));
803 UpdateWindow(GetDlgItem(hDialog, IDC_BUTTONMODEDYNAMIC));
804 // Static: enable only if map available
805 SendDlgItemMessage(hDialog, IDC_BUTTONMODESTATIC, BM_SETSTATE, (iMode == C4LSC_Static), 0);
806 EnableWindow(GetDlgItem(hDialog, IDC_BUTTONMODESTATIC), (Game.Landscape.Map != nullptr));
807 UpdateWindow(GetDlgItem(hDialog, IDC_BUTTONMODESTATIC));
808 // Exact: enable always
809 SendDlgItemMessage(hDialog, IDC_BUTTONMODEEXACT, BM_SETSTATE, (iMode == C4LSC_Exact), 0);
810 UpdateWindow(GetDlgItem(hDialog, IDC_BUTTONMODEEXACT));
811 // Set dialog caption
812 const char *caption;
813 switch (iMode)
814 {
815 case C4LSC_Dynamic:
816 caption = LoadResStr(C4ResStrTableKey::IDS_DLG_DYNAMIC);
817 break;
818
819 case C4LSC_Static:
820 caption = LoadResStr(C4ResStrTableKey::IDS_DLG_STATIC);
821 break;
822
823 default:
824 caption = LoadResStr(C4ResStrTableKey::IDS_DLG_EXACT);
825 break;
826 }
827 SetWindowText(hDialog, StdStringEncodingConverter::WinAcpToUtf16(caption).c_str());
828#elif defined(WITH_DEVELOPER_MODE)
829 g_signal_handler_block(instance: landscape_dynamic, handler_id: handlerDynamic);
830 g_signal_handler_block(instance: landscape_static, handler_id: handlerStatic);
831 g_signal_handler_block(instance: landscape_exact, handler_id: handlerExact);
832
833 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(landscape_dynamic), is_active: iMode == C4LSC_Dynamic);
834 gtk_widget_set_sensitive(widget: landscape_dynamic, sensitive: iMode == C4LSC_Dynamic);
835
836 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(landscape_static), is_active: iMode == C4LSC_Static);
837 gtk_widget_set_sensitive(widget: landscape_static, sensitive: Game.Landscape.Map != nullptr);
838
839 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(landscape_exact), is_active: iMode == C4LSC_Exact);
840
841 g_signal_handler_unblock(instance: landscape_dynamic, handler_id: handlerDynamic);
842 g_signal_handler_unblock(instance: landscape_static, handler_id: handlerStatic);
843 g_signal_handler_unblock(instance: landscape_exact, handler_id: handlerExact);
844
845 C4Console::GCharStringWrapper title;
846 switch (iMode)
847 {
848 case C4LSC_Dynamic:
849 title = LoadResStrGtk(id: C4ResStrTableKey::IDS_DLG_EXACT);
850 break;
851
852 case C4LSC_Static:
853 title = LoadResStrGtk(id: C4ResStrTableKey::IDS_DLG_EXACT);
854 break;
855
856 default:
857 title = LoadResStrGtk(id: C4ResStrTableKey::IDS_DLG_EXACT);
858 break;
859 }
860
861 C4DevmodeDlg::SetTitle(widget: hbox, title: title.c_str());
862#endif
863}
864
865bool C4ToolsDlg::SetLandscapeMode(int32_t iMode, bool fThroughControl)
866{
867 int32_t iLastMode = Game.Landscape.Mode;
868 // Exact to static: confirm data loss warning
869 if (iLastMode == C4LSC_Exact)
870 if (iMode == C4LSC_Static)
871 if (!fThroughControl)
872 if (!Console.Message(szMessage: LoadResStr(id: C4ResStrTableKey::IDS_CNS_EXACTTOSTATIC), fQuery: true))
873 return false;
874 // send as control
875 if (!fThroughControl)
876 {
877 Game.Control.DoInput(eCtrlType: CID_EMDrawTool, pPkt: new C4ControlEMDrawTool(EMDT_SetMode, iMode), eDelivery: CDT_Decide);
878 return true;
879 }
880 // Set landscape mode
881 Game.Landscape.SetMode(iMode);
882 // Exact to static: redraw landscape from map
883 if (iLastMode == C4LSC_Exact)
884 if (iMode == C4LSC_Static)
885 Game.Landscape.MapToLandscape();
886 // Assert valid tool
887 if (iMode != C4LSC_Exact)
888 if (SelectedTool == C4TLS_Fill)
889 SetTool(iTool: C4TLS_Brush, fTemp: false);
890 // Update controls
891 UpdateLandscapeModeCtrls();
892 EnableControls();
893 UpdateTextures();
894 // Success
895 return true;
896}
897
898void C4ToolsDlg::EnableControls()
899{
900 int32_t iLandscapeMode = Game.Landscape.Mode;
901#ifdef _WIN32
902 // Set bitmap buttons
903 SendDlgItemMessage(hDialog, IDC_BUTTONBRUSH, BM_SETIMAGE, IMAGE_BITMAP, reinterpret_cast<LPARAM>((iLandscapeMode >= C4LSC_Static) ? hbmBrush : hbmBrush2));
904 SendDlgItemMessage(hDialog, IDC_BUTTONLINE, BM_SETIMAGE, IMAGE_BITMAP, reinterpret_cast<LPARAM>((iLandscapeMode >= C4LSC_Static) ? hbmLine : hbmLine2));
905 SendDlgItemMessage(hDialog, IDC_BUTTONRECT, BM_SETIMAGE, IMAGE_BITMAP, reinterpret_cast<LPARAM>((iLandscapeMode >= C4LSC_Static) ? hbmRect : hbmRect2));
906 SendDlgItemMessage(hDialog, IDC_BUTTONFILL, BM_SETIMAGE, IMAGE_BITMAP, reinterpret_cast<LPARAM>((iLandscapeMode >= C4LSC_Exact) ? hbmFill : hbmFill2));
907 SendDlgItemMessage(hDialog, IDC_BUTTONPICKER, BM_SETIMAGE, IMAGE_BITMAP, reinterpret_cast<LPARAM>((iLandscapeMode >= C4LSC_Static) ? hbmPicker : hbmPicker2));
908 SendDlgItemMessage(hDialog, IDC_BUTTONIFT, BM_SETIMAGE, IMAGE_BITMAP, reinterpret_cast<LPARAM>(hbmIFT));
909 SendDlgItemMessage(hDialog, IDC_BUTTONNOIFT, BM_SETIMAGE, IMAGE_BITMAP, reinterpret_cast<LPARAM>(hbmNoIFT));
910 SendDlgItemMessage(hDialog, IDC_BUTTONMODEDYNAMIC, BM_SETIMAGE, IMAGE_BITMAP, reinterpret_cast<LPARAM>(hbmDynamic));
911 SendDlgItemMessage(hDialog, IDC_BUTTONMODESTATIC, BM_SETIMAGE, IMAGE_BITMAP, reinterpret_cast<LPARAM>(hbmStatic));
912 SendDlgItemMessage(hDialog, IDC_BUTTONMODEEXACT, BM_SETIMAGE, IMAGE_BITMAP, reinterpret_cast<LPARAM>(hbmExact));
913 // Enable drawing controls
914 EnableWindow(GetDlgItem(hDialog, IDC_BUTTONBRUSH), (iLandscapeMode >= C4LSC_Static));
915 EnableWindow(GetDlgItem(hDialog, IDC_BUTTONLINE), (iLandscapeMode >= C4LSC_Static));
916 EnableWindow(GetDlgItem(hDialog, IDC_BUTTONRECT), (iLandscapeMode >= C4LSC_Static));
917 EnableWindow(GetDlgItem(hDialog, IDC_BUTTONFILL), (iLandscapeMode >= C4LSC_Exact));
918 EnableWindow(GetDlgItem(hDialog, IDC_BUTTONPICKER), (iLandscapeMode >= C4LSC_Static));
919 EnableWindow(GetDlgItem(hDialog, IDC_BUTTONIFT), (iLandscapeMode >= C4LSC_Static));
920 EnableWindow(GetDlgItem(hDialog, IDC_BUTTONNOIFT), (iLandscapeMode >= C4LSC_Static));
921 EnableWindow(GetDlgItem(hDialog, IDC_COMBOMATERIAL), (iLandscapeMode >= C4LSC_Static));
922 EnableWindow(GetDlgItem(hDialog, IDC_COMBOTEXTURE), (iLandscapeMode >= C4LSC_Static) && !SEqual(Material, C4TLS_MatSky));
923 EnableWindow(GetDlgItem(hDialog, IDC_STATICMATERIAL), (iLandscapeMode >= C4LSC_Static));
924 EnableWindow(GetDlgItem(hDialog, IDC_STATICTEXTURE), (iLandscapeMode >= C4LSC_Static) && !SEqual(Material, C4TLS_MatSky));
925 EnableWindow(GetDlgItem(hDialog, IDC_SLIDERGRADE), (iLandscapeMode >= C4LSC_Static));
926 EnableWindow(GetDlgItem(hDialog, IDC_PREVIEW), (iLandscapeMode >= C4LSC_Static));
927#elif defined(WITH_DEVELOPER_MODE)
928 gtk_widget_set_sensitive(widget: brush, sensitive: iLandscapeMode >= C4LSC_Static);
929 gtk_widget_set_sensitive(widget: line, sensitive: iLandscapeMode >= C4LSC_Static);
930 gtk_widget_set_sensitive(widget: rect, sensitive: iLandscapeMode >= C4LSC_Static);
931 gtk_widget_set_sensitive(widget: fill, sensitive: iLandscapeMode >= C4LSC_Exact);
932 gtk_widget_set_sensitive(widget: picker, sensitive: iLandscapeMode >= C4LSC_Static);
933 gtk_widget_set_sensitive(widget: ift, sensitive: iLandscapeMode >= C4LSC_Static);
934 gtk_widget_set_sensitive(widget: no_ift, sensitive: iLandscapeMode >= C4LSC_Static);
935 gtk_widget_set_sensitive(widget: materials, sensitive: iLandscapeMode >= C4LSC_Static);
936 gtk_widget_set_sensitive(widget: textures, sensitive: iLandscapeMode >= C4LSC_Static && !SEqual(szStr1: Material, C4TLS_MatSky));
937 gtk_widget_set_sensitive(widget: scale, sensitive: iLandscapeMode >= C4LSC_Static);
938 gtk_widget_set_sensitive(widget: preview, sensitive: iLandscapeMode >= C4LSC_Static);
939#endif // _WIN32/WITH_DEVELOPER_MODE
940 UpdatePreview();
941}
942
943#ifdef _WIN32
944void C4ToolsDlg::LoadBitmaps()
945{
946 HINSTANCE hInst = Application.hInstance;
947 if (!hbmBrush) hbmBrush = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_BRUSH));
948 if (!hbmLine) hbmLine = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_LINE));
949 if (!hbmRect) hbmRect = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_RECT));
950 if (!hbmFill) hbmFill = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_FILL));
951 if (!hbmPicker) hbmPicker = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_PICKER));
952 if (!hbmBrush2) hbmBrush2 = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_BRUSH2));
953 if (!hbmLine2) hbmLine2 = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_LINE2));
954 if (!hbmRect2) hbmRect2 = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_RECT2));
955 if (!hbmFill2) hbmFill2 = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_FILL2));
956 if (!hbmPicker2) hbmPicker2 = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_PICKER2));
957 if (!hbmIFT) hbmIFT = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_IFT));
958 if (!hbmNoIFT) hbmNoIFT = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_NOIFT));
959 if (!hbmDynamic) hbmDynamic = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_DYNAMIC));
960 if (!hbmStatic) hbmStatic = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_STATIC));
961 if (!hbmExact) hbmExact = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_EXACT));
962}
963#endif
964
965void C4ToolsDlg::AssertValidTexture()
966{
967 // Static map mode only
968 if (Game.Landscape.Mode != C4LSC_Static) return;
969 // Ignore if sky
970 if (SEqual(szStr1: Material, C4TLS_MatSky)) return;
971 // Current material-texture valid
972 if (Game.TextureMap.GetIndex(szMaterial: Material, szTexture: Texture, fAddIfNotExist: false)) return;
973 // Find valid material-texture
974 const char *szTexture;
975 for (int32_t iTexture = 0; szTexture = Game.TextureMap.GetTexture(iIndex: iTexture); iTexture++)
976 {
977 if (Game.TextureMap.GetIndex(szMaterial: Material, szTexture, fAddIfNotExist: false))
978 {
979 SelectTexture(szTexture); return;
980 }
981 }
982 // No valid texture found
983}
984
985bool C4ToolsDlg::SelectTexture(const char *szTexture)
986{
987#ifdef _WIN32
988 SendDlgItemMessage(hDialog, IDC_COMBOTEXTURE, CB_SELECTSTRING, 0, reinterpret_cast<LPARAM>(StdStringEncodingConverter::WinAcpToUtf16(szTexture).c_str()));
989#elif defined(WITH_DEVELOPER_MODE)
990 g_signal_handler_block(instance: textures, handler_id: handlerTextures);
991 SelectComboBoxText(GTK_COMBO_BOX(textures), text: szTexture);
992 g_signal_handler_unblock(instance: textures, handler_id: handlerTextures);
993#endif
994 SetTexture(szTexture);
995 return true;
996}
997
998bool C4ToolsDlg::SelectMaterial(const char *szMaterial)
999{
1000#ifdef _WIN32
1001 SendDlgItemMessage(hDialog, IDC_COMBOMATERIAL, CB_SELECTSTRING, 0, reinterpret_cast<LPARAM>(StdStringEncodingConverter::WinAcpToUtf16(szMaterial).c_str()));
1002#elif defined(WITH_DEVELOPER_MODE)
1003 g_signal_handler_block(instance: materials, handler_id: handlerMaterials);
1004 SelectComboBoxText(GTK_COMBO_BOX(materials), text: szMaterial);
1005 g_signal_handler_unblock(instance: materials, handler_id: handlerMaterials);
1006#endif
1007 SetMaterial(szMaterial);
1008 return true;
1009}
1010
1011void C4ToolsDlg::SetAlternateTool()
1012{
1013 // alternate tool is the picker in any mode
1014 SetTool(iTool: C4TLS_Picker, fTemp: true);
1015}
1016
1017void C4ToolsDlg::ResetAlternateTool()
1018{
1019 // reset tool to selected tool in case alternate tool was set
1020 SetTool(iTool: SelectedTool, fTemp: true);
1021}
1022
1023#ifdef WITH_DEVELOPER_MODE
1024
1025// GTK+ callbacks
1026
1027void C4ToolsDlg::OnButtonModeDynamic(GtkWidget *widget, gpointer data)
1028{
1029 static_cast<C4ToolsDlg *>(data)->SetLandscapeMode(iMode: C4LSC_Dynamic);
1030}
1031
1032void C4ToolsDlg::OnButtonModeStatic(GtkWidget *widget, gpointer data)
1033{
1034 static_cast<C4ToolsDlg *>(data)->SetLandscapeMode(iMode: C4LSC_Static);
1035}
1036
1037void C4ToolsDlg::OnButtonModeExact(GtkWidget *widget, gpointer data)
1038{
1039 static_cast<C4ToolsDlg *>(data)->SetLandscapeMode(iMode: C4LSC_Exact);
1040}
1041
1042void C4ToolsDlg::OnButtonBrush(GtkWidget *widget, gpointer data)
1043{
1044 static_cast<C4ToolsDlg *>(data)->SetTool(iTool: C4TLS_Brush, fTemp: false);
1045}
1046
1047void C4ToolsDlg::OnButtonLine(GtkWidget *widget, gpointer data)
1048{
1049 static_cast<C4ToolsDlg *>(data)->SetTool(iTool: C4TLS_Line, fTemp: false);
1050}
1051
1052void C4ToolsDlg::OnButtonRect(GtkWidget *widget, gpointer data)
1053{
1054 static_cast<C4ToolsDlg *>(data)->SetTool(iTool: C4TLS_Rect, fTemp: false);
1055}
1056
1057void C4ToolsDlg::OnButtonFill(GtkWidget *widget, gpointer data)
1058{
1059 static_cast<C4ToolsDlg *>(data)->SetTool(iTool: C4TLS_Fill, fTemp: false);
1060}
1061
1062void C4ToolsDlg::OnButtonPicker(GtkWidget *widget, gpointer data)
1063{
1064 static_cast<C4ToolsDlg *>(data)->SetTool(iTool: C4TLS_Picker, fTemp: false);
1065}
1066
1067void C4ToolsDlg::OnButtonIft(GtkWidget *widget, gpointer data)
1068{
1069 static_cast<C4ToolsDlg *>(data)->SetIFT(true);
1070}
1071
1072void C4ToolsDlg::OnButtonNoIft(GtkWidget *widget, gpointer data)
1073{
1074 static_cast<C4ToolsDlg *>(data)->SetIFT(false);
1075}
1076
1077void C4ToolsDlg::OnComboMaterial(GtkWidget *widget, gpointer data)
1078{
1079 gchar *text = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(widget));
1080 static_cast<C4ToolsDlg *>(data)->SetMaterial(text);
1081 g_free(mem: text);
1082}
1083
1084void C4ToolsDlg::OnComboTexture(GtkWidget *widget, gpointer data)
1085{
1086 gchar *text = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(widget));
1087 static_cast<C4ToolsDlg *>(data)->SetTexture(text);
1088 g_free(mem: text);
1089}
1090
1091void C4ToolsDlg::OnGrade(GtkWidget *widget, gpointer data)
1092{
1093 C4ToolsDlg *dlg = static_cast<C4ToolsDlg *>(data);
1094 int value = static_cast<int>(gtk_range_get_value(GTK_RANGE(dlg->scale)) + 0.5);
1095 dlg->SetGrade(C4TLS_GradeMax - value);
1096}
1097
1098void C4ToolsDlg::OnWindowHide(GtkWidget *widget, gpointer data)
1099{
1100 static_cast<C4ToolsDlg *>(data)->Active = false;
1101}
1102
1103#endif
1104