News aggregator

Bill Atkins: Simple Combinators for Manipulating CGPoint/CGSize/CGRect with Swift

Planet Haskell - Sat, 12/27/2014 - 8:42am
One of the most painful things about Objective-C was having to modify CGPoint, CGSize or CGRect values. The clunky struct interface made even simple modifications verbose and ugly, since struct expressions were read-only:

    CGRect imageBounds = self.view.bounds;    imageBounds.size.height -= self.footer.bounds.size.height;
    self.imageView.bounds = imageBounds;
Even though we have auto-layout, I often find myself doing this kind of arithmetic with points, size or rects. In Objective-C, it required either generating dummy variables so you can modify members (as above), or really messy struct initialization syntax:
    self.imageView.bounds = (CGRect) {         .origin = self.view.bounds.origin,        .size = CGSizeMake(self.view.bounds.size.width, self.view.bounds.size.height -                               self.footer.bounds.size.height) };
Fortunately, none of this boilerplate is necessary with Swift. Since Swift lets you extend even C structures with new methods, I wrote a handful of combinators that eliminate this kind of code. The above snippet can now be replaced with:
    self.imageView.bounds = self.view.bounds.mapHeight { $0 - self.footer.size.height }
I can easily enlarge a scroll view's content size to hold its pages:

    self.scrollView.contentSize = self.scrollView.bounds.size.mapWidth { $0 * CGFloat(pages.count) }
I can do calculations that previously would've required dozens of lines of code in just one or two:
    let topHalfFrame = self.view.bounds.mapHeight { $0 / 2 }    let bottomHalfFrame = topHalfFrame.mapY { $0 + topHalfFrame.size.height }
These two lines will give me two frames that each take up half of the height of their parent view.
In cases where I simply need to set a value, I use the primitive "with..." functions:
Note that these methods can all be chained to create complex expressions.
The code for these methods is trivial, yet they give you a huge boost in expressive power.

GitHub project
Codeextension CGPoint {    func mapX(f: (CGFloat -> CGFloat)) -> CGPoint {        return self.withX(f(self.x))    }        func mapY(f: (CGFloat -> CGFloat)) -> CGPoint {        return self.withY(f(self.y))    }        func withX(x: CGFloat) -> CGPoint {        return CGPoint(x: x, y: self.y)    }        func withY(y: CGFloat) -> CGPoint {        return CGPoint(x: self.x, y: y)    }}
extension CGSize {    func mapWidth(f: (CGFloat -> CGFloat)) -> CGSize {        return self.withWidth(f(self.width))    }        func mapHeight(f: (CGFloat -> CGFloat)) -> CGSize {        return self.withHeight(f(self.height))    }        func withWidth(width: CGFloat) -> CGSize {        return CGSize(width: width, height: self.height)    }        func withHeight(height: CGFloat) -> CGSize {        return CGSize(width: self.width, height: height)    }}
extension CGRect {    func mapX(f: (CGFloat -> CGFloat)) -> CGRect {        return self.withX(f(self.origin.x))    }        func mapY(f: (CGFloat -> CGFloat)) -> CGRect {        return self.withY(f(self.origin.y))    }        func mapWidth(f: (CGFloat -> CGFloat)) -> CGRect {        return self.withWidth(f(self.size.width))    }        func mapHeight(f: (CGFloat -> CGFloat)) -> CGRect {        return self.withHeight(f(self.size.height))    }        func withX(x: CGFloat) -> CGRect {        return CGRect(origin: self.origin.withX(x), size: self.size)    }        func withY(y: CGFloat) -> CGRect {        return CGRect(origin: self.origin.withY(y), size: self.size)    }        func withWidth(width: CGFloat) -> CGRect {        return CGRect(origin: self.origin, size: self.size.withWidth(width))    }        func withHeight(height: CGFloat) -> CGRect {        return CGRect(origin: self.origin, size: self.size.withHeight(height))    }}
Categories: Offsite Blogs

Shell Monad - Day 3

Haskell on Reddit - Sat, 12/27/2014 - 12:53am
Categories: Incoming News

New gtk2hs 0.12.4 release

gtk2hs - Wed, 11/21/2012 - 12:56pm

Thanks to John Lato and Duncan Coutts for the latest bugfix release! The latest packages should be buildable on GHC 7.6, and the cairo package should behave a bit nicer in ghci on Windows. Thanks to all!


Categories: Incoming News