Making an array of NSRect values in mousedown method - cocoa

My cocoa app calculates the location of every mousedown event. It also checks whether the location is located inside a rectangle using NSPointInRect and while enumerating over an existing mutable array with values of the rectangles. I'm using an if-statement to add the rectangle values in which the mousedown event is located to a new array (selectedRectangles).
The values are added perfectly to selectedRectangles, only problem is that previous values are overwritten. How can I solve this problem.
PS at the end of the mousedown method I use setNeedsDisplay:YES to update the data (this because selectedRectangles is used in another method).

add the rectangle values…to a new array
Assuming that you're asking a continuation of this question. You don't want to create a new array each time. You want to make an NSMutableArray before any click locations are stored, then use its addObject: method to add a new item on each click.

Related

How to animate a relayout of NSCollectionViewLayout on bounds change?

I have a basic implementation of NSCollectionViewLayout very similar to NSCollectionViewFlowLayout:
It places item in a horizontal row. If there's not enough room, the next item is added to the next row and so on.
My question: how can I animate a layout change when an item moves from the first row into the second row?
Here's an example:
Note how item #3 "jumps" from the first to the second row. I'd like to animate that change.
There are lots of methods to animate adding/removing items, but I was not able to figure out how to animate layout changes when no items change.
The methods you're looking to override in your layout subclass are prepare(forAnimatedBoundsChange:) and finalizeAnimatedBoundsChange().
From the documentation:
open func prepare(forAnimatedBoundsChange oldBounds: NSRect) // NSCollectionView calls this when its bounds have changed inside an animation block before displaying items in its new bounds
Prepares the layout object for animated changes to the collection view’s bounds or for the insertion or deletion of items.
open func finalizeAnimatedBoundsChange() // also called inside the animation block
Cleans up after any animated changes to the collection view’s bounds or after the insertion or deletion of items.

10.11 NSCollectionView - determining cell size dynamically

AppKit Release Notes for OS X v10.11 suggests that collection view items can be resized on a per-item basis:
Item size can be determined globally for all of a CollectionView’s items (by setting an NSCollectionViewFlowLayout’s “itemSize” property), or can be varied from one item to the next (by implementing -collectionView:layout:sizeForItemAtIndexPath: on your CollectionView’s delegate).
In my case, my CollectionViewItem consists of a single label that contains a string of varying length. I'm using the NSCollectionView to display an array of strings, as NSStackViews don't support array bindings, and don't flow to new lines. The array of strings is bound to the NSCollectionView's content via an array controller.
My item's nib file is properly set up, the root view and the label both have Content Hugging and Content Compression Resistance Priorities of 1000, and the edges are aligned via AutoLayout.
Now, the NSCollectionViewLayout's delegate method has this signature:
func collectionView(collectionView: NSCollectionView,
layout collectionViewLayout: NSCollectionViewLayout,
sizeForItemAtIndexPath indexPath: NSIndexPath) -> NSSize
My idea now is to grab the item itself, run a layout pass over it, and then returning the new item size.
let item = collectionView.itemAtIndexPath(indexPath)!
item.view.layout()
return item.view.bounds.size
Problem with this approach is that itemAtIndexPath returns nil. If I return a default size in the nil case, that default size is used for all cells.
How can I set a NSCollectionView to respect my item's AutoLayout constraints and for each cell, use the computed size dynamically?
There's a duplicate of this question that I answered but this is probably the one it should be directed to since it's older.
Juul's comment is correct- the items do not exist. sizeForItemAt being called is the collection asking the delegate for any specific sizing for that data entry with which it will use to help create its eventual view controller, NSCollectionViewItem. So you create a loop when you ask the collection to get you an item in the method that it uses to help get an item.
The problem we have is that we want sizing based on the appearance of that data: the length of a text label with proper formatting, not just, say, the string length. So we hit a chicken and egg problem.
The only solution I've come to, which could be prettier, is the following:
Prep
Subclass NSCollectionViewItem and ensure your collection view has a data source that returns the proper subclassed item.
Use constraints in your XIB, completely.
Your subclass should have a method that loads in the data object to be represented- both for this and of course your data source protocol methods.
At some point prior to the first sizeForItemAt call, or at the beginning of the first one if you hadn't by then, manually create an instance of your NSCollectionViewItem subclass, and use NSNib's instantiate(withOwner:topLevelObjects:) to instantiate its XIB with your subclass as an owner. Store that reference as a sort of "sizing template," so you only need to do it once. Delegate was easiest spot for me.
^Note: my first route was to attempt this through the collection's makeItemWithIdentifier, but it was more brittle as it required the collection to have items at the time of creating the sizing template. It also could not be done during an initial sizeForItemAt (accessing/making items during a reload crashes). And I was worried that because it was made with the collection it may get reused down the line and the methods below don't work or start editing visible items. YMMV.
In sizeForItemAt
Directly get the data object being represented from the datasource. Have your sizing template object represent that data object with the method I mentioned earlier.
Access the sizing template's View.FittingSize, the smallest size an item can be given its constraints/priorities, and return that.
Bam! Hasn't been stress tested or anything but no problems on my end, and its not doing a layout pass or anything, just calling FittingSize. I haven't seen this articulated anywhere online yet, so I wanted to write out the full explanation.
I did this in Xamarin.Mac, so my code won't be 1:1 and I don't want to write garbled swift and mess anything up.
TLDR: manually instantiate a NSCollectionViewItem subclass and its xib that you will store, unowned by the collection. During sizeForItem populate that item you store as a sizing reference, and return the FittingSize of the collection item's view.

