What a family! Even Microsofties confess that GetDialogBaseUnits() is a crock
and we should use its sister MapDialogRect()
. But Raymond
forgets to tell us that MapDialogRect() is a... bad girl!
Earlier today, appTranslator
user Karl E. reported a problem with the Dialog Layout Mode:
Sometimes when I move a control left or right (using the arrow keys), it also moves one pixel up or down the first time I hit the key.
You probably know that dialog templates coordinates use Dialog Units (DLUs), which are converted to pixels at runtime according to the font used by the dialog. The reason is to keep consistent dialog layouts for visually-impaired people who use a larger font: The dialog automatically grows or shrinks when you modify the font size.
After investigation, it appeared that the guilty is MapDialogRect(), the Windows API used to convert DLUs to pixels. Consider this example: A static (label) control at pos 7,7 size 156x10 (DLUs). Its rectangle is then (7,7,17,163). Convert it to pixels with, say, font MS Sans Serif 8 and you get pixels rectangle (11,11,28
But the dialog created by Windows initially sets the control at (11,11,27
Where does this 1 px height difference come from ? Obviously, there is a rounding effect in the conversion that leads to different results. Does it mean that the Dialog Manager doesn't use MapDialogRect() ? Hmmm... Strange!
I scratched my head for a while until I realized that the same rectangle at a different position works fine: MapDialogRect() and the Dialog manager yield the same pixels result.Consistent size, please...
Her's my guess to explain the difference: We don't want the same 156x10 DLUs rectangle to have different sizes according to its position, right? (the difference would come from rounding). Here's how Windows solves the problem (again, it's my guess):
1. Compute the size in pixels independantly of the position :
PixelsSize= MapDialogRect( 0,0, DluRect.Height, DluRect.Width );
2. Compute the position in pixels :
PixelsPos= MapDialogRect( DluRect.top, DluRect.left, whatever );
3. Combine the converted pos and size:
PixelsRect= Rect( PixelsPos, PixelsSize );
Oh, Miracle! No more unwanted 1px glitches. It's smart. But why does the dialog layout manager does it on its own ? Why isn't it implemented right into MapDialogRect() ? Oh my...
Now, please excuse me while I go write my own MapDialogRectangle().