Re: drawRect runs twice, bounds are changed in between

2015-01-29 Thread N!K
Thank you.


On Jan 28, 2015, at 8:30 PM, Graham Cox graham@bigpond.com wrote:

 
 On 29 Jan 2015, at 3:05 pm, N!K pu56ucl...@alumni.purdue.edu wrote:
 
 NSBezierPath* temp;   is in the list of declarations.
 This snippet is in drawRect:
 
   NSAffineTransform* tfm = [[NSAffineTransform alloc] init];
   [tfm scaleXBy:scaleX yBy:scaleY];
  temp  = [tfm transformBezierPath:_path];
  NSLog(@“\n\n temp = %p\n\n,temp);
 
 
 I hope ARC keeps cleaning them up. Or do I have a memory leak? If so, I’d 
 appreciate some guidance on how to fix it.
 
 
 You're fine leaks-wise, but your code might be cleaner. The bezier path 
 returned by [tfm transformBezierPath] is autoreleased. ARC cleans up tfm, 
 temp is released at the end of the event cycle. If temp is an ivar, and it's 
 not used anywhere else, just make it a local var (it will be stale after the 
 event cycle completes anyway). If it's an ivar and it is referenced 
 elsewhere, you probably should make it a strong property instead.
 
 --Graham
 
 


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: drawRect runs twice, bounds are changed in between

2015-01-28 Thread N!K
Uti, 

Looking further into your uncertainty about where temp comes from (see previous 
email, below) reveals a possible memory leak. 

NSBezierPath* temp;  is in the list of declarations.
This snippet is in drawRect:

NSAffineTransform* tfm = [[NSAffineTransform alloc] init];
[tfm scaleXBy:scaleX yBy:scaleY];
temp  = [tfm transformBezierPath:_path];
NSLog(@“\n\n temp = %p\n\n,temp);

drawRect runs many times while  dragging the corner of the window. 
transformBezierPath: creates a new object each time. 
A new temp is created each time. Just one memory location is not used 
repeatedly. 

Here’s a list of temp addresses — not temp content  —   (from NSLog %p above) 
while dragging the corner of the window slightly. They are all different.

2015-01-28 16:27:44.042 CVone[780:303] 

 temp = 0x608000320960

2015-01-28 16:27:44.094 CVone[780:303] 

 temp = 0x60800013fd60

2015-01-28 16:27:49.465 CVone[780:303] 

 temp = 0x6080003212c0

2015-01-28 16:27:49.484 CVone[780:303] 

 temp = 0x6013ff40

2015-01-28 16:27:49.501 CVone[780:303] 

 temp = 0x608000321180

2015-01-28 16:27:49.523 CVone[780:303] 

 temp = 0x608000320be0

2015-01-28 16:27:49.541 CVone[780:303] 

I hope ARC keeps cleaning them up. Or do I have a memory leak? If so, I’d 
appreciate some guidance on how to fix it.

Nick



On Jan 16, 2015, at 5:30 AM, Uli Kusterer witness.of.teacht...@gmx.net wrote:

 On 15 Jan 2015, at 07:58, Quincey Morris 
 quinceymor...@rivergatesoftware.com wrote:
 Putting those two ideas together leads to a better approach. Create the 
 bezier path once, relative to an arbitrary bounding rect — say 1000 x 1000. 
 (But any rect would do.) When you need to draw the path, set the CTM of the 
 context to scale 1000 x 1000 (the reference bounds) to the context’s width x 
 height (the view bounds). Then just draw the original path and AppKit will 
 scale the bezier path for you.
 
 That's not the be-all end-all, though. Scaling the CTM scales line widths and 
 heights as well. So if you for example want to skew the path, you'd get lines 
 that are wider than they are tall (kind of calligraphic). Also, changing the 
 CTM means that mouse click coordinates will be in a different coordinate 
 system then your drawing, so if you’re e.g. implementing a graphics editor, 
 you'll have to manually translate the coordinates each time.

 
 A better idea might be to have a list of original objects and projected 
 objects. The list of projected objects is generated by transforming the 
 paths. Whenever your view's bounds change, you rebuild this list of projected 
 objects from the originals (thus keeping rounding errors etc. to a minimum as 
 they can't accumulate). The drawing code just draws this projected list.
 
 As I don't know where 'temp' comes from in N!K’s code,

NSBezierPath* temp;  is in the list of declarations.

_path is created once, in -(id)initWithCoder:(NSCoder*)coder . 
_path is scaled to the new size and assigned to  temp each time drawRect is 
called. Thus, there is no error buildup.

 this may be what's already happening, in which case I find that a better 
 approach than mangling the CTM if your interest is in having a shape drawn 
 crisply in a window. If you're instead looking to scale a drawing (whether 
 vector or otherwise), where you want lines to be skewed, then Quincy.s 
 approach is preferrable.
 
 -- Uli


