{ Graphics Vision: Resource Workshop Library,
  Copr. 1996 Matthias Koeppe
}

library GvRWS;

uses Objects, WinTypes, WinProcs, Strings, CustCntl, GvRWSc, GvTable;

{$R GVRWS.RES}

{ ==============================================================
  TTable
  ============================================================== }

const
  ofFields      = 0;
  ofYellow      = 4;
  ofSize        = 6; { Amount of window extra bytes to use }

{ GetAppInstance -----------------------------------------------
    Returns a handle to the current client application.
  -------------------------------------------------------------- }
function GetAppInstance: THandle; near; assembler;
asm
	PUSH	SS
	CALL	GlobalHandle
end;

{ IsWorkshopWindow ---------------------------------------------
    Returns true if the window belongs to Resource Workshop.
    Used to determine if the control is being edited; allowing
    the LoadResRW function to be called.
  -------------------------------------------------------------- }
function IsWorkshopWindow(Wnd: HWnd): Boolean;
var
  Parent: HWnd;
  ClassName: array[0..80] of Char;
begin
  Parent := Wnd;
  repeat
    Wnd := Parent;
    Parent := GetParent(Wnd);
  until Parent = 0;
  GetClassName(Wnd, ClassName, SizeOf(ClassName));
  IsWorkshopWindow := StrComp(ClassName, 'rwswnd') = 0;
end;

{ LoadResRW ----------------------------------------------------
    Load a resource from Resource Workshop. Initialized by
    ListClasses below.
  -------------------------------------------------------------- }
var
  LoadResRW: TLoad;

{ GvTableWinFn -----------------------------------------------
    Button window procedure.
  -------------------------------------------------------------- }
function GvTableWinFn(HWindow: HWnd; Message: Word; wParam: Word;
  lParam: Longint): Longint; export;
