Crazy Font Issue with NSTextView - cocoa

I'm knee deep in font metrics with NSTextView at the moment. I was hoping a developer here could shed some light as to what's going on.
With Myriad Pro in a default NSTextView (dragged from IB and run in a fresh project), here's what you get:
Notice how the selected rect has the same height as the insertion point.
Now for behavior from Pages:
Notice how the selected rect is similar to the regular text view version, but the insertion point height is actually more reflective of the font (and smaller!).
Weird.
Why do I care? Here is a screen of my application with Helvetica, and then with Myriad:
Notice that in both cases, the outline symbol is perfectly centered with the insertion point height. Those symbols are actually subviews, and not in the text stream. Notice those symbols in Pages. They remain centered for Myriad. Clearly Apple realized something and fixed it. Any ideas what they did?
Thanks!

This isn't a mistake on Apple's part but rather an assumption on yours. This is a function of font metrics as well as line height.The insertion point takes the whole line height; the drawn font parts don't.
I thought it was you who I pointed to the Font Handling guide a few days ago. Either way, you need to understand this topic thoroughly so you can determine where to draw your dot.

Related

DrawFocusRect function: Strange 2-pixel focus rectangle in Windows 10

I noticed that the focus rectangle has changed in one of our legacy app when it works in Windows 10. It turned out that there are other old-style Microsoft apps in which we see the same effect - for example, in HTML Help Workshop. The focus rectangle must be a dotted rectangle consisting of alternating black and white dots, but we see a 2-pixel rectangle blended with the selection that looks like a red-orange rectangle:
The problem appears only on 2 computers with Windows 10, version 1909. One of them is the Pro edition, the other is the Home edition.
The focus rectangle is drawn in our app with the WinAPI DrawFocusRect function. The documentation for the DrawFocusRect function states the following:
Windows XP: The focus rectangle can now be thicker than 1 pixel, so it
is more visible for high-resolution, high-density displays and
accessibility needs.
But this does not help to understand why the problem occurs only on those 2 computers. They are equipped with normal 96dpi displays, and as I know, no accessibility options are turned on in them.
What it could be and how to fix the drawing of focus rectangle to see the traditional 1-pixel black/white dotted rectangle?
If it helps, here is an example of code used to draw the focus rectangle in our VB6 app:
Dim hBrBlack As Long
hBrBlack = CreateSolidBrush(vbBlack)
FrameRect hMemDC, rcFocusRect, hBrBlack
DeleteObject hBrBlack
SetBkColor hMemDC, lColor1
SetTextColor hMemDC, lColor2
DrawFocusRect hMemDC, rcFocusRect
Thank you all who commented my question. The situation became clear, but not in all parts of the problem. I am resuming all what we know by now in this kind of an answer.
Yes, indeed, in Windows 10 we can open Control Panel > Ease of Access > Ease of Access Center > Make the computer easier to see and find the Make the focus rectangle thicker option:
The first thing I do not understand is that why this option became checked. Simon Mourier thinks it is a carryover from a previous Windows installation, but I doubt this is true. I definitely know that at least on my dev pc nobody checked this as only me could do that. It seems that Windows decide at some point to check this option itself depending on some system parameters.
The second incomprehensible point is why the focus rectangle became dark-orange-red. But maybe, this is by design. Perhaps, somebody in Microsoft decided that this color is the best choice for the focus rectangle.
Taking into account all this, I think, the best choice for me and other developers who need the focus rectangle in our apps is to draw the focus rectangle by ourselves using the thickness defined by the SPI_GETFOCUSBORDERHEIGHT and SPI_GETFOCUSBORDERWIDTH system parameter values.

Win81+ GetWindowRect Not Including Complete Drag Area?

