TextLayout.cpp
Go to the documentation of this file.
1 #include "Text.hpp"
2 
3 namespace iv
4 {
5 
6 //-------------------------- TextSegment -----------------------------------------------------
8  cm( elem->instance(), this, "TextSegment" ),
9  geometry_dirty( false ),
10  location( &this->cm ),
11  _elem( elem )
12 {
13 }
14 
16 {
17  return this->_elem->instance();
18 }
19 
21 {
22  return this->_elem;
23 }
24 
25 Elem const * TextSegment::elem() const
26 {
27  return this->_elem;
28 }
29 
30 //-------------------------- TextLayout -----------------------------------------------------
33  SlotChild( this ),
34  cm( inst, this, "TextLayout" ),
35  attr_lineSpacing( &this->cm, 0.0f ),
36  heap(),
37  geometry_dirty( false )
38 {
40 }
41 
43 {
44  this->attr_lineSpacing.Set( val );
45  return this;
46 }
47 
49 {
50  for( TextSegment * child : this->children )
51  {
52  child->elem()->first_pass( er );
53  this->geometry_dirty = this->geometry_dirty || child->geometry_dirty;
54  child->geometry_dirty = false;
55  }
56 
57  if( this->geometry_dirty || this->expectedSize.dirty() || this->attr_lineSpacing.dirty() )
58  {
59  //
60  er->Notify_FirstPass_Refresh( this );
61  this->expectedSize.clear_dirty();
63 
64  //
65  FontMesh::Location location;
66  location.size = float2( this->expectedSize.Get().x, std::numeric_limits< float >::infinity() );
67  location.line_spacing = this->attr_lineSpacing.Get();
68  location.skip_characters = 0;
69 
70  float width = 0.0f;
71 
72  for( TextSegment * child : this->children )
73  {
74  FontMesh::Geometry geometry = child->geometry_Compute( location );
75  location.line_state = geometry.line_state;
76 
77  width = std::max( width, geometry.max_width );
78 
79  if( !geometry.fits )
80  break;
81  }
82 
83  float height;
84  if( location.line_state.baseline_fixed )
85  height = location.line_state.basepoint.y - location.line_state.descender;
86  else
87  height = location.line_state.basepoint.y;
88 
89  this->preferredSize.Set( float3( width + 0.001, height + 0.001, 0.0f ) );
90  }
91 
92  if( this->geometry_dirty || this->children_dirty || this->size.dirty() || this->modelTransform.dirty() || this->scissor.dirty() )
93  er->QueueSecondPass( this );
94 }
95 
96 void TextLayout::RepositionChildren()
97 {
98  //
99  FontMesh::Location location;
100  location.size = float2( this->size.Get().x, this->size.Get().y );
101  location.line_spacing = this->attr_lineSpacing.Get();
102  location.skip_characters = 0;
103 
104  bool fits = true;
105 
106  //
107  for( TextSegment * child : this->children )
108  {
109  if( !fits )
110  {
111  child->location.Set( FontMesh::Location() );
112  }
113  else
114  {
115  // set location
116  child->location.Set( location );
117 
118  // move geometry
119  FontMesh::Geometry geometry = child->geometry_Compute( location );
120  location.line_state = geometry.line_state;
121  fits = fits || geometry.fits;
122  }
123  }
124 }
125 
127 {
128  //
129  bool refresh = false;
130  if( this->geometry_dirty || this->children_dirty || this->size.dirty() )
131  {
132  //
133  refresh = true;
134 
135  //
136  er->Notify_SecondPass_Refresh( this );
137 
138  //
139  this->geometry_dirty = false;
140  this->children_dirty = false;
141  this->size.clear_dirty();
142 
143  //
144  this->RepositionChildren();
145  }
146 
147  if( this->modelTransform.dirty() )
148  {
149  //
150  refresh = true;
151 
152  //
153  this->modelTransform.clear_dirty();
154  for( auto child : this->children )
155  child->elem()->modelTransform.Set( this->modelTransform.Get() );
156  }
157 
158  if( this->scissor.dirty() )
159  {
160  this->scissor.clear_dirty();
161  for( auto child : this->children )
162  child->elem()->scissor.Set( this->scissor.Get() );
163  }
164 
165  if( refresh )
166  {
167  for( auto it = this->children.rbegin(); it != this->children.rend(); ++it )
168  {
169  auto child = *it;
170  child->elem()->second_pass( er );
171  }
172  }
173 }
174 
175 }