var
  DC: HDC;
  Rect: TRect;
  Pt: TPoint;
  Fields: PTableFields;
  PS: TPaintStruct;

	function AccessFields: PTableFields;
	begin
	  Fields := pointer(GetWindowLong(HWindow, ofFields));
	  AccessFields := Fields
	end;

	procedure Paint(DC: HDC);
	var
	  Brush, OldBrush: HBrush;
	  OldPen, Pen: HPen;
	  OldFont, Font: HFont;
	  LogBrush: TLogBrush;
	  Frame: TRect;
	  Height, Width: Integer;
	  Raster: Integer;
	  xDelta: Integer;
	  Metric: TTextMetric;

		procedure DrawTitle;
		var
		  S: array[0..255] of Char;

			procedure DrawField(Field: PTableField); far;
			begin
			  with Field^ do
			    If Title <> nil
			    then begin
			      StrPCopy(S, Title^);
			      TextOut(DC, xDelta + (Left + Right) div 2, Frame.top + 2, S, StrLen(S))
			    end
			end;

		begin
		  SetTextAlign(DC, ta_Center + ta_Top);
		  SetTextCharacterExtra(DC, 1);
		  If Fields <> nil then
		  Fields^.ForEach(@DrawField);
		  SetTextCharacterExtra(DC, 0);
		end;

		procedure DrawSamples;
		var
		  y: Integer;

			procedure DrawField(Field: PTableField); far;
			begin
			  with Field^ do
			    case Alignment of
			      LeftAlign:
				begin
				  SetTextAlign(DC, ta_Left + ta_Top);
				  TextOut(DC, Left + xDelta, y, 'Left', 4)
				end;
			      RightAlign:
				begin
				  SetTextAlign(DC, ta_Right + ta_Top);
				  TextOut(DC, Right + xDelta - 1, y, 'Right', 5)
				end;
			      CenterAlign:
				begin
				  SetTextAlign(DC, ta_Center + ta_Top);
				  TextOut(DC, (Left + Right) div 2 + xDelta, y, 'Centered', 8);
				end;
			      DecimalAlign:
				begin
				  SetTextAlign(DC, ta_Right + ta_Top);
				  TextOut(DC, Right + xDelta - 1, y, 'Dec.1234567890123456789', 4 + Decimal)
				end;
			    end;
			end;

		begin
		  y := Frame.top + Raster + 3;
		  If Fields <> nil then
		  Fields^.ForEach(@DrawField);
		end;

		procedure DrawVertLines;
		var
		  i: Integer;
		  x: Integer;
		begin
		  If Fields <> nil then
		  with Fields^ do
		  For i := 0 to Count - 2 do
		  begin
		    x := xDelta + (PTableField(At(i))^.Right + PTableField(At(i + 1))^.Left) div 2;
		    MoveTo(DC, x, 0);
		    LineTo(DC, x, Height - 1);
		  end
		end;

		procedure DrawItems;
		var
		  y: Integer;
		  OldPen: HPen;
		begin
		  y := Frame.top + Raster + 2;
		  OldPen := SelectObject(DC, GetStockObject(Null_Pen));
		  while y < Frame.bottom do
		  begin
		    Rectangle(DC, 1, y, Width - 1, y + Raster);
		    Inc(y, Raster * 2)
		  end;
		  SelectObject(DC, OldPen)
		end;

	begin
	  GetClientRect(HWindow, Frame);
	  Height := Frame.bottom - Frame.top;
	  Width := Frame.right - Frame.left;
	  xDelta := 1 - GetScrollPos(HWindow, sb_Horz);

	  Pen := GetStockObject(Black_Pen);
	  OldPen := SelectObject(DC, Pen);
	  Font := CreateFont(8,0,0,0,fw_Bold,0,0,0,0,0,0,0,0,'Helv');
	  OldFont := SelectObject(DC, Font);
	  GetTextMetrics(DC, Metric);
	  Raster := Metric.tmHeight + 2;
	  SetBkMode(DC, Transparent);

	  AccessFields;
	  Brush := CreateSolidBrush(RGB(255, 255, 192));
	  OldBrush := SelectObject(DC, Brush);
	  If GetWindowWord(HWindow, ofYellow) <> 0
	  then DrawItems;
	  DeleteObject(SelectObject(DC, GetStockObject(Null_Brush)));
	  Rectangle(DC, Frame.left, Frame.top, Frame.right, Frame.bottom);
	  MoveTo(DC, Frame.left, Frame.top + Raster + 2);
	  LineTo(DC, Frame.right, Frame.top + Raster + 2);
	  DrawVertLines;
	  DrawTitle;
	  DrawSamples;

	  DeleteObject(SelectObject(DC, OldPen));
	  DeleteObject(SelectObject(DC, OldFont));
	  DeleteObject(SelectObject(DC, OldBrush));
	end;

begin
  GvTableWinFn := 0;
  case Message of
    wm_Create:
      begin
	with PCreateStruct(lParam)^ do
	begin
	  SetWindowWord(HWindow, ofYellow, Byte(Style and ts_Yellow <> 0));
	  If lpCreateParams <> nil
	  then Fields := CreateTableFields(PTableB(lpCreateParams)^, 4)
	  else Fields := nil;
	  SetWindowLong(HWindow, ofFields, LongInt(Fields));
	end;
      end;
    wm_NCDestroy:
      begin
	If AccessFields <> nil
	then Dispose(Fields, Done);
	GvTableWinFn := DefWindowProc(HWindow, Message, wParam, lParam);
      end;
    wm_Paint:
      begin
	BeginPaint(HWindow, PS);
	Paint(PS.hDC);
	EndPaint(HWindow, PS);
      end;
  else
    GvTableWinFn := DefWindowProc(HWindow, Message, wParam, lParam);
  end;
end;

function GvLevelZeroWinFn(HWindow: HWnd; Message: Word; wParam: Word;
  lParam: Longint): Longint; export;
