Class: Tuile::ComponentBackground
- Inherits:
-
Object
- Object
- Tuile::ComponentBackground
- Defined in:
- lib/tuile/component_background.rb,
sig/tuile.rbs
Overview
One component's background: what it states, and the Color that resolves to right now. A component reaches its own through the protected Tuile::Component#bg; an app tints through Tuile::Component#bg_color=.
# a widget: its own well, brighter while focused
def initialize
super
bg.default_color = ComponentBackground::INPUT_WELL
end
panel.bg_color = Theme.ref(:panel_bg) # an app: tint a whole subtree
The chain, first answer wins: the owner's Tuile::Component#error_bg_color, then
#color (the app's), then #default_color (the widget's), then the parent's
#effective, then nil — the terminal default. INHERIT at a level skips
the owner's remaining levels and goes straight to the parent. Every level
takes a Color, a Theme::Ref or a Hash keyed by STATES, and resolves
against the live theme and the owner's Tuile::Component#active? at paint time,
so nothing here caches a color.
Implementation details
The error level is pulled from the owner rather than stored here: it follows the validation state, and a pushed copy would need every edge of that state to remember to re-set it. A stale error well fails silently.
Constant Summary collapse
- STATES =
The states a background may be keyed by. Closed and framework-defined: a key is added when Tuile grows the state, never to let an app invent one.
%i[normal active].freeze
- INHERIT =
Assign to #color to say "I contribute no background of my own" — resolution skips the owner's #default_color and takes whatever surrounds it. CSS's
background: inherit, and the reason a widget with a well can be made to sit flush in a tinted panel:field.bg_color = ComponentBackground::INHERIT # no well; take the pane's tintDistinct from
nil, which falls through to #default_color first. There is deliberately no counterpart forcing the terminal default despite a tinted ancestor (D_bg_inherit). :inherit- INPUT_WELL =
The well every input field paints: Theme#input_bg_color at rest, Theme#active_bg_color while on the focus chain. Live Theme::Refs, so a Screen#theme= restyles it with no hook.
{ normal: Theme.ref(:input_bg_color), active: Theme.ref(:active_bg_color) }.freeze
Instance Attribute Summary collapse
-
#color ⇒ Color, ...
@return — the app's background — the value as set, so a Theme::Ref comes back unresolved and a state map comes back a Hash;
nilwhen unset. -
#default_color ⇒ Color, ...
@return — the widget's own surface —
nilby default, meaning "whatever is behind me shows through".
Instance Method Summary collapse
-
#ambient ⇒ Color?
What surrounds the owner — the app's #color, else whatever the parent paints.
-
#coerce(value) ⇒ Color, ...
Validates and normalizes a level's value, so a bad token or a misspelled state raises at the assignment rather than deep in a repaint.
-
#effective ⇒ Color?
@return — the background actually painted, for the state the owner is in right now — the whole chain, resolved.
-
#initialize(owner) ⇒ ComponentBackground
constructor
@param
owner— whose background this is. - #invalidate ⇒ void
- #parent_effective ⇒ Color?
-
#resolve(value) ⇒ Color, ...
Collapses one level to the Color it means right now.
Constructor Details
#initialize(owner) ⇒ ComponentBackground
@param owner — whose background this is.
55 56 57 58 59 |
# File 'lib/tuile/component_background.rb', line 55 def initialize(owner) @owner = owner @color = nil @default_color = nil end |
Instance Attribute Details
#color ⇒ Color, ...
@return — the app's background — the value as set, so a Theme::Ref comes back
unresolved and a state map comes back a Hash; nil when unset.
64 65 66 |
# File 'lib/tuile/component_background.rb', line 64 def color @color end |
#default_color ⇒ Color, ...
@return — the
widget's own surface — nil by default, meaning "whatever is behind me
shows through".
83 84 85 |
# File 'lib/tuile/component_background.rb', line 83 def default_color @default_color end |
Instance Method Details
#ambient ⇒ Color?
What surrounds the owner — the app's #color, else whatever the parent paints. Skips #default_color and the error well, the owner's own surface, which is what makes it the right answer for a dead tail outside Tuile::Component#extent and a container's gaps.
124 125 126 127 128 129 |
# File 'lib/tuile/component_background.rb', line 124 def ambient own = resolve(@color) return parent_effective if own.nil? || own == INHERIT own end |
#coerce(value) ⇒ Color, ...
Validates and normalizes a level's value, so a bad token or a misspelled state raises at the assignment rather than deep in a repaint. A chrome token needs no theme to check, which keeps construction screen-free.
@param value
162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
# File 'lib/tuile/component_background.rb', line 162 def coerce(value) case value when nil, Color, INHERIT then value when Theme::Ref value.tap { _1.resolve(@owner.screen.theme) unless Theme.chrome_token?(_1.name) } when Hash unknown = value.keys - STATES raise ArgumentError, "unknown background state(s) #{unknown.join(", ")}; known: #{STATES.join(", ")}" \ unless unknown.empty? value.to_h { |state, color| [state, coerce(color)] }.freeze else Color.coerce(value) end end |
#effective ⇒ Color?
@return — the background actually painted, for the state the owner is in right now — the whole chain, resolved. Screen#canvas_for loads it onto the canvas; an app never needs it.
112 113 114 115 116 117 |
# File 'lib/tuile/component_background.rb', line 112 def effective own = resolve(@owner.__send__(:error_bg_color)) || resolve(@color) || resolve(@default_color) return parent_effective if own.nil? || own == INHERIT own end |
#invalidate ⇒ void
This method returns an undefined value.
137 138 139 |
# File 'lib/tuile/component_background.rb', line 137 def invalidate @owner.walk_tree { |c| @owner.screen.invalidate(c) } if @owner.attached? end |
#parent_effective ⇒ Color?
134 |
# File 'lib/tuile/component_background.rb', line 134 def parent_effective = @owner.parent&.__send__(:bg)&.effective |
#resolve(value) ⇒ Color, ...
Collapses one level to the Tuile::Color it means right now. An absent state
key yields nil, so resolution falls through to the next level — which
is what lets bg_color = { active: … } keep the widget's own normal well.
@param value
146 147 148 149 150 151 152 153 |
# File 'lib/tuile/component_background.rb', line 146 def resolve(value) case value when nil then nil when Hash then resolve(value[@owner.active? ? :active : :normal]) when Theme::Ref then value.resolve(@owner.screen.theme) else value end end |