LumaButton.cpp
Go to the documentation of this file.
1 #include "LumaButton.hpp"
2 
4 #include "Defs.hpp"
5 
6 namespace iv
7 {
8 
10  PickableSlot( inst ),
11  LumaListener( inst, style_id ),
12  TranslucentElem( this ),
13  cm( inst, this, "LumaButton" ),
14  attr_sufraceNeutralColor( &this->cm, std::nullopt ),
15  attr_overlayNeutralColor( &this->cm, std::nullopt ),
16  attr_resizeStage( &this->cm, FlatShader::ResizeStage::Frame ),
17  attr_surface( &this->cm, ResourcePath() ),
18  attr_overlay( &this->cm, ResourcePath() ),
19  attr_hot( &this->cm, ResourcePath() ),
20  surface_slot( inst ),
21  anim( inst ),
22  hot_last( false )
23 {
25  this->cm.owns( this->surface_slot.cm, this->anim.cm );
26 
27  //
29 
30  //-------- visuals --------------
31  auto surface_border = this->createChild< Border >();
32  surface_border->setChild( &this->surface_slot );
33 
34  this->img_surface = this->surface_slot.createChild< Image >();
35 
36  auto activation_transform = this->surface_slot.createChild< Transform >()
37  ->propagateSize( true );
38 
39  this->img_activation = activation_transform->createChild< Image >()
40  ->colorTransform( ColorTransform::Shift( float4( 1, 1, 1, 1 ) ) * ColorTransform::Zero() )
41  ->translucent( true );
42 
43  this->img_hot = this->surface_slot.createChild< Image >()
44  ->translucent( true );
45 
46  this->img_overlay = this->surface_slot.createChild< Image >();
47 
48  //
49  this->pickable_elem( this->img_surface );
50 
51  //------- animation -------------
52  // in
53  AnimNode< bool > * in_enabled = this->anim.Attribute_SourceNode( &this->input.attr_eventEnabled, false )
54  ->label( "in_enabled" );
55 
56  AnimNode< bool > * in_hover = this->anim.Attribute_SourceNode( &this->input.attr_hover, false )
57  ->label( "in_hover" );
58 
59  AnimNode< bool > * in_hot = this->anim.Attribute_SourceNode( &this->input.attr_hot, false )
60  ->label( "in_hot" );
61 
62  AnimNode< Activator > * in_activation = this->anim.Attribute_SourceNode( &this->input.attr_activation, Activator() )
63  ->label( "in_activation" );
64 
65  //
66  AnimNode< bool > * hot_cooldown = this->anim.Node< bool >( false )
67  ->label( "hot_cd" );
68 
69  // out
70  AnimNode< float3 > * out_activation_scale = this->anim.Attribute_DestinationNode( &activation_transform->attr_scale, float3( 1, 1, 1 ) )
71  ->label( "out_activation_scale" );
72 
73  AnimNode< float > * out_activation_alpha = this->anim.Attribute_DestinationNode( &this->img_activation->shading.alpha, 0.0f )
74  ->label( "out_activation_alpha" );
75 
76  //
77  this->anim.Make_Cooldown_Connector( in_hot, hot_cooldown )
78  ->cooldown_increasing( 0.0f )
79  ->cooldown_decreasing( 0.15f );
80 
81  // lambda connector
82  this->lambda = this->anim.Make_Lambda_Connector()
83  ->AddParent( in_enabled )
84  ->AddParent( in_hover )
85  ->AddParent( hot_cooldown )
86  ->AddParent( in_activation )
87  ->AddChild( out_activation_scale )
88  ->AddChild( out_activation_alpha );
89 
90  this->lambda->Retargeting(
91  [ = ]( bool warping )
92  {
93  LumaStyle const & style = this->style();
94 
95  //-------------- surface color (hover) --------------------------
96  float4 surface_color;
97  float4 text_color;
98  if( !in_enabled->Target() )
99  { // disabled
100  surface_color = style.surface;
101  text_color = style.on_surface;
102  }
103  else if( in_hover->Target() )
104  { // hover
106  text_color = style.on_highlight;
107  }
108  else
109  { // normal
110  surface_color = style.highlight;
111  text_color = style.on_highlight;
112  }
113 
114  // apply colors
115  if( this->attr_sufraceNeutralColor.Get().has_value() )
116  this->img_surface->colorTransform( ColorTransform::Change( this->attr_sufraceNeutralColor.Get().value(), surface_color ) );
117  if( this->attr_overlayNeutralColor.Get().has_value() )
118  this->img_overlay->colorTransform( ColorTransform::Change( this->attr_overlayNeutralColor.Get().value(), text_color ) );
119 
120  // apply colors of inheriting instance
121  this->ColorsChanged( surface_color, text_color );
122 
123  //-------- hot -------------
124  bool up = !in_enabled->Target() || !hot_cooldown->Target();
125  if( up )
126  {
127  // hot
128  this->img_hot->alpha( 0.0f );
129  }
130  else
131  {
132  // hot
133  this->img_hot->alpha( 1.0f );
134  }
135 
136  //-------------- activation animation ---------------------------------------
137  bool activation_connected = this->input.field_press.AssignmentState() != FieldI::Assignment::Unassigned
138  || this->input.field_release.AssignmentState() != FieldI::Assignment::Unassigned;
139 
140  bool hot_start = !this->hot_last && in_hot->Target();
141  this->hot_last = in_hot->Target();
142 
143  if( activation_connected && ( hot_start || ( in_activation->Target().CopyActivations( this->activator_ref ) && out_activation_alpha->Target() != Anim_float( 0.04f ) ) ) )
144  { // reset
145  out_activation_scale->Target( float3( 0, 0, 0 ) )
146  ->Speed_inf();
147  out_activation_alpha->Target( 0.04f )
148  ->Speed_inf();
149  }
150  else if( out_activation_scale->IsInTarget( float3( 0, 0, 0 ) ) )
151  { // scale up
152  out_activation_scale->Target( float3( 1, 1, 1 ) )
153  ->Speed( 4.0f );
154  }
155  else if( out_activation_scale->IsInTarget( float3( 1, 1, 1 ) ) && !in_hot->Target() )
156  { // fade out
157  out_activation_alpha->Target( 0.0f )
158  ->Speed( 0.3f );
159  }
160  }
161  );
162 }
163 
165 {
166  if( this->attr_translucent.clear_dirty() )
167  {
168  auto tr = this->attr_translucent.Get();
169  this->img_surface->translucent( tr );
170  this->img_overlay->translucent( tr );
171  }
172 
173  if( this->attr_preblend.clear_dirty() )
174  {
175  auto pr = this->attr_preblend.Get();
176  this->img_surface->preblend( pr );
177  this->img_overlay->preblend( pr );
178  }
179 
180  // neutralColor
182  {
183  this->lambda->Retarget();
184  }
185 
187  {
188  this->lambda->Retarget();
189  }
190 
191  // resizeStage
192  if( this->attr_resizeStage.clear_dirty() )
193  {
194  auto rs = this->attr_resizeStage.Get();
195 
196  this->img_surface->resizeStage( rs );
197  this->img_overlay->resizeStage( rs );
198  this->img_activation->resizeStage( rs );
199  this->img_hot->resizeStage( rs );
200  }
201 
202  // surface
203  if( this->attr_surface.clear_dirty() )
204  {
205  this->img_surface->filename( this->attr_surface.Get() );
206  this->img_activation->filename( this->attr_surface.Get() );
207  }
208 
209  // overlay
210  if( this->attr_overlay.clear_dirty() )
211  this->img_overlay->filename( this->attr_overlay.Get() );
212 
213  // hot
214  if( this->attr_hot.clear_dirty() )
215  this->img_hot->filename( this->attr_hot.Get() );
216 
217  //
218  this->PickableSlot::first_pass_impl( er );
219 }
220 
222 {
223  this->lambda->Retarget();
224 }
225 
227 {
228  this->lambda->Retarget();
229 }
230 
231 LumaButton * LumaButton::sufraceNeutralColor( std::optional< float4 > val )
232 {
233  this->attr_sufraceNeutralColor.Set( val );
234  return this;
235 }
236 
237 LumaButton * LumaButton::overlayNeutralColor( std::optional< float4 > val )
238 {
239  this->attr_overlayNeutralColor.Set( val );
240  return this;
241 }
242 
244 {
245  this->attr_resizeStage.Set( val );
246  return this;
247 }
248 
250 {
251  this->attr_surface.Set( val );
252  return this;
253 }
254 
256 {
257  this->attr_overlay.Set( val );
258  return this;
259 }
260 
262 {
263  this->attr_hot.Set( val );
264  return this;
265 }
266 
268 {
269  this->TranslucentElem::preblend( val );
270  return this;
271 }
272 
274 {
275  this->TranslucentElem::translucent( val );
276  return this;
277 }
278 
279 }