1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
|
#------------------------------------------------------------------------------
# Copyright (c) 2013-2025, Nucleic Development Team.
#
# Distributed under the terms of the Modified BSD License.
#
# The full license is in the file LICENSE, distributed with this software.
#------------------------------------------------------------------------------
from atom.api import Atom, Range
import kiwisolver as kiwi
from .strength_member import StrengthMember
class Spacer(Atom):
""" A base class for creating constraint spacers.
"""
#: The amount of space to apply for this spacer, in pixels.
size = Range(low=0)
#: The optional strength to apply to the spacer constraints.
strength = StrengthMember()
def __init__(self, size, strength=None):
""" Initialize a Spacer.
Parameters
----------
size : int
The basic size of the spacer, in pixels >= 0.
strength : strength-like, optional
A strength to apply to the generated spacer constraints.
"""
self.size = size
self.strength = strength
def __or__(self, strength):
""" Override the strength of the generated constraints.
Parameters
----------
strength : strength-like
The strength to apply to the generated constraints.
Returns
-------
result : self
The current spacer instance.
"""
self.strength = strength
return self
def when(self, switch):
""" A simple switch method to toggle a spacer.
Parameters
----------
switch : bool
Whether or not the spacer should be active.
Returns
-------
result : self or None
The current instance if the switch is True, None otherwise.
"""
return self if switch else None
def create_constraints(self, first, second):
""" Generate the spacer constraints for the given anchors.
Parameters
----------
first : LinearSymbolic
A linear symbolic representing the first constraint anchor.
second : LinearSymbolic
A linear symbolic representing the second constraint anchor.
Returns
-------
result : list
The list of constraints for the spacer.
"""
cns = self.constraints(first, second)
strength = self.strength
if strength is not None:
cns = [cn | strength for cn in cns]
return cns
def constraints(self, first, second):
""" Generate the spacer constraints for the given anchors.
This abstract method which must be implemented by subclasses.
Parameters
----------
first : LinearSymbolic
A linear symbolic representing the first constraint anchor.
second : LinearSymbolic
A linear symbolic representing the second constraint anchor.
Returns
-------
result : list
The list of constraints for the spacer.
"""
raise NotImplementedError
class EqSpacer(Spacer):
""" A spacer which represents a fixed amount of space.
"""
def constraints(self, first, second):
""" A constraint of the form: (second - first) == size
"""
return [(second - first) == self.size]
class LeSpacer(Spacer):
""" A spacer which represents a flexible space with a maximum value.
"""
def constraints(self, first, second):
""" A constraint of the form: (second - first) <= size
A second constraint is applied to prevent negative space:
(second - first) >= 0
"""
return [(second - first) <= self.size, (second - first) >= 0]
class GeSpacer(Spacer):
""" A spacer which represents a flexible space with a minimum value.
"""
def constraints(self, first, second):
""" A constraint of the form: (second - first) >= size
"""
return [(second - first) >= self.size]
class FlexSpacer(Spacer):
""" A spacer with a hard minimum and a preference for that minimum.
"""
#: The strength for the minimum space constraint.
min_strength = StrengthMember(kiwi.strength.required)
#: The strength for the equality space constraint.
eq_strength = StrengthMember(kiwi.strength.medium * 1.25)
def __init__(self, size, min_strength=None, eq_strength=None):
""" Initialize a FlexSpacer.
Parameters
----------
size : int
The basic size of the spacer, in pixels >= 0.
min_strength : strength-like, optional
The strength to apply to the minimum spacer size. The
default is kiwi.strength.required.
eq_strength : strength-like, optional
The strength to apply to preferred spacer size. The
default is 1.25 * kiwi.strength.medium.
"""
self.size = size
if min_strength is not None:
self.min_strength = min_strength
if eq_strength is not None:
self.eq_strength = eq_strength
def constraints(self, first, second):
""" Generate the constraints for the spacer.
"""
min_cn = ((second - first) >= self.size) | self.min_strength
eq_cn = ((second - first) == self.size) | self.eq_strength
return [min_cn, eq_cn]
class LayoutSpacer(Spacer):
""" A factory-like Spacer with convenient symbolic methods.
"""
def __call__(self, *args, **kwargs):
""" Create a new LayoutSpacer from the given arguments.
"""
return type(self)(*args, **kwargs)
def __or__(self, strength):
""" Create a new LayoutSpacer with the given strength.
"""
return type(self)(self.size, strength)
def __eq__(self, size):
""" Create an EqSpacer with the given size.
"""
return EqSpacer(size, self.strength)
def __le__(self, size):
""" Create an LeSpacer with the given size.
"""
return LeSpacer(size, self.strength)
def __ge__(self, size):
""" Create a GeSpacer withe the given size.
"""
return GeSpacer(size, self.strength)
def flex(self, **kwargs):
""" Create a FlexSpacer with the given configuration.
"""
return FlexSpacer(self.size, **kwargs)
def constraints(self, first, second):
""" Create the constraints for >= spacer constraint.
"""
return GeSpacer(self.size, self.strength).constraints(first, second)
|