unit tabs; interface uses objects,drivers,views; type PTabItem = ^TTabItem; TTabItem = record Next : PTabItem; View : PView; Dis : boolean; end; PTabDef = ^TTabDef; TTabDef = record Next : PTabDef; Name : PString; Items : PTabItem; DefItem : PView; ShortCut : char; end; PTab = ^TTab; TTab = object(TGroup) TabDefs : PTabDef; ActiveDef : integer; DefCount : word; constructor Init(var Bounds: TRect; ATabDef: PTabDef); function AtTab(Index: integer): PTabDef; virtual; procedure SelectTab(Index: integer); virtual; function TabCount: integer; function Valid(Command: Word): Boolean; virtual; procedure ChangeBounds(var Bounds: TRect); virtual; procedure HandleEvent(var Event: TEvent); virtual; function GetPalette: PPalette; virtual; procedure Draw; virtual; function DataSize: sw_word;virtual; procedure SetData(var Rec);virtual; procedure GetData(var Rec);virtual; procedure SetState(AState: Word; Enable: Boolean); virtual; destructor Done; virtual; private InDraw: boolean; end; function NewTabItem(AView: PView; ANext: PTabItem): PTabItem; procedure DisposeTabItem(P: PTabItem); function NewTabDef(AName: string; ADefItem: PView; AItems: PTabItem; ANext: PTabDef): PTabDef; procedure DisposeTabDef(P: PTabDef); implementation uses FvCommon,dialogs; constructor TTab.Init(var Bounds: TRect; ATabDef: PTabDef); begin inherited Init(Bounds); Options:=Options or ofSelectable or ofFirstClick or ofPreProcess or ofPostProcess; GrowMode:=gfGrowHiX+gfGrowHiY+gfGrowRel; TabDefs:=ATabDef; ActiveDef:=-1; SelectTab(0); ReDraw; end; function TTab.TabCount: integer; var i: integer; P: PTabDef; begin I:=0; P:=TabDefs; while (P<>nil) do begin Inc(I); P:=P^.Next; end; TabCount:=I; end; function TTab.AtTab(Index: integer): PTabDef; var i: integer; P: PTabDef; begin i:=0; P:=TabDefs; while (IIndex then begin if Owner<>nil then Owner^.Lock; Lock; { --- Update --- } if TabDefs<>nil then begin DefCount:=1; while AtTab(DefCount-1)^.Next<>nil do Inc(DefCount); end else DefCount:=0; if ActiveDef<>-1 then begin P:=AtTab(ActiveDef)^.Items; while P<>nil do begin if P^.View<>nil then Delete(P^.View); P:=P^.Next; end; end; ActiveDef:=Index; P:=AtTab(ActiveDef)^.Items; while P<>nil do begin if P^.View<>nil then Insert(P^.View); P:=P^.Next; end; V:=AtTab(ActiveDef)^.DefItem; if V<>nil then V^.Select; ReDraw; { --- Update --- } UnLock; if Owner<>nil then Owner^.UnLock; DrawView; end; end; procedure TTab.ChangeBounds(var Bounds: TRect); var D: TPoint; procedure DoCalcChange(P: PView); {$ifndef FPC}far;{$endif} var R: TRect; begin if P^.Owner=nil then Exit; { it think this is a bug in TV } P^.CalcBounds(R, D); P^.ChangeBounds(R); end; var P: PTabItem; I: integer; begin D.X := Bounds.B.X - Bounds.A.X - Size.X; D.Y := Bounds.B.Y - Bounds.A.Y - Size.Y; inherited ChangeBounds(Bounds); for I:=0 to TabCount-1 do if I<>ActiveDef then begin P:=AtTab(I)^.Items; while P<>nil do begin if P^.View<>nil then DoCalcChange(P^.View); P:=P^.Next; end; end; end; procedure TTab.HandleEvent(var Event: TEvent); var Index : integer; I : integer; X : integer; Len : byte; P : TPoint; V : PView; CallOrig: boolean; LastV : PView; FirstV: PView; function FirstSelectable: PView; var FV : PView; begin FV := First; while (FV<>nil) and ((FV^.Options and ofSelectable)=0) and (FV<>Last) do FV:=FV^.Next; if FV<>nil then if (FV^.Options and ofSelectable)=0 then FV:=nil; FirstSelectable:=FV; end; function LastSelectable: PView; var LV : PView; begin LV := Last; while (LV<>nil) and ((LV^.Options and ofSelectable)=0) and (LV<>First) do LV:=LV^.Prev; if LV<>nil then if (LV^.Options and ofSelectable)=0 then LV:=nil; LastSelectable:=LV; end; begin if (Event.What and evMouseDown)<>0 then begin MakeLocal(Event.Where,P); if P.Y<3 then begin Index:=-1; X:=1; for i:=0 to DefCount-1 do begin Len:=CStrLen(AtTab(i)^.Name^); if (P.X>=X) and (P.X<=X+Len+1) then Index:=i; X:=X+Len+3; end; if Index<>-1 then SelectTab(Index); end; end; if Event.What=evKeyDown then begin Index:=-1; case Event.KeyCode of kbTab,kbShiftTab : if GetState(sfSelected) then begin if Current<>nil then begin LastV:=LastSelectable; FirstV:=FirstSelectable; if ((Current=LastV) or (Current=PLabel(LastV)^.Link)) and (Event.KeyCode=kbShiftTab) then begin if Owner<>nil then Owner^.SelectNext(true); end else if ((Current=FirstV) or (Current=PLabel(FirstV)^.Link)) and (Event.KeyCode=kbTab) then begin Lock; if Owner<>nil then Owner^.SelectNext(false); UnLock; end else SelectNext(Event.KeyCode=kbShiftTab); ClearEvent(Event); end; end; else for I:=0 to DefCount-1 do begin if Upcase(GetAltChar(Event.KeyCode))=AtTab(I)^.ShortCut then begin Index:=I; ClearEvent(Event); Break; end; end; end; if Index<>-1 then begin Select; SelectTab(Index); V:=AtTab(ActiveDef)^.DefItem; if V<>nil then V^.Focus; end; end; CallOrig:=true; if Event.What=evKeyDown then begin if ((Owner<>nil) and (Owner^.Phase=phPostProcess) and (GetAltChar(Event.KeyCode)<>#0)) or GetState(sfFocused) then else CallOrig:=false; end; if CallOrig then inherited HandleEvent(Event); end; function TTab.GetPalette: PPalette; begin GetPalette:=nil; end; procedure TTab.Draw; var B : TDrawBuffer; i : integer; C1,C2,C3,C : word; HeaderLen : integer; X,X2 : integer; Name : PString; ActiveKPos : integer; ActiveVPos : integer; FC : char; procedure SWriteBuf(X,Y,W,H: integer; var Buf); var i: integer; begin if Y+H>Size.Y then H:=Size.Y-Y; if X+W>Size.X then W:=Size.X-X; if Buffer=nil then WriteBuf(X,Y,W,H,Buf) else for i:=1 to H do Move(Buf,Buffer^[X+(Y+i-1)*Size.X],W*2); end; procedure ClearBuf; begin MoveChar(B,' ',C1,Size.X); end; begin if InDraw then Exit; InDraw:=true; { - Start of TGroup.Draw - } { if Buffer = nil then begin GetBuffer; end; } { - Start of TGroup.Draw - } C1:=GetColor(1); C2:=(GetColor(7) and $f0 or $08)+GetColor(9)*256; C3:=GetColor(8)+GetColor({9}8)*256; { Calculate the size of the headers } HeaderLen:=0; for i:=0 to DefCount-1 do HeaderLen:=HeaderLen+CStrLen(AtTab(i)^.Name^)+3; Dec(HeaderLen); if HeaderLen>Size.X-2 then HeaderLen:=Size.X-2; { --- 1. sor --- } ClearBuf; MoveChar(B[0],'³',C1,1); MoveChar(B[HeaderLen+1],'³',C1,1); X:=1; for i:=0 to DefCount-1 do begin Name:=AtTab(i)^.Name; X2:=CStrLen(Name^); if i=ActiveDef then begin ActiveKPos:=X-1; ActiveVPos:=X+X2+2; if GetState(sfFocused) then C:=C3 else C:=C2; end else C:=C2; MoveCStr(B[X],' '+Name^+' ',C); X:=X+X2+3; MoveChar(B[X-1],'³',C1,1); end; SWriteBuf(0,1,Size.X,1,B); { --- 0. sor --- } ClearBuf; MoveChar(B[0],'Ú',C1,1); X:=1; for i:=0 to DefCount-1 do begin if I0 then MoveChar(B[X],'Ä',C1,X2); X:=X+X2+1; end; MoveChar(B[HeaderLen+1],'¿',C1,1); MoveChar(B[ActiveKPos],'Ú',C1,1); MoveChar(B[ActiveVPos],'¿',C1,1); SWriteBuf(0,0,Size.X,1,B); { --- 2. sor --- } MoveChar(B[1],'Ä',C1,Max(HeaderLen,0)); MoveChar(B[HeaderLen+2],'Ä',C1,Max(Size.X-HeaderLen-3,0)); MoveChar(B[Size.X-1],'¿',C1,1); MoveChar(B[ActiveKPos],'Ù',C1,1); if ActiveDef=0 then MoveChar(B[0],'³',C1,1) else MoveChar(B[0],{'Ã'}'Ú',C1,1); MoveChar(B[HeaderLen+1],'Ä'{'Á'},C1,1); MoveChar(B[ActiveVPos],'À',C1,1); MoveChar(B[ActiveKPos+1],' ',C1,Max(ActiveVPos-ActiveKPos-1,0)); SWriteBuf(0,2,Size.X,1,B); { --- marad‚k sor --- } ClearBuf; MoveChar(B[0],'³',C1,1); MoveChar(B[Size.X-1],'³',C1,1); {SWriteBuf(0,3,Size.X,Size.Y-4,B);} for i:=3 to Size.Y-1 do SWriteBuf(0,i,Size.X,1,B); { --- Size.X . sor --- } MoveChar(B[0],'À',C1,1); MoveChar(B[1],'Ä',C1,Max(Size.X-2,0)); MoveChar(B[Size.X-1],'Ù',C1,1); SWriteBuf(0,Size.Y-1,Size.X,1,B); { - End of TGroup.Draw - } if Buffer <> nil then begin Lock; Redraw; UnLock; end; if Buffer <> nil then WriteBuf(0, 0, Size.X, Size.Y, Buffer^) else Redraw; { - End of TGroup.Draw - } InDraw:=false; end; function TTab.Valid(Command: Word): Boolean; var PT : PTabDef; PI : PTabItem; OK : boolean; begin OK:=true; PT:=TabDefs; while (PT<>nil) and (OK=true) do begin PI:=PT^.Items; while (PI<>nil) and (OK=true) do begin if PI^.View<>nil then OK:=OK and PI^.View^.Valid(Command); PI:=PI^.Next; end; PT:=PT^.Next; end; Valid:=OK; end; procedure TTab.SetData(var Rec); type Bytes = array[0..65534] of Byte; var I: Sw_Word; PT : PTabDef; PI : PTabItem; begin I := 0; PT:=TabDefs; while (PT<>nil) do begin PI:=PT^.Items; while (PI<>nil) do begin if PI^.View<>nil then begin PI^.View^.SetData(Bytes(Rec)[I]); Inc(I, PI^.View^.DataSize); end; PI:=PI^.Next; end; PT:=PT^.Next; end; end; function TTab.DataSize: sw_word; var I: Sw_Word; PT : PTabDef; PI : PTabItem; begin I := 0; PT:=TabDefs; while (PT<>nil) do begin PI:=PT^.Items; while (PI<>nil) do begin if PI^.View<>nil then begin Inc(I, PI^.View^.DataSize); end; PI:=PI^.Next; end; PT:=PT^.Next; end; DataSize:=i; end; procedure TTab.GetData(var Rec); type Bytes = array[0..65534] of Byte; var I: Sw_Word; PT : PTabDef; PI : PTabItem; begin I := 0; PT:=TabDefs; while (PT<>nil) do begin PI:=PT^.Items; while (PI<>nil) do begin if PI^.View<>nil then begin PI^.View^.GetData(Bytes(Rec)[I]); Inc(I, PI^.View^.DataSize); end; PI:=PI^.Next; end; PT:=PT^.Next; end; end; procedure TTab.SetState(AState: Word; Enable: Boolean); begin inherited SetState(AState,Enable); if (AState and sfFocused)<>0 then DrawView; end; destructor TTab.Done; var P,X: PTabDef; procedure DeleteViews(P: PView); {$ifndef FPC}far;{$endif} begin if P<>nil then Delete(P); end; begin ForEach(@DeleteViews); inherited Done; P:=TabDefs; while P<>nil do begin X:=P^.Next; DisposeTabDef(P); P:=X; end; end; function NewTabItem(AView: PView; ANext: PTabItem): PTabItem; var P: PTabItem; begin New(P); FillChar(P^,SizeOf(P^),0); P^.Next:=ANext; P^.View:=AView; NewTabItem:=P; end; procedure DisposeTabItem(P: PTabItem); begin if P<>nil then begin if P^.View<>nil then Dispose(P^.View, Done); Dispose(P); end; end; function NewTabDef(AName: string; ADefItem: PView; AItems: PTabItem; ANext: PTabDef): PTabDef; var P: PTabDef; x: byte; begin New(P); P^.Next:=ANext; P^.Name:=NewStr(AName); P^.Items:=AItems; x:=pos('~',AName); if (x<>0) and (xnil do begin X:=PI^.Next; DisposeTabItem(PI); PI:=X; end; Dispose(P); end; end.