Nick
___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: drawRect runs twice, bounds are changed in between

2015-01-28 Thread Graham Cox

 On 29 Jan 2015, at 3:05 pm, N!K pu56ucl...@alumni.purdue.edu wrote:
 
 NSBezierPath* temp;is in the list of declarations.
 This snippet is in drawRect:
 
NSAffineTransform* tfm = [[NSAffineTransform alloc] init];
[tfm scaleXBy:scaleX yBy:scaleY];
   temp  = [tfm transformBezierPath:_path];
   NSLog(@“\n\n temp = %p\n\n,temp);
 
 
 I hope ARC keeps cleaning them up. Or do I have a memory leak? If so, I’d 
 appreciate some guidance on how to fix it.


You're fine leaks-wise, but your code might be cleaner. The bezier path 
returned by [tfm transformBezierPath] is autoreleased. ARC cleans up tfm, temp 
is released at the end of the event cycle. If temp is an ivar, and it's not 
used anywhere else, just make it a local var (it will be stale after the event 
cycle completes anyway). If it's an ivar and it is referenced elsewhere, you 
probably should make it a strong property instead.

--Graham



___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: drawRect runs twice, bounds are changed in between

2015-01-17 Thread N!K

On Jan 16, 2015, at 5:30 AM, Uli Kusterer witness.of.teacht...@gmx.net wrote:

 On 15 Jan 2015, at 07:58, Quincey Morris 
 quinceymor...@rivergatesoftware.com wrote:
 Putting those two ideas together leads to a better approach. Create the 
 bezier path once, relative to an arbitrary bounding rect — say 1000 x 1000. 
 (But any rect would do.) When you need to draw the path, set the CTM of the 
 context to scale 1000 x 1000 (the reference bounds) to the context’s width x 
 height (the view bounds). Then just draw the original path and AppKit will 
 scale the bezier path for you.
 
 That's not the be-all end-all, though. Scaling the CTM scales line widths and 
 heights as well. So if you for example want to skew the path, you'd get lines 
 that are wider than they are tall (kind of calligraphic). Also, changing the 
 CTM means that mouse click coordinates will be in a different coordinate 
 system then your drawing, so if you’re e.g. implementing a graphics editor, 
 you'll have to manually translate the coordinates each time.

 
 A better idea might be to have a list of original objects and projected 
 objects. The list of projected objects is generated by transforming the 
 paths. Whenever your view's bounds change, you rebuild this list of projected 
 objects from the originals (thus keeping rounding errors etc. to a minimum as 
 they can't accumulate). The drawing code just draws this projected list.
 
 As I don't know where 'temp' comes from in N!K’s code,

NSBezierPath* temp;  is in the list of declarations.

_path is created once, in -(id)initWithCoder:(NSCoder*)coder . 
_path is scaled to the new size and assigned to  temp each time drawRect is 
called. Thus, there is no error buildup.

 this may be what's already happening, in which case I find that a better 
 approach than mangling the CTM if your interest is in having a shape drawn 
 crisply in a window. If you're instead looking to scale a drawing (whether 
 vector or otherwise), where you want lines to be skewed, then Quincy.s 
 approach is preferrable.
 
 -- Uli


