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