// included by buttons.pp {****************************************************************************** TSpeedButton ****************************************************************************** ***************************************************************************** * * * This file is part of the Lazarus Component Library (LCL) * * * * See the file COPYING.LCL, included in this distribution, * * for details about the copyright. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * * ***************************************************************************** } {$IFOPT C-} // Uncomment for local trace // {$C+} // {$DEFINE ASSERT_IS_ON} {$ENDIF} {------------------------------------------------------------------------------ Method: TSpeedbutton.Create Params: none Returns: Nothing Constructor for the class. ------------------------------------------------------------------------------} constructor TSpeedbutton.Create(AOwner: TComponent); begin Inherited Create(AOwner); FCompStyle := csSpeedButton; FGlyph := TButtonGlyph.Create; FGlyph.OnChange := @GlyphChanged; SetInitialBounds(0, 0, 23, 22); ControlStyle := ControlStyle + [csCaptureMouse]-[csSetCaption]-csMultiClicks; FLayout:= blGlyphLeft; FAllowAllUp:= false; FMouseInControl := False; FDragging := False; FSpacing := 4; FMargin := -1; end; {------------------------------------------------------------------------------ Method: TSpeedbutton.Destroy Params: None Returns: Nothing Destructor for the class. ------------------------------------------------------------------------------} destructor TSpeedbutton.Destroy; begin FreeAndNil(FGlyph); inherited Destroy; end; {------------------------------------------------------------------------------ Method: TSpeedbutton.Click Params: Returns: nothing ------------------------------------------------------------------------------} procedure TSpeedbutton.Click; begin inherited Click; end; {------------------------------------------------------------------------------ Method: TSpeedButton.SetAllowAllUp Params: Value: Returns: nothing ------------------------------------------------------------------------------} procedure TSpeedButton.SetAllowAllUp(Value : Boolean); begin if FAllowAllUp <> Value then begin FAllowAllUp := Value; UpdateExclusive; end; end; {------------------------------------------------------------------------------ Method: TSpeedButton.SetDown Params: Value: Returns: nothing ------------------------------------------------------------------------------} procedure TSpeedButton.SetDown(Value : Boolean); var OldState: TButtonState; begin if FGroupIndex = 0 then Value:= false; if FDown <> Value then begin if FDown and not FAllowAllUp then Exit; FDown := Value; OldState := fState; if FDown then begin fState := bsExclusive; end else begin FState := bsUp; end; if OldState<>FState then Invalidate; if Value then UpdateExclusive; end; end; {------------------------------------------------------------------------------ Method: TSpeedButton.SetFlat Params: Value: Returns: nothing ------------------------------------------------------------------------------} procedure TSpeedButton.SetFlat(const Value : boolean); begin if FFlat <> Value then begin FFlat := Value; Invalidate; end; end; {------------------------------------------------------------------------------ Method: TSpeedButton.SetGlyph Params: Value: Returns: nothing ------------------------------------------------------------------------------} procedure TSpeedButton.SetGlyph(Value : TBitmap); begin FGlyph.Glyph := Value; Invalidate; end; {------------------------------------------------------------------------------ Method: TSpeedButton.SetGroupIndex Params: Value: Returns: nothing ------------------------------------------------------------------------------} procedure TSpeedButton.SetGroupIndex(const Value : Integer); begin if FGroupIndex <> Value then begin FGroupIndex := Value; UpdateExclusive; end; end; {------------------------------------------------------------------------------ Method: TSpeedButton.SetMargin Params: Value: Returns: nothing ------------------------------------------------------------------------------} procedure TSpeedButton.SetMargin(const Value : Integer); begin if FMargin <> Value then begin FMargin := Value; Invalidate; end; end; {------------------------------------------------------------------------------ Method: TSpeedButton.SetNumGlyphs Params: Value : Integer = Number of glyphs in the file/resource Returns: nothing ------------------------------------------------------------------------------} procedure TSpeedButton.SetNumGlyphs(Value : integer); Begin if Value < 0 then Value := 1; if Value > 4 then Value := 4; if Value <> TButtonGlyph(fGlyph).NumGlyphs then Begin TButtonGlyph(fGlyph).NumGlyphs := Value; Invalidate; end; end; {------------------------------------------------------------------------------ Method: TSpeedButton.SetSpacing Params: Value: Returns: nothing ------------------------------------------------------------------------------} procedure TSpeedButton.SetSpacing(const Value : Integer); begin if FSpacing <> Value then begin FSpacing := Value; Invalidate; end; end; {------------------------------------------------------------------------------ procedure TSpeedButton.SetText(const Value: TCaption); ------------------------------------------------------------------------------} procedure TSpeedButton.SetText(const Value: TCaption); begin if Caption=Value then exit; inherited SetText(Value); Invalidate; end; {------------------------------------------------------------------------------ procedure TSpeedButton.UpdateState(InvalidateOnChange: boolean); ------------------------------------------------------------------------------} procedure TSpeedButton.UpdateState(InvalidateOnChange: boolean); var OldState: TButtonState; begin OldState:=FState; if not Enabled then begin FState := bsDisabled; FDragging := False; end else begin if FState = bsDisabled then begin if FDown and (GroupIndex <> 0) then FState := bsExclusive else FState := bsUp; end; end; if InvalidateOnChange and ((FState<>OldState) or (FLastDrawFlags<>GetDrawFlags)) then Invalidate; end; {------------------------------------------------------------------------------ function TSpeedButton.GetDrawFlags: integer; ------------------------------------------------------------------------------} function TSpeedButton.GetDrawFlags: integer; begin Result:=DFCS_BUTTONPUSH; if FState in [bsDown, bsExclusive] then inc(Result,DFCS_PUSHED); if FMouseInControl then inc(Result,DFCS_CHECKED); if not Enabled then inc(Result,DFCS_INACTIVE); if Flat and (not (csDesigning in ComponentState)) and not FMouseInControl and not (FState in [bsDown, bsExclusive]) then inc(Result,DFCS_FLAT); end; {------------------------------------------------------------------------------ Method: TSpeedButton.UpdateExclusive Params: none Returns: nothing ------------------------------------------------------------------------------} procedure TSpeedButton.UpdateExclusive; var msg : TLMessage; begin if (FGroupIndex <> 0) and (Parent <> nil) then begin MSg.MSg := CM_ButtonPressed; Msg.WParam := FGroupIndex; Msg.LParam := Longint(self); Msg.Result := 0; Parent.Broadcast(Msg); end; end; {------------------------------------------------------------------------------ Function: TSpeedButton.GetGlyph Params: none Returns: The bitmap ------------------------------------------------------------------------------} function TSpeedbutton.GetGlyph : TBitmap; begin Result := FGlyph.Glyph; end; {------------------------------------------------------------------------------ Method: TSpeedButton.GetNumGlyphs Params: none Returns: The number stored in TButtonGlyph(FGlyph).NumGlyphs ------------------------------------------------------------------------------} Function TSpeedButton.GetNumGlyphs : Integer; Begin Result := TButtonGlyph(fGlyph).NumGlyphs; end; {------------------------------------------------------------------------------ Method: TSpeedButton.GlyphChanged Params: Sender - The glyph that changed Returns: zippo ------------------------------------------------------------------------------} Procedure TSpeedButton.GlyphChanged(Sender : TObject); Begin //redraw the button; Invalidate; end; {------------------------------------------------------------------------------ Method: TSpeedbutton.Paint Params: none Returns: nothing ------------------------------------------------------------------------------} procedure TSpeedbutton.Paint; var PaintRect: TRect; GlyphWidth, GlyphHeight: Integer; Offset, OffsetCap: TPoint; ClientSize, TotalSize, TextSize: TSize; //BrushStyle : TBrushStyle; M, S : integer; TXTStyle : TTextStyle; SIndex : Longint; TMP : String; begin UpdateState(false); if FGlyph=nil then exit; PaintRect:= ClientRect; {if Transparent and not (csDesigning in ComponentState) then BrushStyle:= bsClear else BrushStyle:= bsSolid;} FLastDrawFlags:=GetDrawFlags; //writeln('TSpeedbutton.Paint ',Name,':',ClassName,' Parent.Name=',Parent.Name); DrawFrameControl(Canvas.GetUpdatedHandle([csBrushValid,csPenValid]), PaintRect, DFC_BUTTON, FLastDrawFlags); GlyphWidth:= TButtonGlyph(FGlyph).Glyph.Width; if TButtonGlyph(FGlyph).NumGlyphs > 1 then GlyphWidth:=GlyphWidth div NumGlyphs; GlyphHeight:=TButtonGlyph(FGlyph).Glyph.Height; ClientSize.cx:= PaintRect.Right - PaintRect.Left; ClientSize.cy:= PaintRect.Bottom - PaintRect.Top; if Caption <> '' then begin TMP := Caption; SIndex := DeleteAmpersands(TMP); TextSize:= Canvas.TextExtent(TMP); If SIndex > 0 then If SIndex <= Length(TMP) then begin FShortcut := Ord(TMP[SIndex]); end; end else begin TextSize.cx:= 0; TextSize.cy:= 0; end; if (GlyphWidth = 0) or (GlyphHeight = 0) or (TextSize.cx = 0) or (TextSize.cy = 0) then S:= 0 else S:= Spacing; { Calculate caption and glyph layout } if Margin = -1 then begin if S = -1 then begin TotalSize.cx:= TextSize.cx + GlyphWidth; TotalSize.cy:= TextSize.cy + GlyphHeight; if Layout in [blGlyphLeft, blGlyphRight] then M:= (ClientSize.cx - TotalSize.cx) div 3 else M:= (ClientSize.cy - TotalSize.cy) div 3; S:= M; end else begin TotalSize.cx:= GlyphWidth + S + TextSize.cx; TotalSize.cy:= GlyphHeight + S + TextSize.cy; if Layout in [blGlyphLeft, blGlyphRight] then M:= (ClientSize.cx - TotalSize.cx + 1) div 2 else M:= (ClientSize.cy - TotalSize.cy + 1) div 2 end; end else begin if S = -1 then begin TotalSize.cx:= ClientSize.cx - (Margin + GlyphWidth); TotalSize.cy:= ClientSize.cy - (Margin + GlyphHeight); if Layout in [blGlyphLeft, blGlyphRight] then S:= (TotalSize.cx - TextSize.cx) div 2 else S:= (TotalSize.cy - TextSize.cy) div 2; end; M:= Margin end; case Layout of blGlyphLeft : begin Offset.X:= M; Offset.Y:= (ClientSize.cy - GlyphHeight + 1) div 2; OffsetCap.X:= Offset.X + GlyphWidth + S; OffsetCap.Y:= (ClientSize.cy - TextSize.cy) div 2; end; blGlyphRight : begin Offset.X:= ClientSize.cx - M - GlyphWidth; Offset.Y:= (ClientSize.cy - GlyphHeight + 1) div 2; OffsetCap.X:= Offset.X - S - TextSize.cx; OffsetCap.Y:= (ClientSize.cy - TextSize.cy) div 2; end; blGlyphTop : begin Offset.X:= (ClientSize.cx - GlyphWidth + 1) div 2; Offset.Y:= M; OffsetCap.X:= (ClientSize.cx - TextSize.cx + 1) div 2; OffsetCap.Y:= Offset.Y + GlyphHeight + S; end; blGlyphBottom : begin Offset.X:= (ClientSize.cx - GlyphWidth + 1) div 2; Offset.Y:= ClientSize.cy - M - GlyphHeight; OffsetCap.X:= (ClientSize.cx - TextSize.cx + 1) div 2; OffsetCap.Y:= Offset.Y - S - TextSize.cy; end; end; FGlyph.Draw(Canvas, PaintRect, Offset, FState, Transparent, 0); if Caption <> '' then begin TXTStyle := Canvas.TextStyle; TXTStyle.Opaque := False; TXTStyle.Clipping := True; TXTStyle.ShowPrefix := True; TXTStyle.Alignment := taLeftJustify; TXTStyle.Layout := tlTop; TXTStyle.SystemFont := True;//Match System Default Style With PaintRect, OffsetCap do begin Left := Left + X; Top := Top + Y; end; If not Enabled then begin Canvas.Font.Color := clBtnHighlight; OffsetRect(PaintRect, 1, 1); Canvas.TextRect(PaintRect, 0, 0, Caption, TXTStyle); Canvas.Font.Color := clBtnShadow; OffsetRect(PaintRect, -1, -1); end else Canvas.Font.Color := clBtnText; //writeln('TSpeedButton.Paint PaintRect=',PaintRect.Left,',',PaintRect.TOp,',',PaintRect.Right,',',PaintRect.Bottom); Canvas.TextRect(PaintRect, 0, 0, Caption, TXTStyle); end; inherited Paint; end; {------------------------------------------------------------------------------ Method: TSpeedButton.UpdateTracking Params: none Returns: nothing ------------------------------------------------------------------------------} procedure TSpeedButton.UpdateTracking; var P : TPoint; begin if FFlat and Enabled then begin GetCursorPos(p); FMouseInControl := not (FindDragTarget(P, True) = Self); if FMouseInControl then Perform(CM_MOUSELEAVE,0,0) else Perform(CM_MOUSEENTER,0,0); end; end; {------------------------------------------------------------------------------ Method: TSpeedButton.MouseDown Params: Button: Shift: X, Y: Returns: nothing ------------------------------------------------------------------------------} procedure TSpeedButton.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin inherited MouseDown(Button, Shift, X, Y); if csDesigning in ComponentState then exit; if (Button = mbLeft) and Enabled then begin if not FDown then begin FState := bsDown; Invalidate; end; FDragging := True; end; end; {------------------------------------------------------------------------------ Method: TSpeedButton.MouseMove Params: Shift: X, Y: Returns: nothing ------------------------------------------------------------------------------} procedure TSpeedButton.MouseMove(Shift: TShiftState; X, Y: Integer); var NewState: TButtonState; begin inherited MouseMove(Shift, X, Y); if csDesigning in ComponentState then exit; if FDragging then begin Assert(False,'Trace:FDragging is true'); if not FDown then NewState := bsUp else NewState := bsExclusive; if (X >= 0) and (X < Width) and (Y >= 0) and (Y < Height) then begin if FDown then NewState := bsExclusive else NewState := bsDown; end; if NewState <> FState then begin FState := NewState; Invalidate; end; end else begin {if not FMouseInControl then begin UpdateTracking; end;} end; end; {------------------------------------------------------------------------------ Method: TSpeedButton.MouseUp Params: Button: Shift: X, Y: Returns: nothing ------------------------------------------------------------------------------} procedure TSpeedButton.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin if not (csDesigning in ComponentState) and FDragging then begin FDragging := False; if FGroupIndex = 0 then begin FState := bsUp; FMouseInControl := False; if not (FState in [bsExclusive, bsDown]) then Invalidate; end else begin SetDown(not FDown); if FDown then Invalidate; end; //UpdateTracking; end; inherited MouseUp(Button, Shift, X, Y); end; {------------------------------------------------------------------------------ Method: TSpeedButton.SetLayout Params: Value: new layout value Returns: nothing ------------------------------------------------------------------------------} procedure TSpeedButton.SetLayout(const Value : TButtonLayout); begin if Value <> FLayout then begin FLayout:= Value; Invalidate; end; end; {------------------------------------------------------------------------------ Method: TSpeedButton.SetTransparent Params: Value: new transparency value Returns: nothing ------------------------------------------------------------------------------} procedure TSpeedButton.SetTransparent(const Value : boolean); begin if Value <> FTransparent then begin FTransparent:= Value; if Value then ControlStyle:= ControlStyle + [csOpaque] else ControlStyle:= ControlStyle - [csOpaque]; Invalidate; end; end; {------------------------------------------------------------------------------ Method: TSpeedButton.CMButtonPressed Params: Message: Returns: nothing ------------------------------------------------------------------------------} procedure TSpeedButton.CMButtonPressed(var Message : TLMessage); var Sender : TSpeedButton; begin if csDesigning in ComponentState then exit; if Message.WParam = FGroupIndex then begin Sender := TSpeedButton(Message.LParam); if Sender <> Self then begin if Sender.Down and FDown then begin FDown := False; FState := bsUp; Invalidate; end; FAllowAllUp := Sender.AllowAllUp; end; end; end; {------------------------------------------------------------------------------ Method: TSpeedButton.CMEnabledChanged Params: Message: Returns: nothing ------------------------------------------------------------------------------} procedure TSpeedButton.CMEnabledChanged(var Message: TLMEssage); Begin //Should create a new glyph based on the new state //UpdateTracking; Invalidate; end; {------------------------------------------------------------------------------ Method: TSpeedButton.CMMouseEnter Params: Message: Returns: nothing ------------------------------------------------------------------------------} procedure TSpeedButton.CMMouseEnter(var Message :TLMessage); begin inherited CMMouseEnter(Message); if csDesigning in ComponentState then exit; if not FMouseInControl and Enabled and (GetCapture = 0) then begin FMouseInControl := True; UpdateState(true); end; end; {------------------------------------------------------------------------------ Method: TSpeedButton.CMMouseLeave Params: Message: Returns: nothing ------------------------------------------------------------------------------} procedure TSpeedButton.CMMouseLeave(var Message :TLMessage); begin inherited CMMouseLeave(Message); if csDesigning in ComponentState then exit; if FMouseInControl and Enabled {and not FDragging} then begin FMouseInControl := False; UpdateState(true); end; end; {$IFDEF ASSERT_IS_ON} {$UNDEF ASSERT_IS_ON} {$C-} {$ENDIF} // included by buttons.pp { ============================================================================= $Log$ Revision 1.41 2003/06/23 09:42:09 mattias fixes for debugging lazarus Revision 1.40 2002/08/17 23:41:34 mattias many clipping fixes Revision 1.39 2003/06/18 11:21:06 mattias fixed taborder=0, implemented TabOrder Editor Revision 1.38 2003/04/29 13:35:39 mattias improved configure build lazarus dialog Revision 1.37 2003/04/02 13:23:23 mattias fixed default font Revision 1.36 2003/03/11 07:46:44 mattias more localization for gtk- and win32-interface and lcl Revision 1.35 2003/02/16 01:40:43 mattias fixed uninitialized style Revision 1.34 2003/02/06 20:46:51 mattias default fpc src dirs and clean ups Revision 1.33 2003/02/06 06:33:57 mattias fixed message Revision 1.32 2003/01/27 13:49:16 mattias reduced speedbutton invalidates, added TCanvas.Frame Revision 1.31 2002/11/21 18:49:53 mattias started OnMouseEnter and OnMouseLeave Revision 1.30 2002/09/27 20:52:23 lazarus MWE: Applied patch from "Andrew Johnson" Here is the run down of what it includes - -Vasily Volchenko's Updated Russian Localizations -improvements to GTK Styles/SysColors -initial GTK Palette code - (untested, and for now useless) -Hint Windows and Modal dialogs now try to stay transient to the main program form, aka they stay on top of the main form and usually minimize/maximize with it. -fixes to Form BorderStyle code(tool windows needed a border) -fixes DrawFrameControl DFCS_BUTTONPUSH to match Win32 better when flat -fixes DrawFrameControl DFCS_BUTTONCHECK to match Win32 better and to match GTK theme better. It works most of the time now, but some themes, noteably Default, don't work. -fixes bug in Bitmap code which broke compiling in NoGDKPixbuf mode. -misc other cleanups/ fixes in gtk interface -speedbutton's should now draw correctly when flat in Win32 -I have included an experimental new CheckBox(disabled by default) which has initial support for cbGrayed(Tri-State), and WordWrap, and misc other improvements. It is not done, it is mostly a quick hack to test DrawFrameControl DFCS_BUTTONCHECK, however it offers many improvements which can be seen in cbsCheck/cbsCrissCross (aka non-themed) state. -fixes Message Dialogs to more accurately determine button Spacing/Size, and Label Spacing/Size based on current System font. -fixes MessageDlgPos, & ShowMessagePos in Dialogs -adds InputQuery & InputBox to Dialogs -re-arranges & somewhat re-designs Control Tabbing, it now partially works - wrapping around doesn't work, and subcontrols(Panels & Children, etc) don't work. TabOrder now works to an extent. I am not sure what is wrong with my code, based on my other tests at least wrapping and TabOrder SHOULD work properly, but.. Anyone want to try and fix? -SynEdit(Code Editor) now changes mouse cursor to match position(aka over scrollbar/gutter vs over text edit) -adds a TRegion property to Graphics.pp, and Canvas. Once I figure out how to handle complex regions(aka polygons) data properly I will add Region functions to the canvas itself (SetClipRect, intersectClipRect etc.) -BitBtn now has a Stored flag on Glyph so it doesn't store to lfm/lrs if Glyph is Empty, or if Glyph is not bkCustom(aka bkOk, bkCancel, etc.) This should fix most crashes with older GDKPixbuf libs. Revision 1.29 2002/09/18 17:07:25 lazarus MG: added patch from Andrew Revision 1.28 2002/09/13 11:49:47 lazarus Cleanups, extended TStatusBar, graphic control cleanups. Revision 1.27 2002/09/12 15:53:10 lazarus MG: small bugfixes Revision 1.26 2002/09/12 15:35:57 lazarus MG: small bugfixes Revision 1.25 2002/09/06 16:14:19 lazarus MG: fixed removing TSpeedButton Revision 1.24 2002/09/03 22:31:25 lazarus MG: removed old workaround in TSpeedButton Revision 1.23 2002/09/03 08:07:20 lazarus MG: image support, TScrollBox, and many other things from Andrew Revision 1.22 2002/09/01 16:11:21 lazarus MG: double, triple and quad clicks now works Revision 1.21 2002/08/30 12:32:21 lazarus MG: MoveWindowOrgEx, Splitted FWinControls/FControls, TControl drawing, Better DesignerDrawing, ... Revision 1.20 2002/08/27 06:34:26 lazarus MG: fixed codetools proc collection Revision 1.19 2002/08/26 17:28:21 lazarus MG: fixed speedbutton in designmode Revision 1.18 2002/08/24 13:41:29 lazarus MG: fixed TSpeedButton.SetDown and Invalidate Revision 1.17 2002/08/22 16:43:35 lazarus MG: improved theme support from Andrew Revision 1.16 2002/08/19 20:34:47 lazarus MG: improved Clipping, TextOut, Polygon functions Revision 1.15 2002/06/01 08:41:28 lazarus MG: DrawFramControl now uses gtk style, transparent STrechBlt Revision 1.14 2002/05/10 06:05:55 lazarus MG: changed license to LGPL Revision 1.13 2002/02/25 17:08:50 lazarus MG: reduced hints Revision 1.12 2002/02/24 20:51:24 lazarus Improved TSpeedButton (Glyph, Spacing, Margin, drawing) Added PageCount to TNotebook Optimized component selection buttons a bit. Revision 1.11 2001/11/22 14:33:26 lazarus MG: fixed painting background of flat speedbuttons Revision 1.10 2001/10/18 13:01:33 lazarus MG: fixed speedbuttons numglyphs>1 and started IDE debugging Revision 1.9 2001/07/03 10:30:32 lazarus MG: speedbuttonglyph centered, buttonglyph border fixed Revision 1.8 2001/06/14 14:57:58 lazarus MG: small bugfixes and less notes Revision 1.7 2001/03/19 14:40:49 lazarus MG: fixed many unreleased DC and GDIObj bugs Revision 1.5 2001/02/06 14:52:47 lazarus Changed TSpeedbutton in gtkobject so it erases itself when it's set to visible=false; Shane Revision 1.4 2001/01/12 18:46:50 lazarus Named the speedbuttons in MAINIDE and took out some writelns. Shane Revision 1.3 2001/01/04 16:12:54 lazarus Removed some writelns and changed the property editor for TStrings a bit. Shane Revision 1.2 2001/01/03 18:44:54 lazarus The Speedbutton now has a numglyphs setting. I started the TStringPropertyEditor Revision 1.1 2000/07/13 10:28:28 michael + Initial import Revision 1.10 2000/06/04 10:00:33 lazarus MWE: * Fixed bug #6. Revision 1.9 2000/05/14 21:56:11 lazarus MWE: + added local messageloop + added PostMessage * fixed Peekmessage * fixed ClientToScreen * fixed Flat style of Speedutton (TODO: Draw) + Added TApplicatio.OnIdle }