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:
Mark van Renswoude 2007-06-01 06:41:52 +00:00
parent e070e53c07
commit 670eb4baa5
3 changed files with 180 additions and 63 deletions

View File

@ -49,6 +49,7 @@ type
private
FMenuBar: TX2CustomMenuBar;
FDesignerAttached: Boolean;
FMoving: Boolean;
procedure SetMenuBar(const Value: TX2CustomMenuBar);
@ -81,7 +82,7 @@ type
implementation
uses
Contnrs,
SysUtils;
SysUtils, Dialogs;
var
@ -289,8 +290,8 @@ begin
{ 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
emulates this by using GetFirst/GetNext. }
if AGroup.Index > 0 then
siblingGroup := TX2MenuBarGroup(AGroup.Collection.Items[Pred(AGroup.Index)]);
if AGroup.Index < Pred(AGroup.Collection.Count) then
siblingGroup := TX2MenuBarGroup(AGroup.Collection.Items[Succ(AGroup.Index)]);
if Assigned(siblingGroup) then
begin
@ -305,9 +306,9 @@ begin
end;
if Assigned(siblingNode) then
groupNode := tvMenu.Items.Add(siblingNode, '')
groupNode := tvMenu.Items.AddNode(nil, siblingNode, '', nil, naInsert)
else
groupNode := tvMenu.Items.AddFirst(nil, '');
groupNode := tvMenu.Items.Add(nil, '');
groupNode.Data := AGroup;
UpdateNode(groupNode);
@ -337,8 +338,8 @@ begin
siblingNode := nil;
{ See AddGroup }
if AItem.Index > 0 then
siblingItem := TX2MenuBarItem(AItem.Collection.Items[Pred(AItem.Index)]);
if AItem.Index < Pred(AItem.Collection.Count) then
siblingItem := TX2MenuBarItem(AItem.Collection.Items[Succ(AItem.Index)]);
if Assigned(siblingItem) then
begin
@ -353,9 +354,9 @@ begin
end;
if Assigned(siblingNode) then
itemNode := tvMenu.Items.Add(siblingNode, '')
itemNode := tvMenu.Items.AddNode(nil, siblingNode, '', nil, naInsert)
else
itemNode := tvMenu.Items.AddChildFirst(ANode, '');
itemNode := tvMenu.Items.AddChild(ANode, '');
itemNode.Data := AItem;
UpdateNode(itemNode);
@ -451,6 +452,9 @@ var
treeNode: TTreeNode;
begin
if FMoving then
Exit;
treeNode := nil;
if AItem is TX2MenuBarGroup then
@ -477,6 +481,9 @@ var
treeNode: TTreeNode;
begin
if FMoving then
Exit;
tvMenu.Items.BeginUpdate();
try
treeNode := tvMenu.Items.GetFirstNode();
@ -496,6 +503,9 @@ var
treeNode: TTreeNode;
begin
if FMoving then
Exit;
treeNode := GetItemNode(AItem);
if Assigned(treeNode) then
tvMenu.Items.Delete(treeNode);
@ -533,53 +543,61 @@ var
begin
if not Assigned(MenuBar) then
Exit;
selectedItem := GetSelectedItem();
if not Assigned(selectedItem) then
Exit;
refresh := False;
group := nil;
if selectedItem is TX2MenuBarItem then
group := TX2MenuBarItem(selectedItem).Group;
if ADown then
begin
if selectedItem.Index < Pred(selectedItem.Collection.Count) then
FMoving := True;
try
if ADown then
begin
selectedItem.Index := Succ(selectedItem.Index);
refresh := True;
end else if Assigned(group) then
begin
{ Move down to another group }
if group.Index < Pred(MenuBar.Groups.Count) then
if selectedItem.Index < Pred(selectedItem.Collection.Count) then
begin
selectedItem.Collection := MenuBar.Groups[Succ(group.Index)].Items;
refresh := True;
selectedItem.Index := Succ(selectedItem.Index);
refresh := True;
end else if Assigned(group) then
begin
{ 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
begin
selectedItem.Collection := MenuBar.Groups[Succ(group.Index)].Items;
selectedItem.Index := 0;
refresh := True;
end;
end;
end else
begin
if selectedItem.Index > 0 then
begin
selectedItem.Index := Pred(selectedItem.Index);
refresh := True;
end else if Assigned(group) then
begin
{ Move up to another group }
if group.Index > 0 then
begin
selectedItem.Collection := MenuBar.Groups[Pred(group.Index)].Items;
refresh := True;
end;
end;
end;
end else
begin
if selectedItem.Index > 0 then
begin
selectedItem.Index := Pred(selectedItem.Index);
refresh := True;
end else if Assigned(group) then
begin
{ Move up to another group }
if group.Index > 0 then
begin
selectedItem.Collection := MenuBar.Groups[Pred(group.Index)].Items;
refresh := True;
end;
end;
end;
finally
FMoving := False;
if refresh then
begin
ItemDeleting(selectedItem);
ItemAdded(selectedItem);
if refresh then
begin
ItemDeleting(selectedItem);
ItemAdded(selectedItem);
end;
end;
end;

View File

@ -21,10 +21,14 @@ uses
Graphics,
ImgList,
Messages,
SysUtils,
Types,
Windows;
type
EInvalidItem = class(Exception);
TX2MenuBarAnimationStyle = (asNone, asSlide, asDissolve, asFade,
asSlideFade, asCustom);
@ -181,7 +185,7 @@ type
:$ Abstract action class.
:: Provides a base for menu bar actions which need to be performed
:: asynchronous and in sequence.
:: asynchronous and/or in sequence.
}
TX2CustomMenuBarAction = class(TObject)
private
@ -457,6 +461,8 @@ type
procedure CMMouseLeave(var Msg: TMessage); message CM_MOUSELEAVE;
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;
function GetMenuHeight(): Integer; virtual;
@ -593,6 +599,8 @@ type
property HideScrollbar;
property Images;
property ParentFont;
property TabOrder;
property TabStop default True;
property OnClick;
property OnCollapsed;
property OnCollapsing;
@ -628,17 +636,18 @@ const
implementation
uses
SysUtils,
X2CLGraphics,
X2CLMenuBarActions,
X2CLMenuBarAnimators;
const
SDefaultItemCaption = 'Menu Item';
SDefaultGroupCaption = 'Group';
SNoPainter = 'Painter property not set';
SInvalidItem = 'Item does not belong to this MenuBar';
type
TProtectedCollection = class(TCollection);
@ -1392,6 +1401,7 @@ begin
FGroups.OnUpdate := GroupsUpdate;
FHideScrollbar := True;
FScrollbar := True;
TabStop := True;
end;
@ -1506,6 +1516,23 @@ begin
begin
currentAction.Stop();
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
@ -1949,8 +1976,29 @@ end;
procedure TX2CustomMenuBar.PushAction(AAction: TX2CustomMenuBarAction);
var
action: TX2CustomMenuBarAction;
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();
end;
@ -1967,16 +2015,31 @@ procedure TX2CustomMenuBar.InternalSetExpanded(AGroup: TX2MenuBarGroup;
begin
AGroup.InternalSetExpanded(AExpanded);
DoExpandedChanged(AGroup);
Invalidate();
end;
procedure TX2CustomMenuBar.InternalSetSelected(AItem: TX2CustomMenuBarItem);
var
group: TX2MenuBarGroup;
begin
FSelectedItem := AItem;
DoSelectedChanged();
if Assigned(SelectedItem) and Assigned(SelectedItem.Action) then
SelectedItem.ActionLink.Execute(Self);
if Assigned(AItem) then
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;
@ -2902,33 +2965,51 @@ var
begin
if Value <> FSelectedItem then
begin
if Assigned(Value) and (Value.MenuBar <> Self) then
raise EInvalidItem.Create(SInvalidItem);
allowed := (not Assigned(Value)) or ItemEnabled(Value);
if allowed then
DoSelectedChanging(Value, allowed);
if allowed then
begin
selectItem := Value;
if selectItem is TX2MenuBarGroup then
if Assigned(selectItem) then
begin
group := TX2MenuBarGroup(selectItem);
if selectItem is TX2MenuBarGroup then
begin
group := TX2MenuBarGroup(selectItem);
{ Check if the group should be collapsed }
if group.Expanded and (not AutoCollapse) then
begin
PerformExpand(group, False);
end else
begin
if group.Items.Count > 0 then
{ Check if the group should be collapsed }
if group.Expanded and (not AutoCollapse) then
begin
PerformExpand(group, True);
PerformAutoSelectItem(group);
PerformExpand(group, False);
end else
begin
if PerformAutoCollapse(group) then
PerformSelectItem(group);
if group.Items.Count > 0 then
begin
PerformExpand(group, True);
PerformAutoSelectItem(group);
end else
begin
if PerformAutoCollapse(group) then
PerformSelectItem(group);
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
PerformSelectItem(selectItem);
@ -2936,5 +3017,15 @@ begin
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.

View File

@ -25,6 +25,7 @@ type
public
constructor Create(AMenuBar: TX2CustomMenuBar; AGroup: TX2MenuBarGroup;
AAnimator: TX2CustomMenuBarAnimator);
destructor Destroy(); override;
procedure Start(); override;
@ -111,7 +112,7 @@ implementation
uses
SysUtils;
type
TProtectedX2CustomMenuBarPainter = class(TX2CustomMenuBarPainter);
TProtectedX2CustomMenuBar = class(TX2CustomMenuBar);
@ -130,6 +131,14 @@ begin
end;
destructor TX2MenuBarAnimateAction.Destroy();
begin
FreeAndNil(FAnimator);
inherited;
end;
procedure TX2MenuBarAnimateAction.Start();
begin
inherited;
@ -340,7 +349,6 @@ begin
inherited;
TProtectedX2CustomMenuBar(MenuBar).InternalSetExpanded(FGroup, FExpanding);
MenuBar.Invalidate();
Terminate();
end;