IDE.MainForm.NavigationHelper.pas 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. unit IDE.MainForm.NavigationHelper;
  2. {
  3. Inno Setup
  4. Copyright (C) 1997-2025 Jordan Russell
  5. Portions by Martijn Laan
  6. For conditions of distribution and use, see LICENSE.TXT.
  7. Compiler form - Navigation helper which has the UAH helper as ancestor
  8. Not used by MainForm: it uses IDE.MainForm.FinalHelper instead
  9. }
  10. interface
  11. uses
  12. Messages,
  13. Menus,
  14. IDE.MainForm, IDE.MainForm.UAHHelper,
  15. IDE.IDEScintEdit;
  16. type
  17. TMainFormNavigationHelper = class helper(TMainFormUAHHelper) for TMainForm
  18. procedure RemoveMemoFromNavigation(const AMemo: TIDEScintEdit);
  19. procedure RemoveMemoBadLinesFromNavigation(const AMemo: TIDEScintEdit);
  20. procedure UpdateNavigationButtons;
  21. procedure NavigateBack;
  22. procedure NavigateForward;
  23. procedure HandleNavigationAppCommand(var Message: TMessage);
  24. procedure UpdateNavigationMenu(const Menu: TMenuItem);
  25. procedure UpdateBackNavigationStack;
  26. { Private }
  27. procedure _NavigationMenuItemClick(Sender: TObject);
  28. end;
  29. implementation
  30. uses
  31. Windows,
  32. SysUtils, TypInfo, ComCtrls,
  33. IDE.HelperFunc, IDE.ScintStylerInnoSetup;
  34. procedure TMainFormNavigationHelper.RemoveMemoFromNavigation(const AMemo: TIDEScintEdit);
  35. begin
  36. if FNavStacks.RemoveMemo(AMemo) then
  37. UpdateNavigationButtons;
  38. if FCurrentNavItem.Memo = AMemo then
  39. FCurrentNavItem.Invalidate;
  40. end;
  41. procedure TMainFormNavigationHelper.RemoveMemoBadLinesFromNavigation(const AMemo: TIDEScintEdit);
  42. begin
  43. if FNavStacks.RemoveMemoBadLines(AMemo) then
  44. UpdateNavigationButtons;
  45. { We do NOT update FCurrentNav here so it might point to a line that's
  46. deleted until next UpdateCaretPosPanelAndBackStack by UpdateMemoUI }
  47. end;
  48. procedure TMainFormNavigationHelper.UpdateNavigationButtons;
  49. begin
  50. ForwardNavButton.Enabled := FNavStacks.Forward.Count > 0;
  51. BackNavButton.Enabled := (FNavStacks.Back.Count > 0) or
  52. ForwardNavButton.Enabled; { for the dropdown }
  53. end;
  54. procedure TMainFormNavigationHelper.NavigateBack;
  55. begin
  56. { Delphi does not support BTNS_WHOLEDROPDOWN so we can't be like VS which
  57. can have a disabled back nav button with an enabled dropdown. To avoid
  58. always showing two dropdowns we keep the back button enabled when we need
  59. the dropdown. So we need to check for this. }
  60. if FNavStacks.Back.Count = 0 then begin
  61. Beep;
  62. Exit;
  63. end;
  64. FNavStacks.Forward.Add(FCurrentNavItem);
  65. var NewNavItem := FNavStacks.Back.ExtractAt(FNavStacks.Back.Count-1);
  66. UpdateNavigationButtons;
  67. FCurrentNavItem := NewNavItem; { Must be done *before* moving }
  68. MoveCaretAndActivateMemo(NewNavItem.Memo,
  69. NewNavItem.Memo.GetPositionFromLineColumn(NewNavItem.Line, NewNavItem.Column), False, True, NewNavItem.VirtualSpace);
  70. end;
  71. procedure TMainFormNavigationHelper.NavigateForward;
  72. begin
  73. FNavStacks.Back.Add(FCurrentNavItem);
  74. var NewNavItem := FNavStacks.Forward.ExtractAt(FNavStacks.Forward.Count-1);
  75. UpdateNavigationButtons;
  76. FCurrentNavItem := NewNavItem; { Must be done *before* moving }
  77. MoveCaretAndActivateMemo(NewNavItem.Memo,
  78. NewNavItem.Memo.GetPositionFromLineColumn(NewNavItem.Line, NewNavItem.Column), False, True, NewNavItem.VirtualSpace);
  79. end;
  80. procedure TMainFormNavigationHelper.HandleNavigationAppCommand(var Message: TMessage);
  81. begin
  82. var Command := GET_APPCOMMAND_LPARAM(Integer(Message.LParam));
  83. if Command = APPCOMMAND_BROWSER_BACKWARD then begin
  84. if BackNavButton.Enabled then
  85. BackNavButton.Click;
  86. Message.Result := 1;
  87. end else if Command = APPCOMMAND_BROWSER_FORWARD then begin
  88. if ForwardNavButton.Enabled then
  89. ForwardNavButton.Click;
  90. Message.Result := 1;
  91. end;
  92. end;
  93. procedure TMainFormNavigationHelper._NavigationMenuItemClick(Sender: TObject);
  94. begin
  95. var MenuItem := Sender as TMenuItem;
  96. var Clicks := Abs(MenuItem.Tag);
  97. if Clicks > 0 then begin
  98. var ButtonToClick: TToolButton;
  99. if MenuItem.Tag > 0 then
  100. ButtonToClick := ForwardNavButton
  101. else
  102. ButtonToClick := BackNavButton;
  103. while Clicks > 0 do begin
  104. if not ButtonToClick.Enabled then
  105. raise Exception.Create('not ButtonToClick.Enabled');
  106. ButtonToClick.Click;
  107. Dec(Clicks);
  108. end;
  109. end;
  110. end;
  111. procedure TMainFormNavigationHelper.UpdateNavigationMenu(const Menu: TMenuItem);
  112. procedure AddNavItemToMenu(const NavItem: TIDEScintEditNavItem; const Checked: Boolean;
  113. const ClicksNeeded: NativeInt; const Menu: TMenuItem);
  114. begin
  115. if NavItem.Line >= NavItem.Memo.Lines.Count then
  116. raise Exception.Create('NavItem.Line >= NavItem.Memo.Lines.Count');
  117. var LineInfo := NavItem.Memo.Lines[NavItem.Line];
  118. if LineInfo.Trim = '' then
  119. LineInfo := Format('Line %d', [NavItem.Line+1]);
  120. var Caption: String;
  121. if MemosTabSet.Visible then
  122. Caption := Format('%s: %s', [MemosTabSet.Tabs[MemoToTabIndex(NavItem.Memo)], LineInfo])
  123. else
  124. Caption := LineInfo;
  125. var MenuItem := TMenuItem.Create(Menu);
  126. MenuItem.Caption := DoubleAmp(Caption);
  127. MenuItem.Checked := Checked;
  128. MenuItem.RadioItem := True;
  129. MenuItem.Tag := ClicksNeeded;
  130. MenuItem.OnClick := _NavigationMenuItemClick;
  131. Menu.Add(MenuItem);
  132. end;
  133. begin
  134. Menu.Clear;
  135. { Setup dropdown. The result should end up being just like Visual Studio 2022
  136. which means from top to bottom:
  137. - Furthest (=oldest) forward item
  138. - ...
  139. - Closest (=next) forward item
  140. - Current position in the active memo, checked
  141. - Closest (=next) back item
  142. - ...
  143. - Furthest (=oldest) back item
  144. The Tag parameter should be set to the amount of clicks needed to get to
  145. the item, positive for forward and negative for back }
  146. for var I := 0 to FNavStacks.Forward.Count-1 do
  147. AddNavItemToMenu(FNavStacks.Forward[I], False, FNavStacks.Forward.Count-I, Menu);
  148. AddNavItemToMenu(FCurrentNavItem, True, 0, Menu);
  149. for var I := FNavStacks.Back.Count-1 downto 0 do
  150. AddNavItemToMenu(FNavStacks.Back[I], False, -(FNavStacks.Back.Count-I), Menu);
  151. end;
  152. procedure TMainFormNavigationHelper.UpdateBackNavigationStack;
  153. begin
  154. { Update NavStacks.Back if needed and remember new position }
  155. var NewNavItem := TIDEScintEditNavItem.Create(FActiveMemo); { This is a record so no need to free }
  156. if FCurrentNavItem.Valid and FNavStacks.AddNewBackForJump(FCurrentNavItem, NewNavItem) then
  157. UpdateNavigationButtons;
  158. FCurrentNavItem := NewNavItem;
  159. end;
  160. end.