返回
{***************************************************************}
{*** FVision Unit Version1.0 ***}
{*** 蓝蚂蚁工作室 ***}
{***************************************************************}
{*** 菜单单元 ***}
{***************************************************************}
{$O+,F+,X+,I-}
Unit FMenu;
Interface
Uses
Graph,FGraph,FEvent,FMouse,FView,FWrite;
Const
slBroad = $0001;
slSaveBack = $0002;
slSetActive = $0004;
Const
MenuMoveActive:Boolean=False;
StatusLineActive:Boolean=False;
Type
MenuStr=string[30];
PMenu=^TMenu;
Subm=record
Ms:MenuStr;
Mk:Word;
Mc:Word;
Mr:TRect;
Sub:PMenu;
end;
SubMenu=array[0..15] of Subm;
PMenuItem=^TMenuItem;
TMenuItem=record
Ms:MenuStr;
Mk:Word;
Mc:Word;
Sub:PMenu;
Next:PMenuItem;
end;
TMenu=object(TView)
OwnerIndex:Integer;
Pot:TPoint;
Len,Num,Pos:Integer;
Mm:SubMenu;
FRect:TRect;
Img:Pointer;
ImgSize:Word;
MenuActive:Boolean;
Constructor Init(AMenu:PMenuItem);
Destructor Done;virtual;
Procedure Insert(S:MenuStr;K,C:Word;Sub:PMenu);virtual;
Procedure MoveTo(X,Y:Integer);virtual;
Procedure Paint;virtual;
Procedure DrawMark;
Procedure UnActive;virtual;
Procedure ChangeMark(N,Dlt:Integer);
Procedure HotKeyEvent(var Event:TEvent);
Procedure RunSubMenu(var Event:TEvent);
Procedure HandleEvent(var Event:TEvent);virtual;
Procedure Run(var Event:TEvent);virtual;
end;
PMainMenu=^TMainMenu;
TMainMenu=object(TMenu)
SysRect:TRect;
SysFlag:Boolean;
NowX:Integer;
Constructor Init(R:TRect;Sf:Boolean;AMenu:PMenuItem);
Procedure Insert(S:MenuStr;K,C:Word;Sub:PMenu);virtual;
Procedure SetBroad(R:TRect);virtual;
Procedure MoveTo(X,Y:Integer);virtual;
Procedure Paint;virtual;
Procedure LeftMenu(var Event:TEvent);
Procedure RightMenu(var Event:TEvent);
Procedure HandleMainMenu(var Event:TEvent);virtual;
Procedure HandleEvent(var Event:TEvent);virtual;
end;
PStatusLine=^TStatusLine;
TStatusLine=object(TView)
Style:Word;
BakImg:Pointer;
BakSize:Word;
Str:string;
Constructor Init(R:TRect;Sty:Word;S:string);
Destructor Done;virtual;
Procedure Paint;virtual;
Procedure Hide;virtual;
Procedure Show;virtual;
Procedure Modify(S:string);
Procedure SwapLine(var S:string);
end;
var
StatusLine:PStatusLine;
Function NewMenuItem(S:MenuStr;K,C:Word;Sub:PMenu;Next:PMenuItem):PMenuItem;
Function NewSubMenu(S:MenuStr;K:Word;Sub:PMenu;Next:PMenuItem):PMenuItem;
Implementation
Function NewMenuItem(S:MenuStr;K,C:Word;Sub:PMenu;Next:PMenuItem):PMenuItem;
var
P:PMenuItem;
begin
New(P);
P^.Ms:=S;
P^.Mk:=K;
P^.Mc:=C;
P^.Sub:=Sub;
P^.Next:=Next;
NewMenuItem:=P;
end;
Function NewSubMenu(S:MenuStr;K:Word;Sub:PMenu;Next:PMenuItem):PMenuItem;
var
P:PMenuItem;
begin
New(P);
P^.Ms:=S;
P^.Mk:=K;
P^.Mc:=0;
P^.Sub:=Sub;
P^.Next:=Next;
NewSubMenu:=P;
end;
Constructor TMenu.Init;
var
Temp:PMenuItem;
begin
Inherited Init;
AssignRect(FRect,0,0,0,0);
Len:=70;
Num:=0;
MoveTo(0,0);
MenuActive:=False;
Pos:=0;
while AMenu<>nil do
begin
Insert(AMenu^.Ms,AMenu^.Mk,AMenu^.Mc,AMenu^.Sub);
Temp:=AMenu;
AMenu:=AMenu^.Next;
Dispose(Temp);
end;
end;
Destructor TMenu.Done;
var
i:Integer;
begin
for i:=0 to Num-1 do
if Mm[i].Sub<>nil then
Dispose(Mm[i].Sub,Done);
Inherited Done;
end;
Procedure TMenu.Insert;
begin
if Len<GetcLen(S)*8+20 then
Len:=GetcLen(S)*8+20;
Mm[Num].Ms:=S;
Mm[Num].Mk:=K;
Mm[Num].Mc:=C;
Mm[Num].Sub:=Sub;
if Sub<>nil then
begin
Sub^.Owner:=@Self;
Sub^.OwnerIndex:=Num;
end;
Inc(Num);
Broad.b.x:=Broad.a.x+Len;
Broad.b.y:=Broad.a.y+Num*18+12;
end;
Procedure TMenu.MoveTo(X,Y:Integer);
begin
if X+Len>GetMaxx then
X:=GetMaxx-Len;
if Y+Num*18+12>GetMaxy then
Y:=GetMaxy-Num*18-12;
Origin.x:=X;
Origin.y:=Y;
AssignRect(Broad,X,Y,X+Len,Y+Num*18+12);
Pot.x:=X+10;
Pot.y:=Y+6;
end;
Procedure TMenu.Paint;
var
i:Integer;
begin
if Num<=0 then Exit;
if Owner<>nil then
begin
if TypeOf(Owner^)=TypeOf(TMenu) then
MoveTo(PMenu(Owner)^.Broad.b.x+1,PMenu(Owner)^.Mm[OwnerIndex].Mr.a.y-6)
else if TypeOf(Owner^)=TypeOf(TMainMenu) then
MoveTo(PMainMenu(Owner)^.Mm[OwnerIndex].Mr.a.x,PMainMenu(Owner)^.Broad.b.y+1);
end;
HideMouse;
Img:=SaveImage(Broad.a.x,Broad.a.y,Broad.b.x+10,Broad.b.y+10,ImgSize);
DrawBroad(Broad.a.x,Broad.a.y,Broad.b.x,Broad.b.y,1);
DrawShadow(Broad.a.x,Broad.a.y,Broad.b.x,Broad.b.y,10);
for i:=0 to Num-1 do
begin
if Mm[i].Ms='' then
DoubleLine(Broad.a.x+5,Pot.y+i*18+7,Broad.b.x-5,Pot.y+i*18+7)
else
WritecStr(Pot.x,Pot.y+i*18,Mm[i].Ms,$00,$04);
if Mm[i].Sub<>nil then
Writecs(Broad.b.x-9,Pot.y+i*18+1,#16,4);
AssignRect(Mm[i].Mr,Broad.a.x+10,Pot.y+i*18,Broad.b.x-10,Pot.y+(i+1)*18);
end;
ShowMouse;
DrawMark;
MenuActive:=True;
if Owner<>nil then
FRect:=PMenu(Owner)^.Mm[OwnerIndex].Mr;
end;
Procedure TMenu.DrawMark;
var
i:Integer;
begin
if MouIn(Broad) then HideMouse;
SetWriteMode(1);
SetColor(7);
PutPixel(0,0,0);
for i:=0 to 15 do
Line(Broad.a.x+10,Pot.y+Pos*18+i,Broad.b.x-10,Pot.y+Pos*18+i);
SetWriteMode(0);
ShowMouse;
end;
Procedure TMenu.UnActive;
begin
if not MenuActive then Exit;
HideMouse;
PutImage(Broad.a.x,Broad.a.y,Img^,Copyput);
FreeMem(Img,ImgSize);
ShowMouse;
MenuActive:=False;
end;
Procedure TMenu.ChangeMark;
begin
if Pos=N then Exit;
DrawMark;
Pos:=N;
if Pos>=Num then Pos:=0;
if Pos<0 then Pos:=Num-1;
if Mm[Pos].Ms='' then
Inc(Pos,Dlt);
DrawMark;
end;
Procedure TMenu.HotKeyEvent;
var
i:Integer;
begin
if Event.What<>evKeyDown then Exit;
for i:=0 to Num-1 do
if (Event.KeyCode<>kbNoKey) and (Event.KeyCode=Mm[i].Mk) then
begin
if Mm[i].Sub<>nil then
begin
Pos:=i;
RunSubMenu(Event);
end else
begin
Event.What:=evCommand;
Event.Command:=Mm[i].Mc;
Pos:=i;
UnActive;
end;
Exit;
end else
if Mm[i].Sub<>nil then
Mm[i].Sub^.HotKeyEvent(Event);
end;
Procedure TMenu.RunSubMenu;
begin
Mm[Pos].Sub^.Run(Event);
if Event.What=evCommand then
UnActive;
end;
Procedure TMenu.HandleEvent;
var
i:Integer;
begin
HotKeyEvent(Event);
if not MenuActive then Exit;
case Event.What of
evCommand:UnActive;
evKeyDown :case Event.KeyCode of
kbUp : ChangeMark(Pos-1,-1);
kbDown:ChangeMark(Pos+1,1);
kbLeft:begin
Event.What:=evCommand;
Event.Command:=cmLeftMenu;
UnActive;
end;
kbRight:begin
Event.What:=evCommand;
Event.Command:=cmRightMenu;
UnActive;
end;
kbEnter:begin
if Mm[Pos].Sub<>nil then
RunSubMenu(Event)
else begin
Event.What:=evCommand;
Event.Command:=Mm[Pos].mc;
UnActive;
end;
end;
kbEsc:begin
ClearEvent(Event);
UnActive;
end;
end;
evMouseDown:if not IsIn(Event.Where,Broad) then
UnActive
else
for i:=0 to Num-1 do
if IsIn(Event.Where,Mm[i].Mr)and(Mm[i].Ms<>'') then
ChangeMark(i,0);
evMouseUp: if (not IsIn(Event.Where,Broad))and(not IsIn(Event.Where,FRect)) then
UnActive
else
for i:=0 to Num-1 do
if IsIn(Event.Where,Mm[i].Mr)and(Mm[i].Ms<>'') then
begin
ChangeMark(i,0);
if Mm[Pos].Sub<>nil then
RunSubMenu(Event)
else begin
Event.What:=evCommand;
Event.Command:=Mm[i].Mc;
UnActive;
Exit;
end;
end;
evMouseMove:begin
for i:=0 to Num-1 do
if IsIn(Event.Where,Mm[i].Mr)and(Mm[i].Ms<>'') then
ChangeMark(i,0);
if Owner<>nil then
if (Event.Buttons=mbLeftButton) and
IsIn(Event.Where,PMenu(Owner)^.Broad) and
(not IsIn(Event.Where,FRect)) then
UnActive;
end;
end;
end;
Procedure TMenu.Run;
begin
Paint;
repeat
ClearEvent(Event);
GetEvent(Event);
HandleEvent(Event);
until not MenuActive;
end;
Constructor TMainMenu.Init;
var
Temp:PMenuItem;
begin
Inherited Init(nil);
Option:=Option or opFirstPros;
GrowMode:=gfGrowHiX;
Size.x:=R.b.x-R.a.x;
Size.y:=R.b.y-R.a.y;
MoveTo(R.a.x,R.a.y);
SysFlag:=Sf;
NowX:=2;
if SysFlag then NowX:=16;
while AMenu<>nil do
begin
Insert(AMenu^.Ms,AMenu^.Mk,AMenu^.Mc,AMenu^.Sub);
Temp:=AMenu;
AMenu:=AMenu^.Next;
Dispose(Temp);
end;
end;
Procedure TMainMenu.Insert;
begin
Mm[Num].Ms:=S;
Mm[Num].Mk:=K;
Mm[Num].Mc:=C;
Mm[Num].Sub:=Sub;
AssignRect(Mm[Num].Mr,Broad.a.x+NowX,Broad.a.y,
Broad.a.x+NowX+GetcLen(Mm[Num].Ms)*8,Broad.b.y);
Inc(NowX,(GetcLen(Mm[Num].Ms)+2)*8);
if Sub<>nil then
begin
Sub^.Owner:=@Self;
Sub^.OwnerIndex:=Num;
end;
Inc(Num);
end;
Procedure TMainMenu.SetBroad;
begin
Size.x:=R.b.x-R.a.x;
Size.y:=R.b.y-R.a.y;
MoveTo(R.a.x,R.a.y);
end;
Procedure TMainMenu.MoveTo;
var
i,Temp:Integer;
begin
Origin.x:=X;
Origin.y:=Y;
AssignRect(Broad,x,y,x+Size.x,y+Size.y);
AssignRect(SysRect,x+3,y+3,x+14,y+14);
Temp:=2;
if SysFlag then Temp:=16;
for i:=0 to Num-1 do
begin
AssignRect(Mm[i].Mr,Broad.a.x+Temp,Broad.a.y,
Broad.a.x+Temp+GetcLen(Mm[i].Ms)*8,Broad.b.y);
Inc(Temp,(GetcLen(Mm[i].Ms)+2)*8);
end;
end;
Procedure TMainMenu.Paint;
var
i:Integer;
begin
HideMouse;
SignBroad(Broad.a.x,Broad.a.y,Broad.b.x,Broad.b.y,1);
if SysFlag then
begin
SignBroadc(SysRect.a.x,SysRect.a.y,SysRect.b.x,SysRect.b.y,0,15);
SetColor(4);
Line(SysRect.a.x+1,SysRect.a.y+1,SysRect.b.x-1,SysRect.b.y-1);
Line(SysRect.b.x-1,SysRect.a.y+1,SysRect.a.x+1,SysRect.b.y-1);
end;
for i:=0 to Num-1 do
WritecStr(Mm[i].Mr.a.x,Mm[i].Mr.a.y+1,Mm[i].Ms,$00,$04);
ShowMouse;
end;
Procedure TMainMenu.LeftMenu;
begin
Dec(Pos);
if Pos<0 then Pos:=Num-1;
RunSubMenu(Event);
end;
Procedure TMainMenu.RightMenu;
begin
Inc(Pos);
if Pos>=Num then Pos:=0;
RunSubMenu(Event);
end;
Procedure TMainMenu.HandleMainMenu;
label Start;
var
i:Integer;
begin
Start:
HotKeyEvent(Event);
case Event.What of
evMouseUp: if SysFlag and IsIn(Event.Where,SysRect)and(Event.Buttons=mbLeftButton) then
begin
Event.What:=evCommand;
Event.Command:=cmQuit;
end;
evMouseDown,evMouseMove:
begin
if (not MenuMoveActive)and(Event.Buttons=0) then Exit;
for i:=0 to Num-1 do
if IsIn(Event.Where,Mm[i].Mr) then
begin
Pos:=i;
RunSubMenu(Event);
goto Start;
end;
end;
end;
end;
Procedure TMainMenu.HandleEvent;
label Start;
var
i:Integer;
begin
repeat
Start:
HandleMainMenu(Event);
if Event.What=evCommand then
case Event.Command of
cmLeftMenu:begin LeftMenu(Event);goto Start; end;
cmRightMenu:begin RightMenu(Event);goto Start; end;
else for i:=0 to Num-1 do
if (Event.Command<>0)and(Event.Command=Mm[i].Mc) then
begin
if Mm[i].Sub<>nil then
Mm[i].Sub^.Run(Event);
goto Start;
end;
end;
until (Event.What<>evCommand)or(not (Event.Command in [cmLeftMenu,cmRightMenu]));
for i:=0 to Num-1 do
if Mm[i].Sub<>nil then
Mm[i].Sub^.HandleEvent(Event);
end;
constructor TStatusLine.Init;
begin
Inherited Init;
GrowMode:=gfGrowHiX+gfGrowLoY+gfGrowHiY;
Style:=Sty;
Size.X:=R.B.X-R.A.X;
Size.Y:=R.B.Y-R.A.Y;
MoveTo(R.A.X,R.A.Y);
Str:=S;
BakImg:=nil;
end;
destructor TStatusLine.Done;
begin
Hide;
Inherited Done;
end;
Procedure TStatusLine.Paint;
var
Rec:TRect;
i,Temp:Integer;
TempStr:string;
ErrorFlag:Boolean;
begin
if Length(Str)=0 then
begin
Hide;
Exit;
end;
HideMouse;
if (BakImg=nil)and((Style and slSaveBack)<>0) then
BakImg:=SaveImage(Broad.a.x,Broad.a.y,Broad.b.x,Broad.b.y,BakSize);
if (Style and slBroad)<>0 then
SignBroad(Broad.a.x,Broad.a.y,Broad.b.x,Broad.b.y,1)
else
Full(Broad.a.x+2,Broad.a.y+2,Broad.b.x-2,Broad.b.y-2,7);
Temp:=5;
TempStr:='';
ErrorFlag:=False;
for i:=1 to Length(Str) do
if (Str[i]=#1) then
ErrorFlag:=True
else if (i=Length(Str))or(Str[i]=#0) then
begin
if (i=Length(Str))and(Str[i]<>#0) then
TempStr:=TempStr+Str[i];
AssignRect(Rec,Broad.a.x+Temp,Broad.a.y+3,
Broad.a.x+Temp+GetcLen(TempStr)*8+4,Broad.b.y-3);
if (i=Length(Str))and(Str[i]=#0) then
Rec.b.x:=Broad.b.x-5;
if ErrorFlag then
begin
SignBroadc(Rec.a.x,Rec.a.y,Rec.b.x,Rec.b.y,0,4);
WritecStr(Rec.a.x+2,Rec.a.y,TempStr,$F,$E);
end else
begin
SignBroad(Rec.a.x,Rec.a.y,Rec.b.x,Rec.b.y,0);
WritecStr(Rec.a.x+2,Rec.a.y,TempStr,$0,$4);
end;
Inc(Temp,GetcLen(TempStr)*8+10);
TempStr:='';
end else
TempStr:=TempStr+Str[i];
ShowMouse;
if (Style and slSetActive)<>0 then
StatusLineActive:=True;
end;
Procedure TStatusLine.Hide;
begin
if BakImg=nil then Exit;
HideMouse;
PutImage(Broad.a.x,Broad.a.y,BakImg^,CopyPut);
ShowMouse;
FreeMem(BakImg,BakSize);
BakImg:=nil;
if (Style and slSetActive)<>0 then
StatusLineActive:=False;
end;
Procedure TStatusLine.Show;
begin
Paint;
end;
Procedure TStatusLine.Modify;
begin
if Str=S then Exit;
Str:=S;
Paint;
end;
Procedure TStatusLine.SwapLine;
var
TempStr:string;
begin
if Str=S then Exit;
TempStr:=S;
S:=Str;
Str:=TempStr;
Paint;
end;
end.