Drag and Drop functionality using testcomplete

I want to simulate a drag and drop functionality from one DevXtraGridcell to another DevXtraGridcell without using the coordinate system.
Can someone give me an idea how can I do it without the default record and play and without the source and destination cordinates.
The Drag action always uses coordinates, but you can calculate the coordinates on the fly instead of using hard-coded coordinates:
Explore your grid in TestComplete's Object Browser and find a method or property that returns cell coordinates.
According to this old blog post, it should be something like:
gridObj.MainView.ViewInfo.RowsInfo.GetInfoByHandle(Row).Cells.Item_2(Column).Bounds
Calculate the coordinates of the first and second cell. (Make sure that both cells are visible on the screen.)
Do the Drag from one first cell's coordiantes to the second cell's coordinates.
in my case i had to user the obj.MainView.get_ViewInfo property worked for one gridcontrol , the other is of card layout the link given doesnt work in my case though

Have a NSComboBox to update when its bound NSMutableArray updates

Let's say I have a window with 2 combo boxes. The NSWindowController that control the window, has two mutable arrays that are bound to the combo boxes Content Values.
What I would like is that while the first combo box has fixed values, the second combo values depends on the first combo selected value.
What should I do to have the second combo box to reload its content when the associated mutable array updates (Or how should I update the array to make this happen?)?
If you set the value of the second array through its normal accessor methods, the right update messages should be propagated to all bound values and other listeners.
// When first combo box changes value
// NSArray *newArray = // Fancy algorithm..
self.secondArray = newArray;
That should get the second combo box to update.
In case you do not want to change the instance of the NSMutableArray backing your property, you could use the mutable accessor methods, discussed here. They will let you change the contents of the mutable array without changing the array itself. And the KVC/KVO system will propagate the changes to the listeners.

RootViewController need to resort/reload data array xcode 4.3

I'm implementing an example, in that example, I read in data from a database, put it in an array, sort it, and it's displayed using the RootViewController. The DB read and array load happen before the RVC code. So, it works, I get the data in the window created by the RVC and there's a nav controller there as well.
I want to add a button or something to the nav controller so that when you hit it, it sends a value back to the RootViewController.m file, then based on that value, I want to resort the array and display it once again in the RootViewController window.
I'm not sure how to do this. What changes would I have to make to the .xib and the RootViewController.m file?
Please, I'm a confused nube. %-0 Thank you very much.
There's a fair amount to this, so I'll give some general points and if any of them cause problems, it may be easier to work out smaller details.
In you RVC's viewDidLoad method, you can create a button and set it as the right or left button in your controller's navigationItem.
You can associate a tap on that button with a method in your controller that can do whatever you want when the button is tapped. (But a button doesn't send values, really, so you may have to explain more about that idea.)
I assume the RVC has a table view if you're showing array contents, so once the array (mutable array, I'd assume) is re-sorted, you can tell the table view to reload its data.
In answer to your secondary question, once you have resorted your array (or generally updated your data however you wish) you can force the table view to reload programmatically
[tableView reloadData];
Where 'tableView' is your instance variable pointing to your table view

Resources