/src/editor/C4PropertyDlg.cpp

https://bitbucket.org/randrian/openclonk2 · C++ · 424 lines · 307 code · 39 blank · 78 comment · 35 complexity · c83d184d8e71c0e03c6b27ca8bfbc898 MD5 · raw file

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