danielchalmers / DesktopClock

A digital clock for your desktop!
https://github.com/danielchalmers
MIT License
137 stars 33 forks source link

Right Justification #33

Closed breem42 closed 10 months ago

breem42 commented 11 months ago

I have another problem, but it doesn't always happen. This is with the latest 4.0 code from Github.

Sometimes I start the program and the time ends up too far to the right, with part of it off the right side of the screen. Or left of where I want it.

Or sometimes it will start in the position I want, but when the time changes it jumps over to a position to the right, or to the left. It usually happens while I'm not looking or it's under another window.

Here's an example of my setup file. You can probably use "Arial" instead of "Crewniverse" and still get the problem. Note also that I'm using a bog standard 1920x1080 monitor, so the positioning may not be the same as on your screen.

{
  "Format": "t",
  "CountdownFormat": "",
  "CountdownTo": "0001-01-01T00:00:00",
  "TimeZone": "",
  "FontFamily": "Crewniverse",
  "TextColor": "#FFFE97B5",
  "OuterColor": "#FFFFFFFF",
  "BackgroundEnabled": false,
  "BackgroundOpacity": 0.0,
  "BackgroundCornerRadius": 0.9,
  "OutlineThickness": 2.0,
  "Topmost": false,
  "ShowInTaskbar": false,
  "Height": 130,
  "RunOnStartup": true,
  "DragToMove": true,
  "RightAligned": true,
  "TipsShown": 0,
  "Placement": {
    "Length": 44,
    "Flags": 0,
    "ShowCommand": 1,
    "MinimizedPosition": {
      "X": -1,
      "Y": -1
    },
    "MaximizedPosition": {
      "X": -1,
      "Y": -1
    },
    "NormalBounds": {
      "Left": 1467,
      "Top": 814,
      "Right": 1915,
      "Bottom": 944
    }
  }
}

I have a theory about what is happening. When the digits of the time change, the resultant graphical representation of the time changes. It remains the same height, but with a large font (and an even larger outline) the width can change by quite a bit. Think of the difference in width of a zero vs a one, or going from "9:59" to "10:00".

Note also that I have set

"RightAligned": true,

I assume that this is supposed to position the time so that it is right justified. I want it to be close to the right side of the screen. What I suspect is that somewhere in the code the values of "Left" and "Right" are being re-calculated assuming that the time is to be left justified, ignoring this flag. Which would explain the right-left movement I'm getting. If the time is supposed to be right justified, the value of "Right" should never change, just "Left". And of course when it's left justified, "Left" should never change, just "Right".

That seems to be what the code in "Window_SizeChanged()" is trying to do.

    private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
    {
        if (_hasInitiallyChangedSize && e.WidthChanged && Settings.Default.RightAligned)
        {
            var previousRight = Left + e.PreviousSize.Width;
            Left = previousRight - ActualWidth;
        }

        // Use this to ignore the change when the window is loaded at the beginning.
        _hasInitiallyChangedSize = true;
    }

But maybe one of the flags you are checking is set wrong? Or shouldn't be checked? Another theory: It might be calling this code more than once?

I tried messing around with the logic a little but it only made it worse. Just grasping at straws here.

Am I interpreting this correctly? Does this make sense?

breem42 commented 11 months ago

So after running the code in the debugger, it seems that when the program started, the width could be very different from the previous time it was run, but because of _hasInitiallyChangedSize is false, Left is not re-calculated, and so the time is displayed with the old Left.

And "e.PreviousSize.Width" contains a garbage uninitialized value (for me 195). So how can the proper width be calculated? It seems like you could use the "Right" value from the settings file, since that shouldn't change? But I don't see any references to right in the code outside of "Window_SizeChanged()"

danielchalmers commented 11 months ago

Huge props for the super detailed issue, it's seriously appreciated 👏👏👏

You're right about the where the problem is and I just tweaked how the right-alignment is done in c37bb2f16cc6c944831bc9d6cf949194e053bc9a.

I hope you can try the latest code and see if it works for you. It's available as an artifact from this action: https://github.com/danielchalmers/DesktopClock/actions/runs/7281012169, or I attached it here too: artifact.zip.

