Qt5,Qt6: use floating point functions for primitives drawing on scaled displays. issue #41422

This commit is contained in:
zeljan1 2025-02-11 14:44:05 +01:00
parent 79707cbc54
commit 683afd5cbb
4 changed files with 76 additions and 12 deletions

View File

@ -465,6 +465,7 @@ type
function getDeviceSize: TPoint;
function getRegionType(ARegion: QRegionH): integer;
function getClipRegion: TQtRegion;
function preferFloatingPointDrawingFunctions: boolean; {when screen is scaled we use drawLineF, drawRectF etc.}
procedure setClipping(const AValue: Boolean);
procedure setClipRect(const ARect: TRect);
procedure setClipRegion(ARegion: QRegionH; AOperation: QtClipOperation = QtReplaceClip);
@ -3398,6 +3399,35 @@ begin
Result := vRegion;
end;
function TQtDeviceContext.preferFloatingPointDrawingFunctions: boolean;
const
AEpsilon: double = 0.01;
var
APixelRatio: QReal;
AWindow: QWindowH;
AWidget: QWidgetH;
AScreen: QScreenH;
begin
Result := False;
if Assigned(Parent) then
begin
AWindow := QWidget_windowHandle(Parent);
if AWindow = nil then
begin
AWidget := QWidget_topLevelWidget(Parent);
AWindow := QWidget_windowHandle(AWidget);
if AWindow = nil then
exit;
end;
AScreen := QWindow_screen(AWindow);
if AScreen = nil then
exit;
APixelRatio := QScreen_devicePixelRatio(AScreen);
if Abs(APixelRatio - 1.00) > AEpsilon then
exit(True);
end;
end;
procedure TQtDeviceContext.setClipping(const AValue: Boolean);
begin
QPainter_setClipping(Widget, AValue);

View File

@ -4896,7 +4896,11 @@ begin
Pt := TQtCustomControl(AHandle).viewport.ScrolledOffset;
Types.OffsetRect(Rect^, -Pt.X, -Pt.Y);
end;
if (Rect^.Width <= 0) or (Rect^.Height <= 0) then
begin
//DebugLn('WARNING: TQtWidgetSet.InvalidateRect() Rect is null ',dbgs(Rect^),' LCL=',dbgsName(TQtWidget(AHandle).LCLObject));
exit(True);
end;
// no need to handle bErase. Qt automatically erase rect on paint event according to docs
TQtWidget(aHandle).Update(Rect);
end else
@ -4966,7 +4970,8 @@ begin
OldBkMode := SetBkMode(DC, TRANSPARENT);
if TQtDeviceContext(DC).pen.getCosmetic then
LastPos := TQtDeviceContext(DC).GetLineLastPixelPos(PenPos, LastPos);
if QPainter_testRenderHint(TQtDeviceContext(DC).Widget, QPainterAntialiasing) then
if QPainter_testRenderHint(TQtDeviceContext(DC).Widget, QPainterAntialiasing) or
TQtDeviceContext(DC).preferFloatingPointDrawingFunctions then
TQtDeviceContext(DC).drawLineF(PenPos.X, PenPos.Y, LastPos.X, LastPos.Y)
else
TQtDeviceContext(DC).drawLine(PenPos.X, PenPos.Y, LastPos.X, LastPos.Y);
@ -5321,7 +5326,8 @@ begin
Result := IsValidDC(DC);
if Result then
begin
if QPainter_testRenderHint(TQtDeviceContext(DC).Widget, QPainterAntialiasing) then
if QPainter_testRenderHint(TQtDeviceContext(DC).Widget, QPainterAntialiasing) or
TQtDeviceContext(DC).preferFloatingPointDrawingFunctions then
begin
GetMem(QtPointsF, NumPts * SizeOf(TQtPointF));
for i := 0 to NumPts - 1 do
@ -5407,7 +5413,8 @@ begin
R := NormalizeRect(Rect(X1, Y1, X2, Y2));
if IsRectEmpty(R) then Exit(True);
if QPainter_testRenderHint(TQtDeviceContext(DC).Widget, QPainterAntialiasing) then
if QPainter_testRenderHint(TQtDeviceContext(DC).Widget, QPainterAntialiasing) or
TQtDeviceContext(DC).preferFloatingPointDrawingFunctions then
TQtDeviceContext(DC).drawRectF(R.Left, R.Top, R.Right - R.Left - 1, R.Bottom - R.Top - 1)
else
TQtDeviceContext(DC).drawRect(R.Left, R.Top, R.Right - R.Left - 1, R.Bottom - R.Top - 1);

