Fixed: moving of menu items in the editor
Fixed: actions are executed immediately if the queue is empty Fixed: SetSelectedItem can handle nil with raising an AV Fixed: memory leak in animation action
This commit is contained in:
parent
e070e53c07
commit
670eb4baa5
@ -49,6 +49,7 @@ type
|
|||||||
private
|
private
|
||||||
FMenuBar: TX2CustomMenuBar;
|
FMenuBar: TX2CustomMenuBar;
|
||||||
FDesignerAttached: Boolean;
|
FDesignerAttached: Boolean;
|
||||||
|
FMoving: Boolean;
|
||||||
|
|
||||||
procedure SetMenuBar(const Value: TX2CustomMenuBar);
|
procedure SetMenuBar(const Value: TX2CustomMenuBar);
|
||||||
|
|
||||||
@ -81,7 +82,7 @@ type
|
|||||||
implementation
|
implementation
|
||||||
uses
|
uses
|
||||||
Contnrs,
|
Contnrs,
|
||||||
SysUtils;
|
SysUtils, Dialogs;
|
||||||
|
|
||||||
|
|
||||||
var
|
var
|
||||||
@ -289,8 +290,8 @@ begin
|
|||||||
{ Make sure the group is inserted in the correct position by searching
|
{ Make sure the group is inserted in the correct position by searching
|
||||||
for it's sibling group. Note: do NOT use Items[x] in a loop; TTreeView
|
for it's sibling group. Note: do NOT use Items[x] in a loop; TTreeView
|
||||||
emulates this by using GetFirst/GetNext. }
|
emulates this by using GetFirst/GetNext. }
|
||||||
if AGroup.Index > 0 then
|
if AGroup.Index < Pred(AGroup.Collection.Count) then
|
||||||
siblingGroup := TX2MenuBarGroup(AGroup.Collection.Items[Pred(AGroup.Index)]);
|
siblingGroup := TX2MenuBarGroup(AGroup.Collection.Items[Succ(AGroup.Index)]);
|
||||||
|
|
||||||
if Assigned(siblingGroup) then
|
if Assigned(siblingGroup) then
|
||||||
begin
|
begin
|
||||||
@ -305,9 +306,9 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
if Assigned(siblingNode) then
|
if Assigned(siblingNode) then
|
||||||
groupNode := tvMenu.Items.Add(siblingNode, '')
|
groupNode := tvMenu.Items.AddNode(nil, siblingNode, '', nil, naInsert)
|
||||||
else
|
else
|
||||||
groupNode := tvMenu.Items.AddFirst(nil, '');
|
groupNode := tvMenu.Items.Add(nil, '');
|
||||||
|
|
||||||
groupNode.Data := AGroup;
|
groupNode.Data := AGroup;
|
||||||
UpdateNode(groupNode);
|
UpdateNode(groupNode);
|
||||||
@ -337,8 +338,8 @@ begin
|
|||||||
siblingNode := nil;
|
siblingNode := nil;
|
||||||
|
|
||||||
{ See AddGroup }
|
{ See AddGroup }
|
||||||
if AItem.Index > 0 then
|
if AItem.Index < Pred(AItem.Collection.Count) then
|
||||||
siblingItem := TX2MenuBarItem(AItem.Collection.Items[Pred(AItem.Index)]);
|
siblingItem := TX2MenuBarItem(AItem.Collection.Items[Succ(AItem.Index)]);
|
||||||
|
|
||||||
if Assigned(siblingItem) then
|
if Assigned(siblingItem) then
|
||||||
begin
|
begin
|
||||||
@ -353,9 +354,9 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
if Assigned(siblingNode) then
|
if Assigned(siblingNode) then
|
||||||
itemNode := tvMenu.Items.Add(siblingNode, '')
|
itemNode := tvMenu.Items.AddNode(nil, siblingNode, '', nil, naInsert)
|
||||||
else
|
else
|
||||||
itemNode := tvMenu.Items.AddChildFirst(ANode, '');
|
itemNode := tvMenu.Items.AddChild(ANode, '');
|
||||||
|
|
||||||
itemNode.Data := AItem;
|
itemNode.Data := AItem;
|
||||||
UpdateNode(itemNode);
|
UpdateNode(itemNode);
|
||||||
@ -451,6 +452,9 @@ var
|
|||||||
treeNode: TTreeNode;
|
treeNode: TTreeNode;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
|
if FMoving then
|
||||||
|
Exit;
|
||||||
|
|
||||||
treeNode := nil;
|
treeNode := nil;
|
||||||
|
|
||||||
if AItem is TX2MenuBarGroup then
|
if AItem is TX2MenuBarGroup then
|
||||||
@ -477,6 +481,9 @@ var
|
|||||||
treeNode: TTreeNode;
|
treeNode: TTreeNode;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
|
if FMoving then
|
||||||
|
Exit;
|
||||||
|
|
||||||
tvMenu.Items.BeginUpdate();
|
tvMenu.Items.BeginUpdate();
|
||||||
try
|
try
|
||||||
treeNode := tvMenu.Items.GetFirstNode();
|
treeNode := tvMenu.Items.GetFirstNode();
|
||||||
@ -496,6 +503,9 @@ var
|
|||||||
treeNode: TTreeNode;
|
treeNode: TTreeNode;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
|
if FMoving then
|
||||||
|
Exit;
|
||||||
|
|
||||||
treeNode := GetItemNode(AItem);
|
treeNode := GetItemNode(AItem);
|
||||||
if Assigned(treeNode) then
|
if Assigned(treeNode) then
|
||||||
tvMenu.Items.Delete(treeNode);
|
tvMenu.Items.Delete(treeNode);
|
||||||
@ -544,6 +554,8 @@ begin
|
|||||||
if selectedItem is TX2MenuBarItem then
|
if selectedItem is TX2MenuBarItem then
|
||||||
group := TX2MenuBarItem(selectedItem).Group;
|
group := TX2MenuBarItem(selectedItem).Group;
|
||||||
|
|
||||||
|
FMoving := True;
|
||||||
|
try
|
||||||
if ADown then
|
if ADown then
|
||||||
begin
|
begin
|
||||||
if selectedItem.Index < Pred(selectedItem.Collection.Count) then
|
if selectedItem.Index < Pred(selectedItem.Collection.Count) then
|
||||||
@ -552,10 +564,13 @@ begin
|
|||||||
refresh := True;
|
refresh := True;
|
||||||
end else if Assigned(group) then
|
end else if Assigned(group) then
|
||||||
begin
|
begin
|
||||||
{ Move down to another group }
|
{ Move down to another group
|
||||||
|
The AddItem is triggered by moving between groups, no need
|
||||||
|
to add here. }
|
||||||
if group.Index < Pred(MenuBar.Groups.Count) then
|
if group.Index < Pred(MenuBar.Groups.Count) then
|
||||||
begin
|
begin
|
||||||
selectedItem.Collection := MenuBar.Groups[Succ(group.Index)].Items;
|
selectedItem.Collection := MenuBar.Groups[Succ(group.Index)].Items;
|
||||||
|
selectedItem.Index := 0;
|
||||||
refresh := True;
|
refresh := True;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
@ -575,6 +590,8 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
finally
|
||||||
|
FMoving := False;
|
||||||
|
|
||||||
if refresh then
|
if refresh then
|
||||||
begin
|
begin
|
||||||
@ -582,6 +599,7 @@ begin
|
|||||||
ItemAdded(selectedItem);
|
ItemAdded(selectedItem);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
function TfrmMenuBarEditor.GetSelectedItem(): TX2CustomMenuBarItem;
|
function TfrmMenuBarEditor.GetSelectedItem(): TX2CustomMenuBarItem;
|
||||||
|
@ -21,10 +21,14 @@ uses
|
|||||||
Graphics,
|
Graphics,
|
||||||
ImgList,
|
ImgList,
|
||||||
Messages,
|
Messages,
|
||||||
|
SysUtils,
|
||||||
Types,
|
Types,
|
||||||
Windows;
|
Windows;
|
||||||
|
|
||||||
|
|
||||||
type
|
type
|
||||||
|
EInvalidItem = class(Exception);
|
||||||
|
|
||||||
TX2MenuBarAnimationStyle = (asNone, asSlide, asDissolve, asFade,
|
TX2MenuBarAnimationStyle = (asNone, asSlide, asDissolve, asFade,
|
||||||
asSlideFade, asCustom);
|
asSlideFade, asCustom);
|
||||||
|
|
||||||
@ -181,7 +185,7 @@ type
|
|||||||
:$ Abstract action class.
|
:$ Abstract action class.
|
||||||
|
|
||||||
:: Provides a base for menu bar actions which need to be performed
|
:: Provides a base for menu bar actions which need to be performed
|
||||||
:: asynchronous and in sequence.
|
:: asynchronous and/or in sequence.
|
||||||
}
|
}
|
||||||
TX2CustomMenuBarAction = class(TObject)
|
TX2CustomMenuBarAction = class(TObject)
|
||||||
private
|
private
|
||||||
@ -457,6 +461,8 @@ type
|
|||||||
procedure CMMouseLeave(var Msg: TMessage); message CM_MOUSELEAVE;
|
procedure CMMouseLeave(var Msg: TMessage); message CM_MOUSELEAVE;
|
||||||
|
|
||||||
procedure WMVScroll(var Msg: TWMVScroll); message WM_VSCROLL;
|
procedure WMVScroll(var Msg: TWMVScroll); message WM_VSCROLL;
|
||||||
|
// procedure WMMouseWheel(var Message: TWMMouseWheel); message WM_MOUSEWHEEL;
|
||||||
|
// procedure CMMouseWheel(var Message: TCMMouseWheel); message CM_MOUSEWHEEL;
|
||||||
|
|
||||||
procedure TestMousePos(); virtual;
|
procedure TestMousePos(); virtual;
|
||||||
function GetMenuHeight(): Integer; virtual;
|
function GetMenuHeight(): Integer; virtual;
|
||||||
@ -593,6 +599,8 @@ type
|
|||||||
property HideScrollbar;
|
property HideScrollbar;
|
||||||
property Images;
|
property Images;
|
||||||
property ParentFont;
|
property ParentFont;
|
||||||
|
property TabOrder;
|
||||||
|
property TabStop default True;
|
||||||
property OnClick;
|
property OnClick;
|
||||||
property OnCollapsed;
|
property OnCollapsed;
|
||||||
property OnCollapsing;
|
property OnCollapsing;
|
||||||
@ -628,16 +636,17 @@ const
|
|||||||
|
|
||||||
implementation
|
implementation
|
||||||
uses
|
uses
|
||||||
SysUtils,
|
|
||||||
|
|
||||||
X2CLGraphics,
|
X2CLGraphics,
|
||||||
X2CLMenuBarActions,
|
X2CLMenuBarActions,
|
||||||
X2CLMenuBarAnimators;
|
X2CLMenuBarAnimators;
|
||||||
|
|
||||||
|
|
||||||
const
|
const
|
||||||
SDefaultItemCaption = 'Menu Item';
|
SDefaultItemCaption = 'Menu Item';
|
||||||
SDefaultGroupCaption = 'Group';
|
SDefaultGroupCaption = 'Group';
|
||||||
SNoPainter = 'Painter property not set';
|
SNoPainter = 'Painter property not set';
|
||||||
|
SInvalidItem = 'Item does not belong to this MenuBar';
|
||||||
|
|
||||||
|
|
||||||
type
|
type
|
||||||
TProtectedCollection = class(TCollection);
|
TProtectedCollection = class(TCollection);
|
||||||
@ -1392,6 +1401,7 @@ begin
|
|||||||
FGroups.OnUpdate := GroupsUpdate;
|
FGroups.OnUpdate := GroupsUpdate;
|
||||||
FHideScrollbar := True;
|
FHideScrollbar := True;
|
||||||
FScrollbar := True;
|
FScrollbar := True;
|
||||||
|
TabStop := True;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
@ -1506,6 +1516,23 @@ begin
|
|||||||
begin
|
begin
|
||||||
currentAction.Stop();
|
currentAction.Stop();
|
||||||
PopCurrentAction();
|
PopCurrentAction();
|
||||||
|
|
||||||
|
{ Start the next action in the queue, continue until we find an
|
||||||
|
action which doesn't terminate immediately. See PushAction. }
|
||||||
|
currentAction := GetCurrentAction();
|
||||||
|
while Assigned(currentAction) do
|
||||||
|
begin
|
||||||
|
currentAction.Start();
|
||||||
|
|
||||||
|
if currentAction.Terminated then
|
||||||
|
begin
|
||||||
|
currentAction.Stop();
|
||||||
|
PopCurrentAction();
|
||||||
|
|
||||||
|
currentAction := GetCurrentAction();
|
||||||
|
end else
|
||||||
|
Break;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
end
|
end
|
||||||
@ -1949,8 +1976,29 @@ end;
|
|||||||
|
|
||||||
|
|
||||||
procedure TX2CustomMenuBar.PushAction(AAction: TX2CustomMenuBarAction);
|
procedure TX2CustomMenuBar.PushAction(AAction: TX2CustomMenuBarAction);
|
||||||
|
var
|
||||||
|
action: TX2CustomMenuBarAction;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
ActionQueue.Add(AAction);
|
action := AAction;
|
||||||
|
|
||||||
|
if ActionQueue.Count = 0 then
|
||||||
|
begin
|
||||||
|
{ Start the action; if it's terminated immediately don't add it to the
|
||||||
|
queue. This enables actions like selecting an item without requiring
|
||||||
|
animation to fire straight away. }
|
||||||
|
action.Start();
|
||||||
|
|
||||||
|
if action.Terminated then
|
||||||
|
begin
|
||||||
|
action.Stop();
|
||||||
|
FreeAndNil(action);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if Assigned(action) then
|
||||||
|
ActionQueue.Add(action);
|
||||||
|
|
||||||
Invalidate();
|
Invalidate();
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -1967,16 +2015,31 @@ procedure TX2CustomMenuBar.InternalSetExpanded(AGroup: TX2MenuBarGroup;
|
|||||||
begin
|
begin
|
||||||
AGroup.InternalSetExpanded(AExpanded);
|
AGroup.InternalSetExpanded(AExpanded);
|
||||||
DoExpandedChanged(AGroup);
|
DoExpandedChanged(AGroup);
|
||||||
|
|
||||||
|
Invalidate();
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
procedure TX2CustomMenuBar.InternalSetSelected(AItem: TX2CustomMenuBarItem);
|
procedure TX2CustomMenuBar.InternalSetSelected(AItem: TX2CustomMenuBarItem);
|
||||||
|
var
|
||||||
|
group: TX2MenuBarGroup;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
FSelectedItem := AItem;
|
FSelectedItem := AItem;
|
||||||
DoSelectedChanged();
|
DoSelectedChanged();
|
||||||
|
|
||||||
if Assigned(SelectedItem) and Assigned(SelectedItem.Action) then
|
if Assigned(AItem) then
|
||||||
SelectedItem.ActionLink.Execute(Self);
|
begin
|
||||||
|
if (AItem is TX2MenuBarItem) then
|
||||||
|
begin
|
||||||
|
group := TX2MenuBarItem(AItem).Group;
|
||||||
|
if Assigned(group) then
|
||||||
|
group.SelectedItem := AItem.Index;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if Assigned(AItem) and Assigned(AItem.Action) then
|
||||||
|
AItem.ActionLink.Execute(Self);
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
@ -2902,14 +2965,21 @@ var
|
|||||||
begin
|
begin
|
||||||
if Value <> FSelectedItem then
|
if Value <> FSelectedItem then
|
||||||
begin
|
begin
|
||||||
|
if Assigned(Value) and (Value.MenuBar <> Self) then
|
||||||
|
raise EInvalidItem.Create(SInvalidItem);
|
||||||
|
|
||||||
|
|
||||||
allowed := (not Assigned(Value)) or ItemEnabled(Value);
|
allowed := (not Assigned(Value)) or ItemEnabled(Value);
|
||||||
if allowed then
|
if allowed then
|
||||||
DoSelectedChanging(Value, allowed);
|
DoSelectedChanging(Value, allowed);
|
||||||
|
|
||||||
|
|
||||||
if allowed then
|
if allowed then
|
||||||
begin
|
begin
|
||||||
selectItem := Value;
|
selectItem := Value;
|
||||||
|
|
||||||
|
if Assigned(selectItem) then
|
||||||
|
begin
|
||||||
if selectItem is TX2MenuBarGroup then
|
if selectItem is TX2MenuBarGroup then
|
||||||
begin
|
begin
|
||||||
group := TX2MenuBarGroup(selectItem);
|
group := TX2MenuBarGroup(selectItem);
|
||||||
@ -2930,11 +3000,32 @@ begin
|
|||||||
PerformSelectItem(group);
|
PerformSelectItem(group);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
end else
|
||||||
|
begin
|
||||||
|
if (selectItem is TX2MenuBarItem) then
|
||||||
|
begin
|
||||||
|
group := TX2MenuBarItem(selectItem).Group;
|
||||||
|
if Assigned(group) and (not group.Expanded) then
|
||||||
|
PerformExpand(group, True);
|
||||||
|
end;
|
||||||
|
|
||||||
|
PerformSelectItem(selectItem);
|
||||||
|
end;
|
||||||
end else
|
end else
|
||||||
PerformSelectItem(selectItem);
|
PerformSelectItem(selectItem);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
//procedure TX2CustomMenuBar.WMMouseWheel(var Message: TWMMouseWheel);
|
||||||
|
//begin
|
||||||
|
//// MessageBox(0, 'I gots a mousewheel', '', 0);
|
||||||
|
//end;
|
||||||
|
//
|
||||||
|
//procedure TX2CustomMenuBar.CMMouseWheel(var Message: TCMMouseWheel);
|
||||||
|
//begin
|
||||||
|
//// MessageBox(0, 'I gots a mousewheel', '', 0);
|
||||||
|
//end;
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@ type
|
|||||||
public
|
public
|
||||||
constructor Create(AMenuBar: TX2CustomMenuBar; AGroup: TX2MenuBarGroup;
|
constructor Create(AMenuBar: TX2CustomMenuBar; AGroup: TX2MenuBarGroup;
|
||||||
AAnimator: TX2CustomMenuBarAnimator);
|
AAnimator: TX2CustomMenuBarAnimator);
|
||||||
|
destructor Destroy(); override;
|
||||||
|
|
||||||
procedure Start(); override;
|
procedure Start(); override;
|
||||||
|
|
||||||
@ -130,6 +131,14 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
destructor TX2MenuBarAnimateAction.Destroy();
|
||||||
|
begin
|
||||||
|
FreeAndNil(FAnimator);
|
||||||
|
|
||||||
|
inherited;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
procedure TX2MenuBarAnimateAction.Start();
|
procedure TX2MenuBarAnimateAction.Start();
|
||||||
begin
|
begin
|
||||||
inherited;
|
inherited;
|
||||||
@ -340,7 +349,6 @@ begin
|
|||||||
inherited;
|
inherited;
|
||||||
|
|
||||||
TProtectedX2CustomMenuBar(MenuBar).InternalSetExpanded(FGroup, FExpanding);
|
TProtectedX2CustomMenuBar(MenuBar).InternalSetExpanded(FGroup, FExpanding);
|
||||||
MenuBar.Invalidate();
|
|
||||||
Terminate();
|
Terminate();
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user