Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RubyMotion and Pointers

I'm an Objective-C noob, have searched high and low not finding the answer to this yet:

In my RubyMotion project I have a UIView subclass called StatusGuage, which contains a method called drawLinearGradient as follows:

def drawLinearGradient(context, rect, startColor, endColor)
  colorspace = CGColorSpaceCreateDeviceRGB()
  locations = [0.0, 1.0]
  # colors = NSArray.arrayWithObjects(startColor, endColor, nil)
  # ptrColors = Pointer.new(:object, colors)
  colors = [startColor, endColor, nil]
  # CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (CFArrayRef) colors, locations);
  CGGradientCreateWithColors(colorspace, colors, locations)
end

I'd like to know how to call CGGradientCreateWithColors. It clearly expects a (CFArrayRef) pointer but I cannot figure out how to pass that in. One of the iterations that I've tried is commented out.

Here is the error message:

2012-05-11 16:57:36.331 HughesNetMeter[34906:17903] 
*** Terminating app due to uncaught exception 'TypeError', 
  reason: 'status_guage.rb:43:in `drawLinearGradient:': expected 
  instance of Pointer, got `[0.0, 1.0]' (Array) (TypeError)
    from status_guage.rb:13:in `drawRect:'

Thanks for any help.

like image 245
Midwire Avatar asked May 11 '12 22:05

Midwire


1 Answers

A couple of things. The error is not talking about the colours, it is referring to the const CGFloat locations[] argument.

This should be a pointer which can be achieved like this (Reference on Pointer class)

locations = Pointer.new(:float, 2)
locations[1] = 1.0

Next up your array does not need the nil termination. In Ruby this would create an array with 3 objects, which is not what you want as it will most likely cause the CGGradientCreateWithColors() function to mess up


This looks like the example from http://www.raywenderlich.com/, so here's the rest from that

def drawLinearGradient(context, rect, startColor, endColor)
  colorspace = CGColorSpaceCreateDeviceRGB()
  locations = Pointer.new(:float, 2)
  locations[1] = 1.0

  colors = [startColor, endColor]
  gradient = CGGradientCreateWithColors(colorspace, colors, locations)

  startPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMinY(rect))
  endPoint   = CGPointMake(CGRectGetMidX(rect), CGRectGetMaxY(rect))

  CGContextSaveGState(context)
  CGContextAddRect(context, rect)
  CGContextClip(context)
  CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0)
  CGContextRestoreGState(context)
end

Final side note

The locations argument isn't even required in this case as CGGradientCreateWithColors() will automatically set the values to 0.0 and 1.0 for the first and last colour. Check the CGGradient Reference

locations
The location for each color provided in components. Each location must be a CGFloat value in the range of 0 to 1, inclusive. If 0 and 1 are not in the locations array, Quartz uses the colors provided that are closest to 0 and 1 for those locations.
If locations is NULL, the first color in colors is assigned to location 0, the last color incolors is assigned to location 1, and intervening colors are assigned locations that are at equal intervals in between.

like image 67
Paul.s Avatar answered Nov 08 '22 21:11

Paul.s