var
  DC: HDC;
  PS: TPaintStruct;

	procedure Paint(DC: HDC);
	var
	  OldBrush: HBrush;
	  OldPen: HPen;
	  Frame: TRect;
	begin
	  GetClientRect(HWindow, Frame);
	  OldPen := SelectObject(DC, GetStockObject(White_Pen));
	  OldBrush := SelectObject(DC, GetStockObject(LtGray_Brush));
	  Rectangle(DC, Frame.left + 1, Frame.top + 1, Frame.right, Frame.bottom);
	  DeleteObject(SelectObject(DC, GetStockObject(Null_Brush)));
	  DeleteObject(SelectObject(DC, CreatePen(ps_Solid, 1, $808080)));
	  Rectangle(DC, Frame.left, Frame.top, Frame.right - 1, Frame.bottom - 1);
	  DeleteObject(SelectObject(DC, OldPen));
	  DeleteObject(SelectObject(DC, OldBrush));
	end;

begin
  GvLevelZeroWinFn := 0;
  case Message of
    wm_Paint:
      begin
	BeginPaint(HWindow, PS);
	Paint(PS.hDC);
	EndPaint(HWindow, PS);
      end;
  else
    GvLevelZeroWinFn := DefWindowProc(HWindow, Message, wParam, lParam);
  end;
end;

{ ==============================================================
  Custom contol interface routines.
  ============================================================== }

{ GvTableInfo ---------------------------------------------------
   Return the information about the capabilities of the
   bit button class.
  -------------------------------------------------------------- }
function GvTableInfo: THandle; export;
var
  hInfo: THandle;
  Info: PRWCtlInfo;
begin
  hInfo := GlobalAlloc(gmem_Share or gmem_ZeroInit,
    SizeOf(TRWCtlInfo));
  if hInfo <> 0 then
  begin
    Info := GlobalLock(hInfo);
    with Info^ do
    begin
      wVersion := $20A;         { Version 2.10 }
      wCtlTypes := 1;
      StrCopy(szClass, 'GvTable');
      StrCopy(szTitle, '');

      { Normal (Un-default) push button type }
      with ctType[0] do
      begin
	wWidth := 200 or $8000;
	wHeight := 100 or $8000;
	StrCopy(szDescr, 'GVision TTable');
	dwStyle := ts_Yellow or ws_TabStop or ws_VScroll;
	hToolBit := LoadBitmap(HInstance, MakeIntResource(bmpTable));
	hDropCurs := LoadCursor(HInstance, MakeIntResource(cursorTable));
      end;

    end;
    GlobalUnlock(hInfo);
  end;
  GvTableInfo := hInfo;
end;

function GvLevelZeroInfo: THandle; export;
var
  hInfo: THandle;
  Info: PRWCtlInfo;
begin
  hInfo := GlobalAlloc(gmem_Share or gmem_ZeroInit,
    SizeOf(TRWCtlInfo));
  if hInfo <> 0 then
  begin
    Info := GlobalLock(hInfo);
    with Info^ do
    begin
      wVersion := $20A;         { Version 2.10 }
      wCtlTypes := 1;
      StrCopy(szClass, 'GvLevelZero');
      StrCopy(szTitle, '');

      with ctType[0] do
      begin
	wWidth := 63 or $8000;
	wHeight := 39 or $8000;
	StrCopy(szDescr, 'GVision TLevel(0)');
	hToolBit := LoadBitmap(HInstance, MakeIntResource(bmpLevelZero));
	hDropCurs := LoadCursor(HInstance, MakeIntResource(cursorLevelZero));
      end;

    end;
    GlobalUnlock(hInfo);
  end;
  GvLevelZeroInfo := hInfo;
end;

function GvTableColsDlg(HWindow: HWnd; Message: Word; wParam: Word;
  lParam: Longint): Longint; export;
const
  Prop = 'Prop';
