libui/osxaltest/box.swift

176 lines
5.1 KiB
Swift
Raw Normal View History

2015-08-07 21:01:19 -05:00
// 7 august 2015
import Cocoa
struct BoxControl {
var c: Control
var stretchy: Bool
var horzHuggingPri: NSLayoutPriority
var vertHuggingPri: NSLayoutPriority
2015-08-07 21:01:19 -05:00
}
class Box : NSView, Control {
private var controls: [BoxControl]
private var parent: Control?
2015-08-07 21:40:09 -05:00
private var vertical: Bool
2015-08-07 21:01:19 -05:00
private var padded: Bool
2015-08-07 21:40:09 -05:00
private var primaryDirPrefix: String
private var secondaryDirPrefix: String
private var primaryOrientation: NSLayoutConstraintOrientation
private var secondaryOrientation: NSLayoutConstraintOrientation
2015-08-07 21:40:09 -05:00
// we implement a lack of stretchy controls by adding a stretchy view at the end of the view list when we assemble layouts
// this is that view
private var noStretchyView: NSView
2015-08-07 21:40:09 -05:00
init(vertical: Bool, padded: Bool) {
2015-08-07 21:01:19 -05:00
self.controls = []
self.parent = nil
2015-08-07 21:40:09 -05:00
self.vertical = vertical
2015-08-07 21:01:19 -05:00
self.padded = padded
2015-08-07 21:40:09 -05:00
self.primaryDirPrefix = "H:"
self.secondaryDirPrefix = "V:"
self.primaryOrientation = NSLayoutConstraintOrientation.Horizontal
self.secondaryOrientation = NSLayoutConstraintOrientation.Vertical
2015-08-07 21:40:09 -05:00
if self.vertical {
self.primaryDirPrefix = "V:"
self.secondaryDirPrefix = "H:"
self.primaryOrientation = NSLayoutConstraintOrientation.Vertical
self.secondaryOrientation = NSLayoutConstraintOrientation.Horizontal
2015-08-07 21:40:09 -05:00
}
self.noStretchyView = NSView(frame: NSZeroRect)
self.noStretchyView.translatesAutoresizingMaskIntoConstraints = false
// make the view stretchy in both directions
// you can tell this is correct by synthesizing an Add() in your head; see below
setHorzHuggingPri(self.noStretchyView, myNSLayoutPriorityDefaultLow)
setVertHuggingPri(self.noStretchyView, myNSLayoutPriorityDefaultLow)
2015-08-07 21:01:19 -05:00
super.init(frame: NSZeroRect)
self.translatesAutoresizingMaskIntoConstraints = false
}
2015-08-07 21:40:09 -05:00
required init?(coder: NSCoder) {
fatalError("can't use this constructor, sorry")
}
2015-08-08 10:12:55 -05:00
func Add(control: Control, _ stretchy: Bool) {
var c: BoxControl
2015-08-07 21:01:19 -05:00
var view = control.View()
2015-08-08 10:12:55 -05:00
c = BoxControl(
c: control,
stretchy: stretchy,
horzHuggingPri: horzHuggingPri(view),
vertHuggingPri: vertHuggingPri(view))
self.addSubview(view)
2015-08-07 21:01:19 -05:00
self.controls.append(c)
2015-08-08 20:31:15 -05:00
// if a control is stretchy, it should not hug in the primary direction
// otherwise, it should *forcibly* hug
if c.stretchy {
setHuggingPri(view, myNSLayoutPriorityDefaultLow, self.primaryOrientation)
} else {
2015-08-08 21:06:57 -05:00
// TODO will default high work?
2015-08-08 20:31:15 -05:00
setHuggingPri(view, myNSLayoutPriorityRequired, self.primaryOrientation)
}
// make sure controls don't hug their secondary direction so they fill the width of the view
setHuggingPri(view, myNSLayoutPriorityDefaultLow, self.secondaryOrientation)
2015-08-08 20:31:15 -05:00
2015-08-07 21:40:09 -05:00
self.relayout()
2015-08-07 21:01:19 -05:00
}
func View() -> NSView {
return self
}
func SetParent(p: Control) {
self.parent = p
}
2015-08-07 21:40:09 -05:00
2015-08-11 19:23:12 -05:00
// TODO do we still need to set hugging? I think we do for stretchy controls...
// TODO try unsetting spinbox intrinsics and seeing what happens
2015-08-07 21:40:09 -05:00
private func relayout() {
2015-08-08 10:12:55 -05:00
var constraint: String
if self.controls.count == 0 {
2015-08-07 21:40:09 -05:00
return
}
self.removeConstraints(self.constraints)
// first collect the views
var views = [String: NSView]()
var n = 0
var firstStretchy = -1
var metrics = [String: CGFloat]()
2015-08-07 21:40:09 -05:00
for c in self.controls {
views["view\(n)"] = c.c.View()
var s = fittingAlignmentSize(c.c.View())
metrics["view\(n)width"] = s.width
metrics["view\(n)height"] = s.height
if firstStretchy == -1 && c.stretchy {
firstStretchy = n
}
2015-08-08 10:12:55 -05:00
n++
2015-08-07 21:40:09 -05:00
}
// if there are no stretchy controls, we must add the no-stretchy view
// if there are, we must remove it
if firstStretchy == -1 {
if self.noStretchyView.superview == nil {
self.addSubview(self.noStretchyView)
}
views["noStretchyView"] = self.noStretchyView
} else {
if self.noStretchyView.superview != nil {
self.noStretchyView.removeFromSuperview()
}
}
2015-08-07 21:40:09 -05:00
// next, assemble the views in the primary direction
// they all go in a straight line
2015-08-08 10:12:55 -05:00
constraint = "\(self.primaryDirPrefix)|"
for i in 0..<n {
if self.padded && i != 0 {
constraint += "-"
}
constraint += "[view\(i)"
// implement multiple stretchiness properly
if self.controls[i].stretchy && i != firstStretchy {
constraint += "(==view\(firstStretchy))"
}
// if the control is not stretchy, restrict it to the fitting size
if !self.controls[i].stretchy {
if self.vertical {
constraint += "(==view\(i)height)"
} else {
constraint += "(==view\(i)width)"
}
}
constraint += "]"
2015-08-08 10:12:55 -05:00
}
if firstStretchy == -1 { // don't space between the last control and the no-stretchy view
constraint += "[noStretchyView]"
}
2015-08-08 10:12:55 -05:00
constraint += "|"
var constraints = mkconstraints(constraint, metrics, views)
2015-08-08 10:12:55 -05:00
self.addConstraints(constraints)
2015-08-07 21:40:09 -05:00
// next: assemble the views in the secondary direction
// each of them will span the secondary direction
2015-08-08 10:12:55 -05:00
for i in 0..<n {
constraint = "\(self.secondaryDirPrefix)|[view\(i)]|"
var constraints = mkconstraints(constraint, nil, views)
2015-08-08 10:12:55 -05:00
self.addConstraints(constraints)
}
if firstStretchy == -1 { // and again to the no-stretchy view
constraint = "\(self.secondaryDirPrefix)|[noStretchyView]|"
var constraints = mkconstraints(constraint, nil, views)
self.addConstraints(constraints)
}
2015-08-07 21:40:09 -05:00
}
2015-08-07 21:01:19 -05:00
}