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 }