var
  hRec: THandle;
  Field: PTableField;
  S: array[0..256] of Char;
  Radio: Integer;
  Translate: Bool;

	function AccessField: PTableField;
	begin
	  hRec := GetProp(HWindow, Prop);
	  Field := pointer(GlobalLock(hRec)^);
	  AccessField := Field;
	  GlobalUnlock(hRec);
	end;

	function ScrollHandle: HWnd;
	begin
	  ScrollHandle := GetDlgItem(HWindow, idWidthScroll)
	end;

	procedure UpdateScrollbar;
	var
	  Value: Integer;
	begin
	  Value := GetDlgItemInt(HWindow, idWidth, @Translate, false);
	  If Translate then
	  SetScrollPos(ScrollHandle, sb_Ctl, Value, true)
	end;

	procedure UpdateLine;
	begin
	  Str(GetScrollPos(ScrollHandle, sb_Ctl), S);
	  SetDlgItemText(HWindow, idWidth, S)
	end;

begin
  case Message of
    wm_InitDialog:
      begin
	Field := pointer(lParam);
	{ Save the Field pointer in a property }
	hRec := GlobalAlloc(gmem_Share, SizeOf(pointer));
	pointer(GlobalLock(hRec)^) := Field;
	GlobalUnlock(hRec);
	SetProp(HWindow, Prop, hRec);
	with Field^ do
	begin
	  If Title = nil
	  then S[0] := #0
	  else StrPCopy(S, Title^);
	  SetDlgItemText(HWindow, idColTitle, S);

	  case Alignment of
	    LeftAlign:
	      Radio := idAlignLeft;
	    RightAlign:
	      Radio := idAlignRight;
	    CenterAlign:
	      Radio := idAlignCentered;
	    DecimalAlign:
	      Radio := idAlignDecimal;
	  end;
	  CheckRadioButton(HWindow, idAlignLeft, idAlignCentered, Radio);

	  Str(Decimal, S);
	  SetDlgItemText(HWindow, idDecimals, S);

	  Str(Right - Left, S);
	  SetDlgItemText(HWindow, idWidth, S);
	  SetScrollRange(ScrollHandle, sb_Ctl, 0, 100 {max}, true);
	  UpdateScrollbar;

	end;
	GlobalUnlock(hRec);
      end;
    wm_Command:
      case wParam of
	idCancel:
	  EndDialog(HWindow, 0);
	idOk:
	  begin
	    with AccessField^ do
	    begin
	      GetDlgItemText(HWindow, idColTitle, S, SizeOf(S));
	      If Title <> nil then DisposeStr(Title);
	      Title := NewStr(StrPas(S));

	      Right := Left + GetDlgItemInt(HWindow, idWidth, @Translate, false);

	      If IsDlgButtonChecked(HWindow, idAlignLeft) <> 0
	      then Alignment := LeftAlign else
	      if IsDlgButtonChecked(HWindow, idAlignRight) <> 0
	      then Alignment := RightAlign else
	      if IsDlgButtonChecked(HWindow, idAlignCentered) <> 0
	      then Alignment := CenterAlign
	      else begin
		Alignment := DecimalAlign;
		Decimal := GetDlgItemInt(HWindow, idDecimals, @Translate, false)
	      end;
	    end;
	    EndDialog(HWindow, 1);
	  end;
      else
	GvTableColsDlg := 0;
      end;
    wm_Destroy:
      RemoveProp(HWindow, Prop);
  else
    GvTableColsDlg := 0;
  end;
end;

type
  PParamRec = ^TParamRec;
  TParamRec = record
    CtlStyle: THandle;
    IdToStr: TIdToStr;
    StrToId: TStrToId;
    Columns: PTableFields;
  end;

{   Style dialog's dialog hook.  Used by the dialog and called
    when the control is double-clicked inside the dialog
    editor.
  -------------------------------------------------------------- }
function GvTableStyleDlg(HWindow: HWnd; Message: Word; wParam: Word;
  lParam: Longint): Longint; export;
const
  Prop = 'Prop';
