home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 14 / CDACTUAL.iso / cdactual / demobin / share / program / Pascal / TVDMX.ZIP / TVDMX.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1993-04-09  |  74.9 KB  |  3,009 lines

  1.  
  2. {■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■}
  3. {                            }
  4. {    tvDMX    --data editing project (ver 2.x)    }
  5. {                            }
  6. {    Copyright (c) 1992,93   Randolph Beck        }
  7. {                P.O. Box  56-0487    }
  8. {                Orlando, FL 32856    }
  9. {                CIS:  72361,753        }
  10. {                            }
  11. {■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■}
  12.  
  13. Unit tvDMX;
  14.  
  15. {$B-,D+,O+,R-,V-,X+ }
  16.  
  17. interface
  18.  
  19. uses  Objects, Drivers, Views, Dialogs, App, RSet, DmxGizma;
  20.  
  21. type
  22.     PDmxLink       = ^TDmxLink;
  23.     PDmxLabels       = ^TDmxLabels;
  24.     PDmxExtLabels  = ^TDmxExtLabels;
  25.     PDmxFLabels    = ^TDmxFLabels;
  26.     PDmxMLabels    = ^TDmxMLabels;
  27.     PDmxScroller   = ^TDmxScroller;
  28.     PDmxRecInd       = ^TDmxRecInd;
  29.     PDmxEditor       = ^TDmxEditor;
  30.  
  31.  
  32.     TDmxLink    =  OBJECT (TView)
  33.     Link    : PDmxScroller;
  34.       constructor Init (var Bounds : TRect);
  35.       constructor Load (var S : TStream);
  36.       function  GetPalette : PPalette;  VIRTUAL;
  37.       procedure Insert (AOwner : PGroup);
  38.       procedure Store (var S : TStream);
  39.       procedure SetState (AState : word;  Enable : boolean);  VIRTUAL;
  40.     end;
  41.  
  42.  
  43.     TDmxExtLabels  =  OBJECT (TDmxLink)
  44.     Len    : integer;
  45.     Data    : PCharArray;
  46.     Heaped    : boolean;
  47.     DblBar    : boolean;
  48.       constructor Init (ALen : integer; AData : PCharArray; var Bounds : TRect);
  49.       constructor InitInsert (AOwner : PGroup; ALen : integer; AData : PCharArray);
  50.       destructor  Done;  VIRTUAL;
  51.       constructor Load (var S : TStream);
  52.       procedure Store (var S : TStream);
  53.       procedure Draw;  VIRTUAL;
  54.       procedure DrawRuler (Upper, AtLimit : boolean);
  55.       procedure HandleEvent (var Event : TEvent);  VIRTUAL;
  56.       procedure SetState (AState : word;  Enable : boolean);  VIRTUAL;
  57.     end;
  58.  
  59.  
  60.     TDmxLabels    =  OBJECT (TDmxExtLabels)
  61.       constructor Init (DataStr : pstring; var Bounds : TRect);
  62.       constructor InitInsert (AOwner : PGroup;  DataStr : pstring);
  63.     end;
  64.  
  65.  
  66.     TDmxFLabels  =  OBJECT (TDmxExtLabels)
  67.       constructor Init (LabelStr : string;  var Bounds : TRect);
  68.       constructor InitInsert (AOwner : PGroup;  LabelStr : string);
  69.     end;
  70.  
  71.  
  72.     TDmxMLabels  =  OBJECT (TDmxExtLabels)
  73.       constructor Init (Labels : PSItem;  var Bounds : TRect);
  74.       constructor InitInsert (AOwner : PGroup;  Labels : PSItem);
  75.     end;
  76.  
  77.  
  78.     TDmxScroller =  OBJECT (TScroller)
  79.     Labels        : PDmxLink;
  80.     WorkingData    : pointer;
  81.     DataBlockSize    : longint;
  82.     CurrentRecord    : integer;
  83.     CurrentField    : pDMXfieldrec;
  84.     DMXfield1    : pDMXfieldrec;
  85.     LeftField    : pDMXfieldrec;
  86.     TotalFields    : integer;
  87.     RecordSize    : integer;
  88.     Locked        : boolean;
  89.     InitValid    : boolean;
  90.       constructor Init (ATemplate : string; var AData; BSize : longint;
  91.         var Bounds : TRect;  ALabels : PView;  AHScrollBar,AVScrollBar : PScrollBar);
  92.       procedure   InitStruct (var ATemplate );  VIRTUAL;
  93.       procedure   InitData (var AData );  VIRTUAL;
  94.       destructor  Done;  VIRTUAL;
  95.       constructor Load (var S : TStream);
  96.       procedure Store (var S : TStream);
  97.       procedure ChangeBounds (var Bounds : TRect);  VIRTUAL;
  98.       function  DataAt (RecNum : integer)  : pointer;  VIRTUAL;
  99.       procedure DoneData;  VIRTUAL;
  100.       procedure DoneStruct;  VIRTUAL;
  101.       procedure Draw;  VIRTUAL;
  102.       procedure DrawRecord (Y : integer;  var DataRecord );
  103.       procedure FieldText (var S : string;  var Color : word;
  104.                Field : pDMXfieldrec;  var DataRec );  VIRTUAL;
  105.       procedure GetData (var Rec );  VIRTUAL;
  106.       function  GetPalette  : PPalette;  VIRTUAL;
  107.       procedure HandleEvent (var Event : TEvent);  VIRTUAL;
  108.       procedure LoadData (var S : TStream);  VIRTUAL;
  109.       procedure LoadStruct (var S : TStream);  VIRTUAL;
  110.       function  RecNumStr (RecNum : integer) : string;  VIRTUAL;
  111.       function  RecordLimit : longint;  VIRTUAL;
  112.       procedure ScrollDraw;  VIRTUAL;
  113.       procedure SetData (var Rec );  VIRTUAL;
  114.       procedure SetState (AState : word;  Enable : boolean);  VIRTUAL;
  115.       procedure StoreData (var S : TStream);  VIRTUAL;
  116.       procedure StoreStruct (var S : TStream);  VIRTUAL;
  117.       function  Valid (Command : word)  : boolean;  VIRTUAL;
  118.       procedure WrongKeypressed (var Event : TEvent);  VIRTUAL;
  119.       private
  120.     InBuffer    : boolean;
  121.     DDelta,DSize    : TPoint;
  122.     end;
  123.  
  124.  
  125.     TDmxRecInd   =  OBJECT (TDmxLink)
  126.       constructor Init (var Bounds : TRect;  Len : integer);
  127.       constructor InitInsert (AOwner : PGroup; Len : integer);
  128.       procedure Draw;  VIRTUAL;
  129.       procedure SetState (AState : word; Enable : boolean);  VIRTUAL;
  130.       procedure HandleEvent (var Event : TEvent);  VIRTUAL;
  131.     end;
  132.  
  133.  
  134.     TDmxEditor   =  OBJECT (TDmxScroller)
  135.     RecInd        : PDmxLink;
  136.     FieldData    : pointer;
  137.     RecordData    : pointer;
  138.     CurPos        : integer;
  139.     Vidis        : boolean;
  140.     DoubleValid    : boolean;
  141.     FirstKey    : boolean;
  142.     RedrawRecord    : boolean;
  143.     FieldAltered    : boolean;
  144.     RecordAltered    : boolean;
  145.     JustAltered    : boolean;
  146.     DataAltered    : boolean;
  147.     FieldSelected    : boolean;
  148.     RecordSelected    : boolean;
  149.     RecWasLocked    : boolean;
  150.     LockChecked    : boolean;
  151.     ShowFmt        : showset;
  152.       constructor Init (ATemplate  : string;  var AData; BSize : longint;
  153.             var Bounds : TRect;  ALabels,ARecInd  : PDmxLink;
  154.             AHScrollBar,AVScrollBar : PScrollBar);
  155.       constructor Load (var S : TStream);
  156.       destructor  Done;  VIRTUAL;
  157.       procedure Store (var S : TStream);
  158.       procedure ChangeBounds (var Bounds : TRect);  VIRTUAL;
  159.       procedure ChangeMade;
  160.       function  CheckRecLock : boolean;
  161.       procedure ClearRecLock;
  162.       procedure Draw;  VIRTUAL;
  163.       procedure DrawField (var Field : pDMXfieldrec);
  164.       procedure EvaluateField;  VIRTUAL;
  165.       procedure EvaluateRecord;  VIRTUAL;
  166.       procedure GetBlob (Num : integer; var Blob : pointer; var Len : integer);
  167.       procedure GotoPos (AFieldNum,ARecNum : integer);
  168.       procedure HandleEvent (var Event : TEvent);  VIRTUAL;
  169.       procedure ProcessCommand (var Command : word;  XY  : TPoint);
  170.       procedure ProcessKey (var Event : TEvent);
  171.       procedure ProcessMouse (var Event : TEvent);
  172.       procedure ResetRecLock;  VIRTUAL;
  173.       function  SetRecLock : boolean;  VIRTUAL;
  174.       procedure SetState (AState : word;  Enable : boolean);  VIRTUAL;
  175.       procedure SetUpField;  VIRTUAL;
  176.       procedure SetUpRecord;  VIRTUAL;
  177.       function  Valid (Command : word)  : boolean;  VIRTUAL;
  178.       procedure ZeroizeField (Whole : boolean; Field : pDMXfieldrec);  VIRTUAL;
  179.       procedure ZeroizeRecord;  VIRTUAL;
  180.       private
  181.     FirstPos    : integer;
  182.       procedure ProcessEnter (var Event : TEvent);
  183.     end;
  184.  
  185.  
  186. const
  187.     RDmxExtLabels :  TStreamRec = (
  188.     ObjType:  rnDmxExtLabels;
  189.     VmtLink:  ofs (TypeOf (TDmxExtLabels)^);
  190.     Load:     @TDmxExtLabels.Load;
  191.     Store:    @TDmxExtLabels.Store
  192.       );
  193.  
  194.     RDmxLabels    :  TStreamRec = (
  195.     ObjType:  rnDmxLabels;
  196.     VmtLink:  ofs (TypeOf (TDmxLabels)^);
  197.     Load:     @TDmxLabels.Load;
  198.     Store:    @TDmxLabels.Store
  199.       );
  200.  
  201.     RDmxFLabels    :  TStreamRec = (
  202.     ObjType:  rnDmxFLabels;
  203.     VmtLink:  ofs (TypeOf (TDmxFLabels)^);
  204.     Load:     @TDmxFLabels.Load;
  205.     Store:    @TDmxFLabels.Store
  206.       );
  207.  
  208.     RDmxMLabels    :  TStreamRec = (
  209.     ObjType:  rnDmxMLabels;
  210.     VmtLink:  ofs (TypeOf (TDmxMLabels)^);
  211.     Load:     @TDmxMLabels.Load;
  212.     Store:    @TDmxMLabels.Store
  213.       );
  214.  
  215.     RDmxRecInd    :  TStreamRec = (
  216.     ObjType:  rnDmxRecInd;
  217.     VmtLink:  ofs (TypeOf (TDmxRecInd)^);
  218.     Load:     @TDmxRecInd.Load;
  219.     Store:    @TDmxRecInd.Store
  220.       );
  221.  
  222.     RDmxScroller :  TStreamRec = (
  223.     ObjType:  rnDmxScroller;
  224.     VmtLink:  ofs (TypeOf (TDmxScroller)^);
  225.     Load:     @TDmxScroller.Load;
  226.     Store:    @TDmxScroller.Store
  227.       );
  228.  
  229.     RDmxEditor    :  TStreamRec = (
  230.     ObjType:  rnDmxEditor;
  231.     VmtLink:  ofs (TypeOf (TDmxEditor)^);
  232.     Load:     @TDmxEditor.Load;
  233.     Store:    @TDmxEditor.Store
  234.       );
  235.  
  236.  
  237.   procedure RegisterTVDMX;
  238.  
  239.  
  240. implementation
  241.  
  242. const    NewestDMX    : PDmxScroller    = nil;
  243.     NowScrolling    : boolean    = FALSE;
  244.  
  245. var    FirstField    : pDMXfieldrec;
  246.  
  247.  
  248.   { ══ TDmxLink ══════════════════════════════════════════════════════════ }
  249.  
  250.  
  251. constructor TDmxLink.Init (var Bounds : TRect);
  252. begin
  253.   TView.Init (Bounds);
  254.   GrowMode  := gfGrowLoY or gfGrowHiY;
  255.   EventMask := evMessage or evMouseDown;
  256.   NewestDMX := Link;
  257. end;
  258.  
  259.  
  260. constructor TDmxLink.Load (var S : TStream);
  261. begin
  262.   TView.Load (S);
  263.   GetPeerViewPtr (S, Link);
  264. end;
  265.  
  266.  
  267. function  TDmxLink.GetPalette : PPalette;
  268. const  P : string [length (cDMX)] = cDMX;
  269. begin
  270.   GetPalette := @P
  271. end;
  272.  
  273.  
  274. procedure TDmxLink.Insert (AOwner : PGroup);
  275. begin
  276.   If (AOwner <> nil) then AOwner^.Insert (@Self);
  277. end;
  278.  
  279.  
  280. procedure TDmxLink.SetState (AState : word; Enable : boolean);
  281. begin
  282.   TView.SetState (AState, Enable);
  283.   If Enable and (AState and sfExposed <> 0) then
  284.     begin
  285.     If (Link = nil) then Link := Message (Owner, evCommand, cmDMX_RollCall, @Self);
  286.     If (Link <> nil) and (Link^.State and sfExposed = 0) then
  287.       begin
  288.       Link^.PutInFrontOf (@Self);
  289.       Link^.SetState (sfExposed, TRUE);
  290.       end;
  291.     end;
  292. end;
  293.  
  294.  
  295. procedure TDmxLink.Store (var S : TStream);
  296. begin
  297.   TView.Store (S);
  298.   PutPeerViewPtr (S, Link);
  299. end;
  300.  
  301.  
  302.   { ══ TDmxExtLabels ═════════════════════════════════════════════════════ }
  303.  
  304. const  Clicked : PDmxLink = nil;
  305.  
  306.  
  307. constructor TDmxExtLabels.Init (ALen : integer; AData : PCharArray; var Bounds : TRect);
  308. begin
  309.   TDmxLink.Init (Bounds);
  310.   Data    := AData;
  311.   Len    := ALen;
  312. end;
  313.  
  314.  
  315. constructor TDmxExtLabels.InitInsert (AOwner : PGroup; ALen : integer; AData : PCharArray);
  316. var  R : TRect;
  317. begin
  318.   AOwner^.GetExtent (R);
  319.   Inc (R.A.Y);
  320.   R.B.Y  := R.A.Y + 2;
  321.   R.Grow (-1, 0);
  322.   TDmxLink.Init (R);
  323.   Data := AData;
  324.   Len  := ALen;
  325.   Insert (AOwner);
  326. end;
  327.  
  328.  
  329. destructor TDmxExtLabels.Done;
  330. begin
  331.   If Heaped and (Data <> nil) and (Len > 0) then FreeMem (Data, Len);
  332.   TDmxLink.Done;
  333. end;
  334.  
  335.  
  336. constructor TDmxExtLabels.Load (var S : TStream);
  337. begin
  338.   TDmxLink.Load (S);
  339.   S.Read (Len, sizeof (Len));
  340.   If Len > 0 then
  341.     begin
  342.     GetMem (Data, Len);
  343.     S.Read (Data^, Len);
  344.     Heaped := TRUE;
  345.     end
  346.    else
  347.     Data := nil;
  348.   S.Read (DblBar,  sizeof (DblBar));
  349. end;
  350.  
  351.  
  352. procedure TDmxExtLabels.Store (var S : TStream);
  353. begin
  354.   TDmxLink.Store (S);
  355.   S.Write (Len, sizeof (Len));
  356.   If Len > 0 then S.Write (Data^, Len);
  357.   S.Write (DblBar,  sizeof (DblBar));
  358. end;
  359.  
  360.  
  361. procedure TDmxExtLabels.Draw;
  362. var  i    : integer;
  363.      A    : string;
  364.      B    : TDrawBuffer;
  365. begin
  366.   If (Link = nil) or (Link^.Delta.X >= Len) then
  367.     fillchar (A [1], Size.X, ' ')
  368.    else
  369.     begin
  370.     Move (Data^ [Link^.Delta.X], A [1], Size.X);
  371.     If (Link^.Delta.X + Size.X > Len) then
  372.       fillchar (A [succ (Len - Link^.Delta.X)], (Size.X + Link^.Delta.X - Len), ' ');
  373.     end;
  374.   A [0] := chr (lo (Size.X));
  375.   MoveStr (B, A, GetColor (1));
  376.   If (Link^.Origin.Y <= Origin.Y) then i := pred (Size.Y) else i := 0;
  377.   WriteLine (0, i, Size.X, 1, B);
  378.   If (Size.Y > 1) then DrawRuler ((i = 0), DblBar);
  379. end;
  380.  
  381.  
  382. procedure TDmxExtLabels.DrawRuler (Upper, AtLimit : boolean);
  383. const
  384.   LtArr        =  17;
  385.   RtArr        =  16;
  386.   Markers    : string [10] = '─═┬╤╥╦┴╧╨╩';
  387. var
  388.   Color        : word;
  389.   i,X,width    : integer;
  390.   Mk        : integer;
  391.   frontcut    : integer;
  392.   fieldrec    : pDMXfieldrec;
  393.   A        : string;
  394.   B        : TDrawBuffer;
  395. begin
  396.   If (longint (Size) = 0) or (Link = nil) or (Link^.DMXfield1 = nil) then Exit;
  397.   fieldrec  := Link^.LeftField;
  398.   If (fieldrec = nil) or (fieldrec^.screentab > Link^.Delta.X) then
  399.     fieldrec := Link^.DMXfield1;
  400.   While (fieldrec^.Next^.screentab <= Link^.Delta.X) and
  401.     (fieldrec^.Next <> nil)
  402.    do
  403.     fieldrec := fieldrec^.Next;
  404.   frontcut  := Link^.Delta.X - fieldrec^.screentab;
  405.   If frontcut < 0 then frontcut := 0;
  406.   X := 0;
  407.   If (Clicked = @Self) then Color := GetColor (6) else Color := GetColor (5);
  408.   If AtLimit then Mk := 2 else Mk := 1;
  409.   MoveChar (B, Markers [Mk], Color, Size.X);
  410.   Inc (Mk, 2);
  411.   If not Upper then Inc (Mk, 4);
  412.   If (Clicked <> @Self) then While (X < Size.X) do
  413.     begin
  414.     With fieldrec^ do
  415.       begin
  416.       If (access and accHidden = 0) then
  417.     begin
  418.     If access and accDelimiter <> 0 then
  419.       begin
  420.       If fieldrec^.typecode = '║' then char (B [X]) := Markers [Mk + 2]
  421.        else If fieldrec^.typecode = '│' then char (B [X]) := Markers [Mk];
  422.       Inc (X);
  423.       end
  424.      else
  425.       begin
  426.       X := X + shownwid - frontcut;
  427.       end;
  428.     frontcut := 0;
  429.     end;
  430.       end;
  431.     fieldrec := fieldrec^.Next;
  432.     If (fieldrec = nil) and (Size.X > X) then X := Size.X;
  433.     end;
  434.   If Upper then i := pred (Size.Y) else i := 0;
  435.   WriteLine (0, i, Size.X, succ (i), B);
  436. end;
  437.  
  438.  
  439. procedure TDmxExtLabels.HandleEvent (var Event : TEvent);
  440. var  dX,dY  : integer;
  441.      Cmd    : word;
  442. begin
  443.   TDmxLink.HandleEvent (Event);
  444.   With Event do
  445.     If (What and evMouseDown <> 0) then
  446.       begin
  447.       If (Link = nil) then Exit;
  448.       If (Link^.State and sfSelected = 0) then
  449.     Link^.Select
  450.        else
  451.     begin
  452.     Repeat
  453.       Clicked := @Self;
  454.       DrawView;
  455.       If (Link^.Origin.Y <= Origin.Y) then Cmd := cmDMX_Down else Cmd := cmDMX_Up;
  456.       Message (Link, evCommand, Cmd, @Self);
  457.       Application^.Idle;
  458.       Clicked := nil;
  459.       DrawView;
  460.     Until not MouseEvent (Event, evMouseDown or evMouseAuto);
  461.     end;
  462.       ClearEvent (Event);
  463.       end
  464.     else
  465.     If (What and evMessage <> 0) then
  466.       begin
  467.       If (Command = cmDMX_ScrollBarChanged) then
  468.     begin
  469.     If (InfoPtr = Link) then DrawView;
  470.     end
  471.       else
  472.       If (Command = cmDMX_FixSize) and (Size.X > Len)
  473.     and (Link <> nil) and (Link^.Labels = @Self) then
  474.     begin
  475.     dX := (Owner^.Size.X - Size.X) + Len;
  476.     dY :=  Owner^.Size.Y;
  477.     Owner^.GrowTo (dX, dY);
  478.     end;
  479.       end;
  480. end;
  481.  
  482.  
  483. procedure TDmxExtLabels.SetState (AState : word; Enable : boolean);
  484. var  L : longint;
  485. begin
  486.   TDmxLink.SetState (AState, Enable);
  487.   If Enable and (AState and sfExposed <> 0) and (Link <> nil) then
  488.     begin
  489.     If (Link^.Origin.Y <= Origin.Y) then
  490.       GrowMode := gfGrowHiX or gfGrowLoY or gfGrowHiY
  491.      else
  492.       GrowMode := gfGrowHiX;
  493.     end;
  494. end;
  495.  
  496.  
  497.   { ══ TDmxLabels ════════════════════════════════════════════════════════ }
  498.  
  499.  
  500. constructor TDmxLabels.Init (DataStr : pstring;  var Bounds : TRect);
  501. begin
  502.   TDmxLink.Init (Bounds);
  503.   Move (DataStr, Data, sizeof (Data));
  504.   Len := length (DataStr^);
  505.   Inc (PtrRec (Data).Ofs);
  506. end;
  507.  
  508.  
  509. constructor TDmxLabels.InitInsert (AOwner : PGroup;  DataStr : pstring);
  510. var  R : TRect;
  511. begin
  512.   AOwner^.GetExtent (R);
  513.   Inc (R.A.Y);
  514.   R.B.Y := R.A.Y + 2;
  515.   R.Grow (-1, 0);
  516.   TDmxLink.Init (R);
  517.   Move (DataStr, Data, sizeof (Data));
  518.   Len := length (DataStr^);
  519.   Inc (PtrRec (Data).Ofs);
  520.   Insert (AOwner);
  521. end;
  522.  
  523.  
  524.   { ══ TDmxFLabels ═══════════════════════════════════════════════════════ }
  525.  
  526.  
  527. constructor TDmxFLabels.Init (LabelStr : string;  var Bounds : TRect);
  528. begin
  529.   TDmxLink.Init (Bounds);
  530.   Len := length (LabelStr);
  531.   If (Len > 0) then
  532.     begin
  533.     GetMem (Data, Len);
  534.     Move (LabelStr [1], Data^, Len);
  535.     Heaped := TRUE;
  536.     end;
  537. end;
  538.  
  539.  
  540. constructor TDmxFLabels.InitInsert (AOwner : PGroup;  LabelStr : string);
  541. var  R : TRect;
  542. begin
  543.   AOwner^.GetExtent (R);
  544.   Inc (R.A.Y);
  545.   R.B.Y := R.A.Y + 2;
  546.   R.Grow (-1, 0);
  547.   TDmxFLabels.Init (LabelStr, R);
  548.   Insert (AOwner);
  549. end;
  550.  
  551.  
  552.   { ══ TDmxMLabels ═══════════════════════════════════════════════════════ }
  553.  
  554.  
  555. constructor TDmxMLabels.Init (Labels : PSItem;  var Bounds : TRect);
  556. var  i : integer;
  557. begin
  558.   TDmxLink.Init (Bounds);
  559.   Len := SItemsLen (Labels);
  560.   If (Len > 0) then
  561.     begin
  562.     GetMem (Data, Len);
  563.     i := 0;
  564.     While (Labels <> nil) do
  565.       begin
  566.       If (Labels^.Value <> nil) then
  567.         begin
  568.         Move (Labels^.Value^[1], Data^[i], length (Labels^.Value^));
  569.         Inc (i, length (Labels^.Value^));
  570.         end;
  571.       Labels := Labels^.Next;
  572.       end;
  573.     Heaped := TRUE;
  574.     end;
  575. end;
  576.  
  577.  
  578. constructor TDmxMLabels.InitInsert (AOwner : PGroup;  Labels : PSItem);
  579. var  R : TRect;
  580. begin
  581.   AOwner^.GetExtent (R);
  582.   Inc (R.A.Y);
  583.   R.B.Y := R.A.Y + 2;
  584.   R.Grow (-1, 0);
  585.   TDmxMLabels.Init (Labels, R);
  586.   Insert (AOwner);
  587. end;
  588.  
  589.  
  590.   { ══ TDmxScroller ══════════════════════════════════════════════════════ }
  591.  
  592.  
  593. constructor TDmxScroller.Init (ATemplate : string;  var AData;
  594.                    BSize : longint;  var Bounds : TRect;
  595.                    ALabels : PView;
  596.                    AHScrollBar,AVScrollBar : PScrollBar);
  597. var  L : longint;
  598. begin
  599.   TScroller.Init (Bounds, AHScrollBar, AVScrollBar);
  600.   NewestDMX    := @Self;
  601.   Labels    := PDmxLink (ALabels);
  602.   If Labels <> nil then Labels^.Link := @Self;
  603.   InitValid    := TRUE;
  604.   DataBlockSize    := BSize;
  605.   WorkingData    := @AData;
  606.   Limit.X    := 0;
  607.   InitStruct (ATemplate);
  608.   InitData (AData);
  609.   If (RecordSize > 0) then
  610.     begin
  611.     L := RecordSize;
  612.     L := DataBlockSize div L;
  613.     SetLimit (Limit.X, L);
  614.     end;
  615.   LeftField := DMXfield1;
  616.   GrowMode  := gfGrowHiX or gfGrowHiY;
  617. end;
  618.  
  619.  
  620. destructor TDmxScroller.Done;
  621. begin
  622.   If (NewestDMX = @Self) then NewestDMX := nil;
  623.   DoneData;
  624.   DoneStruct;
  625.   TScroller.Done;
  626. end;
  627.  
  628.  
  629. constructor TDmxScroller.Load (var S : TStream);
  630. begin
  631.   TScroller.Load (S);
  632.   InitValid := TRUE;
  633.   GetPeerViewPtr (S, Labels);
  634.   S.Read (TotalFields, sizeof (TotalFields));
  635.   S.Read (RecordSize,  sizeof (RecordSize));
  636.   S.Read (CurrentRecord, sizeof (CurrentRecord));
  637.   S.Read (DataBlockSize, sizeof (DataBlockSize));
  638.   InBuffer  := FALSE;
  639.   LoadData (S);
  640.   LoadStruct (S);
  641. end;
  642.  
  643.  
  644. procedure TDmxScroller.Store (var S : TStream);
  645. begin
  646.   TScroller.Store (S);
  647.   PutPeerViewPtr (S, Labels);
  648.   S.Write (TotalFields, sizeof (TotalFields));
  649.   S.Write (RecordSize,  sizeof (RecordSize));
  650.   S.Write (CurrentRecord, sizeof (CurrentRecord));
  651.   S.Write (DataBlockSize, sizeof (DataBlockSize));
  652.   StoreData (S);
  653.   StoreStruct (S);
  654. end;
  655.  
  656.  
  657. procedure TDmxScroller.ChangeBounds (var Bounds : TRect);
  658. begin
  659.   InBuffer := FALSE;
  660.   TScroller.ChangeBounds (Bounds);
  661. end;
  662.  
  663.  
  664. function  TDmxScroller.DataAt (RecNum : integer) : pointer;
  665. begin
  666.   DataAt := ptr (PtrRec (WorkingData).Seg, PtrRec (WorkingData).Ofs + RecNum * RecordSize);
  667. end;
  668.  
  669.  
  670. procedure TDmxScroller.DoneData;
  671. begin
  672. end;
  673.  
  674.  
  675. procedure TDmxScroller.DoneStruct;
  676. var  P : pDMXfieldrec;
  677. begin
  678.   While (DMXfield1 <> nil) do
  679.     begin
  680.     P := DMXfield1^.Next;
  681.     If DMXfield1^.template <> nil then
  682.       begin
  683.       If (upcase (DMXfield1^.typecode) = fldENUM) then
  684.     DisposeSItems (PSItem (DMXfield1^.template))
  685.        else
  686.     DisposeStr (DMXfield1^.template);
  687.       end;
  688.     Dispose (DMXfield1);
  689.     DMXfield1 := P;
  690.     end;
  691.   LeftField    := nil;
  692. end;
  693.  
  694.  
  695. var  EmptyRecord : byte;
  696.  
  697.  
  698. procedure TDmxScroller.Draw;
  699. var
  700.   i,rows,Y,owid  :  integer;
  701.   A   :  string;
  702.   B   :  TDrawBuffer;
  703.   Buf : ^TDrawBuffer;
  704. begin
  705.   HideCursor;
  706.   rows := Size.Y;
  707.   Y    := -1;
  708.   FirstField := nil;
  709.   If (Owner^.Buffer <> nil) and InBuffer then
  710.     begin
  711.     If (Delta.X = DDelta.X) and (abs (Delta.Y - DDelta.Y) = 1) and
  712.        (Size.Y > 1) and (longint (Size) = longint (DSize))
  713.      then  { use part of the owner's buffer if this is a 1 line scroll }
  714.       begin
  715.       owid := Owner^.Size.X shl 1;
  716.       longint (Buf) := longint (Owner^.Buffer) + ((Origin.Y * owid) + (Origin.X shl 1));
  717.       If (Delta.Y > DDelta.Y) then  { Down }
  718.     begin
  719.     For i := 0 to (Size.Y - 2) do
  720.       begin
  721.       ptrrec (Buf).ofs := ptrrec (Buf).ofs + owid;
  722.       WriteBuf (0, i, Size.X, 1, Buf^);
  723.       end;
  724.     Y := Size.Y - 2;
  725.     end
  726.        else  { Up }
  727.     begin
  728.     ptrrec (Buf).ofs := ptrrec (Buf).ofs + ((Size.Y - 2) * owid);
  729.     For i := (Size.Y - 1) downto 1 do
  730.       begin
  731.       WriteBuf (0, i, Size.X, 1, Buf^);
  732.       ptrrec (Buf).ofs := ptrrec (Buf).ofs - owid;
  733.       end;
  734.     Rows := 1;
  735.     end;
  736.       end;
  737.     end;
  738.   If rows > 0 then
  739.     begin
  740.     While (Y < pred (rows)) do
  741.       begin
  742.       Inc (Y);
  743.       If Y + Delta.Y < Limit.Y then
  744.     DrawRecord (Y, DataAt (Y + Delta.Y)^)
  745.        else
  746.     DrawRecord (Y, EmptyRecord);
  747.       end;
  748.     end;
  749.   DDelta   := Delta;
  750.   DSize    := Size;
  751.   InBuffer := (Owner^.Buffer <> nil);
  752.   If NowScrolling then
  753.     begin
  754.     Message (Owner, evBroadcast, cmDMX_ScrollBarChanged, @Self);
  755.     NowScrolling := FALSE;
  756.     end;
  757. end;
  758.  
  759.  
  760. procedure TDmxScroller.DrawRecord (Y : integer;  var DataRecord );
  761. var Color        : word;
  762.     ColorA, ColorB    : word;
  763.     I,X, width        : integer;
  764.     frontcut        : integer;
  765.     fieldrec        : pDMXfieldrec;
  766.     A            : string;
  767.     B            : TDrawBuffer;
  768. begin
  769.   If (FirstField <> DMXfield1) then
  770.     begin
  771.     FirstField := DMXfield1;
  772.     LeftField  := DMXfield1;
  773.     While (LeftField^.Next <> nil) and
  774.       (LeftField^.Next^.screentab <= Delta.X)
  775.      do
  776.       LeftField := LeftField^.Next;
  777.     end;
  778.   If (LeftField = nil) then Exit;
  779.   fieldrec := LeftField;
  780.   frontcut := Delta.X - fieldrec^.screentab;
  781.   X       := 0;
  782.   ColorA   := GetColor (1);
  783.   ColorB   := GetColor (5);
  784.   While (X < Size.X) do
  785.     begin
  786.     With fieldrec^ do
  787.       begin
  788.       If (access and accHidden = 0) then
  789.     begin
  790.     If access and accDelimiter <> 0 then
  791.       begin
  792.       A    := typecode;
  793.       Color := ColorB;
  794.       end
  795.      else
  796.       begin
  797.       If (@DataRecord = @EmptyRecord) then
  798.         begin
  799.         A [0] := chr (fieldrec^.shownwid);
  800.         fillchar (A [1], fieldrec^.shownwid, ' ');
  801.         end
  802.        else
  803.         A    := FieldString (fieldrec, [], DataRecord);
  804.       If fieldsize > 0 then Color := ColorA else Color := ColorB;
  805.       FieldText (A, Color, fieldrec, DataRecord);
  806.       If length (A) > shownwid then A [0] := chr (shownwid);
  807.       If frontcut > 0 then Delete (A, 1, frontcut);
  808.       end;
  809.     frontcut := 0;
  810.     MoveStr (B [X], A, Color);
  811.     X  := X + length (A);
  812.     end;
  813.       end;
  814.     fieldrec := fieldrec^.Next;
  815.     If (fieldrec = nil) and (Size.X > X) then
  816.       begin
  817.       MoveChar (B [X], ' ', ColorB, Size.X - X);
  818.       X  := Size.X;
  819.       end;
  820.     end;
  821.   WriteLine (0, Y, Size.X, 1, B);
  822. end;
  823.  
  824.  
  825. procedure TDmxScroller.FieldText (var S : string;  var Color : word;
  826.                   Field : pDMXfieldrec;  var DataRec );
  827. begin
  828. end;
  829.  
  830.  
  831. procedure TDmxScroller.GetData (var Rec );
  832. begin
  833.   pointer (Rec) := WorkingData
  834. end;
  835.  
  836.  
  837. function  TDmxScroller.GetPalette : PPalette;
  838. const  P : string [length (cDMX)] = cDMX;
  839. begin
  840.   GetPalette := @P
  841. end;
  842.  
  843.  
  844. procedure TDmxScroller.HandleEvent (var Event : TEvent);
  845. var  WasHere : boolean;
  846. begin
  847.   TScroller.HandleEvent (Event);
  848.   With Event do
  849.     If (What and evMessage <> 0) then
  850.       begin
  851.       WasHere := TRUE;
  852.       If (Command = cmDMX_RollCall) then
  853.     begin
  854.     If (InfoPtr <> nil) and (InfoPtr <> @Self) then
  855.       Message (InfoPtr, evCommand, cmDMX_Ack, @Self);
  856.     end
  857.       else
  858.       If (((Command = cmDMX_DrawData) and (WorkingData = InfoPtr)) or
  859.       ((Command = cmDMX_Draw) and
  860.       ((InfoPtr = nil) or (PDmxScroller (InfoPtr)^.WorkingData = WorkingData) or (What = evCommand))))
  861.       then DrawView
  862.       else
  863.       If not Locked and (((Command = cmDMX_LockData) and (WorkingData = InfoPtr)) or
  864.     ((Command = cmDMX_Lock) and
  865.     ((InfoPtr = nil) or (PDmxScroller (InfoPtr)^.WorkingData = WorkingData) or (What = evCommand))))
  866.       then Locked := TRUE
  867.       else
  868.       If Locked and (((Command = cmDMX_UnlockData) and (WorkingData = InfoPtr)) or
  869.     ((Command = cmDMX_Unlock) and
  870.     ((InfoPtr = nil) or (PDmxScroller (InfoPtr)^.WorkingData = WorkingData) or (What = evCommand))))
  871.       then Locked := FALSE
  872.       else
  873.         WasHere := FALSE;
  874.       If WasHere and (What = evCommand) then ClearEvent (Event);
  875.       end;
  876. end;
  877.  
  878.  
  879. procedure TDmxScroller.InitData (var AData );
  880. begin
  881.   WorkingData := @AData;
  882. end;
  883.  
  884.  
  885. procedure TDmxScroller.InitStruct (var ATemplate );
  886. var
  887.   SameFieldNum    :  boolean;
  888.   WasSameNum    :  boolean;
  889.   NoFieldNum    :  boolean;
  890.   AllZeroes    :  boolean;
  891.   C        :  char;
  892.   DoDecimal    :  integer;
  893.   Rex,X        :  pDMXfieldrec;
  894.   templx    :  string;
  895.  
  896.   procedure NewRecord;
  897.   var i,j : integer;
  898.       A   : pstring;
  899.   begin
  900.     If not InitValid then Exit;
  901.     With Rex^ do
  902.       begin
  903.       If DoDecimal > 0 then Rex^.decimals := pred (DoDecimal);
  904.       DoDecimal := 0;
  905.       If (fieldsize = 0) then
  906.     access := access or accSkip
  907.        else
  908.     begin
  909.     If not NoFieldNum then
  910.       If SameFieldNum then
  911.         fieldnum := succ (TotalFields)
  912.        else
  913.         If TRUE or (access and accHidden = 0) or WasSameNum then
  914.           begin
  915.           Inc (TotalFields);
  916.           fieldnum := TotalFields;
  917.           end;
  918.     datatab    := RecordSize;
  919.     RecordSize := RecordSize + fieldsize;
  920.     end;
  921.       screentab  := Limit.X;
  922.       If (typecode = fldBOOLEAN) and (truelen = 0) then showzeroes := FALSE;
  923.       If (upcase (typecode) = fldENUM) then
  924.         begin
  925.     columnwid := truelen;
  926.         end
  927.        else
  928.     begin
  929.     columnwid := length (templx);
  930.     If (length (templx) > 0) or (template <> nil) then
  931.       begin
  932.       If (MaxAvail > length (templx)) then
  933.         template  := NewStr (templx)
  934.        else
  935.         InitValid := FALSE;
  936.       end
  937.          else
  938.       begin
  939.       If (typecode <> #0) and (access and accHidden = 0) then Inc (Limit.X);
  940.       end;
  941.     end;
  942.       If (shownwid = 0) then shownwid := columnwid;
  943.       If access and accHidden = 0 then Limit.X := Limit.X + shownwid;
  944.       end;
  945.     templx := '';
  946.     If (MaxAvail > sizeof (Rex^)) then
  947.       begin
  948.       New (Rex^.Next);
  949.       X   := Rex;
  950.       Rex := Rex^.Next;
  951.       fillchar (Rex^, sizeof (Rex^), 0);
  952.       Rex^.Prev := X;
  953.       Rex^.Next := nil;
  954.       Rex^.showzeroes := AllZeroes;
  955.       end
  956.      else
  957.       InitValid := FALSE;
  958.     WasSameNum := FALSE;
  959.     NoFieldNum := FALSE;
  960.   end;
  961.  
  962.   procedure TranslateStruct (dataformat : pstring);
  963.   var  df   : pstring;
  964.        i,j  : integer;
  965.        TS   : PSItem;
  966.   begin
  967.     SameFieldNum := FALSE;
  968.     WasSameNum   := FALSE;
  969.     NoFieldNum     := FALSE;
  970.     DoDecimal :=  0;
  971.     i := 1;
  972.     While (i <= length (dataformat^)) do
  973.       begin
  974.       C := upcase (dataformat^ [i]);
  975.       Case C of
  976.     fldSTR, fldSTRNUM:
  977.       With Rex^ do
  978.         begin
  979.         templx   := templx + #0;
  980.         typecode := dataformat^ [i];
  981.         Inc (truelen);
  982.         If fieldsize > 0 then
  983.           Inc (fieldsize)
  984.          else
  985.           begin
  986.           fieldsize :=  2;
  987.           fillvalue := ' ';
  988.           end;
  989.         end;
  990.     fldCHAR, fldCHARVAL, fldCHARNUM:
  991.       With Rex^ do
  992.         begin
  993.         templx    := templx + #0;
  994.         typecode  := dataformat^ [i];
  995.         Inc (truelen);
  996.         Inc (fieldsize);
  997.         fillvalue := ' ';
  998.         If DoDecimal > 0 then Inc (DoDecimal);
  999.         end;
  1000.     fldBYTE, fldSHORTINT, fldBOOLEAN:
  1001.       With Rex^ do
  1002.         begin
  1003.         templx    := templx + #0;
  1004.         If upcase (C) <> fldSHORTINT then C := upcase (C);
  1005.         typecode  := dataformat^ [i];
  1006.         Inc (truelen);
  1007.         fieldsize := sizeof (BYTE);
  1008.         fillvalue := #0;
  1009.         end;
  1010.     ^X :
  1011.       With Rex^ do
  1012.         begin
  1013.         typecode  := fldBOOLEAN;
  1014.         truelen   := 0;
  1015.         fieldsize := sizeof (BOOLEAN);
  1016.         fillvalue := #0;
  1017.         end;
  1018.     fldZEROMOD:  { 'Z' }
  1019.       With Rex^ do
  1020.         begin
  1021.         If (typecode = #0) or (typecode = fldCHARVAL) then Inc (fieldsize);
  1022.         templx := templx + #1;
  1023.         Inc (truelen);
  1024.         If DoDecimal > 0 then Inc (DoDecimal);
  1025.         end;
  1026.     fldWORD, fldINTEGER:
  1027.       With Rex^ do
  1028.         begin
  1029.         templx    := templx + #0;
  1030.         typecode  := dataformat^ [i];
  1031.         Inc (truelen);
  1032.         fieldsize := sizeof (INTEGER);
  1033.         fillvalue := #0;
  1034.         end;
  1035.     fldLONGINT:
  1036.       With Rex^ do
  1037.         begin
  1038.         templx    := templx + #0;
  1039.         typecode  := dataformat^ [i];
  1040.         Inc (truelen);
  1041.         fieldsize := sizeof (LONGINT);
  1042.         fillvalue := #0;
  1043.         end;
  1044.     fldHEXVALUE:
  1045.       With Rex^ do
  1046.         begin
  1047.         templx    := templx + #0;
  1048.         typecode  := dataformat^ [i];
  1049.         Inc (truelen);
  1050.         fieldsize := succ (truelen) shr 1;
  1051.         fillvalue := #0;
  1052.         end;
  1053.     fldREALNUM:
  1054.       With Rex^ do
  1055.         begin
  1056.         templx    := templx + #0;
  1057.         typecode  := dataformat^ [i];
  1058.         Inc (truelen);
  1059.         fieldsize := sizeof (TREALNUM);
  1060.         fillvalue := #0;
  1061.         If DoDecimal > 0 then Inc (DoDecimal);
  1062.         end;
  1063.     fldENUM:
  1064.       begin
  1065.       If (templx <> '') then NewRecord;
  1066.       Move (dataformat^ [succ (i)], Rex^.template, sizeof (Rex^.template));
  1067.       Rex^.typecode      := fldENUM;
  1068.       Rex^.truelen      := MaxItemStrLen (PSItem (Rex^.template));
  1069.       Rex^.fieldsize  := sizeof (BYTE);
  1070.       Rex^.showzeroes := boolean (dataformat^ [i+5]);
  1071.       Rex^.access      := byte (dataformat^ [i+6]);
  1072.       Rex^.fillvalue  := dataformat^ [i+7];
  1073.       Inc (i, sizeof (DmxIDstr) - 2);
  1074.       NewRecord;
  1075.       end;
  1076.     fldBLOB:
  1077.       begin
  1078.       If (templx <> '') then NewRecord;
  1079.       Rex^.typecode      := fldBLOB;
  1080.       Move (dataformat^ [succ (i)], Rex^.fieldsize, sizeof (Rex^.fieldsize));
  1081.       Rex^.fieldsize  := integer (dataformat^ [i+1]);
  1082.       Rex^.access      := byte (dataformat^ [i+6]) or accHidden;
  1083.       Rex^.fillvalue  := dataformat^ [i+7];
  1084.       Inc (i, sizeof (DmxIDstr) - 2);
  1085.       NewRecord;
  1086.       end;
  1087.     fldAPPEND:
  1088.       begin
  1089.       If (templx <> '') then NewRecord;
  1090.       Move (dataformat^ [succ (i)], df, sizeof (df));
  1091.       TranslateStruct (df);
  1092.       Inc (i, sizeof (DmxIDstr) - 2);
  1093.       end;
  1094.     fldSITEMS:
  1095.       begin
  1096.       If (templx <> '') then NewRecord;
  1097.       Move (dataformat^ [succ (i)], TS, sizeof (TS));
  1098.       While (TS <> nil) do
  1099.         begin
  1100.         If (TS^.Value <> nil) then TranslateStruct (TS^.Value);
  1101.         TS := TS^.Next;
  1102.         end;
  1103.       Inc (i, sizeof (DmxIDstr) - 2);
  1104.       end;
  1105.     ')','.':
  1106.       With Rex^ do
  1107.         begin
  1108.         templx := templx + C;
  1109.         If (upcase (Rex^.typecode) = fldCHARVAL) then
  1110.           begin
  1111.           If (C = ')') then Inc (truelen);
  1112.           Inc (fieldsize);
  1113.           end;
  1114.         If (C = '.') then
  1115.           begin
  1116.           If (upcase (typecode) = fldREALNUM) or
  1117.              (upcase (typecode) = fldCHARVAL) then
  1118.             DoDecimal := 1;
  1119.           end
  1120.          else
  1121.           parenthesis := TRUE;
  1122.         end;
  1123.     '~':
  1124.       begin
  1125.       Inc (i);
  1126.       While (dataformat^[i] <> '~') and (i <= length (dataformat^)) do
  1127.         begin
  1128.         C := dataformat^ [i];
  1129.         If C = #0 then C := ' ';
  1130.         If C = #1 then C := #2;
  1131.         templx := templx + C;
  1132.         Inc (i);
  1133.         end;
  1134.       end;
  1135.     #0,'\','|','│','║':
  1136.       begin
  1137.       If (templx <> '') then NewRecord;
  1138.       If C <> #0 then
  1139.         begin
  1140.         If C = '|' then C := '│' else If C = '\' then C := ' ';
  1141.         Rex^.access    := Rex^.access or accDelimiter;
  1142.         Rex^.typecode  := C;
  1143.         NewRecord;
  1144.         end;
  1145.       end;
  1146.     ^A:
  1147.       begin
  1148.       AllZeroes    := not AllZeroes;
  1149.       Rex^.showzeroes := AllZeroes;
  1150.       end;
  1151.     ^C:
  1152.       begin
  1153.       Inc (i);
  1154.       Rex^.access := Rex^.access or ord (dataformat^[i]);
  1155.       end;
  1156.     ^D:
  1157.       begin
  1158.       If (templx <> '') then NewRecord;
  1159.       Inc (i);
  1160.       C := dataformat^ [i];
  1161.       Rex^.access    := Rex^.access or accDelimiter;
  1162.       Rex^.typecode  := C;
  1163.       NewRecord;
  1164.       end;
  1165.     ^F:
  1166.       begin
  1167.       If (i < length (dataformat^)) and (dataformat^[i+1] = ^F) then
  1168.         begin
  1169.         NoFieldNum := TRUE;
  1170.         Inc (i);
  1171.         end
  1172.        else
  1173.         begin
  1174.         WasSameNum   := SameFieldNum;
  1175.         SameFieldNum := not SameFieldNum;
  1176.         end;
  1177.       end;
  1178.     ^H:   With Rex^ do access := access or accHidden;
  1179.     ^P:   With Rex^ do
  1180.         begin
  1181.         Inc (i);
  1182.         RecordSize := RecordSize + shortint (dataformat^ [i]);
  1183.         end;
  1184.     ^R:   With Rex^ do access := access or accReadOnly;
  1185.     ^S:   With Rex^ do access := access or accSkip;
  1186.     ^U:   With Rex^ do
  1187.         begin
  1188.         Inc (i);
  1189.         upperlimit := byte (dataformat^ [i]);
  1190.         end;
  1191.     ^V:   With Rex^ do
  1192.         begin
  1193.         Inc (i);
  1194.         fillvalue := dataformat^ [i];
  1195.         end;
  1196.     ^Z:   Rex^.showzeroes := TRUE;
  1197.     fldCONTRACTION:   With Rex^ do shownwid := length (templx);
  1198.        else
  1199.       begin
  1200.       templx := templx + dataformat^ [i];
  1201.       end;
  1202.         end;  { case of C }
  1203.       Inc (i);
  1204.       end;
  1205.   end;
  1206.  
  1207. begin
  1208.   If (@ATemplate = nil) then Exit;
  1209.   AllZeroes := FALSE;
  1210.   templx    := '';
  1211.   New (Rex);
  1212.   fillchar (Rex^, sizeof (Rex^), 0);
  1213.   Rex^.Next := nil;
  1214.   Rex^.Prev := nil;
  1215.   Rex^.showzeroes := AllZeroes;
  1216.   X := nil;
  1217.   If DMXfield1 = nil then
  1218.     DMXfield1 := Rex
  1219.    else
  1220.     begin
  1221.     X := DMXfield1;
  1222.     While X^.Next <> nil do X := X^.Next;
  1223.     X^.Next := Rex;
  1224.     Rex^.Prev := X;
  1225.     end;
  1226.   TranslateStruct (@ATemplate);
  1227.   SameFieldNum := FALSE;
  1228.   If templx <> '' then NewRecord;
  1229.   If (Rex = DMXfield1) then DMXfield1 := nil;
  1230.   Dispose (Rex);
  1231.   If (X <> nil) then X^.Next := nil;
  1232.   If DMXfield1 <> nil then DMXfield1^.Prev := X;
  1233. end;
  1234.  
  1235.  
  1236. procedure TDmxScroller.LoadData (var S : TStream);
  1237. begin
  1238. end;
  1239.  
  1240.  
  1241. procedure TDmxScroller.LoadStruct (var S : TStream);
  1242. var n     : integer;
  1243.     P,Px : pDMXfieldrec;
  1244. begin
  1245.   DMXfield1 := nil;
  1246.   S.Read (n, sizeof (n));
  1247.   Px := nil;
  1248.   While (n > 0) do
  1249.     begin
  1250.     GetMem (P, sizeof (P^));
  1251.     S.Read (P^, sizeof (P^));
  1252.     If (P^.template <> nil) then
  1253.       begin
  1254.       If upcase (P^.typecode) = fldENUM then
  1255.     P^.template := pstring (ReadSItems (S))
  1256.        else
  1257.         P^.template := S.ReadStr;
  1258.       end;
  1259.     If DMXfield1 = nil then DMXfield1 := P;
  1260.     If Px <> nil then Px^.Next := P;
  1261.     P^.Prev := Px;
  1262.     P^.Next := nil;
  1263.     Px      := P;
  1264.     Dec (n);
  1265.     end;
  1266.   LeftField := DMXfield1;
  1267.   If DMXfield1 <> nil then DMXfield1^.Prev := P;
  1268. end;
  1269.  
  1270.  
  1271. function  TDmxScroller.RecNumStr (RecNum : integer) : string;
  1272. var  S : string;
  1273. begin
  1274.   If (RecNum >= RecordLimit) then
  1275.     RecNumStr := '      '
  1276.    else
  1277.     begin
  1278.     Str (succ (RecNum):5, S);
  1279.     RecNumStr := S + ' ';
  1280.     end;
  1281. end;
  1282.  
  1283.  
  1284. function  TDmxScroller.RecordLimit : longint;
  1285. begin
  1286.   If (RecordSize > 0) then
  1287.     RecordLimit := (DataBlockSize div RecordSize)
  1288.    else
  1289.     RecordLimit := 0;
  1290. end;
  1291.  
  1292.  
  1293. procedure TDmxScroller.ScrollDraw;
  1294. begin
  1295.   NowScrolling := ((HScrollBar <> nil) and (HScrollBar^.Value <> Delta.X)) or
  1296.           ((VScrollBar <> nil) and (VScrollBar^.Value <> Delta.Y));
  1297.   TScroller.ScrollDraw;
  1298. end;
  1299.  
  1300.  
  1301. procedure TDmxScroller.SetData (var Rec );
  1302. begin
  1303.   WorkingData := pointer (Rec)
  1304. end;
  1305.  
  1306.  
  1307. procedure TDmxScroller.SetState (AState : word; Enable : boolean);
  1308. var  L1,L2 : longint;
  1309. begin
  1310.   If (AState and sfFocused <> 0) then
  1311.     begin
  1312.     If Enable then
  1313.       begin
  1314.       If (RecordSize > 0) then
  1315.     begin
  1316.     L1 := RecordSize;
  1317.     L2 := L1 * Limit.Y;
  1318.     L1 := DataBlockSize - (DataBlockSize mod L1);
  1319.     If (L1 <> L2) then
  1320.       begin
  1321.       L1 := RecordSize;
  1322.       L1 := DataBlockSize div L1;
  1323.       SetLimit (Limit.X, L1);
  1324.       end;
  1325.     end;
  1326.       If (Application <> nil) then
  1327.     TScroller.SetState (sfCursorIns, Application^.GetState (sfCursorIns));
  1328.       end
  1329.      else
  1330.       begin
  1331.       If (Application <> nil) then
  1332.     Application^.SetState (sfCursorIns, GetState (sfCursorIns));
  1333.       end;
  1334.     end;
  1335.   TScroller.SetState (AState, Enable);
  1336. end;
  1337.  
  1338.  
  1339. procedure TDmxScroller.StoreData (var S : TStream);
  1340. begin
  1341. end;
  1342.  
  1343.  
  1344. procedure TDmxScroller.StoreStruct (var S : TStream);
  1345. var  n : integer;
  1346.      P : pDMXfieldrec;
  1347. begin
  1348.   n  := 0;
  1349.   P  := DMXfield1;
  1350.   While (P <> nil) do
  1351.     begin
  1352.     Inc (n);
  1353.     P := P^.Next;
  1354.     end;
  1355.   S.Write (n, sizeof (n));
  1356.   P := DMXfield1;
  1357.   While (P <> nil) do
  1358.     begin
  1359.     S.Write (P^, sizeof (P^));
  1360.     If (P^.template <> nil) then
  1361.       begin
  1362.       If upcase (P^.typecode) = fldENUM then
  1363.     WriteSItems (S, PSItem (P^.template))
  1364.        else
  1365.     S.WriteStr (P^.template);
  1366.       end;
  1367.     P := P^.Next;
  1368.     end;
  1369. end;
  1370.  
  1371.  
  1372. function  TDmxScroller.Valid (Command : word)  : boolean;
  1373. var  V : boolean;
  1374. begin
  1375.   V := TScroller.Valid (Command);
  1376.   If (Command = cmValid) then V := V and InitValid;
  1377.   Valid := V;
  1378. end;
  1379.  
  1380.  
  1381. procedure TDmxScroller.WrongKeypressed (var Event : TEvent);
  1382. begin
  1383.   Message (Application, evCommand, cmDMX_WrongKey, @Self);
  1384. end;
  1385.  
  1386.  
  1387.   { ══ TDmxRecInd ════════════════════════════════════════════════════════ }
  1388.  
  1389.  
  1390. constructor TDmxRecInd.Init (var Bounds : TRect;  Len : integer);
  1391. begin
  1392.   TDmxLink.Init (Bounds);
  1393.   GrowMode  := gfGrowLoY or gfGrowHiY;
  1394. end;
  1395.  
  1396.  
  1397. constructor TDmxRecInd.InitInsert (AOwner : PGroup; Len : integer);
  1398. var  R : TRect;
  1399. begin
  1400.   AOwner^.GetExtent (R);
  1401.   Inc (R.A.X);
  1402.   R.A.Y  := pred (R.B.Y);
  1403.   R.Grow (-1, 0);
  1404.   If (R.B.X - R.A.X > Len) then R.B.X := R.A.X + Len;
  1405.   R.B.Y  := succ (R.A.Y);
  1406.   TDmxLink.Init (R);
  1407.   GrowMode  := gfGrowLoY or gfGrowHiY;
  1408.   Insert (AOwner);
  1409. end;
  1410.  
  1411.  
  1412. procedure TDmxRecInd.Draw;
  1413. var  A  : string;
  1414.      B  : TDrawBuffer;
  1415.      C  : word;
  1416. begin
  1417.   C := GetColor (6);
  1418.   MoveChar (B, '═', C, Size.X);
  1419.   Str (succ (Link^.CurrentRecord):1, A);
  1420.   If length (A) > Size.X then
  1421.     MoveChar (B, showOVERFLOW, C, Size.X)
  1422.    else
  1423.     begin
  1424.     If length (A) < Size.X then A := A + ' ';
  1425.     If length (A) < Size.X then A := ' ' + A;
  1426.     MoveStr (B [succ ((Size.X) - length (A)) shr 1], A, C);
  1427.     end;
  1428.   WriteBuf (0, 0, Size.X, 1, B);
  1429. end;
  1430.  
  1431.  
  1432. procedure TDmxRecInd.HandleEvent (var Event : TEvent);
  1433. begin
  1434.   TDmxLink.HandleEvent (Event);
  1435.   With Event do
  1436.     begin
  1437.     If (What and evMouseDown <> 0) then
  1438.       begin
  1439.       Message (Application, evCommand, cmDMX_RecIndClicked, @Self);
  1440.       ClearEvent (Event);
  1441.       end;
  1442.     end;
  1443. end;
  1444.  
  1445.  
  1446. procedure TDmxRecInd.SetState (AState : word;  Enable : boolean);
  1447. begin
  1448.   If (AState and (sfActive or sfDragging) <> 0) then
  1449.     TDmxLink.SetState (sfVisible, Enable xor (AState and sfDragging <> 0));
  1450.   TDmxLink.SetState (AState, Enable);
  1451. end;
  1452.  
  1453.  
  1454.   { ══ TDmxEditor ═══════════════════════════════════════════════════════ }
  1455.  
  1456.  
  1457. constructor TDmxEditor.Init (ATemplate : string;  var AData;  BSize : longint;
  1458.                  var Bounds : TRect;  ALabels,ARecInd  : PDmxLink;
  1459.                  AHScrollBar,AVScrollBar : PScrollBar);
  1460. var  inbounds  : TRect;
  1461. begin
  1462.   TDmxScroller.Init (ATemplate, AData, BSize, Bounds, ALabels, AHScrollBar, AVScrollBar);
  1463.   CurrentField := DMXfield1;
  1464.   While (CurrentField <> nil) and
  1465.     (CurrentField^.access and (accHidden or accSkip or accDelimiter) <> 0)
  1466.    do
  1467.     CurrentField := CurrentField^.Next;
  1468.   CurrentRecord  := 0;
  1469.   RecInd := ARecInd;
  1470.   If RecInd <> nil then
  1471.     begin
  1472.     RecInd^.Link := @Self;
  1473.     If (HScrollBar <> nil) then
  1474.       begin
  1475.       HScrollBar^.GetBounds (inbounds);
  1476.       inbounds.A.X := inbounds.A.X + RecInd^.Size.X + 1;
  1477.       HScrollBar^.Locate (inbounds);
  1478.       end;
  1479.     end;
  1480. end;
  1481.  
  1482.  
  1483. constructor TDmxEditor.Load (var S : TStream);
  1484. var  i,n : integer;
  1485. begin
  1486.   TDmxScroller.Load (S);
  1487.   GetPeerViewPtr (S, RecInd);
  1488.   CurrentField := DMXfield1;
  1489.   S.Read (n, sizeof (n));
  1490.   i := 0;
  1491.   While (i <> n) and (CurrentField <> nil) do
  1492.     begin
  1493.     CurrentField := CurrentField^.Next;
  1494.     Inc (i);
  1495.     end;
  1496.   If CurrentField = nil then CurrentField := DMXfield1;
  1497.   S.Read (Locked, sizeof (Locked));
  1498. end;
  1499.  
  1500.  
  1501. destructor TDmxEditor.Done;
  1502. begin
  1503.   If (CurrentField <> nil) and FieldSelected then EvaluateField;
  1504.   If RecordSelected then EvaluateRecord;
  1505.   TDmxScroller.Done;
  1506. end;
  1507.  
  1508.  
  1509. procedure TDmxEditor.Store (var S : TStream);
  1510. var n  : integer;
  1511.     df : pDMXfieldrec;
  1512. begin
  1513.   TDmxScroller.Store (S);
  1514.   PutPeerViewPtr (S, RecInd);
  1515.   df := DMXfield1;
  1516.   n  := 0;
  1517.   While (df <> CurrentField) do
  1518.     begin
  1519.     df := df^.Next;
  1520.     Inc (n);
  1521.     end;
  1522.   S.Write (n, sizeof (n));
  1523.   S.Write (Locked, sizeof (Locked));
  1524. end;
  1525.  
  1526.  
  1527. procedure TDmxEditor.ChangeBounds (var Bounds : TRect);
  1528. var  i,j    : integer;
  1529.      ReScroll    : boolean;
  1530.      RS,FS    : boolean;
  1531.      xy        : TPoint;
  1532. begin
  1533.   RS := RecordSelected;
  1534.   FS := FieldSelected;
  1535.   If FS then EvaluateField;
  1536.   If RS then EvaluateRecord;
  1537.   TDmxScroller.ChangeBounds (Bounds);
  1538.   ReScroll := FALSE;
  1539.   If CurrentField <> nil then With CurrentField^ do
  1540.     If (template <> nil) then
  1541.       begin
  1542.       xy := Delta;
  1543.       If (Size.X - (screentab - Delta.X) < 0) or
  1544.      (Size.X <= shownwid) then
  1545.     begin
  1546.     xy.X  := screentab + shownwid - Size.X;
  1547.     If (Size.X <= shownwid) then xy.X := screentab else If (xy.X > 0) then Inc (xy.X);
  1548.     ReScroll := TRUE;
  1549.     end
  1550.        else
  1551.     If (Size.X - (screentab + shownwid - Delta.X) < 0) then
  1552.       begin
  1553.       xy.X  := screentab + shownwid - Size.X;
  1554.       ReScroll := TRUE;
  1555.       end;
  1556.       end;
  1557.     If (Size.Y - (CurrentRecord - Delta.Y) <= 0) then
  1558.       begin
  1559.       xy.Y := succ (CurrentRecord - Size.Y);
  1560.       If xy.Y < 0 then xy.Y := 0;
  1561.       ReScroll := TRUE;
  1562.       end;
  1563.   If ReScroll then ScrollTo (xy.X, xy.Y);
  1564.   If RS then SetupRecord;
  1565.   If FS then SetupField;
  1566. end;
  1567.  
  1568.  
  1569. procedure TDmxEditor.ChangeMade;
  1570. begin
  1571.   FieldAltered  := TRUE;
  1572.   RecordAltered := TRUE;
  1573.   JustAltered   := TRUE;
  1574.   DataAltered   := TRUE;
  1575. end;
  1576.  
  1577.  
  1578. function  TDmxEditor.CheckRecLock : boolean;
  1579. begin
  1580.   If not LockChecked then
  1581.     begin
  1582.     RecWasLocked := not SetRecLock;
  1583.     LockChecked  := TRUE;
  1584.     end;
  1585.   CheckRecLock := not RecWasLocked;
  1586. end;
  1587.  
  1588.  
  1589. procedure TDmxEditor.ClearRecLock;
  1590. begin
  1591.   If LockChecked then
  1592.     begin
  1593.     If not RecWasLocked then ResetRecLock;
  1594.     LockChecked := FALSE;
  1595.     end;
  1596.   RecWasLocked := FALSE;
  1597. end;
  1598.  
  1599.  
  1600. procedure TDmxEditor.Draw;
  1601. begin
  1602.   If (Owner <> nil) then Owner^.Lock;
  1603.   TDmxScroller.Draw;
  1604.   If FieldSelected and (showanyway in ShowFmt) then DrawField (CurrentField);
  1605.   If (Owner <> nil) then Owner^.Unlock;
  1606. end;
  1607.  
  1608.  
  1609. procedure TDmxEditor.DrawField (var Field : pDMXfieldrec);
  1610. const
  1611.   rpoint = #16;
  1612.   lpoint = #17;
  1613. var
  1614.   Color  : word;
  1615.   i,j,k  : integer;
  1616.   x1,x2  : integer;
  1617.   Len    : integer;
  1618.   front  : boolean;
  1619.   hyde   : boolean;
  1620.   S      : string;
  1621.   B      : TDrawBuffer;
  1622. begin
  1623.   If (CurrentField = nil) then Exit;
  1624.   If RedrawRecord then
  1625.     begin
  1626.     DrawRecord (CurrentRecord - Delta.Y, RecordData^);
  1627.     RedrawRecord := FALSE;
  1628.     end;
  1629.   hyde := TRUE;
  1630.   With Field^ do If (truelen > 0) or ((template <> nil) and (shownwid > 0)) then
  1631.     begin
  1632.     If (access and (accHidden or accDelimiter) = 0) then
  1633.       begin
  1634.       If (showanyway in ShowFmt) then CurrentCurPos := CurPos;
  1635.       S  := FieldString (Field, ShowFmt, RecordData^);
  1636.       x1 := screentab - Delta.X;
  1637.       x2 := x1 + length (S);
  1638.       If x1 < 0 then
  1639.     begin
  1640.     x1 := 0;
  1641.     front := FALSE;
  1642.     end
  1643.        else
  1644.     front := TRUE;
  1645.       If x2 - x1 > shownwid then x2 := x1 + shownwid;
  1646.       If x2 > Size.X then x2 := Size.X;
  1647.       Len  := x2 - x1;
  1648.       If Len > 0 then
  1649.     begin
  1650.     If not (showregular in ShowFmt) then
  1651.       begin
  1652.       If (access and accReadOnly <> 0) then
  1653.         Color := GetColor (3)
  1654.        else
  1655.         If Locked or RecWasLocked then
  1656.           Color := GetColor (4)
  1657.          else
  1658.           begin
  1659.           hyde := FALSE;
  1660.           Color := GetColor (2);
  1661.           end;
  1662.       If hyde and (Color = GetColor (1)) then Color := Color or $80;
  1663.       FieldText (S, Color, Field, RecordData^);
  1664.       j := 0;
  1665.       k := 0;
  1666.       If (fieldsize > 0) then
  1667.             begin
  1668.             If (upcase (typecode) = fldENUM) then
  1669.           begin
  1670.           For i := length (S) downto 1 do If (S [i] <> ' ') then k := i;
  1671.               end
  1672.              else
  1673.           For i := 1 to length (S) do
  1674.         If (ord (template^ [i]) and $FE = 0) then
  1675.           begin
  1676.           If (CurPos >= j) then k := i;
  1677.           Inc (j);
  1678.           end;
  1679.         end;
  1680.       If k > 0 then
  1681.         begin
  1682.         If CurPos = 0 then FirstPos := 0;
  1683.         If (CurPos = truelen) and (length (S) > Len) then
  1684.           FirstPos := length (S) - Len;
  1685.         If length (S) <= Len then
  1686.           begin
  1687.           FirstPos := 0;
  1688.           end
  1689.          else
  1690.           begin
  1691.           If pred (k) <= FirstPos then
  1692.         begin
  1693.         FirstPos := pred (k);
  1694.         If FirstPos > 0 then
  1695.           begin
  1696.           Delete (S, 1,FirstPos);
  1697.           k := k - FirstPos;
  1698.           end;
  1699.         end
  1700.            else
  1701.         begin
  1702.         j := 0;
  1703.         If FirstPos > 0 then
  1704.           begin
  1705.           Delete (S, 1,FirstPos);
  1706.           k := k - FirstPos;
  1707.           j := FirstPos;
  1708.           end;
  1709.         If length (S) > Len then
  1710.           begin
  1711.           If k > Len then
  1712.             begin
  1713.             i := k - Len;
  1714.             FirstPos := i + j;
  1715.             If i > 0 then Delete (S, 1, i);
  1716.             k := k - i;
  1717.             end;
  1718.           end;
  1719.         end;
  1720.           end;
  1721.         If Len > 3 then
  1722.           begin
  1723.           If (k = Len) and (length (S) > Len) then
  1724.         begin
  1725.         Delete (S, 1,1);
  1726.         Inc (FirstPos);
  1727.         Dec (k);
  1728.         end;
  1729.           If (FirstPos > 0) then
  1730.         begin
  1731.         If k > 1 then S [1] := lpoint
  1732.          else
  1733.           begin
  1734.           System.Insert (lpoint, S, 1);
  1735.           Inc (k);
  1736.           Inc (FirstPos);
  1737.           end;
  1738.         end;
  1739.           If length (S) > Len then S [Len] := rpoint;
  1740.           end;
  1741.         SetCursor (pred (k) + x1, CurrentRecord - Delta.Y);
  1742.         end;
  1743.       end
  1744.      else
  1745.       begin
  1746.       Color := GetColor (1);
  1747.       FieldText (S, Color, Field, RecordData^);
  1748.       If (length (S) > Len) and not front then Delete (S, 1, length (S) - Len);
  1749.       end;
  1750.     MoveStr (B, S, Color);
  1751.     i := CurrentRecord - Delta.Y;
  1752.     WriteLine (x1, i, Len, 1, B);
  1753.     end;
  1754.       end;
  1755.     end;
  1756.   If hyde or (k = 0) then HideCursor else ShowCursor;
  1757. end;
  1758.  
  1759.  
  1760. procedure TDmxEditor.EvaluateField;
  1761. begin
  1762.   ShowFmt   := ShowFmt + [showregular] - [shownegative] - [showanyway];
  1763.   DrawField (CurrentField);
  1764.   ShowFmt   := ShowFmt - [showregular];
  1765.   If FieldAltered then Message (Owner, evBroadcast, cmDMX_FieldAltered, @Self);
  1766.   FieldSelected := FALSE;
  1767. end;
  1768.  
  1769.  
  1770. procedure TDmxEditor.EvaluateRecord;
  1771. begin
  1772.   RecordSelected := FALSE;
  1773.   ClearRecLock;
  1774. end;
  1775.  
  1776.  
  1777. procedure TDmxEditor.GetBlob (Num : integer; var Blob : pointer; var Len : integer);
  1778. var  i   : integer;
  1779.      Fld : pDMXfieldrec;
  1780. begin
  1781.   Blob := nil;
  1782.   Len  := 0;
  1783.   If (Num <= 0) then Exit;
  1784.   i    := 0;
  1785.   Fld  := DMXfield1;
  1786.   While (i < Num) do
  1787.     begin
  1788.     While (Fld <> nil) and (Fld^.typecode <> fldBLOB) do Fld := Fld^.Next;
  1789.     Inc (i);
  1790.     end;
  1791.   If (Fld <> nil) then
  1792.     begin
  1793.     Blob := RecordData;
  1794.     Inc (word (Blob), Fld^.datatab);
  1795.     Len  := Fld^.fieldsize;
  1796.     end;
  1797. end;
  1798.  
  1799.  
  1800. procedure TDmxEditor.GotoPos (AFieldNum,ARecNum : integer);
  1801. var X,Y      : integer;
  1802.     RS,FS : boolean;
  1803.     F      : pDMXfieldrec;
  1804. begin
  1805.   RS := RecordSelected;
  1806.   If RS then
  1807.     begin
  1808.     FS := FieldSelected;
  1809.     If FS then EvaluateField;
  1810.     If (CurrentRecord = ARecNum) then RS := FALSE;
  1811.     If RS then EvaluateRecord;
  1812.     end
  1813.    else
  1814.     FS := FALSE;
  1815.   CurrentRecord := ARecNum;
  1816.   Y := CurrentRecord - (Size.Y shr 1);
  1817.   If (Y < 0) then Y := 0;
  1818.   F := DMXfield1;
  1819.   While (F <> nil) and (F^.fieldnum <> AFieldNum) do F := F^.Next;
  1820.   If (F = nil) or (AFieldNum = 0) then
  1821.     X := Delta.X
  1822.    else
  1823.     begin
  1824.     X := F^.screentab;
  1825.     CurrentField := F;
  1826.     end;
  1827.   If (X > Limit.X) then X := Limit.X;
  1828.   If (Y > Limit.Y) then Y := Limit.Y;
  1829.   ScrollTo (X, Y);
  1830.   If RS then SetupRecord;
  1831.   If FS then SetupField;
  1832. end;
  1833.  
  1834.  
  1835. procedure TDmxEditor.HandleEvent (var Event : TEvent);
  1836. var  XY    : TPoint;
  1837.      Cmd: word;
  1838.      RS,FS : boolean;
  1839.     function  OK4Command : boolean;
  1840.     begin
  1841.       With Event do
  1842.     OK4Command := (What = evCommand) or (InfoPtr = nil) or
  1843.       ((PDmxScroller (InfoPtr)^.WorkingData = WorkingData));
  1844.     end;
  1845. begin
  1846.   RS := FALSE;
  1847.   FS := FALSE;
  1848.   With Event do
  1849.     begin
  1850.     If not GetState (sfDragging) then
  1851.       begin
  1852.       If (What = evKeyDown) and (CharCode in [^M,^T,^Y]) then
  1853.     begin
  1854.     Case CharCode of
  1855.       ^M:    Cmd := cmDMX_Enter;
  1856.       ^Y:    Cmd := cmDMX_ZeroizeRecord;
  1857.      else   Cmd := cmDMX_ZeroizeField;
  1858.       end;
  1859.     Message (TopView, evCommand, Cmd, @Self);
  1860.     ClearEvent (Event);
  1861.     end;
  1862.       Case What of
  1863.     evNothing:   begin end;
  1864.     evMouseDown: ProcessMouse (Event);
  1865.     evKeyDown:
  1866.         If (KeyCode <> kbEsc) and (Size.Y > 0) and (What = evKeyDown) then
  1867.           ProcessKey (Event);
  1868.     evCommand:
  1869.         If (Command >= cmDMX_ZeroizeField) and (Command <= cmDMX_Bottom)
  1870.         and Valid (Command)
  1871.          then
  1872.           begin
  1873.           If Command = cmDMX_Enter then ProcessEnter (Event);
  1874.           If (Command <> 0) then ProcessCommand (Command, XY);
  1875.           If (Command = 0) then ClearEvent (Event);
  1876.           end;
  1877.     end;
  1878.       end;
  1879.     If (What and evMessage <> 0) then
  1880.       If ((Command = cmDMX_DrawData) and (WorkingData = InfoPtr)) or
  1881.      ((Command = cmDMX_LockData) and (WorkingData = InfoPtr)) or
  1882.      ((Command = cmDMX_UnlockData) and (WorkingData = InfoPtr)) or
  1883.      ((Command = cmDMX_Draw) and OK4Command) or
  1884.      ((Command = cmDMX_Lock) and OK4Command) or
  1885.      ((Command = cmDMX_Unlock) and OK4Command)
  1886.        then
  1887.     begin
  1888.     RS := RecordSelected;
  1889.     If RS then
  1890.       begin
  1891.       FS := FieldSelected;
  1892.       If FS then EvaluateField;
  1893.       EvaluateRecord;
  1894.       end;
  1895.     end;
  1896.     end;
  1897.   If (Event.What <> evNothing) then
  1898.     begin
  1899.     If (Event.What = evKeyDown) and ((Size.X <= 0) or (Size.Y <= 0)) then
  1900.       TView.HandleEvent (Event) else TDmxScroller.HandleEvent (Event);
  1901.     end;
  1902.   If RS then
  1903.     begin
  1904.     SetupRecord;
  1905.     If FS then SetupField;
  1906.     end;
  1907. end;
  1908.  
  1909.  
  1910. procedure TDmxEditor.ProcessCommand (var Command : word;  XY : TPoint);
  1911. var
  1912.   i,j   : word;
  1913.   xx,yy : integer;
  1914.   DoIt  : integer;
  1915.   F     : pDMXfieldrec;
  1916.   RS,FS,Chg : boolean;
  1917.  
  1918.     procedure DoHome;
  1919.     begin
  1920.       F := DMXfield1;
  1921.       If F <> nil then
  1922.     begin
  1923.     While (F^.access and (accHidden or accSkip or accDelimiter) <> 0)
  1924.       and (F^.Next <> nil)
  1925.      do
  1926.       F := F^.Next;
  1927.     CurrentField := F;
  1928.     end;
  1929.       If CurrentField <> nil then With CurrentField^ do
  1930.     begin
  1931.     xx := 0;
  1932.     If (screentab + shownwid - 1 > Size.X) then xx := screentab;
  1933.     end;
  1934.     end;
  1935.  
  1936. begin
  1937.   RS    := RecordSelected;
  1938.   FS    := FieldSelected;
  1939.   If (Command = cmDMX_ZeroizeField) then
  1940.     begin
  1941.     If FS then Chg := TRUE else Exit;
  1942.     end
  1943.    else
  1944.     Chg    := FALSE;
  1945.   DoIt    :=  0;
  1946.   xx    := Delta.X;
  1947.   yy    := Delta.Y;
  1948.   If (Command >= cmDMX_Enter) and (Command <= cmDMX_Bottom) then
  1949.     begin
  1950.     If FS then EvaluateField;
  1951.     DoIt  :=  1;
  1952.     If (Command > cmDMX_goto) then
  1953.       begin
  1954.       If RS then EvaluateRecord;
  1955.       DoIt  :=  2;
  1956.       end;
  1957.     end;
  1958.   If ReDrawRecord then
  1959.     begin
  1960.     DrawRecord (CurrentRecord - Delta.Y, RecordData^);
  1961.     ReDrawRecord := FALSE;
  1962.     end;
  1963.  
  1964.   Case Command of
  1965.  
  1966.     cmDMX_ZeroizeField:
  1967.     begin
  1968.     If FieldSelected then
  1969.       begin
  1970.       EvaluateField;
  1971.       SetupField;
  1972.       end;
  1973.     ZeroizeField (TRUE, CurrentField);
  1974.     end;
  1975.  
  1976.     cmDMX_ZeroizeRecord:
  1977.     begin
  1978.     If FieldSelected then
  1979.       begin
  1980.       EvaluateField;
  1981.       SetupField;
  1982.       end;
  1983.     ZeroizeRecord;
  1984.     end;
  1985.  
  1986.     cmDMX_Left:
  1987.     If CurrentField <> DMXfield1 then
  1988.       begin
  1989.       F := CurrentField^.Prev;
  1990.       While (F <> nil) and (F^.access and (accHidden or accSkip or accDelimiter) <> 0)
  1991.        do
  1992.         begin
  1993.         If F = DMXfield1 then F := nil else F := F^.Prev;
  1994.         end;
  1995.       If F <> nil then CurrentField := F;
  1996.       If CurrentField <> nil then With CurrentField^ do
  1997.         begin
  1998.         If (screentab < xx) then
  1999.           begin
  2000.           xx := screentab;
  2001.           If (xx > 0) and (Size.X > shownwid) then Dec (xx);
  2002.           end;
  2003.         end;
  2004.       end;
  2005.  
  2006.     cmDMX_Right:
  2007.     begin
  2008.     F := CurrentField^.Next;
  2009.     While (F <> nil) and (F^.access and (accHidden or accSkip or accDelimiter) <> 0)
  2010.      do F := F^.Next;
  2011.     If F <> nil then CurrentField := F;
  2012.     If CurrentField <> nil then With CurrentField^ do
  2013.       begin
  2014.       If (screentab + shownwid - 1 > xx + pred (Size.X)) then
  2015.         begin
  2016.         xx := screentab + shownwid - Size.X;
  2017.         If (xx < Limit.X) and (Size.X > shownwid) then Inc (xx);
  2018.         end;
  2019.       end;
  2020.     end;
  2021.  
  2022.     cmDMX_Home:  DoHome;
  2023.  
  2024.     cmDMX_End:
  2025.     begin
  2026.     F := CurrentField;
  2027.     If F <> nil then
  2028.       begin
  2029.       While (F^.Next <> nil) do F := F^.Next;
  2030.       While (F^.access and (accHidden or accSkip or accDelimiter) <> 0)
  2031.         and (F^.Prev <> nil)
  2032.        do
  2033.         F := F^.Prev;
  2034.       CurrentField := F;
  2035.       xx := Limit.X;
  2036.       With CurrentField^ do
  2037.         If (screentab < xx) then
  2038.           begin
  2039.           xx := screentab;
  2040.           If (xx > 0) and (Size.X > shownwid) then Dec (xx);
  2041.           end;
  2042.       end;
  2043.     end;
  2044.  
  2045.     cmDMX_goto:
  2046.     begin
  2047.     F := CurrentField;
  2048.     DoubleValid := FALSE;
  2049.     If F <> nil then
  2050.       begin
  2051.       While (F <> nil) and ((F^.access and accHidden <> 0) or (F^.screentab < XY.x))
  2052.          and (F^.Next <> nil)
  2053.        do F := F^.Next;
  2054.       If (F <> nil) then
  2055.         begin
  2056.         While (F <> nil) and ((F^.access and accHidden <> 0) or (F^.screentab > XY.x))
  2057.          do F := F^.Prev;
  2058.         If (F <> nil) and (F^.access and (accDelimiter or accSkip) = 0) then
  2059.           begin
  2060.           DoubleValid := TRUE;
  2061.           With F^ do
  2062.         begin
  2063.         If (screentab < xx) then
  2064.           begin
  2065.           xx := screentab;
  2066.           If (xx > 0) and (Size.X > shownwid) then Dec (xx);
  2067.           end
  2068.          else
  2069.           begin
  2070.           If (screentab + shownwid - 1 > xx + pred (Size.X)) then
  2071.             begin
  2072.             xx := screentab + shownwid - Size.X;
  2073.             If (xx < Limit.X) and (Size.X > shownwid) then Inc (xx);
  2074.             end;
  2075.           end;
  2076.         end;
  2077.           If (CurrentRecord = XY.y) then
  2078.         CurrentField := F
  2079.            else
  2080.         begin
  2081.         If RS then EvaluateRecord;
  2082.         DoIt  :=  2;
  2083.         If ReDrawRecord then
  2084.           begin
  2085.           DrawRecord (CurrentRecord - Delta.Y, RecordData^);
  2086.           ReDrawRecord := FALSE;
  2087.           end;
  2088.         CurrentField  :=  F;
  2089.         CurrentRecord := XY.y;
  2090.         If CurrentRecord >= Limit.Y then CurrentRecord := pred (Limit.Y);
  2091.         end;
  2092.           end;
  2093.         end;
  2094.       end;
  2095.     end;
  2096.  
  2097.     cmDMX_NextRow:
  2098.     begin
  2099.     If succ (CurrentRecord) < Limit.Y then
  2100.       begin
  2101.       Inc (CurrentRecord);
  2102.       If yy + Size.Y <= CurrentRecord then
  2103.         yy := CurrentRecord - Size.Y + 1;
  2104.       If yy < 0 then yy := 0;
  2105.       end;
  2106.     DoHome;
  2107.     end;
  2108.  
  2109.     cmDMX_Up:
  2110.     begin
  2111.     If CurrentRecord > 0 then
  2112.       begin
  2113.       Dec (CurrentRecord);
  2114.       If yy > CurrentRecord then yy := CurrentRecord;
  2115.       end;
  2116.     end;
  2117.  
  2118.     cmDMX_Down:
  2119.     begin
  2120.     If succ (CurrentRecord) < Limit.Y then
  2121.       begin
  2122.       Inc (CurrentRecord);
  2123.       If yy + Size.Y <= CurrentRecord then
  2124.         yy := CurrentRecord - Size.Y + 1;
  2125.       If yy < 0 then yy := 0;
  2126.       end;
  2127.     end;
  2128.  
  2129.     cmDMX_PgUp:
  2130.     begin
  2131.     CurrentRecord := CurrentRecord - Size.Y + 1;
  2132.     If CurrentRecord < 0 then CurrentRecord := 0;
  2133.     yy := yy - Size.Y + 1;
  2134.     If yy < 0 then
  2135.       begin
  2136.       yy := 0;
  2137.       CurrentRecord := 0;
  2138.       end;
  2139.     end;
  2140.  
  2141.     cmDMX_PgDn:
  2142.     begin
  2143.     CurrentRecord := CurrentRecord + Size.Y - 1;
  2144.     If CurrentRecord >= Limit.Y then
  2145.       CurrentRecord := pred (Limit.Y);
  2146.     If CurrentRecord < 0 then CurrentRecord := 0;
  2147.     yy := yy + Size.Y - 1;
  2148.     If yy < 0 then
  2149.       begin
  2150.       yy := 0;
  2151.       CurrentRecord := 0;
  2152.       end;
  2153.     If yy > Limit.Y + Size.Y - 1 then yy := Limit.Y + Size.Y - 1;
  2154.     end;
  2155.  
  2156.     cmDMX_ScreenTop:  CurrentRecord := Delta.Y;
  2157.  
  2158.     cmDMX_ScreenBottom:
  2159.     begin
  2160.     CurrentRecord := Delta.Y + Size.Y - 1;
  2161.     If CurrentRecord > Limit.Y then CurrentRecord := pred (Limit.Y);
  2162.     end;
  2163.  
  2164.     cmDMX_Top:
  2165.     begin
  2166.     CurrentRecord := 0;
  2167.     yy := 0;
  2168.     end;
  2169.  
  2170.     cmDMX_Bottom:
  2171.     begin
  2172.     CurrentRecord := pred (Limit.Y);
  2173.     If CurrentRecord < 0 then CurrentRecord := 0;
  2174.     yy := pred (Limit.Y);
  2175.     end;
  2176.  
  2177.    else begin  end;
  2178.  
  2179.     end;
  2180.  
  2181.   If DoIt <> 0 then
  2182.     begin
  2183.     If (xx <> Delta.X) or (yy <> Delta.Y) then ScrollTo (xx, yy);
  2184.     Command := 0;
  2185.     If (DoIt > 1) and RS then SetUpRecord;
  2186.     If (DoIt > 0) and FS then
  2187.       begin
  2188.       SetUpField;
  2189.       end;
  2190.     end;
  2191.   If Chg then ChangeMade;
  2192.   If ReDrawRecord then DrawField (CurrentField);
  2193. end;
  2194.  
  2195.  
  2196. procedure TDmxEditor.ProcessEnter (var Event : TEvent);
  2197.  
  2198.     function  NextFieldExists : boolean;
  2199.     var  F : pDMXfieldrec;
  2200.     begin
  2201.       F := CurrentField^.Next;
  2202.       While (F <> nil) and
  2203.         (F^.access and (accHidden or accSkip or accDelimiter) <> 0)
  2204.        do  F := F^.Next;
  2205.       NextFieldExists := (F <> nil);
  2206.     end;
  2207.  
  2208. begin
  2209.   If NextFieldExists then
  2210.     Event.Command := cmDMX_Right
  2211.    else
  2212.     begin
  2213.     Event.What := evCommand;
  2214.     Event.Command := cmDMX_NextRow;
  2215.     HandleEvent (Event);
  2216.     ClearEvent (Event);
  2217.     end;
  2218. end;
  2219.  
  2220.  
  2221. procedure TDmxEditor.ProcessKey (var Event : TEvent);
  2222. var i,j,k : integer;
  2223.     inx   : integer;
  2224.     TC    : char;
  2225.     Go    : boolean;
  2226.     InsOn : boolean;
  2227.     A     : string [80];
  2228.     DFld  : pDMXfieldrec;
  2229.  
  2230.   procedure QuitField (Command : word);
  2231.   begin
  2232.     Event.What    := evCommand;
  2233.     Event.Command := Command;
  2234.     HandleEvent (Event);
  2235.     Event.KeyCode := kbNoKey;
  2236.     ClearEvent (Event);
  2237.   end;
  2238.  
  2239.   procedure SetBoolean (B : boolean);
  2240.   begin
  2241.     pboolean (FieldData)^ := B;
  2242.     ChangeMade;
  2243.     DrawField (CurrentField);
  2244.     If not (Event.CharCode in [^G,^H]) then QuitField (cmDMX_Enter);
  2245.   end;
  2246.  
  2247.   function  HexByte (Number : byte)  : string;
  2248.   const bts  : array [0..15] of char = '0123456789ABCDEF';
  2249.   begin
  2250.     HexByte := bts [(Number shr 4) and $0F] + bts [Number and $0F]
  2251.   end;
  2252.  
  2253.   function  EffectField (HEX : boolean;  Min,Max : longint)  : boolean;
  2254.   var i,j    : integer;
  2255.       FirstChar : integer;
  2256.       b        : boolean;
  2257.       R        : real;
  2258.   begin
  2259.     b := FALSE;
  2260.     If not ((Event.CharCode in [^G,^H,'.','-','_','0'..'9']) or
  2261.        (HEX and (upcase (Event.CharCode) in ['A'..'F'])))
  2262.     or (CurrentField^.access and accReadOnly <> 0)
  2263.     or (Locked) or (not CheckRecLock)
  2264.      then
  2265.       begin
  2266.       WrongKeypressed (Event);
  2267.       end
  2268.      else
  2269.       If A <> '' then With CurrentField^ do
  2270.     begin
  2271.     If (upperlimit <> 0) and (Max > upperlimit) then Max := upperlimit;
  2272.     If (decimals > 0) then i := succ (truelen) else i := truelen;
  2273.     If not HEX and (length (A) > i) then
  2274.       begin
  2275.       A [0] := chr (i);
  2276.       fillchar (A [1], length (A), '0');
  2277.       If length (A) - decimals > 2 then
  2278.         fillchar (A [1], length (A) - decimals - 2, ' ');
  2279.       If decimals > 0 then A [length (A) - decimals] := '.';
  2280.       end;
  2281.     If typecode in ['A'..'Z'] then Min := 0;
  2282.     FirstChar := pos ('.', A);
  2283.     If FirstChar > 0 then Dec (FirstChar) else FirstChar := length (A);
  2284.     If CurPos < pred (FirstChar) then CurPos := pred (FirstChar);
  2285.     Case Event.CharCode of
  2286.       ^G,
  2287.       ^H  :
  2288.           begin
  2289.           If CurPos = pred (FirstChar) then
  2290.         begin
  2291.         If (FirstChar < length (A)) then
  2292.           fillchar (A [FirstChar + 2], length (A) - succ (FirstChar), '0');
  2293.         If FirstChar > 1 then
  2294.           begin
  2295.           Move (A [1], A [2], pred (FirstChar));
  2296.           If HEX then A [1] := '0' else A [1] := ' ';
  2297.           If A [FirstChar] = '-' then
  2298.             begin
  2299.             A [FirstChar] := '0';
  2300.             ShowFmt := ShowFmt - [shownegative];
  2301.             end;
  2302.           end
  2303.          else
  2304.           begin
  2305.           A [1] := '0';
  2306.           end;
  2307.         end
  2308.            else
  2309.         begin
  2310.         A [succ (CurPos)] := '0';
  2311.         Dec (CurPos);
  2312.         If CurPos = FirstChar then Dec (CurPos);
  2313.         end;
  2314.           b := FALSE;
  2315.           For i := 1 to length (A) do If A [i] > '0' then b := TRUE;
  2316.           If not b then ShowFmt := ShowFmt - [shownegative];
  2317.           b := TRUE;
  2318.               If (A [FirstChar] = ' ') then A [FirstChar] := '0';
  2319.           end;
  2320.       '.' :
  2321.           begin
  2322.           If FirstChar < length (A) then
  2323.         begin
  2324.         CurPos := FirstChar;
  2325.         fillchar (A [FirstChar + 2], length (A) - succ (FirstChar), '0');
  2326.         b := TRUE;
  2327.         end
  2328.            else WrongKeypressed (Event);
  2329.           end;
  2330.       '-','_' :
  2331.           begin
  2332.           If (Min <> 0) and (A [1] = ' ') and
  2333.          (FirstChar > 1) and (pos ('-', A) = 0) then
  2334.         begin
  2335.         i := pred (FirstChar);
  2336.         ShowFmt := ShowFmt + [shownegative];
  2337.         While (A [i] <> ' ') do Dec (i);
  2338.         A [i] := '-';
  2339.         b := TRUE;
  2340.         end
  2341.            else WrongKeypressed (Event);
  2342.           end;
  2343.      else begin
  2344.           If (shownegative in ShowFmt) and (pos ('-',A) = 0) then
  2345.         begin
  2346.         If A [1] = ' ' then
  2347.           begin
  2348.           i := FirstChar;
  2349.           While (A [i] <> ' ') do Dec (i);
  2350.           If i <> 0 then A [i] := '-';
  2351.           end;
  2352.         end;
  2353.           If CurPos = pred (FirstChar) then
  2354.         begin
  2355.         If A [1] in [' ','0'] then
  2356.           begin
  2357.           If (FirstChar > 1) and not ((A [FirstChar] = '0') and (A [pred (FirstChar)] in ['-',' ']))
  2358.            then Move (A [2], A [1], pred (FirstChar));
  2359.           A [FirstChar] := Event.CharCode;
  2360.           b := TRUE;
  2361.           end;
  2362.         end
  2363.            else
  2364.         begin
  2365.         A [succ (CurPos) + 1] := Event.CharCode;
  2366.         If pred (length (A)) > CurPos then Inc (CurPos);
  2367.         b := TRUE;
  2368.         end;
  2369.           If (Max > 0) then
  2370.         begin
  2371.         Val (A, R, i);
  2372.         If (i <> 0) or (R > Max) or (R < Min) then b := FALSE;
  2373.         end
  2374.            else
  2375.         begin
  2376.         If (TC = fldCHARVAL) and parenthesis and (A [1] > '-') then b := FALSE;
  2377.         end;
  2378.           If not b then WrongKeypressed (Event);
  2379.           end;
  2380.       end;
  2381.     end;
  2382.     If b then
  2383.       begin
  2384.       ChangeMade;
  2385.       end;
  2386.     EffectField := b;
  2387.   end;
  2388.  
  2389.   procedure EditEnumField;
  2390.   var  i,j  : integer;
  2391.        Pick : PSItem;
  2392.        C    : char;
  2393.  
  2394.       function  MaxItems : integer;
  2395.       var  i     : integer;
  2396.            Items : PSItem;
  2397.       begin
  2398.         Items := PSItem (CurrentField^.template);
  2399.         i := 0;
  2400.         While (Items^.Next <> nil) do
  2401.           begin
  2402.           Items := Items^.Next;
  2403.           inc (i);
  2404.           end;
  2405.         MaxItems := i;
  2406.       end;
  2407.  
  2408.   begin
  2409.     If (CurrentField^.access and accReadOnly <> 0)
  2410.       or Locked or not CheckRecLock then
  2411.       begin
  2412.       WrongKeypressed (Event);
  2413.       end
  2414.      else
  2415.       begin
  2416.       Event.CharCode := upcase (Event.CharCode);
  2417.       Case Event.CharCode of
  2418.     ^M:   QuitField (cmDMX_Enter);
  2419.     'A'..'Z':
  2420.       begin
  2421.       Pick := PSItem (CurrentField^.template);
  2422.       j    := 0;
  2423.       While (Pick <> nil) do
  2424.         begin
  2425.         i :=  1;
  2426.         C := #0;
  2427.         While (Pick^.Value <> nil) and (i < length (Pick^.Value^)) and (C = #0) do
  2428.           begin
  2429.           If (Pick^.Value^ [i] in ['A'..'Z']) then C := upcase (Pick^.Value^ [i]);
  2430.           Inc (i);
  2431.           end;
  2432.         If (C = Event.CharCode) then
  2433.           begin
  2434.           pbyte (FieldData)^ := j;
  2435.           ChangeMade;
  2436.           Pick := nil;
  2437.           end
  2438.          else
  2439.           begin
  2440.           Inc (j);
  2441.           Pick := Pick^.Next;
  2442.           end;
  2443.         end;
  2444.       end;
  2445.     '+','*',' ':
  2446.       begin
  2447.       Inc (pbyte (FieldData)^);
  2448.           If (pbyte (FieldData)^ > MaxItems) then pbyte (FieldData)^ := 0;
  2449.       ChangeMade;
  2450.       end;
  2451.     ^G, ^H,'-':
  2452.       begin
  2453.           If (pbyte (FieldData)^ = 0) then
  2454.             pbyte (FieldData)^ := MaxItems else Dec (pbyte (FieldData)^);
  2455.       ChangeMade;
  2456.       end;
  2457.        else WrongKeypressed (Event);
  2458.     end;
  2459.       end;
  2460.   end;
  2461.  
  2462.   function  AnotherView (View : PView) : boolean;  far;
  2463.   begin
  2464.     AnotherView := (View^.Options and ofSelectable <> 0) and (View <> @Self);
  2465.   end;
  2466.  
  2467. begin
  2468.   If (DataBlockSize < RecordSize) or (RecordSize <= 0) then Exit;
  2469.   If (Event.KeyCode = kbTab) or (Event.KeyCode = kbShiftTab) then
  2470.     begin
  2471.     If (Owner^.FirstThat (@AnotherView) = nil) then
  2472.       begin
  2473.       If (Event.KeyCode = kbTab) then QuitField (cmDMX_Right) else QuitField (cmDMX_Left);
  2474.       end;
  2475.     Exit;
  2476.     end;
  2477.   If Locked or RecWasLocked or (CurrentField^.access and accReadOnly <> 0) then FirstKey := TRUE;
  2478.   InsOn        := not GetState (sfCursorIns);
  2479.   Go        := TRUE;
  2480.   If CurrentField = nil then CurrentField := DMXfield1;
  2481.   If (Event.What = evKeyDown) then
  2482.     begin
  2483.     If (Event.KeyCode = kbShiftEnter) then Exit;
  2484.     If (Event.KeyCode = kbShiftIns) then Event.CharCode := '0';
  2485.     If (Event.KeyCode = kbShiftDel) then Event.CharCode := '.';
  2486.     With CurrentField^ do
  2487.       begin
  2488.       TC := upcase (typecode);
  2489.       If (Event.KeyCode = kbEsc) or (Event.KeyCode = kbEnter) then
  2490.     begin
  2491.     QuitField (cmDMX_Enter);
  2492.     end
  2493.        else
  2494.     begin
  2495.     Event.KeyCode := CtrlToArrow (Event.KeyCode);
  2496.     If (FirstKey and InsOn) or
  2497.        (Locked or (CurrentField^.access and accReadOnly <> 0)) then
  2498.       begin
  2499.       If Event.KeyCode = kbRight then Event.KeyCode := kbCtrlRight
  2500.       else
  2501.       If Event.KeyCode = kbLeft  then Event.KeyCode := kbCtrlLeft;
  2502.       end
  2503.      else
  2504.       If (TC in [fldSTR,fldSTRNUM,fldCHAR,fldCHARNUM]) then
  2505.         begin
  2506.         If Event.KeyCode = kbRight then Event.CharCode := ^D else
  2507.         If Event.KeyCode = kbLeft  then Event.CharCode := ^S;
  2508.         end;
  2509.     If (Event.KeyCode = kbDel) then Event.CharCode := ^G;
  2510.     If (Event.CharCode <> #0) then
  2511.       begin
  2512.       If FirstKey
  2513.         and (upcase (Event.CharCode) in ['-','.','0'..'9','A'..'F'])
  2514.         and (access and accReadOnly = 0)
  2515.        then
  2516.         begin
  2517.         If (TC in [fldBYTE, fldSHORTINT, fldWORD, fldINTEGER,
  2518.                fldLONGINT, fldCHARVAL, fldREALNUM, fldHEXVALUE])
  2519.          then ZeroizeField (FALSE, CurrentField);
  2520.         end;
  2521.       Case TC of
  2522.         fldSTR,
  2523.         fldSTRNUM,
  2524.         fldCHAR,
  2525.         fldCHARNUM :
  2526.           begin
  2527.           If typecode < 'a' then Event.CharCode := upcase (Event.CharCode);
  2528.           If ((TC in [fldSTRNUM, fldCHARNUM]) and
  2529.          not (Event.CharCode in [#0..'9'])) or Locked
  2530.           or (access and accReadOnly <> 0)
  2531.           or not CheckRecLock then
  2532.         begin
  2533.         WrongKeypressed (Event);
  2534.         Go  := FALSE;
  2535.         end
  2536.            else
  2537.         begin
  2538.         If TC in [fldSTR, fldSTRNUM] then inx := 1 else inx := 0;
  2539.         Case Event.CharCode of
  2540.           ^G,    { kbDel }
  2541.           ^H  :  { kbBack }
  2542.             begin
  2543.             If Event.CharCode = ^H then
  2544.               begin
  2545.               If CurPos = 0 then Go := FALSE else Dec (CurPos);
  2546.               end;
  2547.             If Go then
  2548.               begin
  2549.               If (inx > 0) and (length (pstring (FieldData)^) <= CurPos) then Go := FALSE;
  2550.               If Go then
  2551.             begin
  2552.             ChangeMade;
  2553.             Move (pstring (FieldData)^ [CurPos + inx + 1],
  2554.                   pstring (FieldData)^ [CurPos + inx], fieldsize - CurPos - inx);
  2555.             pstring (FieldData)^ [pred (fieldsize)] := fillvalue;
  2556.             If (inx <> 0) and (pbyte (FieldData)^ > 0) then Dec (pstring (FieldData)^ [0]);
  2557.             end;
  2558.               end;
  2559.             end;
  2560.           ^D  :  { kbRight }
  2561.             If CurPos < fieldsize - inx - 1 then Inc (CurPos) else QuitField (cmDMX_Right);
  2562.           ^S  :  { kbLeft }
  2563.             begin
  2564.             If (CurPos > 0) then Dec (CurPos) else QuitField (cmDMX_Left);
  2565.             end;
  2566.           ^A..^Z  :  { prevent ctrl-characters from being entered }
  2567.             begin
  2568.             end;
  2569.            else begin
  2570.             If inx = 0 then i := fieldsize else i := pbyte (FieldData)^;
  2571.             If InsOn then
  2572.               begin
  2573.               If (fieldsize = succ (inx)) then pstring (FieldData)^ [inx] := fillvalue;
  2574.               If (ord (pstring (FieldData)^ [pred (fieldsize)]) and $DF = 0)
  2575.               or
  2576.              ((inx = 1) and (length (pstring (FieldData)^) < pred (fieldsize)))
  2577.                then
  2578.             begin
  2579.             ChangeMade;
  2580.             If (inx <> 0) then
  2581.               begin
  2582.               If (CurPos > i) then
  2583.                 begin
  2584.                 fillchar (pstring (FieldData)^ [succ (i)],
  2585.                       CurPos - i, fillvalue);
  2586.                 pbyte (FieldData)^ := succ (CurPos);
  2587.                 end
  2588.                else
  2589.                 Inc (pbyte (FieldData)^);
  2590.               end;
  2591.             If succ (CurPos) + inx < fieldsize then
  2592.               Move (pstring (FieldData)^ [CurPos + inx],
  2593.                 pstring (FieldData)^ [CurPos + inx + 1],
  2594.                 fieldsize - CurPos - inx - 1);
  2595.             pstring (FieldData)^ [CurPos + inx] := Event.CharCode;
  2596.             end
  2597.                else
  2598.             begin
  2599.             WrongKeypressed (Event);
  2600.             Go := FALSE;
  2601.             end;
  2602.               end
  2603.              else
  2604.               begin
  2605.               ChangeMade;
  2606.               If (inx <> 0) and (CurPos >= i) then
  2607.             begin
  2608.             fillchar (pstring (FieldData)^ [succ (i)],
  2609.                   CurPos - i, fillvalue);
  2610.             pbyte (FieldData)^ := succ (CurPos);
  2611.             end;
  2612.               pstring (FieldData)^ [CurPos + inx] := Event.CharCode;
  2613.               end;
  2614.             If CurPos < fieldsize - inx - 1 then
  2615.               begin
  2616.               If Go then Inc (CurPos);
  2617.               end
  2618.              else QuitField (cmDMX_Right);
  2619.             end;
  2620.           end;  { case of CharCode }
  2621.         If (CurPos < FirstPos) then FirstPos := CurPos;
  2622.         end;
  2623.           end;
  2624.  
  2625.         fldCHARVAL :
  2626.           begin
  2627.           Move (FieldData^, A [1], fieldsize);
  2628.           A [0] := chr (fieldsize);
  2629.           j := 0;
  2630.           For i := 1 to fieldsize do
  2631.         begin
  2632.         If (ord (A [i]) and not $20 = 0) then A [i] := ' ' else
  2633.         If (A [i] in ['-', '.', '0'..'9']) then j := 1;
  2634.         end;
  2635.           If j = 0 then
  2636.         begin
  2637.         fillchar (A [1], fieldsize, '0');
  2638.         If fieldsize - decimals > 2 then fillchar (A [1], fieldsize - decimals - 2, ' ');
  2639.         If decimals > 0 then A [fieldsize - decimals] := '.';
  2640.         end;
  2641.           If EffectField (FALSE, -1, 0) then
  2642.         begin
  2643.         i := 1;
  2644.         While (i < length (A)) and (A [i] <= '.') do
  2645.           begin
  2646.           If (A [succ (i)] <> '.') then A [i] := CurrentField^.fillvalue;
  2647.           Inc (i);
  2648.           end;
  2649.         Move (A [1], FieldData^, fieldsize);
  2650.         end;
  2651.           end;
  2652.  
  2653.         fldBYTE :
  2654.           begin
  2655.           Str (pbyte (FieldData)^:truelen, A);
  2656.           If EffectField (FALSE, 0,255) then Val (A,pbyte (FieldData)^,i);
  2657.           end;
  2658.  
  2659.         fldSHORTINT :
  2660.           begin
  2661.           Str (pshortint (FieldData)^:truelen, A);
  2662.           If EffectField (FALSE, -128,127) then Val (A,pshortint (FieldData)^,i);
  2663.           end;
  2664.  
  2665.         fldWORD :
  2666.           begin
  2667.           Str (pword (FieldData)^:truelen, A);
  2668.           If EffectField (FALSE, 0,65535) then Val (A,pword (FieldData)^,i);
  2669.           end;
  2670.  
  2671.         fldINTEGER :
  2672.           begin
  2673.           Str (pinteger (FieldData)^:truelen, A);
  2674.           If EffectField (FALSE, -1 - MaxInt, MaxInt) then Val (A,pinteger (FieldData)^,i);
  2675.           end;
  2676.  
  2677.         fldLONGINT :
  2678.           begin
  2679.           Str (plongint (FieldData)^:truelen, A);
  2680.           If EffectField (FALSE, -1 - MaxLongInt, MaxLongInt) then
  2681.         Val (A,plongint (FieldData)^,i);
  2682.           end;
  2683.  
  2684.         fldREALNUM :
  2685.           begin
  2686.           If decimals > 0 then i := 1 else i := 0;
  2687.           Str (prealnum (FieldData)^:truelen + i:decimals, A);
  2688.           If EffectField (FALSE, -1, 0) then Val (A,prealnum (FieldData)^,i);
  2689.           end;
  2690.  
  2691.         fldENUM:
  2692.           begin
  2693.           EditEnumField;
  2694.           end;
  2695.  
  2696.         fldBOOLEAN:
  2697.           begin
  2698.           If (access and accReadOnly <> 0) or Locked or not CheckRecLock then
  2699.         begin
  2700.         WrongKeypressed (Event);
  2701.         end
  2702.            else
  2703.         begin
  2704.         Event.CharCode := upcase (Event.CharCode);
  2705.         If (Event.CharCode >= ' ') then
  2706.           begin
  2707.           If pboolean (FieldData)^ then
  2708.             Event.CharCode := '-' else Event.CharCode := '+';
  2709.           end;
  2710.         Case Event.CharCode of
  2711.           '+' : SetBoolean (TRUE);
  2712.           ^G, ^H,
  2713.           '-' : SetBoolean (FALSE);
  2714.          else WrongKeypressed (Event);
  2715.           end;
  2716.         end;
  2717.           end;
  2718.  
  2719.         fldHEXVALUE :
  2720.           begin
  2721.           Event.CharCode := upcase (Event.CharCode);
  2722.           If Event.CharCode in [^G,^H, '0'..'9', 'A'..'F'] then
  2723.         begin
  2724.         A  := '';
  2725.         For i := 1 to fieldsize do A := hexbyte (ord (pstring (FieldData)^ [pred (i)])) + A;
  2726.         If (length (A) > truelen) then Delete (A, 1,1);
  2727.         If EffectField (TRUE, 0, 0) then
  2728.           begin
  2729.           If odd (length (A)) then A [0] := '0' else Move (A [1], A [0], length (A));
  2730.           For i := 0 to pred (fieldsize) do
  2731.             begin
  2732.             j := ord (A [i shl 1]);
  2733.             k := ord (A [succ (i shl 1)]);
  2734.             If j > ord ('9') then Dec (j, 7);
  2735.             If k > ord ('9') then Dec (k, 7);
  2736.             pstring (FieldData)^ [pred (fieldsize) - i] := chr (((j and 15) shl 4) or (k and 15));
  2737.             end;
  2738.           end;
  2739.         end
  2740.            else
  2741.         begin
  2742.         WrongKeypressed (Event);
  2743.         end;
  2744.           end;
  2745.         end;
  2746.       end;
  2747.     If Event.What <> evNothing then FirstKey := FALSE;
  2748.     end;
  2749.       end;
  2750.     end;
  2751.   If (Event.What = evKeyDown) and (Event.CharCode <> #0) then
  2752.     begin
  2753.     DrawField (CurrentField);
  2754.     ClearEvent (Event);
  2755.     end
  2756.    else
  2757.     begin
  2758.     Go := TRUE;
  2759.     Case Event.ScanCode of
  2760.       hi (kbIns):    If InsOn then BlockCursor else NormalCursor;
  2761.       hi (kbCtrlEnd):    QuitField (cmDMX_ScreenBottom);
  2762.       hi (kbCtrlHome):    QuitField (cmDMX_ScreenTop);
  2763.       hi (kbCtrlLeft),
  2764.       hi (kbLeft):    QuitField (cmDMX_Left);
  2765.       hi (kbShiftTab):
  2766.       begin
  2767.       TScroller.HandleEvent (Event);
  2768.       If GetState (sfFocused) then QuitField (cmDMX_Left) else QuitField (cmDMX_Enter);
  2769.       end;
  2770.       hi (kbCtrlPgDn):    QuitField (cmDMX_Bottom);
  2771.       hi (kbCtrlPgUp):    QuitField (cmDMX_Top);
  2772.       hi (kbCtrlRight),
  2773.       hi (kbRight):    QuitField (cmDMX_Right);
  2774.       hi (kbEnd):    QuitField (cmDMX_End);
  2775.       hi (kbHome):    QuitField (cmDMX_Home);
  2776.       hi (kbPgDn):    QuitField (cmDMX_PgDn);
  2777.       hi (kbPgUp):    QuitField (cmDMX_PgUp);
  2778.       hi (kbUp):    QuitField (cmDMX_Up);
  2779.       hi (kbDown):    QuitField (cmDMX_Down);
  2780.      else        Go := FALSE;
  2781.       end;
  2782.     If Go then ClearEvent (Event);
  2783.     end;
  2784.  
  2785. end;
  2786.  
  2787.  
  2788. procedure TDmxEditor.ProcessMouse (var Event : TEvent);
  2789. var  i,j    : word;
  2790.      X        : boolean;
  2791.      MousePlace    : TPoint;
  2792. begin
  2793.   With Event do
  2794.     If (What = evMouseDown) and MouseInView (Where) then
  2795.       begin
  2796.       X  := TRUE;
  2797.       If (State and sfFocused = 0) then
  2798.     begin
  2799.     If (Options and (ofFirstClick or ofSelectable) = ofSelectable) or
  2800.        (State and sfActive = 0) then
  2801.       Exit;
  2802.     Select;
  2803.     X := FALSE;
  2804.     If (State and sfFocused = 0) then Exit;
  2805.     end;
  2806.       MakeLocal (Where, MousePlace);
  2807.       MousePlace.X := MousePlace.X + Delta.X;
  2808.       MousePlace.Y := MousePlace.Y + Delta.Y;
  2809.       i := cmDMX_goto;
  2810.       ProcessCommand (i, MousePlace);
  2811.       If X then
  2812.     begin
  2813.     If DoubleValid then
  2814.       begin
  2815.       If Double then Message (Application, evCommand, cmDMX_DoubleClick, @Self);
  2816.       end
  2817.      else
  2818.       WrongKeypressed (Event);
  2819.     end;
  2820.       If (Options and ofFirstClick = 0) then ClearEvent (Event);
  2821.       end;
  2822. end;
  2823.  
  2824.  
  2825. procedure TDmxEditor.ResetRecLock;
  2826. begin
  2827. end;
  2828.  
  2829.  
  2830. function  TDmxEditor.SetRecLock : boolean;
  2831. begin
  2832.   SetRecLock := TRUE;
  2833. end;
  2834.  
  2835.  
  2836. procedure TDmxEditor.SetState (AState : word; Enable : boolean);
  2837.  
  2838.     procedure HoldState (On : boolean);
  2839.     begin
  2840.       If On then
  2841.     begin
  2842.     RedrawRecord := TRUE;
  2843.     If (DataBlockSize > 0) and (RecordSize > 0) and
  2844.        (DataBlockSize div RecordSize < CurrentRecord)
  2845.      then CurrentRecord := DataBlockSize div RecordSize;
  2846.     SetUpRecord;
  2847.     SetUpField;
  2848.     TDmxScroller.SetState (AState, Enable);
  2849.     end
  2850.        else
  2851.     begin
  2852.     TDmxScroller.SetState (AState, Enable);
  2853.     EvaluateField;
  2854.     EvaluateRecord;
  2855.     If JustAltered then
  2856.       begin
  2857.       If DeskTop <> nil then Message (DeskTop, evBroadcast, cmDMX_Draw, @Self);
  2858.       JustAltered := FALSE;
  2859.       end;
  2860.     end;
  2861.     end;
  2862.  
  2863. begin
  2864.   If not Vidis and (CurrentField <> nil) and (AState and sfFocused <> 0) then
  2865.     HoldState (Enable)
  2866.   else
  2867.   If (AState and sfDragging <> 0) and (State and sfFocused <> 0) then
  2868.     HoldState (not Enable)
  2869.   else
  2870.   TDmxScroller.SetState (AState, Enable);
  2871. end;
  2872.  
  2873.  
  2874. procedure TDmxEditor.SetUpField;
  2875. begin
  2876.   FieldSelected := TRUE;
  2877.   FieldAltered  := FALSE;
  2878.   FieldData := ptr (seg (RecordData^), ofs (RecordData^) + CurrentField^.datatab);
  2879.   FirstKey  := TRUE;
  2880.   ShowFmt   := [showanyway];
  2881.   CurPos    :=  0;
  2882.   FirstPos  :=  0;
  2883.   With CurrentField^ do
  2884.     If upcase (typecode) in [fldCHARVAL, fldBYTE, fldSHORTINT, fldWORD,
  2885.                  fldINTEGER, fldLONGINT, fldREALNUM, fldHEXVALUE]
  2886.      then
  2887.       begin
  2888.       CurPos := pred (truelen - decimals);
  2889.       If CurPos < 0 then CurPos := 0;
  2890.       end
  2891.      else
  2892.       If (upcase (typecode) = fldENUM) then CurPos := -1;
  2893.   If (State and sfVisible <> 0) then DrawField (CurrentField);
  2894.   If (RecInd <> nil) then RecInd^.DrawView;
  2895. end;
  2896.  
  2897.  
  2898. procedure TDmxEditor.SetUpRecord;
  2899. begin
  2900.   RecordData     := DataAt (CurrentRecord);
  2901.   RecordAltered  := FALSE;
  2902.   RecordSelected := TRUE;
  2903.   ClearRecLock;
  2904.   Message (Owner, evBroadcast, cmDMX_SetupRecord, @Self);
  2905. end;
  2906.  
  2907.  
  2908. function  TDmxEditor.Valid (Command : word)  : boolean;
  2909.     function RO : boolean;
  2910.     var  field : pDMXfieldrec;
  2911.     begin
  2912.       If (Command = cmDMX_ZeroizeField) then
  2913.     RO := (CurrentField = nil) or (CurrentField^.access and accReadOnly <> 0)
  2914.        else
  2915.     begin
  2916.     RO := FALSE;
  2917.     field := DMXfield1;
  2918.     While (field <> nil) do
  2919.       begin
  2920.       If (field^.access and accReadOnly <> 0) then RO := TRUE;
  2921.       field := field^.Next;
  2922.       end;
  2923.     end;
  2924.     end;
  2925. begin
  2926.   If ((Command = cmDMX_ZeroizeRecord) or (Command = cmDMX_ZeroizeField))
  2927.      and (Locked or RO)
  2928.    then
  2929.     Valid := FALSE
  2930.    else
  2931.     Valid := TDmxScroller.Valid (Command);
  2932. end;
  2933.  
  2934.  
  2935. procedure TDmxEditor.ZeroizeField (Whole : boolean;  Field : pDMXfieldrec);
  2936. var  FData : pointer;
  2937.      fn    : integer;
  2938. begin
  2939.   If (RecordData = nil) or (Field = nil) or Locked then Exit;
  2940.   If CheckRecLock then
  2941.     begin
  2942.     fn := Field^.fieldnum;
  2943.     If Whole and (fn <> 0) then Field := DMXfield1;
  2944.     While Field <> nil do
  2945.       begin
  2946.       If Field^.fieldnum = fn then
  2947.     begin
  2948.     With Field^ do
  2949.       If (access and accReadOnly = 0) and (fieldsize > 0) then
  2950.         begin
  2951.         FData := ptr (seg (RecordData^), ofs (RecordData^) + datatab);
  2952.         fillchar (FData^, fieldsize, fillvalue);
  2953.         Case upcase (typecode) of
  2954.           fldSTR,
  2955.           fldSTRNUM:   pstring (FData)^ [0] := #0;
  2956.           fldCHARVAL:
  2957.         begin
  2958.         fillchar (FData^, fieldsize, '0');
  2959.         If fieldsize - decimals > 2 then fillchar (FData^, fieldsize - decimals - 2, ' ');
  2960.         If decimals > 0 then pstring (FData)^ [fieldsize - decimals - 1] := '.';
  2961.         end;
  2962.           end;
  2963.         ChangeMade;
  2964.         end;
  2965.     end;
  2966.       If Whole and (fn <> 0) then Field := Field^.Next else Field := nil;
  2967.       end;
  2968.     FirstKey     := TRUE;
  2969.     RedrawRecord := TRUE;
  2970.     end;
  2971. end;
  2972.  
  2973.  
  2974. procedure TDmxEditor.ZeroizeRecord;
  2975. var  field : pDMXfieldrec;
  2976. begin
  2977.   If CheckRecLock then
  2978.     begin
  2979.     field := DMXfield1;
  2980.     If (RecordData <> nil) then
  2981.       While (field <> nil) do
  2982.     begin
  2983.     ZeroizeField (FALSE, field);
  2984.     field := field^.Next;
  2985.     end;
  2986.     end;
  2987. end;
  2988.  
  2989.  
  2990.   { ══════════════════════════════════════════════════════════════════════ }
  2991.  
  2992.  
  2993. procedure RegisterTVDMX;
  2994. begin
  2995.   RegisterType (RDmxExtLabels);
  2996.   RegisterType (RDmxLabels);
  2997.   RegisterType (RDmxFLabels);
  2998.   RegisterType (RDmxMLabels);
  2999.   RegisterType (RDmxRecInd);
  3000.   RegisterType (RDmxScroller);
  3001.   RegisterType (RDmxEditor);
  3002. end;
  3003.  
  3004.  
  3005.   { ══════════════════════════════════════════════════════════════════════ }
  3006.  
  3007.  
  3008. End.
  3009.