160 lines
3.9 KiB
Swift
160 lines
3.9 KiB
Swift
// 31 july 2015
|
|
import Cocoa
|
|
|
|
// leave a whole lot of space around the alignment rect, just to be safe
|
|
// TODO fine tune this
|
|
// TODO de-duplicate this from spinbox.m
|
|
class tBoxContainer : NSView {
|
|
override func alignmentRectInsets() -> NSEdgeInsets {
|
|
return NSEdgeInsetsMake(50, 50, 50, 50)
|
|
}
|
|
}
|
|
|
|
struct tBoxChild {
|
|
var c: tControl
|
|
var stretchy: Bool
|
|
}
|
|
|
|
class tBox : tControl {
|
|
private var v: NSView
|
|
private var children: [tBoxChild]
|
|
private var vertical: Bool
|
|
private var parent: tControl
|
|
private var spaced: Bool
|
|
|
|
// TODO rename to padded
|
|
init(vertical: Bool, spaced: Bool) {
|
|
self.v = tBoxContainer(frame: NSZeroRect)
|
|
self.v.translatesAutoresizingMaskIntoConstraints = false
|
|
self.children = []
|
|
self.vertical = vertical
|
|
self.parent = nil
|
|
self.spaced = spaced
|
|
}
|
|
|
|
func tAddControl(c: tControl, stretchy: Bool) {
|
|
c.tSetParent(self, addToView: self.v)
|
|
self.children.append(tBoxChild(
|
|
c: c,
|
|
stretchy: stretchy))
|
|
self.tRelayout()
|
|
}
|
|
|
|
func tSetParent(p: tControl, addToView v: NSView) {
|
|
self.parent = p
|
|
v.addSubview(self.v)
|
|
}
|
|
|
|
// TODO make the other dimension not hug (as an experiment)
|
|
func tFillAutoLayout(p: tAutoLayoutParams) {
|
|
var orientation: NSLayoutConstraintOrientation
|
|
var i, n: UIntMax
|
|
var pp: tAutoLayoutParams
|
|
var nStretchy: UIntMax
|
|
|
|
if self.children.count == 0 {
|
|
goto selfOnly
|
|
}
|
|
|
|
self.v.removeConstraints(self.v.constraints)
|
|
|
|
orientation = NSLayoutConstraintOrientation.Horizontal
|
|
if self.vertical {
|
|
orientation = NSLayoutConstraintOrientation.Vertical
|
|
}
|
|
|
|
var views = [String: NSView]()
|
|
n = 0
|
|
var predicates = [String]()
|
|
for child in self.children {
|
|
var priority: NSLayoutPriority
|
|
|
|
pp.nonStretchyWidthPredicate = ""
|
|
pp.nonStretchyHeightPredicate = ""
|
|
// this also resets the hugging priority
|
|
// TODO do this when adding and removing controls instead
|
|
child.c.tFillAutoLayout(pp)
|
|
priority = NSLayoutPriorityDefaultHigh // forcibly hug; avoid stretching out
|
|
if child.stretchy {
|
|
priority = NSLayoutPriorityDefaultLow // do not forcibly hug; freely stretch out
|
|
}
|
|
if self.vertical {
|
|
predicates.append(pp.nonStretchyHeightPredicate)
|
|
} else {
|
|
predicates.append(pp.nonStretchyWidthPredicate)
|
|
}
|
|
pp.view.setContentHuggingPriority(priority, forOrientation:orientation)
|
|
views[tAutoLayoutKey(n)] = pp.view
|
|
n++
|
|
}
|
|
|
|
// first string the views together
|
|
var constraint = "H:"
|
|
if self.vertical {
|
|
constraint = "V:"
|
|
}
|
|
var firstStretchy = true
|
|
for i = 0; i < n; i++ {
|
|
if self.spaced && i != 0 {
|
|
constraint += "-"
|
|
}
|
|
constraint += "[" + tAutoLayoutKey(i)
|
|
if self.children[i].stretchy {
|
|
if firstStretchy {
|
|
firstStretchy = false
|
|
nStretchy = i
|
|
} else {
|
|
constraint += "(==" + tAutoLayoutKey(nStretchy) + ")"
|
|
}
|
|
} else {
|
|
constraint += predicates[i]
|
|
}
|
|
constraint += "]"
|
|
}
|
|
constraint += "|"
|
|
self.v.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat(
|
|
visualFormat: constraint,
|
|
options: 0,
|
|
metrics: nil,
|
|
views: views))
|
|
// TODO do not release constraint; it's autoreleased?
|
|
|
|
// next make the views span the full other dimension
|
|
// TODO make all of these the same width/height
|
|
for i = 0; i < n; i++ {
|
|
constraint = "V:|["
|
|
if self.vertical {
|
|
constraint = "H:|["
|
|
}
|
|
constraint += tAutoLayoutKey(i) + "]|"
|
|
self.v.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat(
|
|
visualFormat: constraint,
|
|
options: 0,
|
|
metrics: nil,
|
|
views: views))
|
|
// TODO do not release constraint; it's autoreleased?
|
|
}
|
|
|
|
// and now populate for self
|
|
selfOnly:
|
|
p.view = self.v
|
|
p.attachLeft = true
|
|
p.attachTop = true
|
|
// don't attach to the end if there weren't any stretchy controls
|
|
// firstStretchy is false if there was at least one stretchy control
|
|
if self.vertical {
|
|
p.attachRight = true
|
|
p.attachBottom = !firstStretchy
|
|
} else {
|
|
p.attachRight = !firstStretchy
|
|
p.attachBottom = true
|
|
}
|
|
}
|
|
|
|
func tRelayout() {
|
|
if self.parent != nil {
|
|
self.parent.tRelayout()
|
|
}
|
|
}
|
|
}
|