diff options
Diffstat (limited to 'src/corelib/fpg_widget.pas')
-rw-r--r-- | src/corelib/fpg_widget.pas | 227 |
1 files changed, 148 insertions, 79 deletions
diff --git a/src/corelib/fpg_widget.pas b/src/corelib/fpg_widget.pas index 39bb4193..5e3ba007 100644 --- a/src/corelib/fpg_widget.pas +++ b/src/corelib/fpg_widget.pas @@ -34,12 +34,19 @@ type THintEvent = procedure(Sender: TObject; var AHint: TfpgString) of object; + TfpgDragEnterEvent = procedure(Sender, Source: TObject; AMimeList: TStringList; var AMimeChoice: TfpgString; var ADropAction: TfpgDropAction; var Accept: Boolean) of object; + TfpgDragDropEvent = procedure(Sender, Source: TObject; X, Y: integer; AData: variant) of object; + TfpgWidget = class(TfpgWindow) private + FAcceptDrops: boolean; FAlignRect: TfpgRect; FOnClick: TNotifyEvent; FOnDoubleClick: TMouseButtonEvent; + FOnDragDrop: TfpgDragDropEvent; + FOnDragEnter: TfpgDragEnterEvent; + FOnDragLeave: TNotifyEvent; FOnEnter: TNotifyEvent; FOnExit: TNotifyEvent; FOnMouseDown: TMouseButtonEvent; @@ -52,9 +59,12 @@ type FOnResize: TNotifyEvent; FOnScreen: boolean; FOnShowHint: THintEvent; + FDragStartPos: TfpgPoint; + alist: TList; procedure SetActiveWidget(const AValue: TfpgWidget); function IsShowHintStored: boolean; procedure SetFormDesigner(const AValue: TObject); + procedure SetAlign(const AValue: TAlign); protected procedure MsgPaint(var msg: TfpgMessageRec); message FPGM_PAINT; procedure MsgResize(var msg: TfpgMessageRec); message FPGM_RESIZE; @@ -69,6 +79,8 @@ type procedure MsgMouseEnter(var msg: TfpgMessageRec); message FPGM_MOUSEENTER; procedure MsgMouseExit(var msg: TfpgMessageRec); message FPGM_MOUSEEXIT; procedure MsgMouseScroll(var msg: TfpgMessageRec); message FPGM_SCROLL; + procedure MsgDropEnter(var msg: TfpgMessageRec); message FPGM_DROPENTER; + procedure MsgDropExit(var msg: TfpgMessageRec); message FPGM_DROPEXIT; protected FFormDesigner: TObject; FVisible: boolean; @@ -85,6 +97,8 @@ type FBackgroundColor: TfpgColor; FTextColor: TfpgColor; FIsContainer: Boolean; + FOnClickPending: Boolean; + procedure SetAcceptDrops(const AValue: boolean); virtual; function GetOnShowHint: THintEvent; virtual; procedure SetOnShowHint(const AValue: THintEvent); virtual; procedure SetBackgroundColor(const AValue: TfpgColor); virtual; @@ -98,7 +112,7 @@ type function GetHint: TfpgString; virtual; procedure SetHint(const AValue: TfpgString); virtual; procedure DoUpdateWindowPosition; override; - procedure DoAlign(AAlign: TAlign); + procedure DoAlignment; procedure DoResize; procedure DoShowHint(var AHint: TfpgString); procedure HandlePaint; virtual; @@ -122,7 +136,7 @@ type procedure InternalHandleShow; virtual; procedure HandleHide; virtual; procedure MoveAndResize(ALeft, ATop, AWidth, AHeight: TfpgCoord); - procedure RePaint; + procedure RePaint; virtual; { property events } property OnClick: TNotifyEvent read FOnClick write FOnClick; property OnDoubleClick: TMouseButtonEvent read FOnDoubleClick write FOnDoubleClick; @@ -141,8 +155,6 @@ type constructor Create(AOwner: TComponent); override; destructor Destroy; override; procedure AfterConstruction; override; - function GetClientRect: TfpgRect; virtual; - function GetBoundsRect: TfpgRect; virtual; function InDesigner: boolean; procedure InvokeHelp; virtual; procedure Realign; @@ -153,6 +165,7 @@ type procedure Invalidate; // double check this works as developers expect???? property FormDesigner: TObject read FFormDesigner write SetFormDesigner; property Parent: TfpgWidget read GetParent write SetParent; + property AcceptDrops: boolean read FAcceptDrops write SetAcceptDrops default False; property ActiveWidget: TfpgWidget read FActiveWidget write SetActiveWidget; property IsContainer: Boolean read FIsContainer; property Visible: boolean read FVisible write SetVisible default True; @@ -161,13 +174,16 @@ type { Is the widget allowed to receive keyboard focus. } property Focusable: boolean read FFocusable write FFocusable default False; property Focused: boolean read FFocused write FFocused default False; - property Anchors: TAnchors read FAnchors write FAnchors; - property Align: TAlign read FAlign write FAlign; + property Anchors: TAnchors read FAnchors write FAnchors default [anLeft, anTop]; + property Align: TAlign read FAlign write SetAlign default alNone; property Hint: TfpgString read GetHint write SetHint; property ShowHint: boolean read FShowHint write SetShowHint stored IsShowHintStored; property ParentShowHint: boolean read FParentShowHint write SetParentShowHint default True; property BackgroundColor: TfpgColor read FBackgroundColor write SetBackgroundColor default clWindowBackground; property TextColor: TfpgColor read FTextColor write SetTextColor default clText1; + property OnDragEnter: TfpgDragEnterEvent read FOnDragEnter write FOnDragEnter; + property OnDragLeave: TNotifyEvent read FOnDragLeave write FOnDragLeave; + property OnDragDrop: TfpgDragDropEvent read FOnDragDrop write FOnDragDrop; end; @@ -181,7 +197,8 @@ implementation uses fpg_constants, - fpg_menu; + fpg_menu, + fpg_form; { for OnKeyPress handling } var @@ -202,6 +219,33 @@ begin end; end; +function CompareInts(i1, i2: integer): integer; +begin + if i1 < i2 then + Result := -1 + else if i1 > i2 then + Result := 1 + else + Result := 0; +end; + +function AlignCompare(p1, p2: Pointer): integer; +var + w1: TfpgWidget; + w2: TfpgWidget; +begin + w1 := TfpgWidget(p1); + w2 := TfpgWidget(p2); + case w1.Align of + alTop: Result := CompareInts(w1.Top, w2.Top); + alBottom: Result := CompareInts(w2.Top, w1.Top); + alLeft: Result := CompareInts(w1.Left, w2.Left); + alRight: Result := CompareInts(w2.Left, w1.Left); + else + Result := 0; + end; +end; + { TfpgWidget } @@ -234,6 +278,14 @@ begin FActiveWidget.HandleSetFocus; end; +procedure TfpgWidget.SetAcceptDrops(const AValue: boolean); +begin + if FAcceptDrops = AValue then + exit; + FAcceptDrops := AValue; + DoAcceptDrops(AValue); +end; + function TfpgWidget.GetHint: TfpgString; begin Result := FHint; @@ -256,6 +308,14 @@ begin end; end; +procedure TfpgWidget.SetAlign(const AValue: TAlign); +begin + if FAlign = AValue then + Exit; + FAlign := AValue; + Realign; +end; + procedure TfpgWidget.SetVisible(const AValue: boolean); begin if FVisible = AValue then @@ -341,16 +401,6 @@ begin end; end; -function TfpgWidget.GetClientRect: TfpgRect; -begin - Result.SetRect(0, 0, Width, Height); -end; - -function TfpgWidget.GetBoundsRect: TfpgRect; -begin - Result.SetRect(Left, Top, Width+1, Height+1); -end; - function TfpgWidget.InDesigner: boolean; begin Result := (FFormDesigner <> nil) @@ -416,7 +466,9 @@ begin FShowHint := False; FParentShowHint := True; FBackgroundColor := clWindowBackground; - FTextColor := clText1; + FTextColor := clText1; + FAcceptDrops := False; + FOnClickPending := False; inherited Create(AOwner); @@ -487,6 +539,7 @@ var ss: TShiftState; consumed: boolean; wg: TfpgWidget; + wlast: TfpgWidget; begin if InDesigner then begin @@ -502,13 +555,27 @@ begin HandleKeyPress(key, ss, consumed); if not consumed then begin + { work it's way to one before top level form - forms are not focusable remember } wg := Parent; + wlast := wg; while (not consumed) and (wg <> nil) do begin wg.HandleKeyPress(key, ss, consumed); + wlast := wg; wg := wg.Parent; end; end; + { we should now be at the top level form } + if (not consumed) and (wlast <> nil) then + begin + if (wlast is TfpgForm) and Assigned(wlast.OnKeyPress) then + wlast.OnKeyPress(self, key, ss, consumed); + end; + { now finaly, lets give fpgApplication a chance } + if (not consumed) and Assigned(fpgApplication.OnKeyPress) then + begin + fpgApplication.OnKeyPress(self, key, ss, consumed); + end; end; procedure TfpgWidget.MsgKeyRelease(var msg: TfpgMessageRec); @@ -559,6 +626,7 @@ begin case msg.Params.mouse.Buttons of MOUSE_LEFT: begin + FDragStartPos.SetPoint(msg.Params.mouse.x, msg.Params.mouse.y); mb := mbLeft; HandleLMouseDown(msg.Params.mouse.x, msg.Params.mouse.y, msg.Params.mouse.shiftstate); end; @@ -585,6 +653,7 @@ var IsDblClick: boolean; begin // writeln('TfpgWidget.MsgMouseUp'); + FDragActive := False; if InDesigner then begin FFormDesigner.Dispatch(msg); @@ -600,6 +669,7 @@ begin case msg.Params.mouse.Buttons of MOUSE_LEFT: begin + FOnClickPending := True; mb := mbLeft; if uLastClickWidget = self then IsDblClick := ((fpgGetTickCount - uLastClickTime) <= DOUBLECLICK_MS) @@ -613,7 +683,7 @@ begin uLastClickTime := fpgGetTickCount; if IsDblClick then begin - + FOnClickPending := False; { When Double Click occurs we don't want single click } HandleDoubleClick(msg.Params.mouse.x, msg.Params.mouse.y, msg.Params.mouse.Buttons, msg.Params.mouse.shiftstate); if Assigned(FOnDoubleClick) then FOnDoubleClick(self, mb, msg.Params.mouse.shiftstate, @@ -649,6 +719,16 @@ begin Exit; end; + if (msg.Params.mouse.Buttons and MOUSE_LEFT) = MOUSE_LEFT then + begin + if not FDragActive and (FDragStartPos.ManhattanLength(fpgPoint(msg.Params.mouse.x, msg.Params.mouse.y)) > fpgApplication.StartDragDistance) then + begin + FDragActive := True; + // In Windows dragging is a blocking function, so FDragActive is false after this call + DoDragStartDetected; + end; + end; + HandleMouseMove(msg.Params.mouse.x, msg.Params.mouse.y, msg.Params.mouse.Buttons, msg.Params.mouse.shiftstate); if Assigned(OnMouseMove) then OnMouseMove(self, msg.Params.mouse.shiftstate, @@ -710,6 +790,16 @@ begin msg.Params.mouse.shiftstate, msg.Params.mouse.delta); end; +procedure TfpgWidget.MsgDropEnter(var msg: TfpgMessageRec); +begin + // do nothing +end; + +procedure TfpgWidget.MsgDropExit(var msg: TfpgMessageRec); +begin + // do nothing +end; + function TfpgWidget.GetOnShowHint: THintEvent; begin Result := FOnShowHint; @@ -942,7 +1032,7 @@ end; procedure TfpgWidget.HandleLMouseUp(x, y: integer; shiftstate: TShiftState); begin - if Assigned(FOnClick) then + if FOnClickPending and Assigned(FOnClick) then FOnClick(self); end; @@ -1119,25 +1209,39 @@ var dy: integer; dw: integer; dh: integer; + w: TfpgWidget; begin if (csLoading in ComponentState) then Exit; //==> // writeln('HandleAlignments - ', Classname); FAlignRect := GetClientRect; - DoAlign(alTop); - DoAlign(alBottom); - DoAlign(alLeft); - DoAlign(alRight); - DoAlign(alClient); + alist := TList.Create; + try + for n := 0 to ComponentCount - 1 do + if Components[n] is TfpgWidget then + begin + w := TfpgWidget(Components[n]); + if (w.Align <> alNone) and (w.Visible) then + alist.Add(w); + end; + + DoAlignment; + //DoAlign(alTop); + //DoAlign(alBottom); + //DoAlign(alLeft); + //DoAlign(alRight); + //DoAlign(alClient); + finally + alist.Free; + end; // handle anchors finally for alNone for n := 0 to ComponentCount - 1 do if (Components[n] is TfpgWidget) then begin wg := TfpgWidget(Components[n]); - if (wg.FAlign = alNone) and - ((anBottom in wg.Anchors) or (anRight in wg.Anchors)) then + if (wg.FAlign = alNone) and ([anLeft, anTop] <> wg.Anchors) then begin // we must alter the window dx := 0; @@ -1145,15 +1249,21 @@ begin dw := 0; dh := 0; - if (anLeft in wg.Anchors) and (anRight in wg.Anchors) then - dw := dwidth - else if anRight in wg.Anchors then - dx := dwidth; - - if (anTop in wg.Anchors) and (anBottom in wg.Anchors) then - dh := dheight - else if anBottom in wg.Anchors then - dy := dheight; + if (anRight in wg.Anchors) then + if (anLeft in wg.Anchors) then + dw := dwidth + else + dx := dwidth + else if not (anLeft in wg.Anchors) then + dx := (dwidth div 2); + + if (anBottom in wg.Anchors) then + if (anTop in wg.Anchors) then + dh := dheight + else + dy := dheight + else if not (anTop in wg.Anchors) then + dy := (dheight div 2); wg.MoveAndResizeBy(dx, dy, dw, dh); end; @@ -1188,55 +1298,16 @@ begin MoveAndResize(FLeft + dx, FTop + dy, FWidth + dw, FHeight + dh); end; -function CompareInts(i1, i2: integer): integer; -begin - if i1 < i2 then - Result := -1 - else if i1 > i2 then - Result := 1 - else - Result := 0; -end; - -function AlignCompare(p1, p2: Pointer): integer; +procedure TfpgWidget.DoAlignment; var - w1: TfpgWidget; - w2: TfpgWidget; -begin - w1 := TfpgWidget(p1); - w2 := TfpgWidget(p2); - case w1.Align of - alTop: Result := CompareInts(w1.Top, w2.Top); - alBottom: Result := CompareInts(w2.Top, w1.Top); - alLeft: Result := CompareInts(w1.Left, w2.Left); - alRight: Result := CompareInts(w2.Left, w1.Left); - else - Result := 0; - end; -end; - -procedure TfpgWidget.DoAlign(AAlign: TAlign); -var - alist: TList; w: TfpgWidget; n: integer; begin - alist := TList.Create; - for n := 0 to ComponentCount - 1 do - if Components[n] is TfpgWidget then - begin - w := TfpgWidget(Components[n]); - if (w.Align = AAlign) and (w.Visible) then - alist.Add(w); - end; - - alist.Sort(@AlignCompare); - // and process this list in order for n := 0 to alist.Count - 1 do begin w := TfpgWidget(alist[n]); - case AAlign of + case w.Align of alTop: begin w.MoveAndResize(FAlignRect.Left, FAlignRect.Top, FAlignRect.Width, w.Height); @@ -1267,8 +1338,6 @@ begin w.MoveAndResize(FAlignRect.Left, FAlignRect.Top, FAlignRect.Width, FAlignRect.Height); end; { case } end; - - alist.Free; end; procedure TfpgWidget.DoResize; |