By setting the lineHeightMultiple of a NSParagraphStyle that is used in a text view I'm getting drawing artifacts when selecting text. This is reproducible in TextEdit. More specifically:
Open TextEdit in rich text mode
Pick Courier 14 as the font
Set line height multiple to 1.4
Insert a bunch of text
Select a portion of text with the mouse until the top
Start decreasing the selection (moving the mouse down)
In some lines, the selection is not totally cleared, leaving a 1px horizontal artifact behind (see screnshot). This also occurs with different fonts, font sizes as lineHeightMultiple values (although not all).
Has anyone experience this or has any idea why this is happening?
Thanks,
Rúben
I fixed this in my own code by adding the paragraph style to the selected text attributes, and rounding the line height.
I had a similar issue with NSTextAttachment's which were having a height larger than the default line spacing. I was able to mitigate it by adding this line to my NSTextViewDelegate.
func textViewDidChangeSelection(_ notification: Notification) {
// will fix artifacts after releasing mouse button
self.textView.needsDisplay = true
}
I also tried to create a larger redraw area during mouseDragged in my custom NSTextView class, but unfortunately NSTextView is handling this completely different, thus mouseDragged is never being invoked.
The trick with the paragraph style did not work for me.
Related
UITextField shows its content text bang against the left edge of the field, which is ugly and can be hard to read if the field has a visible border. UITextView, on the other hand, automatically has padding (blank space) around the text. I examined and experimented with all the UITextField properties but I don't see any way they can be used to get padding around the text.
I also tried calling drawText(in:CGRect) on the text field but it had no effect. But I'm not sure what CGRect is needed in that call. I tried different border styles including .none. I also tried making a blank UIView and assigning that to the text field's leftView property but that also had no effect. And I tried doing these things in viewDidLoad, viewDidAppear, and at the point where I'm writing the text into the textField. The text shows in the textField as expected but none of these other things seem to affect the textField's appearance in any way. It seems to me lots of people must show text in a UITextField and somehow get it padded on the left so I'm misunderstanding something but what???
The following works for a field called "textField". It inserts padding by shifting the left side of the field's content 8 pixels right relative to the left edge of the textField:
textField.layer.sublayerTransform = CATransform3DMakeTranslation(8, 0, 0);
This is given in an answer to a different question by user Dhiru (reputation 1285) in Nov. 2016. Thank you Dhiru!
I have to add that I am not familiar with either sublayerTransform or CATransform3DMakeTranslation so I can't be sure that this doesn't have some side effect that isn't immediately obvious. I'm a little worried that it's called "3D transform" whereas there is nothing 3D about my application. But at least for now this seems to answer the question.
I'm faced with a problem where I need to display some characters in a tree-view item (those belonging to the Symbol charset) using Symbol font while others in the default System font (Segoi UI on my Windows 7).
Custom draw allows us to draw different items using different fonts, but I would like to draw the same item string using different fonts as it applies to each character in the string as told above.
So, what I've done with not-so-pleasing results w.r.t. drawing performance upon a horizontal scroll when the number of items is more so far is this:
I disabled horizontal scrolling in my tree-view control using TVS_NOHSCROLL style (since I'm using my own scroll bar control inside the tree-view window to handle all horizontal scrolling)
I sub-classed the treeview control and in the sub-classed winproc, I handle the horizontal scroll notification and mouse notification (where I do my own hittesting and send message like TVM_EXPAND and TVM_SELECT as a result of mosue clicks/double-clicks). Also the scroll bar range is set based on how wide my custom drawn string is (the maximum length amongst all items).
I draw the string for each item upon receiving CDDS_ITEMPOSTPAINT using my own fonts for each character in the item.
The above approach (I left out some details for the sake of brevity) works BUT there are some problems which makes me post this question here and look for an alternare way:
Problems:
The horizontal scroll bar control I create is hosted "inside" the tree-view control at the bottom of the tree-view window. However, when the number of items goes beyond what the tree-view client area can accommodate vertically, the last visible tree-view item gets obscured by the scroll bar control. This can be solved by not making the scroll bar a child of the tree-view and hosting it outside the tree-view window just below it. But I don't want to do this since the scroll bar should typically be a child window of the tree-view.
This is the major one. Since I draw the items myself at each horizontal scroll, the drawing performance upon horizontal scrolling is very slow and also leads to flicker upon scrolling.
Any ideas will be much appreciated as I've been grappling with this for the last one week without success.
I can also post the relevant code here if you want to see the approach I took but I'm sure there shoould be a better approach to this and there must be some other people who would've faced this problem and solved it in the past.
Thanks in advance.
Custom-draw allows you to draw items however you want. You are not limited to a single font per item. When you receive the NM_CUSTOMDRAW notification, draw whatever you want on the provided HDC for the specified item. You can draw pieces of text in one font, pieces of text in a different font, etc. Be sure to return CDRF_SKIPDEFAULT so the TreeView itself will not try to draw anything on the item.
#Anurag S Sharma: I tried to edit this into Remy's answer. It's incomplete as is, but addresses your comment/concerns and answers this particularly vexing/useful question...
The problem is that ff I return CDRF_SKIPDEFAULT, Windows does not even draw the +/- buttons (expanding/collapsing) nor the indent lines in the control which I do want Windows to draw. – Anurag S Sharma
To retain the lines, buttons, and icons you can use ExcludeClipRect to mask only the text region and instead of returning CDRF_SKIPDEFAULT, return 0 as if you didn't draw anything. This itself would not be necessary if the text of the tree item was empty, except that the margins of the text will always be drawn by the default handler (note that Microsoft's controls do not always respect clipping shapes, but in this case they do.)
To replicate the classic TreeView label style in your custom draw procedure you need to do something like the following:
HTREEITEM item = (HTREEITEM)p->dwItemSpec;
TreeView_GetItemRect(p->hdr.hwndFrom,item,&p->rc,1);
RECT cr, rc = p->rc; GetClientRect(p->hdr.hwndFrom,&cr);
DrawTextW(p->hdc,text,-1,&rc,DT_CALCRECT|DT_NOPREFIX|DT_NOCLIP);
rc.right+=4; rc.bottom+=2; IntersectRect(&rc,&cr,&rc);
ExtTextOutW(p->hdc,rc.left+2,rc.top+1,ETO_CLIPPED|ETO_OPAQUE,&rc,text,wcslen(text),0);
After much reading and experimenting, I still cannot get a simple TextView to resize fully in the horizontal direction using Xcode 5.0.2 in Mavericks. It resizes partially as the window is resized, then stops with long lines wrapped around even though my containing NSScrollView continues to resize as expected (it has four default constraints and no horizontal scroller).
Can anyone point me to a simple code/IB+AutoLayout example, preferably just a window containing just an NSTextView dragged in from the IB template library --- one that works? The Apple TextEdit sample code is almost irrelevant for this purpose although it does resize horizontally quite well. Also, there is the clip view for which I can find little information.
Any other tips appreciated.
Thanks.
Answering my own question:
Turns out that my problem had nothing to do with AutoLayout and little to do with NSTextView. It was the textfile I was using to test my code! This file was composed of records with tab-delimited fields.
Turns out that NSTextView comes with a default NSParagraphStyle with predefined tab stops that end at character 56 whereas my test file had tabs beyond that. Therefore, my lines wrapped around at the last defined tab no matter how much I stretched the window.
After changing my search terms, I found what I needed at the following links:
Premature line wrapping in NSTextView when tabs are used
How to have unlimited tab stops in a NSTextView with disabled text wrap
Apologies for wasting bandwidth.
Not sure why such a simple thing does not work in your case, but nevertheless here's what I did in Xcode to get an NSTextView follow window resize:
Create a new project (not document based in my case but it doesn't really make a difference)
Drag a NSTextView from the palette to your window. Align all four edges with the window edges.
Open the "Add constraints" pop-up (second button from the segmented control on the bottom-right part of your IB view.
Each of the four spacing constraints should show a number equal to the distance of your text view from the container window. If you aligned them, this number should be either 0 or -1. Click the down arrow for each of them and select "Use Current Canvas Value". Do it for all four. Make sure no other constraints are selected.
Click on "Add constraints" on the bottom of the panel.
Run your project. Your textview should resize with the window.
Also, as Jay's comment mentions, make sure you do not have any "leftover" constraints in your view. You can check this either by observing Xcode's warnings, or manually by inspecting your view's constraints by going to the Size Inspector tab (4th tab on the Utilities bar).
If you need to have your textview arranged in a more complex layout, it might be worth taking a look at the AutoLayout Guide.
I'm writing an OS X app and have a problem with font smoothing in separate window.
I have a text field where you put text and suggestion window which pops up with a list of suggestions according to what you wrote. I'm using View-cell based NSTableView to display those suggestions and SFBPopoverWindowController to display it as a "popup" window (tried other classes with the same effect). When rows are first drawn they look fine but after I select them (keyboard or mouse) the font changes it's weight. It's only visual - like you would change smoothing method on the font, not it's bold setting.
"Music note" is the selected cell here
What's even more strange is that after I hide and show the window 3 times everything works fine from that point on.
Again - "Music note" is the selected cell.
The selection is done by overwriting NSTableRowView class and its drawSelectionInRect: method but I tried with drawing everything inside custom NSTableCellView class and it didn't help. The text is standard NSTextField - nothing's changed there.
The SFBPopoverWindow (and it's controller) are created once and reused with styleMask NSBorderlessWindowMask, backing NSBackingStoreBuffered, defer set to YES. The only change in SFBPopoverWindowController I made was to turn off window becoming key window but it doesn't change anything.
It might be related to the way a table view draws it's selected cells (setSelectionHightLightStyle:). Try to set the style to None/ NSTableViewSelectionHighlightStyleNone in your code or IB / Storyboard-file and draw the selection yourself (in a NSTableRowView subclass).
Background: When you use NSTableViewSelectionHighlightStyleRegular or NSTableViewSelectionHighlightStyleSourceList the table view assumes that you use the standard selection behaviour and appearance and does some magic to support that.
==========
UPDATE
==========
My previous answer is still valid but since it only describes the problem and hints at a workaround, I wanted to add a real solution. If you want to use NSTableViewSelectionHighlightStyleRegular for your table view (with custom font and colors), you need a way to 'disable' the system magic that comes into place once your row is highlighted. One proposed solution is to decline the first responder status. It has a lot of drawbacks and isn't a good solution at all.
So, let's have a closer look at the system 'magic' that kicks in as soon as the row will be highlighted: NSTableRowView has a property interiorBackgroundStyle that is – according to the documentation – 'an indication of how the subviews should draw'. Furthermore 'This value is dynamically computed based on the set of properties set for the NSTableRowView. Subclassers can override this value when they draw differently based on the currently displayed properties. This method can also be called to determine what color a subview should use, or alternatively, NSControls can have the -backgroundStyle set on their cell to this value.'
I assume that this style will be handed down the subview hierarchy and causes your text fields to look odd. The system assumes that a highlighted cell has a dark background and changes the interiorBackgroundStyle to dark. Other controls try to adapt accordingly.
I think there are two solutions to this problem:
1) Override interiorBackgroundStyle in your NSTableRowView subclass and return the style that fits your interface (in my case it's .light because my highlight color is a very bright blue). This worked for me.
2) If changing the whole style is a bit too much because you only want certain elements to not change their style, you may only need to adjust these subclasses. I haven't tried this yet.
I have an owner drawn header of a ListView control. If the header is not owner drawn we have a nice hover effect when mouse is on one of the header's columns. After I made header columns owner drawn I have to take care of the hover effect myself.
In order to catch it I monitor WM_MOUSEMOVE message within header window and when I get this message I redraw the column of a header with changed background first and on top of that I draw text and other necessary graphics. There is just one but... The font of a text becomes bold.
You can see it below. First header is mine, and second header is from Windows explorer with hover effect on Date modified column.
Why does the font suddenly becomes bold?
Is this the right way to implement hover effect? Maybe I missed some Header specific notification?
In owner draw mode you have to take care of everything including fonts. Don't assume you know what the current DC font is. If you want a specific font you need to select one into the DC before drawing text.
Well, I solved this mystery :) Even though I still don't know why the font used in DrawThemeText function suddenly changed in WM_MOUSEMOVE notification. My approach still relies on catching WM_MOUSEMOVE event and redrawing the column underneath the mouse pointer. In order not to change the default header font (like in illustration in my question) I used the following code to get and set it:
HFONT displayFont = (HFONT)SendMessage( header, WM_GETFONT, 0, 0 ); // gets default header font
SelectObject(hdc, displayFont); // sets device context to use newly found font
This solution has at least one drawback: I redraw the Header too frequently (each time mouse moves within header column).