testwindow.pas 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. {
  2. FreePascal / Delphi bindings for ImGui
  3. Copyright (C) 2023 Coldzer0 <Coldzer0 [at] protonmail.ch>
  4. This program is free software: you can redistribute it and/or modify
  5. it under the terms of the MIT License.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  9. MIT License for more details.
  10. }
  11. {
  12. Code From https://github.com/dpethes/imgui-pas - Updated by Coldzer0
  13. Partial translation of imgui demo / ShowTestWindow
  14. While you're probably better off with the original version as it's way more extensive,
  15. this is good as
  16. * a test case for the bindings or
  17. * a quick guide if something isn't translated in a straightforward way
  18. }
  19. Unit TestWindow;
  20. {$IFDEF FPC}
  21. {$mode objfpc}{$H+}
  22. {$ENDIF}
  23. {$J+}
  24. Interface
  25. Uses
  26. Classes,
  27. SysUtils,
  28. PasImGui,
  29. PasImGui.Utils;
  30. Type
  31. { TTestWindow }
  32. TTestWindow = Class
  33. Private
  34. show_app_main_menu_bar: boolean;
  35. show_app_console: boolean;
  36. show_app_log: boolean;
  37. show_app_layout: boolean;
  38. show_app_property_editor: boolean;
  39. show_app_long_text: boolean;
  40. show_app_auto_resize: boolean;
  41. show_app_constrained_resize: boolean;
  42. show_app_fixed_overlay: boolean;
  43. show_app_manipulating_window_title: boolean;
  44. show_app_custom_rendering: boolean;
  45. show_app_style_editor: boolean;
  46. show_app_metrics: boolean;
  47. show_app_about: boolean;
  48. no_titlebar: boolean;
  49. no_resize: boolean;
  50. no_move: boolean;
  51. no_scrollbar: boolean;
  52. no_collapse: boolean;
  53. no_menu: boolean;
  54. Procedure Trees;
  55. Public
  56. Constructor Create;
  57. Procedure Show(Var p_open: boolean);
  58. End;
  59. Implementation
  60. Procedure ShowHelpMarker(Const desc: AnsiString);
  61. Begin
  62. ImGui.TextDisabled('(?)');
  63. If (ImGui.IsItemHovered()) Then
  64. Begin
  65. ImGui.BeginTooltip();
  66. ImGui.PushTextWrapPos(450.0);
  67. ImGui.TextUnformatted(desc);
  68. ImGui.PopTextWrapPos();
  69. ImGui.EndTooltip();
  70. End;
  71. End;
  72. { TTestWindow }
  73. Procedure TTestWindow.Trees;
  74. Const //static vars
  75. align_label_with_current_x_position: boolean = False;
  76. selection_mask: integer = 1 shl 2;
  77. // Dumb representation of what may be user-side selection state. You may carry selection state inside or outside your objects in whatever format you see fit.
  78. Var
  79. node_open: Boolean;
  80. node_clicked: Integer;
  81. i: Integer;
  82. node_flags: ImGuiTreeNodeFlags;
  83. Begin
  84. If (ImGui.TreeNode('Basic trees')) Then
  85. Begin
  86. For i := 0 To 4 Do
  87. If (ImGui.TreeNode({%H-}PImGuiID(i), 'Child %d', [i])) Then
  88. Begin
  89. ImGui.Text('blah blah');
  90. ImGui.SameLine();
  91. If (ImGui.SmallButton('print')) Then
  92. begin
  93. ImGui.LogText('Child ' + i.ToString + ' pressed');
  94. Imgui.LogFinish;
  95. end;
  96. ImGui.TreePop();
  97. End;
  98. ImGui.TreePop();
  99. End;
  100. If (ImGui.TreeNode('Advanced, with Selectable nodes')) Then
  101. Begin
  102. ShowHelpMarker('This is a more standard looking tree with selectable nodes.' + #10 +
  103. 'Click to select, CTRL+Click to toggle, click on arrows or double-click to open.');
  104. ImGui.Checkbox('Align label with current X position)',
  105. @align_label_with_current_x_position);
  106. ImGui.Text('Hello!');
  107. If (align_label_with_current_x_position) Then
  108. ImGui.Unindent(ImGui.GetTreeNodeToLabelSpacing());
  109. node_clicked := -1;
  110. // Temporary storage of what node we have clicked to process selection at the end of the loop. May be a pointer to your own node type, etc.
  111. ImGui.PushStyleVar(ImGuiStyleVar_IndentSpacing, ImGui.GetFontSize() * 3);
  112. // Increase spacing to differentiate leaves from expanded contents.
  113. For i := 0 To 5 Do
  114. Begin
  115. // Disable the default open on single-click behavior and pass in Selected flag according to our selection state.
  116. //ImGuiTreeNodeFlags node_flags := ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ((selection_mask & (1 << i)) ? ImGuiTreeNodeFlags_Selected : 0);
  117. node_flags := ImGuiTreeNodeFlags_OpenOnArrow Or
  118. ImGuiTreeNodeFlags_OpenOnDoubleClick;
  119. If (selection_mask And (1 shl i)) > 0 Then
  120. node_flags := node_flags Or ImGuiTreeNodeFlags_Selected;
  121. If (i < 3) Then
  122. Begin
  123. // Node
  124. node_open := ImGui.TreeNodeEx({%H-}PImGuiID(i), node_flags,
  125. 'Selectable Node %d', [i]);
  126. If (ImGui.IsItemClicked()) Then
  127. node_clicked := i;
  128. If (node_open) Then
  129. Begin
  130. ImGui.Text('Blah blah' + #10 + 'Blah Blah');
  131. ImGui.TreePop();
  132. End;
  133. End
  134. Else
  135. Begin
  136. // Leaf: The only reason we have a TreeNode at all is to allow selection of the leaf. Otherwise we can use BulletText() or TreeAdvanceToLabelPos()+Text().
  137. node_flags := node_flags Or ImGuiTreeNodeFlags_Leaf Or
  138. ImGuiTreeNodeFlags_NoTreePushOnOpen;
  139. ImGui.TreeNodeEx({%H-}PImGuiID(i), node_flags, 'Selectable Leaf %d', [i]);
  140. If (ImGui.IsItemClicked()) Then
  141. node_clicked := i;
  142. End;
  143. End;
  144. If (node_clicked <> -1) Then
  145. Begin
  146. // Update selection state. Process outside of tree loop to avoid visual inconsistencies during the clicking-frame.
  147. If (ImGui.GetIO()^.KeyCtrl) Then
  148. selection_mask := selection_mask Xor (1 shl node_clicked) // CTRL+click to toggle
  149. Else
  150. //if (!(selection_mask & (1 << node_clicked))) // Depending on selection behavior you want, this commented bit preserve selection when clicking on item that is part of the selection
  151. selection_mask := (1 shl node_clicked); // Click to single-select
  152. End;
  153. ImGui.PopStyleVar();
  154. If (align_label_with_current_x_position) Then
  155. ImGui.Indent(ImGui.GetTreeNodeToLabelSpacing());
  156. ImGui.TreePop();
  157. End;
  158. ImGui.TreePop();
  159. End;
  160. Constructor TTestWindow.Create;
  161. Begin
  162. show_app_main_menu_bar := False;
  163. show_app_console := False;
  164. show_app_log := False;
  165. show_app_layout := False;
  166. show_app_property_editor := False;
  167. show_app_long_text := False;
  168. show_app_auto_resize := False;
  169. show_app_constrained_resize := False;
  170. show_app_fixed_overlay := False;
  171. show_app_manipulating_window_title := False;
  172. show_app_custom_rendering := False;
  173. show_app_style_editor := False;
  174. show_app_metrics := False;
  175. show_app_about := False;
  176. no_titlebar := False;
  177. no_resize := False;
  178. no_move := False;
  179. no_scrollbar := False;
  180. no_collapse := False;
  181. no_menu := False;
  182. End;
  183. Procedure TTestWindow.Show(Var p_open: boolean);
  184. Var
  185. io: PImGuiIO;
  186. window_flags: ImGuiWindowFlags;
  187. draw_list: PImDrawList;
  188. value_raw, value_with_lock_threshold, mouse_delta: ImVec2;
  189. Begin
  190. window_flags := ImGuiWindowFlags_None;
  191. // Demonstrate the various window flags. Typically you would just use the default.
  192. If (no_titlebar) Then window_flags := window_flags Or ImGuiWindowFlags_NoTitleBar;
  193. If (no_resize) Then window_flags := window_flags Or ImGuiWindowFlags_NoResize;
  194. If (no_move) Then window_flags := window_flags Or ImGuiWindowFlags_NoMove;
  195. If (no_scrollbar) Then window_flags := window_flags Or ImGuiWindowFlags_NoScrollbar;
  196. If (no_collapse) Then window_flags := window_flags Or ImGuiWindowFlags_NoCollapse;
  197. If (Not no_menu) Then window_flags := window_flags Or ImGuiWindowFlags_MenuBar;
  198. ImGui.SetNextWindowSize(ImVec2.New(550, 680), ImGuiCond_FirstUseEver);
  199. If Not ImGui.Begin_('ImGui Demo (FreePascal / Delphi version)', @p_open, window_flags) Then
  200. Begin
  201. // Early out if the window is collapsed, as an optimization.
  202. ImGui.End_;
  203. exit;
  204. End;
  205. //ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.65f); // 2/3 of the space for widget and 1/3 for labels
  206. ImGui.PushItemWidth(ImGui.GetWindowWidth() * 0.65);
  207. // Right align, keep 140 pixels for labels
  208. ImGui.Text('Dear ImGui says hello.');
  209. // Menu
  210. If (ImGui.BeginMenuBar()) Then
  211. Begin
  212. If (ImGui.BeginMenu('Menu')) Then
  213. Begin
  214. ImGui.MenuItem('Open');
  215. ImGui.MenuItem('Close');
  216. ImGui.EndMenu();
  217. End;
  218. If (ImGui.BeginMenu('Examples')) Then
  219. Begin
  220. ImGui.MenuItem('Main menu bar', nil, @show_app_main_menu_bar);
  221. ImGui.MenuItem('Console', nil, @show_app_console);
  222. ImGui.MenuItem('Log', nil, @show_app_log);
  223. ImGui.MenuItem('Simple layout', nil, @show_app_layout);
  224. ImGui.MenuItem('Property editor', nil, @show_app_property_editor);
  225. ImGui.MenuItem('Long text display', nil, @show_app_long_text);
  226. ImGui.MenuItem('Auto-resizing window', nil, @show_app_auto_resize);
  227. ImGui.MenuItem('Constrained-resizing window', nil,
  228. @show_app_constrained_resize);
  229. ImGui.MenuItem('Simple overlay', nil, @show_app_fixed_overlay);
  230. ImGui.MenuItem('Manipulating window title', nil,
  231. @show_app_manipulating_window_title);
  232. ImGui.MenuItem('Custom rendering', nil, @show_app_custom_rendering);
  233. ImGui.EndMenu();
  234. End;
  235. If (ImGui.BeginMenu('Help')) Then
  236. Begin
  237. ImGui.MenuItem('Metrics', nil, @show_app_metrics);
  238. ImGui.MenuItem('Style Editor', nil, @show_app_style_editor);
  239. ImGui.MenuItem('About ImGui', nil, @show_app_about);
  240. ImGui.EndMenu();
  241. End;
  242. ImGui.EndMenuBar();
  243. End;
  244. ImGui.Spacing();
  245. If ImGui.CollapsingHeader('Help') Then
  246. Begin
  247. ImGui.TextWrapped(
  248. 'This window is being created by the ShowTestWindow() function. Please refer to the code for programming reference.'
  249. + #10#10 +
  250. 'User Guide:');
  251. ImGui.ShowUserGuide();
  252. End;
  253. If ImGui.CollapsingHeader('Window options') Then
  254. Begin
  255. ImGui.Checkbox('No titlebar', @no_titlebar);
  256. ImGui.SameLine(150);
  257. ImGui.Checkbox('No resize', @no_resize);
  258. ImGui.Checkbox('No move', @no_move);
  259. ImGui.SameLine(150);
  260. ImGui.Checkbox('No scrollbar', @no_scrollbar);
  261. ImGui.SameLine(300);
  262. ImGui.Checkbox('No collapse', @no_collapse);
  263. ImGui.Checkbox('No menu', @no_menu);
  264. If ImGui.TreeNode('Style') Then
  265. Begin
  266. ImGui.ShowStyleEditor(Imgui.GetStyle());
  267. //this is useful to have, but doesn't need to be translated as an example
  268. ImGui.TreePop();
  269. End;
  270. If ImGui.TreeNode('Logging') Then
  271. Begin
  272. ImGui.TextWrapped(
  273. 'The logging API redirects all text output so you can easily capture the content of a window or a block. Tree nodes can be automatically expanded. You can also call ImGui.LogText() to output directly to the log without a visual output.');
  274. ImGui.LogButtons();
  275. ImGui.TreePop();
  276. End;
  277. End;
  278. If ImGui.CollapsingHeader('Widgets') Then
  279. Begin
  280. If ImGui.TreeNode('Trees') Then
  281. Trees;
  282. End;
  283. If ImGui.CollapsingHeader('Keyboard, Mouse & Focus') Then
  284. Begin
  285. If ImGui.TreeNode('Dragging') Then
  286. Begin
  287. ImGui.TextWrapped(
  288. 'You can use ImGui::GetMouseDragDelta(0) to query for the dragged amount on any widget.');
  289. ImGui.Button('Drag Me');
  290. If ImGui.IsItemActive() Then
  291. Begin
  292. io := ImGui.GetIO();
  293. // Draw a line between the button and the mouse cursor
  294. draw_list := ImGui.GetWindowDrawList();
  295. draw_list^.PushClipRectFullScreen;
  296. draw_list^.AddLine(io^.MouseClickedPos[0], io^.MousePos,
  297. ImGui.GetColorU32Vec(ImGui.GetStyle()^.Colors[ImGuiCol_DragDropTarget]),
  298. 4.0);
  299. draw_list^.PopClipRect;
  300. value_raw := ImGui.GetMouseDragDelta(ImGuiMouseButton_Left, 0.0);
  301. value_with_lock_threshold := ImGui.GetMouseDragDelta(ImGuiMouseButton_Left);
  302. mouse_delta := ImGui.GetIO()^.MouseDelta;
  303. ImGui.SameLine();
  304. ImGui.TextWrapped(
  305. 'Raw (%.1f, %.1f), WithLockThresold (%.1f, %.1f), MouseDelta (%.1f, %.1f)',
  306. [value_raw.x, value_raw.y, value_with_lock_threshold.x,
  307. value_with_lock_threshold.y, mouse_delta.x, mouse_delta.y]);
  308. End;
  309. ImGui.TreePop();
  310. End;
  311. End;
  312. ImGui.End_;
  313. End;
  314. End.