var
  hRec: THandle;
  Rec: PParamRec;
  Style: PCtlStyle;
  S: array[0..256] of Char;
  Radio: Integer;
  Item: PTableField;
  l: LongInt;
  w: Word;
  Translate: Bool;

	procedure UpdateList;
	const
	  Alignments: array[TAlignment] of PChar =
	    ('Left', 'Centered', 'Right', 'Decimal');
	var
	  Buf: string[10];
	  i: Integer;
	begin
	  SendDlgItemMessage(HWindow, idTableCols, lb_ResetContent, 0, 0);
	  with Rec^.Columns^ do
	  For i := 0 to Count - 1 do
	  begin
	    with PTableField(At(i))^ do
	    begin
	      If Title = nil
	      then S[0] := #0
	      else StrPCopy(S, Title^);
	      StrCat(S, #9);
	      StrCat(S, Alignments[Alignment]);
	      StrCat(S, #9);
	      Str(Right-Left, Buf);
	      StrPCopy(StrEnd(S), Buf);
	      If Alignment = DecimalAlign
	      then begin
		StrCat(S, #9);
		Str(Decimal, Buf);
		StrPCopy(StrEnd(S), Buf);
	      end;
	    end;
	    SendDlgItemMessage(HWindow, idTableCols, lb_AddString, 0, LongInt(@S));
	  end;
	end;

	function CurrentItem: PTableField;
	var
	  Item: Integer;
	begin
	  Item := SendDlgItemMessage(HWindow, idTableCols, lb_GetCursel, 0, 0);
	  If (Item < 0) or (Item >= Rec^.Columns^.Count)
	  then CurrentItem := nil
	  else CurrentItem := Rec^.Columns^.At(Item)
	end;

	procedure InsertItem(Item: PTableField);
	var
	  Index: Integer;
	begin
	  Index := SendDlgItemMessage(HWindow, idTableCols, lb_GetCursel, 0, 0);
	  If (Index < 0) or (Index > Rec^.Columns^.Count)
	  then Index := 0;
	  Rec^.Columns^.AtInsert(Index, Item)
	end;

	function Edit(Item: PTableField): Bool;
	begin
	  Edit := Bool(DialogBoxParam(HInstance,
	    MakeIntResource(dlgTableCols), HWindow, @GvTableColsDlg, LongInt(Item)));
	end;

begin
  case Message of
    wm_InitDialog:
      begin
	hRec := LoWord(lParam);
	Rec := GlobalLock(hRec);
	Style := GlobalLock(Rec^.CtlStyle);
	SetProp(HWindow, Prop, hRec);
	with Rec^, Style^ do
	begin
	  IdToStr(wId, S, SizeOf(S));
	  SetDlgItemText(HWindow, idControlId, S);
	  Str(wID, S);
	  SetDlgItemText(HWindow, idControlIDnumber, S);

	  If szTitle[0] = #$FF
	  then Str(Word(pointer(@szTitle[1])^), S)
	  else StrCopy(S, szTitle);
	  SetDlgItemText(HWindow, idTableInfo, S);
	  SetDlgItemText(HWindow, idTableInfonumber, S);

	  CheckDlgButton(HWindow, idTableHoriz,
	    Integer(dwStyle and ws_HScroll <> 0));

	  CheckDlgButton(HWindow, idTableVert,
	    Integer(dwStyle and ws_VScroll <> 0));

	  CheckDlgButton(HWindow, idTableYellow,
	    Integer(dwStyle and ts_Yellow <> 0));

	  UpdateList;

	end;
	GlobalUnlock(Rec^.CtlStyle);
	GlobalUnlock(hRec);
      end;
    wm_Command:
      case wParam of
	idTableEdit:
	  begin
	    hRec := GetProp(HWindow, Prop);
	    Rec := GlobalLock(hRec);
	    Item := CurrentItem;
	    If Item <> nil
	    then If Edit(Item) then UpdateList;
	    GlobalUnlock(hRec);
	  end;
	idTableInsert:
	  begin
	    hRec := GetProp(HWindow, Prop);
	    Rec := GlobalLock(hRec);
	    Item := New(PTableField, Init('Column', LeftAlign, 0, 100, 3));
	    If Edit(Item)
	    then begin
	      InsertItem(Item);
	      UpdateList
	    end
	    else Dispose(Item, Done);
	    GlobalUnlock(hRec);
	  end;
	idTableAppend:
	  begin
	    hRec := GetProp(HWindow, Prop);
	    Rec := GlobalLock(hRec);
	    Item := New(PTableField, Init('Column', LeftAlign, 0, 100, 3));
	    If Edit(Item)
	    then begin
	      Rec^.Columns^.Insert(Item);
	      UpdateList
	    end
	    else Dispose(Item, Done);
	    GlobalUnlock(hRec);
	  end;
	idTableDelete:
	  begin
	    hRec := GetProp(HWindow, Prop);
	    Rec := GlobalLock(hRec);
	    Item := CurrentItem;
	    If Item <> nil
	    then begin
	      Rec^.Columns^.Free(Item);
	      UpdateList
	    end;
	    GlobalUnlock(hRec);
	  end;
	idCancel:
	  EndDialog(HWindow, 0);
	idOk:
	  begin
	    hRec := GetProp(HWindow, Prop);
	    Rec := GlobalLock(hRec);
	    Style := GlobalLock(Rec^.CtlStyle);
	    with Rec^, Style^ do
	    begin

	      { Get control id }
	      GetDlgItemText(HWindow, idControlId, S, SizeOf(S));
	      l := StrToId(S);
	      If LoWord(l) <> 0
	      then begin
		wId := HiWord(l);

		GetDlgItemText(HWindow, idTableInfo, szTitle, SizeOf(szTitle));

		dwStyle := dwStyle and not (ws_HScroll or ws_VScroll or ts_Yellow);
		if IsDlgButtonChecked(HWindow, idTableHoriz) <> 0 then
		  dwStyle := dwStyle or ws_HScroll;
		if IsDlgButtonChecked(HWindow, idTableVert) <> 0 then
		  dwStyle := dwStyle or ws_VScroll;
		if IsDlgButtonChecked(HWindow, idTableYellow) <> 0 then
		  dwStyle := dwStyle or ts_Yellow;
	      end
	    end;
	    GlobalUnlock(Rec^.CtlStyle);
	    GlobalUnlock(hRec);
	    If LoWord(l) <> 0
	    then EndDialog(HWindow, 1);
	  end;
      else
	GvTableStyleDlg := 0;
      end;
    wm_Destroy:
      RemoveProp(HWindow, Prop);
  else
    GvTableStyleDlg := 0;
  end;
end;

{ GvTableStyle --------------------------------------------------
    The function will bring up a dialog box to modify the style
    of the button.  Called when the button is double-clicked in
    the dialog editor.
  -------------------------------------------------------------- }
function GvTableStyle(hWindow: HWnd; CtlStyle: THandle;
  StrToId: TStrToId; IdToStr: TIdToStr): Bool; export;
var
  hRec: THandle;
  Rec: PParamRec;
  hFocus: HWnd;
  Style: PRWCtlStyle;
  Result: Bool;
begin
  GvTableStyle := False;
  hRec := GlobalAlloc(gmem_Share, SizeOf(TParamRec));
  if hRec <> 0 then
  begin
    Rec := GlobalLock(hRec);
    Rec^.IdToStr := IdToStr;
    Rec^.StrToId := StrToId;
    Rec^.CtlStyle := CtlStyle;

    Style := GlobalLock(CtlStyle);
    If Style^.CtlDataSize > 0
    then Rec^.Columns := CreateTableFields(Style^.CtlData, 4)
    else Rec^.Columns := New(PTableFields, Init);
    GlobalUnlock(CtlStyle);

    GlobalUnlock(hRec);

    hFocus := GetFocus;
    Result := Bool(DialogBoxParam(HInstance,
      MakeIntResource(dlgTable), HWindow, @GvTableStyleDlg,
      hRec));
    If Result
    then begin
      Rec := GlobalLock(hRec);
      Style := GlobalLock(CtlStyle);
      Style^.CtlDataSize := CreateTableFieldB(Rec^.Columns, Style^.CtlData, 4);
      GlobalUnlock(CtlStyle);
      GlobalUnlock(hRec)
    end;

    GvTableStyle := Result;
    if hFocus <> 0 then SetFocus(hFocus);
    GlobalFree(hRec);
  end;
end;

function GvLevelZeroStyle(hWindow: HWnd; CtlStyle: THandle;
  StrToId: TStrToId; IdToStr: TIdToStr): Bool; export;
begin
  GvLevelZeroStyle := False
end;


{ GvTableFlags --------------------------------------------------
    Called to decompose the style double word into the .RC
    script expression that it represents.  This only needs to
    decompose the style bits added to the style double word,
    it need not decompose the, for example, the ws_XXX bits.
    The expression returned must be a valid .RC expression
    (i.e. C syntax, case sensitive).
  -------------------------------------------------------------- }
function GvTableFlags(Style: LongInt; Buff: PChar;
  BuffLength: Word): Word; export;
begin
  if Style and ts_Yellow <> 0
  then StrLCopy(Buff, '1', BuffLength)
  else StrLCopy(Buff, '0', BuffLength);
  GvTableFlags := StrLen(Buff);
end;

function GvLevelZeroFlags(Style: LongInt; Buff: PChar;
  BuffLength: Word): Word; export;
begin
  Buff[0] := #0;
  GvLevelZeroFlags := 0;
end;

{ ListClasses --------------------------------------------------
    Called by Resource Workshop retrieve the information
    necessary to edit the custom controls contain in this DLL.
    This is an alternative to the Microsoft xxxStyle convention.
  -------------------------------------------------------------- }
function ListClasses(szAppName: PChar; wVersion: Word;
  fnLoad: TLoad; fnEdit: TEdit): THandle; export;
var
  hClasses: THandle;
  Classes: PCtlClassList;
begin
  LoadResRW := fnLoad;
  hClasses := GlobalAlloc(gmem_Share or gmem_ZeroInit,
    SizeOf(Integer) + 2 * SizeOf(TRWCtlClass));
  if hClasses <> 0 then
  begin
    Classes := GlobalLock(hClasses);
    with Classes^ do
    begin
      nClasses := 2;
      with Classes[0] do
      begin
	fnInfo  := GvLevelZeroInfo;
	fnStyle := GvLevelZeroStyle;
	fnFlags := GvLevelZeroFlags;
      end;
      with Classes[1] do
      begin
	fnInfo  := GvTableInfo;
	fnStyle := GvTableStyle;
	fnFlags := GvTableFlags;
      end;
    end;
    GlobalUnlock(hClasses);
  end;
  ListClasses := hClasses;
end;

exports
  ListClasses,
  GvTableWinFn,
  GvLevelZeroWinFn;

var
  C: TWndClass;

begin
  with C do
  begin
    lpszClassName := 'GvTable';
    hCursor       := LoadCursor(0, idc_Arrow);
    lpszMenuName  := nil;
    style         := cs_HRedraw or cs_VRedraw or cs_DblClks or cs_GlobalClass;
    lpfnWndProc   := TFarProc(@GvTableWinFn);
    hInstance     := System.hInstance;
    hIcon         := 0;
    cbWndExtra    := ofSize;
    cbClsExtra    := 0;
    hbrBackground := GetStockObject(White_Brush);
  end;
  RegisterClass(C);
  with C do
  begin
    lpszClassName := 'GvLevelZero';
    hCursor       := LoadCursor(0, idc_Arrow);
    lpszMenuName  := nil;
    style         := cs_HRedraw or cs_VRedraw or cs_DblClks or cs_GlobalClass;
    lpfnWndProc   := TFarProc(@GvLevelZeroWinFn);
    hInstance     := System.hInstance;
    hIcon         := 0;
    cbWndExtra    := 0;
    cbClsExtra    := 0;
    hbrBackground := GetStockObject(LtGray_Brush);
  end;
  RegisterClass(C);
end.