I am trying to get the width and height of all the windows. I did this easily with GetWindowRect however the styling in Win8.1+ seems such that there is a border on some windows and thats not being included. When I move/drag the window, this area moves with the window, so I expected it would be apart of its geometry. Is this known? Is there away to include the border width?
New Example
I created a second screenshot to explain after I see some confusion in the comments.
I have two windows side by side as seen in this image here:
Now if I take the GetWindowRect of the left and right windows, it should be a continuous rectangle around both of thse windows. However in the below we see this is not the case. I put a black fade over the whole desktop and cut out just the parts of the GetWindowRect for each window, we see the left window GetWindowRect is a bit smaller, this is my problem.
Old Example
For example this is a screenshot, using the cleared/non-black curtain area is what GetWindowRect identified as the width height, x and y:
We see there is some area of the window not included, I think this is the border? I used photoshop here to put a blue border around what all should have been:
And just for clarity I put an inner red border to show that the area between the red and blue borders was what should have been included, but was not:
Does anyone know how to include this "border" in the GetWindowRect?
Yes, GetWindowRect() lies to you. As you found out. It is a necessary lie. Goes back to Vista, the first Windows version that gave resizable windows their fat border. A pretty necessary feature, high screen resolutions were getting pretty common and the traditional 2-pixel border was getting too hard to hit with a mouse.
That created a massive compatibility problem however, many programs that create a window use CreateWindowEx(), you specify the outer window size. And don't use AdjustWindowRectEx(), the function that you must use to calculate the window size you need. Necessary because almost every window actually cares about the client size of the window. The part you fill with content. If they would have done nothing then legacy programs would end up creating windows with a client area that is too small, no longer fitting the content or aligning it out of whack. Very, very ugly.
So GetWindowRect() lies and pretends that the window has the traditional 2-pixel border. Pretty consistent lie, if you ask for the border size with GetSystemMetrics() then you get 2 back, even though it is 5. All works pretty well, until you start caring about positioning windows next to each other. Impossible to lie about that.
Turning off the lies requires letting Windows know that you are aware of the consequences of the fat borders. And know how to deal with Aero being turned off, possible on Vista and Win7. You must select the sub-system version number in the EXE file header and pick at least 6.00. The vast majority of programs use the legacy value, 4.00. Exactly how that's done depends on your tooling, for the Microsoft linker it is the /SUBSYSTEM option. It can be changed after the program was built with Editbin.exe, /SUBSYSTEM option. The program will no longer run on XP and earlier.
Windows 10 took an interesting new approach to this problem. The skinny borders are back. But now with a much bigger drop-shadow, the mouse is active beyond the border, even for windows that don't have a shadow. Works pretty well, hopefully we can all forget about this appcompat detail soon :)

Blind programmer: designing an interface in Xcode without being able to visually position UI elements

