mmdesign.pas
上传用户:hylc_2004
上传日期:2014-01-23
资源大小:46800k
文件大小:53k
源码类别:

Delphi控件源码

开发平台:

Delphi

  1. {========================================================================}
  2. {=                (c) 1995-98 SwiftSoft Ronald Dittrich                 =}
  3. {========================================================================}
  4. {=                          All Rights Reserved                         =}
  5. {========================================================================}
  6. {=  D 01099 Dresden             = Fax.: +49 (0)351-8037944              =}
  7. {=  Loewenstr.7a                = info@swiftsoft.de                     =}
  8. {========================================================================}
  9. {=  Actual versions on http://www.swiftsoft.de/mmtools.html             =}
  10. {========================================================================}
  11. {=  This code is for reference purposes only and may not be copied or   =}
  12. {=  distributed in any format electronic or otherwise except one copy   =}
  13. {=  for backup purposes.                                                =}
  14. {=                                                                      =}
  15. {=  No Delphi Component Kit or Component individually or in a collection=}
  16. {=  subclassed or otherwise from the code in this unit, or associated   =}
  17. {=  .pas, .dfm, .dcu, .asm or .obj files may be sold or distributed     =}
  18. {=  without express permission from SwiftSoft.                          =}
  19. {=                                                                      =}
  20. {=  For more licence informations please refer to the associated        =}
  21. {=  HelpFile.                                                           =}
  22. {========================================================================}
  23. {=  $Date: 12.08.98 - 13:14:05 $                                        =}
  24. {========================================================================}
  25. unit MMDesign;
  26. {$I COMPILER.INC}
  27. {.$DEFINE _MMDEBUG}
  28. interface
  29. uses
  30. {$IFDEF WIN32}
  31.   Windows,
  32. {$ELSE}
  33.   WinProcs,
  34.   WinTypes,
  35. {$ENDIF}
  36.   SysUtils,
  37.   Messages,
  38.   Classes,
  39.   Graphics,
  40.   Controls,
  41.   Forms,
  42.   Dialogs,
  43.   ExtCtrls,
  44.   StdCtrls,
  45.   MMObj,
  46.   MMHook,
  47.   MMPanel;
  48. type
  49.   TCompRect = record
  50.        Left  : integer;
  51.        Top   : integer;
  52.        Height: integer;
  53.        Width : integer;
  54.        Ok    : Boolean;
  55.   end;
  56.   TPropType     = (ptInput,ptOutput);
  57.   TConnectCheck = function(C1, C2: TComponent): Boolean;
  58.   TConnect      = procedure(C1, C2: TComponent);
  59.   {-- TMMDesigner --------------------------------------------------------}
  60.   TMMDesigner = class(TMMWndProcComponent)
  61.   private
  62.     FAutoUpdate     : Boolean;
  63.     FActive         : Boolean;
  64.     FUpdate         : Boolean;
  65.     FVisible        : Boolean;
  66.     FSound          : Boolean;
  67.     FColor          : TColor;
  68.     FLineWidth      : integer;
  69.     FMargin         : integer;
  70.     FParentForm     : TForm;
  71.     FParentComponent: TComponent;
  72.     FTimer          : TTimer;
  73.     FPaintOk        : Boolean;
  74.     FRuntimeHeight  : integer;
  75.     FShowButton     : Boolean;
  76.     FButtonDown     : Boolean;
  77.     FButtonPressed  : Boolean;
  78.     FProhibited     : TStringList;
  79.     FAllowed        : TList;
  80.     FPortList       : TList;
  81.     FConnList       : TList;
  82.     FValidLists     : Boolean;
  83.     FRebuilding     : Boolean;
  84.     procedure SetActive(aValue: Boolean);
  85.     procedure SetUpdate(aValue: Boolean);
  86.     procedure SetLineWidth(aValue: integer);
  87.     procedure SetMargin(aValue: integer);
  88.     procedure SetColor(aValue: TColor);
  89.     procedure SetShowButton(aValue: Boolean);
  90.     procedure DesignerFormPos;
  91.     function  ButtonRect: TRect;
  92.     function  InButton(pt: TPoint): Boolean;
  93.     procedure PaintButton(Down: Boolean);
  94.     procedure RefreshCaption;
  95.     procedure SetPen(Color: TColor; Width:integer; Style: TPenStyle);
  96.     procedure TimerAction(Sender:TObject);
  97.     procedure RefreshForm(ControlsOk, ComponentsOk: Boolean);
  98.     procedure GetComponentPos(Comp: TComponent; var CompRect: TCompRect);
  99.     procedure DrawConnection(CompRect1,CompRect2: TCompRect;ArrowOk: Boolean);
  100.     procedure DrawPorts(Comp: TComponent; InPort,OutPort: Boolean);
  101.     procedure InitDesigner;
  102.   protected
  103.     procedure ChangeDesigning(aValue: Boolean); override;
  104.     procedure Loaded; override;
  105.     procedure HookWndProc(var Message: TMessage); override;
  106.     function  HasInput(C: TComponent): Boolean;
  107.     function  HasOutput(C: TComponent): Boolean;
  108.     function  FindConnectProp(C1,C2: TComponent): Integer;
  109.     function  HasPotentialInput(C: TComponent): Boolean;
  110.     function  HasPotentialOutput(C: TComponent): Boolean;
  111.     function  CheckInput(C: TComponent; Pt: TPoint; var R: TRect): Boolean;
  112.     function  CheckOutput(C: TComponent; Pt: TPoint; var R: TRect): Boolean;
  113.     function  FindProp(Pt: TPropType; CFrom: TComponent; CTo: TComponent; StartFrom: Integer): Integer;
  114.     function  HasException(CompFrom: TComponent; CompTo: TComponent;
  115.                            Index: Integer): Boolean;
  116.     function  FindRef(PropType: TPropType;C: TComponent;StartFrom: Integer): Integer;
  117.     function  FindRefs(PropType:TPropType;R,C:TComponent;StartFrom:Integer):Integer;
  118.     function  RemoveRef(C: TComponent; PropType: TPropType): Boolean;
  119.     function  RemoveRefs(C: TComponent; PropType: TPropType): Boolean;
  120.     procedure GetConnected(C: TComponent; List: TList);
  121.     function  Allowed: TList;
  122.     procedure RebuildLists;
  123.     procedure Notification(AComponent: TComponent; Operation: TOperation); override ;
  124.   public
  125.     constructor Create(AOwner: TComponent); override;
  126.     destructor  Destroy; override;
  127.     function  FindTarget(Form: TForm; Wnd: HWND; var Pt: TPoint; var TargetType: TPropType; var R: TRect): TComponent;
  128.     function  RemoveInput(C: TComponent): Boolean;
  129.     function  RemoveOutput(C: TComponent): Boolean;
  130.     procedure DrawPaintBox;
  131.     procedure BeepSound(aValue: Cardinal);
  132.     function  CanConnect(C1,C2: TComponent): Boolean;
  133.     procedure Connect(C1,C2: TComponent);
  134.     property  ParentForm: TForm read FParentForm;
  135.     property  ParentComponent: TComponent read FParentComponent;
  136.     property  Visible: Boolean read FVisible;
  137.   published
  138.     property  Active: Boolean read FActive write SetActive default True;
  139.     property  Color: TColor read FColor write SetColor default clRed;
  140.     property  LineWidth: integer read FLineWidth write SetLineWidth default 1;
  141.     property  Margin: integer read FMargin write SetMargin default 6;
  142.     property  AutoUpdate: Boolean read FAutoUpdate write FAutoUpdate default True;
  143.     property  Update: Boolean read FUpdate write SetUpdate;
  144.     property  Sound: Boolean read FSound write FSound default True;
  145.     property  ShowButton: Boolean read FShowButton write SetShowButton default False;
  146.     property  RuntimeHeight: integer read FRuntimeHeight write FRuntimeHeight;
  147.   end;
  148.   {-- TMMDesignerForm ----------------------------------------------------}
  149.   TMMDesignerForm = class(TForm)
  150.     MMPanel1: TMMPanel;
  151.     btnClose: TButton;
  152.     ckbActive: TCheckBox;
  153.     ckbAuto: TCheckBox;
  154.     ckbSound: TCheckBox;
  155.     btnHeight: TButton;
  156.     GroupBox: TListBox;
  157.     Label1: TLabel;
  158.     btnAll: TButton;
  159.     btnNone: TButton;
  160.     Bevel1: TBevel;
  161.     Bevel2: TBevel;
  162.     procedure CheckBoxClick(Sender: TObject);
  163.     procedure FormShow(Sender: TObject);
  164.     procedure btnHeightClick(Sender: TObject);
  165.     procedure FormHide(Sender: TObject);
  166.     procedure btnAllClick(Sender: TObject);
  167.     procedure btnNoneClick(Sender: TObject);
  168.   public
  169.     Designer: TMMDesigner;
  170.   end;
  171.   {-- TPropRec ----------------------------------------------------------------}
  172.   TPropRec = class(TObject)
  173.     PropType    : TPropType;
  174.     PropGroup   : string;
  175.     ClassFrom   : TClass;
  176.     PropName    : string;
  177.     ClassTo     : TClass;
  178.     CheckProc   : TConnectCheck;
  179.     constructor Create(APropType: TPropType; const APropGroup: string;
  180.                        AClassFrom: TClass;
  181.                        const APropName: string; AClassTo: TClass;
  182.                        ACheckProc: TConnectCheck);
  183.   end;
  184. var
  185.    DesignerForm: TMMDesignerForm;
  186. var
  187.    _FindDesignerForWindow: function(Wnd: HWND): TMMDesigner = nil;
  188.    _AddDesigner          : procedure(Designer: TMMDesigner) = nil;
  189.    _RemoveDesigner       : procedure(Designer: TMMDesigner) = nil;
  190.    _RedrawTrack          : procedure(Show: Boolean);
  191. const
  192.    Griff = 5;
  193.    ComponentWidth  = 28;
  194.    ComponentHeight = 28;
  195. const
  196.    ControlList : TList   = nil;
  197.    CreateCount : integer = 0;
  198.    GetMsgHook  : HHook   = 0;
  199.    PaintCount  : integer = 0;
  200.    PaintOk     : Boolean = False;
  201.    Dragging    : Boolean = False;
  202.    Deconnect   : Boolean = False;
  203.    Adjusting   : Boolean = False;
  204.    PropList     : TList  = nil;
  205.    ExcPropList  : TList  = nil;
  206. var
  207.    DragDesigner: TMMDesigner;
  208.    DragOrigin  : TPoint;
  209.    DragPoint   : TPoint;
  210.    DragRect    : TRect;
  211.    DragInput   : Boolean;
  212.    DragSource  : TComponent;
  213.    DragDest    : TComponent;
  214.    TrackVisible: Boolean;
  215.    DesignBitmap: HBITMAP;
  216.    BitmapWidth : integer;
  217.    BitmapHeight: integer;
  218. procedure DoneDragging;
  219. {========================================================================}
  220. implementation
  221. {$R *.DFM}
  222. uses
  223.     Consts,
  224.     TabNotBk,
  225.     TypInfo,
  226.     MMUtils
  227.     {$IFDEF WIN32}
  228.     ,ComCtrls
  229.     {$ENDIF}
  230.     {$IFDEF _MMDEBUG}
  231.     ,MMDebug
  232.     {$ENDIF};
  233. {== TPropRec ============================================================}
  234. constructor TPropRec.Create(APropType: TPropType; const APropGroup: string;
  235.                             AClassFrom: TClass;
  236.                             const APropName: string; AClassTo: TClass;
  237.                             ACheckProc: TConnectCheck);
  238. begin
  239.    inherited Create;
  240.    PropType    := APropType;
  241.    PropGroup   := APropGroup;
  242.    ClassFrom   := AClassFrom;
  243.    PropName    := APropName;
  244.    ClassTo     := AClassTo;
  245.    CheckProc   := ACheckProc;
  246. end;
  247. {------------------------------------------------------------------------}
  248. function IsCompiling: Boolean;
  249. begin
  250.    Result := FindWindow('TProgressForm',nil) <> 0;
  251. end;
  252. {------------------------------------------------------------------------}
  253. function LeftGriff(C: TComponent): TRect;
  254. begin
  255.    if (C is TControl) then
  256.    with (C as TControl) do
  257.    begin
  258.       Result.Left   := Left - Griff div 2;
  259.       Result.Top    := (Top + Height div 2) - Griff div 2 - (Height+1) mod 2;
  260.    end
  261.    else
  262.    begin
  263.       Result.Left   := LoWord(C.DesignInfo) - Griff div 2;
  264.       Result.Top    := HiWord(C.DesignInfo) + (ComponentWidth div 2) - 1 - Griff div 2;
  265.    end;
  266.    Result.Right  := Result.Left + Griff;
  267.    Result.Bottom := Result.Top + Griff;
  268. end;
  269. {------------------------------------------------------------------------}
  270. function RightGriff(C: TComponent): TRect;
  271. begin
  272.    Result          := LeftGriff(C);
  273.    Result.Left     := Result.Left + ComponentWidth - 1;
  274.    Result.Right    := Result.Left + Griff;
  275. end;
  276. {------------------------------------------------------------------------}
  277. function DesignerVisible(Designer: TMMDesigner): Boolean;
  278. var
  279.    L,T: integer;
  280. begin
  281.    Result := False;
  282.    if (Designer <> nil) then
  283.    with Designer do
  284.    begin
  285.       L:= LoWord(DesignInfo);
  286.       T:= HiWord(DesignInfo);
  287.       Result := (L < FParentForm.ClientWidth) and
  288.                 (T < FParentForm.ClientHeight);
  289.    end;
  290. end;
  291. {------------------------------------------------------------------------}
  292. function ControlVisible(AControl: TControl): Boolean;
  293. begin
  294.    if AControl is TForm then
  295.    begin
  296.       Result := True;
  297.       Exit;
  298.    end;
  299.    if (AControl is TWinControl)
  300.    {$IFDEF WIN32}
  301.       and not (AControl is TTabSheet)
  302.    {$ENDIF}
  303.       and not (AControl is TPage) then
  304.       Result := IsWindowVisible((AControl as TWinControl).Handle)
  305.    else
  306.       Result := AControl.Visible;
  307.    if (AControl.Parent <> nil) then
  308.        Result := Result and ControlVisible(AControl.Parent);
  309. end;
  310. {------------------------------------------------------------------------}
  311. procedure DoneDragging;
  312. begin
  313.    if (DragDesigner <> nil) then
  314.    with DragDesigner do
  315.    if MMDesign.Dragging or Adjusting then
  316.    begin
  317.       _RedrawTrack(False);
  318.       ClipCursor(nil);
  319.       MMDesign.Dragging := False;
  320.       Adjusting:= False;
  321.    end;
  322. end;
  323. {------------------------------------------------------------------------}
  324. function CheckPropAvail(C: TComponent; i: Integer; NeedCheck: Boolean): Boolean;
  325. begin
  326.    if NeedCheck then
  327.       Result := GetPropInfo(C.ClassInfo,TPropRec(PropList[i]).PropName) <> nil
  328.    else
  329.       Result := True;
  330. end;
  331. {------------------------------------------------------------------------}
  332. function GetPropValue(C: TComponent; i: Integer): TComponent;
  333. begin
  334.    Result := TComponent(GetOrdProp(C,GetPropInfo(C.ClassInfo,TPropRec(PropList[i]).PropName)));
  335. end;
  336. {------------------------------------------------------------------------}
  337. procedure SetPropValue(C: TComponent; i: Integer; Value: TComponent);
  338. begin
  339.    SetOrdProp(C,GetPropInfo(C.ClassInfo,TPropRec(PropList[i]).PropName),LongInt(Value));
  340. end;
  341. {== TMMDesigner =========================================================}
  342. constructor TMMDesigner.Create(AOwner: TComponent);
  343. var
  344.    CompOwner: TComponent;
  345. begin
  346.    inherited Create(AOwner);
  347.    {$IFDEF WIN32}
  348.    if (Owner is TDataModule) then
  349.    begin
  350.       CompOwner := Owner.Owner;
  351.    end
  352.    else {$ENDIF} CompOwner := Owner;
  353. {  TODO: DataModules currently not supported !!!        }
  354. {  if (CompOwner <> nil) and (CompOwner is TForm) then  }
  355.    if (Owner <> nil) and (Owner is TForm) then
  356.    begin
  357.       FParentForm := CompOwner as TForm;
  358.       FParentComponent := Owner;
  359.       {$IFDEF BUILD_ACTIVEX}
  360.       ParentWindow := TWinControl(aOwner).Handle;
  361.       {$ENDIF}
  362.       if assigned(_FindDesignerForWindow) then
  363.          if _FindDesignerForWindow(FParentForm.Handle) <> nil then
  364.             raise Exception.Create('Only one Designer is allowed per Form');
  365.       FActive := True;
  366.       FAutoUpdate := True;
  367.       FUpdate := False;
  368.       FSound := True;
  369.       FColor := clRed;
  370.       FLineWidth := 1;
  371.       FMargin := 6;
  372.       RuntimeHeight := -1;
  373.       FShowButton := False;
  374.       FButtonDown := False;
  375.       FButtonPressed:= False;
  376.       InitDesigner;
  377.    end
  378.    else FormOk := False;
  379.    ErrorCode := ComponentRegistered(InitCode, Self, ClassName);
  380.    if (ErrorCode <> 0) then RegisterFailed(InitCode, Self , ClassName);
  381. end;
  382. {-- TMMDesigner ---------------------------------------------------------}
  383. destructor TMMDesigner.Destroy;
  384. begin
  385.    if FormOK and (FTimer <> nil) then
  386.    begin
  387.       { Timer may be nil because of MessageDlg instead of raise }
  388.       FTimer.OnTimer := nil;
  389.       FTimer.Free;
  390.       { unhook the parent Forms WndProc }
  391.       UnHookOwner;
  392.       if assigned(_RemoveDesigner) then
  393.          _RemoveDesigner(Self);
  394.       RefreshForm(True,False);
  395.       {  RefreshCaption;}
  396.       FAllowed.Free;
  397.       FProhibited.Free;
  398.       FPortList.Free;
  399.       FConnList.Free;
  400.    end;
  401.    inherited Destroy;
  402. end;
  403. {-- TMMDesigner ---------------------------------------------------------}
  404. procedure TMMDesigner.InitDesigner;
  405. begin
  406.    if (csDesigning in ComponentState) and (FTimer = nil) then
  407.    begin
  408.       { create Timer }
  409.       try
  410.          FTimer := TTimer.Create(self);
  411.          FTimer.Interval := 1000;
  412.          FTimer.OnTimer := TimerAction;
  413.       except
  414.          MessageDlg({$IFDEF DELPHI3}SNoTimers{$ELSE}LoadStr(SNoTimers){$ENDIF},mtError,[mbOk],0);
  415.       end;
  416.       FProhibited := TStringList.Create;
  417.       FAllowed    := TList.Create;
  418.       if assigned(_AddDesigner) then
  419.          _AddDesigner(Self);
  420.       { hook the parent forms WndProc }
  421.       HookOwner;
  422.       FVisible := DesignerVisible(Self);
  423.       FPaintOk := True;
  424.       DrawPaintBox;
  425.       { Because when form is loaded nothing exist }
  426.       FPaintOk := True;
  427.    end;
  428. end;
  429. {-- TMMDesigner ---------------------------------------------------------}
  430. procedure TMMDesigner.ChangeDesigning(aValue: Boolean);
  431. begin
  432.    inherited;
  433.    InitDesigner;
  434. end;
  435. {-- TMMDesigner ---------------------------------------------------------}
  436. procedure TMMDesigner.Loaded;
  437. begin
  438.    inherited Loaded;
  439.    if not (csDesigning in ComponentState) and (FRuntimeHeight > 0) then
  440.    begin
  441.       FParentForm.ClientHeight := FRuntimeHeight;
  442.    end;
  443. end;
  444. {-- TMMDesigner ---------------------------------------------------------}
  445. procedure TMMDesigner.BeepSound(aValue: Cardinal);
  446. begin
  447.    if FSound then MessageBeep(aValue);
  448. end;
  449. {-- TMMDesigner ---------------------------------------------------------}
  450. procedure TMMDesigner.SetPen(Color: TColor; Width: integer; Style: TPenStyle);
  451. begin
  452.    with FParentForm.Canvas do
  453.    begin
  454.       Pen.Color := Color;
  455.       Pen.Width := Width;
  456.       Pen.Style := Style;
  457.    end;
  458. end;
  459. {-- TMMDesigner ---------------------------------------------------------}
  460. procedure TMMDesigner.DesignerFormPos;
  461. var
  462.    pt: TPoint;
  463. begin
  464.    if (DesignerForm <> nil) and (FParentForm <> nil) then
  465.    begin
  466.       pt := FParentForm.ClientToScreen(Point(ButtonRect.Left,0));
  467.       DesignerForm.Left := Max(1,pt.X-GetSystemMetrics(SM_CXFRAME)+(ButtonRect.Right-ButtonRect.Left)-DesignerForm.Width);
  468.       DesignerForm.Top := pt.Y;
  469.    end;
  470. end;
  471. {-- TMMDesigner ---------------------------------------------------------}
  472. procedure TMMDesigner.RefreshCaption;
  473. begin
  474.    if (FParentForm <> nil) and (FParentForm.Handle <> 0) and
  475.       not (csDestroying in FParentForm.ComponentState) then
  476.       SetWindowPos(FParentForm.Handle,0,0,0,0,0,SWP_DRAWFRAME or SWP_NOSIZE or
  477.                    SWP_NOMOVE or SWP_NOZORDER or SWP_NOACTIVATE);
  478. end;
  479. {-- TMMDesigner ---------------------------------------------------------}
  480. function TMMDEsigner.InButton(pt: TPoint): Boolean;
  481. begin
  482.    pt.X := pt.X + GetSystemMetrics(SM_CXFRAME);
  483.    pt.Y := pt.Y + NonClientHeight - 3;
  484.    {$IFDEF WIN32}
  485.    if not NewStyleControls then
  486.    {$ELSE}
  487.    if not _Win9x_ and not _WinNT4_ then
  488.    {$ENDIF}
  489.       pt.Y := pt.Y -2;
  490.    if (FParentForm.Menu <> nil) and (FParentForm.Menu.Items.Count > 0) then
  491.       pt.Y := pt.Y + GetSystemMetrics(SM_CYMENU);
  492.    MapWindowPoints(0,FParentForm.Handle,pt,1);
  493.    Result := ptInRect(ButtonRect,pt);
  494. end;
  495. {-- TMMDesigner ---------------------------------------------------------}
  496. function TMMDesigner.ButtonRect: TRect;
  497. var
  498.   ButtonWidth,
  499.   ButtonHeight,
  500.   FrameWidth,
  501.   FrameHeight: Integer;
  502. begin
  503.    {$IFDEF WIN32}
  504.    if NewStyleControls then
  505.    {$ELSE}
  506.    if _Win9x_ or _WinNT4_ then
  507.    {$ENDIF}
  508.    begin
  509.       ButtonWidth := GetSystemMetrics(SM_CXSIZE)-2;
  510.       ButtonHeight:= GetSystemMetrics(SM_CYSIZE)-4;
  511.       FrameWidth  := GetSystemMetrics(SM_CXFRAME)+2;
  512.       FrameHeight := GetSystemMetrics(SM_CYFRAME)+2;
  513.       with FParentForm do
  514.       Result := Rect(Width-FrameWidth-3*ButtonWidth-4-BitmapWidth-5,
  515.                      FrameHeight,
  516.                      Width-FrameWidth-3*ButtonWidth-4,
  517.                      FrameHeight + ButtonHeight);
  518.    end
  519.    else
  520.    begin
  521.       ButtonWidth := GetSystemMetrics(SM_CXSIZE);
  522.       ButtonHeight:= GetSystemMetrics(SM_CYSIZE);
  523.       FrameWidth  := GetSystemMetrics(SM_CXFRAME)+2;
  524.       FrameHeight := GetSystemMetrics(SM_CYFRAME);
  525.       with FParentForm do
  526.       Result := Rect(Width-FrameWidth-2*ButtonWidth-BitmapWidth-6,
  527.                      FrameHeight,
  528.                      Width-FrameWidth-2*ButtonWidth,
  529.                      FrameHeight + ButtonHeight);
  530.    end;
  531. end;
  532. {-- TMMDesigner ---------------------------------------------------------}
  533. procedure TMMDesigner.PaintButton(Down: Boolean);
  534. var
  535.    R    : TRect;
  536.    CV   : TCanvas;
  537. begin
  538.    R  := ButtonRect;
  539.    CV := TCanvas.Create;
  540.    CV.Handle := GetWindowDC(FParentForm.Handle);
  541.    {$IFDEF WIN32}
  542.    if NewStyleControls then
  543.    {$ELSE}
  544.    if _Win9x_ or _WinNT4_ then
  545.    {$ENDIF}
  546.    with CV do
  547.    begin
  548.       if Down then
  549.       begin
  550.          Frame3D(CV, R, clBlack, clBtnHighLight, 1);
  551.          Frame3D(CV, R, clBtnShadow, clBtnFace, 1);
  552.          Brush.Color := clBtnFace;
  553.          FillRect(R);
  554.          OffsetRect(R,1,1);
  555.       end
  556.       else
  557.       begin
  558.          Frame3D(CV, R, clBtnHighLight, clBlack, 1);
  559.          Frame3D(CV, R, clBtnFace, clBtnShadow, 1);
  560.          Brush.Color := clBtnFace;
  561.          FillRect(R);
  562.       end;
  563.    end
  564.    else
  565.    with CV do
  566.    begin
  567.       Pen.Color := clBlack;
  568.       MoveTo(R.Left-1,R.Top);
  569.       LineTo(R.Left-1,R.Bottom);
  570.       if Down then
  571.       begin
  572.          Frame3D(CV, R, clBtnShadow, clBtnFace, 1);
  573.          Brush.Color := clBtnFace;
  574.          FillRect(R);
  575.          OffsetRect(R,2,2);
  576.       end
  577.       else
  578.       begin
  579.          Frame3D(CV, R, clBtnHighLight, clBtnShadow, 1);
  580.          Frame3D(CV, R, clBtnFace, clBtnShadow, 1);
  581.          Brush.Color := clBtnFace;
  582.          FillRect(R);
  583.       end;
  584.    end;
  585.    R.Top := R.Top+((R.Bottom-R.Top) - BitmapHeight) div 2;
  586.    DrawTransparentBitmap(CV.Handle,DesignBitmap,R.Left+1,R.Top,GetTransparentColor(DesignBitmap));
  587.    ReleaseDC(FParentForm.Handle, CV.Handle);
  588.    CV.Free;
  589. end;
  590. {-- TMMDesigner ---------------------------------------------------------}
  591. procedure TMMDesigner.HookWndProc(var Message: TMessage);
  592. var
  593.    CompRec: TCompRect;
  594.    i,H    : integer;
  595.    pt     : TPoint;
  596.    Down   : Boolean;
  597. begin
  598.     with Message do
  599.     begin
  600.        case Msg of
  601.          WM_ACTIVATEAPP,
  602.          WM_ACTIVATE: if ((Msg = WM_ACTIVATEAPP) and Boolean(wParam)) or
  603.                          ((Msg = WM_ACTIVATE) and (LoWord(wParam) = WA_INACTIVE)) then
  604.          begin
  605.             if MMDesign.Dragging or Adjusting then
  606.              begin
  607.                DoneDragging;
  608.                BeepSound(MB_ICONHAND);
  609.             end
  610.             else PaintOK := True;
  611.             if (DesignerForm <> nil) then
  612.             begin
  613.                SendMessage(FParentForm.Handle, WM_NCACTIVATE, 1, 0);
  614.                Message.Result := 0;
  615.             end;
  616.          end;
  617.          WM_SIZE:
  618.          begin
  619.             if FShowButton then RefreshCaption;
  620.             if FVisible then
  621.             begin
  622.                if not DesignerVisible(Self) then
  623.                begin
  624.                   FVisible := False;
  625.                   RefreshForm(True,True);
  626.                end;
  627.             end
  628.             else if DesignerVisible(Self) then
  629.             begin
  630.                FVisible := True;
  631.                PaintOK := True;
  632.                DrawPaintBox;
  633.             end;
  634.          end;
  635.          WM_NCPAINT,
  636.          WM_NCACTIVATE: if FShowButton then
  637.          begin
  638.             inherited HookWndProc(Message);
  639.             if not IsIconic(FParentForm.Handle) then PaintButton(False);
  640.             exit;
  641.          end;
  642.          WM_NCHITTEST: if FButtonPressed then
  643.          begin
  644.             inherited HookWndProc(Message);
  645.             Message.Result := Longint(HTCAPTION);
  646.             exit;
  647.          end;
  648.          WM_NCLBUTTONDOWN,
  649.          WM_NCLBUTTONDBLCLK,
  650.          WM_NCRBUTTONDOWN,
  651.          WM_NCRBUTTONDBLCLK:
  652.          begin
  653.             if FShowButton and (wParam in [HTCAPTION]) and InButton(SmallPointToPoint(TSmallPoint(lParam))) then
  654.             begin
  655.                Windows.SetFocus(FParentForm.Handle);
  656.                FButtonPressed:= True;
  657.                FButtonDown := True;
  658.                PaintButton(True);
  659.                exit;
  660.             end;
  661.          end;
  662.          WM_NCMOUSEMOVE: if FButtonPressed then
  663.          begin
  664.             pt := SmallPointToPoint(TSmallPoint(lParam));
  665.             Down := InButton(pt);
  666.             if FButtonDown <> Down then
  667.             begin
  668.                FButtonDown := Down;
  669.                PaintButton(FButtonDown);
  670.             end;
  671.             exit;
  672.          end;
  673.          WM_NCLBUTTONUP,
  674.          WM_NCRBUTTONUP: if FButtonPressed then
  675.          begin
  676.             FButtonPressed := False;
  677.             PaintButton(False);
  678.             if (Msg = WM_NCLBUTTONUP) and FActive then
  679.             begin
  680.                if InButton(SmallPointToPoint(TSmallPoint(lParam))) then
  681.                begin
  682.                   if not FVisible or (FRuntimeHeight = FParentForm.ClientHeight) then
  683.                   begin
  684.                      H := FParentForm.ClientHeight;
  685.                      for i := 0 to FParentForm.ComponentCount-1 do
  686.                      begin
  687.                         GetComponentPos(FParentForm.Components[i],CompRec);
  688.                         H := Max(H,CompRec.Top+CompRec.Height+5);
  689.                      end;
  690.                      FParentForm.ClientHeight := H;
  691.                   end
  692.                   else
  693.                   begin                                 { Top }
  694.                      if (FRuntimeHeight = -1) then
  695.                          H := HiWord(DesignInfo)-5
  696.                      else
  697.                          H := FRuntimeHeight;
  698.                      FParentForm.ClientHeight := H;
  699.                   end;
  700.                end;
  701.                exit;
  702.             end;
  703.             if InButton(SmallPointToPoint(TSmallPoint(lParam))) then
  704.             begin
  705.                DesignerForm := TMMDesignerForm.Create(nil);
  706.                DesignerFormPos;
  707.                DesignerForm.Designer := Self;
  708.                DesignerForm.ShowModal;
  709.                DesignerForm.Free;
  710.                DesignerForm := nil;
  711.             end;
  712.             exit;
  713.          end;
  714.        end;
  715.        inherited HookWndProc(Message);
  716.     end;
  717. end;
  718. {-- TMMDesigner ---------------------------------------------------------}
  719. procedure TMMDesigner.SetShowButton(aValue: Boolean);
  720. begin
  721.    if (aValue <> FShowButton) then
  722.    begin
  723.       FShowButton := aValue;
  724.       { redraw the Forms caption }
  725.       RefreshCaption;
  726.    end;
  727. end;
  728. {-- TMMDesigner ---------------------------------------------------------}
  729. procedure TMMDesigner.RefreshForm(ControlsOk, ComponentsOk: Boolean);
  730. var
  731.    Wnd: THandle;
  732.    procedure RefreshControls(Parent: TWinControl);
  733.    var
  734.       i : Integer;
  735.    begin
  736.       with Parent do
  737.       for i := 0 to ControlCount - 1 do
  738.       begin
  739.          if Controls[i] is TWinControl then
  740.             SetWindowPos((Controls[i] as TWinControl).Handle,
  741.                          0, 0, 0, 0, 0, SWP_FRAMECHANGED+SWP_NOZORDER+
  742.                          SWP_NOMOVE+SWP_NOSIZE+SWP_NOACTIVATE);
  743.          Controls[i].Refresh;
  744.          if Controls[i] is TWinControl then
  745.             RefreshControls(Controls[i] as TWinControl);
  746.       end
  747.    end;
  748. begin
  749.    if FormOK then
  750.    with FParentForm do
  751.    begin
  752.       RefreshControls(FParentForm);
  753.       if ComponentsOk then
  754.       begin
  755.          { Let's look for window's childs, if they are not controls,
  756.            then they are components or their captions }
  757.          Wnd := GetWindow(Handle,GW_CHILD);
  758.          while Wnd <> 0 do
  759.          begin
  760.             if FindControl(Wnd) = nil then
  761.                InvalidateRect(Wnd,nil,False);
  762.             Wnd := GetWindow(Wnd,GW_HWNDNEXT);
  763.          end;
  764.       end;
  765.       Refresh;
  766.    end;
  767. end;
  768. {-- TMMDesigner ---------------------------------------------------------}
  769. procedure TMMDesigner.GetComponentPos(Comp: TComponent; var CompRect: TCompRect);
  770. var
  771.    Pt: TPoint;
  772. begin
  773.    with CompRect do
  774.    if Comp is TControl then
  775.    begin
  776.       Ok := True;
  777.       Pt := ClientToClient(FParentForm,Comp as TControl,Point(0,0));
  778.       Left := Pt.X;
  779.       Top  := Pt.Y;
  780.       Width := (Comp as TControl).Width;
  781.       Height := (Comp as TControl).Height;
  782.    end
  783.    else if Comp <> nil then
  784.    begin
  785.       Ok := True;
  786.       Left := LoWord(Comp.DesignInfo);
  787.       Top := HiWord(Comp.DesignInfo);
  788.       {$IFDEF WIN32}
  789.       if (FParentComponent is TDataModule) then
  790.       begin
  791.          inc(Left,2);
  792.          inc(Top,2);
  793.       end;
  794.       {$ENDIF}
  795.       Width := ComponentWidth;
  796.       Height := ComponentHeight;
  797.    end
  798.    else OK := False;
  799. end;
  800. {-- TMMDesigner ---------------------------------------------------------}
  801. procedure TMMDesigner.DrawConnection(CompRect1, CompRect2: TCompRect;ArrowOk: Boolean);
  802. var
  803.    x1,y1,x2,y2: integer;
  804. begin
  805.    with FParentForm.Canvas do
  806.    begin
  807.       x1 := CompRect1.Left + CompRect1.Width;
  808.       y1 := CompRect1.Top + CompRect1.Height div 2 - (CompRect1.Height+1) mod 2;
  809.       x2 := CompRect2.Left;
  810.       y2 := CompRect2.Top + CompRect2.Height div 2 - (CompRect2.Height+1) mod 2;
  811.       if (CompRect1.Left + CompRect1.Width+2*FMargin > CompRect2.Left) and
  812.          ((CompRect1.Top <> CompRect2.Top) or (CompRect1.Left > CompRect2.Left)) then
  813.       begin
  814.          if (CompRect1.Top > CompRect2.Top) then
  815.          begin
  816.             if (CompRect2.Top + CompRect2.Height + 2*FMargin > CompRect1.Top) then
  817.             begin
  818.                MoveTo(x1,y1);
  819.                LineTo(Max(x1+FMargin,CompRect2.Left+CompRect2.Width+FMargin),y1);
  820.                LineTo(Max(x1+FMargin,CompRect2.Left+CompRect2.Width+FMargin),CompRect2.Top-FMargin);
  821.                LineTo(x2-FMargin,CompRect2.Top-FMargin);
  822.                LineTo(x2-FMargin,y2);
  823.                LineTo(x2,y2);
  824.             end
  825.             else
  826.             begin
  827.                MoveTo(x1,y1);
  828.                LineTo(Max(x1+FMargin,CompRect2.Left+CompRect2.Width+FMargin),y1);
  829.                LineTo(Max(x1+FMargin,CompRect2.Left+CompRect2.Width+FMargin),CompRect2.Top+CompRect2.Height+FMargin);
  830.                LineTo(x2-FMargin,CompRect2.Top+CompRect2.Height+FMargin);
  831.                LineTo(x2-FMargin,y2);
  832.                LineTo(x2,y2);
  833.             end;
  834.          end
  835.          else
  836.          begin
  837.             if (CompRect1.Top + CompRect1.Height+2*FMargin > CompRect2.Top) then
  838.             begin
  839.                MoveTo(x1,y1);
  840.                LineTo(Max(x1+FMargin,CompRect2.Left+CompRect2.Width+FMargin),y1);
  841.                LineTo(Max(x1+FMargin,CompRect2.Left+CompRect2.Width+FMargin),CompRect2.Top+CompRect2.Height+FMargin);
  842.                LineTo(x2-FMargin,CompRect2.Top+CompRect2.Height+FMargin);
  843.                LineTo(x2-FMargin,y2);
  844.                LineTo(x2,y2);
  845.             end
  846.             else
  847.             begin
  848.                MoveTo(x1,y1);
  849.                LineTo(Max(x1+FMargin,CompRect2.Left+CompRect2.Width+FMargin),y1);
  850.                LineTo(Max(x1+FMargin,CompRect2.Left+CompRect2.Width+FMargin),CompRect2.Top-FMargin);
  851.                LineTo(x2-FMargin,CompRect2.Top-FMargin);
  852.                LineTo(x2-FMargin,y2);
  853.                LineTo(x2,y2);
  854.             end;
  855.          end;
  856.       end
  857.       else
  858.       begin
  859.          MoveTo(x1,y1);
  860.          LineTo(x2-FMargin,y1);
  861.          LineTo(x2-FMargin,y2);
  862.          LineTo(x2,y2);
  863.       end;
  864.       if ArrowOk then
  865.       begin
  866.          MoveTo(x2-2,y2-1); LineTo(x2-2,y2+2);
  867.          MoveTo(x2-3,y2-2); LineTo(x2-3,y2+3);
  868.       end;
  869.    end;
  870. end;
  871. type
  872.     TCustomControlWithCanvas = class(TCustomControl)
  873.     public
  874.        property Canvas;
  875.     end;
  876. {-- TMMDesigner ---------------------------------------------------------}
  877. procedure TMMDesigner.DrawPorts(Comp: TComponent; InPort,OutPort: Boolean);
  878. var
  879.    R: TRect;
  880.    x1,y1,x2,y2: integer;
  881.    CompRect: TCompRect;
  882. begin
  883.    if (Comp is TControl) and not ControlVisible(Comp as TControl) then
  884.       Exit;
  885.    GetComponentPos(Comp, CompRect);
  886.    with FParentForm.Canvas do
  887.    begin
  888.       Brush.Color := clNavy;
  889.       y1 := CompRect.Top + (CompRect.Height div 2 - Griff div 2 - (CompRect.Height+1) mod 2);
  890.       y2 := y1 + Griff;
  891.       if InPort then
  892.       begin
  893.         x1 := CompRect.Left - Griff div 2;
  894.         x2 := x1 + Griff;
  895.         R := Rect(x1,y1,x2,y2);
  896.         FillRect(R);
  897.         {$IFDEF BUILD_ACTIVEX}
  898.         if (Comp is TCustomControl) then
  899.         with TCustomControlWithCanvas(Comp) do
  900.         begin
  901.            MapWindowPoints(FParentForm.Handle,Handle,R,2);
  902.            Canvas.Brush.Color := clNavy;
  903.            Canvas.FillRect(R);
  904.         end;
  905.         {$ENDIF}
  906.       end;
  907.       if OutPort then
  908.       begin
  909.         x1 := CompRect.Left + CompRect.Width + Griff div 2;
  910.         x2 := x1 - Griff;
  911.         R := Rect(x1,y1,x2,y2);
  912.         FillRect(R);
  913.         {$IFDEF BUILD_ACTIVEX}
  914.         if (Comp is TCustomControl) then
  915.         with TCustomControlWithCanvas(Comp) do
  916.         begin
  917.            MapWindowPoints(FParentForm.Handle,Handle,R,2);
  918.            Canvas.Brush.Color := clNavy;
  919.            Canvas.FillRect(R);
  920.         end;
  921.         {$ENDIF}
  922.       end;
  923.     end;
  924. end;
  925. {-- Port utils ----------------------------------------------------------}
  926. type
  927.    TInfoRec = packed record
  928.     case Byte of
  929.         0 : (InPort: WordBool; OutPort: WordBool);
  930.         1 : (Long: LongInt);
  931.    end;
  932. {------------------------------------------------------------------------}
  933. function GetPortInfo(Designer: TMMDesigner; i: Integer): TInfoRec;
  934. begin
  935.    if not Designer.FValidLists and not Designer.FRebuilding then
  936.       Designer.RebuildLists;
  937.    if Designer.FPortList = nil then
  938.       Result.Long := 0
  939.    else
  940.       Result.Long := LongInt(Designer.FPortList[i]);
  941. end;
  942. {------------------------------------------------------------------------}
  943. procedure SetPortInfo(Designer: TMMDesigner; i: Integer; const Info: TInfoRec);
  944. begin
  945.    Designer.FPortList[i] := Pointer(Info.Long);
  946. end;
  947. {-- TMMDesigner ---------------------------------------------------------}
  948. procedure TMMDesigner.RebuildLists;
  949.    procedure AddConn(C1, C2: TComponent);
  950.    begin
  951.       FConnList.Add(C1);
  952.       FConnList.Add(C2);
  953.    end;
  954.    procedure FindReferred(C : TComponent; Prop : Integer; PropType : TPropType);
  955.    var
  956.       i           : Integer;
  957.       R           : TComponent;
  958.       CInfo, RInfo: TInfoRec;
  959.    begin
  960.     for i := 0 to FParentComponent.ComponentCount - 1 do
  961.     begin
  962.        R := FParentComponent.Components[i];
  963.        if C <> R then
  964.        with TPropRec(PropList[Prop]) do
  965.        if ((PropType = ptOutput) and (R is ClassTo)) or
  966.           ((PropType = ptInput) and (R is ClassFrom)) then
  967.           if not HasException(C,R,Prop) and
  968.              (not Assigned(CheckProc) or
  969.               ((PropType = ptOutput) and CheckProc(C,R)) or
  970.               ((PropType = ptInput) and CheckProc(R,C))) then
  971.              begin
  972.                 CInfo := GetPortInfo(Self,C.ComponentIndex);
  973.                 RInfo := GetPortInfo(Self,R.ComponentIndex);
  974.                 if PropType = ptOutput then
  975.                 begin
  976.                    CInfo.OutPort := True;
  977.                    RInfo.InPort  := True;
  978.                    if GetPropValue(C,Prop) = R then
  979.                       AddConn(C,R);
  980.                 end
  981.                 else
  982.                 begin
  983.                    RInfo.OutPort := True;
  984.                    CInfo.InPort  := True;
  985.                    if GetPropValue(C,Prop) = R then
  986.                       AddConn(R,C);
  987.                 end;
  988.                 SetPortInfo(Self,C.ComponentIndex,CInfo);
  989.                 SetPortInfo(Self,R.ComponentIndex,RInfo);
  990.              end;
  991.        end;
  992.     end;
  993. var
  994.     i, j : Integer;
  995.     C : TComponent;
  996. begin
  997.     FRebuilding := True;
  998.     try
  999.         if FPortList <> nil then
  1000.            FPortList.Clear
  1001.         else
  1002.            FPortList:= TList.Create;
  1003.         if FConnList <> nil then
  1004.            FConnList.Clear
  1005.         else
  1006.            FConnList := TList.Create;
  1007.         with FParentComponent do
  1008.         begin
  1009.            FPortList.Capacity := ComponentCount;
  1010.            for i := 0 to ComponentCount - 1 do
  1011.                FPortList.Add(nil);
  1012.            for i := 0 to ComponentCount - 1 do
  1013.            begin
  1014.               C := Components[i];
  1015.               for j := 0 to PropList.Count - 1 do
  1016.               if Allowed[j] <> nil then
  1017.               with TPropRec(PropList[j]) do
  1018.               if PropType = ptOutput then
  1019.               begin
  1020.                  if (C is ClassFrom) and CheckPropAvail(C,j,True) then
  1021.                      FindReferred(C,j,ptOutput)
  1022.               end
  1023.               else if PropType = ptInput then
  1024.               begin
  1025.                  if (C is ClassTo) and CheckPropAvail(C,j,True) then
  1026.                      FindReferred(C,j,ptInput)
  1027.               end;
  1028.            end;
  1029.         end;
  1030.     finally
  1031.         FRebuilding := False;
  1032.     end;
  1033.     FValidLists := True;
  1034. end;
  1035. {-- TMMDesigner ---------------------------------------------------------}
  1036. procedure TMMDesigner.Notification(AComponent: TComponent; Operation: TOperation);
  1037. begin
  1038.     inherited Notification(AComponent,Operation);
  1039.     FValidLists := False;
  1040. end;
  1041. {-- TMMDesigner ---------------------------------------------------------}
  1042. procedure TMMDesigner.DrawPaintBox;
  1043. var
  1044.    i: integer;
  1045. var
  1046.    Info     : TInfoRec;
  1047.    procedure DrawConn(C1, C2 : TComponent);
  1048.    var
  1049.       R1, R2 : TCompRect;
  1050.    begin
  1051.       GetComponentPos(C1, R1);
  1052.       GetComponentPos(C2, R2);
  1053.       DrawConnection(R1,R2,True);
  1054.    end;
  1055.    procedure DrawConnections;
  1056.    var
  1057.     i : Integer;
  1058.    begin
  1059.     for i := 0 to FConnList.Count div 2 - 1 do
  1060.         DrawConn(TComponent(FConnList[2*i]),TComponent(FConnList[2*i+1]));
  1061.    end;
  1062. begin
  1063.    if IsCompiling then exit;
  1064.    if PaintOk then FPaintOk := True;
  1065.    if (csDesigning in ComponentState) and FPaintOk and FActive and FVisible then
  1066.    with FParentComponent do
  1067.    begin
  1068.       RefreshForm(True,True);
  1069.       SetPen(FColor,FLineWidth,psSolid);
  1070.       RebuildLists;
  1071.       for i := 0 to ComponentCount-1 do
  1072.       begin
  1073.          Info := GetPortInfo(Self,i);
  1074.          { draw all input and output ports }
  1075.          DrawPorts(Components[i],Info.InPort,Info.OutPort);
  1076.       end;
  1077.       DrawConnections;
  1078.       if Adjusting and assigned(_RedrawTrack) then
  1079.          _RedrawTrack(True);
  1080.       inc(PaintCount);
  1081.       if PaintCount >= CreateCount then
  1082.       begin
  1083.          PaintOk := False;
  1084.          PaintCount := 0;
  1085.       end;
  1086.       FPaintOk := False;
  1087.    end
  1088.    else if PaintOk and FActive and Adjusting then
  1089.    begin
  1090.       if assigned(_RedrawTrack) then
  1091.          _RedrawTrack(True);
  1092.       PaintOK := False;
  1093.    end;
  1094. end;
  1095. {-- TMMDesigner ---------------------------------------------------------}
  1096. procedure TMMDesigner.TimerAction(Sender: TObject);
  1097. begin
  1098.    if AutoUpdate then DrawPaintBox;
  1099. end;
  1100. {-- TMMDesigner ---------------------------------------------------------}
  1101. procedure TMMDesigner.SetLineWidth(aValue: integer);
  1102. begin
  1103.    if (FLineWidth <> aValue) then
  1104.    begin
  1105.       FLineWidth := aValue;
  1106.       FPaintOk := True;
  1107.       DrawPaintBox;
  1108.    end;
  1109. end;
  1110. {-- TMMDesigner ---------------------------------------------------------}
  1111. procedure TMMDesigner.SetMargin(aValue: integer);
  1112. begin
  1113.    if (FMargin <> aValue) then
  1114.    begin
  1115.       FMargin := aValue;
  1116.       FPaintOk := True;
  1117.       DrawPaintBox;
  1118.    end;
  1119. end;
  1120. {-- TMMDesigner ---------------------------------------------------------}
  1121. procedure TMMDesigner.SetColor(aValue: TColor);
  1122. begin
  1123.    if (FColor <> aValue) then
  1124.    begin
  1125.       FColor := aValue;
  1126.       FPaintOk := True;
  1127.       DrawPaintBox;
  1128.    end;
  1129. end;
  1130. {-- TMMDesigner ---------------------------------------------------------}
  1131. procedure TMMDesigner.SetActive(aValue: Boolean);
  1132. begin
  1133.    if aValue then
  1134.    begin
  1135.       FPaintOk := True;
  1136.       DrawPaintBox;
  1137.    end
  1138.    else
  1139.    begin
  1140.       RefreshForm(True,True);
  1141.    end;
  1142.    FActive := aValue;
  1143. end;
  1144. {-- TMMDesigner ---------------------------------------------------------}
  1145. procedure TMMDesigner.SetUpdate(aValue: Boolean);
  1146. begin
  1147.    if aValue then
  1148.    begin
  1149.       Active := False;
  1150.       Active := True;
  1151.    end;
  1152.    FUpdate := False;
  1153. end;
  1154. {-- TMMDesigner ---------------------------------------------------------}
  1155. function TMMDesigner.FindTarget(Form: TForm; Wnd: HWND; var Pt: TPoint;
  1156.                                 var TargetType: TPropType; var R: TRect): TComponent;
  1157. var
  1158.    i: Integer;
  1159.    function Check(C: TComponent): Boolean;
  1160.    begin
  1161.       if C = nil then
  1162.       begin
  1163.          Result := False;
  1164.          Exit;
  1165.       end;
  1166.       Result := True;
  1167.       if HasInput(C) and CheckInput(C,Pt,R) then
  1168.       begin
  1169.          TargetType := ptInput;
  1170.          Exit;
  1171.       end;
  1172.       if HasOutput(C) and CheckOutput(C,Pt,R) then
  1173.       begin
  1174.          TargetType := ptOutput;
  1175.          Exit;
  1176.       end;
  1177.       Result := False;
  1178.    end;
  1179.    procedure MapIt;
  1180.    begin
  1181.       MapWindowPoints(Wnd,Form.Handle,R,2);
  1182.       MapWindowPoints(Wnd,Form.Handle,Pt,1);
  1183.    end;
  1184. begin
  1185.    MapIt;
  1186.    with FParentComponent do
  1187.    for i := 0 to ComponentCount - 1 do
  1188.    if Check(Components[i]) then
  1189.    begin
  1190.       Result := Components[i];
  1191.       Exit;
  1192.    end;
  1193.    Result := nil;
  1194. end;
  1195. {-- TMMDesigner ---------------------------------------------------------}
  1196. function TMMDesigner.HasInput(C: TComponent): Boolean;
  1197. begin
  1198.    Result := GetPortInfo(Self,C.ComponentIndex).InPort;
  1199. end;
  1200. {-- TMMDesigner ---------------------------------------------------------}
  1201. function TMMDesigner.HasOutput(C: TComponent): Boolean;
  1202. begin
  1203.    Result := GetPortInfo(Self,C.ComponentIndex).OutPort;
  1204. end;
  1205. {-- TMMDesigner ---------------------------------------------------------}
  1206. function TMMDesigner.HasPotentialInput(C: TComponent): Boolean;
  1207. begin
  1208.    Result := HasInput(C);
  1209. end;
  1210. {-- TMMDesigner ---------------------------------------------------------}
  1211. function TMMDesigner.HasPotentialOutput(C: TComponent): Boolean;
  1212. begin
  1213.    Result := HasOutput(C);
  1214. end;
  1215. {-- TMMDesigner ---------------------------------------------------------}
  1216. function TMMDesigner.CheckInput(C: TComponent; Pt: TPoint; var R: TRect): Boolean;
  1217. begin
  1218.    R := LeftGriff(C);
  1219.    if C is TControl then
  1220.    begin
  1221.       R.TopLeft     := ClientToClient(GetParentForm(C as TControl), (C as TControl).Parent, R.TopLeft);
  1222.       R.BottomRight := ClientToClient(GetParentForm(C as TControl), (C as TControl).Parent, R.BottomRight);
  1223.    end;
  1224.    Result   := PtInRect(R, Pt);
  1225. end;
  1226. {-- TMMDesigner ---------------------------------------------------------}
  1227. function TMMDesigner.CheckOutput(C: TComponent; Pt: TPoint; var R: TRect): Boolean;
  1228. begin
  1229.    R := RightGriff(C);
  1230.    if C is TControl then
  1231.    begin
  1232.       R.TopLeft     := ClientToClient(GetParentForm(C as TControl), (C as TControl).Parent, R.TopLeft);
  1233.       R.BottomRight := ClientToClient(GetParentForm(C as TControl), (C as TControl).Parent, R.BottomRight);
  1234.    end;
  1235.    Result := PtInRect(R, Pt);
  1236. end;
  1237. {-- TMMDesigner ---------------------------------------------------------}
  1238. function TMMDesigner.HasException(CompFrom: TComponent; CompTo: TComponent;
  1239.                       Index: Integer): Boolean;
  1240. var
  1241.    i         : Integer;
  1242.    Pt        : TPropType;
  1243.    CFrom, CTo: TClass;
  1244.    PName     : string;
  1245. begin
  1246.    with TPropRec(PropList[Index]) do
  1247.    begin
  1248.       if CompFrom = nil then
  1249.          CFrom := ClassFrom
  1250.       else
  1251.          CFrom := CompFrom.ClassType;
  1252.       if CompTo = nil then
  1253.          CTo := ClassTo
  1254.       else
  1255.          CTo := CompTo.ClassType;
  1256.       PName   := PropName;
  1257.       Pt      := PropType;
  1258.    end;
  1259.    for i := 0 to ExcPropList.Count - 1 do
  1260.    with TPropRec(ExcPropList[i]) do
  1261.    if (PropType = Pt) and (PropName = PName) and
  1262.       ((ClassFrom = nil) or CFrom.InheritsFrom(ClassFrom)) and
  1263.       ((ClassTo = nil) or CTo.InheritsFrom(ClassTo)) and
  1264.       ((@CheckProc = nil) or CheckProc(CompFrom,CompTo)) then
  1265.    begin
  1266.       Result := True;
  1267.       Exit;
  1268.    end;
  1269.    Result := False;
  1270. end;
  1271. {-- TMMDesigner ---------------------------------------------------------}
  1272. function TMMDesigner.FindProp(Pt: TPropType; CFrom: TComponent; CTo: TComponent;
  1273.                   StartFrom: Integer): Integer;
  1274. var
  1275.     i : Integer;
  1276. begin
  1277.    for i := StartFrom + 1 to PropList.Count - 1 do
  1278.    with TPropRec(PropList[i]) do
  1279.    if (PropType = Pt) then
  1280.     if Allowed[i] <> nil then
  1281.       if (CFrom = nil) or ((CFrom is ClassFrom) and CheckPropAvail(CFrom,i,PropType=ptOutput)) then
  1282.          if (CTo = nil) or ((CTo is ClassTo) and CheckPropAvail(CTo,i,PropType=ptInput)) then
  1283.             if not HasException(CFrom,CTo,i) then
  1284.             begin
  1285.                Result := i;
  1286.                Exit;
  1287.             end;
  1288.    Result := -1;
  1289. end;
  1290. {-- TMMDesigner ---------------------------------------------------------}
  1291. function TMMDesigner.FindRef(PropType: TPropType;C: TComponent;StartFrom: Integer): Integer;
  1292. begin
  1293.    if PropType = ptInput then
  1294.       Result := FindProp(ptInput,nil,C,StartFrom)
  1295.    else
  1296.       Result := FindProp(ptOutput,C,nil,StartFrom);
  1297. end;
  1298. {-- TMMDesigner ---------------------------------------------------------}
  1299. function TMMDesigner.FindRefs(PropType:TPropType;R,C:TComponent;StartFrom:Integer):Integer;
  1300. begin
  1301.    if PropType = ptInput then
  1302.       Result := FindProp(ptOutput,R,C,StartFrom)
  1303.    else
  1304.       Result := FindProp(ptInput,C,R,StartFrom);
  1305. end;
  1306. {-- TMMDesigner ---------------------------------------------------------}
  1307. function TMMDesigner.FindConnectProp(C1,C2: TComponent): Integer;
  1308. var
  1309.    i: Integer;
  1310.    FirstBusy : Integer;
  1311. begin
  1312.    FirstBusy := -1;
  1313.    i := FindProp(ptOutput,C1,C2,-1);
  1314.    while i <> -1 do
  1315.    begin
  1316.       with TPropRec(PropList[i]) do
  1317.       if not Assigned(CheckProc) or CheckProc(C1,C2) then
  1318.       begin
  1319.          if (GetPropValue(C1,i) = nil) then
  1320.          begin
  1321.             Result := i;
  1322.             Exit;
  1323.          end
  1324.          else if FirstBusy = -1 then
  1325.                  FirstBusy := i;
  1326.       end;
  1327.       i := FindProp(ptOutput,C1,C2,i);
  1328.    end;
  1329.    i := FindProp(ptInput,C1,C2,-1);
  1330.    while i <> -1 do
  1331.    begin
  1332.       with TPropRec(PropList[i]) do
  1333.       if not Assigned(CheckProc) or CheckProc(C1,C2) then
  1334.       begin
  1335.          if (GetPropValue(C2,i) = nil) then
  1336.          begin
  1337.             Result := i;
  1338.             Exit;
  1339.          end
  1340.          else if FirstBusy = -1 then
  1341.                  FirstBusy := i;
  1342.       end;
  1343.       i := FindProp(ptInput,C1,C2,i);
  1344.    end;
  1345.    Result := FirstBusy;
  1346. end;
  1347. {-- TMMDesigner ---------------------------------------------------------}
  1348. procedure TMMDesigner.Connect(C1,C2: TComponent);
  1349. var
  1350.     i : Integer;
  1351. begin
  1352.     i := FindConnectProp(C1,C2);
  1353.     if i <> -1 then
  1354.     begin
  1355.        with TPropRec(PropList[i]) do
  1356.        if PropType = ptOutput then
  1357.           SetPropValue(C1,i,C2)
  1358.        else
  1359.           SetPropValue(C2,i,C1);
  1360.     end;
  1361. end;
  1362. {-- TMMDesigner ---------------------------------------------------------}
  1363. function TMMDesigner.CanConnect(C1,C2: TComponent): Boolean;
  1364. begin
  1365.    Result := FindConnectProp(C1,C2) <> -1;
  1366. end;
  1367. { Out -> In }
  1368. {-- TMMDesigner ---------------------------------------------------------}
  1369. procedure TMMDesigner.GetConnected(C: TComponent; List: TList);
  1370. var
  1371.     i, j: Integer;
  1372.     R: TComponent;
  1373. begin
  1374.    List.Clear;
  1375.    for j := 0 to C.Owner.ComponentCount - 1 do
  1376.    if C.Owner.Components[j] <> C then
  1377.    begin
  1378.       R := C.Owner.Components[j];
  1379.       i := FindProp(ptOutput,C,R,-1);
  1380.       while i <> -1 do
  1381.       begin
  1382.          if (GetPropValue(C,i) = R) then Break;
  1383.          i := FindProp(ptOutput,C,R,i);
  1384.       end;
  1385.       if i <> -1 then
  1386.       begin
  1387.          List.Add(R);
  1388.          Continue;
  1389.       end;
  1390.       i := FindProp(ptInput,C,R,-1);
  1391.       while i <> -1 do
  1392.       begin
  1393.          if (GetPropValue(R,i) = C) then Break;
  1394.          i := FindProp(ptInput,C,R,i);
  1395.       end;
  1396.       if i <> -1 then
  1397.       begin
  1398.          List.Add(R);
  1399.          Continue;
  1400.       end;
  1401.    end;
  1402. end;
  1403. { Removes reference from C to others }
  1404. {-- TMMDesigner ---------------------------------------------------------}
  1405. function TMMDesigner.RemoveRef(C: TComponent; PropType: TPropType): Boolean;
  1406. var
  1407.    i: Integer;
  1408. begin
  1409.    i := FindRef(PropType,C,-1);
  1410.    while i <> -1 do
  1411.    begin
  1412.       with TPropRec(PropList[i]) do
  1413.       if (GetPropValue(C,i) <> nil) then
  1414.       begin { Ok, here it is }
  1415.          SetPropValue(C,i,nil);
  1416.          Result := True;
  1417.          Exit;
  1418.       end;
  1419.       i := FindRef(PropType,C,i);
  1420.     end;
  1421.     Result := False;
  1422. end;
  1423. { Remove references from others to C }
  1424. {-- TMMDesigner ---------------------------------------------------------}
  1425. function TMMDesigner.RemoveRefs(C: TComponent; PropType: TPropType): Boolean;
  1426. var
  1427.    i, j: Integer;
  1428.    R : TComponent;
  1429. begin
  1430.    for j := 0 to C.Owner.ComponentCount - 1 do
  1431.    begin
  1432.       R := C.Owner.Components[j];
  1433.       if R <> C then
  1434.       begin
  1435.          i := FindRefs(PropType,R,C,-1);
  1436.          while i <> -1 do
  1437.          begin
  1438.             with TPropRec(PropList[i]) do
  1439.             if (GetPropValue(R,i) = C) then
  1440.             begin
  1441.                SetPropValue(R,i,nil);
  1442.                Result := True;
  1443.                Exit;
  1444.             end;
  1445.             i := FindRefs(PropType,R,C,i);
  1446.          end;
  1447.       end;
  1448.    end;
  1449.    Result := False;
  1450. end;
  1451. {-- TMMDesigner ---------------------------------------------------------}
  1452. function TMMDesigner.RemoveInput(C: TComponent): Boolean;
  1453. begin
  1454.    Result := RemoveRef(C,ptInput);
  1455.    if not Result then
  1456.       Result := RemoveRefs(C,ptInput);
  1457. end;
  1458. {-- TMMDesigner ---------------------------------------------------------}
  1459. function TMMDesigner.RemoveOutput(C: TComponent): Boolean;
  1460. begin
  1461.    Result := RemoveRef(C,ptOutput);
  1462.    if not Result then
  1463.       Result := RemoveRefs(C,ptOutput);
  1464. end;
  1465. {-- TMMDesigner ---------------------------------------------------------}
  1466. function  TMMDesigner.Allowed : TList;
  1467. var
  1468.     i : Integer;
  1469. begin
  1470.    if FAllowed.Count <> PropList.Count then
  1471.    begin
  1472.       FAllowed.Clear;
  1473.       FAllowed.Capacity := PropList.Count;
  1474.       for i := 0 to PropList.Count - 1 do
  1475.       if FProhibited.IndexOf(TPropRec(PropList[i]).PropGroup) = -1 then
  1476.          FAllowed.Add(Pointer(1))
  1477.       else
  1478.          FAllowed.Add(Pointer(0));
  1479.    end;
  1480.    Result := FAllowed;
  1481. end;
  1482. {------------------------------------------------------------------------}
  1483. procedure FreeProps; far;
  1484. var
  1485.    i: integer;
  1486. begin
  1487.    for i := 0 to PropList.Count-1 do
  1488.        TPropRec(PropList[i]).Free;
  1489.    PropList.Free;
  1490.    for i := 0 to PropList.Count-1 do
  1491.        TPropRec(ExcPropList[i]).Free;
  1492.    ExcPropList.Free;
  1493. end;
  1494. {-- TMMDesignerForm -----------------------------------------------------}
  1495. procedure TMMDesignerForm.FormShow(Sender: TObject);
  1496.    procedure FillGroups;
  1497.    var
  1498.       i : Integer;
  1499.       Group : string;
  1500.    begin
  1501.       with GroupBox do
  1502.       begin
  1503.          Items.BeginUpdate;
  1504.          try
  1505.              Items.Clear;
  1506.              for i := 0 to PropList.Count - 1 do
  1507.              begin
  1508.                 Group := TPropRec(PropList[i]).PropGroup;
  1509.                 if Items.IndexOf(Group) = -1 then
  1510.                 begin
  1511.                    Items.Add(Group);
  1512.                    Selected[Items.Count-1] := (Designer.FProhibited.IndexOf(Group) = -1);
  1513.                 end;
  1514.              end;
  1515.          finally
  1516.             Items.EndUpdate;
  1517.          end;
  1518.       end;
  1519.    end;
  1520. begin
  1521.    btnHeight.Enabled := Designer.Active;
  1522.    ckbActive.Checked := Designer.Active;
  1523.    ckbAuto.Checked := Designer.AutoUpdate;
  1524.    ckbSound.Checked := Designer.Sound;
  1525.    FillGroups;
  1526. end;
  1527. {-- TMMDesignerForm -----------------------------------------------------}
  1528. procedure TMMDesignerForm.CheckBoxClick(Sender: TObject);
  1529. begin
  1530.    if (Sender = ckbActive) then
  1531.    begin
  1532.       Designer.Active := ckbActive.Checked;
  1533.       btnHeight.Enabled := Designer.Active;
  1534.    end
  1535.    else if (Sender = ckbAuto) then
  1536.    begin
  1537.       Designer.AutoUpdate := ckbAuto.Checked;
  1538.    end
  1539.    else if (Sender = ckbSound) then
  1540.    begin
  1541.       Designer.Sound := ckbSound.Checked;
  1542.    end;
  1543. end;
  1544. {-- TMMDesignerForm -----------------------------------------------------}
  1545. procedure TMMDesignerForm.btnHeightClick(Sender: TObject);
  1546. begin
  1547.    Adjusting := True;
  1548.    Close;
  1549. end;
  1550. {-- TMMDesignerForm -----------------------------------------------------}
  1551. procedure TMMDesignerForm.FormHide(Sender: TObject);
  1552. var
  1553.    P :TPoint;
  1554.    R: TRect;
  1555.    procedure SetupProhibited;
  1556.    var
  1557.       i : Integer;
  1558.    begin
  1559.       Designer.FProhibited.Clear;
  1560.       with GroupBox do
  1561.       for i := 0 to Items.Count - 1 do
  1562.           if not Selected[i] then
  1563.              Designer.FProhibited.Add(Items[i]);
  1564.       { Force list rebuilding }
  1565.       Designer.FAllowed.Clear;
  1566.    end;
  1567. begin
  1568.    SetupProhibited;
  1569.    if Adjusting then
  1570.    with Designer do
  1571.    begin
  1572.       R := FParentForm.ClientRect;
  1573.       MapWindowPoints(FParentForm.Handle,0,R,2);
  1574.       ClipCursor(@R);
  1575.       GetCursorPos(P);
  1576.       DragPoint := Point(0,FParentForm.ScreenToClient(P).Y);
  1577.       DragDesigner := Designer;
  1578.       PaintOK := True;
  1579.    end;
  1580. end;
  1581. {-- TMMDesignerForm -----------------------------------------------------}
  1582. procedure TMMDesignerForm.btnAllClick(Sender: TObject);
  1583. var
  1584.     i : Integer;
  1585. begin
  1586.     with GroupBox do
  1587.     for i := 0 to Items.Count - 1 do
  1588.         Selected[i] := True;
  1589. end;
  1590. {-- TMMDesignerForm -----------------------------------------------------}
  1591. procedure TMMDesignerForm.btnNoneClick(Sender: TObject);
  1592. var
  1593.     i : Integer;
  1594. begin
  1595.     with GroupBox do
  1596.     for i := 0 to Items.Count - 1 do
  1597.         Selected[i] := False;
  1598. end;
  1599. initialization
  1600.    {$IFNDEF WIN32}
  1601.    AddExitProc(FreeProps);
  1602.    {$ENDIF}
  1603.    PropList    := TList.Create;
  1604.    ExcPropList := TList.Create;
  1605.    DesignerForm := nil;
  1606. {$IFDEF WIN32}
  1607. finalization
  1608.    FreeProps;
  1609. {$ENDIF}
  1610. end.