Divider.cpp
Go to the documentation of this file.
1 #include "Divider.hpp"
2 #include "../Defs.hpp"
3 
4 namespace iv
5 {
6 
7 //----------------------------------- DividerSlot ----------------------------------
9  Slot( inst ),
10  cm( inst, this, "DividerSlot", ClientMarker::Status() ),
11  attr_lowerOrder( &this->cm, 0 ),
12  attr_higherOrder( &this->cm, unsigned( -1 ) )
13 {
14  this->cm.inherits( this->Slot::cm );
15 }
16 
18 {
19  static iv::TableId DebugTable = TableId::create( "DividerSlot" );
20 
21  auto row = view->Table( DebugTable ).Row( this );
22 
23  row.Column( "lowerOrder", this->attr_lowerOrder.Get() );
24  row.Column( "higherOrder", this->attr_higherOrder.Get() );
25 }
26 
28 {
29  this->attr_lowerOrder.Set( val );
30  return this;
31 }
32 
34 {
35  this->attr_higherOrder.Set( val );
36  return this;
37 }
38 
39 //----------------------------------- Divider ----------------------------------
42  SlotChild( this ),
43  cm( inst, this, "Divider", ClientMarker::Status() ),
44  attr_axis( &this->cm, Axis::X ),
45  attr_axisOrder( &this->cm, AxisOrder::Incremental ),
46  offsets_dirty( true )
47 {
49 }
50 
52 {
53  this->attr_axis.Set( val );
54  return this;
55 }
56 
58 {
59  this->attr_axisOrder.Set( val );
60  return this;
61 }
62 
64 {
65  static iv::TableId DebugTable = TableId::create( "Divider" );
66 
67  auto row = view->Table( DebugTable ).Row( this );
68 
69  row.Column( "axis", this->attr_axis.Get() );
70  row.Column( "axisOrder", this->attr_axisOrder.Get() );
71  row.Column( "children", this->children.size() );
72 }
73 
75 {
76  this->cm.log( SRC_INFO, Defs::Log::ElementFirstPass, "First pass." );
77 
78  //--------- call first pass on children ---------------------------------------
79  const bool expectedSize_changed = this->expectedSize.clear_dirty();
80 
81  bool prefsize_changed = this->children_dirty;
82  bool phases_changed = this->children_dirty;
83 
84  this->children_dirty = false;
85 
86  for( DividerSlot * child : this->children )
87  {
88  // expected size to child
89  if( expectedSize_changed )
90  child->expectedSize.Set( this->expectedSize.Get() );
91 
92  // first pass
93  child->first_pass( er );
94 
95  // preferred size change detect
96  prefsize_changed = prefsize_changed + child->preferredSize.clear_dirty();
97  phases_changed = phases_changed + child->attr_lowerOrder.clear_dirty() + child->attr_higherOrder.clear_dirty();
98  }
99 
100  //--------------- refresh preferred size ------------------------------
101  if( this->attr_axis.clear_dirty() )
102  prefsize_changed = true;
103 
104  if( prefsize_changed )
105  {
106  er->Notify_FirstPass_Refresh( this );
107 
108  float3 prefsize_new( 0 );
109  for( SlotChild * child : this->children )
110  {
111  float3 child_prefsize = child->preferredSize.Get();
112  foreach_axis(
113  [&]( Axis axis )
114  {
115  if( axis == this->attr_axis.Get() )
116  float3_Axis( prefsize_new, axis ) += float3_Axis( child_prefsize, axis );
117  else
118  float3_Axis( prefsize_new, axis ) = std::max( float3_Axis( prefsize_new, axis ), float3_Axis( child_prefsize, axis ) );
119  }
120  );
121  }
122 
123  //
124  this->cm.log( SRC_INFO, Defs::Log::ElementFirstPass_Refresh, "Refreshed preferred_size: ", this->children.size(), " children with total prefsize ", prefsize_new , "." );
125  this->preferredSize.Set( prefsize_new );
126  }
127 
128  //-------------------- refresh phases cache -----------------------------
129  if( phases_changed )
130  {
131  er->Notify_FirstPass_Refresh( this );
132 
133  this->phases.clear();
134 
135  for( size_t i = 0; i < this->children.size(); i++ )
136  {
137  DividerSlot * child = this->children[ i ];
138 
139  bool first = true;
140 
141  if( child->attr_lowerOrder.Get() < child->attr_higherOrder.Get() )
142  {
143  // lower part
144  Phase phase;
145  phase.segment = i;
146  phase.higher = false;
147  phase.first = first;
148  phase.weight = 0;
149  phase.size = 0;
150  this->phases.insert( std::pair( child->attr_lowerOrder.Get(), phase ) );
151 
152  first = false;
153  }
154 
155  // higher part
156  Phase phase;
157  phase.segment = i;
158  phase.higher = true;
159  phase.first = first;
160  phase.weight = 0;
161  phase.size = 0;
162  this->phases.insert( std::pair( child->attr_higherOrder.Get(), phase ) );
163  }
164 
165  this->cm.log( SRC_INFO, Defs::Log::ElementFirstPass_Refresh, "Regenerated phase cache: ", this->children.size(), " children -> ", this->phases.size() , " phases." );
166  }
167 
168  //---------------- recompute sizes and weights -----------------------
169  if( phases_changed || prefsize_changed )
170  {
171  //
172  this->offsets_dirty = true;
173 
174  // cycle over each equal range of phases with same order
175  Axis axis = this->attr_axis.Get();
176  bool last = false;
177  auto it = this->phases.begin();
178  size_t groups = 0;
179  while( it != this->phases.end() && !last )
180  {
181  groups += 1;
182 
183  // get equal range
184  auto it_first = it;
185  size_t range_size = 0;
186  float full_size = 0.0f;
187  while( it != this->phases.end() && it->first == it_first->first )
188  {
189  // read prefsize and process it
190  size_t segment = it->second.segment;
191  DividerSlot * child = this->children[ segment ];
192  float own_size;
193  if( !it->second.higher )
194  own_size = float3_Axis( child->preferredSize.Get(), axis );
195  else
196  own_size = std::numeric_limits< float >::infinity();
197 
198  it->second.size = own_size;
199  full_size += own_size;
200 
201  // next
202  ++it;
203  range_size++;
204  }
205 
206  // fill in weights
207  last = full_size == std::numeric_limits< float >::infinity();
208  auto it_again = it_first;
209  while( it_again != it )
210  {
211  // compute weight
212  if( !last && full_size > 0.0f )
213  {
214  it_again->second.weight = it_again->second.size / full_size;
215  full_size -= it_again->second.size;
216  }
217  else
218  {
219  it_again->second.weight = 1.0f / float( range_size );
220  }
221 
222  // next
223  ++it_again;
224  }
225  }
226 
227  this->cm.log( SRC_INFO, Defs::Log::ElementFirstPass_Refresh, "Refreshed weights and sizes: ", groups, " groups." );
228  }
229 
230  //-------------- call second pass -------------------------------
231  if( this->size.dirty() || this->modelTransform.dirty() || this->scissor.dirty() || this->offsets_dirty || this->attr_axisOrder.dirty() )
232  {
233  this->cm.log( SRC_INFO, Defs::Log::ElementFirstPass_Refresh, "Queue second pass." );
234  er->QueueSecondPass( this );
235  }
236 }
237 
239 {
240  this->cm.log( SRC_INFO, Defs::Log::ElementSecondPass, "Second pass." );
241 
242  bool refresh = false;
243 
244  // inner geometry
245  if( this->offsets_dirty || this->size.dirty() )
246  {
247  this->size.clear_dirty();
248  this->offsets_dirty = false;
249 
250  // notify about refresh
251  refresh = true;
252  this->cm.log( SRC_INFO, Defs::Log::ElementFirstPass_Refresh, "Refresh inner geometry." );
253  er->Notify_SecondPass_Refresh( this );
254 
255  // setup sizes
256  float3 full_size = this->size.Get();
257  Axis axis = this->attr_axis.Get();
258  float remaining = float3_Axis( full_size, axis );
259  for( auto const & [ order, phase ] : this->phases )
260  {
261  DividerSlot * child = this->children[ phase.segment ];
262 
263  // compute size for the item
264  float available = phase.weight * remaining;
265  float granted = std::min( available, phase.size );
266 
267  // modify variables
268  float3 size = full_size;
269  if( phase.first )
270  float3_Axis( size, axis ) = 0;
271  else
272  float3_Axis( size, axis ) = float3_Axis( child->size.Get(), axis );
273 
274  float3_Axis( size, axis ) += granted;
275 
276  // modify things
277  child->size.Set( size );
278  remaining -= granted;
279  }
280  }
281 
282  // outer geometry
283  if( refresh || this->modelTransform.dirty() || this->attr_axisOrder.dirty() )
284  {
285  // notify about refresh
286  refresh = true;
287  this->cm.log( SRC_INFO, Defs::Log::ElementFirstPass_Refresh, "Refresh outer geometry." );
288 
289  // clear flags
290  this->modelTransform.clear_dirty();
291  this->attr_axisOrder.clear_dirty();
292 
293  // copy to children
294  if( this->attr_axisOrder.Get() == AxisOrder::Incremental )
295  {
296  float offset = 0;
297  for( DividerSlot * child : this->children )
298  {
299  float3 translate( 0 );
300  float3_Axis( translate, this->attr_axis.Get() ) = offset;
301  offset += float3_Axis( child->size.Get(), this->attr_axis.Get() );
302  child->modelTransform.Set( this->modelTransform.Get() * glm::translate( float4x4( 1 ), translate ) );
303  }
304  }
305  else
306  {
307  float offset = 0;
308  for( auto it = this->children.rbegin(); it != this->children.rend(); ++it )
309  {
310  DividerSlot * child = *it;
311  float3 translate( 0 );
312  float3_Axis( translate, this->attr_axis.Get() ) = offset;
313  offset += float3_Axis( child->size.Get(), this->attr_axis.Get() );
314  child->modelTransform.Set( this->modelTransform.Get() * glm::translate( float4x4( 1 ), translate ) );
315  }
316  }
317  }
318 
319  if( this->scissor.dirty() )
320  {
321  refresh = true;
322  this->scissor.clear_dirty();
323 
324  this->cm.log( SRC_INFO, Defs::Log::ElementFirstPass_Refresh, "Refresh scissor." );
325 
326  for( DividerSlot * child : this->children )
327  child->scissor.Set( this->scissor.Get() );
328  }
329 
330  // call second pass on children
331  if( refresh )
332  for( auto it = this->children.rbegin(); it != this->children.rend(); ++it )
333  {
334  auto child = *it;
335  child->second_pass( er );
336  }
337 }
338 
339 }