I am fairly new to Mac and iOS programming, and have recently decided to get really serious about developing applications for both platforms. The first step I took was to register to the Mac and iOS developer programs, download Xcode and study a book about Objective-C. I spent the last 6 weeks familiarizing myself with Objective-C, its syntax, concepts and the Foundation framework, and was purely developing command line applications for those purposes.
Now, the next step seems to be Cocoa and developing applications that offer graphical UIs, which I'm now looking into. Now, here's an issue I am having with this: as I am completely blind, I cannot visually see the screen. Thus, I use VoiceOver, the screen reader built into OS X and iOS. Maybe some of you devs have heard of VoiceOver at some point, as Apple has specified a variety of accessibility guidelines that concern VoiceOver. On that note, thanks a lot to all of you who abide by those guidelines, your effort is greatly appreciated!!! :-)
As for Xcode, it actually works really well with VoiceOver (VO). Adding in new UI elements is also no big deal, I can just copy them from the library and paste them into the view. However, I cannot drag them around and set them up in an appealing fashion, or at least I haven't found any way of doing it just yet as I'm just starting out!
Now, I really would like to know if there is any 'textual' way of arranging UI elements. I know the inspector has a great variety of options, but I'm not sure yet if any of them would let me, say, change the coordinates of an UI element by hand. Also, I've read about the new constraints which help create a consistent layout, but at this point I'm not really familiar with how they can be used or if they would be at all helpful in my case.
Also, I do realize that producing an interface that is 100% appealing to a sighted end user may not be possible for me, as it's hard for me to decide on color selections or to design a logo. Thus, I would probably need to hire someone for those things. However, if it would be possible for me to just specify the layout roughly, that would already help me a lot!
Thanks for any ideas / suggestions :-)
Robin
I'm not a blind user myself but I've worked with VoiceOver so hopefully some of this will help. I'm making this a community answer so feel free to add tips from your own experience if you've worked with UI layout in Xcode with VoiceOver.
When editing UI in Xcode there is an Inspector where you can change the size and position of the views. The shortcut to get to the Size Inspector is Alt+Command+5. The same shortcut works with VoiceOver.
You said that you were coding for both iOS and OS X. On iOS the y-axis starts in the top and points downward (so a higher y value means that the view is lower on the screen). This means that x and y specify the upper left corner of the view and the width and height extends to the right and down from there.
On OS X it's the opposite. The y-axis start at the bottom and a higher y value means that the view is higher on the screen. In both cases the x-axis goes from left to right. This means that x and y specifies the lower left corner and the width and height extends to the right an up.
Further, each view is positioned relative to their parent instead of absolute coordinates. This means that if you position a view at x=10 and y=30 and then position another view inside that at x=5 and y=10 it will have an absolute position on the screen that is x=15 and y=40.
If you can picture the layout in your head then you should be able to do it like this but it may still be hard to do.
Update
At the top of the hierarchy these coordinates relate to the size of the window. On iOS you have fixed sizes (320×480 for the iPhone and 1024×768 for the iPad). Depending on if the device is in landscape or portrait one of these is the width and the other is the heigh. You usually subtract 20 pixels from the height to account for the status bar. So the coordinate where y=0 would be directly below the status bar.
On OS X you can change the size of the window yourself. I will try and explain where to find it.
At the top level. Navigate to the "source code group" and interact with it. There you should find a "navigation bar group" and a "table" and a "scroll area". Interact with the table. In that table you should find a list of Placeholders and a list of Objects. One of the Objects will be the "Window". With the Window selected, all the inspectors will change properties of the Window. You can quickly jump to the Size Inspector by changing to any inspector and then back to the Size Inspector. For exaple type Alt+Command+4 and then Alt+Command+5. The first two elements in the Size Inspector should be the Width and Height of the Window.
This discussion will inevitably go off-topic, but here are my ideas:
Consider specializing in something else. There are so many things a programmer can work on. Many, if not most, programmers can enjoy long, successful careers without ever having to arrange any UI elements. Frankly, I don't think that this is particularly exciting, unless you have more of a designer mindset.
Alternatively, whatever tool you are using to arrange the elements, this layout is probably saved to some file, probably in some XML-like fashion. Find this file and edit it.
If you want to get really good at arranging UI elements, consider first hiring several people to do multiple arrangements for you. Then analyze the numbers and come up with some kind of formula that will be a good heuristic for such an arrangement. Or perhaps somebody has already come up with this kind of formula.

In Win7 some fonts don't work like they did in Win2K/XP

