Calculating width of checkboxes in NSOutlineView - macos

I'm programmatically setting up a multi-column NSOutlineView. The first column contains only checkboxes whereas the other columns contain text. I'm creating the checkboxes like this:
cell = [[NSButtonCell alloc] init];
[cell setButtonType:NSSwitchButton];
[cell setImagePosition:NSImageOnly];
Now I want to adjust the width of the first NSTableColumn to the exact width required by a checkbox. To calculate the dimensions of a checkbox cell, I do the following:
NSCell *cell = [m_view preparedCellAtColumn:0 row:0];
unsigned cellWidth = [cell cellSize].width;
This returns 18 in cellWidth. This is probably the right value but it isn't sufficient because NSOutlineView always seems to insert some blank space before the cells of the very first column. Here's what it looks like:
As you can see the checkboxes are currently cut off because the column width is too small because of the blank space in front of the checkbox.
Therefore, here is my question: How can I calculate the width of this blank space for my first NSTableColumn so that I can calculate the full column width required to show the checkbox and blank space? Is there maybe also a way to get rid of this blank space?

Related

NSView-based table view with auto layout grows, but does not shrink rows

I have a NSTableView in view-based mode (not cell-based) with usesAutomaticRowHeights=YES. The rows have dynamic height that might change at any time. This setup successfully grows table view rows (row content is never clipped), but table view rows don't shrink to the intrinsic row view height when rows get shorter. Calling noteHeightOfRowsWithIndexesChanged: on the table view after layout does not seem to fix the problem, my tableView:heightOfRow: is also not called again after noteHeightOfRowsWithIndexesChanged:.
Is there anything I have missed/isn't documented about using auto layout in NSView-based tableviews with variable row height? After all, growing rows always works without any additional code, they just do not shrink on their own.
NSTableView* tv = [[NSTableView alloc] init];
[tv setTranslatesAutoresizingMaskIntoConstraints:NO];
[tv setUsesAutomaticRowHeights:YES]; // Use auto layout for row height
NSTableColumn* column = [[NSTableColumn alloc] init];
[tv addTableColumn:column];
// Set table view data source and delegate, rows are then loaded...
After debugging the default table view layout for a long time, I finally found the issue. The table view row views come with some autoresizingmask settings that interfere with content, when using autolayout for the row content views. You need to set the row view's translatesAutoresizingMaskIntoConstraints to NO. This can be achieved for a view-based NSTableView using the delegate method tableView:(NSTableView *)tableView didAddRowView:(NSTableRowView *)rowView forRow:(NSInteger)row:
- (void)tableView:(NSTableView *)tableView didAddRowView:(NSTableRowView *)rowView forRow:(NSInteger)row
{
// Remember that rowView != row content view!
[rowView setTranslatesAutoresizingMaskIntoConstraints:NO]; // Disable constraints interfering with row view content
}
Interestingly, this does not seem to be an issue if content does not shrink past the initial row height or maximum row height it has grown to, due to dynamic height increases.

UITableView: Hide border/separator between cells

Is it possible to hide the separator between the cells of an UITableView?
But it should configure-able for each cell seperate (so not for the whole TableView).
What I already tried out is:
UIView *backView = [[[UIView alloc] initWithFrame:CGRectZero] autorelease];
backView.backgroundColor = UIColorFromRGB(CELL_COLOR_DEFAULT);
cell.backgroundView = backView;
The only problem here is, that on the left and right side is also no border, but here I would need it.
Thanks
NG
So are you trying to have a border around the entire cell or just the separator?
You could try adding something like
cell.layer.borderColor = [[UIColor blackColor]CGColor];
cell.layer.borderWidth = 10.0f;
to your cellForRowAtIndexPath method (you can decide whether to display the border for a given cell than as well).

Tooltip for view based NSTableView