Nick
___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: drawRect runs twice, bounds are changed in between

2015-01-16 Thread Uli Kusterer
On 15 Jan 2015, at 07:58, Quincey Morris quinceymor...@rivergatesoftware.com 
wrote:
 Putting those two ideas together leads to a better approach. Create the 
 bezier path once, relative to an arbitrary bounding rect — say 1000 x 1000. 
 (But any rect would do.) When you need to draw the path, set the CTM of the 
 context to scale 1000 x 1000 (the reference bounds) to the context’s width x 
 height (the view bounds). Then just draw the original path and AppKit will 
 scale the bezier path for you.

 That's not the be-all end-all, though. Scaling the CTM scales line widths and 
heights as well. So if you for example want to skew the path, you'd get lines 
that are wider than they are tall (kind of calligraphic). Also, changing the 
CTM means that mouse click coordinates will be in a different coordinate system 
then your drawing, so if you're e.g. implementing a graphics editor, you'll 
have to manually translate the coordinates each time.

 A better idea might be to have a list of original objects and projected 
objects. The list of projected objects is generated by transforming the paths. 
Whenever your view's bounds change, you rebuild this list of projected objects 
from the originals (thus keeping rounding errors etc. to a minimum as they 
can't accumulate). The drawing code just draws this projected list.

As I don't know where 'temp' comes from in N!K's code, this may be what's 
already happening, in which case I find that a better approach than mangling 
the CTM if your interest is in having a shape drawn crisply in a window. If 
you're instead looking to scale a drawing (whether vector or otherwise), where 
you want lines to be skewed, then Quincy.s approach is preferrable.

-- Uli
___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: drawRect runs twice, bounds are changed in between

2015-01-15 Thread Steve Christensen
Would the Managing Live Resize methods of NSView 
(https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/NSView_Class/#//apple_ref/doc/uid/2014-SW41)
 be helpful?

The docs for -viewWillStartLiveResize suggest that that would be a good place 
to prepare for a resize instead of trying to manage how has the size changed 
decisions in -drawRect:.


On Jan 14, 2015, at 8:39 PM, N!K pu56ucl...@alumni.purdue.edu wrote:

 On Jan 13, 2015, at 10:50 PM, Jens Alfke j...@mooseyard.com wrote:
 
 
 On Jan 13, 2015, at 9:25 PM, N!K pu56ucl...@alumni.purdue.edu wrote:
 
 A breakpoint at the end of drawRect shows that it runs twice. After the 
 second pass, the view appears, as it should.
 Between passes, bounds is changed somehow, as shown by NSLog  at the start 
 and end of drawRect. 
 Since this will upset code that I will add later, I’d like to stop this. 
 
 The view's being resized, probably as part of view layout. Ideally AppKit 
 shouldn't draw the view before it gets to its final size, but maybe this is 
 part of an animation, or maybe it's something that hasn't been optimized 
 100% in AppKit.
 
 In general, you should not make assumptions about when and how often 
 -drawRect: will be called. That's up to AppKit. Your job is just to draw the 
 view when you’re told to.
 
 OK. Cause is unknown (probably unknowable?) but part of Cocoa. Just because 
 there was only one pass in other projects, I can’t depend on it. drawRect can 
 happen anytime.
 
 You haven't said why the bounds change will upset your code; is the view 
 being changed to the wrong size? That would be an actual problem, but it 
 isn't related to being drawn multiple times. You'd need to look at the view 
 constraints in your window to diagnose that.
 
 —Jens
 
 “Why” takes a little explaining. Thank you for your patience.
 
 I’m trying to learn more about drawing. One stumbling block was getting an 
 NSBezierPath to change size proportional to the window size when the corner 
 is dragged. Per Graham Cox’s suggestion, the view size change can be detected 
 in subsequent passes of drawRect by comparing 
   ratioX = NSWidth ([_path bounds])/NSWidth(bounds);
   ratioY = NSHeight([_path bounds])/NSHeight(bounds);
 with their initial values, which were established in the one pass of drawRect 
 before the view appeared.
 
 This worked perfectly. I used the ratios in 
 -(void)resize{
scaleX = ratioX0/ratioX;
scaleY = ratioY0/ratioY;
NSAffineTransform* tfm = [[NSAffineTransform alloc] init];
[tfm scaleXBy:scaleX yBy:scaleY];
   temp  = [tfm transformBezierPath:_path];
 }
 The initial view was correct. Then dragging the window corner  induced 
 drawRect’s, which detected the changes and scaled the original _path each 
 time; no cumulative errors. The path size tracked the view size correctly. 
 
 
 
 Next I wanted to learn how to scale the whole view in a new project, not just 
 the NSBezierPath. I was  planning to  later include other objects with the 
 NSBezierPath and wanted them to be scaled, too. I used the same 
 initialization and failed because of the bounds change between two passes, 
 which I failed to anticipate. The first pass set the initial values. The 
 second pass detected the change and scaled the view before the view appeared.
 -(void)resize{
scaleX = ratioX0/ratioX;
scaleY = ratioY0/ratioY;
NSAffineTransform* tfm = [[NSAffineTransform alloc] init];
[tfm scaleXBy:scaleX yBy:scaleY];
temp  = [tfm transformBezierPath:_path];
 }
 Thus the path in the initial view was quite different from the initial path, 
 and dragging the corner of the window caused wildly incorrect scaling.
 
 My hope was that there might be a way of suppressing the second pass before 
 display of the view. Now I know better and will figure out another way to 
 initialize and track. Thank you for correcting me.
 
 Nick


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: drawRect runs twice, bounds are changed in between

2015-01-15 Thread Graham Cox

 On 15 Jan 2015, at 3:39 pm, N!K pu56ucl...@alumni.purdue.edu wrote:
 
 I’m trying to learn more about drawing. One stumbling block was getting an 
 NSBezierPath to change size proportional to the window size when the corner 
 is dragged. Per Graham Cox’s suggestion, the view size change can be detected 
 in subsequent passes of drawRect by comparing 
   ratioX = NSWidth ([_path bounds])/NSWidth(bounds);
   ratioY = NSHeight([_path bounds])/NSHeight(bounds);
 with their initial values, which were established in the one pass of drawRect 
 before the view appeared.
 


This wasn't my suggestion, exactly.

Don't use -drawRect to establish anything - just use it to draw. Only draw. 
Only ever draw.

My actual suggestion was to create your bezier path at some known size - I've 
used a size of 1 x 1 centred at 0,0 for example, then scale it to your needs 
*WHEN* you draw it, then discard the scaled version. That way you are proof 
against whatever size your view is, and when and how often it's called. You 
don't (and shouldn't) need a -resize method because you never store the results 
of it anyway.

All that said, this is just toy code that shows you how you can apply scaling 
to a path - it isn't necessarily much use in real-world app. One problem with 
it for example is that it's possible to end up (if your view is zero-sized, as 
it can be when initialized) with div-by-zero errors that end up putting NaNs 
into the path's coordinates. Core Graphics (which has always tolerated that 
sort of thing historically) will, since 10.9, throw a fit and summarily abort 
your app.