My question is about how font handling needs to be changed in order to work correctly under Windows 7. I'm sure that I've made an assumption about something that was valid before, but is no longer valid. But I don't even know where to begin looking! I'm praying someone can help! Here are the details as I understand them (I've also posted this question on a Microsoft Windows Developers forum, but they're not answering):
Yes, I'm behind the times (heck, I still write WIN32 code in plain C!) I have a 10 yr old DLL I wrote that mimics an even older DOS screen I/O library within the client area of a window. Needless to say, it only allows the use of fixed-width fonts. When some of the programs using the DLL have been moved to Windows 7, there is a strange flickering that appears when a fixed-width TRUE TYPE font is used (bitmap fonts still work perfectly.) We've tracked the problem down to the fact that a single character written with ExtTextOut is wider than it should be. I've checked the measurements three different ways (by using GetTextExtentPoint32 on a 132 character string and dividing by 132, by calling GetTextMetrics and even by using GetCharABCWidths for all 256 characters) and they all agree that the font is the same width. But ExtTextOut is rendering the background rectangle one or two pixels wider than the font width. Either than, or it is beginning the background rendering a pixel or two to the left of the position given in the parameters [I call it like this: ExtTextOut( hdc, r.left, r.top, ETO_OPAQUE, &r, &ch, 1, NULL ).] And remember, this EXACT code worked perfectly under Windows 2000, Windows XP and, with bitmap fonts on Windows 7 -- but it no longer works correctly with fixed-width true type fonts under Windows 7.
For anyone who isn't grasping what I need to do: try to imagine writing one character per square on a piece of graph paper. Every square uses the same font, but may have a different foreground and/or background color. I use TA_TOP|TA_LEFT text alignment, because it is the simplest and any consistently applied alignment should work for a fixed-width font.
What I'm seeing is that ExtTextOut is emitting a larger background rectangle than I've specified in the RECT * parameter. Since the rectangle I'm providing is created from the reported size of the font, this should NEVER happen -- and it never happened on Windows XP and earlier, and doesn't happen with bitmap (i.e. .FON) fonts under Windows 7, either. But it ALWAYS happens with fixed-width TrueType fonts under Windows 7. This is with the EXACT SAME EXECUTABLE running on Windows 2000, Windows XP and Windows 7 (32 & 64.) While I would love to simply say Windows 7 has a bug, I'm more inclined to believe that some fundamental assumption that I've made about font handling under Windows is no longer true (after 20 years of writing software for Windows.)
But I have no idea how or where to discover what that might be! Please, PLEASE help me!
--- ammendment ---
For anyone interested, I've managed to work around what I am considering a bug -- until I find documentation to the contrary. My workaround consists of two changes to my library:
Use the size returned from GetTextExtentPoint32() of an 'X' instead
of data from TEXTMETRICS.
Include the ETO_CLIPPING flag in all ExtTextOut() calls.
Previously, I was using tmHeight+tmExternalLeading for the number of pixels between the tops of consecutive rows of text, as is documented. I discovered that the size.cy value coming back from the GetTextExtentPoint32() wasn't the same and seemed more accurate. The worst example I found was the OCRB true type font. Here's what I saw in the debugger for the OCRB font I'd created (using the system font selection dialog):
ocrbtm.tmHeight = 11
ocrbtm.tmExternalLeading = 7
ocrbsize.cy = 11
So, for some reason that I've yet to discover, Windows is ignoring the external leading value defined for the OCRB font. Using the size value instead of the TM results in nice, neat, close packed text, which is just what I wanted.
The ETO_CLIPPING flag should not be necessary for me because I am setting the rectangle to exactly the dimensions of a single character and using ETO_OPAQUE to fill in the background (and overwrite the previous cell content.) But without the clipping flag, a single character is wider than either the size, text metric, or ABC width would indicate -- at least, that is true based on all of the documentation I've found so far.
I believe that HEIGHT issue has existed for a long time, but the rest was unnecessary until we ran our software under Windows 7. I'm appending this to my question to see if anyone can explain what I obviously don't understand.
-- ammendment 2 --
1: All documentation I can find says that tmHeight+tmExternalLeading should produce single spaced lines of text. Period. But that is not always true and I cannot find documentation indicating how Windows determines the different values that are sometimes returned by GetTextExtentPoint32().
2: under Win7 (maybe Vista) ExtTextOut started filling in a little more background than it should (by adding a couple extra pixels to the right), but only when a true type font is selected. It does this even if the rectangle is double the expected size of the character (in BOTH dimensions.) DPI/Scaling might be a factor, but since my system is set to 100%, it would seem that Windows is having trouble with a 1:1 scaling factor and that would seem to be a bug. The fact that it only affects true type and not bitmap (.FON) fonts also seems to rule out scaling (unless there is a bug in the scaling system), since Windows should attempt to scale all of the text, not just some of it. Also, there's a greyed (but checked) setting "Use Windows XP style DPI scaling" in the "Custom DPI Setting" dialog. Lastly, this entire issue may be a result of my running under the Windows Classic theme instead of one of the Aero or other Win7 native themes.
-- ammendment 3 --
Simply calling SetProcessDPIAware() has no effect on the issue I'm having. Since my problem exists at the 100% DPI setting (scale 1:1), if my problem is DPI-related, then I must have discovered a bug in the DPI virtualization because this is how Microsoft describes the feature:
This feature works by providing "virtualized" system metrics and UI elements to the application, as if it were running at 96 DPI. The application then renders to a 96-DPI off-screen surface, and the Desktop Windows Manager scales the resulting application window to match the DPI setting.
All of my settings show that I'm at 100% scaling, and looking in the custom settings box clearly shows that means 96 DPI. So, if the DPI virtualization from 96 DPI to 96 DPI is not working for my fixed-width true type fonts, then Windows has a problem, right? Or is there some function I need to call (or stop calling?) in order allow the DPI virtualizer to work correctly?
I'm still not convinced that the supposed scaling issue actually has as much to do with the font SIZE as I originally thought. That's because the problem is manifesting in the background rectangle being filled by ExtTextOut() instead of the text character being emitted. The background rectangle gets enlarged a bit when the font is true type. I've also now verified that this problem occurs whether using the Windows Classic theme or the standard Windows Aero theme. Now to build a simplified example so others can experiment with it.
-- ammendment 4 --
I've created a minimal demo program that shows what I'm seeing (and what I'm doing.) The Visual Studio 2010 project/source may be downloaded from http://www.svalli.com/files/fwtt.7z -- I intentionally didn't include executables because I don't want to risk spreading malware. The program has you choose a fixed-width font and then writes two 5x5 character grids to the client area, one created using the GetTextExtentPoint32 size and one using the TEXTMETRIC size as documented by Microsoft. The grids are in a black&white checkerboard pattern with a yellow on red character written last into the center to show the overlap effect (you may need a zoom utility to see it clearly.) The program also draws a string that starts with 5 X's just below the grid, starting at the same left offset, to be used as a comparison for my method of placing individual characters (I match the string.) The menu allows toggling clipping on/off in ExtTextOut and selection of other fonts. There is also a command line option dpiaware (case-sensitive) that causes the program to call SetProcessDPIAware() when it starts up, so that the effect of that call may also be evaluated.
From creating this I've learned that ExtTextOut is filling the correct background rectangle, but the character being rendered with an opaque background may be wider than it should be and may not even begin where ExtTextOut was told to begin drawing! I said "should be" because the character spacing I'm ending up with matches what I get when I have ExtTextOut render a whole string. The overlap may apparently be on either or both sides of the given rectangle, for example, OCRB adds an extra pixel to both the left and right sides of the character cell while the other true type fonts I've checked add two pixels to the right edge.
I really want to do this the "right" way, but I cannot find any documentation that shows what I'm doing wrong or am missing. Well, I am probably missing something for DPI Aware at scales other than 100%, but otherwise, I'm just baffled.
-- ammendment 5 --
Slightly less baffled... the problem is caused by ClearType. Turning off ClearType made all of the fonts work again. Turning ON ClearType under XP causes the same problem. Apparently ClearType can silently (until someone tells me how to detect it) stretch characters horizontally by a couple pixels in order to make space for the shaded pixels it adds to smooth things out.
Is clipping the only way around this problem?
-- ammendment 6 --
Partial answer to my clipping question above: When creating a new font I now do the following (in pseudo code):
CreateFontIndirect
SelectFont
GetTextMetrics
if( (tmPitchAndFamily & TMPF_TRUETYPE) && Win6.x or above )
if( SystemParametersInfo( SPI_GETCLEARTYPE ) )
lfQuality = NONANTIALIASED_QUALITY
DeleteObject( font )
CreateFontIndirect
Without enabling clipping this almost always works with the font sizes I'm using, though I've found a few that still render an extra pixel to the right (or left) of the character cell. Luckily, those appear to be free fonts found on the internet, so their overall quality might be below the standards of professional font foundries.
If anyone can find a better answer, I'd really, REALLY love to hear it! Until then, I think this is as good as it will get. Thanks for reading this far!
Make sure your code is high DPI aware, and then tell the OS that your process is DPI aware.
If you don't tell the OS that you're DPI aware, some of the measurement functions will lie and give you numbers based on the assumption that the display DPI is actually 96 dpi regardless of what it really is. Meanwhile, the drawing functions will try to scale in the other direction. For simple high-level drawing, this approach generally works (though it often leads to fuzzy text). For small measurements and precise placement of individual characters, this often results in round off problems that lead to things like inconsistent font sizes. This behavior was introduced in Windows Vista.
You can see it all the time in Visual Studio 2010+ as the syntax highlighter colors the text and words shift by a couple pixels here and there as you type. Really frickin' annoying.
Regarding the amendment:
tmExternalLeading is simply a recommendation from the font designer as to how much extra space to put between lines of text. MSDN documentation typically says, "the amount of extra leading (space) that the application adds between rows." Well, you're the application, so the "Right Thing To Do" is to add it between rows when you're drawing text yourself, but it really is up to you. (I suspect higher level functions like DrawText will use it.
It is perfectly correct for GetTextExtentPoint32 (and friends) to return a size.cy equal to tmHeight and to ignore tmExternalLeading. As the programmer, it's ultimately your choice how much leading to actually use.
You can see that this with some simply drawing code. Select a font with a non-zero tmExternalLeading (Arial works for me). Draw some text using TextOut and a unique background color. Then measure the text with GetTextExtentPoint32 and draw some lines based on the values you get back. You'll see that the background color rectangle excludes the external leading. External leading is just that: external. It's not in the bounds of the character cell.
// Draw the sample text with an opaque background.
assert(::GetMapMode(ps.hdc) == MM_TEXT);
assert(::GetBkMode(ps.hdc) == OPAQUE);
assert(::GetTextAlign(ps.hdc) == TA_TOP);
COLORREF rgbOld = ::SetBkColor(ps.hdc, RGB(0xC0, 0xFF, 0xC0));
::TextOutW(ps.hdc, x, y, pszText, cchText);
::SetBkColor(ps.hdc, rgbOld);
// This vertical line at the right side of the text shows that opaque
// background is exactly the height returned by GetTextExtentPoint32.
SIZE size = {0};
if (::GetTextExtentPoint32W(ps.hdc, pszText, cchText, &size)) {
::MoveToEx(ps.hdc, x + size.cx, y, NULL);
::LineTo(ps.hdc, x + size.cx, y + size.cy);
}
// These horizontal lines show the normal line spacing, taking into
// account tmExternalLeading.
assert(tm.tmExternalLeading > 0); // ensure it's an interesting case
::MoveToEx(ps.hdc, x, y, NULL);
::LineTo(ps.hdc, x + size.cx, y); // top of this line
const int yNext = y + tm.tmHeight + tm.tmExternalLeading;
::MoveToEx(ps.hdc, x, yNext, NULL);
::LineTo(ps.hdc, x + size.cx, yNext); // top of next line
The gap between the bottom of the colored rectangle and the top of the next line represents the external leading, which is always outside the character cell.
OCR-B is designed for reliable optical character recognition in banking equipment. Having a large external leading (relative to the height of the actual text) may be appropriate for some OCR applications. For this particular font, it's probably not an aesthetic choice.

UILabel sizing during device rotation

In my app I have two labels. Second one should be positioned below the first one (with some small const padding). The first label is multi-lined and takes all possible width. So after changing interface orientation, its real height can change (because necessary line number can change). That's why autoresizing mask can't help me here.
So.. How can I control this and display labels correctly even during interface orientation change animation?
Damn. I'm so sorry about this question. I've really googled before asking and tried to read docs. But somehow I've missed this and this with great details about my question.

Resources