/src/editor/C4PropertyDlg.cpp
C++ | 424 lines | 307 code | 39 blank | 78 comment | 35 complexity | c83d184d8e71c0e03c6b27ca8bfbc898 MD5 | raw file
Possible License(s): WTFPL, 0BSD, LGPL-2.1, CC-BY-3.0
1/*
2 * OpenClonk, http://www.openclonk.org
3 *
4 * Copyright (c) 1998-2000 Matthes Bender
5 * Copyright (c) 2001, 2006 Peter Wortmann
6 * Copyright (c) 2001 Sven Eberhardt
7 * Copyright (c) 2005, 2007 G?nther Brammer
8 * Copyright (c) 2006-2007 Armin Burgmeier
9 * Copyright (c) 2009 Nicolas Hake
10 * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de
11 *
12 * Portions might be copyrighted by other authors who have contributed
13 * to OpenClonk.
14 *
15 * Permission to use, copy, modify, and/or distribute this software for any
16 * purpose with or without fee is hereby granted, provided that the above
17 * copyright notice and this permission notice appear in all copies.
18 * See isc_license.txt for full license and disclaimer.
19 *
20 * "Clonk" is a registered trademark of Matthes Bender.
21 * See clonk_trademark_license.txt for full license.
22 */
23
24/* Console mode dialog for object properties and script interface */
25
26#include <C4Include.h>
27#include <C4PropertyDlg.h>
28
29#ifndef BIG_C4INCLUDE
30#include <C4Console.h>
31#include <C4Application.h>
32#include <C4Object.h>
33#include <C4Player.h>
34#include <C4Game.h>
35#include <C4PlayerList.h>
36#include <C4GameObjects.h>
37#endif
38
39#include <StdRegistry.h>
40
41#ifdef WITH_DEVELOPER_MODE
42# include <C4DevmodeDlg.h>
43# include <C4Language.h>
44
45# include <gtk/gtkentry.h>
46# include <gtk/gtkvbox.h>
47# include <gtk/gtktextview.h>
48# include <gtk/gtkwindow.h>
49# include <gtk/gtkscrolledwindow.h>
50#endif
51
52#ifdef _WIN32
53BOOL CALLBACK PropertyDlgProc(HWND hDlg, UINT Msg, WPARAM wParam, LPARAM lParam)
54 {
55 switch (Msg)
56 {
57 //------------------------------------------------------------------------------------------------
58 case WM_CLOSE:
59 Console.PropertyDlg.Clear();
60 break;
61 //------------------------------------------------------------------------------------------------
62 case WM_DESTROY:
63 StoreWindowPosition(hDlg, "Property", Config.GetSubkeyPath("Console"), FALSE);
64 break;
65 //------------------------------------------------------------------------------------------------
66 case WM_INITDIALOG:
67 SendMessage(hDlg,DM_SETDEFID,(WPARAM)IDOK,(LPARAM)0);
68 return TRUE;
69 //------------------------------------------------------------------------------------------------
70 case WM_COMMAND:
71 // Evaluate command
72 switch (LOWORD(wParam))
73 {
74 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
75 case IDOK:
76 // IDC_COMBOINPUT to Console.EditCursor.In()
77 char buffer[16000];
78 GetDlgItemText(hDlg,IDC_COMBOINPUT,buffer,16000);
79 if (buffer[0])
80 Console.EditCursor.In(buffer);
81 return TRUE;
82 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
83 case IDC_BUTTONRELOADDEF:
84 Game.ReloadDef( Console.PropertyDlg.idSelectedDef );
85 return TRUE;
86 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
87 }
88 return FALSE;
89 //-----------------------------------------------------------------------------------------------
90 }
91 return FALSE;
92 }
93#endif
94C4PropertyDlg::C4PropertyDlg()
95 {
96 Default();
97 }
98
99C4PropertyDlg::~C4PropertyDlg()
100 {
101 Clear();
102
103#ifdef WITH_DEVELOPER_MODE
104 if(vbox != NULL)
105 {
106 g_signal_handler_disconnect(G_OBJECT(C4DevmodeDlg::GetWindow()), handlerHide);
107 C4DevmodeDlg::RemovePage(vbox);
108 vbox = NULL;
109 }
110#endif // WITH_DEVELOPER_MODE
111 }
112
113bool C4PropertyDlg::Open()
114 {
115#ifdef _WIN32
116 if (hDialog) return true;
117 hDialog = CreateDialog(Application.GetInstance(),
118 MAKEINTRESOURCE(IDD_PROPERTIES),
119 Console.hWindow,
120 (DLGPROC) PropertyDlgProc);
121 if (!hDialog) return false;
122 // Set text
123 SetWindowText(hDialog,LoadResStr("IDS_DLG_PROPERTIES"));
124 // Enable controls
125 EnableWindow( GetDlgItem(hDialog,IDOK), Console.Editing );
126 EnableWindow( GetDlgItem(hDialog,IDC_COMBOINPUT), Console.Editing );
127 EnableWindow( GetDlgItem(hDialog,IDC_BUTTONRELOADDEF), Console.Editing );
128 // Show window
129 RestoreWindowPosition(hDialog, "Property", Config.GetSubkeyPath("Console"));
130 SetWindowPos(hDialog,HWND_TOPMOST,0,0,0,0,SWP_NOSIZE | SWP_NOMOVE);
131 ShowWindow(hDialog,SW_SHOWNORMAL | SW_SHOWNA);
132#else // _WIN32
133#ifdef WITH_DEVELOPER_MODE
134 if(vbox == NULL)
135 {
136 vbox = gtk_vbox_new(false, 6);
137
138 GtkWidget* scrolled_wnd = gtk_scrolled_window_new(NULL, NULL);
139 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_wnd), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
140 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled_wnd), GTK_SHADOW_IN);
141
142 textview = gtk_text_view_new();
143 entry = gtk_entry_new();
144
145 gtk_container_add(GTK_CONTAINER(scrolled_wnd), textview);
146 gtk_box_pack_start(GTK_BOX(vbox), scrolled_wnd, true, true, 0);
147 gtk_box_pack_start(GTK_BOX(vbox), entry, false, false, 0);
148
149 gtk_text_view_set_editable(GTK_TEXT_VIEW(textview), false);
150 gtk_widget_set_sensitive(entry, Console.Editing);
151
152 gtk_widget_show_all(vbox);
153
154 C4DevmodeDlg::AddPage(vbox, GTK_WINDOW(Console.window), LoadResStr("IDS_DLG_PROPERTIES"));
155
156 g_signal_connect(G_OBJECT(entry), "activate", G_CALLBACK(OnScriptActivate), this);
157
158 handlerHide = g_signal_connect(G_OBJECT(C4DevmodeDlg::GetWindow()), "hide", G_CALLBACK(OnWindowHide), this);
159 }
160
161 C4DevmodeDlg::SwitchPage(vbox);
162#endif // WITH_DEVELOPER_MODE
163#endif // _WIN32
164 Active = true;
165 return true;
166 }
167
168bool C4PropertyDlg::Update(C4ObjectList &rSelection)
169 {
170 if (!Active) return false;
171 // Set new selection
172 Selection.Copy(rSelection);
173 // Update input control
174 UpdateInputCtrl(Selection.GetObject());
175 // Update contents
176 return Update();
177 }
178
179bool IsObjectPointer(int iValue)
180 {
181 for (C4ObjectLink *cLnk=::Objects.First; cLnk; cLnk=cLnk->Next)
182 if (cLnk->Obj == (C4Object*) iValue)
183 return true;
184 return false;
185 }
186
187bool C4PropertyDlg::Update()
188 {
189 if (!Active) return false;
190
191 StdStrBuf Output;
192
193 idSelectedDef=C4ID_None;
194
195 // Compose info text by selected object(s)
196 switch (Selection.ObjectCount())
197 {
198 // No selection
199 case 0:
200 Output = LoadResStr("IDS_CNS_NOOBJECT");
201 break;
202 // One selected object
203 case 1:
204 {
205 C4Object *cobj=Selection.GetObject();
206 DecompileToBuf_Log<StdCompilerINIWrite>(mkNamingAdapt(*cobj, "Object"), &Output, "C4PropertyDlg::Update");
207 // Type
208 Output.AppendFormat(LoadResStr("IDS_CNS_TYPE"),cobj->GetName(),C4IdText(cobj->Def->id));
209 // Owner
210 if (ValidPlr(cobj->Owner))
211 {
212 Output.Append(LineFeed);
213 Output.AppendFormat(LoadResStr("IDS_CNS_OWNER"),::Players.Get(cobj->Owner)->GetName());
214 }
215 // Contents
216 if (cobj->Contents.ObjectCount())
217 {
218 Output.Append(LineFeed);
219 Output.Append(LoadResStr("IDS_CNS_CONTENTS"));
220 Output.Append(static_cast<const StdStrBuf &>(cobj->Contents.GetNameList(::Definitions)));
221 }
222 // Action
223 if (cobj->Action.pActionDef)
224 {
225 Output.Append(LineFeed);
226 Output.Append(LoadResStr("IDS_CNS_ACTION"));
227 Output.Append(cobj->Action.pActionDef->GetName());
228 }
229 // Locals
230 int cnt; bool fFirstLocal = true;
231 for (cnt=0; cnt < cobj->LocalNamed.GetAnzItems(); cnt++)
232 {
233 // Header
234 if (fFirstLocal) { Output.Append(LineFeed); Output.Append(LoadResStr("IDS_CNS_LOCALS")); fFirstLocal = false; }
235 Output.Append(LineFeed);
236 // Append name
237 Output.AppendFormat(" %s = ", cobj->LocalNamed.pNames->pNames[cnt]);
238 // write value
239 Output.Append(static_cast<const StdStrBuf &>(cobj->LocalNamed.pData[cnt].GetDataString()));
240 }
241 // Effects
242 for(C4Effect *pEffect = cobj->pEffects; pEffect; pEffect = pEffect->pNext)
243 {
244 // Header
245 if (pEffect == cobj->pEffects)
246 {
247 Output.Append(LineFeed);
248 Output.Append(LoadResStr("IDS_CNS_EFFECTS"));
249 }
250 Output.Append(LineFeed);
251 // Effect name
252 Output.AppendFormat(" %s: Interval %d", pEffect->Name, pEffect->iIntervall);
253 }
254 // Store selected def
255 idSelectedDef=cobj->id;
256 break;
257 }
258 // Multiple selected objects
259 default:
260 Output.Format(LoadResStr("IDS_CNS_MULTIPLEOBJECTS"),Selection.ObjectCount());
261 break;
262 }
263 // Update info edit control
264#ifdef _WIN32
265 int iLine = SendDlgItemMessage(hDialog,IDC_EDITOUTPUT,EM_GETFIRSTVISIBLELINE,(WPARAM)0,(LPARAM)0);
266 SetDlgItemText(hDialog,IDC_EDITOUTPUT,Output.getData());
267 SendDlgItemMessage(hDialog,IDC_EDITOUTPUT,EM_LINESCROLL,(WPARAM)0,(LPARAM)iLine);
268 UpdateWindow(GetDlgItem(hDialog,IDC_EDITOUTPUT));
269#else
270#ifdef WITH_DEVELOPER_MODE
271 GtkTextBuffer* buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview));
272 gtk_text_buffer_set_text(buffer, Output.getData(), -1);
273#endif
274#endif
275 return true;
276 }
277
278void C4PropertyDlg::Default()
279 {
280#ifdef _WIN32
281 hDialog=NULL;
282#else
283#ifdef WITH_DEVELOPER_MODE
284 vbox = NULL;
285#endif
286#endif
287 Active = false;
288 idSelectedDef=C4ID_None;
289 Selection.Default();
290 }
291
292void C4PropertyDlg::Clear()
293 {
294 Selection.Clear();
295#ifdef _WIN32
296 if (hDialog) DestroyWindow(hDialog); hDialog=NULL;
297#else
298#ifdef WITH_DEVELOPER_MODE
299 //if(vbox != NULL)
300 // C4DevmodeDlg::SwitchPage(NULL);
301#endif
302#endif
303 Active = false;
304 }
305
306void C4PropertyDlg::UpdateInputCtrl(C4Object *pObj)
307 {
308 int cnt;
309#ifdef _WIN32
310 HWND hCombo = GetDlgItem(hDialog,IDC_COMBOINPUT);
311 // Remember old window text
312 char szLastText[500+1];
313 GetWindowText(hCombo,szLastText,500);
314 // Clear
315 SendMessage(hCombo,CB_RESETCONTENT,0,0);
316#else // _WIN32
317#ifdef WITH_DEVELOPER_MODE
318
319 GtkEntryCompletion* completion = gtk_entry_get_completion(GTK_ENTRY(entry));
320 GtkListStore* store;
321
322 // Uncouple list store from completion so that the completion is not
323 // notified for every row we are going to insert. This enhances
324 // performance significantly.
325 if(!completion)
326 {
327 completion = gtk_entry_completion_new();
328 store = gtk_list_store_new(1, G_TYPE_STRING);
329
330 gtk_entry_completion_set_text_column(completion, 0);
331 gtk_entry_set_completion(GTK_ENTRY(entry), completion);
332 g_object_unref(G_OBJECT(completion));
333 }
334 else
335 {
336 store = GTK_LIST_STORE(gtk_entry_completion_get_model(completion));
337 g_object_ref(G_OBJECT(store));
338 gtk_entry_completion_set_model(completion, NULL);
339 }
340
341 GtkTreeIter iter;
342 gtk_list_store_clear(store);
343#endif // WITH_DEVELOPER_MODE
344#endif // _WIN32
345
346 // add global and standard functions
347 for (C4AulFunc *pFn = ::ScriptEngine.GetFirstFunc(); pFn; pFn = ::ScriptEngine.GetNextFunc(pFn))
348 if (pFn->GetPublic())
349 {
350#ifdef _WIN32
351 SendMessage(hCombo,CB_ADDSTRING,0,(LPARAM)pFn->Name);
352#else
353#ifdef WITH_DEVELOPER_MODE
354 gtk_list_store_append(store, &iter);
355 gtk_list_store_set(store, &iter, 0, pFn->Name, -1);
356#endif
357#endif
358 }
359 // Add object script functions
360#ifdef _WIN32
361 bool fDivider = false;
362#endif
363 C4AulScriptFunc *pRef;
364 // Object script available
365 if (pObj && pObj->Def)
366 // Scan all functions
367 for (cnt=0; pRef=pObj->Def->Script.GetSFunc(cnt); cnt++)
368 // Public functions only
369 if (pRef->Access=AA_PUBLIC)
370 {
371#ifdef _WIN32
372 // Insert divider if necessary
373 if (!fDivider) { SendMessage(hCombo,CB_INSERTSTRING,0,(LPARAM)"----------"); fDivider=true; }
374#endif
375 // Add function
376#ifdef _WIN32
377 SendMessage(hCombo,CB_INSERTSTRING,0,(LPARAM)pRef->Name);
378#else
379#ifdef WITH_DEVELOPER_MODE
380 gtk_list_store_append(store, &iter);
381 gtk_list_store_set(store, &iter, 0, pRef->Name, -1);
382#endif
383#endif
384 }
385
386#ifdef _WIN32
387 // Restore old text
388 SetWindowText(hCombo,szLastText);
389#elif defined(WITH_DEVELOPER_MODE)
390 // Reassociate list store with completion
391 gtk_entry_completion_set_model(completion, GTK_TREE_MODEL(store));
392#endif
393 }
394
395void C4PropertyDlg::Execute()
396 {
397 if (!::Game.iTick35) Update();
398 }
399
400void C4PropertyDlg::ClearPointers(C4Object *pObj)
401 {
402 Selection.ClearPointers(pObj);
403 }
404
405#ifdef WITH_DEVELOPER_MODE
406// GTK+ callbacks
407void C4PropertyDlg::OnScriptActivate(GtkWidget* widget, gpointer data)
408{
409 const gchar* text = gtk_entry_get_text(GTK_ENTRY(widget));
410 if(text && text[0])
411 Console.EditCursor.In(text);
412}
413
414void C4PropertyDlg::OnWindowHide(GtkWidget* widget, gpointer user_data)
415{
416 static_cast<C4PropertyDlg*>(user_data)->Active = false;
417}
418
419/*void C4PropertyDlg::OnDestroy(GtkWidget* widget, gpointer data)
420{
421 static_cast<C4PropertyDlg*>(data)->window = NULL;
422 static_cast<C4PropertyDlg*>(data)->Active = false;
423}*/
424#endif