diff --git a/ide/codeexplorer.pas b/ide/codeexplorer.pas index 390db2ecce..7f51f67b16 100644 --- a/ide/codeexplorer.pas +++ b/ide/codeexplorer.pas @@ -255,8 +255,7 @@ end; procedure TCodeExplorerView.CodeExplorerViewDestroy(Sender: TObject); begin - debugln('TCodeExplorerView.CodeExplorerViewDestroy'); - CodeExplorerMenuRoot.MenuItem:=nil; + //debugln('TCodeExplorerView.CodeExplorerViewDestroy'); end; procedure TCodeExplorerView.CodeExplorerViewRESIZE(Sender: TObject); diff --git a/ide/debugmanager.pas b/ide/debugmanager.pas index b1b65f1432..ffc0d9c1eb 100644 --- a/ide/debugmanager.pas +++ b/ide/debugmanager.pas @@ -41,7 +41,9 @@ uses {$ENDIF} Classes, SysUtils, Forms, Controls, Dialogs, Menus, FileUtil, LCLProc, Laz_XMLCfg, - SynEdit, CodeCache, CodeToolManager, LazConf, DebugOptionsFrm, + SynEdit, CodeCache, CodeToolManager, + MenuIntf, + LazConf, DebugOptionsFrm, CompilerOptions, EditorOptions, EnvironmentOpts, KeyMapping, UnitEditor, Project, IDEProcs, InputHistory, Debugger, IDEOptionDefs, LazarusIDEStrConsts, diff --git a/ide/main.pp b/ide/main.pp index a26711000d..199935b201 100644 --- a/ide/main.pp +++ b/ide/main.pp @@ -332,7 +332,7 @@ type procedure OnSrcNotebookToggleObjectInsp(Sender: TObject); procedure OnSrcNotebookViewJumpHistory(Sender: TObject); procedure OnSrcNotebookShowSearchResultsView(Sender: TObject); - procedure OnSrcNoteBookPopupMenu(AddMenuItemProc: TAddMenuItemProc); + procedure OnSrcNoteBookPopupMenu(const AddMenuItemProc: TAddMenuItemProc); // ObjectInspector + PropertyEditorHook events procedure OIOnSelectPersistents(Sender: TObject); @@ -11214,7 +11214,8 @@ begin CreateSearchResultWindow; end; -procedure TMainIDE.OnSrcNoteBookPopupMenu(AddMenuItemProc: TAddMenuItemProc); +procedure TMainIDE.OnSrcNoteBookPopupMenu( + const AddMenuItemProc: TAddMenuItemProc); begin PkgBoss.OnSourceEditorPopupMenu(AddMenuItemProc); end; diff --git a/ide/msgview.pp b/ide/msgview.pp index c20ec73e30..40df179ebe 100644 --- a/ide/msgview.pp +++ b/ide/msgview.pp @@ -208,7 +208,6 @@ begin ClearItems; FreeThenNil(FItems); FreeThenNil(FVisibleItems); - MessagesMenuRoot.MenuItem:=nil; inherited Destroy; end; diff --git a/ide/sourcemarks.pas b/ide/sourcemarks.pas index 362aa33249..78df49d81b 100644 --- a/ide/sourcemarks.pas +++ b/ide/sourcemarks.pas @@ -49,9 +49,6 @@ type TGetSourceMarkHintEvent = procedure(SenderMark: TSourceMark; var Hint: string) of object; - TAddMenuItemProc = - function (const NewCaption: string; const NewEnabled: boolean; - const NewOnClick: TNotifyEvent): TMenuItem of object; TCreateSourceMarkPopupMenuEvent = procedure(SenderMark: TSourceMark; const AddMenuItem: TAddMenuItemProc) of object; @@ -98,7 +95,7 @@ type ALine: integer): integer; function GetFilename: string; function GetHint: string; virtual; - procedure CreatePopupMenuItems(AddMenuItemProc: TAddMenuItemProc); + procedure CreatePopupMenuItems(const AddMenuItemProc: TAddMenuItemProc); public // handlers procedure RemoveAllHandlersForObject(HandlerObject: TObject); @@ -392,7 +389,8 @@ begin TGetSourceMarkHintEvent(FHandlers[smhGetHint][i])(Self,Result); end; -procedure TSourceMark.CreatePopupMenuItems(AddMenuItemProc: TAddMenuItemProc); +procedure TSourceMark.CreatePopupMenuItems( + const AddMenuItemProc: TAddMenuItemProc); var i: Integer; begin diff --git a/ide/uniteditor.pp b/ide/uniteditor.pp index afd00b86db..d53f1e4135 100644 --- a/ide/uniteditor.pp +++ b/ide/uniteditor.pp @@ -325,7 +325,7 @@ type CaretPos: TPoint) of object; TOnInitIdentCompletion = procedure(Sender: TObject; JumpToError: boolean; out Handled, Abort: boolean) of object; - TSrcEditPopupMenuEvent = procedure(AddMenuItemProc: TAddMenuItemProc + TSrcEditPopupMenuEvent = procedure(const AddMenuItemProc: TAddMenuItemProc ) of object; TOnShowCodeContext = procedure(JumpToError: boolean; out Abort: boolean) of object; @@ -408,8 +408,10 @@ type private fAutoFocusLock: integer; FCodeTemplateModul: TSynEditAutoComplete; + {$IFDEF DisableMenuIntf} fCustomPopupMenuItems: TList; fContextPopupMenuItems: TList; + {$ENDIF} fIdentCompletionJumpToError: boolean; FIncrementalSearchPos: TPoint; // last set position fIncrementalSearchStartPos: TPoint; // position where to start searching @@ -461,11 +463,11 @@ type procedure RemoveUserDefinedMenuItems; function AddUserDefinedPopupMenuItem(const NewCaption: string; const NewEnabled: boolean; - const NewOnClick: TNotifyEvent): TMenuItem; + const NewOnClick: TNotifyEvent): TIDEMenuItem; procedure RemoveContextMenuItems; function AddContextPopupMenuItem(const NewCaption: string; const NewEnabled: boolean; - const NewOnClick: TNotifyEvent): TMenuItem; + const NewOnClick: TNotifyEvent): TIDEMenuItem; procedure UpdateActiveEditColors; procedure SetIncrementalSearchStr(const AValue: string); @@ -2484,10 +2486,6 @@ destructor TSourceNotebook.Destroy; var i: integer; begin - {$IFDEF UseMenuIntf} - SourceEditorMenuRoot.MenuItem:=nil; - {$ENDIF} - FProcessingCommand:=false; for i:=FSourceEditorList.Count-1 downto 0 do Editors[i].Free; @@ -2504,8 +2502,10 @@ begin FreeThenNil(aCompletion); FreeThenNil(FHintTimer); FreeThenNil(FHintWindow); + {$IFDEF DisableMenuIntf} FreeThenNil(fCustomPopupMenuItems); FreeThenNil(fContextPopupMenuItems); + {$ENDIF} inherited Destroy; end; @@ -3058,7 +3058,7 @@ begin end; procedure TSourceNotebook.SrcPopUpMenuPopup(Sender: TObject); -{$IFDEF UseMenuIntf} +{$IFNDEF DisableMenuIntf} var ASrcEdit: TSourceEditor; BookMarkID, BookMarkX, BookMarkY: integer; @@ -3076,8 +3076,8 @@ var SelAvailAndWritable: Boolean; CurFilename: String; begin - //RemoveUserDefinedMenuItems; - //RemoveContextMenuItems; + RemoveUserDefinedMenuItems; + RemoveContextMenuItems; ASrcEdit:= FindSourceEditorWithEditorComponent(TPopupMenu(Sender).PopupComponent); @@ -3135,14 +3135,14 @@ begin if Marks<>nil then begin for i:=0 to MarkCount-1 do begin CurMark:=Marks[i]; - //CurMark.CreatePopupMenuItems(@AddUserDefinedPopupMenuItem); + CurMark.CreatePopupMenuItems(@AddUserDefinedPopupMenuItem); end; FreeMem(Marks); end; end; // add context specific menu items - {CurFilename:=ASrcEdit.FileName; + CurFilename:=ASrcEdit.FileName; if FilenameIsPascalUnit(CurFilename) and (FilenameIsAbsolute(CurFilename)) then begin if FileExists(ChangeFileExt(CurFilename,'.lfm')) then @@ -3164,7 +3164,7 @@ begin AddContextPopupMenuItem( 'Open '+ChangeFileExt(ExtractFileName(CurFilename),'.pp'), true,@OnPopupMenuOpenPPFile); - end;} + end; //if Assigned(OnPopupMenu) then OnPopupMenu(@AddContextPopupMenuItem); end; @@ -3316,11 +3316,11 @@ begin end; Procedure TSourceNotebook.BuildPopupMenu; -{$IFDEF UseMenuIntf} +{$IFNDEF DisableMenuIntf} var i: Integer; begin - debugln('TSourceNotebook.BuildPopupMenu'); + //debugln('TSourceNotebook.BuildPopupMenu'); SrcPopupMenu := TPopupMenu.Create(Self); with SrcPopupMenu do begin @@ -3330,8 +3330,11 @@ begin // assign the root TMenuItem to the registered menu root. // This will automatically create all registered items - SourceEditorMenuRoot.MenuItem:=SrcPopupMenu.Items; + {$IFDEF VerboseMenuIntf} SrcPopupMenu.Items.WriteDebugReport('TSourceNotebook.BuildPopupMenu '); + SourceEditorMenuRoot.ConsistencyCheck; + {$ENDIF} + SourceEditorMenuRoot.MenuItem:=SrcPopupMenu.Items; SrcEditMenuFindDeclaration.OnClickMethod:=@FindDeclarationClicked; SrcEditMenuOpenFileAtCursor.OnClickMethod:=@OpenAtCursorClicked; @@ -3671,6 +3674,11 @@ end; {$ENDIF} procedure TSourceNotebook.RemoveUserDefinedMenuItems; +{$IFNDEF DisableMenuIntf} +begin + SrcEditMenuSectionFirstDynamic.Clear; +end; +{$ELSE} var AMenuItem: TMenuItem; begin @@ -3681,9 +3689,17 @@ begin fCustomPopupMenuItems.Delete(fCustomPopupMenuItems.Count-1); end; end; +{$ENDIF} function TSourceNotebook.AddUserDefinedPopupMenuItem(const NewCaption: string; - const NewEnabled: boolean; const NewOnClick: TNotifyEvent): TMenuItem; + const NewEnabled: boolean; const NewOnClick: TNotifyEvent): TIDEMenuItem; +{$IFNDEF DisableMenuIntf} +begin + Result:=RegisterIDEMenuCommand(SrcEditMenuSectionFirstDynamic.GetPath, + 'Dynamic',NewCaption,NewOnClick); + Result.Enabled:=NewEnabled; +end; +{$ELSE} var NewIndex: Integer; begin @@ -3696,8 +3712,17 @@ begin Result.OnClick:=NewOnClick; SrcPopUpMenu.Items.Insert(NewIndex,Result); end; +{$ENDIF} procedure TSourceNotebook.RemoveContextMenuItems; +{$IFNDEF DisableMenuIntf} +begin + SrcEditMenuSectionFileDynamic.Clear; + {$IFDEF VerboseMenuIntf} + SrcEditMenuSectionFileDynamic.WriteDebugReport('TSourceNotebook.RemoveContextMenuItems '); + {$ENDIF} +end; +{$ELSE} var AMenuItem: TMenuItem; begin @@ -3708,9 +3733,17 @@ begin fContextPopupMenuItems.Delete(fContextPopupMenuItems.Count-1); end; end; +{$ENDIF} function TSourceNotebook.AddContextPopupMenuItem(const NewCaption: string; - const NewEnabled: boolean; const NewOnClick: TNotifyEvent): TMenuItem; + const NewEnabled: boolean; const NewOnClick: TNotifyEvent): TIDEMenuItem; +{$IFNDEF DisableMenuIntf} +begin + Result:=RegisterIDEMenuCommand(SrcEditMenuSectionFileDynamic.GetPath, + 'FileDynamic',NewCaption,NewOnClick); + Result.Enabled:=NewEnabled; +end; +{$ELSE} var NewIndex: Integer; begin @@ -3730,6 +3763,7 @@ begin NewIndex:=fContextPopupMenuItems.Count+ClosePageMenuItem.MenuIndex; SrcPopUpMenu.Items.Insert(NewIndex,Result); end; +{$ENDIF} {------------------------------------------------------------------------------- Procedure TSourceNotebook.EditorChanged diff --git a/ideintf/menuintf.pas b/ideintf/menuintf.pas index 444ddb90ac..ca2656933e 100644 --- a/ideintf/menuintf.pas +++ b/ideintf/menuintf.pas @@ -33,11 +33,13 @@ uses IDECommands; type + TIDEMenuItem = class; + TIDEMenuSection = class; + TAddMenuItemProc = function (const NewCaption: string; const NewEnabled: boolean; - const NewOnClick: TNotifyEvent): TMenuItem of object; + const NewOnClick: TNotifyEvent): TIDEMenuItem of object; - TIDEMenuSection = class; TNotifyProcedure = procedure(Sender: TObject); { TIDEMenuItem @@ -48,6 +50,7 @@ type TIDEMenuItem = class(TPersistent) private + FAutoFreeMenuItem: boolean; FBitmap: TBitmap; FCaption: string; FEnabled: Boolean; @@ -62,7 +65,9 @@ type FSectionIndex: Integer; FSize: integer; FVisible: Boolean; + FLastVisibleActive: boolean; procedure MenuItemClick(Sender: TObject); + procedure MenuItemDestroy(Sender: TObject); protected function GetBitmap: TBitmap; virtual; function GetCaption: string; virtual; @@ -87,6 +92,8 @@ type function GetContainerSection: TIDEMenuSection; function GetContainerMenuItem: TMenuItem; function Size: integer; virtual; + procedure WriteDebugReport(const Prefix: string); virtual; + procedure ConsistencyCheck; virtual; public property Name: string read FName write SetName; property Bitmap: TBitmap read GetBitmap write SetBitmap; @@ -101,6 +108,7 @@ type property MenuItem: TMenuItem read FMenuItem write SetMenuItem; property MenuItemClass: TMenuItemClass read FMenuItemClass write FMenuItemClass; property SectionIndex: Integer read FSectionIndex; + property AutoFreeMenuItem: boolean read FAutoFreeMenuItem write FAutoFreeMenuItem; end; TIDEMenuItemClass = class of TIDEMenuItem; @@ -130,9 +138,12 @@ type FTopSeparator: TMenuItem; FChildMenuItemsCreated: boolean; FVisibleCount: integer; - FInvalidChildVisibility: Integer; + FInvalidChildStartIndex: Integer; + FInvalidChildEndIndex: Integer; FUpdateLock: Integer; function GetItems(Index: Integer): TIDEMenuItem; + procedure SeparatorDestroy(Sender : TObject); + procedure FreeSeparators; protected procedure SetMenuItem(const AValue: TMenuItem); override; procedure SetChildsAsSubMenu(const AValue: boolean); virtual; @@ -142,6 +153,7 @@ type procedure UpdateChildsIndex(StartIndex: Integer); procedure UpdateMenuStructure; procedure UpdateSize(Diff: integer); + procedure Invalidate(FromIndex, ToIndex: integer); public constructor Create(const TheName: string); override; destructor Destroy; override; @@ -162,6 +174,8 @@ type function Size: integer; override; procedure BeginUpdate; procedure EndUpdate; + procedure WriteDebugReport(const Prefix: string); override; + procedure ConsistencyCheck; override; public property ChildsAsSubMenu: boolean read FChildsAsSubMenu write SetChildsAsSubMenu default true; @@ -353,10 +367,18 @@ begin if Assigned(OnClickProc) then OnClickProc(Sender); end; +procedure TIDEMenuItem.MenuItemDestroy(Sender: TObject); +begin + FMenuItem:=nil; + FAutoFreeMenuItem:=false; +end; + procedure TIDEMenuItem.SetEnabled(const AValue: Boolean); begin if FEnabled=AValue then exit; FEnabled:=AValue; + if MenuItem<>nil then + MenuItem.Enabled:=Enabled; end; function TIDEMenuItem.GetBitmap: TBitmap; @@ -417,8 +439,12 @@ procedure TIDEMenuItem.SetMenuItem(const AValue: TMenuItem); begin if FMenuItem=AValue then exit; if FMenuItem<>nil then ClearMenuItems; - if FMenuItem=nil then + if FMenuItem=nil then begin FMenuItem:=AValue; + AutoFreeMenuItem:=false; + if MenuItem<>nil then + MenuItem.AddHandlerOnDestroy(@MenuItemDestroy); + end; if MenuItem<>nil then begin MenuItem.Caption:=Caption; MenuItem.Bitmap:=FBitmap; @@ -464,7 +490,10 @@ end; procedure TIDEMenuItem.ClearMenuItems; begin - FMenuItem.Free; + if AutoFreeMenuItem then begin + FAutoFreeMenuItem:=false; + FMenuItem.Free; + end; FMenuItem:=nil; end; @@ -476,6 +505,7 @@ begin FEnabled:=true; FVisible:=true; FMenuItemClass:=TMenuItem; + FSectionIndex:=-1; {$IFDEF VerboseMenuIntf} //debugln('TIDEMenuItem.Create ',dbgsName(Self),' Name="',Name,'"'); {$ENDIF} @@ -486,7 +516,12 @@ begin if Section<>nil then Section.Remove(Self); FreeAndNil(FBitmap); - FreeAndNil(FMenuItem); + if FMenuItem<>nil then begin + if FAutoFreeMenuItem then + FreeAndNil(FMenuItem) + else + FMenuItem.RemoveAllHandlersOfObject(Self); + end; inherited Destroy; end; @@ -504,6 +539,8 @@ begin //debugln('TIDEMenuItem.CreateMenuItem ',dbgsName(Self),' Name="',Name,'"'); {$ENDIF} MenuItem:=MenuItemClass.Create(nil); + MenuItem.AddHandlerOnDestroy(@MenuItemDestroy); + AutoFreeMenuItem:=true; end; function TIDEMenuItem.GetPath: string; @@ -551,6 +588,46 @@ begin Result:=FSize; end; +procedure TIDEMenuItem.WriteDebugReport(const Prefix: string); +begin + debugln(Prefix,'SectionIndex=',dbgs(SectionIndex),' Name="',DbgStr(Name),'" VisibleActive=',dbgs(VisibleActive)); +end; + +procedure TIDEMenuItem.ConsistencyCheck; + + procedure RaiseError; + var + s: String; + begin + s:='TIDEMenuItem.ConsistencyCheck Name="'+Name+'" Caption="'+DbgStr(Caption)+'"'; + debugln(s); + RaiseGDBException(s); + end; + +begin + if MenuItem<>nil then begin + if MenuItem.HasBitmap<>HasBitmap then + RaiseError; + if MenuItem.Enabled<>Enabled then + RaiseError; + if MenuItem.Visible<>Visible then + RaiseError; + if MenuItem.Caption<>Caption then + RaiseError; + if MenuItem.ImageIndex<>ImageIndex then + RaiseError; + if MenuItem.Hint<>Hint then + RaiseError; + end; + if (Section=nil) then begin + if SectionIndex<>-1 then + RaiseError; + end else begin + if SectionIndex<0 then + RaiseError; + end; +end; + { TIDEMenuSection } procedure TIDEMenuSection.SetSubMenuImages(const AValue: TCustomImageList); @@ -565,6 +642,7 @@ procedure TIDEMenuSection.ClearMenuItems; var i: Integer; begin + FreeSeparators; for i:=0 to Count-1 do Items[i].ClearMenuItems; inherited ClearMenuItems; end; @@ -583,6 +661,7 @@ var ContainerMenuItem: TMenuItem; ContainerMenuIndex: integer; Item: TIDEMenuItem; + CurSection: TIDEMenuSection; procedure UpdateNeedTopSeparator; // a separator at top is needed, if @@ -602,6 +681,7 @@ var if Section[i].VisibleActive then begin // there is a visible menu item in front // => the Top separator is needed + //debugln('TIDEMenuSection.UpdateNeedTopSeparator Name="',Name,'" ItemInFront="',Section[i].Name,'"'); NewNeedTopSeparator:=true; break; end; @@ -623,12 +703,16 @@ var if TopSeparator<>nil then begin // TopSeparator is not needed anymore FreeAndNil(FTopSeparator); + {$IFDEF VerboseMenuIntf} + debugln('TIDEMenuSection.UpdateMenuStructure FREE TopSeparator Name="',Name,'"'); + {$ENDIF} end else begin // TopSeparator is needed FTopSeparator:=TMenuItem.Create(nil); + FTopSeparator.AddHandlerOnDestroy(@SeparatorDestroy); FTopSeparator.Caption:='-'; {$IFDEF VerboseMenuIntf} - debugln('TIDEMenuSection.UpdateMenuStructure TopSeparator Name="',Name,'" ContainerMenuIndex=',dbgs(ContainerMenuIndex)); + debugln('TIDEMenuSection.UpdateNeedTopSeparator CREATE TopSeparator Name="',Name,'" ContainerMenuIndex=',dbgs(ContainerMenuIndex),' ContainerMenuItem.Count=',dbgs(ContainerMenuItem.Count)); {$ENDIF} ContainerMenuItem.Insert(ContainerMenuIndex,FTopSeparator); end; @@ -647,6 +731,7 @@ var NewNeedBottomSeparator: Boolean; begin NewNeedBottomSeparator:=false; + //debugln('TIDEMenuSection.UpdateNeedBottomSeparator Name="',Name,'" ChildsAsSubMenu=',dbgs(ChildsAsSubMenu),' Section=',dbgs(Section<>nil),' VisibleActive=',dbgs(VisibleActive)); if (not ChildsAsSubMenu) and (Section<>nil) and VisibleActive then begin // check for any visible item in front i:=SectionIndex+1; @@ -654,10 +739,11 @@ var ItemBehind:=Section[i]; if ItemBehind.VisibleActive then begin // there is a visible menu item behind + //debugln('TIDEMenuSection.UpdateNeedBottomSeparator Name="',Name,'" ItemBehind="',ItemBehind.Name,'"'); if (ItemBehind is TIDEMenuSection) and (not TIDEMenuSection(ItemBehind).ChildsAsSubMenu) then begin - // the visible menu item behind has already a separator + // the visible menu item behind will create its own separator end else begin // the Bottom separator is needed NewNeedBottomSeparator:=true; @@ -667,6 +753,9 @@ var inc(i); end; end; + {$IFDEF VerboseMenuIntf} + debugln('TIDEMenuSection.UpdateNeedBottomSeparator Name="',Name,'" Need BottomSeparator=',dbgs(NewNeedBottomSeparator)); + {$ENDIF} if NewNeedBottomSeparator<>FNeedBottomSeparator then begin FNeedBottomSeparator:=NewNeedBottomSeparator; @@ -682,12 +771,16 @@ var if BottomSeparator<>nil then begin // BottomSeparator is not needed anymore FreeAndNil(FBottomSeparator); + {$IFDEF VerboseMenuIntf} + debugln('TIDEMenuSection.UpdateMenuStructure FREE BottomSeparator Name="',Name,'"'); + {$ENDIF} end else begin // BottomSeparator is needed FBottomSeparator:=TMenuItem.Create(nil); + FBottomSeparator.AddHandlerOnDestroy(@SeparatorDestroy); FBottomSeparator.Caption:='-'; {$IFDEF VerboseMenuIntf} - debugln('TIDEMenuSection.UpdateMenuStructure BottomSeparator Name="',Name,'" ContainerMenuIndex=',dbgs(ContainerMenuIndex)); + debugln('TIDEMenuSection.UpdateMenuStructure CREATE BottomSeparator Name="',Name,'" ContainerMenuIndex=',dbgs(ContainerMenuIndex),' ContainerMenuItem.Count=',dbgs(ContainerMenuItem.Count)); {$ENDIF} ContainerMenuItem.Insert(ContainerMenuIndex,FBottomSeparator); end; @@ -695,17 +788,18 @@ var end; begin - if (FInvalidChildVisibility>=Count) then exit; + if (FInvalidChildStartIndex>FInvalidChildEndIndex) then exit; if FUpdateLock>0 then begin exit; end; - + if FInvalidChildStartIndex<0 then FInvalidChildStartIndex:=0; + if (Section<>nil) and (not Section.ChildsAsSubMenu) - and (Section.FInvalidChildVisibility<=SectionIndex) then begin + and (Section.FInvalidChildStartIndex<=SectionIndex) then begin // the sections in front need update too // => start the update in front {$IFDEF VerboseMenuIntf} - debugln('TIDEMenuSection.UpdateMenuStructure Front Section="',Section.Name,'" Name="',Name,'" Section.FInvalidChildVisibility=',dbgs(Section.FInvalidChildVisibility),' Count=',dbgs(Count),' SectionIndex=',dbgs(SectionIndex)); + debugln('TIDEMenuSection.UpdateMenuStructure Front Section="',Section.Name,'" Name="',Name,'" Section.Invalid=',dbgs(Section.FInvalidChildStartIndex),'..',dbgs(Section.FInvalidChildEndIndex),' Count=',dbgs(Count),' SectionIndex=',dbgs(SectionIndex)); {$ENDIF} Section.UpdateMenuStructure; end else begin @@ -716,37 +810,53 @@ begin else ContainerMenuIndex:=GetContainerIndex(false); {$IFDEF VerboseMenuIntf} - debugln('TIDEMenuSection.UpdateMenuStructure Childs Name="',Name,'" FInvalidChildVisibility=',dbgs(FInvalidChildVisibility),' Count=',dbgs(Count)); + debugln('TIDEMenuSection.UpdateMenuStructure Childs Name="',Name,'" Invalid=',dbgs(FInvalidChildStartIndex),'..',dbgs(FInvalidChildEndIndex),' Count=',dbgs(Count)); {$ENDIF} // update TopSeparator - if FInvalidChildVisibility=0 then + if FInvalidChildStartIndex=0 then UpdateNeedTopSeparator; if FTopSeparator<>nil then inc(ContainerMenuIndex); // update childs - while FInvalidChildVisibilityVisibleActive) and (Section<>nil) then + if (Section<>nil) and (OldVisibleActive<>VisibleActive) then Section.ItemVisibleActiveChanged(Self); + EndUpdate; end; function TIDEMenuSection.Count: Integer; @@ -847,8 +1006,11 @@ begin UpdateChildsIndex(Index); UpdateSize(1); AnItem.FSection:=Self; - if AnItem.Visible then + if AnItem.VisibleActive then ItemVisibleActiveChanged(AnItem); + {$IFDEF VerboseMenuIntf} + ConsistencyCheck; + {$ENDIF} end; procedure TIDEMenuSection.Remove(AnItem: TIDEMenuItem); @@ -964,18 +1126,62 @@ begin UpdateMenuStructure; end; +procedure TIDEMenuSection.WriteDebugReport(const Prefix: string); +var + i: Integer; +begin + inherited WriteDebugReport(Prefix); + for i:=0 to Count-1 do Items[i].WriteDebugReport(Prefix+' '); +end; + +procedure TIDEMenuSection.ConsistencyCheck; +var + i: Integer; + Item: TIDEMenuItem; + RealVisibleCount: Integer; +begin + inherited ConsistencyCheck; + RealVisibleCount:=0; + for i:=0 to Count-1 do begin + Item:=Items[i]; + Item.ConsistencyCheck; + if Item.SectionIndex<>i then + RaiseGDBException(''); + if Item.VisibleActive then + inc(RealVisibleCount); + end; + if RealVisibleCount<>VisibleCount then + RaiseGDBException(''); +end; + function TIDEMenuSection.GetItems(Index: Integer): TIDEMenuItem; begin Result:=TIDEMenuItem(FItems[Index]); end; +procedure TIDEMenuSection.SeparatorDestroy(Sender: TObject); +begin + if Sender=FTopSeparator then + FTopSeparator:=nil; + if Sender=FBottomSeparator then + FBottomSeparator:=nil; +end; + +procedure TIDEMenuSection.FreeSeparators; +begin + FNeedTopSeparator:=false; + FreeAndNil(FTopSeparator); + FNeedBottomSeparator:=false; + FreeAndNil(FBottomSeparator); +end; + procedure TIDEMenuSection.SetMenuItem(const AValue: TMenuItem); begin if MenuItem=AValue then exit; inherited SetMenuItem(AValue); - FInvalidChildVisibility:=0; + Invalidate(0,Count-1); {$IFDEF VerboseMenuIntf} - debugln('TIDEMenuSection.SetMenuItem ',Name,' FInvalidChildVisibility=',dbgs(FInvalidChildVisibility)); + debugln('TIDEMenuSection.SetMenuItem Name="',Name,'"'); {$ENDIF} UpdateMenuStructure; end; @@ -986,9 +1192,9 @@ begin FChildsAsSubMenu:=AValue; ClearMenuItems; if Section<>nil then begin - Section.FInvalidChildVisibility:=SectionIndex; + Section.Invalidate(SectionIndex,SectionIndex); {$IFDEF VerboseMenuIntf} - debugln('TIDEMenuSection.SetChildsAsSubMenu FInvalidChildVisibility=',dbgs(FInvalidChildVisibility)); + debugln('TIDEMenuSection.SetChildsAsSubMenu Name="',Name,'"'); {$ENDIF} Section.UpdateMenuStructure; end; diff --git a/lcl/controls.pp b/lcl/controls.pp index e9089701b1..f52627397c 100644 --- a/lcl/controls.pp +++ b/lcl/controls.pp @@ -985,7 +985,7 @@ type procedure DoOnShowHint(HintInfo: Pointer); procedure VisibleChanging; dynamic; procedure AddHandler(HandlerType: TControlHandlerType; - const AMethod: TMethod; AsLast: boolean); + const AMethod: TMethod; AsLast: boolean = false); procedure RemoveHandler(HandlerType: TControlHandlerType; const AMethod: TMethod); procedure DoContextPopup(const MousePos: TPoint; var Handled: Boolean); virtual; @@ -1104,11 +1104,12 @@ type public // Event lists procedure RemoveAllHandlersOfObject(AnObject: TObject); override; - procedure AddHandlerOnResize(OnResizeEvent: TNotifyEvent; AsLast: boolean); - procedure RemoveHandlerOnResize(OnResizeEvent: TNotifyEvent); - procedure AddHandlerOnChangeBounds(OnChangeBoundsEvent: TNotifyEvent; - AsLast: boolean); - procedure RemoveHandlerOnChangeBounds(OnChangeBoundsEvent: TNotifyEvent); + procedure AddHandlerOnResize(const OnResizeEvent: TNotifyEvent; + AsLast: boolean = false); + procedure RemoveHandlerOnResize(const OnResizeEvent: TNotifyEvent); + procedure AddHandlerOnChangeBounds(const OnChangeBoundsEvent: TNotifyEvent; + AsLast: boolean = false); + procedure RemoveHandlerOnChangeBounds(const OnChangeBoundsEvent: TNotifyEvent); public // standard properties, which should be supported by all descendants property Action: TBasicAction read GetAction write SetAction; diff --git a/lcl/include/control.inc b/lcl/include/control.inc index c5ce005b59..5f087c58a4 100644 --- a/lcl/include/control.inc +++ b/lcl/include/control.inc @@ -3039,25 +3039,25 @@ begin Result:=Control.ManualDock(NewDockSite,DropControl,ControlSide); end; -procedure TControl.AddHandlerOnResize(OnResizeEvent: TNotifyEvent; +procedure TControl.AddHandlerOnResize(const OnResizeEvent: TNotifyEvent; AsLast: boolean); begin AddHandler(chtOnResize,TMethod(OnResizeEvent),AsLast); end; -procedure TControl.RemoveHandlerOnResize(OnResizeEvent: TNotifyEvent); +procedure TControl.RemoveHandlerOnResize(const OnResizeEvent: TNotifyEvent); begin RemoveHandler(chtOnResize,TMethod(OnResizeEvent)); end; -procedure TControl.AddHandlerOnChangeBounds(OnChangeBoundsEvent: TNotifyEvent; - AsLast: boolean); +procedure TControl.AddHandlerOnChangeBounds( + const OnChangeBoundsEvent: TNotifyEvent; AsLast: boolean); begin AddHandler(chtOnChangeBounds,TMethod(OnChangeBoundsEvent),AsLast); end; -procedure TControl.RemoveHandlerOnChangeBounds(OnChangeBoundsEvent: TNotifyEvent - ); +procedure TControl.RemoveHandlerOnChangeBounds( + const OnChangeBoundsEvent: TNotifyEvent); begin RemoveHandler(chtOnChangeBounds,TMethod(OnChangeBoundsEvent)); end; diff --git a/lcl/include/menuitem.inc b/lcl/include/menuitem.inc index a43d80be35..a165ff716c 100644 --- a/lcl/include/menuitem.inc +++ b/lcl/include/menuitem.inc @@ -175,6 +175,9 @@ destructor TMenuItem.Destroy; var i : integer; begin + i:=FMenuItemHandlers[mihtDestroy].Count; + while FMenuItemHandlers[mihtDestroy].NextDownIndex(i) do + TNotifyEvent(FMenuItemHandlers[mihtDestroy][i])(Self); if FBitmap<>nil then FreeAndNil(FBitmap); DestroyHandle; @@ -796,6 +799,40 @@ begin end; end; +procedure TMenuItem.RemoveAllHandlersOfObject(AnObject: TObject); +var + HandlerType: TMenuItemHandlerType; +begin + inherited RemoveAllHandlersOfObject(AnObject); + for HandlerType:=Low(TMenuItemHandlerType) to High(TMenuItemHandlerType) do + FMenuItemHandlers[HandlerType].RemoveAllMethodsOfObject(AnObject); +end; + +procedure TMenuItem.AddHandlerOnDestroy(const OnDestroyEvent: TNotifyEvent; + AsLast: boolean); +begin + AddHandler(mihtDestroy,TMethod(OnDestroyEvent),AsLast); +end; + +procedure TMenuItem.RemoveHandlerOnDestroy(const OnDestroyEvent: TNotifyEvent); +begin + RemoveHandler(mihtDestroy,TMethod(OnDestroyEvent)); +end; + +procedure TMenuItem.AddHandler(HandlerType: TMenuItemHandlerType; + const AMethod: TMethod; AsLast: boolean); +begin + if FMenuItemHandlers[HandlerType]=nil then + FMenuItemHandlers[HandlerType]:=TMethodList.Create; + FMenuItemHandlers[HandlerType].Add(AMethod); +end; + +procedure TMenuItem.RemoveHandler(HandlerType: TMenuItemHandlerType; + const AMethod: TMethod); +begin + FMenuItemHandlers[HandlerType].Remove(AMethod); +end; + function TMenuItem.MenuVisibleIndex: integer; begin Result:=-1; diff --git a/lcl/menus.pp b/lcl/menus.pp index 32536319db..59b9ff94d1 100644 --- a/lcl/menus.pp +++ b/lcl/menus.pp @@ -91,6 +91,10 @@ type { TMenuItem } + + TMenuItemHandlerType = ( + mihtDestroy + ); TMenuItem = class(TLCLComponent) private @@ -119,6 +123,7 @@ type FShowAlwaysCheckable: boolean; FSubMenuImages: TCustomImageList; FVisible: Boolean; + FMenuItemHandlers: array[TMenuItemHandlerType] of TMethodList; function GetBitmap: TBitmap; function GetCount: Integer; function GetItem(Index: Integer): TMenuItem; @@ -203,6 +208,16 @@ type procedure Clear; function HasBitmap: boolean; function GetIconSize: TPoint; virtual; + public + // Event lists + procedure RemoveAllHandlersOfObject(AnObject: TObject); override; + procedure AddHandlerOnDestroy(const OnDestroyEvent: TNotifyEvent; + AsLast: boolean = false); + procedure RemoveHandlerOnDestroy(const OnDestroyEvent: TNotifyEvent); + procedure AddHandler(HandlerType: TMenuItemHandlerType; + const AMethod: TMethod; AsLast: boolean); + procedure RemoveHandler(HandlerType: TMenuItemHandlerType; + const AMethod: TMethod); public property Count: Integer read GetCount; property Handle: HMenu read GetHandle write FHandle; diff --git a/packager/basepkgmanager.pas b/packager/basepkgmanager.pas index 45dc425538..f4880bb429 100644 --- a/packager/basepkgmanager.pas +++ b/packager/basepkgmanager.pas @@ -83,7 +83,7 @@ type procedure SaveSettings; virtual; abstract; procedure UpdateVisibleComponentPalette; virtual; abstract; procedure ProcessCommand(Command: word; var Handled: boolean); virtual; abstract; - procedure OnSourceEditorPopupMenu(AddMenuItemProc: TAddMenuItemProc); virtual; abstract; + procedure OnSourceEditorPopupMenu(const AddMenuItemProc: TAddMenuItemProc); virtual; abstract; // files function GetDefaultSaveDirectoryForFile(const Filename: string): string; virtual; abstract; diff --git a/packager/pkgmanager.pas b/packager/pkgmanager.pas index f67d14a7a1..4b43ed8bc5 100644 --- a/packager/pkgmanager.pas +++ b/packager/pkgmanager.pas @@ -194,7 +194,7 @@ type procedure SaveSettings; override; procedure UpdateVisibleComponentPalette; override; procedure ProcessCommand(Command: word; var Handled: boolean); override; - procedure OnSourceEditorPopupMenu(AddMenuItemProc: TAddMenuItemProc); override; + procedure OnSourceEditorPopupMenu(const AddMenuItemProc: TAddMenuItemProc); override; // files function GetDefaultSaveDirectoryForFile(const Filename: string): string; override; @@ -2113,8 +2113,8 @@ begin end; end; -procedure TPkgManager.OnSourceEditorPopupMenu(AddMenuItemProc: TAddMenuItemProc - ); +procedure TPkgManager.OnSourceEditorPopupMenu( + const AddMenuItemProc: TAddMenuItemProc); var PkgFile: TPkgFile; begin