If you want to allow your view to zoom, rather than just display some content 
scaled, look into the relationship between the bounds and the frame of the 
view. Setting these different will cause zooming. If you want a slghtly more 
realistic way to place bezier path objects in a view, one approach could be to 
create an object that has a bezier path (maybe at a fixed size, such as 1 x 1), 
and also other states of it, such as its drawn size, angle and position from 
which you can create a transform. It's also convenient to include things such 
as stroke and fill colours.

--Graham



___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: drawRect runs twice, bounds are changed in between

2015-01-14 Thread N!K

On Jan 13, 2015, at 10:55 PM, Quincey Morris 
quinceymor...@rivergatesoftware.com wrote:

 On Jan 13, 2015, at 21:25 , N!K pu56ucl...@alumni.purdue.edu wrote:
 
 I have not been able to find  a reason for this behavior. . I don’t know how 
 to reveal the point between passes where bounds is actually changed. It does 
 not happen in any other NSView projects of mine; drawRect runs only once in 
 them
 
 The immediate reason is probably that the view’s size changed, which is not 
 unlikely when the window is in the process of being displayed. The view may 
 be resized for a “local” reason, such as the application of auto layout 
 constraints, or for a “global” reason, such as the containing being resized 
 and the change filtering down to subviews.
 
 Another possibility is that the view didn’t change size, but that (as an 
 implementation detail of the Cocoa drawing system) it received two partial 
 invalidations, and these weren’t coalesced in this case.
 
 I would like to prevent the second pass, or at least prevent the bounds 
 change between passes.
 
 I don’t see any practical way to prevent ‘drawRect’ from being called again.


 Redundant ‘drawRect’ calls can occur any time during the view’s lifetime. 

