Phoenix icon indicating copy to clipboard operation
Phoenix copied to clipboard

GraphicsContext 0.5 Offset Helper not working in v4.2

Open TravStu22 opened this issue 2 years ago • 1 comments
trafficstars

Operating system: Microsoft Windows 10 Pro Version 10.0.19045 Build 19045 wxPython version & source: 4.2.1 msw (phoenix) wxWidgets 3.2.2.1 from pypi Python version & source: Python 3.7.1 (v3.7.1:260ec2c36a, Oct 20 2018, 14:57:15) [MSC v.1915 64 bit (AMD64)] on win32 from stock

Description of the problem: I upgraded to v4.2 and noticed my line drawing is now blurry on a scaled display. While researching the problem, I saw that there is something important about 0.5 and how there is a helper function in the graphics context that is supposed to deal with that automatically?

It looks like the offset helper only does something at 100% scale in v4.2.

Here is v4.2 at 3 different display scales. Note how the top left and bottom left panel show the helper being on/off has an effect at 100% but not at the other scales. (in the right side panels, I’m manually offsetting x and y by 0.5) graphics context offset issue examples

Now going back to v4.1 we see that the helper does something at each scale. (shoe-horned into image above)

Here is some code to reproduce the samples: (click to expand)
import wx
import ctypes

ctypes.windll.shcore.SetProcessDpiAwareness(1) #1=PROCESS_SYSTEM_DPI_AWARE, 2=PROCESS_PER_MONITOR_DPI_AWARE

class ExampleFrame(wx.Frame):
    def __init__(self, parent):
        super(ExampleFrame, self).__init__(parent)

        self.SetTitle('{}     Display Scale: {}%'.format(wx.version(), self.scaled_dpi(100)))
        self.SetSize(650, 350)

        self.buffer = wx.Bitmap(600, 300, 32)

        dc = wx.MemoryDC(self.buffer)
        dc.SetBackground(wx.Brush(wx.Colour(255,  255,  255)))
        dc.Clear()
        
        gc = wx.GraphicsContext.Create(dc)

        self.draw(gc)

        self.Bind(wx.EVT_PAINT, self.on_paint)
        self.Show(True)


    def scaled_dpi(self, value):
        #round down the result scaled by DPI
        return int(value * (self.FromDIP(100)/100))


    def draw(self, gc):
        font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
        if '4.1' in wx.version():
            font.SetPointSize(12)
        else:
            font.SetPointSize(self.scaled_dpi(12))
        gc.SetFont(font, wx.BLACK)

        gc.SetPen(wx.Pen(wx.Colour(0,  0,  0), 1))

        #divider
        path = gc.CreatePath()
        path.MoveToPoint(300, 0)
        path.AddLineToPoint(300, 300)
        path.MoveToPoint(0, 150)
        path.AddLineToPoint(600, 150)
        gc.DrawPath(path)

        for i in range(4):
            gc.PushState()
            
            if i==0:
                gc.Translate(0, 0)
                gc.DrawText('( x, y )', 60, 5)

                gc.EnableOffset()
                gc.DrawText('GC Offset Enabled', 60, 110)

            if i==1:
                gc.Translate(300, 0)
                gc.Translate(0.5, 0.5)
                gc.DrawText('( x+0.5, y+0.5 )', 60, 5)

                gc.EnableOffset()
                gc.DrawText('GC Offset Enabled', 60, 110)

            if i==2:
                gc.Translate(0, 150)
                gc.DrawText('( x, y )', 60, 5)

                gc.DisableOffset()
                gc.DrawText('GC Offset Disabled', 60, 110)

            if i==3:
                gc.Translate(300, 150)
                gc.Translate(0.5, 0.5)
                gc.DrawText('( x+0.5, y+0.5 )', 60, 5)

                gc.DisableOffset()
                gc.DrawText('GC Offset Disabled', 60, 110)


            gc.SetBrush(wx.Brush(wx.Colour(245,  245,  245)))
            gc.DrawRectangle(100, 50, 50, 50)
            gc.SetBrush(wx.NullBrush)

            path = gc.CreatePath()
            path.MoveToPoint(20, 20)
            path.AddLineToPoint(100, 100)
            path.AddLineToPoint(200, 100)
            path.AddLineToPoint(220, 50)
            gc.DrawPath(path)
            
            gc.PopState()


    def on_paint(self, e):
        dc = wx.BufferedPaintDC(self, self.buffer)


app = wx.App()
ExampleFrame(None)
app.MainLoop()

TravStu22 avatar Aug 22 '23 20:08 TravStu22

Thanks for the detailed report. I don't think anything relevant changed in wxPython itself, so I think the difference in behavior is likely due to upstream wxWidgets changes. You may want to ask on one of the wxWidgets support forums (e.g., mailing lists: https://wxwidgets.org/support/mailing-lists/) as they are going to have more expertise in this area.

swt2c avatar Aug 23 '23 00:08 swt2c