From 1d097a9a7dd54a61b34ce5daad562383039b0e7a Mon Sep 17 00:00:00 2001 From: juha Date: Sun, 14 Mar 2021 08:12:17 +0000 Subject: [PATCH] LCL-GTK3: Improve bitmap drawing etc. Issue #38567, patch from Anton Kavalenka. git-svn-id: trunk@64802 - --- lcl/interfaces/gtk3/gtk3lclintf.inc | 71 +++++++++++++++++++++++--- lcl/interfaces/gtk3/gtk3objects.pas | 79 ++++++++++++++++++++++++++++- lcl/interfaces/gtk3/gtk3widgets.pas | 13 +++-- lcl/interfaces/gtk3/gtk3winapi.inc | 8 ++- 4 files changed, 154 insertions(+), 17 deletions(-) diff --git a/lcl/interfaces/gtk3/gtk3lclintf.inc b/lcl/interfaces/gtk3/gtk3lclintf.inc index 376ba347e7..1b16f06a12 100644 --- a/lcl/interfaces/gtk3/gtk3lclintf.inc +++ b/lcl/interfaces/gtk3/gtk3lclintf.inc @@ -180,6 +180,8 @@ begin Result:=inherited GetAcceleratorString(AVKey,AShiftState); end; + + {------------------------------------------------------------------------------ Function: RawImage_CreateBitmap Params: ARawImage: @@ -196,6 +198,9 @@ var NewData: PByte; ImageFormat: cairo_format_t; ARowStride: PtrUInt; + x,y:integer; + src,dst,pdst,psrc,SrcRowPtr,DstRowPtr:pbyte; + ridx,gidx,bidx,aidx:byte; begin Result := False; ABitmap := 0; @@ -203,8 +208,57 @@ begin if ARawImage.DataSize > 0 then begin - NewData := GetMem(ARawImage.DataSize); - Move(ARawImage.Data^, NewData^, ARawImage.DataSize); + case Desc.LineEnd of + rileQWordBoundary: + begin + ARowStride := Desc.Width; + if Desc.Width and 1 <> 0 then Inc(ARowStride); + ARowStride := ARowStride shl 2; + end; + rileDQWordBoundary: + begin + ARowStride := Desc.Width shr 1; + if Desc.Width and 3 <> 0 then Inc(ARowStride); + ARowStride := ARowStride shl 3; + end; + else + ARowStride := Desc.Width shl 2; + end; + + // check if the pixels are in order, pixbuf expects them in R-G-B-A + Desc.GetRGBIndices(Ridx, Gidx, Bidx, AIdx); + + GetMem(NewData, ArawImage.DataSize); + + //if (Ridx <> 0) or (Gidx <> 1) or (Bidx <> 2) or (AIdx <> 3) then + begin + // put components in right order + + DstRowPtr := NewData; + SrcRowPtr := ArawImage.Data; + y := Desc.Height; + while y > 0 do + begin + Src := SrcRowPtr; + Dst := DstRowPtr; + x := Desc.Width; + while x > 0 do + begin + Dst[0] := Src[Ridx]; + Dst[1] := Src[Gidx]; + Dst[2] := Src[Bidx]; + Dst[3] := $ff;//Src[Aidx] ; + + Inc(Src, 4); + Inc(Dst, 4); + Dec(x); + end; + Inc(SrcRowPtr, ARowstride); + Inc(DstRowPtr, ARowstride); + Dec(y); + end; + end; + end else NewData := nil; @@ -218,21 +272,26 @@ begin end; ARowStride := GetBytesPerLine(Desc.Width, Desc.BitsPerPixel, rileDWordBoundary); ABitmap := HBitmap(TGtk3Image.Create(NewData, Desc.Width, Desc.Height, ARowStride, ImageFormat, - not ASkipMask)); // Using ASkipMask for DataOwner param prevents a crash later. + {not ASkipMask}true)); // Using ASkipMask for DataOwner param prevents a crash later. Result := ABitmap <> 0; + { if ASkipMask then + FreeMem(NewData); } + if ASkipMask then Exit; if (ARawImage.Mask <> nil) and (ARawImage.MaskSize > 0) then begin NewData := GetMem(ARawImage.MaskSize); + //FillChar(NewData^, ARawImage.MaskSize,$ff); Move(ARawImage.Mask^, NewData^, ARawImage.MaskSize); end else NewData := nil; - ARowStride := GetBytesPerLine(Desc.Width, Desc.BitsPerPixel, rileDWordBoundary); - AMask := HBitmap(TGtk3Image.Create(NewData, Desc.Width, Desc.Height, ARowStride, CAIRO_FORMAT_A1, True)); + + ARowStride := GetBytesPerLine(Desc.Width, {Desc.BitsPerPixel}8, rileDWordBoundary); + AMask := HBitmap(TGtk3Image.Create(NewData, Desc.Width, Desc.Height, ARowStride, CAIRO_FORMAT_A8, True)); end; @@ -747,7 +806,7 @@ begin if InvertPixels then WorkMask.invertPixels(QImageInvertRGB); *) - if WorkMask.bits<>nil then + if (WorkMask.bits<>nil) and (ARawImage.Mask<>nil) then Move(WorkMask.bits^, ARawImage.Mask^, ARawImage.MaskSize); // if InvertPixels then // WorkMask.invertPixels(QImageInvertRGB); diff --git a/lcl/interfaces/gtk3/gtk3objects.pas b/lcl/interfaces/gtk3/gtk3objects.pas index dcaf20714c..86bbfb8919 100644 --- a/lcl/interfaces/gtk3/gtk3objects.pas +++ b/lcl/interfaces/gtk3/gtk3objects.pas @@ -264,6 +264,7 @@ type procedure fillRect(x, y, w, h: Integer; ABrush: HBRUSH); overload; procedure fillRect(x, y, w, h: Integer); overload; function RoundRect(X1, Y1, X2, Y2: Integer; RX, RY: Integer): Boolean; + function drawFrameControl(arect:TRect;uType,uState:cardinal):boolean; function drawFocusRect(const aRect: TRect): boolean; function getBpp: integer; function getDepth: integer; @@ -714,11 +715,12 @@ begin sz:=fHandle^.get_size; if fHandle^.get_size_is_absolute then begin - sz:=12;// sz div PANGO_SCALE; + sz:= sz div PANGO_SCALE; end else begin { in points } - sz:=round(96*sz/PANGO_SCALE/72);//round(2.03*sz/PANGO_SCALE); + //sz:=round(96*sz/PANGO_SCALE/72);//round(2.03*sz/PANGO_SCALE); + sz := MulDiv(sz, 96{Screen.PixelsPerInch}, 72 * PANGO_SCALE) end; fLogFont.lfHeight:=sz;//round(sz/PANGO_SCALE); @@ -2103,6 +2105,79 @@ begin end; end; +function TGtk3DeviceContext.drawFrameControl(arect:TRect;uType,uState:cardinal):boolean; +var + Context: PGtkStyleContext; + AValue: TGValue; + pw:PGtkWidget; + path:PGtkwIdgetPath; + pc:pgchar; + w:PgtkWidget; +begin + + Result:=false; + + { if Parent <> nil then + Context := Parent^.get_style_context + else + begin + Context:=TGtkStyleContext.new(); + Context^.add_class('button'); + end; + if Context = nil then + begin + DebugLn('WARNING: TGtk3WidgetSet.DrawFrameControl on non widget context isn''t implemented.'); + exit; + end; } + + w:=nil; + + if uType=DFC_BUTTON then + begin + w:=GetStyleWidget(lgsButton); + end else + if uType=DFC_MENU then + begin + w:=GetStyleWidget(lgsMenu); + end; + + if not Assigned(w) then exit; + + Context:=w^.get_style_context; + path:=w^.get_path; + gtk_style_context_set_path (context, path); + gtk_style_context_set_state (context,(* gtk_widget_path_iter_get_state (path, -1)*) -1); + + {GTK_STATE_FLAG_NORMAL: TGtkStateFlags = 0; + GTK_STATE_FLAG_ACTIVE: TGtkStateFlags = 1; + GTK_STATE_FLAG_PRELIGHT: TGtkStateFlags = 2; + GTK_STATE_FLAG_SELECTED: TGtkStateFlags = 4; + GTK_STATE_FLAG_INSENSITIVE: TGtkStateFlags = 8; + GTK_STATE_FLAG_INCONSISTENT: TGtkStateFlags = 16; + GTK_STATE_FLAG_FOCUSED: TGtkStateFlags = 32; + GTK_STATE_FLAG_BACKDROP: TGtkStateFlags = 64; + GTK_STATE_FLAG_DIR_LTR: TGtkStateFlags = 128; + GTK_STATE_FLAG_DIR_RTL: TGtkStateFlags = 256; + } + gtk_style_context_set_state (context, GTK_STATE_FLAG_FOCUSED or GTK_STATE_FLAG_PRELIGHT); + + pw:=w; + while Assigned(pw) do + begin + + Context:=pw^.get_style_context; + path:=pw^.get_path; + with aRect do + begin + gtk_render_background(Context,pcr, Left, Top, Right - Left, Bottom - Top); + gtk_render_frame(Context,pcr, Left, Top, Right - Left, Bottom - Top); + end; + pw:=pw^.parent; + end; + + Result := True; +end; + function TGtk3DeviceContext.drawFocusRect(const aRect: TRect): boolean; var Context: PGtkStyleContext; diff --git a/lcl/interfaces/gtk3/gtk3widgets.pas b/lcl/interfaces/gtk3/gtk3widgets.pas index 50ff16f2c9..e6fe1612ab 100644 --- a/lcl/interfaces/gtk3/gtk3widgets.pas +++ b/lcl/interfaces/gtk3/gtk3widgets.pas @@ -2370,7 +2370,7 @@ begin *) end else begin - ARgba := TColortoTGdkRGBA(AValue); + ARgba := TColortoTGdkRGBA(ColorToRGB(AValue)); {$info GTK3: set GdkRGBA.alpah to 1.0?} {ColorToCairoRGB(ColorToRGB(AValue), R, G, B); @@ -6734,10 +6734,15 @@ begin Result := PGtkWidget(check); check^.set_use_underline(True); {fWidgetRGBA[0].G:=0.8; - fWidgetRGBA[0].Alpha:=0.7; - check^.override_color(GTK_STATE_NORMAL,@Self.FWidgetRGBA[0]);} + fWidgetRGBA[0].Alpha:=1; + check^.override_color(GTK_STATE_FLAG_NORMAL,@Self.FWidgetRGBA[0]);} + (*fWidgetRGBA[0].G:=0.8; + fWidgetRGBA[0].B:=0.9; + fWidgetRGBA[0].Alpha:=0.9; + check^.override_color(GTK_STATE_FLAG_ACTIVE,@Self.FWidgetRGBA[0]); *) // nil resets color to gtk default - FWidget^.override_background_color(GTK_STATE_FLAG_NORMAL, nil); + { FWidget^.override_color(GTK_STATE_FLAG_NORMAL, nil); + FWidget^.override_background_color(GTK_STATE_FLAG_NORMAL, nil);} end; { TGtk3RadioButton } diff --git a/lcl/interfaces/gtk3/gtk3winapi.inc b/lcl/interfaces/gtk3/gtk3winapi.inc index 4923eded8d..a2549bbc88 100644 --- a/lcl/interfaces/gtk3/gtk3winapi.inc +++ b/lcl/interfaces/gtk3/gtk3winapi.inc @@ -600,11 +600,9 @@ end; function TGtk3WidgetSet.DrawFrameControl(DC: HDC; const aRect: TRect; uType, uState: Cardinal): Boolean; begin - {$IFDEF GTK3DEBUGNOTIMPLEMENTED} - DebugLn('WARNING: TGtk3WidgetSet.DrawFrameControl not implemented ...'); - {$ENDIF} - Result := False; - // inherited DrawFrameControl(DC, aRect, uType, uState); + Result:=false; + if IsValidDC(DC) then + Result:=TGtk3DeviceContext(DC).drawFrameControl(aRect,uType,uState); end; function TGtk3WidgetSet.DrawFocusRect(DC: HDC; const aRect: TRect): boolean;