use CGPoint as an array - cgpoint

I want to use an function to pass a lot of points to another function, but the Xcode has errors on the line with: CGContextAddLines......
the add points is filled with information like:
CGPoint addPoints[] = {
CGPointMake(10,10),
CGPointMake(10,10),
}
the use the
-(void) constructPoints:(CGContextRef) context withPoints:(CGPoint) addPoints {
// do some context set attributes, color
// and
CGContextAddLines(context, addPoints, sizeof(addPoints)/sizeof(addPoints[0]));
// and draw-it
}

Try it like this:
-(void) constructPoints:(CGContextRef) context withPoints:(CGPoint[]) addPoints numPoints:(int) size {
// do some context set attributes, color
// and
CGContextAddLines(context, addPoints, size);
// and draw-it
}
Then on your call:
[self constructPoints:yourContext withPoints:addPoints numPoints:sizeof(addPoints)/sizeof(addPoints[0])];

Related

crash on CPTScatterPlotDelegate in CorePlot

I am trying to overlay multiple graphs in one plot and I am getting crashes (EXC_BAD_ACCESS) on the CPTScatterPlotDelegate below in class CPTScatterPlot.m
-(void)renderAsVectorInContext:(nonnull CGContextRef)context {
...
// Draw line
if ( theLineStyle ) {
CGPathRef dataLinePath = [self newDataLinePathForViewPoints:viewPoints indexRange:viewIndexRange baselineYValue:CPTNAN];
// Give the delegate a chance to prepare for the drawing.
id<CPTScatterPlotDelegate> theDelegate = self.delegate;
....
}
...
}
The Same in CPTLegendDelegate in class CPTPlot.m
-(void)drawSwatchForLegend:(nonnull CPTLegend *)legend atIndex:(NSUInteger)idx inRect:(CGRect)rect inContext:(nonnull CGContextRef)context
{
id<CPTLegendDelegate> theDelegate = (id<CPTLegendDelegate>)self.delegate;
...
}
I am using CorePlot 2.1, and I have modified the renderInGraphHostingView in file SimpleScatterPlot.m in examples/CorePlotGallery as follows:
-(void)renderInGraphHostingView:(nonnull CPTGraphHostingView *)hostingView withTheme:(nullable CPTTheme *)theme animated:(BOOL)animated {
...
static CPTGraph *graph = nil;
if( initialize ) {
graph = [[CPTXYGraph alloc] initWithFrame:bounds];
...
}
[self addGraph:graph toHostingView:hostingView];
theme = [CPTTheme themeNamed:kCPTDarkGradientTheme];
...
}
So every time I want to draw a new line of data, I use the same graph.
The problem is random and sometimes program crashes when I draw the second line, sometimes in the third, but it always works fine for the first graph. It also depends on the compilation.
Any ideas?
Thanks in Advance
The delegate property holds a weak reference to the delegate object. Make sure the delegate isn't being deallocated between graph updates.

Primary view controller content disappearing when manually setting preferredDisplayMode on split view rotation

I have a custom UISplitViewController subclass in iOS 8. When in landscape I want the default behavior of both the primary and secondary VCs being visible (preferredDisplayMode = UISplitViewControllerDisplayModeAllVisible), but when I rotate to portrait I would like the primary VC to be displayed in the default popover (preferredDisplayMode = UISplitViewControllerDisplayModePrimaryOverlay).
By implementing -viewWillTransitionToSize: on the subclass I can kind of get this working, but after rotating a couple times the primary VC disappears and will not reappear until I tap the split view's bar button item.
The log in the rotation animation completion block on the first couple rotations shows the preferred display mode being the same as the actual display mode, but after a couple rotations the actual display mode is stuck as UISplitViewControllerDisplayModePrimaryOverlay in landscape, even when the preferred display mode is UISplitViewControllerDisplayModeAllVisible.
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
if (self.traitCollection.userInterfaceIdiom == UIUserInterfaceIdiomPad) {
BOOL isPortrait = size.height > size.width;
if (isPortrait) {
self.preferredDisplayMode = UISplitViewControllerDisplayModePrimaryOverlay;
}
else {
self.preferredDisplayMode = UISplitViewControllerDisplayModeAllVisible;
}
[coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) {
self.dividerView.hidden = isPortrait;
} completion:^(id<UIViewControllerTransitionCoordinatorContext> context) {
NSLog(#"Preferred display mode: %ld | Actual display mode: %ld", self.preferredDisplayMode, self.displayMode);
}];
}
}
Thanks to https://devforums.apple.com/message/1024928#1024928 I got it figured.
In the completion block for the animation coordinator, setting the preferredDisplayMode to UISplitViewControllerDisplayModeAutomatic makes it work.
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
if (self.traitCollection.userInterfaceIdiom == UIUserInterfaceIdiomPad) {
BOOL isPortrait = size.height > size.width;
if (isPortrait) {
self.preferredDisplayMode = UISplitViewControllerDisplayModePrimaryOverlay;
}
[coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) {
if (isPortrait) {
self.preferredDisplayMode = UISplitViewControllerDisplayModePrimaryOverlay;
}
self.dividerView.hidden = isPortrait;
} completion:^(id<UIViewControllerTransitionCoordinatorContext> context) {
// ADD THIS TO THE COMPLETION BLOCK
self.preferredDisplayMode = UISplitViewControllerDisplayModeAutomatic;
NSLog(#"Preferred display mode: %ld | Actual display mode: %ld", self.preferredDisplayMode, self.displayMode);
}];
}
}