EDIT: Ok so I just found some weird positioning on startup on my laptop but not my desktop. I'll keep thinking and see what other changes I can make.

breem42 commented 11 months ago

It works better but not perfectly for me anyway. Is there no way for you to access the "Right" value in the settings file so that you can calculate "Left" properly? It seems like a pain that the information exists but you can't get it, and that the library you seem to be using assumes left justification -- at least from what I can tell.

I had it jump left a few pixels for a split second, then jump to the correct right justified position, and then later act as if it was left justified. It takes patience and vigilance to catch these, as I am not including seconds in my time so I have to wait for the minute to change.

I also had it overwrite the settings file with defaults once while I was messing around.

danielchalmers commented 11 months ago

Was just about to post the second attempt at fixing this but you caught me :)

https://github.com/danielchalmers/DesktopClock/actions/runs/7283097882

artifact (1).zip

One thing is that the hidden padding around the outline may make it look slightly misaligned, but it also might be fine.

breem42 commented 11 months ago

Well it's even a bit better now... but I still detect a bit of left justification as the digits change. When I started the new executable you linked to above, the time was way to the left of where I wanted it. so I dragged it back to the right edge of the screen, and it's staying put, mostly.

I wish I understood the code and C# a bit more. It almost seems like the libraries you use, or perhaps C# itself is taking away low level control of how it works, and you are left poking at it trying to get it to do what you want, without really knowing what will work.

As I was typing this another problem just showed up. You know I have the background turned off. I just randomly right clicked and turned it on. This turned off my outlines and made the size of my font larger. I think it's the same height as the smaller font + outline. When I turned the background back on, it turned the outline on again and it went back to the previous size. Once again here is my settings file:

{
  "Format": "t",
  "CountdownFormat": "",
  "CountdownTo": "0001-01-01T00:00:00",
  "TimeZone": "",
  "FontFamily": "Crewniverse",
  "TextColor": "#FF9BE2F6",
  "OuterColor": "#FF9BE2F6",
  "BackgroundEnabled": false,
  "BackgroundOpacity": 0.0,
  "BackgroundCornerRadius": 0.9,
  "OutlineThickness": 1.3,
  "Topmost": false,
  "ShowInTaskbar": false,
  "Height": 130,
  "RunOnStartup": true,
  "DragToMove": true,
  "RightAligned": true,
  "TipsShown": 0,
  "LastDisplay": "9:52 PM",
  "Placement": {
    "Length": 44,
    "Flags": 0,
    "ShowCommand": 1,
    "MinimizedPosition": {
      "X": -1,
      "Y": -1
    },
    "MaximizedPosition": {
      "X": -1,
      "Y": -1
    },
    "NormalBounds": {
      "Left": 1461,
      "Top": 831,
      "Right": 1927,
      "Bottom": 961
    }
  }
}
danielchalmers commented 11 months ago

@breem42

Well it's even a bit better now... but I still detect a bit of left justification as the digits change.

It might be a visual effect caused by the extra invisible padding that is added to account for the outline. it seems to work well for me on mine

When I started the new executable you linked to above, the time was way to the left of where I wanted it.

It needs to save the time to keep the positioning so it moved because it didn't have that yet. should only happen once.

taking away low level control of how it works

yes, WPF makes it difficult to get truly low-level control. that's why, for example, it looks a little jarring when it shifts the position of the window. there's no simple way that I know of to intercept the location change BEFORE it's rendered.

You know I have the background turned off. I just randomly right clicked and turned it on. This turned off my outlines and made the size of my font larger. I think it's the same height as the smaller font + outline. When I turned the background back on, it turned the outline on again and it went back to the previous size.

the background is mutually exclusive with the outline for simplicity.

the "size" option dictates the window size NOT the text size, so an outline will take up more space, leaving less for the text.


as always, thanks for the feedback. it's valuable to me

breem42 commented 10 months ago

I suspect this is one of those mysterious bugs that comes from either 1) not completely understanding the system you are using 2) some unexpected combination of events that you were not aware could happen

Problem 1 might only be solved by long experience with WPF, which might or might not be worth it. Problem 2 might take a long time to fix.

For me it's working "good enough". I'm going to submit a feature request.