{%MainUnit ../buttons.pp} { ***************************************************************************** This file is part of the Lazarus Component Library (LCL) See the file COPYING.modifiedLGPL.txt, included in this distribution, for details about the license. ***************************************************************************** } type { TGlyphBitmap } TGlyphBitmap = class(TBitmap) private FOwner: TButtonGlyph; protected procedure SetMasked(AValue: Boolean); override; procedure SetTransparent(AValue: Boolean); override; public procedure Assign(ASource: TPersistent); override; constructor Create(AOwner: TButtonGlyph); reintroduce; end; procedure TGlyphBitmap.Assign(ASource: TPersistent); begin inherited Assign(ASource); if FOwner = nil then Exit; if FOwner.FTransparentMode = gtmGlyph then Exit; inherited SetTransparent(FOwner.FTransparentMode = gtmTransparent); end; constructor TGlyphBitmap.Create(AOwner: TButtonGlyph); begin FOwner := AOwner; inherited Create; inherited SetTransparent(True); end; procedure TGlyphBitmap.SetMasked(AValue: Boolean); begin if (FOwner = nil) or (FOwner.FTransparentMode = gtmGlyph) then inherited SetMasked(AValue) else inherited SetMasked(FOwner.FTransparentMode = gtmTransparent); end; procedure TGlyphBitmap.SetTransparent(AValue: Boolean); begin if (FOwner = nil) or (FOwner.FTransparentMode = gtmGlyph) then inherited SetTransparent(AValue) else inherited SetTransparent(FOwner.FTransparentMode = gtmTransparent); end; {------------------------------------------------------------------------------} { TButtonGlyph Constructor } {------------------------------------------------------------------------------} constructor TButtonGlyph.Create; begin FImagesCache := nil; FIsDesigning := False; FShowMode:= gsmApplication; FOriginal := TGlyphBitmap.Create(Self); FOriginal.OnChange := @GlyphChanged; FNumGlyphs := Low(TNumGlyphs); ResetExternalImageIndexes; end; {------------------------------------------------------------------------------ TButtonGlyph destructor ------------------------------------------------------------------------------} destructor TButtonGlyph.Destroy; begin if FImagesCache <> nil then begin FImagesCache.UnregisterListener(Self); FImagesCache := nil; // cache can free on unregister end; FOriginal.Free; FOriginal := nil; inherited Destroy; end; procedure TButtonGlyph.DoChange; begin if Assigned(FOnChange) then FOnChange(Self); end; procedure TButtonGlyph.GetImageIndexAndEffect(State: TButtonState; APPI: Integer; const ACanvasScaleFactor: Double; out AImageResolution: TScaledImageListResolution; out AIndex: Integer; out AEffect: TGraphicsDrawEffect); var AStoredState: TButtonState; AUseAutoEffects: Integer; AImages: TCustomImageList; const CEffects: array[Boolean, TButtonState] of TGraphicsDrawEffect = ((gdeNormal, gdeDisabled, gdeNormal, gdeNormal, gdeNormal), (gdeNormal, gdeDisabled, gdeShadowed, gdeNormal, gdeHighlighted)); begin AUseAutoEffects := ThemeServices.GetOption(toUseGlyphEffects); if Assigned(FExternalImages) and CanShow then begin AImages := FExternalImages; AIndex := FExternalImageIndexes[State]; if (State <> bsUp) and (AIndex = -1) then AIndex := FExternalImageIndexes[bsUp]; AEffect := CEffects[AUseAutoEffects > 0, State]; AImageResolution := AImages.ResolutionForPPI[FExternalImageWidth, APPI, ACanvasScaleFactor]; end else if (FLCLGlyphResourceName<>'') and CanShow then begin AImages := LCLGlyphs; AIndex := LCLGlyphs.GetImageIndex(FLCLGlyphResourceName); AEffect := CEffects[AUseAutoEffects > 0, State]; AImageResolution := AImages.ResolutionForPPI[0, APPI, ACanvasScaleFactor]; end else begin AImages := FImages; if AImages<>nil then AImageResolution := AImages.ResolutionForPPI[0, 96, 1] else AImageResolution := TScaledImageListResolution.Create(nil, 1); AStoredState := bsUp; AEffect := gdeNormal; case State of bsDisabled: if NumGlyphs > 1 then AStoredState := State else AEffect := gdeDisabled; bsDown: if NumGlyphs > 2 then AStoredState := State else if AUseAutoEffects > 0 then AEffect := gdeShadowed; bsExclusive: if NumGlyphs > 3 then AStoredState := State; bsHot: if NumGlyphs > 4 then AStoredState := State else if AUseAutoEffects > 0 then AEffect := gdeHighlighted; end; AIndex := FImageIndexes[AStoredState]; end; end; function TButtonGlyph.GetNumGlyphs: TNumGlyphs; begin if Assigned(FExternalImages) then Result := 1 else Result := FNumGlyphs; end; {------------------------------------------------------------------------------ TButtonGlyph SetGlyph ------------------------------------------------------------------------------} procedure TButtonGlyph.SetGlyph(Value : TBitmap); var GlyphCount : integer; begin if FOriginal = Value then exit; if FOriginal = nil then FOriginal := TGlyphBitmap.Create(Self) else begin FExternalImages := nil; ResetExternalImageIndexes; end; FOriginal.OnChange := nil; FOriginal.Assign(Value); FOriginal.OnChange := @GlyphChanged; FNumGlyphs := 1; if not FOriginal.Empty then ClearLCLGlyph; if FOriginal.Height > 0 then begin if FOriginal.Width mod FOriginal.Height = 0 then begin GlyphCount := FOriginal.Width div FOriginal.Height; if GlyphCount > High(TNumGlyphs) then GlyphCount := Low(TNumGlyphs); FNumGlyphs := TNumGlyphs(GlyphCount); end; end; Refresh; end; procedure TButtonGlyph.SetLCLGlyphName(const ALCLGlyphName: string); begin if FLCLGlyphResourceName = ALCLGlyphName then Exit; FLCLGlyphResourceName := ALCLGlyphName; if FLCLGlyphResourceName<>'' then begin ClearImages; FExternalImages := nil; ResetExternalImageIndexes; FExternalImageWidth := 0; end; DoChange; end; procedure TButtonGlyph.SetShowMode(const AValue: TGlyphShowMode); begin if FShowMode = AValue then Exit; FShowMode := AValue; if not IsDesigning then Refresh; end; function TButtonGlyph.GetHeight: Integer; begin if FImages <> nil then Result := FImages.Height else Result := 0; end; function TButtonGlyph.GetWidth: Integer; begin if FImages <> nil then Result := FImages.Width else Result := 0; end; function SystemShowButtonGlyphs: Boolean; inline; begin Result := ThemeServices.GetOption(toShowButtonImages) = 1; {$ifdef Windows} // force False on windows since gtk and qt can return True Result := False; {$endif} end; procedure TButtonGlyph.GlyphChanged(Sender: TObject); begin if FImagesCache <> nil then begin FImagesCache.UnregisterListener(Self); FImagesCache := nil; // cache can free on unregister ClearImages; end; if CanShow and (FOriginal.Width > 0) and (FOriginal.Height > 0) then begin FImagesCache := GetImageListCache; FImagesCache.RegisterListener(Self); FImagesCache.RegisterBitmap(Self, FOriginal, NumGlyphs); //ResetExternalImageIndexes; FExternalImages := nil; ClearLCLGlyph; end; if Sender = FOriginal then DoChange; end; {------------------------------------------------------------------------------ TButtonGlyph Draw ------------------------------------------------------------------------------} function TButtonGlyph.Draw(Canvas: TCanvas; const Client: TRect; const Offset: TPoint; State: TButtonState; Transparent: Boolean; BiDiFlags, PPI: Longint; const ScaleFactor: Double): TRect; var ImgRes: TScaledImageListResolution; ImgID: integer; AEffect: TGraphicsDrawEffect; begin Result := Client; if (FOriginal = nil) then exit; if (Client.Left >= Client.Right) or (Client.Top >= Client.Bottom) then Exit; GetImageIndexAndEffect(State, PPI, ScaleFactor, ImgRes, ImgID, AEffect); if (ImgRes.Resolution=nil) or (ImgID<0) then Exit; ImgRes.Draw(Canvas, Client.Left + Offset.X, Client.Top + Offset.y, ImgID, AEffect); // ToDo: VCL returns the text rectangle end; function TButtonGlyph.Draw(Canvas: TCanvas; const Client: TRect; const Offset: TPoint; State: TButtonState; Transparent: Boolean; BiDiFlags: Longint): TRect; begin Result := Draw(Canvas, Client, Offset, State, Transparent, BiDiFlags, 96, 1); end; function TButtonGlyph.GetExternalImageIndex(AState: TButtonState): Integer; begin Result := FExternalImageIndexes[AState]; end; procedure TButtonGlyph.Refresh; begin GlyphChanged(FOriginal); end; procedure TButtonGlyph.ResetExternalImageIndexes; begin FillChar(FExternalImageIndexes, SizeOf(FExternalImageIndexes), $FF); end; procedure TButtonGlyph.SetExternalImageIndex(AState: TButtonState; const AExternalImageIndex: Integer); begin if FExternalImageIndexes[AState] = AExternalImageIndex then Exit; FExternalImageIndexes[AState] := AExternalImageIndex; if FExternalImageIndexes[AState] >= 0 then ClearLCLGlyph; DoChange; end; procedure TButtonGlyph.SetExternalImages(const AExternalImages: TCustomImageList ); begin if FExternalImages = AExternalImages then Exit; FExternalImages := AExternalImages; if FExternalImages<>nil then ClearLCLGlyph; DoChange; end; procedure TButtonGlyph.SetExternalImageWidth(const AExternalImageWidth: Integer ); begin if FExternalImageWidth = AExternalImageWidth then Exit; FExternalImageWidth := AExternalImageWidth; DoChange; end; {------------------------------------------------------------------------------ TButtonGlyph SetNumGlyphs ------------------------------------------------------------------------------} procedure TButtonGlyph.SetNumGlyphs(Value : TNumGlyphs); begin if Value <> FNumGlyphs then begin FNumGlyphs := Value; Refresh; end; end; procedure TButtonGlyph.SetTransparentMode(AValue: TGlyphTransparencyMode); begin if AValue = FTransparentMode then Exit; FTransparentMode := AValue; if FTransparentMode = gtmGlyph then Exit; FOriginal.Transparent := FTransparentMode = gtmTransparent; end; procedure TButtonGlyph.ClearImages; var i: TButtonState; begin FImages := nil; for i := Low(TButtonState) to High(TButtonState) do FImageIndexes[i] := -1; end; procedure TButtonGlyph.ClearLCLGlyph; begin FLCLGlyphResourceName := ''; end; function TButtonGlyph.QueryInterface(constref iid: TGuid; out obj): longint; {$IFDEF WINDOWs}stdcall{$ELSE}cdecl{$ENDIF}; begin if GetInterface(iid, obj) then Result := 0 else Result := E_NOINTERFACE; end; function TButtonGlyph._AddRef: longint; {$IFDEF WINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; begin Result := -1; end; function TButtonGlyph._Release: longint; {$IFDEF WINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; begin Result := -1; end; procedure TButtonGlyph.CacheSetImageList(AImageList: TCustomImageList); begin FImages := AImageList; end; function TButtonGlyph.CanShow: Boolean; begin Result := True; if IsDesigning then Exit; case ShowMode of gsmAlways: Result := True; gsmNever: Result := False; gsmApplication: begin case Application.ShowButtonGlyphs of sbgAlways: Result := True; sbgNever: Result := False; sbgSystem: Result := SystemShowButtonGlyphs; end; end; gsmSystem: Result := SystemShowButtonGlyphs; end; end; function TButtonGlyph.CanShowGlyph: Boolean; begin Result := ((FImages <> nil) and (FImageIndexes[Low(TButtonState)]>=0)) or (FLCLGlyphResourceName <> '') or ((FExternalImages <> nil) and (ExternalImageIndex > -1)); end; procedure TButtonGlyph.CacheSetImageIndex(AIndex, AImageIndex: Integer); begin if (AIndex >= ord(Low(TButtonState))) and (AIndex <= Ord(High(TButtonState))) then FImageIndexes[TButtonState(AIndex)] := AImageIndex; end; // included by buttons.pp