1 /*
2 * grouptree.c - group trees
3 * Copyright (C) 2010 Alexandre Martins <alemartf(at)gmail(dot)com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "grouptree.h"
21 #include "../../core/util.h"
22 #include "../../core/video.h"
23
24
25 /* tree manipulation */
26
27
28
29
30
31 /*
32 * grouptree_destroy_all()
33 * destroys the whole tree.
34 * ps: release_all() must be called first
35 */
grouptree_destroy_all(group_t * root)36 void grouptree_destroy_all(group_t *root)
37 {
38 int i;
39
40 if(root) {
41 for(i=0; i<root->child_count; i++)
42 grouptree_destroy_all(root->child[i]);
43 free(root);
44 }
45 }
46
47
48 /*
49 * grouptree_init_all()
50 * initializes root's and root's children internal data (without creating them)
51 */
grouptree_init_all(group_t * root)52 void grouptree_init_all(group_t *root)
53 {
54 int i;
55
56 if(root) {
57 root->init(root);
58 for(i=0; i<root->child_count; i++)
59 grouptree_init_all(root->child[i]);
60 }
61 }
62
63 /*
64 * grouptree_release_all()
65 * releases root's and root's children internal data (without destroying them)
66 */
grouptree_release_all(group_t * root)67 void grouptree_release_all(group_t *root)
68 {
69 int i;
70
71 if(root) {
72 for(i=0; i<root->child_count; i++)
73 grouptree_release_all(root->child[i]);
74 root->release(root);
75 }
76 }
77
78
79 /*
80 * grouptree_update_all()
81 * updates root and its children
82 */
grouptree_update_all(group_t * root)83 void grouptree_update_all(group_t *root)
84 {
85 int i;
86
87 if(root) {
88 for(i=0; i<root->child_count; i++)
89 grouptree_update_all(root->child[i]);
90 root->update(root);
91 }
92 }
93
94 /*
95 * grouptree_render_all()
96 * renders root and its children
97 */
grouptree_render_all(group_t * root,v2d_t camera_position)98 void grouptree_render_all(group_t *root, v2d_t camera_position)
99 {
100 int i;
101
102 if(root) {
103 for(i=0; i<root->child_count; i++)
104 grouptree_render_all(root->child[i], camera_position);
105 root->render(root, camera_position);
106 }
107 }
108
109
110
111 /*
112 * grouptree_nodecount()
113 * returns:
114 * 1 (root) +
115 * root->child_count +
116 * root->child[i]->child_count +
117 * root->child[i]->child[j]->child_count +
118 * ...
119 */
grouptree_nodecount(group_t * root)120 int grouptree_nodecount(group_t *root)
121 {
122 int i, sum = 0;
123
124 if(root) {
125 for(i=0; i<root->child_count; i++)
126 sum += grouptree_nodecount(root->child[i]);
127 return 1 + sum;
128 }
129 else
130 return 0;
131 }
132
133
134
135
136
137
138
139
140
141 /* <<abstract>> base class */
142
143 /*
144 * group_create()
145 * creates a group node, but doesn't initialize it
146 */
group_create(void (* init)(group_t *),void (* release)(group_t *),void (* update)(group_t *),void (* render)(group_t *,v2d_t))147 group_t *group_create(void (*init)(group_t*), void (*release)(group_t*), void (*update)(group_t*), void (*render)(group_t*,v2d_t))
148 {
149 group_t *g = mallocx(sizeof *g);
150
151 /* methods */
152 g->init = init;
153 g->release = release;
154 g->update = update;
155 g->render = render;
156
157 /* internal data */
158 g->font = NULL;
159 g->data = NULL;
160 g->parent = NULL;
161 g->child_count = 0;
162
163 /* done! */
164 return g;
165 }
166
167 /*
168 * group_addchild()
169 * adds a child to g
170 */
group_addchild(group_t * g,group_t * child)171 void group_addchild(group_t *g, group_t *child)
172 {
173 if(g->child_count < GROUPTREE_MAXCHILDREN) {
174 g->child[ g->child_count++ ] = child;
175 child->parent = g;
176 }
177 }
178
179
180
181
182
183
184
185
186
187
188
189
190
191 /* labels - they are just labels that do nothing */
192
193 /*
194 * group_label_create()
195 * creates a label: shortcut to group_create(...METHODS...)
196 */
group_label_create()197 group_t* group_label_create()
198 {
199 return group_create(group_label_init, group_label_release, group_label_update, group_label_render);
200 }
201
202 /*
203 * group_label_init()
204 * initializes g's internal data (without touching g's children)
205 */
group_label_init(group_t * g)206 void group_label_init(group_t *g)
207 {
208 g->font = font_create(8);
209 font_set_text(g->font, "LABEL"); /* if you want a different text, please derive this class */
210
211 /* calculating my position... */
212 if(g->parent != NULL) {
213 int my_id, i, nodecount=0;
214 v2d_t spacing = (g->parent->font != NULL) ? font_get_charsize(g->parent->font) : v2d_new(12,12);
215
216 for(my_id=0; my_id < g->parent->child_count; my_id++) {
217 if(g->parent->child[my_id] == g)
218 break;
219 }
220
221 for(i=0; i<my_id; i++)
222 nodecount += grouptree_nodecount(g->parent->child[i])-1;
223
224 g->font->position = g->parent->font->position;
225 g->font->position.x += spacing.x * 3;
226 g->font->position.y += (1+nodecount+my_id) * spacing.y * 2;
227 }
228 }
229
230 /*
231 * group_label_release()
232 * releases g's internal data (without touching g's children)
233 */
group_label_release(group_t * g)234 void group_label_release(group_t *g)
235 {
236 font_destroy(g->font);
237 }
238
239 /*
240 * group_label_update()
241 * updates g (without touching its children)
242 */
group_label_update(group_t * g)243 void group_label_update(group_t *g)
244 {
245 }
246
247 /*
248 * group_label_render()
249 * renders g (without touching its children)
250 */
group_label_render(group_t * g,v2d_t camera_position)251 void group_label_render(group_t *g, v2d_t camera_position)
252 {
253 font_render(g->font, camera_position);
254 }
255
256