1 // Written in the D programming language. 2 /++ 3 + Authors: KanzakiKino 4 + Copyright: KanzakiKino 2018 5 + License: LGPL-3.0 6 ++/ 7 module w4d.layout.base; 8 import w4d.layout.placer.base, 9 w4d.layout.exception, 10 w4d.style.widget; 11 import gl3n.linalg; 12 import std.algorithm; 13 14 enum LayoutState 15 { 16 None, 17 Dirty, 18 Clean, 19 } 20 21 /// A baseclass of Layout object. 22 /// Layout object decides children position to place 23 /// and calculates all styles. 24 abstract class Layout 25 { 26 protected Placer _placer; 27 28 /// Placer of the layout. 29 inout @property inout(Placer) placer () { return _placer; } 30 31 protected Layoutable _owner; 32 /// Owner of the layout. 33 inout @property owner () { return _owner; } 34 35 protected LayoutState _status; 36 37 protected vec2 _beforeBasePos; 38 protected vec2 _beforeParentSize; 39 40 protected @property children () 41 { 42 return _owner.childLayoutables; 43 } 44 protected @property style () 45 { 46 return _owner.style; 47 } 48 49 /// 50 this ( Placer placer, Layoutable owner ) 51 { 52 enforce( owner, "Owner is null." ); 53 _placer = placer; 54 _owner = owner; 55 56 _status = LayoutState.None; 57 _beforeBasePos = vec2(0,0); 58 _beforeParentSize = vec2(-1,-1); 59 } 60 61 /// Moves the owner and the children. 62 void shift ( vec2 size ) 63 { 64 if ( size == vec2(0,0) ) return; 65 66 _beforeBasePos += size; 67 style.shift( size ); 68 children.each!( x => x.shift( size ) ); 69 } 70 71 protected bool updateDirtyState () 72 { 73 auto dirty = false; 74 foreach ( child; children ) { 75 if ( child.layoutObject.updateDirtyState() ) { 76 dirty = true; 77 } 78 } 79 if ( !dirty ) { 80 dirty = _owner.checkNeedLayout( false ); 81 } 82 _status = dirty? LayoutState.Dirty: LayoutState.Clean; 83 return dirty; 84 } 85 86 /// Just moves the owner and the children to pos 87 /// if no need to layout completely. 88 /// Returns: Whether the owner is placed easily. 89 protected bool placeEasily ( vec2 basepos, vec2 parentSize ) 90 { 91 scope(exit) { 92 _status = LayoutState.None; 93 _beforeBasePos = basepos; 94 _beforeParentSize = parentSize; 95 } 96 if ( _status == LayoutState.None ) { 97 updateDirtyState(); 98 } 99 100 auto dirty = (_status != LayoutState.Clean); 101 if ( _beforeParentSize != parentSize || dirty ) { 102 return false; 103 } 104 105 shift( basepos - _beforeBasePos ); 106 return true; 107 } 108 109 /// Calculates styles and decodes position of children. 110 void place ( vec2, vec2 ); 111 } 112 113 /// An interface of layoutable objects. 114 interface Layoutable : PlacerOwner 115 { 116 /// Layout object. 117 inout @property inout(Layout) layoutObject (); 118 119 /// Child layoutables. 120 @property Layoutable[] childLayoutables (); 121 122 /// Wanted size. 123 @property vec2 wantedSize (); 124 125 /// Checks if need to layout completely. 126 /// Set the first argument true to check recursively. 127 bool checkNeedLayout ( bool ); 128 129 /// Moves the owner and the children. 130 void shift ( vec2 ); 131 }