1 /*
2 * Copyright 2013 Ole Loots <ole@monochrom.net>
3 *
4 * This file is part of NetSurf, http://www.netsurf-browser.org/
5 *
6 * NetSurf is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * NetSurf 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
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * Module Description:
19 *
20 * AES Object tree tools.
21 *
22 */
23
24 #include <assert.h>
25 #include "gemtk.h"
26
gemtk_obj_get_text(OBJECT * tree,short idx)27 char *gemtk_obj_get_text(OBJECT * tree, short idx)
28 {
29 static char p[]="";
30
31 switch (tree[idx].ob_type & 0x00FF) {
32 case G_BUTTON:
33 case G_STRING:
34 case G_TITLE:
35 return( tree[idx].ob_spec.free_string);
36 case G_TEXT:
37 case G_BOXTEXT:
38 case G_FTEXT:
39 case G_FBOXTEXT:
40 return (tree[idx].ob_spec.tedinfo->te_ptext);
41 case G_ICON:
42 case G_CICON:
43 return (tree[idx].ob_spec.iconblk->ib_ptext);
44 break;
45
46 default:
47 break;
48 }
49 return (p);
50 }
51
52 /*
53 static void set_text(OBJECT *obj, short idx, char * text, int len)
54 {
55 char spare[255];
56
57 if( len > 254 )
58 len = 254;
59 if( text != NULL ) {
60 strncpy(spare, text, 254);
61 } else {
62 strcpy(spare, "");
63 }
64
65 set_string(obj, idx, spare);
66 }
67 */
68
gemtk_obj_set_str_safe(OBJECT * tree,short idx,const char * txt)69 char gemtk_obj_set_str_safe(OBJECT * tree, short idx, const char *txt)
70 {
71 char spare[204];
72 short type = 0;
73 short maxlen = 0;
74
75
76 type = (tree[idx].ob_type & 0xFF);
77 if (type == G_FTEXT || type == G_FBOXTEXT) {
78 TEDINFO *ted = ((TEDINFO *)get_obspec(tree, idx));
79 maxlen = ted->te_tmplen+1;
80 if (maxlen > 200) {
81 maxlen = 200;
82 } else if (maxlen < 0) {
83 maxlen = 0;
84 }
85 } else {
86 assert((type == G_FTEXT) || (type == G_FBOXTEXT));
87 }
88
89 snprintf(spare, maxlen, "%s", txt);
90 set_string(tree, idx, spare);
91
92 return(0);
93 }
94
gemtk_obj_get_tree(int idx)95 OBJECT *gemtk_obj_get_tree(int idx)
96 {
97
98 OBJECT *tree;
99
100 rsrc_gaddr(R_TREE, idx, &tree);
101
102 return tree;
103 }
104
gemtk_obj_is_inside(OBJECT * tree,short obj,GRECT * area)105 bool gemtk_obj_is_inside(OBJECT * tree, short obj, GRECT *area)
106 {
107 GRECT obj_screen;
108 bool ret = false;
109
110 objc_offset(tree, obj, &obj_screen.g_x, &obj_screen.g_y);
111 obj_screen.g_w = tree[obj].ob_width;
112 obj_screen.g_h = tree[obj].ob_height;
113
114 ret = RC_WITHIN(&obj_screen, area);
115
116 return(ret);
117 }
118
gemtk_obj_screen_rect(OBJECT * tree,short obj)119 GRECT * gemtk_obj_screen_rect(OBJECT * tree, short obj)
120 {
121 static GRECT obj_screen;
122
123 get_objframe(tree, obj, &obj_screen);
124
125 return(&obj_screen);
126 }
127
128
gemtk_obj_mouse_sprite(OBJECT * tree,int index)129 void gemtk_obj_mouse_sprite(OBJECT *tree, int index)
130 {
131 MFORM mform;
132 int dum;
133
134 if ((tree[index].ob_type & 0xFF) != G_ICON)
135 return;
136
137 dum = tree[index].ob_spec.iconblk->ib_char;
138 mform . mf_nplanes = 1;
139 mform . mf_fg = (dum>>8)&0x0F;
140 mform . mf_bg = dum>>12;
141 mform . mf_xhot = 0; /* to prevent the mform to "jump" on the */
142 mform . mf_yhot = 0; /* screen (zebulon rules!) */
143
144 for( dum = 0; dum<16; dum ++) {
145 mform . mf_mask[dum] = tree[index].ob_spec.iconblk->ib_pmask[dum];
146 mform . mf_data[dum] = tree[index].ob_spec.iconblk->ib_pdata[dum];
147 }
148 graf_mouse(USER_DEF, &mform);
149 }
150
151
152 /*
153 * gemtk_obj_tree_copy
154 *
155 * Copy a complete object-tree including all substructures (optional).
156 *
157 * CAUTION: The object-tree *must* have the LASTOB-flag (0x20) set in
158 * it's physically last member.
159 *
160 * BUG: Up to now tree_copy won't copy the color-icon-structure,
161 * because I'm too lazy ;) Maybe I'll do that one day. If you need it
162 * urgently, contact me and force me to work... Btw, this doesn't mean
163 * that G_CICONs won't be copied at all, but the copied tree will
164 * share the CICONBLKs with the original.
165 *
166 * Input:
167 * tree: Pointer to tree which should be copied
168 * what: Specifies what substructures should be copied, too (see the
169 * C_xxx-definitions in tree-copy.h for details)
170 *
171 * Output:
172 * NULL: Tree couldn't be copied (due to lack of memory)
173 * otherwise: Pointer to copied tree, use free to dealloc it's memory
174 */
gemtk_obj_tree_copy(OBJECT * tree)175 OBJECT *gemtk_obj_tree_copy(OBJECT *tree)
176 {
177 int16_t i, objects;
178 size_t to_malloc, size;
179 OBJECT *new_tree;
180 char *area;
181
182 /* Calculate the number of bytes we need for the new tree */
183 to_malloc = (size_t) 0;
184 for (i = 0;;) {
185
186 /* Size of the OBJECT-structure itself */
187 to_malloc += sizeof(OBJECT);
188
189 switch (tree[i].ob_type & 0xff) {
190 case G_TEXT:
191 case G_BOXTEXT:
192 case G_FTEXT:
193 case G_FBOXTEXT:
194 /* Size of a TEDINFO-structure */
195 to_malloc += sizeof(TEDINFO);
196
197 /* Sizes of the strings in the TEDINFO-structure */
198 to_malloc += (size_t)tree[i].ob_spec.tedinfo->te_txtlen;
199 to_malloc += (size_t)tree[i].ob_spec.tedinfo->te_txtlen;
200 to_malloc += (size_t)tree[i].ob_spec.tedinfo->te_tmplen;
201 break;
202
203 case G_IMAGE:
204
205 /* Size of the BITBLK-structure */
206 to_malloc += sizeof(BITBLK);
207
208 /* Size of the image-data in the BITBLK-structure */
209 to_malloc += (size_t)((int32_t)tree[i].ob_spec.bitblk->bi_wb *
210 (int32_t)tree[i].ob_spec.bitblk->bi_hl);
211
212 break;
213
214 case G_USERDEF:
215 /* Size of the USERBLK-structure */
216 to_malloc += sizeof(USERBLK);
217 break;
218
219 case G_BUTTON:
220 case G_STRING:
221 case G_TITLE:
222 /* Size of the string (with one null character at the end) */
223 to_malloc += strlen(tree[i].ob_spec.free_string) + 1L;
224 break;
225
226 case G_ICON:
227 /* Size of the ICONBLK-structure */
228 to_malloc += sizeof(BITBLK);
229
230 /* Sizes of icon-data, icon-mask and icon-text */
231 to_malloc += (size_t)((int32_t)tree[i].ob_spec.iconblk->ib_wicon *
232 (int32_t)tree[i].ob_spec.iconblk->ib_hicon /
233 4L + 1L +
234 (int32_t)strlen(tree[i].ob_spec.iconblk->ib_ptext));
235
236 break;
237 }
238
239 /* If the size is odd, make it even */
240 if ((long)to_malloc & 1)
241 to_malloc++;
242
243 /* Exit if we've reached the last object in the tree */
244 if (tree[i].ob_flags & OF_LASTOB)
245 break;
246
247 i++;
248 }
249
250 objects = i + 1;
251
252 /* If there's not enough memory left for the new tree, return NULL */
253 if ((new_tree = (OBJECT *)calloc(1, to_malloc)) == NULL) {
254 return(NULL);
255 }
256
257 /*
258 * area contains a pointer to the area where we copy the structures to
259 */
260 area = (char *)((int32_t)new_tree+(int32_t)objects*(int32_t)sizeof(OBJECT));
261
262 for (i = 0; i < objects; i++) {
263
264 /* Copy the contents of the OBJECT-structure */
265 new_tree[i] = tree[i];
266
267 /* This was added to assure true copies of the object type */
268 new_tree[i].ob_type = tree[i].ob_type;
269
270 switch (tree[i].ob_type & 0xff) {
271 case G_TEXT:
272 case G_BOXTEXT:
273 case G_FTEXT:
274 case G_FBOXTEXT:
275
276 /* Copy the contents of the TEDINFO-structure */
277 *(TEDINFO *)area = *tree[i].ob_spec.tedinfo;
278 new_tree[i].ob_spec.tedinfo = (TEDINFO *)area;
279 area += sizeof(TEDINFO);
280
281 /* Copy the strings in the TEDINFO-structure */
282 strncpy(area, tree[i].ob_spec.tedinfo->te_ptext,
283 tree[i].ob_spec.tedinfo->te_txtlen);
284 new_tree[i].ob_spec.tedinfo->te_ptext = area;
285 area += tree[i].ob_spec.tedinfo->te_txtlen;
286 strncpy(area, tree[i].ob_spec.tedinfo->te_ptmplt,
287 tree[i].ob_spec.tedinfo->te_tmplen);
288 new_tree[i].ob_spec.tedinfo->te_ptmplt = area;
289 area += tree[i].ob_spec.tedinfo->te_tmplen;
290 strncpy(area, tree[i].ob_spec.tedinfo->te_pvalid,
291 tree[i].ob_spec.tedinfo->te_txtlen);
292 new_tree[i].ob_spec.tedinfo->te_pvalid = area;
293 area += tree[i].ob_spec.tedinfo->te_txtlen;
294
295 break;
296
297 case G_IMAGE:
298
299 /* Copy the contents of the BITBLK-structure */
300 *(BITBLK *)area = *tree[i].ob_spec.bitblk;
301 new_tree[i].ob_spec.bitblk = (BITBLK *)area;
302 area += sizeof(BITBLK);
303
304 /* Copy the image-data */
305 size = (size_t)((int32_t)tree[i].ob_spec.bitblk->bi_wb *
306 (int32_t)tree[i].ob_spec.bitblk->bi_hl);
307 memcpy(area, tree[i].ob_spec.bitblk->bi_pdata, size);
308 new_tree[i].ob_spec.bitblk->bi_pdata = (int16_t *)area;
309 area += size;
310
311 break;
312
313 case G_USERDEF:
314
315 /* Copy the contents of the USERBLK-structure */
316 *(USERBLK *)area = *tree[i].ob_spec.userblk;
317 new_tree[i].ob_spec.userblk = (USERBLK *)area;
318 area += sizeof(USERBLK);
319
320 break;
321
322 case G_BUTTON:
323 case G_STRING:
324 case G_TITLE:
325
326 /* Copy the string */
327 size = strlen(tree[i].ob_spec.free_string) + 1L;
328 strcpy(area, tree[i].ob_spec.free_string);
329 new_tree[i].ob_spec.free_string = area;
330 area += size;
331
332 break;
333
334 case G_ICON:
335
336 /* Copy the contents of the ICONBLK-structure */
337 *(ICONBLK *)area = *tree[i].ob_spec.iconblk;
338 new_tree[i].ob_spec.iconblk = (ICONBLK *)area;
339 area += sizeof(ICONBLK);
340
341 size = (size_t)((int32_t)tree[i].ob_spec.iconblk->ib_wicon *
342 (int32_t)tree[i].ob_spec.iconblk->ib_hicon /
343 8L);
344 /* Copy the mask-data */
345 memcpy(area, tree[i].ob_spec.iconblk->ib_pmask, size);
346 new_tree[i].ob_spec.iconblk->ib_pmask = (int16_t *)area;
347 area += size;
348
349 /* Copy the icon-data */
350 memcpy(area, tree[i].ob_spec.iconblk->ib_pdata, size);
351 new_tree[i].ob_spec.iconblk->ib_pdata = (int16_t *)area;
352 area += size;
353 size = strlen(tree[i].ob_spec.iconblk->ib_ptext) + 1L;
354
355 /* Copy the icon-string */
356 strcpy(area, tree[i].ob_spec.iconblk->ib_ptext);
357 new_tree[i].ob_spec.iconblk->ib_ptext = area;
358 area += size;
359
360 break;
361 }
362
363 /* Assure that area contains an even address */
364 if ((int32_t)area & 1)
365 area++;
366 }
367
368 return(new_tree);
369 }
370
371 /***
372 * Create a simple OBJECT tree from a list of strings, to be used with menu_popup
373 * OBJECT ownership is passed to caller.
374 * Call gemtk_obj_destroy_popup_tree once the popup isn't needed anymore.
375 *
376 * \param items A list of string to be used as items
377 * \param nitems The number of items in the list
378 * \param selected The text of the selected item
379 * \param horizontal Set to true to render the tree horizontally
380 * \param max_width -1: autodetect width
381 * \param max_heigth -1: autodetect height (set to postive value when using a vertical scrolling popup)
382 * \return a pointer to the new OBJECT tree
383 */
gemtk_obj_create_popup_tree(const char ** items,int nitems,char * selected,bool horizontal,int max_width,int max_height)384 OBJECT * gemtk_obj_create_popup_tree(const char **items, int nitems,
385 char * selected, bool horizontal,
386 int max_width, int max_height)
387 {
388 OBJECT * popup = NULL;
389 int box_width = 0;
390 int box_height = 0;
391 int char_width = 10;
392 int char_height = 16;
393 int item_height; // height of each item
394
395 assert(items != NULL);
396
397 item_height = char_height;
398
399 /* Allocate room for n items and the root G_BOX: */
400 popup = calloc(nitems+1, sizeof(OBJECT));
401 assert(popup != null);
402
403 for (int i=0; i<nitems; i++) {
404
405 int len = strlen(items[i]);
406
407 if (horizontal && (max_width<1)) {
408 box_width += (len * char_width)+4;
409 }
410 else if (!horizontal){
411 /* Detect max width, used for vertical rendering: */
412 if(len*char_width > box_width){
413 box_width = (len+2) * char_width;
414 }
415 //if (max_height < 1) {
416 box_height += item_height;
417 //}
418 }
419 }
420
421 if (max_width>0){
422 box_width = max_width;
423 }
424
425 if (horizontal) {
426 box_height = item_height;
427 }
428 else if(max_height > 0){
429 // TODO: validate max_height, shrink values larger than screen height
430 //box_height = max_height;
431 }
432
433 /*
434 printf("popup height: %d, popup width: %d\n", box_height, box_width);
435 */
436
437 popup[0].ob_next = -1; /**< object's next sibling */
438 popup[0].ob_head = 1; /**< head of object's children */
439 popup[0].ob_tail = nitems; /**< tail of object's children */
440 popup[0].ob_type = G_BOX; /**< type of object */
441 popup[0].ob_flags = OF_FL3DBAK; /**< flags */
442 popup[0].ob_state = OS_NORMAL; /**< state */
443 popup[0].ob_spec.index = (long) 16650496L; /**< object-specific data */
444 popup[0].ob_x = 0; /**< upper left corner of object */
445 popup[0].ob_y = 0; /**< upper left corner of object */
446 popup[0].ob_width = box_width; /**< width of obj */
447 popup[0].ob_height = box_height;
448
449
450
451 /* Add items to popup: */
452 int xpos = 0, ypos = 0;
453
454 for (int i=0; i<nitems; i++) {
455
456 int state = OS_NORMAL;
457 int flags = OF_NONE;
458 int item_width;
459 char * string = calloc(1, strlen(items[i])+3);
460
461 snprintf(string, strlen(items[i])+3, " %s", items[i]);
462
463 if (selected != NULL) {
464 if (strcmp(selected, items[i]) == 0) {
465 state |= OS_CHECKED;
466 }
467 }
468
469 if (i == nitems-1) {
470 flags |= OF_LASTOB;
471 }
472
473 item_width = (horizontal) ? ((int)strlen(items[i])*char_width)+2 : box_width;
474 /*
475 printf("addin popup item \"%s\" (w: %d, h: %d, flags: %x) at %d/%d\n", items[i],
476 item_width, item_height, flags,
477 xpos, ypos);
478 */
479
480 popup[i+1].ob_next = ((flags&OF_LASTOB) != 0) ? 0 : i+2; /**< object's next sibling */
481 popup[i+1].ob_head = -1; /**< head of object's children */
482 popup[i+1].ob_tail = -1; /**< tail of object's children */
483 popup[i+1].ob_type = G_STRING; /**< type of object */
484 popup[i+1].ob_flags = flags; /**< flags */
485 popup[i+1].ob_state = state; /**< state */
486 popup[i+1].ob_spec.free_string = string; /**< object-specific data */
487 popup[i+1].ob_x = xpos; /**< upper left corner of object */
488 popup[i+1].ob_y = ypos; /**< upper left corner of object */
489 popup[i+1].ob_width = item_width; /**< width of obj */
490 popup[i+1].ob_height = item_height;
491
492 if (horizontal) {
493 xpos += item_width;
494 }
495 else {
496 ypos += item_height;
497 }
498
499 }
500
501 return(popup);
502 }
503
504 /***
505 * Free memory of an OBJECT tree created with gemtk_obj_create_popup_tree.
506 *
507 * \param popup The tree to destroy
508 */
gemtk_obj_destroy_popup_tree(OBJECT * popup)509 void gemtk_obj_destroy_popup_tree(OBJECT * popup)
510 {
511 int i=0;
512
513 while (1) {
514 if (popup[i].ob_type == G_STRING) {
515 free(popup[i+1].ob_spec.free_string);
516 }
517 if((popup[i].ob_flags & OF_LASTOB) != OF_LASTOB){
518 break;
519 }
520 i++;
521 }
522
523 free(popup);
524 }
525