I have a tooltip:
cellView.textField.toolTip = cellView.textField.stringValue;
It shows always, but I need to show tooltip only if text clipped... How I can achieve it?
Set allowsExpansionToolTips property to YES for Table View Cell in xib.
I think you can do this by implementing the text field delegate method, controlTextDidEndEditing, and checking the size of the text. I found that the size returned by sizeWithAttributes: didn't match the size I would have expected when I filled the text field, so I just determined the value I needed for my if statement empirically (in this example I had the text field's value bound to a property, theText).
-(void)controlTextDidEndEditing:(NSNotification *)obj {
NSLog(#"%#",NSStringFromRect([obj.object frame]));
NSDictionary *dict = [NSDictionary dictionaryWithObject:[NSFont systemFontOfSize:13] forKey:#"NSFontAttributeName"];
NSSize size = [theText sizeWithAttributes:dict];
NSLog(#"%#",NSStringFromSize(size));
if (size.width >69) {
[obj.object setToolTip:theText];
}
}
Try: allowsExpansionToolTips (in Swift, Obj-C)
Expansion tooltips are shown when the cell cannot show the full
content and the user hovers the pointer over the control.

NSTableView: How to draw a custom separators before and after a selected row

This is my first question here, and I will try to do it as clear as possible.
I want to draw a custom gradient on a selected row in a view-based NSTableView, while adding a subtle raised effect. For this, I need to use a darker color for the grid-lines that are before and after the selected row (see here for an example). I have overrode drawSeparatorInRect: method in NSTableRowView to draw the custom separator line for the selected row (using isSelected method as a flag), but I cannot do the same for the above/below one (since I draw the line at the bottom/top).
I have tried several ways to tell the closest row that it should draw a darker separator line with no success since the display step does not follow the same order (I checked it with NSLogs in the drawSeparatorInRect:, and it seems that when you scroll a little this order changes). So, sometimes (mostly after scrolling) the row doesn't know that it should use a darker color since it draws itself before the selected one (I think at this point, the selected-row is not aware yet that it's selected, otherwise I don't understand what is going on).
Some of the things I tried:
In the drawSeparatorInRect: method of the selected row, I have tried to access to the siblings views ([superview subviews]) and force the previous/next one to draw itself again.
From the NSTableView subclass, modify directly the closest row when the selectedIndexes change.
Drawing the line outside the selected row from within its drawSeparatorInRect: method as showing here.
Note that I did this having: a row view asking if the previous/next one is selected, a closestRowIsSelected flag or externally calling a method to "force" the dark color.
What I have now is that the selected row draws both top and bottom borders, so one of them is placed together to the previous/next row line... It's subtle but it still there.
Any help will be well received.
Thank you in advance.
! I didn't post any code since the problem is not there (it just calls [NSBezierPath fillRect:rect] with red color), I think... so I have nothing to show.
I've also tried this and noticed that drawSeparatorInRect: can really only draw its bottom separator line as the position of the top separator line (which is the same as the bottom separator line of the preceding row) is one pixel outside (above) the clipRect of the row.
However, I got it working by subclassing NSTableRowView and having drawSeparatorInRect: as follows:
- (void)drawSeparatorInRect:(NSRect)dirtyRect
{
// Define our drawing colors
NSColor *normalColor = [NSColor colorWithCalibratedWhite:0.76 alpha:1.0]; // Default separator color
NSColor *selectedTopColor = [NSColor colorWithCalibratedWhite:0.60 alpha:1.0]; // Color of the top separator line of selected row
NSColor *selectedBottomColor = [NSColor colorWithCalibratedWhite:0.60 alpha:1.0]; // Color of the bottom separator line of selected row
// Define coordinates of separator line
NSRect drawingRect = [self frame]; // Ignore dirtyRect
drawingRect.origin.y = drawingRect.size.height - 1.0;
drawingRect.size.height = 1.0; // Height of the separator line we're going to draw at the bottom of the row
// Get the table view and info on row index numbers
NSTableView *tableView = (NSTableView*)[self superview]; // The table view the row is part of
NSInteger selectedRowNumber = [tableView selectedRow];
NSInteger ownRowNumber = [tableView rowForView:self];
// Set the color of the separator line
[normalColor set]; // Default
if (([self isSelected]) && ((selectedRowNumber + 1) < [tableView numberOfRows])) [selectedBottomColor set]; // If the row is selected, use selectedBottomColor
if ((![self isSelected]) && (selectedRowNumber > 0) && (ownRowNumber == (selectedRowNumber-1))) [selectedTopColor set]; // If the row is followed by the selected row, draw its bottom separator line in selectedTopColor
// Draw separator line
NSRectFill (drawingRect);
// If the row is selected, tell the preceding row to redraw its bottom separator line (which is also the top line of the selected row)
if (([self isSelected]) && (selectedRowNumber > 0)) [tableView setNeedsDisplayInRect:[tableView rectOfRow:selectedRowNumber-1]];
}
This method will (only) draw its own bottom separator line. If it is the selected row, it will draw the line not with the default color, but highlighted, it will then also tell the preceding row to redraw its separator line, i.e. the same as the top separator line of the selected row.
In order to get this working, the row above the selected row needs to redraw its bottom separator line once the selection moves. I achieved this by having this method in the NSTableView delegate:
// Tell the row above the row which is going to loose the selection to redraw its bottom separator line
- (BOOL)selectionShouldChangeInTableView:(NSTableView *)aTableView
{
NSInteger selectedRowNumber = [aTableView selectedRow];
if (selectedRowNumber > 0) {
[aTableView setNeedsDisplayInRect:[aTableView rectOfRow:selectedRowNumber-1]];
}
return YES;
}
This delegate method tells the row above the still selected row to redraw its separator line. It is called immediately before the selection changes.

NSTableView setting the sort column?

I have a NSTableView with multiple columns. clicking each of the columns sorts by the column like in iTunes. However when the tableview first loads the rows are unsorted and no tablecolumn is highlighted or displaying the up/down indicator image. I'm wondering if theres a simple way I can programmatically set the column the table is sorted by and set the indicator image on startup.
The only solution I can think of is using [NSTableView setIndicatorImage: inTableColumn:] and [NSTableView setHighlightedColumn:], but that makes it so that clicking on the header doesnt highlight the column. I would rather not have to use tableView:mouseDownInHeaderOfTableColumn: and rewrite the whole click on header to sort thing.
You might try setting your sort discriptor.
- (void)setSortDescriptors:(NSArray *)array
- (void)windowControllerDidLoadNib:(NSWindowController *) windowController
{
[super windowControllerDidLoadNib:windowController];
NSSortDescriptor* sortDescriptor = [[[NSSortDescriptor alloc] initWithKey: #"order" ascending: YES] autorelease];
[oTable setSortDescriptors:[NSArray arrayWithObject:sortDescriptor]];
}
http://lists.apple.com/archives/cocoa-dev/2006/May/msg01434.html

Resources