View File

@ -472,6 +472,7 @@ type
function getDeviceSize: TPoint;
function getRegionType(ARegion: QRegionH): integer;
function getClipRegion: TQtRegion;
function preferFloatingPointDrawingFunctions: boolean; {when screen is scaled we use drawLineF, drawRectF etc.}
procedure setClipping(const AValue: Boolean);
procedure setClipRect(const ARect: TRect);
procedure setClipRegion(ARegion: QRegionH; AOperation: QtClipOperation = QtReplaceClip);
@ -3568,6 +3569,25 @@ begin
Result := vRegion;
end;
function TQtDeviceContext.preferFloatingPointDrawingFunctions: boolean;
const
AEpsilon: double = 0.01;
var
APixelRatio: QReal;
AScreen: QScreenH;
begin
Result := False;
if Assigned(Parent) then
begin
AScreen := QWidget_screen(Parent);
if AScreen = nil then
exit;
APixelRatio := QScreen_devicePixelRatio(AScreen);
if Abs(APixelRatio - 1.00) > AEpsilon then
exit(True);
end;
end;
procedure TQtDeviceContext.setClipping(const AValue: Boolean);
begin
QPainter_setClipping(Widget, AValue);

View File

@ -4924,7 +4924,11 @@ begin
Pt := TQtCustomControl(AHandle).viewport.ScrolledOffset;
Types.OffsetRect(Rect^, -Pt.X, -Pt.Y);
end;
if (Rect^.Width <= 0) or (Rect^.Height <= 0) then
begin
//DebugLn('WARNING: TQtWidgetSet.InvalidateRect() Rect is null ',dbgs(Rect^),' LCL=',dbgsName(TQtWidget(AHandle).LCLObject));
exit(True);
end;
// no need to handle bErase. Qt automatically erase rect on paint event according to docs
TQtWidget(aHandle).Update(Rect);
end else
@ -4994,7 +4998,8 @@ begin
OldBkMode := SetBkMode(DC, TRANSPARENT);
if TQtDeviceContext(DC).pen.getCosmetic then
LastPos := TQtDeviceContext(DC).GetLineLastPixelPos(PenPos, LastPos);
if QPainter_testRenderHint(TQtDeviceContext(DC).Widget, QPainterAntialiasing) then
if QPainter_testRenderHint(TQtDeviceContext(DC).Widget, QPainterAntialiasing) or
TQtDeviceContext(DC).preferFloatingPointDrawingFunctions then
TQtDeviceContext(DC).drawLineF(PenPos.X, PenPos.Y, LastPos.X, LastPos.Y)
else
TQtDeviceContext(DC).drawLine(PenPos.X, PenPos.Y, LastPos.X, LastPos.Y);
@ -5393,7 +5398,8 @@ begin
Result := IsValidDC(DC);
if Result then
begin
if QPainter_testRenderHint(TQtDeviceContext(DC).Widget, QPainterAntialiasing) then
if QPainter_testRenderHint(TQtDeviceContext(DC).Widget, QPainterAntialiasing) or
TQtDeviceContext(DC).preferFloatingPointDrawingFunctions then
begin
GetMem(QtPointsF, NumPts * SizeOf(TQtPointF));
for i := 0 to NumPts - 1 do
@ -5479,7 +5485,8 @@ begin
R := NormalizeRect(Rect(X1, Y1, X2, Y2));
if IsRectEmpty(R) then Exit(True);
if QPainter_testRenderHint(TQtDeviceContext(DC).Widget, QPainterAntialiasing) then
if QPainter_testRenderHint(TQtDeviceContext(DC).Widget, QPainterAntialiasing) or
TQtDeviceContext(DC).preferFloatingPointDrawingFunctions then
TQtDeviceContext(DC).drawRectF(R.Left, R.Top, R.Right - R.Left - 1, R.Bottom - R.Top - 1)
else
TQtDeviceContext(DC).drawRect(R.Left, R.Top, R.Right - R.Left - 1, R.Bottom - R.Top - 1);