This I didn’t realize, until you and Jens are explaining to me now. 

 
 Are you implying that one bounds rect is “right” and one is “wrong”?

No. The system draws the view correctly, as long as I don’t interfere by adding 
my attempt at initialization and scaling.

 If so, how do you know that, and why can’t you just make your code do nothing 
 if the bounds are “wrong”?
 
 If the only criterion is that the *last* bounds rect is “right”, you’ve got a 
 big problem, because there’s no such concept in the drawing system.
 
 If you’re hoping that someone can suggest a solution, you probably need to be 
 more specific about what “right” and “wrong” mean. 


 
 I’m reluctant to try restoring bounds to its first value. I appreciate Ken 
 Thomases’ warning in a previous subject not to change bounds in drawRect.
 
 
 I’d say it wasn’t a warning, but rather an injunction to never, ever do that. 
 Doing so is Wile E. Coyote stuff.
 


I wish this had appeared in the Cocoa books I’ve read.


On  a lighter note, the Roadrunner cartoons are my favorites. Every blunder 
presents a classic engineering failure.  :)




___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: drawRect runs twice, bounds are changed in between

2015-01-14 Thread N!K

On Jan 13, 2015, at 10:50 PM, Jens Alfke j...@mooseyard.com wrote:

 
 On Jan 13, 2015, at 9:25 PM, N!K pu56ucl...@alumni.purdue.edu wrote:
 
 A breakpoint at the end of drawRect shows that it runs twice. After the 
 second pass, the view appears, as it should.
 Between passes, bounds is changed somehow, as shown by NSLog  at the start 
 and end of drawRect. 
 Since this will upset code that I will add later, I’d like to stop this. 
 
 The view's being resized, probably as part of view layout. Ideally AppKit 
 shouldn't draw the view before it gets to its final size, but maybe this is 
 part of an animation, or maybe it's something that hasn't been optimized 100% 
 in AppKit.
 
 In general, you should not make assumptions about when and how often 
 -drawRect: will be called. That's up to AppKit. Your job is just to draw the 
 view when you’re told to.

OK. Cause is unknown (probably unknowable?) but part of Cocoa. Just because 
there was only one pass in other projects, I can’t depend on it. drawRect can 
happen anytime.

 
 You haven't said why the bounds change will upset your code; is the view 
 being changed to the wrong size? That would be an actual problem, but it 
 isn't related to being drawn multiple times. You'd need to look at the view 
 constraints in your window to diagnose that.
 
 —Jens

“Why” takes a little explaining. Thank you for your patience.

