eclistframeunit.pas 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711
  1. unit eclistframeunit;
  2. {$mode objfpc}{$H+}
  3. interface
  4. uses
  5. Classes, SysUtils, Forms, Controls, StdCtrls, database, fpjson, Types,
  6. ecstringiser, eccolourscheme, constants, LCLTranslator, Menus;
  7. type
  8. { TECListFrame }
  9. TECListFrame = class(TFrame)
  10. EcListBox: TListBox;
  11. EcListPopupMenu: TPopupMenu;
  12. EditEcMenuItem: TMenuItem;
  13. AddNewEcMenuItem: TMenuItem;
  14. EcListSeparator1MenuItem: TMenuItem;
  15. CutEcMenuItem: TMenuItem;
  16. CopyEcMenuItem: TMenuItem;
  17. DeleteEcMenuItem: TMenuItem;
  18. EcListSeparator2MenuItem: TMenuItem;
  19. SelectAllEcsMenuItem: TMenuItem;
  20. PasteEcMenuItem: TMenuItem;
  21. procedure AddNewEcMenuItemClick(Sender: TObject);
  22. procedure CopyEcMenuItemClick(Sender: TObject);
  23. procedure EcListBoxClick(Sender: TObject);
  24. procedure EcListBoxDblClick(Sender: TObject);
  25. procedure EcListBoxDrawItem(Control: TWinControl; Index: Integer;
  26. ARect: TRect; State: TOwnerDrawState);
  27. procedure EcListBoxMouseUp(Sender: TObject; Button: TMouseButton;
  28. Shift: TShiftState; X, Y: Integer);
  29. procedure EcListBoxSelectionChange(Sender: TObject; User: boolean);
  30. procedure EditEcMenuItemClick(Sender: TObject);
  31. procedure PasteEcMenuItemClick(Sender: TObject);
  32. private
  33. Db: TDatabase;
  34. Troop: TJSONObject;
  35. List: TJSONArray;
  36. ColourScheme: TEcColourScheme;
  37. Stringiser: TEcStringiser;
  38. LeaderWidth: Integer;
  39. SelectionStart, SelectionLength: Integer;
  40. function GetSelectionStart(MiddleIndex: Integer): Integer;
  41. function GetSelectionLength(StartingFrom: Integer): Integer;
  42. function IsEcSelected(Index: Integer): Boolean;
  43. function IsSingleEcSelected: Boolean;
  44. procedure EditSelectedCommand;
  45. procedure AddNewCommand;
  46. procedure SetUpPopupMenu;
  47. public
  48. procedure SetDatabase(ADb: TDatabase);
  49. procedure SetTroop(ATroop: TJSONObject);
  50. procedure SetList(AList: TJSONArray);
  51. procedure FillEventCommands;
  52. destructor Destroy; override;
  53. end;
  54. TStarterEcDesc = record
  55. ContinuationCode: Integer;
  56. StartCode: Integer;
  57. end;
  58. TEcContinuationType = (
  59. ectEat {< Take as many event commands of the specified type as possible,
  60. but only if they follow starter or each other directly},
  61. ectFind {< Find exactly one event command at the same indent, but probably
  62. separated by commands of other types},
  63. ectSpecial {< Used for 'Battle processing', which sometimes acts as ectFind}
  64. );
  65. TEnderEcDesc = record
  66. StartCode: Integer;
  67. EndCode: Integer;
  68. ContinuationType: TEcContinuationType;
  69. end;
  70. PEnderEcDesc = ^TEnderEcDesc;
  71. const
  72. EC_INDENT = 10;
  73. INDENT_WIDTH = 20;
  74. StarterEcs: array [1..16] of TStarterEcDesc = (
  75. (ContinuationCode: SHOW_MESSAGE_LINE_EC_CODE; StartCode: SHOW_MESSAGE_START_EC_CODE),
  76. (ContinuationCode: SHOW_CHOICES_BRANCH_EC_CODE; StartCode: SHOW_CHOICES_START_EC_CODE),
  77. (ContinuationCode: SHOW_CHOICES_CANCEL_BRANCH_EC_CODE; StartCode: SHOW_CHOICES_START_EC_CODE),
  78. (ContinuationCode: SHOW_CHOICES_END_EC_CODE; StartCode: SHOW_CHOICES_START_EC_CODE),
  79. (ContinuationCode: SCROLLING_TEXT_LINE_EC_CODE; StartCode: SCROLLING_TEXT_START_EC_CODE),
  80. (ContinuationCode: COMMENT_CONTINUATION_EC_CODE; StartCode: COMMENT_EC_CODE),
  81. (ContinuationCode: CONDITIONAL_BRANCH_ELSE_EC_CODE; StartCode: CONDITIONAL_BRANCH_IF_EC_CODE),
  82. (ContinuationCode: CONDITIONAL_BRANCH_END_EC_CODE; StartCode: CONDITIONAL_BRANCH_IF_EC_CODE),
  83. (ContinuationCode: LOOP_END_EC_CODE; StartCode: LOOP_EC_CODE),
  84. (ContinuationCode: SET_MOVEMENT_ROUTE_SUBCOMMAND_EC_CODE; StartCode: SET_MOVEMENT_ROUTE_EC_CODE),
  85. (ContinuationCode: BATTLE_PROCESSING_WIN_EC_CODE; StartCode: BATTLE_PROCESSING_EC_CODE),
  86. (ContinuationCode: BATTLE_PROCESSING_ESCAPE_EC_CODE; StartCode: BATTLE_PROCESSING_EC_CODE),
  87. (ContinuationCode: BATTLE_PROCESSING_LOSE_EC_CODE; StartCode: BATTLE_PROCESSING_EC_CODE),
  88. (ContinuationCode: BATTLE_PROCESSING_END_EC_CODE; StartCode: BATTLE_PROCESSING_EC_CODE),
  89. (ContinuationCode: SHOP_PROCESSING_LINE_EC_CODE; StartCode: SHOP_PROCESSING_EC_CODE),
  90. (ContinuationCode: SCRIPT_LINE_EC_CODE; StartCode: SCRIPT_EC_CODE)
  91. );
  92. EnderEcs: array [1..10] of TEnderEcDesc = (
  93. (StartCode: SHOW_MESSAGE_START_EC_CODE; EndCode: SHOW_MESSAGE_LINE_EC_CODE; ContinuationType: ectEat),
  94. (StartCode: SHOW_CHOICES_START_EC_CODE; EndCode: SHOW_CHOICES_END_EC_CODE; ContinuationType: ectFind),
  95. (StartCode: SCROLLING_TEXT_START_EC_CODE; EndCode: SCROLLING_TEXT_LINE_EC_CODE; ContinuationType: ectEat),
  96. (StartCode: COMMENT_EC_CODE; EndCode: COMMENT_CONTINUATION_EC_CODE; ContinuationType: ectEat),
  97. (StartCode: CONDITIONAL_BRANCH_IF_EC_CODE; EndCode: CONDITIONAL_BRANCH_END_EC_CODE; ContinuationType: ectFind),
  98. (StartCode: LOOP_EC_CODE; EndCode: LOOP_END_EC_CODE; ContinuationType: ectFind),
  99. (StartCode: SET_MOVEMENT_ROUTE_EC_CODE; EndCode: SET_MOVEMENT_ROUTE_SUBCOMMAND_EC_CODE; ContinuationType: ectEat),
  100. (StartCode: BATTLE_PROCESSING_EC_CODE; EndCode: BATTLE_PROCESSING_END_EC_CODE; ContinuationType: ectSpecial),
  101. (StartCode: SHOP_PROCESSING_EC_CODE; EndCode: SHOP_PROCESSING_LINE_EC_CODE; ContinuationType: ectEat),
  102. (StartCode: SCRIPT_EC_CODE; EndCode: SCRIPT_LINE_EC_CODE; ContinuationType: ectEat)
  103. );
  104. implementation
  105. uses
  106. Graphics, Math, echelper, ec_base, newecformunit, clipboardhelper, globals,
  107. //debug-only
  108. Dialogs;
  109. {$R *.lfm}
  110. { TECListFrame }
  111. procedure TECListFrame.EcListBoxDrawItem(Control: TWinControl; Index: Integer;
  112. ARect: TRect; State: TOwnerDrawState);
  113. var
  114. Phrase: TEcPhrase;
  115. CurrentX: Integer;
  116. I: Integer;
  117. Part: TEcPhrasePart;
  118. PartSize: TSize;
  119. Ec: TJSONObject;
  120. Indent: Integer;
  121. IndentJson: TJSONNumber;
  122. function GetLeaderWidth: Integer;
  123. var
  124. ColonSize: TSize;
  125. begin
  126. ColonSize := EcListBox.Canvas.TextExtent(':');
  127. GetLeaderWidth := Max(ColonSize.Width, EcListBox.ItemHeight);
  128. end;
  129. procedure DrawLeader;
  130. procedure DrawContinuationLeader;
  131. var
  132. ColonSize: TSize;
  133. begin
  134. with EcListBox.Canvas do begin
  135. ColonSize := TextExtent(':');
  136. if IsEcSelected(Index) then
  137. Font.Color := ColourScheme.GetSelTextColour(ecDefault)
  138. else
  139. Font.Color := ColourScheme.GetTextColour(ecDefault);
  140. TextOut(CurrentX + (LeaderWidth - ColonSize.Width - 6) div 2, ARect.Top + (EcListBox.ItemHeight - ColonSize.Height) div 2, ':');
  141. end;
  142. end;
  143. procedure DrawBeginningLeader;
  144. var
  145. Points: array [1..4] of TPoint;
  146. Padding: Integer;
  147. FullWidth: Integer;
  148. HalfWidth: Integer;
  149. begin
  150. Padding := 3;
  151. FullWidth := LeaderWidth - Padding * 2;
  152. HalfWidth := FullWidth div 2;
  153. with EcListBox.Canvas do begin
  154. Brush.Style := bsSolid;
  155. if IsEcSelected(Index) then
  156. Brush.Color := ColourScheme.GetSelTextColour(ecDefault)
  157. else
  158. Brush.Color := ColourScheme.GetTextColour(ecDefault);
  159. Points[1] := Point(CurrentX, ARect.Top + Padding + HalfWidth);
  160. Points[2] := Point(CurrentX + HalfWidth, ARect.Top + Padding);
  161. Points[3] := Point(CurrentX + FullWidth, ARect.Top + Padding + HalfWidth);
  162. Points[4] := Point(CurrentX + HalfWidth, ARect.Top + Padding + FullWidth);
  163. Polygon(@Points[1], 4);
  164. end;
  165. end;
  166. begin
  167. if IsFlipped then
  168. Dec(CurrentX, LeaderWidth + 1);
  169. if EcIsContinuation(Ec.Integers['code']) then
  170. DrawContinuationLeader
  171. else
  172. DrawBeginningLeader;
  173. if not IsFlipped then
  174. Inc(CurrentX, LeaderWidth + 1);
  175. end;
  176. begin
  177. if (List = nil) or (Index >= List.Count) or (Index < 0) then
  178. Exit;
  179. Ec := List.Objects[Index];
  180. if (Ec <> nil) and Ec.Find('indent', IndentJson) then
  181. Indent := IndentJson.AsInteger;
  182. if LeaderWidth <= 0 then
  183. LeaderWidth := GetLeaderWidth;
  184. Phrase := Stringiser.StringiseEc(Ec);
  185. with EcListBox.Canvas do begin
  186. Pen.Style := psClear;
  187. Rectangle(ARect.Left, ARect.Top, ARect.Right, ARect.Bottom + 1);
  188. if IsFlipped then
  189. CurrentX := ARect.Right - EC_INDENT - Indent*INDENT_WIDTH
  190. else
  191. CurrentX := ARect.Left + EC_INDENT + Indent*INDENT_WIDTH;
  192. DrawLeader;
  193. Brush.Style := bsClear;
  194. for I := Low(Phrase) to High(Phrase) do begin
  195. Part := Phrase[I];
  196. PartSize := TextExtent(Part.Text);
  197. if IsFlipped then
  198. Dec(CurrentX, PartSize.Width);
  199. if IsEcSelected(Index) then
  200. Font.Color := ColourScheme.GetSelTextColour(Part.Colour)
  201. else
  202. Font.Color := ColourScheme.GetTextColour(Part.Colour);
  203. if Part.Colour <> ecInvisible then
  204. TextOut(CurrentX, ARect.Top + (EcListBox.ItemHeight - PartSize.Height) div 2, Part.Text);
  205. if not IsFlipped then
  206. Inc(CurrentX, PartSize.Width);
  207. end;
  208. end;
  209. end;
  210. procedure TECListFrame.EcListBoxMouseUp(Sender: TObject; Button: TMouseButton;
  211. Shift: TShiftState; X, Y: Integer);
  212. var
  213. ScreenCoordinates: TPoint;
  214. procedure EnsureClickedIsSelected;
  215. var
  216. ListBoxCoordinates: TPoint;
  217. Index: Integer;
  218. begin
  219. ListBoxCoordinates := Point(X, Y);
  220. Index := EcListBox.ItemAtPos(ListBoxCoordinates, True);
  221. if (Index < 0) or (Index > EcListBox.Count) then
  222. Exit;
  223. if (Index >= SelectionStart) and
  224. (Index < SelectionStart + SelectionLength) then
  225. Exit;
  226. EcListBox.ClearSelection;
  227. EcListBox.ItemIndex := Index;
  228. EcListBox.Selected[Index] := True;
  229. EcListBoxSelectionChange(Sender, True);
  230. end;
  231. begin
  232. if Button = mbRight then begin
  233. EnsureClickedIsSelected;
  234. SetUpPopupMenu;
  235. ScreenCoordinates := ClientToScreen(Point(X, Y));
  236. EcListPopupMenu.PopUp(ScreenCoordinates.X, ScreenCoordinates.Y);
  237. end;
  238. end;
  239. procedure TECListFrame.EcListBoxClick(Sender: TObject);
  240. begin
  241. //TODO
  242. end;
  243. procedure TECListFrame.AddNewEcMenuItemClick(Sender: TObject);
  244. begin
  245. AddNewCommand
  246. end;
  247. procedure TECListFrame.CopyEcMenuItemClick(Sender: TObject);
  248. begin
  249. //TODO
  250. end;
  251. procedure TECListFrame.EcListBoxDblClick(Sender: TObject);
  252. begin
  253. AddNewCommand
  254. end;
  255. procedure TECListFrame.EcListBoxSelectionChange(Sender: TObject; User: boolean);
  256. procedure UpdateSelection;
  257. var
  258. I: Integer;
  259. begin
  260. for I := SelectionStart to SelectionStart + SelectionLength -1 do begin
  261. EcListBox.Selected[I] := True;
  262. end;
  263. end;
  264. function GetFirstSelectedLine: Integer;
  265. var
  266. I: Integer;
  267. begin
  268. I := EcListBox.ItemIndex;
  269. while (I-1 >= 0) and EcListBox.Selected[I-1] do
  270. Dec(I);
  271. GetFirstSelectedLine := I;
  272. end;
  273. function GetUserSelectionLength: Integer;
  274. var
  275. I: Integer;
  276. begin
  277. I := 0;
  278. while (SelectionStart + I < List.Count) and EcListBox.Selected[SelectionStart + I] do
  279. Inc(I);
  280. GetUserSelectionLength := I;
  281. end;
  282. begin
  283. if not User then
  284. Exit;
  285. if EcListBox.ItemIndex >= 0 then begin
  286. SelectionStart := GetSelectionStart(GetFirstSelectedLine);
  287. SelectionLength := GetSelectionLength(SelectionStart)
  288. end else
  289. SelectionLength := 0;
  290. UpdateSelection;
  291. SelectionLength := GetUserSelectionLength
  292. { TODO: make sure indent of the last command is same as of the first command }
  293. end;
  294. procedure TECListFrame.EditEcMenuItemClick(Sender: TObject);
  295. begin
  296. EditSelectedCommand
  297. end;
  298. procedure TECListFrame.PasteEcMenuItemClick(Sender: TObject);
  299. var
  300. PastedArray: TJSONArray;
  301. TypeString: String;
  302. StartIndex, I: Integer;
  303. IndentDifference, NewIndent: Integer;
  304. begin
  305. TypeString := DataTypeStrings[DATA_TYPE_ID_EVENT_COMMAND];
  306. if ClipboardHasData(TypeString) then begin
  307. PastedArray := GetJsonArrayFromClipboard(TypeString);
  308. if (PastedArray <> nil) and (PastedArray.Count > 0) then begin
  309. if (SelectionStart >= 0) and (SelectionStart < List.Count) then
  310. StartIndex := SelectionStart
  311. else
  312. StartIndex := List.Count - 1;
  313. IndentDifference := List.Objects[StartIndex].Integers['indent']
  314. - PastedArray.Objects[0].Integers['indent'];
  315. EcListBox.Items.BeginUpdate;
  316. for I := PastedArray.Count -1 downto 0 do begin
  317. List.Insert(StartIndex, PastedArray[I].Clone);
  318. NewIndent := List.Objects[StartIndex].Integers['indent']
  319. + IndentDifference;
  320. List.Objects[StartIndex].Integers['indent'] := NewIndent;
  321. EcListBox.Items.Append('+');
  322. end;
  323. EcListBox.Items.EndUpdate;
  324. EcListBox.ClearSelection;
  325. SelectionStart := StartIndex;
  326. SelectionLength := PastedArray.Count;
  327. for I := SelectionStart to SelectionLength -1 do begin
  328. EcListBox.Selected[SelectionStart + I] := True;
  329. end;
  330. end;
  331. end;
  332. end;
  333. function TECListFrame.GetSelectionStart(MiddleIndex: Integer): Integer;
  334. function GetStarterEcCode(CurrentCode: Integer): Integer;
  335. var
  336. I: Integer;
  337. begin
  338. GetStarterEcCode := 0;
  339. for I := Low(StarterEcs) to High(StarterEcs) do begin
  340. if StarterEcs[I].ContinuationCode > CurrentCode then
  341. Exit;
  342. if StarterEcs[I].ContinuationCode = CurrentCode then begin
  343. GetStarterEcCode := StarterEcs[I].StartCode;
  344. Exit
  345. end;
  346. end;
  347. end;
  348. var
  349. CurrentStart, StarterCode, StarterIndent: Integer;
  350. CurrentEc: TJSONObject;
  351. IsStarter: Boolean;
  352. begin
  353. if (List = nil) or (MiddleIndex >= List.Count) then begin
  354. GetSelectionStart := MiddleIndex;
  355. Exit;
  356. end;
  357. CurrentStart := MiddleIndex;
  358. CurrentEc := List.Objects[MiddleIndex];
  359. StarterCode := GetStarterEcCode(CurrentEc.Integers['code']);
  360. StarterIndent := CurrentEc.Integers['indent'];
  361. IsStarter := False;
  362. if StarterCode <> 0 then
  363. while (CurrentStart >= 0) and not IsStarter do begin
  364. Dec(CurrentStart);
  365. CurrentEc := List.Objects[CurrentStart];
  366. IsStarter := (CurrentEc.Integers['code'] = StarterCode) and
  367. (CurrentEc.Integers['indent'] = StarterIndent);
  368. end;
  369. GetSelectionStart := Max(0, CurrentStart);
  370. end;
  371. function TECListFrame.GetSelectionLength(StartingFrom: Integer): Integer;
  372. function GetEnderDesc(CurrentCode: Integer): PEnderEcDesc;
  373. var
  374. I: Integer;
  375. begin
  376. GetEnderDesc := nil;
  377. for I := Low(EnderEcs) to High(EnderEcs) do begin
  378. if EnderEcs[I].StartCode > CurrentCode then
  379. Exit;
  380. if EnderEcs[I].StartCode = CurrentCode then begin
  381. GetEnderDesc := @EnderEcs[I];
  382. Exit
  383. end;
  384. end;
  385. end;
  386. var
  387. EnderDesc: ^TEnderEcDesc;
  388. CurrentEc: TJSONObject;
  389. StartIndent, NewLength: Integer;
  390. IsStopped: Boolean;
  391. EffectiveContinuation: TEcContinuationType;
  392. begin
  393. GetSelectionLength := 1;
  394. if (List = nil) or (StartingFrom >= List.Count) then begin
  395. Exit;
  396. end;
  397. CurrentEc := List.Objects[StartingFrom];
  398. EnderDesc := GetEnderDesc(CurrentEc.Integers['code']);
  399. StartIndent := CurrentEc.Integers['indent'];
  400. NewLength := 1;
  401. IsStopped := False;
  402. if EnderDesc <> nil then begin
  403. EffectiveContinuation := EnderDesc^.ContinuationType;
  404. if (CurrentEc.Integers['code'] = BATTLE_PROCESSING_EC_CODE) and
  405. (CurrentEc.Arrays['parameters'].Booleans[2]
  406. or CurrentEc.Arrays['parameters'].Booleans[3]) then
  407. EffectiveContinuation := ectFind;
  408. while (StartingFrom + NewLength <= List.Count) and not IsStopped and
  409. (EffectiveContinuation <> ectSpecial) do begin
  410. CurrentEc := List.Objects[StartingFrom + NewLength - 1];
  411. if EffectiveContinuation = ectFind then begin
  412. IsStopped := (CurrentEc.Integers['code'] = EnderDesc^.EndCode) and
  413. (CurrentEc.Integers['indent'] = StartIndent);
  414. end;
  415. if EffectiveContinuation = ectEat then begin
  416. IsStopped := ((CurrentEc.Integers['code'] <> EnderDesc^.EndCode)
  417. and ((CurrentEc.Integers['code'] <> EnderDesc^.StartCode)
  418. or (NewLength <> 1)))
  419. or (CurrentEc.Integers['indent'] <> StartIndent);
  420. end;
  421. Inc(NewLength);
  422. end;
  423. Dec(NewLength);
  424. if EnderDesc^.ContinuationType = ectEat then
  425. Dec(NewLength);
  426. end;
  427. GetSelectionLength := NewLength;
  428. end;
  429. function TECListFrame.IsEcSelected(Index: Integer): Boolean;
  430. begin
  431. IsEcSelected := EcListBox.Selected[Index];
  432. {
  433. IsEcSelected := (Index >= SelectionStart) and
  434. (Index < SelectionStart + SelectionLength);
  435. }
  436. end;
  437. function TECListFrame.IsSingleEcSelected: Boolean;
  438. var
  439. OneCommandLength: Integer;
  440. begin
  441. OneCommandLength := GetSelectionLength(SelectionStart);
  442. IsSingleEcSelected := OneCommandLength = SelectionLength;
  443. end;
  444. procedure TECListFrame.EditSelectedCommand;
  445. var
  446. F: TECBaseFrame;
  447. FrameClass: TEcFrameClass;
  448. LengthChange, I: Integer;
  449. begin
  450. //TODO: remove the test code
  451. FrameClass := GetEditorForEc(List.Objects[SelectionStart].Integers['code']);
  452. if FrameClass <> nil then begin
  453. F := FrameClass.Create(Self);
  454. F.SetUp(Db, nil, Troop);
  455. F.UpdateLanguage(EditorLanguage);
  456. if F.ShowWithExisting(List, SelectionStart) then begin
  457. LengthChange := F.GetLength - SelectionLength;
  458. if LengthChange <> 0 then begin
  459. EcListBox.Items.BeginUpdate;
  460. if LengthChange > 0 then
  461. for I := 1 to LengthChange do
  462. EcListBox.Items.Add('+')
  463. else
  464. for I := 1 to -LengthChange do
  465. EcListBox.Items.Delete(EcListBox.Items.Count -1);
  466. EcListBox.Items.EndUpdate;
  467. end;
  468. F.ReplaceEditedCommand(SelectionStart, SelectionLength);
  469. SelectionLength := F.GetLength;
  470. EcListBox.Refresh
  471. end;
  472. FreeAndNil(F);
  473. end;
  474. end;
  475. procedure TECListFrame.AddNewCommand;
  476. var
  477. F: TECBaseFrame;
  478. FrameClass: TEcFrameClass;
  479. Indent, I, SelectedCode, EcLength: Integer;
  480. begin
  481. NewECForm.SetDatabase(Db);
  482. SelectedCode := NewECForm.ShowSelection;
  483. if SelectedCode <> EC_SELECTION_CANCELLED then begin
  484. FrameClass := GetEditorForEc(NewECForm.SelectedCode);
  485. Indent := List.Objects[SelectionStart].Integers['indent'];
  486. if FrameClass <> nil then begin
  487. F := FrameClass.Create(Self);
  488. F.SetUp(Db, nil, Troop);
  489. F.UpdateLanguage(EditorLanguage);
  490. if F.ShowWithNew(Indent) then begin
  491. EcLength := F.GetLength;
  492. EcListBox.Items.BeginUpdate;
  493. for I := 1 to EcLength do
  494. EcListBox.Items.Add('+');
  495. EcListBox.Items.EndUpdate;
  496. F.AddNewCommand(List, SelectionStart);
  497. SelectionLength := EcLength;
  498. end;
  499. FreeAndNil(F);
  500. end else if NewECForm.SelectedCode = LOOP_EC_CODE then begin
  501. // TODO: replace here F.AddNewCommand with something else and then uncomment
  502. EcListBox.Items.Add('+');
  503. EcListBox.Items.Add('+');
  504. EcListBox.Items.Add('+');
  505. TECBaseFrame.AddCommandToList(TJSONArray.Create([
  506. TJSONObject.Create([
  507. 'code', NewECForm.SelectedCode,
  508. 'indent', Indent,
  509. 'parameters', TJSONArray.Create()
  510. ]),
  511. TJSONObject.Create([
  512. 'code', 0,
  513. 'indent', Indent + 1,
  514. 'parameters', TJSONArray.Create()
  515. ]),
  516. TJSONObject.Create([
  517. 'code', LOOP_END_EC_CODE,
  518. 'indent', Indent,
  519. 'parameters', TJSONArray.Create()
  520. ])
  521. ]), List, SelectionStart);
  522. SelectionLength := 1;
  523. end else if IsCommandWithoutParameters(NewECForm.SelectedCode) then begin
  524. EcListBox.Items.Add('+');
  525. TECBaseFrame.AddCommandToList(TJSONArray.Create([
  526. TJSONObject.Create([
  527. 'code', NewECForm.SelectedCode,
  528. 'indent', Indent,
  529. 'parameters', TJSONArray.Create()
  530. ])
  531. ]), List, SelectionStart);
  532. SelectionLength := 1;
  533. end
  534. end
  535. end;
  536. procedure TECListFrame.SetUpPopupMenu;
  537. var
  538. ForSingleEc: Boolean;
  539. begin
  540. ForSingleEc := IsSingleEcSelected;
  541. EditEcMenuItem.Enabled := ForSingleEc;
  542. end;
  543. procedure TECListFrame.SetDatabase(ADb: TDatabase);
  544. begin
  545. Db := ADb;
  546. Troop := nil;
  547. {TODO: move colour scheme stuff out of here (perhaps into gameproject?)}
  548. ColourScheme := TEcLightColourScheme.Create;
  549. {TODO: move stringiser out of here???}
  550. Stringiser := TEcStringiser.Create;
  551. Stringiser.Db := Db;
  552. Stringiser.Troop := Troop;
  553. LeaderWidth := 0;
  554. end;
  555. procedure TECListFrame.SetTroop(ATroop: TJSONObject);
  556. begin
  557. Troop := ATroop;
  558. Stringiser.Troop := Troop;
  559. end;
  560. procedure TECListFrame.SetList(AList: TJSONArray);
  561. begin
  562. List := AList;
  563. if List <> nil then
  564. FillEventCommands;
  565. end;
  566. procedure TECListFrame.FillEventCommands;
  567. var
  568. I: Integer;
  569. begin
  570. { Lazarus doesn't seem to have lbVirtualOwnerDraw, so listboxes have to be
  571. either owner-drawn or virtual. We're choosing the first one. }
  572. with EcListBox.Items do begin
  573. BeginUpdate;
  574. Clear;
  575. for I := 0 to List.Count -1 do begin
  576. Add(IntToStr(I));
  577. end;
  578. EndUpdate;
  579. end;
  580. end;
  581. destructor TECListFrame.Destroy;
  582. begin
  583. inherited Destroy;
  584. if ColourScheme <> nil then
  585. ColourScheme.Free;
  586. if Stringiser <> nil then
  587. Stringiser.Free;
  588. end;
  589. end.