Making an NSTableView behave like a WPF StackPanel

I'm trying to implement a vertical StackPanel equivalent in my MonoMac project and am having trouble figuring it out. I am not using interface builder but creating the controls programmatically (this is a restriction). I tried using a CollectionView but all items in that control are sizing to the same height.
Looking around the internet, it seems NSTableView is the way to go, but I'm not sure how to do it, especially with C# while using a MonoMac target. CollectionView was somewhat more straightforward with the CollectionViewItem.ItemPrototype allowing me to create the views I want to render. But with an NSTableView, it seems like I can only specify a data source that returns the NSObjects I want to display. How do I grab this data and then bind them to the view I want to stick in there?
I would prefer C# code but I'm at a stage where I'll accept any and all help!
I was finally able to get it working. Here is some code for anyone who wants to try it out. Basically, we need to write NSTableViewDelegates for the required functions. This implementation also doesn't cache the controls or anything. The Cocoa API documentation mentioned using an identifier to reuse the control, or something, but the identifier field is get-only in MonoMac.
I also ended up implementing my NSTableViewDelegate functions in my data-source itself which I am sure is not kosher at all, but I'm not sure what the best practice is.
Here's the data source class:
class MyTableViewDataSource : NSTableViewDataSource
{
private NSObject[] _data;
// I'm coming from an NSCollectionView, so my data is already in this format
public MyTableViewDataSource(NSObject[] data)
{
_data = data;
}
public override int GetRowCount(NSTableView tableView)
{
return _data.Length;
}
#region NSTableViewDelegate Methods
public NSView GetViewForItem(NSTableView tableView, NSTableColumn tableColumn, int row)
{
// MyViewClass extends NSView
MyViewClass result = tableView.MakeView("MyView", this) as MyViewClass;
if (result == null)
{
result = new MyViewClass(_data[row]);
result.Frame = new RectangleF(0, 0, tableView.Frame.Width, 100); // height doesn't matter since that is managed by GetRowHeight
result.NeedsDisplay = true;
// result.Identifier = "MyView"; // this line doesn't work because Identifier only has a getter
}
return result;
}
public float GetRowHeight(NSTableView tableView, int row)
{
float height = FigureOutHeightFromData(_data[row]); // run whatever algorithm you need to get the row's height
return height;
}
#endregion
}
And here's the snippet that programmatically creates the table:
var tableView = new NSTableView();
var dataSource = new MyTableViewDataSource();
tableView.DataSource = dataSource;
tableView.HeaderView = null; // get rid of header row
tableView.GetViewForItem = dataSource.GetViewForItem;
tableView.GetRowHeight = dataSource.GetRowHeight;
AddSubView(tableView);
So, it is not a perfect StackPanel because one needs to manually calculate row heights, but it's better than nothing.

Two way binding when setter is overriden

I have an NSTextField bound to some object "zoom" property.
In this object's class implementation, I have the following
- (void)setZoom:(CGFloat)zoom
{
_zoom = MAX(0, MIN(10, zoom));
}
If I write "-5" in the textfield, setZoom: will be called with "-5" as argument and _zoom will be set to 0.
Then problem is that the textfield is not updating itself and it shows "-5" instead of re-reading the property value it has just set.
If I do myObject.zoom = -5; in code, the text field will display 0 correctly.
I tried to wrap _zoom =... inside willChangeValueForKey/didChangeValueForKey calls but it didn't change anything.
You can try to do in such way:
- (void)setZoom:(CGFloat)zoom
{
CGFloat corectedValue = MAX(0, MIN(10, zoom));
if (zoom != corectedValue)
{
[self setZoom:correctedValue];
} else {
_zoom = zoom;
}
}

Return CGPoints from a function

I have another question about passing CGPoint in junctions:
(CGPoint[]) displayPoints:(CGPoint) startPoint
withEnd:(CGPoint) endPoint
withBaseRotate:(Boolean) baseRotate {
// do some stuf with four or six points
// create a array of the points and return - it
CGPoint ourPoints[] = {
CGPointMake(point1.x, point1.y),
CGPointMake(point2.x, point2.y),
CGPointMake(point3.x, point3.y),
//... some more points
} ;
return ourPoints[];
}
Why is this not working?
Have to return a pointer to where it is stored at in memory
(const CGPoint *) displayPoints:(CGPoint) startPoint
withEnd:(CGPoint) endPoint
withBaseRotate:(Boolean) baseRotate {
CGPoint ourPoints[] = {
CGPointMake(point1.x, point1.y),
CGPointMake(point2.x, point2.y),
CGPointMake(point3.x, point3.y),
//... some more points
} ;
return ourPoints;
}
If you look at the signature of CFContextAddLines, you'll see that is what they're using. Now the compiler will throw a warning for returning a pointer to memory... so I'm not sure if this is the preferred way but it answers your question.

Resources