I’m trying to learn more about drawing. One stumbling block was getting an 
NSBezierPath to change size proportional to the window size when the corner is 
dragged. Per Graham Cox’s suggestion, the view size change can be detected in 
subsequent passes of drawRect by comparing 
ratioX = NSWidth ([_path bounds])/NSWidth(bounds);
ratioY = NSHeight([_path bounds])/NSHeight(bounds);
with their initial values, which were established in the one pass of drawRect 
before the view appeared.

This worked perfectly. I used the ratios in 
-(void)resize{
scaleX = ratioX0/ratioX;
scaleY = ratioY0/ratioY;
NSAffineTransform* tfm = [[NSAffineTransform alloc] init];
[tfm scaleXBy:scaleX yBy:scaleY];
temp  = [tfm transformBezierPath:_path];
}
The initial view was correct. Then dragging the window corner  induced 
drawRect’s, which detected the changes and scaled the original _path each time; 
no cumulative errors. The path size tracked the view size correctly. 



Next I wanted to learn how to scale the whole view in a new project, not just 
the NSBezierPath. I was  planning to  later include other objects with the 
NSBezierPath and wanted them to be scaled, too. I used the same initialization 
and failed because of the bounds change between two passes, which I failed to 
anticipate. The first pass set the initial values. The second pass detected the 
change and scaled the view before the view appeared.
-(void)resize{
scaleX = ratioX0/ratioX;
scaleY = ratioY0/ratioY;
NSAffineTransform* tfm = [[NSAffineTransform alloc] init];
[tfm scaleXBy:scaleX yBy:scaleY];
temp  = [tfm transformBezierPath:_path];
}
Thus the path in the initial view was quite different from the initial path, 
and dragging the corner of the window caused wildly incorrect scaling.

My hope was that there might be a way of suppressing the second pass before 
display of the view. Now I know better and will figure out another way to 
initialize and track. Thank you for correcting me.

Nick








___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: drawRect runs twice, bounds are changed in between

2015-01-14 Thread Quincey Morris
On Jan 14, 2015, at 20:39 , N!K pu56ucl...@alumni.purdue.edu wrote:
 
 I’m trying to learn more about drawing. One stumbling block was getting an 
 NSBezierPath to change size proportional to the window size when the corner 
 is dragged.

This is the wrong way to approach the problem. Scaling the bezier path itself 
is a bad idea, for two unrelated reasons:

1. Each time you apply a transform to the path, you’re doing floating point 
arithmetic, so you’re introducing errors. Possibly, in most circumstances, you 
won’t notice much, but the fact of accumulating error tells you that the 
approach is wrong.

2. A bezier path’s coordinates are dimensionless (that is, unit-less) numbers. 
They have no meaning in terms of points or pixels.

They are *given* a meaning by the current transform matrix (CTM) of a context 
you draw the path into. When the CTM is the identity matrix, 1 unit in the 
Bezier path’s coordinates equals one point, but that’s a byproduct of the way 
the graphics system was designed — a mere convenience.

Putting those two ideas together leads to a better approach. Create the bezier 
path once, relative to an arbitrary bounding rect — say 1000 x 1000. (But any 
rect would do.) When you need to draw the path, set the CTM of the context to 
scale 1000 x 1000 (the reference bounds) to the context’s width x height (the 
view bounds). Then just draw the original path and AppKit will scale the bezier 
path for you.

This will work for all graphics in the view. Create all the elements relative 
to the same 1000 x 1000 bounds you used for the first bezier path, and 
everything will come out the correct size.

It’s a little more complicated for “bitmap” graphics, because they 
intrinsically contain pixels. That may, but does not necessarily, mean that the 
bitmaps have an absolute size. This is important when you want to avoid having 
your bitmaps scaled when they’re drawn to the screen. However, in your case, 
you’re allowing the view to get resized to any size, which means bitmap scaling 
is going to happen most of the time. In this case, you can set your NSImage 
sizes (which are an abstract quantity) relative to the same 1000 x 1000 bounds 
you used before. Then, drawing NSImages will automatically scale the underlying 
bitmaps (regardless of their actual pixel dimensions) to the correct size for 
the view.

