1 module ws.gui.tree; 2 3 import 4 std.datetime, 5 std.math, 6 std.algorithm, 7 std.conv, 8 ws.animation, 9 ws.gl.draw, 10 ws.gui.base, 11 ws.gui.button; 12 13 14 class DynamicList: Base { 15 16 int padding = 5; 17 18 override Base add(Base elem){ 19 super.add(elem); 20 update; 21 return elem; 22 } 23 24 override void resize(int[2] size){ 25 int y = size.h-padding; 26 int h = padding; 27 foreach(c; children){ 28 if(c.hidden) 29 continue; 30 c.move(pos.a + [padding, y-c.size.h]); 31 c.resize([size.w-padding*2, c.size.h]); 32 y -= c.size.h + padding; 33 h += c.size.h + padding; 34 } 35 super.resize(size); 36 } 37 38 void update(){ 39 int h = padding; 40 foreach(i, c; children){ 41 if(c.hidden) 42 continue; 43 h += c.size.h + padding; 44 } 45 if(parent) 46 parent.resizeRequest(this, [size.w, h]); 47 } 48 49 override void resizeRequest(Base child, int[2] size){ 50 child.resize(size); 51 update; 52 } 53 54 } 55 56 double sinApproach(double a){ 57 return (sin((a-0.5)*PI)+1)/2; 58 } 59 60 class Tree: Base { 61 62 Button expander; 63 bool expanded = false; 64 int padding = 0; 65 int inset = 0; 66 int tail = 10; 67 68 Animation animation; 69 70 this(Button expander){ 71 this.expander = expander; 72 animation = new Animation(expander.size.h, expander.size.h, 0.3, &sinApproach); 73 expander.leftClick ~= &toggle; 74 size = [size.w, expander.size.h]; 75 add(expander); 76 } 77 78 override Base add(Base elem){ 79 super.add(elem); 80 update; 81 resize(size); 82 return elem; 83 } 84 85 Base add(Base elem, bool delegate(Base) here){ 86 foreach(i, c; children ~ null){ 87 if(here(c)){ 88 elem.parent = this; 89 elem.hidden = false; 90 children = children[0..i] ~ elem ~ children[i..$]; 91 break; 92 } 93 } 94 update; 95 resize(size); 96 return elem; 97 } 98 99 override void resize(int[2] size){ 100 int y = padding; 101 expander.move(pos.a+[0,size.h-expander.size.h]); 102 expander.resize([size.w, expander.size.h]); 103 foreach_reverse(i, c; children[1..$]){ 104 c.move(pos.a + [padding + inset, y+tail]); 105 c.resize([size.w-padding*2 - inset, c.size.h]); 106 y += c.size.h + padding; 107 } 108 super.resize(size); 109 } 110 111 void update(){ 112 int h = padding + (expanded ? tail : 0); 113 foreach(i, c; children[0..expanded ? $ : 1]) 114 h += c.size.h + padding; 115 if(parent && size.h != animation.calculate) 116 parent.resizeRequest(this, [size.w, animation.calculate.lround.to!int]); 117 if(h != animation.end) 118 animation.change(h); 119 } 120 121 override void resizeRequest(Base child, int[2] size){ 122 child.resize(size); 123 update; 124 animation.replace(animation.end); 125 } 126 127 override void remove(Base child){ 128 super.remove(child); 129 update; 130 } 131 132 void toggle(){ 133 expanded = !expanded; 134 update; 135 } 136 137 override void onDraw(){ 138 children[0].onDraw; 139 if(expanded || size.h != children[0].size.h){ 140 draw.clip(pos, [size.x, size.h-expander.size.h]); 141 super.onDraw; 142 draw.noclip; 143 } 144 update; 145 } 146 147 }