The last point I want make is that if your goal is to scale *everything* in the 
view by the same amount, according to the size of the view, then you can use 
‘setBoundsSize:’ to set the bounds size relative to the view frame size, which 
effectively causes everything in the view to be scaled automatically. If your 
ultimate goal is this uniform, bounds scaling is the easiest way to get there.

The reference for all of this is the Cocoa Drawing Guide:


https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CocoaDrawingGuide/Introduction/Introduction.html
 
https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CocoaDrawingGuide/Introduction/Introduction.html

If you’re trying to gain expertise in custom drawing in custom views, you’re 
going to need to be familiar with pretty much everything in this document.

P.S. ‘drawRect:’ never really had any relevance to what you’re trying to do. 
Even the NSView doesn’t really matter, except for telling you what absolute 
size to scale your graphics to.

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: drawRect runs twice, bounds are changed in between

2015-01-13 Thread Jens Alfke

 On Jan 13, 2015, at 9:25 PM, N!K pu56ucl...@alumni.purdue.edu wrote:
 
 A breakpoint at the end of drawRect shows that it runs twice. After the 
 second pass, the view appears, as it should.
 Between passes, bounds is changed somehow, as shown by NSLog  at the start 
 and end of drawRect. 
 Since this will upset code that I will add later, I’d like to stop this. 

The view's being resized, probably as part of view layout. Ideally AppKit 
shouldn't draw the view before it gets to its final size, but maybe this is 
part of an animation, or maybe it's something that hasn't been optimized 100% 
in AppKit.

In general, you should not make assumptions about when and how often -drawRect: 
will be called. That's up to AppKit. Your job is just to draw the view when 
you're told to. 

You haven't said why the bounds change will upset your code; is the view being 
changed to the wrong size? That would be an actual problem, but it isn't 
related to being drawn multiple times. You'd need to look at the view 
constraints in your window to diagnose that.

—Jens
___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: drawRect runs twice, bounds are changed in between

2015-01-13 Thread Quincey Morris
On Jan 13, 2015, at 21:25 , N!K pu56ucl...@alumni.purdue.edu wrote:
 
 I have not been able to find  a reason for this behavior. . I don’t know how 
 to reveal the point between passes where bounds is actually changed. It does 
 not happen in any other NSView projects of mine; drawRect runs only once in 
 them

The immediate reason is probably that the view’s size changed, which is not 
unlikely when the window is in the process of being displayed. The view may be 
resized for a “local” reason, such as the application of auto layout 
constraints, or for a “global” reason, such as the containing being resized and 
the change filtering down to subviews.

Another possibility is that the view didn’t change size, but that (as an 
implementation detail of the Cocoa drawing system) it received two partial 
invalidations, and these weren’t coalesced in this case.

 I would like to prevent the second pass, or at least prevent the bounds 
 change between passes.

I don’t see any practical way to prevent ‘drawRect’ from being called again. 
Redundant ‘drawRect’ calls can occur any time during the view’s lifetime. 

Are you implying that one bounds rect is “right” and one is “wrong”? If so, how 
do you know that, and why can’t you just make your code do nothing if the 
bounds are “wrong”?

If the only criterion is that the *last* bounds rect is “right”, you’ve got a 
big problem, because there’s no such concept in the drawing system.

If you’re hoping that someone can suggest a solution, you probably need to be 
more specific about what “right” and “wrong” mean. 

 I’m reluctant to try restoring bounds to its first value. I appreciate Ken 
 Thomases’ warning in a previous subject not to change bounds in drawRect.


I’d say it wasn’t a warning, but rather an injunction to never, ever do that. 
Doing so is Wile E. Coyote stuff.



___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com