3492 lines
71 KiB
C
3492 lines
71 KiB
C
|
|
/*
|
|
* $XConsortium: brws_mthds.c /main/4 1996/07/08 10:43:05 mustafa $
|
|
*
|
|
* @(#)brws_mthds.c 1.69 29 Apr 1995
|
|
*
|
|
* RESTRICTED CONFIDENTIAL INFORMATION:
|
|
*
|
|
* The information in this document is subject to special
|
|
* restrictions in a confidential disclosure agreement between
|
|
* HP, IBM, Sun, USL, SCO and Univel. Do not distribute this
|
|
* document outside HP, IBM, Sun, USL, SCO, or Univel without
|
|
* Sun's specific written approval. This document and all copies
|
|
* and derivative works thereof must be returned or destroyed at
|
|
* Sun's request.
|
|
*
|
|
* Copyright 1993 Sun Microsystems, Inc. All rights reserved.
|
|
*
|
|
*/
|
|
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/types.h>
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <X11/Xlib.h>
|
|
#include <Xm/Xm.h>
|
|
#include <Xm/DialogS.h>
|
|
#include <ab_private/obj.h>
|
|
#include <ab_private/trav.h>
|
|
#include <ab_private/istr.h>
|
|
#include <ab/util_types.h>
|
|
#include <ab_private/vwr.h>
|
|
#include <ab_private/pal.h>
|
|
#include <ab_private/abobj.h>
|
|
#include <ab_private/proj.h>
|
|
#include <ab_private/projP.h>
|
|
#include <ab_private/brwsP.h>
|
|
#include <ab_private/ui_util.h>
|
|
|
|
#define BRWS_DASH_WIDTH 3
|
|
#define BRWS_NUM_DASHES 3
|
|
|
|
/*
|
|
* Somehow the compiler is not picking up strdup()
|
|
* from string.h properly...
|
|
*/
|
|
extern char *strdup();
|
|
|
|
/*
|
|
* Misc functions used only in this file
|
|
*/
|
|
static ABObj first_module_of_project(
|
|
ABObj project
|
|
);
|
|
|
|
/*
|
|
* Viewer methods
|
|
*/
|
|
static ViewerNode *init_vnode(
|
|
Vwr b,
|
|
void *obj_data
|
|
);
|
|
|
|
static ViewerNode *init_toplevel_node(
|
|
Vwr b,
|
|
void *obj_data
|
|
);
|
|
|
|
static ViewerNode *init_proj_vnode(
|
|
Vwr b,
|
|
void *obj_data
|
|
);
|
|
|
|
static void init_glyph_elm(
|
|
VNode vnode,
|
|
VNodeElm elm,
|
|
void *client_data
|
|
);
|
|
|
|
static void init_name_elm(
|
|
VNode vnode,
|
|
VNodeElm elm,
|
|
void *client_data
|
|
);
|
|
|
|
static void init_class_elm(
|
|
VNode vnode,
|
|
VNodeElm elm,
|
|
void *client_data
|
|
);
|
|
|
|
static void init_wclass_elm(
|
|
VNode vnode,
|
|
VNodeElm elm,
|
|
void *client_data
|
|
);
|
|
|
|
static void free_str_elm(
|
|
VNode vnode,
|
|
VNodeElm elm
|
|
);
|
|
|
|
static void init_elements(
|
|
VNode bnode
|
|
);
|
|
|
|
static void free_elements(
|
|
VNode bnode
|
|
);
|
|
|
|
static void free_prop(
|
|
Vwr v
|
|
);
|
|
|
|
static void free_node(
|
|
VNode vnode,
|
|
void *obj_data
|
|
);
|
|
|
|
static void init_proj_props(
|
|
Vwr viewer
|
|
);
|
|
|
|
static void init_mod_props(
|
|
Vwr viewer
|
|
);
|
|
|
|
static void free_elements(
|
|
VNode bnode
|
|
);
|
|
|
|
static int insert_projview_tree(
|
|
Vwr viewer,
|
|
void *obj_data
|
|
);
|
|
static int insert_proj_tree(
|
|
Vwr viewer,
|
|
void *obj_data
|
|
);
|
|
|
|
static int insert_entire_tree(
|
|
Vwr viewer,
|
|
void *obj_data
|
|
);
|
|
|
|
static VNode insert_node(
|
|
Vwr viewer,
|
|
void *obj_data
|
|
);
|
|
|
|
static void remove_tree(
|
|
Vwr viewer,
|
|
void *obj_data
|
|
);
|
|
|
|
static void remove_node(
|
|
Vwr viewer,
|
|
void *obj_data
|
|
);
|
|
|
|
static VNode get_browser_data(
|
|
void *obj_data
|
|
);
|
|
|
|
static void set_browser_data(
|
|
void *obj_data,
|
|
VNode vnode
|
|
);
|
|
|
|
static VNode get_projwin_data(
|
|
void *obj_data
|
|
);
|
|
|
|
static void set_projwin_data(
|
|
void *obj_data,
|
|
VNode vnode
|
|
);
|
|
|
|
static ViewerNode *get_parent(
|
|
VNode bnode
|
|
);
|
|
|
|
static int get_num_salient_children(
|
|
VNode bnode
|
|
);
|
|
|
|
static int get_num_children_of_mod(
|
|
VNode bnode
|
|
);
|
|
|
|
static int get_num_children_of_proj(
|
|
VNode bnode
|
|
);
|
|
|
|
static VNode get_salient_child(
|
|
VNode bnode,
|
|
int which_child
|
|
);
|
|
|
|
static VNode get_child_of_mod(
|
|
VNode bnode,
|
|
int which_child
|
|
);
|
|
|
|
static VNode get_child_of_proj(
|
|
VNode bnode,
|
|
int which_child
|
|
);
|
|
|
|
static int get_num_children_ui(
|
|
VNode bnode
|
|
);
|
|
|
|
static ViewerNode *get_child_ui(
|
|
VNode bnode,
|
|
int which_child
|
|
);
|
|
|
|
static unsigned long get_toplevel_drawarea(
|
|
Vwr v
|
|
);
|
|
|
|
static unsigned long get_detailed_drawarea(
|
|
Vwr v
|
|
);
|
|
|
|
static unsigned long get_proj_drawarea(
|
|
Vwr v
|
|
);
|
|
|
|
static void compute_tree(
|
|
Vwr b,
|
|
int *end_x,
|
|
int *end_y
|
|
);
|
|
|
|
static void compute_matrix(
|
|
Vwr b,
|
|
int *end_x,
|
|
int *end_y
|
|
);
|
|
|
|
static void compute_subtree(
|
|
VNode tree,
|
|
int start_x,
|
|
int start_y,
|
|
int *max_x,
|
|
int *max_y
|
|
);
|
|
|
|
static void compute_submatrix(
|
|
VNode tree,
|
|
int start_x,
|
|
int start_y,
|
|
int *max_x,
|
|
int *max_y
|
|
);
|
|
|
|
static void compute_glyph_elm(
|
|
VNode node,
|
|
VNodeElm str_elm,
|
|
int x,
|
|
int y
|
|
);
|
|
|
|
static void compute_str_elm(
|
|
VNode node,
|
|
VNodeElm str_elm,
|
|
int x,
|
|
int y
|
|
);
|
|
|
|
static void compute_node(
|
|
VNode node,
|
|
int x,
|
|
int y
|
|
);
|
|
|
|
static void render_salient_tree(
|
|
VNode tree
|
|
);
|
|
|
|
static void render_mod_tree(
|
|
VNode tree
|
|
);
|
|
|
|
static void render_proj_tree(
|
|
VNode tree
|
|
);
|
|
|
|
static void render_glyph_elm(
|
|
VNode node,
|
|
VNodeElm glyph_elm,
|
|
int hilite
|
|
);
|
|
|
|
static void render_str_elm(
|
|
VNode node,
|
|
VNodeElm str_elm,
|
|
int hilite
|
|
);
|
|
|
|
static void render_node(
|
|
VNode node,
|
|
int hilite
|
|
);
|
|
|
|
static void render_line(
|
|
VNode parent,
|
|
VNode child
|
|
);
|
|
|
|
static VNode locate_node(
|
|
VNode tree,
|
|
int x,
|
|
int y
|
|
);
|
|
|
|
static unsigned long locate_elements(
|
|
VNode vnode,
|
|
int x,
|
|
int y
|
|
);
|
|
|
|
static void render_node_bbox(
|
|
ViewerNode *node
|
|
);
|
|
|
|
static void draw_zoom_in(
|
|
Vwr b,
|
|
VNode node
|
|
);
|
|
|
|
static void draw_zoom_out(
|
|
Vwr b
|
|
);
|
|
|
|
static void draw_collapsed_feedback(
|
|
VNode node
|
|
);
|
|
|
|
static void compute_collapsed_feedback(
|
|
VNode node,
|
|
int *max_x,
|
|
int *max_y
|
|
);
|
|
|
|
|
|
static ViewerMethods proj_view_methods = {
|
|
init_proj_props, /* init_prop */
|
|
NULL, /* init_ui */
|
|
init_toplevel_node, /* init_node */
|
|
init_elements, /* init_elements */
|
|
free_prop, /* free_prop */
|
|
NULL, /* free_ui */
|
|
free_node, /* free_node */
|
|
free_elements, /* free_elements */
|
|
insert_projview_tree, /* insert_tree */
|
|
insert_node, /* insert_node */
|
|
remove_tree, /* remove_tree */
|
|
remove_node, /* remove_node */
|
|
NULL, /* get_obj_data */
|
|
get_browser_data, /* get_viewer_data */
|
|
set_browser_data, /* set_viewer_data */
|
|
NULL, /* get_sibling */
|
|
get_parent, /* get_parent */
|
|
get_num_children_of_mod, /* get_num_children */
|
|
get_child_of_mod, /* get_child */
|
|
get_toplevel_drawarea, /* get_drawarea */
|
|
compute_matrix, /* compute_tree */
|
|
compute_node, /* compute_node */
|
|
render_mod_tree, /* render_tree */
|
|
render_node, /* render_node */
|
|
render_line, /* render_line */
|
|
NULL, /* preview_node */
|
|
locate_node, /* locate_node */
|
|
locate_elements /* locate_elements */
|
|
};
|
|
|
|
static ViewerMethods mod_view_methods = {
|
|
init_mod_props, /* init_prop */
|
|
NULL, /* init_ui */
|
|
init_vnode, /* init_node */
|
|
init_elements, /* init_elements */
|
|
free_prop, /* free_prop */
|
|
NULL, /* free_ui */
|
|
free_node, /* free_node */
|
|
free_elements, /* free_elements */
|
|
insert_entire_tree, /* insert_tree */
|
|
insert_node, /* insert_node */
|
|
remove_tree, /* remove_tree */
|
|
remove_node, /* remove_node */
|
|
NULL, /* get_obj_data */
|
|
get_browser_data, /* get_viewer_data */
|
|
set_browser_data, /* set_viewer_data */
|
|
NULL, /* get_sibling */
|
|
get_parent, /* get_parent */
|
|
get_num_salient_children, /* get_num_children */
|
|
get_salient_child, /* get_child */
|
|
get_detailed_drawarea, /* get_drawarea */
|
|
compute_tree, /* compute_tree */
|
|
compute_node, /* compute_node */
|
|
render_salient_tree, /* render_tree */
|
|
render_node, /* render_node */
|
|
render_line, /* render_line */
|
|
NULL, /* preview_node */
|
|
locate_node, /* locate_node */
|
|
locate_elements /* locate_elements */
|
|
};
|
|
|
|
static ViewerMethods proj_methods = {
|
|
init_proj_props, /* init_prop */
|
|
NULL, /* init_ui */
|
|
init_proj_vnode, /* init_node */
|
|
init_elements, /* init_elements */
|
|
free_prop, /* free_prop */
|
|
NULL, /* free_ui */
|
|
free_node, /* free_node */
|
|
free_elements, /* free_elements */
|
|
insert_proj_tree, /* insert_tree */
|
|
insert_node, /* insert_node */
|
|
remove_tree, /* remove_tree */
|
|
remove_node, /* remove_node */
|
|
NULL, /* get_obj_data */
|
|
get_projwin_data, /* get_viewer_data */
|
|
set_projwin_data, /* set_viewer_data */
|
|
NULL, /* get_sibling */
|
|
get_parent, /* get_parent */
|
|
get_num_children_of_proj, /* get_num_children */
|
|
get_child_of_proj, /* get_child */
|
|
get_proj_drawarea, /* get_drawarea */
|
|
compute_matrix, /* compute_tree */
|
|
compute_node, /* compute_node */
|
|
render_proj_tree, /* render_tree */
|
|
render_node, /* render_node */
|
|
render_line, /* render_line */
|
|
NULL, /* preview_node */
|
|
locate_node, /* locate_node */
|
|
locate_elements /* locate_elements */
|
|
};
|
|
|
|
static ViewerElmMethods glyphElmMethods = {
|
|
init_glyph_elm,
|
|
compute_glyph_elm,
|
|
render_glyph_elm,
|
|
NULL
|
|
};
|
|
|
|
static ViewerElmMethods nameElmMethods = {
|
|
init_name_elm,
|
|
compute_str_elm,
|
|
render_str_elm,
|
|
free_str_elm
|
|
};
|
|
|
|
static ViewerElmMethods classElmMethods = {
|
|
init_class_elm,
|
|
compute_str_elm,
|
|
render_str_elm,
|
|
free_str_elm
|
|
};
|
|
|
|
static ViewerElmMethods wclassElmMethods = {
|
|
init_wclass_elm,
|
|
compute_str_elm,
|
|
render_str_elm,
|
|
free_str_elm
|
|
};
|
|
|
|
static VElmMethods elmMethods[] = {
|
|
&glyphElmMethods,
|
|
&nameElmMethods,
|
|
&classElmMethods,
|
|
&wclassElmMethods
|
|
};
|
|
|
|
VMethods brwsP_proj_methods = &proj_view_methods;
|
|
VMethods brwsP_mod_methods = &mod_view_methods;
|
|
VMethods projP_methods = &proj_methods;
|
|
|
|
/*
|
|
* Create, initialize and return a browser node
|
|
*/
|
|
static ViewerNode *
|
|
init_vnode(
|
|
Viewer *b,
|
|
void *obj_data
|
|
)
|
|
{
|
|
AB_OBJ *obj = (AB_OBJ *)obj_data;
|
|
ViewerNode *node, *cur_node;
|
|
BrowserProps props;
|
|
ViewerMethods *m;
|
|
|
|
if (!b)
|
|
return (NULL);
|
|
|
|
props = aob_browser_properties(b);
|
|
|
|
node = vwr_create_node();
|
|
|
|
node->browser = b;
|
|
node->obj_data = (void *) obj;
|
|
node->elm_methods = elmMethods;
|
|
node->elements = NULL;
|
|
node->num_elements = 0;
|
|
node->boundbox_shown = TRUE;
|
|
node->x = node->y = node->width = node->height = -1;
|
|
|
|
/*
|
|
* Use initial state as stored in browser object
|
|
*/
|
|
node->state = props->initial_state;
|
|
|
|
/*
|
|
* Init node state to:
|
|
* SELECTED - to match AB_OBJ's select state
|
|
*/
|
|
if (obj_is_selected(obj))
|
|
BRWS_NODE_SET_STATE(node, BRWS_NODE_SELECTED);
|
|
else
|
|
BRWS_NODE_UNSET_STATE(node, BRWS_NODE_SELECTED);
|
|
|
|
m = b->methods;
|
|
cur_node = (*m->get_viewer_data)(obj);
|
|
node->next = cur_node;
|
|
|
|
/*
|
|
* If nodes for other browsers exist, link them to this new
|
|
* one
|
|
*/
|
|
if (cur_node)
|
|
cur_node->previous = node;
|
|
|
|
/*
|
|
* Make this new node the first one on the AB_OBJ list
|
|
*/
|
|
if (obj)
|
|
(*m->set_viewer_data)(obj, node);
|
|
|
|
return node;
|
|
}
|
|
|
|
/*
|
|
* Create, initialize and return a viewer node for toplevel view
|
|
*/
|
|
static ViewerNode *
|
|
init_toplevel_node(
|
|
Viewer *b,
|
|
void *obj_data
|
|
)
|
|
{
|
|
AB_OBJ *obj = (AB_OBJ *)obj_data;
|
|
ViewerNode *node, *cur_node;
|
|
BrowserProps props;
|
|
ViewerMethods *m;
|
|
|
|
if (!b)
|
|
return (NULL);
|
|
|
|
props = aob_browser_properties(b);
|
|
|
|
node = vwr_create_node();
|
|
|
|
node->browser = b;
|
|
node->obj_data = (void *) obj;
|
|
node->elm_methods = elmMethods;
|
|
node->elements = NULL;
|
|
node->num_elements = 0;
|
|
node->boundbox_shown = TRUE;
|
|
node->x = node->y = node->width = node->height = -1;
|
|
|
|
/*
|
|
* Use initial state as stored in browser object
|
|
*/
|
|
node->state = props->initial_state;
|
|
|
|
/*
|
|
* Do not initialize node select state
|
|
* This is taken care of by initial state
|
|
*/
|
|
|
|
m = b->methods;
|
|
cur_node = (*m->get_viewer_data)(obj);
|
|
node->next = cur_node;
|
|
|
|
/*
|
|
* If nodes for other browsers exist, link them to this new
|
|
* one
|
|
*/
|
|
if (cur_node)
|
|
cur_node->previous = node;
|
|
|
|
/*
|
|
* Make this new node the first one on the AB_OBJ list
|
|
*/
|
|
if (obj)
|
|
(*m->set_viewer_data)(obj, node);
|
|
|
|
return node;
|
|
}
|
|
|
|
/*
|
|
* Create, initialize and return a vnode for the project window
|
|
*/
|
|
static ViewerNode *
|
|
init_proj_vnode(
|
|
Viewer *b,
|
|
void *obj_data
|
|
)
|
|
{
|
|
AB_OBJ *obj = (AB_OBJ *)obj_data;
|
|
ViewerNode *node, *cur_node;
|
|
BrowserProps props;
|
|
ViewerMethods *m;
|
|
|
|
if (!b)
|
|
return (NULL);
|
|
|
|
m = b->methods;
|
|
|
|
/*
|
|
* If a projwin vnode already exists, return it.
|
|
*/
|
|
if (cur_node = (*m->get_viewer_data)(obj))
|
|
return (cur_node);
|
|
|
|
props = aob_browser_properties(b);
|
|
|
|
node = vwr_create_node();
|
|
|
|
node->browser = b;
|
|
node->obj_data = (void *) obj;
|
|
node->elm_methods = elmMethods;
|
|
node->elements = NULL;
|
|
node->num_elements = 0;
|
|
node->boundbox_shown = TRUE;
|
|
node->x = node->y = node->width = node->height = -1;
|
|
node->next = NULL;
|
|
|
|
/*
|
|
* Use initial state as stored in browser object
|
|
*/
|
|
node->state = props->initial_state;
|
|
|
|
BRWS_NODE_UNSET_STATE(node, BRWS_NODE_SELECTED);
|
|
|
|
/*
|
|
* Make this new node the first one on the AB_OBJ list
|
|
*/
|
|
if (obj)
|
|
(*m->set_viewer_data)(obj, node);
|
|
|
|
return node;
|
|
}
|
|
|
|
static void
|
|
init_glyph_elm(
|
|
VNode vnode,
|
|
VNodeElm elm,
|
|
void *client_data
|
|
)
|
|
{
|
|
AB_OBJ *obj = (AB_OBJ *)client_data;
|
|
Pixmap image = NULL; /* gotta set to NULL!!! */
|
|
|
|
/*
|
|
* Object glyph
|
|
*/
|
|
ui_get_obj_pixmap(obj, &image, &elm->width, &elm->height);
|
|
elm->data = (void *)image;
|
|
elm->x = elm->y = -1;
|
|
}
|
|
|
|
static void
|
|
init_name_elm(
|
|
VNode vnode,
|
|
VNodeElm elm,
|
|
void *client_data
|
|
)
|
|
{
|
|
AB_OBJ *obj = (AB_OBJ *)client_data;
|
|
char *tmp;
|
|
|
|
/*
|
|
* Object name
|
|
*/
|
|
if (elm->data)
|
|
free(elm->data);
|
|
#ifdef BRWS_NO_FILE_NAMES
|
|
if (obj_is_module(obj) && (obj->info.module.file != NULL))
|
|
{
|
|
char *fullpath, *filename;
|
|
|
|
fullpath = obj_get_file(obj);
|
|
|
|
/*
|
|
* Check return value of strrchr before adding 1 to it
|
|
*/
|
|
if (filename = strrchr(fullpath, '/'))
|
|
tmp = strdup(filename + 1);
|
|
else
|
|
tmp = strdup(fullpath);
|
|
}
|
|
else
|
|
#else
|
|
tmp = strdup(util_strsafe(obj_get_name(obj)));
|
|
#endif /* BRWS_NO_FILE_NAMES */
|
|
elm->data = (void *)tmp;
|
|
elm->x = elm->y = elm->width = elm->height = -1;
|
|
}
|
|
|
|
static void
|
|
init_class_elm(
|
|
VNode vnode,
|
|
VNodeElm elm,
|
|
void *client_data
|
|
)
|
|
{
|
|
PalEditableObjInfo *editable_obj_info = NULL;
|
|
AB_OBJ *obj = (AB_OBJ *)client_data;
|
|
int subtype;
|
|
char *tmp = NULL;
|
|
|
|
if (!elm || !obj)
|
|
return;
|
|
|
|
/*
|
|
* Free Object class/type string if it exists
|
|
*/
|
|
if (elm->data)
|
|
free(elm->data);
|
|
|
|
/*
|
|
* Get subtype
|
|
*/
|
|
subtype = obj_get_subtype(obj);
|
|
|
|
/*
|
|
* However, if the object is a scale (i.e. either scale/gauge),
|
|
* the subtype field is not used, instead, it's read-only state
|
|
* is used.
|
|
*/
|
|
if (obj_is_scale(obj))
|
|
{
|
|
BOOL read_only = obj_get_read_only(obj);
|
|
|
|
/*
|
|
* Scale: read_only == False
|
|
* Gauge: read_only == True
|
|
*/
|
|
subtype = (int)read_only;
|
|
}
|
|
|
|
/*
|
|
* The type strings can be obtained from various places.
|
|
* We should centralize this sometime...
|
|
*/
|
|
|
|
/*
|
|
* If the object in question is a module, just hardcode the string
|
|
* since there is no palette info on modules.
|
|
* Note: Object type strings are NOT internationalized, so no problem
|
|
* here.
|
|
*/
|
|
if (obj_is_module(obj))
|
|
{
|
|
tmp = "Module";
|
|
}
|
|
|
|
/*
|
|
* Hardcode string for layers object.
|
|
* Layers are not palette objects and they are not editable either.
|
|
*/
|
|
if (!tmp && obj_is_layers(obj))
|
|
{
|
|
tmp = "Layers";
|
|
}
|
|
|
|
/*
|
|
* If the object is an item/message object, get the string from
|
|
* the palette editable object information.
|
|
*/
|
|
if (!tmp && (obj_is_item(obj) || obj_is_message(obj)))
|
|
{
|
|
editable_obj_info = pal_get_editable_obj_info(obj);
|
|
|
|
if (editable_obj_info && editable_obj_info->name)
|
|
tmp = istr_string(editable_obj_info->name);
|
|
}
|
|
|
|
/*
|
|
* Still no string up to now.
|
|
* Use the palette item info. pal_get_item_subname()
|
|
* will return the subtype (e.g. Drawn Button) string
|
|
* if it exists for the object type.
|
|
*/
|
|
if (!tmp)
|
|
{
|
|
tmp = pal_get_item_subname(obj, subtype);
|
|
}
|
|
|
|
/*
|
|
* No subtype string.
|
|
* Return the type string.
|
|
*/
|
|
if (!tmp)
|
|
{
|
|
PalItemInfo *pal_info;
|
|
pal_info = pal_get_item_info(obj);
|
|
if (pal_info)
|
|
tmp = pal_info->name;
|
|
}
|
|
|
|
/*
|
|
* This is the 'old' lookup table with all uppercase strings.
|
|
*/
|
|
if (!tmp)
|
|
tmp = util_object_type_to_browser_string(obj->type);
|
|
|
|
tmp = strdup(tmp);
|
|
|
|
elm->data = (void *)tmp;
|
|
elm->x = elm->y = elm->width = elm->height = -1;
|
|
}
|
|
|
|
static void
|
|
init_wclass_elm(
|
|
VNode vnode,
|
|
VNodeElm elm,
|
|
void *client_data
|
|
)
|
|
{
|
|
AB_OBJ *obj = (AB_OBJ *)client_data;
|
|
char *tmp;
|
|
|
|
/*
|
|
* Widget class
|
|
*/
|
|
if (elm->data)
|
|
free(elm->data);
|
|
tmp = strdup(util_strsafe(obj_get_class_name(obj)));
|
|
elm->data = (void *)tmp;
|
|
elm->x = elm->y = elm->width = elm->height = -1;
|
|
}
|
|
|
|
static void
|
|
free_str_elm(
|
|
VNode vnode,
|
|
VNodeElm elm
|
|
)
|
|
{
|
|
/*
|
|
* Free string element
|
|
*/
|
|
if (elm->data)
|
|
{
|
|
free(elm->data);
|
|
elm->data = NULL;
|
|
}
|
|
elm->x = elm->y = elm->width = elm->height = -1;
|
|
}
|
|
|
|
|
|
static void
|
|
init_elements(
|
|
ViewerNode *vnode
|
|
)
|
|
{
|
|
AB_OBJ *obj;
|
|
ViewerNodeElm *elm;
|
|
VElmMethods *elm_methods;
|
|
int i;
|
|
|
|
|
|
if (!vnode)
|
|
return;
|
|
|
|
if (!vnode->elements)
|
|
{
|
|
elm = (ViewerNodeElm *)calloc(BRWS_NUM_ELM, sizeof(ViewerNodeElm));
|
|
vnode->num_elements = BRWS_NUM_ELM;
|
|
vnode->elements = elm;
|
|
|
|
for (i=0; i < vnode->num_elements; ++i)
|
|
{
|
|
elm[i].data = NULL;
|
|
elm[i].x = elm[0].y =
|
|
elm[i].width = elm[i].height = -1;
|
|
}
|
|
}
|
|
else
|
|
elm = vnode->elements;
|
|
|
|
obj = (AB_OBJ *)vnode->obj_data;
|
|
elm_methods = vnode->elm_methods;
|
|
|
|
for (i=0; i < vnode->num_elements; ++i)
|
|
{
|
|
(*(elm_methods[i]->init))(vnode, &elm[i], (void *)obj);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Free structure that holds browser properties
|
|
*/
|
|
static void
|
|
free_prop(
|
|
Vwr v
|
|
)
|
|
{
|
|
if (!v && !v->properties)
|
|
return;
|
|
|
|
free(v->properties);
|
|
|
|
v->properties = NULL;
|
|
}
|
|
|
|
/*
|
|
* The obj_data parameter is not really necessary since
|
|
* it hangs off the vnode, but I did not want to assume that
|
|
* is the case for all users of the viewer node
|
|
*/
|
|
static void
|
|
free_node(
|
|
VNode vnode,
|
|
void *obj_data
|
|
)
|
|
{
|
|
ABObj obj = (ABObj)obj_data;
|
|
Vwr viewer;
|
|
VNode prev,
|
|
next;
|
|
VMethods m;
|
|
int i;
|
|
|
|
if (!vnode || !obj_data)
|
|
return;
|
|
|
|
viewer = vnode->browser;
|
|
m = viewer ? viewer->methods : NULL;
|
|
|
|
if (!m)
|
|
return;
|
|
|
|
prev = vnode->previous;
|
|
next = vnode->next;
|
|
|
|
if (prev)
|
|
{
|
|
prev->next = vnode->next;
|
|
}
|
|
else
|
|
{
|
|
(*m->set_viewer_data)(obj, vnode->next);
|
|
}
|
|
|
|
if (next)
|
|
{
|
|
next->previous = vnode->previous;
|
|
}
|
|
|
|
free(vnode);
|
|
}
|
|
|
|
static void
|
|
free_elements(
|
|
ViewerNode *vnode
|
|
)
|
|
{
|
|
AB_OBJ *obj;
|
|
ViewerNodeElm *elm;
|
|
VElmMethods *elm_methods;
|
|
int i;
|
|
|
|
|
|
if (!vnode || !vnode->elm_methods ||
|
|
!vnode->elements || !vnode->elements)
|
|
return;
|
|
|
|
obj = (AB_OBJ *)vnode->obj_data;
|
|
elm = vnode->elements;
|
|
elm_methods = vnode->elm_methods;
|
|
|
|
for (i=0; i < vnode->num_elements; ++i)
|
|
{
|
|
if (elm_methods[i]->free)
|
|
(*(elm_methods[i]->free))(vnode, &elm[i]);
|
|
}
|
|
|
|
free(elm);
|
|
|
|
vnode->elements = NULL;
|
|
vnode->num_elements = 0;
|
|
}
|
|
|
|
static void
|
|
init_proj_props(
|
|
Vwr viewer
|
|
)
|
|
{
|
|
BrowserProps props;
|
|
|
|
props = (BrowserProps)malloc(sizeof(BrowserProperties));
|
|
|
|
/*
|
|
* Possible values for bit vector:
|
|
* BRWS_SHOW_TYPE, BRWS_SHOW_NAME, BRWS_SHOW_WIDGET_CLASS, BRWS_SHOW_GLYPH
|
|
*/
|
|
props->elements_shown = BRWS_SHOW_NAME | BRWS_SHOW_GLYPH;
|
|
props->initial_state = BRWS_NODE_EXPANDED | BRWS_NODE_VISIBLE;
|
|
props->orientation = BRWS_HORIZONTAL;
|
|
props->show_mult_trees = FALSE;
|
|
|
|
/*
|
|
* This flag is currently used to determine if feedback
|
|
* is needed for the browser when say someone selects an
|
|
* object on an module or on another browser.
|
|
*/
|
|
props->active = FALSE;
|
|
|
|
viewer->properties = (void *)props;
|
|
}
|
|
|
|
static void
|
|
init_mod_props(
|
|
Vwr viewer
|
|
)
|
|
{
|
|
BrowserProps props;
|
|
|
|
props = (BrowserProps)malloc(sizeof(BrowserProperties));
|
|
|
|
/*
|
|
* Possible values for bit vector:
|
|
* BRWS_SHOW_TYPE, BRWS_SHOW_NAME, BRWS_SHOW_WIDGET_CLASS, BRWS_SHOW_GLYPH
|
|
*/
|
|
props->elements_shown = BRWS_SHOW_GLYPH | BRWS_SHOW_NAME;
|
|
props->initial_state = BRWS_NODE_EXPANDED | BRWS_NODE_VISIBLE;
|
|
props->orientation = BRWS_VERTICAL;
|
|
props->show_mult_trees = FALSE;
|
|
props->active = TRUE;
|
|
|
|
viewer->properties = (void *)props;
|
|
}
|
|
|
|
static ABObj
|
|
first_module_of_project(
|
|
ABObj project
|
|
)
|
|
{
|
|
AB_TRAVERSAL trav;
|
|
ABObj first_mod = NULL;
|
|
|
|
if (!project || !obj_is_project(project))
|
|
return (NULL);
|
|
|
|
trav_open(&trav, project, AB_TRAV_MODULES);
|
|
first_mod = trav_next(&trav);
|
|
trav_close(&trav);
|
|
|
|
return first_mod;
|
|
}
|
|
|
|
|
|
/*
|
|
* insert_projview_tree()
|
|
* insert_tree() method for module view of browser.
|
|
*
|
|
* This insert_tree() method only inserts nodes into
|
|
* modules, and immediate children of modules. The current
|
|
* module the browser is currently browsing is stored in:
|
|
* viewer->obj_data
|
|
*
|
|
* The obj_data passed can be any type of AB_OBJ. If the obj_data
|
|
* passed is not in the current module browsed, the browser nodes of
|
|
* current module browsed is deleted and the module containing the
|
|
* obj_data passed is inserted.
|
|
*
|
|
*
|
|
*
|
|
*/
|
|
static int
|
|
insert_projview_tree
|
|
(
|
|
Vwr viewer,
|
|
void *obj_data
|
|
)
|
|
{
|
|
ABObj root = (ABObj)obj_data,
|
|
browsed_module = NULL,
|
|
insert_module = NULL,
|
|
cur_obj;
|
|
Vwr b_list;
|
|
AB_TRAVERSAL trav;
|
|
VNode bnode,
|
|
module_node;
|
|
ViewerMethods *m;
|
|
|
|
if ((!viewer) || (!root))
|
|
return(0);
|
|
|
|
/*
|
|
* This function only insert nodes into modules, and immediate children
|
|
* of modules.
|
|
*
|
|
* NOTE: If an object passed in is not a project/module/window, we
|
|
* can get an infinite loop. This is avoided by trav'ing on the modules
|
|
* with AB_TRAV_WINDOWS.
|
|
*/
|
|
if (!obj_is_project(root) && !obj_is_module(root)
|
|
&& !obj_is_window(root) && !obj_is_menu(root) && !obj_is_message(root))
|
|
{
|
|
root = obj_get_module(root);
|
|
}
|
|
|
|
/*
|
|
* Get methods vector
|
|
*/
|
|
m = viewer->methods;
|
|
|
|
/*
|
|
* Get module that this browser is currently browsing...
|
|
*/
|
|
if (viewer->tree)
|
|
browsed_module = (AB_OBJ *)viewer->tree->obj_data;
|
|
|
|
/*
|
|
* If a project is passed in, this function is called
|
|
* recursively with the appropriate module.
|
|
*/
|
|
if (obj_is_project(root))
|
|
{
|
|
|
|
/*
|
|
* The module to insert depends on whether this browser
|
|
* is already being used to browse an existing module or
|
|
* not.
|
|
*/
|
|
if (!browsed_module)
|
|
{
|
|
/*
|
|
* Currently not browsing anything. This browser will
|
|
* browse the first module of the project
|
|
*/
|
|
insert_module = first_module_of_project(root);
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* This browser is currently being used. Check if the
|
|
* module passed is the same one. If yes, re-insert it.
|
|
* Otherwise, insert nothing.
|
|
* Re-inserting will only have an effect if there are new
|
|
* objects in the tree that the browser does not know
|
|
* about yet.
|
|
*/
|
|
if (root == obj_get_project(browsed_module))
|
|
{
|
|
insert_module = browsed_module;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Recursive call with proper module to insert
|
|
*/
|
|
insert_projview_tree(viewer, insert_module);
|
|
|
|
return(0);
|
|
}
|
|
|
|
if (obj_is_module(root))
|
|
{
|
|
if (browsed_module != root)
|
|
{
|
|
(*m->remove_tree)(viewer, browsed_module);
|
|
viewer->tree = viewer->current_tree = NULL;
|
|
viewer->obj_data = (void *)NULL;
|
|
}
|
|
|
|
bnode = (*m->insert_node)(viewer, root);
|
|
|
|
viewer->tree = viewer->current_tree = bnode;
|
|
viewer->obj_data = (void *)obj_get_project(root);
|
|
|
|
/*
|
|
* Insert all windows of this module, skip
|
|
* actions
|
|
*/
|
|
for (trav_open(&trav, root, AB_TRAV_WINDOWS);
|
|
(cur_obj = trav_next(&trav)) != NULL; )
|
|
{
|
|
insert_projview_tree(viewer, cur_obj);
|
|
}
|
|
trav_close(&trav);
|
|
|
|
/*
|
|
* Insert all menus of this module.
|
|
*/
|
|
for (trav_open(&trav, root, AB_TRAV_MENUS);
|
|
(cur_obj = trav_next(&trav)) != NULL; ) {
|
|
insert_projview_tree(viewer, cur_obj);
|
|
}
|
|
trav_close(&trav);
|
|
|
|
/*
|
|
* Insert all message objects of this module.
|
|
*/
|
|
for (trav_open(&trav, root, AB_TRAV_CHILDREN);
|
|
(cur_obj = trav_next(&trav)) != NULL; )
|
|
{
|
|
if (obj_is_message(cur_obj))
|
|
insert_projview_tree(viewer, cur_obj);
|
|
}
|
|
trav_close(&trav);
|
|
|
|
brws_set_module_name(viewer);
|
|
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* The object is something below a module
|
|
* Check:
|
|
* 1. Is this object in the same module as the currently
|
|
* browsed module ('browsed_module') ?
|
|
* 2. Has the viewer node been inserted into the module for
|
|
* this object ?
|
|
*
|
|
* In either case, we want to insert the module.
|
|
*/
|
|
insert_module = obj_get_module(root);
|
|
|
|
module_node = aob_find_bnode(insert_module, viewer);
|
|
|
|
if ((insert_module != browsed_module) || (!module_node))
|
|
{
|
|
insert_projview_tree(viewer, insert_module);
|
|
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* Attach viewer node onto object
|
|
*/
|
|
bnode = (*m->insert_node)(viewer, root);
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
insert_proj_tree
|
|
(
|
|
Vwr viewer,
|
|
void *obj_data
|
|
)
|
|
{
|
|
AB_OBJ *root = (AB_OBJ *)obj_data;
|
|
Vwr b_list;
|
|
AB_TRAVERSAL trav;
|
|
AB_OBJ *cur_obj;
|
|
VNode bnode;
|
|
ViewerMethods *m;
|
|
|
|
if (!viewer || !root)
|
|
return(0);
|
|
|
|
/*
|
|
* This routine does not insert viewer nodes into anything
|
|
* below a module. This checks for that.
|
|
*/
|
|
if (!obj_is_project(root) && !obj_is_module(root))
|
|
{
|
|
root = obj_get_module(root);
|
|
|
|
if (!root || !obj_is_defined(root))
|
|
return(0);
|
|
}
|
|
|
|
m = viewer->methods;
|
|
bnode = (*m->insert_node)(viewer, root);
|
|
|
|
if (obj_is_project(root))
|
|
{
|
|
viewer->tree = viewer->current_tree = bnode;
|
|
viewer->obj_data = (void *)root;
|
|
|
|
for (trav_open(&trav, root, AB_TRAV_MODULES);
|
|
(cur_obj = trav_next(&trav)) != NULL; )
|
|
{
|
|
/* Don't show any undefined modules.
|
|
* Undefined modules can occur if a module
|
|
* is imported which references another
|
|
* module that does not exist in the project
|
|
* (i.e. :win-children).
|
|
*/
|
|
if (obj_is_defined(cur_obj))
|
|
{
|
|
insert_proj_tree(viewer, cur_obj);
|
|
}
|
|
}
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
insert_entire_tree
|
|
(
|
|
Viewer *viewer,
|
|
void *obj_data
|
|
)
|
|
{
|
|
ABObj root = (ABObj)obj_data,
|
|
browsed_module = NULL,
|
|
insert_module = NULL,
|
|
cur_obj;
|
|
Viewer *b_list;
|
|
VNode bnode,
|
|
module_node;
|
|
ViewerMethods *m;
|
|
AB_TRAVERSAL trav;
|
|
|
|
if (!viewer || !root)
|
|
return(0);
|
|
|
|
/*
|
|
* Get methods vector
|
|
*/
|
|
m = viewer->methods;
|
|
|
|
/*
|
|
* Get module that this browser is currently browsing...
|
|
*/
|
|
if (viewer->tree)
|
|
browsed_module = (ABObj)viewer->tree->obj_data;
|
|
|
|
/*
|
|
* If a project is passed in, this function is called
|
|
* recursively with the appropriate module.
|
|
*/
|
|
if (obj_is_project(root))
|
|
{
|
|
|
|
/*
|
|
* The module to insert depends on whether this browser
|
|
* is already being used to browse an existing module or
|
|
* not.
|
|
*/
|
|
if (!browsed_module)
|
|
{
|
|
/*
|
|
* Currently not browsing anything. This browser will
|
|
* browse the first module of the project
|
|
*/
|
|
insert_module = first_module_of_project(root);
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* This browser is currently being used. Check if the
|
|
* module passed is the same one. If yes, re-insert it.
|
|
* Otherwise, insert nothing.
|
|
* Re-inserting will only have an effect if there are new
|
|
* objects in the tree that the browser does not know
|
|
* about yet.
|
|
*/
|
|
if (root == obj_get_project(browsed_module))
|
|
{
|
|
insert_module = browsed_module;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Recursive call with proper module to insert
|
|
*/
|
|
insert_entire_tree(viewer, insert_module);
|
|
|
|
return(0);
|
|
}
|
|
|
|
if (obj_is_module(root))
|
|
{
|
|
if (browsed_module != root)
|
|
{
|
|
(*m->remove_tree)(viewer, browsed_module);
|
|
viewer->tree = viewer->current_tree = NULL;
|
|
viewer->obj_data = (void *)NULL;
|
|
}
|
|
|
|
bnode = (*m->insert_node)(viewer, root);
|
|
|
|
viewer->tree = viewer->current_tree = bnode;
|
|
viewer->obj_data = (void *)obj_get_project(root);
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* The object is something below a module
|
|
* Check:
|
|
* 1. Is this object in the same module as the currently
|
|
* browsed module ('browsed_module') ?
|
|
* 2. Has the viewer node been inserted into the module for
|
|
* this object ?
|
|
*
|
|
* In either case, we want to insert the module.
|
|
*/
|
|
insert_module = obj_get_module(root);
|
|
|
|
module_node = aob_find_bnode(insert_module, viewer);
|
|
|
|
if ((insert_module != browsed_module) || (!module_node))
|
|
{
|
|
insert_entire_tree(viewer, insert_module);
|
|
|
|
return (0);
|
|
}
|
|
|
|
bnode = (*m->insert_node)(viewer, root);
|
|
}
|
|
|
|
/*
|
|
* Insert viewer nodes into all AB_OBJ's, even though we only
|
|
* need salient ones. We will need the non-salient ones later,
|
|
* e.g. for showing widget classes etc...
|
|
*
|
|
* NOTE: AB_TRAV_UI will not work here since a trav of AB_TRAV_UI
|
|
* on a module will return the module first. This will cause
|
|
* an infinite loop.
|
|
*/
|
|
for (trav_open(&trav, root, AB_TRAV_CHILDREN);
|
|
(cur_obj = trav_next(&trav)) != NULL; ) {
|
|
insert_entire_tree(viewer, cur_obj);
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
|
|
/*
|
|
* Insert an object to the object browser.
|
|
*/
|
|
static VNode
|
|
insert_node(
|
|
Vwr viewer,
|
|
void *obj_data
|
|
)
|
|
{
|
|
AB_OBJ *obj = (AB_OBJ *)obj_data;
|
|
ViewerMethods *m;
|
|
ViewerNode *node;
|
|
|
|
if (!viewer || !obj)
|
|
return (NULL);
|
|
|
|
m = viewer->methods;
|
|
|
|
node = aob_find_bnode(obj, viewer);
|
|
|
|
if (!node)
|
|
{
|
|
node = (*m->init_node)(viewer, obj);
|
|
}
|
|
else
|
|
return (node);
|
|
|
|
(*m->init_elements)(node);
|
|
|
|
return (node);
|
|
|
|
}
|
|
|
|
|
|
static void
|
|
remove_tree
|
|
(
|
|
Vwr viewer,
|
|
void *obj_data
|
|
)
|
|
{
|
|
AB_OBJ *root = (AB_OBJ *)obj_data;
|
|
Vwr b_list;
|
|
AB_TRAVERSAL trav;
|
|
AB_OBJ *cur_obj;
|
|
ViewerMethods *m;
|
|
|
|
if (!viewer || !root)
|
|
return;
|
|
|
|
for (trav_open(&trav, root, AB_TRAV_CHILDREN);
|
|
(cur_obj = trav_next(&trav)) != NULL; ) {
|
|
remove_tree(viewer, cur_obj);
|
|
}
|
|
|
|
m = viewer->methods;
|
|
(*m->remove_node)(viewer, root);
|
|
}
|
|
|
|
/*
|
|
* Delete an object from the object browser.
|
|
*/
|
|
static void
|
|
remove_node(
|
|
Vwr viewer,
|
|
void *obj_data
|
|
)
|
|
{
|
|
AB_OBJ *obj = (AB_OBJ *)obj_data;
|
|
ViewerMethods *m;
|
|
VNode node;
|
|
|
|
if (!viewer || !obj)
|
|
return;
|
|
|
|
m = viewer->methods;
|
|
|
|
node = aob_find_bnode(obj, viewer);
|
|
|
|
if (node)
|
|
{
|
|
/*
|
|
* Reset current_tree if the node it is pointing to is destroyed
|
|
* NOTE: This does not catch the case where a node *between*
|
|
* viewer->tree and viewer->current_tree is removed.
|
|
*/
|
|
if (viewer->current_tree == node)
|
|
viewer->current_tree = viewer->tree;
|
|
|
|
if (viewer->tree == node)
|
|
viewer->tree = viewer->current_tree = NULL;
|
|
|
|
/*
|
|
* Free elements of node
|
|
*/
|
|
(*m->free_elements)(node);
|
|
|
|
/*
|
|
* Free node
|
|
*/
|
|
(*m->free_node)(node, obj);
|
|
}
|
|
}
|
|
|
|
|
|
static VNode
|
|
get_browser_data(
|
|
void *obj_data
|
|
)
|
|
{
|
|
AB_OBJ *obj = (AB_OBJ *)obj_data;
|
|
|
|
return (VNode)(obj->browser_data);
|
|
}
|
|
|
|
static void
|
|
set_browser_data(
|
|
void *obj_data,
|
|
VNode vnode
|
|
)
|
|
{
|
|
AB_OBJ *obj = (AB_OBJ *)obj_data;
|
|
|
|
obj->browser_data = (void *)vnode;
|
|
}
|
|
|
|
static VNode
|
|
get_projwin_data(
|
|
void *obj_data
|
|
)
|
|
{
|
|
AB_OBJ *obj = (AB_OBJ *)obj_data;
|
|
|
|
return (VNode)(obj->projwin_data);
|
|
}
|
|
|
|
static void
|
|
set_projwin_data(
|
|
void *obj_data,
|
|
VNode vnode
|
|
)
|
|
{
|
|
AB_OBJ *obj = (AB_OBJ *)obj_data;
|
|
|
|
obj->projwin_data = (void *)vnode;
|
|
}
|
|
|
|
|
|
static ViewerNode *
|
|
get_parent
|
|
(
|
|
ViewerNode *bnode
|
|
)
|
|
{
|
|
AB_OBJ *obj, *parent_obj, *tmp_parent;
|
|
Viewer *browser;
|
|
|
|
if (!bnode)
|
|
return(NULL);
|
|
|
|
obj = (AB_OBJ *)bnode->obj_data;
|
|
|
|
if (!obj)
|
|
return(NULL);
|
|
|
|
tmp_parent = obj_get_parent(obj);
|
|
parent_obj = tmp_parent ? obj_get_root(tmp_parent) : NULL;
|
|
|
|
browser = bnode->browser;
|
|
|
|
return(aob_find_bnode(parent_obj, browser));
|
|
}
|
|
|
|
static int
|
|
get_num_children_of_proj
|
|
(
|
|
ViewerNode *bnode
|
|
)
|
|
{
|
|
AB_OBJ *obj;
|
|
|
|
if (!bnode)
|
|
return(-1);
|
|
|
|
obj = (AB_OBJ *)bnode->obj_data;
|
|
|
|
if (obj_is_project(obj))
|
|
return(obj_get_num_children_cond(obj, obj_is_defined_module));
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
get_num_children_of_mod
|
|
(
|
|
ViewerNode *bnode
|
|
)
|
|
{
|
|
AB_OBJ *obj;
|
|
|
|
if (!bnode)
|
|
return(-1);
|
|
|
|
obj = (AB_OBJ *)bnode->obj_data;
|
|
|
|
if (obj_is_module(obj))
|
|
return(obj_get_num_children(obj));
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
get_num_salient_children
|
|
(
|
|
ViewerNode *bnode
|
|
)
|
|
{
|
|
AB_OBJ *obj;
|
|
|
|
if (!bnode)
|
|
return(-1);
|
|
|
|
obj = (AB_OBJ *)bnode->obj_data;
|
|
|
|
/*
|
|
return(obj_get_num_children(obj));
|
|
*/
|
|
return(obj_get_num_salient_children(obj));
|
|
}
|
|
|
|
static ViewerNode *
|
|
get_child_of_mod
|
|
(
|
|
ViewerNode *bnode,
|
|
int which_child
|
|
)
|
|
{
|
|
AB_OBJ *obj,
|
|
*child;
|
|
Viewer *browser;
|
|
ViewerNode *child_bnode;
|
|
|
|
if (!bnode)
|
|
return(NULL);
|
|
|
|
obj = (AB_OBJ *)bnode->obj_data;
|
|
browser = bnode->browser;
|
|
|
|
if (!obj || !browser || !obj_is_module(obj))
|
|
return (NULL);
|
|
|
|
child = obj_get_child(obj, which_child);
|
|
|
|
child_bnode = aob_find_bnode(child, browser);
|
|
|
|
return(child_bnode);
|
|
}
|
|
|
|
static ViewerNode *
|
|
get_child_of_proj
|
|
(
|
|
ViewerNode *bnode,
|
|
int which_child
|
|
)
|
|
{
|
|
AB_OBJ *obj,
|
|
*child;
|
|
Viewer *browser;
|
|
ViewerNode *child_bnode;
|
|
|
|
if (!bnode)
|
|
return(NULL);
|
|
|
|
obj = (AB_OBJ *)bnode->obj_data;
|
|
browser = bnode->browser;
|
|
|
|
if (!obj || !browser || !obj_is_project(obj))
|
|
return (NULL);
|
|
|
|
child = obj_get_child_cond(obj, which_child, obj_is_defined_module);
|
|
|
|
child_bnode = aob_find_bnode(child, browser);
|
|
|
|
return(child_bnode);
|
|
}
|
|
|
|
static ViewerNode *
|
|
get_salient_child(
|
|
ViewerNode *bnode,
|
|
int which_child
|
|
)
|
|
{
|
|
AB_OBJ *obj,
|
|
*child;
|
|
Viewer *browser;
|
|
ViewerNode *child_bnode;
|
|
|
|
if (!bnode)
|
|
return(NULL);
|
|
|
|
obj = (AB_OBJ *)bnode->obj_data;
|
|
browser = bnode->browser;
|
|
|
|
if (!obj || !browser)
|
|
return (NULL);
|
|
|
|
/*
|
|
child = obj_get_child(obj, which_child);
|
|
*/
|
|
child = obj_get_salient_child(obj, which_child);
|
|
|
|
child_bnode = aob_find_bnode(child, browser);
|
|
|
|
return(child_bnode);
|
|
}
|
|
|
|
static BOOL
|
|
has_ui
|
|
(
|
|
AB_OBJ *obj
|
|
)
|
|
{
|
|
if (obj_is_project(obj) || obj_is_module(obj))
|
|
return(True);
|
|
|
|
if (obj->ui_handle)
|
|
return(True);
|
|
|
|
return(False);
|
|
}
|
|
|
|
static int
|
|
get_num_children_ui
|
|
(
|
|
ViewerNode *bnode
|
|
)
|
|
{
|
|
AB_OBJ *obj;
|
|
|
|
if (!bnode)
|
|
return(-1);
|
|
|
|
obj = (AB_OBJ *)bnode->obj_data;
|
|
|
|
return(obj_get_num_children_cond(obj, has_ui));
|
|
}
|
|
|
|
static ViewerNode *
|
|
get_child_ui(
|
|
ViewerNode *bnode,
|
|
int which_child
|
|
)
|
|
{
|
|
AB_OBJ *obj,
|
|
*child;
|
|
Viewer *browser;
|
|
ViewerNode *child_bnode = NULL;
|
|
|
|
if (!bnode)
|
|
return(NULL);
|
|
|
|
obj = (AB_OBJ *)bnode->obj_data;
|
|
browser = bnode->browser;
|
|
|
|
if (!obj || !browser)
|
|
return (NULL);
|
|
|
|
child = obj_get_child_cond(obj, which_child, has_ui);
|
|
|
|
child_bnode = aob_find_bnode(child, browser);
|
|
|
|
return(child_bnode);
|
|
}
|
|
|
|
/*
|
|
* Apply the (x, y) offset to all the elements of the passed
|
|
* node
|
|
*/
|
|
static void
|
|
node_elm_offset
|
|
(
|
|
ViewerNode *node,
|
|
int x,
|
|
int y
|
|
)
|
|
{
|
|
Viewer *b;
|
|
ViewerNodeElm *elm;
|
|
int elm_shown;
|
|
int i;
|
|
|
|
b = node->browser;
|
|
elm_shown = browser_get_elm_shown(b);
|
|
elm = node->elements;
|
|
|
|
for (i=0; i < node->num_elements; ++i)
|
|
{
|
|
if (elm_shown | (1L << i))
|
|
{
|
|
elm[i].x += x;
|
|
elm[i].y += y;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static unsigned long
|
|
get_toplevel_drawarea(
|
|
Vwr v
|
|
)
|
|
{
|
|
DtbBrwsMainwindowInfo instance;
|
|
BrowserUiObj ui;
|
|
|
|
if (!v)
|
|
return (NULL);
|
|
|
|
ui = (BrowserUiObj)v->ui_handle;
|
|
|
|
if (!ui)
|
|
return (NULL);
|
|
|
|
instance = (DtbBrwsMainwindowInfo)ui->ip;
|
|
|
|
return (instance ? (unsigned long)instance->toplevel_drawarea :
|
|
(unsigned long)NULL);
|
|
}
|
|
|
|
static unsigned long
|
|
get_detailed_drawarea(
|
|
Vwr v
|
|
)
|
|
{
|
|
DtbBrwsMainwindowInfo instance;
|
|
BrowserUiObj ui;
|
|
|
|
if (!v)
|
|
return (NULL);
|
|
|
|
ui = (BrowserUiObj)v->ui_handle;
|
|
|
|
if (!ui)
|
|
return (NULL);
|
|
|
|
instance = (DtbBrwsMainwindowInfo)(ui->ip);
|
|
|
|
return (instance ? (unsigned long)instance->detailed_drawarea :
|
|
(unsigned long)NULL);
|
|
}
|
|
|
|
static unsigned long
|
|
get_proj_drawarea(
|
|
Vwr v
|
|
)
|
|
{
|
|
DtbProjProjMainInfo proj_d;
|
|
BrowserUiObj ui;
|
|
|
|
if (!v)
|
|
return (NULL);
|
|
|
|
ui = (BrowserUiObj)v->ui_handle;
|
|
|
|
if (!ui)
|
|
return (NULL);
|
|
|
|
proj_d = (DtbProjProjMainInfo)ui->ip;
|
|
|
|
return (proj_d ?
|
|
(unsigned long)proj_d->module_drawarea
|
|
: (unsigned long)NULL);
|
|
}
|
|
|
|
/*
|
|
* Compute the coordinates of each node in the tree.
|
|
* It does not draw the tree.
|
|
*/
|
|
static void
|
|
compute_tree
|
|
(
|
|
Vwr b,
|
|
int *end_x,
|
|
int *end_y
|
|
)
|
|
{
|
|
VNode top;
|
|
AB_OBJ *obj;
|
|
int i, num_child,
|
|
max_x = BRWS_X_ORIGIN,
|
|
max_y = BRWS_Y_ORIGIN;
|
|
|
|
if (!b || !b->current_tree)
|
|
return;
|
|
|
|
top = b->current_tree;
|
|
|
|
if (!top)
|
|
return;
|
|
|
|
if (!BRWS_NODE_STATE_IS_SET(top, BRWS_NODE_VISIBLE))
|
|
return;
|
|
|
|
obj = (AB_OBJ *)top->obj_data;
|
|
|
|
if (!obj)
|
|
return;
|
|
|
|
if (BRWS_NODE_STATE_IS_SET(top, BRWS_NODE_VISIBLE))
|
|
compute_subtree(top, BRWS_X_ORIGIN, BRWS_Y_ORIGIN, end_x, end_y);
|
|
}
|
|
|
|
|
|
/*
|
|
* Compute the coordinates of each node in the tree.
|
|
* It does not draw the tree.
|
|
*/
|
|
static void
|
|
compute_matrix
|
|
(
|
|
Vwr b,
|
|
int *end_x,
|
|
int *end_y
|
|
)
|
|
{
|
|
VNode top;
|
|
AB_OBJ *obj;
|
|
int i, num_child,
|
|
max_x = BRWS_X_ORIGIN,
|
|
max_y = BRWS_Y_ORIGIN;
|
|
Widget draw_area;
|
|
XRectangle w_rect;/* widget width,height,x,y */
|
|
|
|
if (!b || !b->current_tree)
|
|
return;
|
|
|
|
top = b->current_tree;
|
|
|
|
if (!top)
|
|
return;
|
|
|
|
obj = (AB_OBJ *)top->obj_data;
|
|
|
|
if (!obj)
|
|
return;
|
|
|
|
draw_area = brws_draw_area(b);
|
|
XtVaGetValues(draw_area,
|
|
XtNwidth, &(w_rect.width),
|
|
XtNheight, &(w_rect.height),
|
|
NULL);
|
|
|
|
*end_x = w_rect.width;
|
|
*end_y = w_rect.height;
|
|
|
|
compute_submatrix(top, BRWS_X_ORIGIN, BRWS_Y_ORIGIN,
|
|
end_x, end_y);
|
|
}
|
|
|
|
|
|
/*
|
|
* Compute the coordinates of each node in the subtree.
|
|
* It does not draw the tree.
|
|
*/
|
|
static void
|
|
compute_subtree
|
|
(
|
|
ViewerNode *tree,
|
|
int start_x,
|
|
int start_y,
|
|
int *max_x,
|
|
int *max_y
|
|
)
|
|
{
|
|
ViewerMethods *m;
|
|
AB_OBJ *obj;
|
|
Viewer *b;
|
|
int i,
|
|
tmp,
|
|
num_child;
|
|
|
|
if (!tree)
|
|
return;
|
|
|
|
obj = (AB_OBJ *)tree->obj_data;
|
|
b = tree->browser;
|
|
m = b->methods;
|
|
|
|
/*
|
|
* Get number of children
|
|
*/
|
|
num_child = (*m->get_num_children)(tree);
|
|
|
|
/*
|
|
* If tree is childless.
|
|
*/
|
|
if ((num_child == 0) || !(BRWS_NODE_STATE_IS_SET(tree, BRWS_NODE_EXPANDED)))
|
|
{
|
|
/*
|
|
* Store start_x and start_y into the node.
|
|
*/
|
|
(*m->compute_node)(tree, start_x, start_y);
|
|
|
|
/*
|
|
* Compute max_x and max_y which will be
|
|
* used in subsequent calls to draw other
|
|
* parts of the tree.
|
|
*/
|
|
tmp = start_x + tree->width + BRWS_NODE_X_GAP;
|
|
if (tmp > *max_x)
|
|
*max_x = tmp;
|
|
|
|
/*
|
|
* Takes into consideration the icon height and
|
|
* the height needed to display the name of the obj.
|
|
*/
|
|
tmp = start_y + tree->height + BRWS_NODE_Y_GAP;
|
|
if (tmp > *max_y)
|
|
*max_y = tmp;
|
|
|
|
if (!(BRWS_NODE_STATE_IS_SET(tree, BRWS_NODE_EXPANDED)))
|
|
{
|
|
compute_collapsed_feedback(tree, max_x, max_y);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ViewerNode *child;
|
|
BrowserProperties *props;
|
|
|
|
props = aob_browser_properties(b);
|
|
|
|
/*
|
|
* Place the parent mid-way in between its
|
|
* children.
|
|
*/
|
|
if (props->orientation == BRWS_VERTICAL)
|
|
{
|
|
(*m->compute_node)(tree, 0, start_y);
|
|
tmp = start_y + tree->height + BRWS_NODE_Y_GAP;
|
|
|
|
/*
|
|
* Recursively compute the children of this node.
|
|
* Compute procs should check for (child == NULL)
|
|
*/
|
|
for (i=0, child = (*m->get_child)(tree, 0);
|
|
(i < num_child);
|
|
child = (*m->get_child)(tree, ++i))
|
|
if (child && BRWS_NODE_STATE_IS_SET(child, BRWS_NODE_VISIBLE))
|
|
compute_subtree(child, *max_x, tmp, max_x, max_y);
|
|
|
|
tmp = (*max_x - start_x - BRWS_NODE_X_GAP - tree->width)/2 + start_x;
|
|
if (tmp < start_x)
|
|
{
|
|
tree->x = start_x;
|
|
tmp = start_x + tree->width + BRWS_NODE_X_GAP;
|
|
}
|
|
else
|
|
{
|
|
tree->x = tmp;
|
|
tmp = tmp + tree->width + BRWS_NODE_X_GAP;
|
|
}
|
|
|
|
node_elm_offset(tree, tree->x, 0);
|
|
|
|
if (tmp > *max_x)
|
|
*max_x = tmp;
|
|
|
|
/*
|
|
* If for some reason the the max_y (i.e. height) of the entire
|
|
* subtree was not incremented (error in compute_node of child),
|
|
* make it big enough for this node.
|
|
*/
|
|
tmp = start_y + tree->height + BRWS_NODE_Y_GAP;
|
|
if (*max_y < tmp)
|
|
*max_y = tmp;
|
|
}
|
|
else
|
|
{
|
|
(*m->compute_node)(tree, start_x, 0);
|
|
tmp = start_x + tree->width + BRWS_NODE_X_GAP;
|
|
|
|
/*
|
|
* Recursively draw the children of this node.
|
|
* Compute procs should check for (child == NULL)
|
|
*/
|
|
for (i=0, child = (*m->get_child)(tree, 0);
|
|
(i < num_child);
|
|
child = (*m->get_child)(tree, ++i))
|
|
if (child && BRWS_NODE_STATE_IS_SET(child, BRWS_NODE_VISIBLE))
|
|
compute_subtree(child, tmp, *max_y, max_x, max_y);
|
|
|
|
tmp = (*max_y - start_y - BRWS_NODE_Y_GAP - tree->height)/2 + start_y;
|
|
if (tmp < start_y)
|
|
{
|
|
tree->y = start_y;
|
|
tmp = start_y + tree->height + BRWS_NODE_Y_GAP;
|
|
}
|
|
else
|
|
{
|
|
tree->y = tmp;
|
|
tmp = tmp + tree->height + BRWS_NODE_Y_GAP;
|
|
}
|
|
|
|
node_elm_offset(tree, 0, tree->y);
|
|
|
|
if (tmp > *max_y)
|
|
*max_y = tmp;
|
|
|
|
/*
|
|
* If for some reason the the max_x (i.e. width) of the entire
|
|
* subtree was not incremented (error in compute_node of child),
|
|
* make it big enough for this node.
|
|
*/
|
|
tmp = start_x + tree->width + BRWS_NODE_X_GAP;
|
|
if (*max_x < tmp)
|
|
*max_x = tmp;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Compute the coordinates of each node in the subtree.
|
|
* It does not draw the tree.
|
|
*/
|
|
static void
|
|
compute_submatrix
|
|
(
|
|
ViewerNode *tree,
|
|
int start_x,
|
|
int start_y,
|
|
int *max_x,
|
|
int *max_y
|
|
)
|
|
{
|
|
ViewerMethods *m;
|
|
AB_OBJ *obj;
|
|
Vwr b;
|
|
VNode child;
|
|
BrowserProps props;
|
|
int i,
|
|
x = start_x,
|
|
y = start_y,
|
|
num_child,
|
|
col_max_width = 0,
|
|
row_max_height = 0;
|
|
|
|
if (!tree)
|
|
return;
|
|
|
|
obj = (AB_OBJ *)tree->obj_data;
|
|
b = tree->browser;
|
|
m = b->methods;
|
|
props = aob_browser_properties(b);
|
|
|
|
/*
|
|
* Skip the root node
|
|
*/
|
|
if (tree != b->tree)
|
|
{
|
|
(*m->compute_node)(tree, x, y);
|
|
|
|
if (props->orientation == BRWS_HORIZONTAL)
|
|
x += tree->width + BRWS_NODE_X_GAP;
|
|
else
|
|
y += tree->height + BRWS_NODE_Y_GAP;
|
|
}
|
|
|
|
/*
|
|
* Get number of children
|
|
*/
|
|
num_child = (*m->get_num_children)(tree);
|
|
|
|
for (i=0, child = (*m->get_child)(tree, 0);
|
|
(i < num_child);
|
|
child = (*m->get_child)(tree, ++i))
|
|
{
|
|
if (!child)
|
|
continue;
|
|
compute_submatrix(child, x, y, max_x, max_y);
|
|
|
|
if (props->orientation == BRWS_HORIZONTAL)
|
|
{
|
|
if (x + child->width > *max_x)
|
|
{
|
|
x = start_x;
|
|
y += row_max_height + BRWS_NODE_Y_GAP;
|
|
row_max_height = 0;
|
|
(*m->compute_node)(child, x, y);
|
|
}
|
|
|
|
x += child->width + BRWS_NODE_X_GAP;
|
|
|
|
if (child->height > row_max_height)
|
|
row_max_height = child->height;
|
|
}
|
|
else
|
|
{
|
|
if (y + child->height > *max_y)
|
|
{
|
|
y = start_y;
|
|
x += col_max_width + BRWS_NODE_X_GAP;
|
|
col_max_width = 0;
|
|
(*m->compute_node)(child, x, y);
|
|
}
|
|
|
|
y += child->height + BRWS_NODE_Y_GAP;
|
|
|
|
if (child->width > col_max_width)
|
|
col_max_width = child->width;
|
|
}
|
|
}
|
|
|
|
*max_y = y + row_max_height + BRWS_NODE_Y_GAP;
|
|
/*
|
|
*max_x = x + col_max_width + BRWS_NODE_X_GAP;
|
|
*/
|
|
}
|
|
|
|
|
|
/*
|
|
* compute the coordinates of the glyph element in
|
|
* a node
|
|
*/
|
|
static void
|
|
compute_glyph_elm
|
|
(
|
|
VNode node,
|
|
VNodeElm glyph_elm,
|
|
int x,
|
|
int y
|
|
)
|
|
{
|
|
if (!node || !glyph_elm)
|
|
return;
|
|
|
|
/*
|
|
* The width/height of the glyph element
|
|
* was initialized at init time
|
|
*/
|
|
|
|
glyph_elm->x = x;
|
|
glyph_elm->y = y;
|
|
}
|
|
|
|
/*
|
|
* compute the coordinates of the string element in
|
|
* a node
|
|
*/
|
|
static void
|
|
compute_str_elm
|
|
(
|
|
VNode node,
|
|
VNodeElm str_elm,
|
|
int x,
|
|
int y
|
|
)
|
|
{
|
|
Viewer *b;
|
|
BrowserUiObjects *ui;
|
|
XFontStruct *sm_font;
|
|
int font_ascent,
|
|
font_descent;
|
|
char *str;
|
|
|
|
if (!node || !str_elm)
|
|
return;
|
|
|
|
b = node->browser;
|
|
ui = (BrowserUiObjects *)b->ui_handle;
|
|
sm_font = ui->sm_font;
|
|
font_ascent = sm_font->max_bounds.ascent;
|
|
font_descent = sm_font->max_bounds.descent;
|
|
|
|
str = (char *)str_elm->data;
|
|
|
|
str_elm->width = XTextWidth(sm_font, str, strlen(str));
|
|
str_elm->height = font_ascent + font_descent;
|
|
|
|
str_elm->x = x;
|
|
str_elm->y = y;
|
|
}
|
|
|
|
/*
|
|
* Compute the coordinates of one node.
|
|
* A browser node consists of node->num_elements
|
|
* elements. Each element has a margin of width
|
|
* BRWS_ELM_BBOX_MARGIN. And surrounding each element
|
|
* and it's margin, on all 4 sides, is a border of
|
|
* width BRWS_ELM_BORDER_WIDTH.
|
|
*
|
|
* The size (width/height) of each element is exactly
|
|
* that. It DOES NOT include the margins/borders. The
|
|
* position (x,y) of each element can be used directly
|
|
* by the rendering routines - they have already been
|
|
* padded by the size of margins/borders.
|
|
*
|
|
* The size of the node DOES include margins/borders.
|
|
* The position of the node is the top left corner
|
|
* of the border.
|
|
*/
|
|
static void
|
|
compute_node(
|
|
ViewerNode *node,
|
|
int x,
|
|
int y
|
|
)
|
|
{
|
|
Vwr b;
|
|
ViewerNodeElm *elm;
|
|
VElmMethods *elm_methods;
|
|
int elm_shown;
|
|
int cur_height = 0,
|
|
cur_width = 0,
|
|
cur_y_offset,
|
|
i;
|
|
BOOL first_elm = TRUE;
|
|
|
|
if (!node)
|
|
return;
|
|
|
|
b = node->browser;
|
|
elm_shown = browser_get_elm_shown(b);
|
|
elm = node->elements;
|
|
elm_methods = node->elm_methods;
|
|
|
|
/*
|
|
* cur_height is the current height of the node as a whole
|
|
* cur_y_offset is the current y offset for the current element
|
|
* calculated
|
|
*
|
|
* We start both with the width of the top border and margin
|
|
*/
|
|
cur_height = BRWS_ELM_BORDER_WIDTH + BRWS_ELM_BBOX_MARGIN;
|
|
cur_y_offset = y + BRWS_ELM_BORDER_WIDTH + BRWS_ELM_BBOX_MARGIN;
|
|
|
|
/*
|
|
* Set x,y for node
|
|
*/
|
|
node->x = x;
|
|
node->y = y;
|
|
|
|
for (i=0; i < node->num_elements; ++i)
|
|
{
|
|
if (elm_shown & (1L << i))
|
|
{
|
|
/*
|
|
* For each visible element...
|
|
*/
|
|
|
|
if (!first_elm)
|
|
{
|
|
cur_height += BRWS_INTER_ELM_DISTANCE;
|
|
cur_y_offset += BRWS_INTER_ELM_DISTANCE;
|
|
}
|
|
|
|
first_elm = FALSE;
|
|
|
|
/*
|
|
* increment node height, y offset by top margin
|
|
cur_height += BRWS_ELM_BBOX_MARGIN;
|
|
cur_y_offset += BRWS_ELM_BBOX_MARGIN;
|
|
*/
|
|
|
|
/*
|
|
* Compute size, position of element
|
|
*/
|
|
(*(elm_methods[i]->compute))(node, &elm[i], x, cur_y_offset);
|
|
|
|
/*
|
|
* Increment node height, y offset by new element height,
|
|
* bottom margin and bottom border
|
|
*/
|
|
cur_height += elm[i].height;
|
|
cur_y_offset += elm[i].height;
|
|
|
|
/*
|
|
* Keep track of max width
|
|
*/
|
|
cur_width = (cur_width > elm[i].width) ?
|
|
cur_width : elm[i].width;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* We end with the width of the bottom border and margin
|
|
*/
|
|
cur_height += BRWS_ELM_BORDER_WIDTH + BRWS_ELM_BBOX_MARGIN;
|
|
cur_y_offset += BRWS_ELM_BORDER_WIDTH + BRWS_ELM_BBOX_MARGIN;
|
|
|
|
|
|
/*
|
|
* The width of the node is the width of the widest element plus
|
|
* space for the margins/borders on both sides
|
|
*/
|
|
node->width = cur_width +
|
|
(2 * (BRWS_ELM_BBOX_MARGIN + BRWS_ELM_BORDER_WIDTH));
|
|
|
|
/*
|
|
* Set height obtained so far
|
|
*/
|
|
node->height = cur_height;
|
|
|
|
/*
|
|
* Center all elements according to max width
|
|
*/
|
|
for (i=0; i < BRWS_NUM_ELM; ++i)
|
|
{
|
|
if (elm_shown & (1L << i))
|
|
{
|
|
elm[i].x = x + (node->width - elm[i].width)/2;
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
* compute the coordinates of one collapsed node.
|
|
*/
|
|
static void
|
|
compute_collapsed_node(
|
|
ViewerNode *node,
|
|
int x,
|
|
int y
|
|
)
|
|
{
|
|
Viewer *b;
|
|
BrowserUiObjects *ui;
|
|
ViewerNodeElm *elm;
|
|
XFontStruct *sm_font;
|
|
int elm_shown;
|
|
int font_ascent,
|
|
font_descent,
|
|
cur_height = 0,
|
|
cur_width = 0,
|
|
cur_x_offset,
|
|
cur_y_offset,
|
|
i;
|
|
char *collapsed_str = ". . .";
|
|
XCharStruct overall = {0};
|
|
int ascent, descent, direction;
|
|
|
|
b = node->browser;
|
|
ui = (BrowserUiObjects *)b->ui_handle;
|
|
elm_shown = browser_get_elm_shown(b);
|
|
sm_font = ui->sm_font;
|
|
font_ascent = sm_font->max_bounds.ascent;
|
|
font_descent = sm_font->max_bounds.descent;
|
|
elm = node->elements;
|
|
|
|
/*
|
|
cur_x_offset = 0;
|
|
cur_height = cur_y_offset =
|
|
BRWS_ELM_BBOX_MARGIN + BRWS_ELM_BORDER_WIDTH;
|
|
*/
|
|
cur_x_offset = cur_y_offset = 0;
|
|
|
|
node->x = x;
|
|
node->y = y;
|
|
|
|
XTextExtents(sm_font, collapsed_str, strlen(collapsed_str),
|
|
&direction, &ascent, &descent, &overall);
|
|
|
|
node->height = ascent + descent + BRWS_ELM_BBOX_MARGIN;
|
|
node->width = overall.width + BRWS_ELM_BBOX_MARGIN;
|
|
}
|
|
|
|
/*
|
|
* Render module tree
|
|
*/
|
|
static void
|
|
render_mod_tree
|
|
(
|
|
VNode tree
|
|
)
|
|
{
|
|
ViewerMethods *m;
|
|
AB_OBJ *obj;
|
|
|
|
if (!tree)
|
|
return;
|
|
|
|
m = BNODE_METHODS(tree);
|
|
|
|
obj = (AB_OBJ *)tree->obj_data;
|
|
|
|
if (obj_is_module(obj))
|
|
{
|
|
VNode child;
|
|
int i, num_child;
|
|
|
|
num_child = (*m->get_num_children)(tree);
|
|
/*
|
|
* Render child nodes
|
|
*
|
|
* Render procs should check for (child == NULL)
|
|
*/
|
|
for (i=0, child = (*m->get_child)(tree, 0);
|
|
(i < num_child);
|
|
child = (*m->get_child)(tree, ++i))
|
|
{
|
|
(*m->render_tree)(child);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (obj_is_window(obj) || obj_is_menu(obj) || obj_is_message(obj))
|
|
{
|
|
if (BRWS_NODE_STATE_IS_SET(tree, BRWS_NODE_SELECTED))
|
|
(*m->render_node)(tree, TRUE);
|
|
else
|
|
(*m->render_node)(tree, FALSE);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
* Actually render the tree on the given canvas.
|
|
*/
|
|
static void
|
|
render_proj_tree
|
|
(
|
|
VNode tree
|
|
)
|
|
{
|
|
ViewerMethods *m;
|
|
AB_OBJ *obj;
|
|
|
|
if (!tree)
|
|
return;
|
|
|
|
m = BNODE_METHODS(tree);
|
|
|
|
obj = (AB_OBJ *)tree->obj_data;
|
|
|
|
if (obj_is_project(obj))
|
|
{
|
|
VNode child;
|
|
int i, num_child;
|
|
|
|
num_child = (*m->get_num_children)(tree);
|
|
/*
|
|
* Render child nodes
|
|
*
|
|
* Render procs should check for (child == NULL)
|
|
*/
|
|
for (i=0, child = (*m->get_child)(tree, 0);
|
|
(i < num_child);
|
|
child = (*m->get_child)(tree, ++i))
|
|
{
|
|
(*m->render_tree)(child);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (obj_is_module(obj))
|
|
{
|
|
if (BRWS_NODE_STATE_IS_SET(tree, BRWS_NODE_SELECTED))
|
|
(*m->render_node)(tree, TRUE);
|
|
else
|
|
(*m->render_node)(tree, FALSE);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
* Render all 'salient' children of the tree (excluding the
|
|
* project node).
|
|
*/
|
|
static void
|
|
render_salient_tree
|
|
(
|
|
VNode tree
|
|
)
|
|
{
|
|
ViewerMethods *m;
|
|
AB_OBJ *obj;
|
|
VNode child;
|
|
int i, num_child;
|
|
|
|
if (!tree)
|
|
return;
|
|
|
|
m = BNODE_METHODS(tree);
|
|
|
|
obj = (AB_OBJ *)tree->obj_data;
|
|
|
|
num_child = (*m->get_num_children)(tree);
|
|
|
|
/*
|
|
* If this node is not supposed to be seen,
|
|
* don't render it
|
|
*/
|
|
if (!BRWS_NODE_STATE_IS_SET(tree, BRWS_NODE_VISIBLE))
|
|
return;
|
|
|
|
if (obj_is_project(obj))
|
|
{
|
|
/*
|
|
* Don't render project nodes - render it's child nodes
|
|
*
|
|
* Render procs should check for (child == NULL)
|
|
*/
|
|
for (i=0, child = (*m->get_child)(tree, 0);
|
|
(i < num_child);
|
|
child = (*m->get_child)(tree, ++i))
|
|
{
|
|
/*
|
|
* If this child node is not supposed to be seen,
|
|
* don't render it.
|
|
*/
|
|
if (child && !BRWS_NODE_STATE_IS_SET(child, BRWS_NODE_VISIBLE))
|
|
continue;
|
|
|
|
(*m->render_tree)(child);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (BRWS_NODE_STATE_IS_SET(tree, BRWS_NODE_SELECTED))
|
|
(*m->render_node)(tree, TRUE);
|
|
else
|
|
(*m->render_node)(tree, FALSE);
|
|
|
|
if (BRWS_NODE_STATE_IS_SET(tree, BRWS_NODE_EXPANDED))
|
|
{
|
|
/*
|
|
* Render child nodes
|
|
*
|
|
* Render procs should check for (child == NULL)
|
|
*/
|
|
for (i=0, child = (*m->get_child)(tree, 0);
|
|
(i < num_child);
|
|
child = (*m->get_child)(tree, ++i))
|
|
{
|
|
/*
|
|
* If this child node is not supposed to be seen,
|
|
* don't render it.
|
|
* The render_tree method (this routine we're in at
|
|
* this moment) actually checks for this, but ...
|
|
*/
|
|
if (child && !BRWS_NODE_STATE_IS_SET(child, BRWS_NODE_VISIBLE))
|
|
continue;
|
|
|
|
(*m->render_line)(tree, child);
|
|
(*m->render_tree)(child);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Draw collapsed subtree feedback
|
|
*/
|
|
if (num_child > 0)
|
|
{
|
|
draw_collapsed_feedback(tree);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
* Render a glyph element of a node
|
|
*/
|
|
static void
|
|
render_glyph_elm
|
|
(
|
|
VNode node,
|
|
VNodeElm glyph_elm,
|
|
int hilite
|
|
)
|
|
{
|
|
Display *dpy;
|
|
Widget draw_area;
|
|
Vwr b;
|
|
BrowserUiObj ui;
|
|
GC gc;
|
|
Pixmap image;
|
|
|
|
if (!node || !glyph_elm)
|
|
return;
|
|
|
|
/*
|
|
* Get handle to browser, draw area widget, ui info,
|
|
* display
|
|
*/
|
|
b = node->browser;
|
|
ui = aob_ui_from_browser(b);
|
|
draw_area = brws_draw_area(b);
|
|
dpy = XtDisplay(draw_area);
|
|
|
|
gc = ui->normal_gc;
|
|
|
|
/*
|
|
* Get handle to pixmap
|
|
*/
|
|
image = (Pixmap)glyph_elm->data;
|
|
|
|
/*
|
|
* Render element by copying the image from pixmap to
|
|
* draw area
|
|
*/
|
|
XCopyArea(dpy, image, XtWindow(draw_area), gc,
|
|
0, 0,
|
|
glyph_elm->width, glyph_elm->height,
|
|
glyph_elm->x, glyph_elm->y);
|
|
}
|
|
|
|
/*
|
|
* Render a string element of a node
|
|
*/
|
|
static void
|
|
render_str_elm
|
|
(
|
|
VNode node,
|
|
VNodeElm str_elm,
|
|
int hilite
|
|
)
|
|
{
|
|
Display *dpy;
|
|
Widget draw_area;
|
|
XFontStruct *sm_font;
|
|
Vwr b;
|
|
BrowserUiObj ui;
|
|
GC gc;
|
|
int font_ascent;
|
|
char *str;
|
|
|
|
if (!node || !str_elm)
|
|
return;
|
|
|
|
/*
|
|
* Get handle to browser, ui handle, draw area
|
|
* display, font ascent
|
|
*/
|
|
b = node->browser;
|
|
ui = aob_ui_from_browser(b);
|
|
draw_area = brws_draw_area(b);
|
|
dpy = XtDisplay(draw_area);
|
|
sm_font = ui->sm_font;
|
|
font_ascent = sm_font->max_bounds.ascent;
|
|
|
|
/*
|
|
* Select GC depending on hilite flag
|
|
*/
|
|
if (hilite)
|
|
{
|
|
gc = ui->select_gc;
|
|
}
|
|
else {
|
|
gc = ui->normal_gc;
|
|
}
|
|
|
|
/*
|
|
* String to render
|
|
*/
|
|
str = (char *)str_elm->data;
|
|
|
|
/*
|
|
* Render string element on draw area
|
|
*/
|
|
XDrawImageString(dpy, XtWindow(draw_area), gc,
|
|
str_elm->x, str_elm->y + font_ascent,
|
|
str, strlen(str));
|
|
}
|
|
|
|
/*
|
|
* Draw one node on the offscreen pixmap.
|
|
* The hilite boolean flag indicates whether the node should be drawn
|
|
* hilited or not.
|
|
*/
|
|
static void
|
|
render_node
|
|
(
|
|
ViewerNode *node,
|
|
int hilite
|
|
)
|
|
{
|
|
Display *dpy;
|
|
Widget draw_area;
|
|
Viewer *b;
|
|
AB_OBJ *obj;
|
|
VMethods m;
|
|
VNode parent;
|
|
ViewerNodeElm *elm;
|
|
VElmMethods *elm_methods;
|
|
int elm_shown;
|
|
int cur_height = 0,
|
|
cur_width = 0,
|
|
cur_x_offset = 0,
|
|
cur_y_offset = 0,
|
|
i;
|
|
|
|
if (!node)
|
|
return;
|
|
|
|
b = node->browser;
|
|
m = b->methods;
|
|
|
|
obj = (AB_OBJ *)node->obj_data;
|
|
|
|
elm_shown = browser_get_elm_shown(b);
|
|
|
|
draw_area = brws_draw_area(b);
|
|
|
|
if (!draw_area)
|
|
return;
|
|
|
|
dpy = XtDisplay(draw_area);
|
|
|
|
elm = node->elements;
|
|
elm_methods = node->elm_methods;
|
|
|
|
if (!BRWS_NODE_STATE_IS_SET(node, BRWS_NODE_VISIBLE))
|
|
return;
|
|
|
|
parent = (*m->get_parent)(node);
|
|
while (parent)
|
|
{
|
|
if (!BRWS_NODE_STATE_IS_SET(parent, BRWS_NODE_VISIBLE))
|
|
return;
|
|
|
|
parent = (*m->get_parent)(parent);
|
|
}
|
|
|
|
/*
|
|
* Don't render this node if it is outside the window
|
|
*/
|
|
if (node->x > 32766 || node->y > 32766)
|
|
return;
|
|
|
|
if (!hilite)
|
|
{
|
|
XClearArea(dpy, XtWindow(draw_area),
|
|
node->x, node->y,
|
|
node->width, node->height, FALSE);
|
|
}
|
|
|
|
for (i=0; i < node->num_elements; ++i)
|
|
{
|
|
if (elm_shown & (1L << i))
|
|
{
|
|
(*(elm_methods[i]->render))(node, &elm[i], hilite);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Draw a bounding rectangle for the icon.
|
|
*/
|
|
if (hilite)
|
|
render_node_bbox(node);
|
|
|
|
}
|
|
|
|
/*
|
|
* Draw the line between the node's icon and its parent's icon.
|
|
*/
|
|
static void
|
|
render_line(
|
|
ViewerNode *parent,
|
|
ViewerNode *child
|
|
)
|
|
{
|
|
BrowserUiObjects *ui;
|
|
BrowserProperties *props;
|
|
Viewer *b;
|
|
ViewerMethods *m;
|
|
ViewerNode *real_parent;
|
|
ViewerNode *cur_child;
|
|
Widget draw_area;
|
|
GC line_gc;
|
|
XGCValues gcvalues;
|
|
XPoint xp[3];
|
|
int num_child,
|
|
num_visible_siblings = 0,
|
|
i;
|
|
|
|
if (!parent || !child)
|
|
return;
|
|
|
|
/*
|
|
* If the child node is not supposed to be seen, don't
|
|
* draw a line to it.
|
|
*/
|
|
if (!BRWS_NODE_STATE_IS_SET(child, BRWS_NODE_VISIBLE))
|
|
return;
|
|
|
|
b = child->browser;
|
|
m = b->methods;
|
|
props = aob_browser_properties(b);
|
|
draw_area = brws_draw_area(b);
|
|
|
|
if (!draw_area)
|
|
return;
|
|
|
|
ui = aob_ui_from_browser(b);
|
|
line_gc = ui->line_gc;
|
|
|
|
gcvalues.line_style = LineSolid;
|
|
XChangeGC(XtDisplay(draw_area), line_gc, GCLineStyle, &gcvalues);
|
|
|
|
/*
|
|
* Don't render this link if it is outside the window
|
|
*/
|
|
if (child->x > 32766 || child->y > 32766 ||
|
|
parent->x > 32766 || parent->y > 32766)
|
|
return;
|
|
|
|
real_parent = (*m->get_parent)(child);
|
|
|
|
num_child = (*m->get_num_children)(real_parent);
|
|
|
|
for (i=0, cur_child = (*m->get_child)(real_parent, 0);
|
|
(i < num_child);
|
|
cur_child = (*m->get_child)(real_parent, ++i))
|
|
{
|
|
if (cur_child == child)
|
|
continue;
|
|
|
|
if (cur_child &&
|
|
BRWS_NODE_STATE_IS_SET(cur_child, BRWS_NODE_VISIBLE))
|
|
++num_visible_siblings;
|
|
}
|
|
|
|
if (props->orientation == BRWS_VERTICAL)
|
|
{
|
|
/*
|
|
* Tree orientation is vertical
|
|
*/
|
|
if (num_visible_siblings == 0)
|
|
{
|
|
/*
|
|
* This child is the only child of the parent.
|
|
* Draw just one line, centered, from child to parent
|
|
* It is up to the compute procs to make sure that the
|
|
* child and parent are already centered on top of one
|
|
* another.
|
|
*/
|
|
xp[0].x = child->x + child->width/2;
|
|
xp[0].y = child->y - BRWS_NODE_LINK_GAP;
|
|
|
|
xp[1].x = child->x + child->width/2;
|
|
xp[1].y = parent->y + parent->height + BRWS_NODE_LINK_GAP;
|
|
|
|
XDrawLines(XtDisplay(draw_area), XtWindow(draw_area), line_gc, xp, 2, CoordModeOrigin);
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Multiple siblings exist for the parent.
|
|
* 2 lines (3 points) are drawn per child:
|
|
* The one extra XDrawLine is unfortunately repeated
|
|
* for every child unnecessarily. It is for drawing the
|
|
* line from the parent to the subtree.
|
|
*/
|
|
xp[0].x = child->x + child->width/2;
|
|
xp[0].y = child->y - BRWS_NODE_LINK_GAP;
|
|
|
|
xp[1].x = child->x + child->width/2;
|
|
xp[1].y = parent->y + parent->height +
|
|
(BRWS_NODE_LINK_GAP + BRWS_NODE_SUBTREE_GAP);
|
|
|
|
xp[2].x = parent->x + parent->width/2;
|
|
xp[2].y = parent->y + parent->height +
|
|
(BRWS_NODE_LINK_GAP + BRWS_NODE_SUBTREE_GAP);
|
|
|
|
XDrawLines(XtDisplay(draw_area), XtWindow(draw_area), line_gc, xp, 3, CoordModeOrigin);
|
|
|
|
xp[0].x = xp[1].x = parent->x + parent->width/2;
|
|
xp[0].y = parent->y + parent->height + BRWS_NODE_LINK_GAP;
|
|
xp[1].y = xp[0].y + BRWS_NODE_SUBTREE_GAP;
|
|
|
|
XDrawLines(XtDisplay(draw_area), XtWindow(draw_area), line_gc, xp, 2, CoordModeOrigin);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Tree orientation is vertical
|
|
*/
|
|
if (num_visible_siblings == 0)
|
|
{
|
|
/*
|
|
* This child is the only child of the parent.
|
|
* Draw just one line, centered, from child to parent
|
|
* It is up to the compute procs to make sure that the
|
|
* child and parent are already centered on top of one
|
|
* another.
|
|
*/
|
|
xp[0].x = child->x - BRWS_NODE_LINK_GAP;
|
|
xp[0].y = child->y + child->height/2;
|
|
|
|
xp[1].x = parent->x + parent->width + BRWS_NODE_LINK_GAP;
|
|
xp[1].y = child->y + child->height/2;
|
|
|
|
XDrawLines(XtDisplay(draw_area), XtWindow(draw_area), line_gc, xp, 2, CoordModeOrigin);
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Multiple siblings exist for the parent.
|
|
* 2 lines (3 points) are drawn per child:
|
|
* The one extra XDrawLine is unfortunately repeated
|
|
* for every child unnecessarily. It is for drawing the
|
|
* line from the parent to the subtree.
|
|
*/
|
|
xp[0].x = child->x - BRWS_NODE_LINK_GAP;
|
|
xp[0].y = child->y + child->height/2;
|
|
|
|
xp[1].x = parent->x + parent->width +
|
|
(BRWS_NODE_LINK_GAP + BRWS_NODE_SUBTREE_GAP);
|
|
xp[1].y = child->y + child->height/2;
|
|
|
|
xp[2].x = parent->x + parent->width +
|
|
(BRWS_NODE_LINK_GAP + BRWS_NODE_SUBTREE_GAP);
|
|
xp[2].y = parent->y + parent->height/2;
|
|
|
|
XDrawLines(XtDisplay(draw_area), XtWindow(draw_area), line_gc, xp, 3, CoordModeOrigin);
|
|
|
|
xp[0].x = parent->x + parent->width + BRWS_NODE_LINK_GAP;
|
|
xp[1].x = xp[0].x + BRWS_NODE_SUBTREE_GAP;
|
|
xp[0].y = xp[1].y = parent->y + parent->height/2;
|
|
|
|
XDrawLines(XtDisplay(draw_area), XtWindow(draw_area), line_gc, xp, 2, CoordModeOrigin);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Recursively calls itself to determine which node the point
|
|
* is in.
|
|
*/
|
|
static VNode
|
|
locate_node
|
|
(
|
|
VNode tree,
|
|
int x,
|
|
int y
|
|
)
|
|
{
|
|
ViewerMethods *m;
|
|
VNode child;
|
|
int i, num_child;
|
|
|
|
if (!tree)
|
|
return (NULL);
|
|
|
|
if (!BRWS_NODE_STATE_IS_SET(tree, BRWS_NODE_VISIBLE))
|
|
return (NULL);
|
|
|
|
/*
|
|
* Return the root if (x,y) is within the root
|
|
* node
|
|
*/
|
|
if (x >= tree->x &&
|
|
x <= tree->x + tree->width &&
|
|
y >= tree->y &&
|
|
y <= tree->y + tree->height)
|
|
return tree;
|
|
|
|
/*
|
|
* If this node is collapsed, don't bother
|
|
* traversing it's children
|
|
*/
|
|
if (!BRWS_NODE_STATE_IS_SET(tree, BRWS_NODE_EXPANDED))
|
|
return (NULL);
|
|
|
|
m = BNODE_METHODS(tree);
|
|
|
|
num_child = (*m->get_num_children)(tree);
|
|
|
|
/*
|
|
* Recursively look for a 'match' in each child
|
|
* The locate proc should check for (child == NULL)
|
|
*/
|
|
for (i=0, child = (*m->get_child)(tree, 0);
|
|
(i < num_child);
|
|
child = (*m->get_child)(tree, ++i))
|
|
{
|
|
VNode tmp;
|
|
|
|
if (tmp = (*m->locate_node)(child, x, y))
|
|
return tmp;
|
|
}
|
|
|
|
return (NULL);
|
|
}
|
|
|
|
static unsigned long
|
|
locate_elements(
|
|
VNode vnode,
|
|
int x,
|
|
int y
|
|
)
|
|
{
|
|
Vwr v;
|
|
VNodeElm elm;
|
|
int i,
|
|
num_elm,
|
|
elm_shown;
|
|
unsigned long ret_mask = 0;
|
|
|
|
if (!vnode || (x < 0) || (y < 0))
|
|
{
|
|
return (ret_mask);
|
|
}
|
|
|
|
if ((x < vnode->x) || (x > vnode->x + vnode->width) ||
|
|
(y < vnode->y) || (y > vnode->y + vnode->height))
|
|
{
|
|
return (ret_mask);
|
|
}
|
|
|
|
v = vnode->browser;
|
|
elm_shown = browser_get_elm_shown(v);
|
|
elm = vnode->elements;
|
|
num_elm = vnode->num_elements;
|
|
|
|
for (i=0; i < num_elm; ++i)
|
|
{
|
|
if (!(elm_shown & (1L << i)) ||
|
|
(y < elm[i].y -
|
|
BRWS_ELM_BBOX_MARGIN - BRWS_ELM_BORDER_WIDTH) ||
|
|
(y > elm[i].y + elm[i].height +
|
|
BRWS_ELM_BBOX_MARGIN + BRWS_ELM_BORDER_WIDTH))
|
|
{
|
|
continue;
|
|
}
|
|
ret_mask |= (1L << i);
|
|
}
|
|
|
|
return (ret_mask);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Draw the zoom out feed back on the canvas.
|
|
*/
|
|
static void
|
|
draw_zoom_out
|
|
(
|
|
Viewer *b
|
|
)
|
|
{
|
|
BrowserUiObjects *ui_handle;
|
|
int x, y, width, height;
|
|
Widget draw_area;
|
|
|
|
draw_area = brws_draw_area(b);
|
|
|
|
XtVaGetValues(draw_area,
|
|
XtNx, &x,
|
|
XtNy, &y,
|
|
XtNwidth, &width,
|
|
XtNheight, &height,
|
|
NULL);
|
|
|
|
ui_handle = aob_ui_from_browser(b);
|
|
|
|
while (width > 0 || height > 0)
|
|
{
|
|
/*
|
|
* Draw the rectangle.
|
|
*/
|
|
XDrawRectangle(XtDisplay(draw_area), XtWindow(draw_area),
|
|
ui_handle->normal_gc, x, y, width, height);
|
|
XClearArea(XtDisplay(draw_area), XtWindow(draw_area),
|
|
x-4, y-4, width+8, height+8, FALSE);
|
|
x+=4; y+=4; width-=8; height-=8;
|
|
if (width < 0)
|
|
width = 0;
|
|
if (height < 0)
|
|
height = 0;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Draw the zoom in feedback on the canvas.
|
|
*/
|
|
static void
|
|
draw_zoom_in
|
|
(
|
|
Viewer *b,
|
|
ViewerNode *node
|
|
)
|
|
{
|
|
BrowserUiObjects *ui_handle;
|
|
Widget draw_area;
|
|
int x, y, width, height,
|
|
canvas_x, canvas_y,
|
|
canvas_width, canvas_height;
|
|
|
|
if (!node)
|
|
return;
|
|
|
|
draw_area = brws_draw_area(b);
|
|
|
|
XtVaGetValues(draw_area,
|
|
XtNx, &canvas_x,
|
|
XtNy, &canvas_y,
|
|
XtNwidth, &canvas_width,
|
|
XtNheight, &canvas_height,
|
|
NULL);
|
|
|
|
x = node->x + node->width/2;
|
|
y = node->y + node->height/2;
|
|
width = 2;
|
|
height = 2;
|
|
|
|
ui_handle = aob_ui_from_browser(b);
|
|
|
|
while (width < canvas_width || height < canvas_height)
|
|
{
|
|
/*
|
|
* Draw the rectangle.
|
|
*/
|
|
XDrawRectangle(XtDisplay(draw_area), XtWindow(draw_area),
|
|
ui_handle->normal_gc, x, y, width, height);
|
|
|
|
x-=4; y-=4; width+=8; height+=8;
|
|
if (width > canvas_width)
|
|
width = canvas_width;
|
|
if (height > canvas_height)
|
|
height = canvas_height;
|
|
if (x < canvas_x)
|
|
x = canvas_x;
|
|
if (y < canvas_y)
|
|
y = canvas_y;
|
|
|
|
/*
|
|
* Erase the rectangle.
|
|
*/
|
|
XClearArea(XtDisplay(draw_area), XtWindow(draw_area),
|
|
x, y, width, height, FALSE);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Draw bounding box of one node
|
|
*/
|
|
static void
|
|
render_node_bbox
|
|
(
|
|
ViewerNode *node
|
|
)
|
|
{
|
|
XFontStruct *sm_font;
|
|
Display *dpy;
|
|
Widget draw_area;
|
|
Viewer *b;
|
|
BrowserUiObjects *ui;
|
|
ViewerNodeElm *elm;
|
|
unsigned long elm_shown;
|
|
Pixel hc, bg;
|
|
Pixmap hp;
|
|
GC highlightGC;
|
|
XGCValues gcv;
|
|
XtGCMask gcm;
|
|
int num_elm_shown, i, font_ascent;
|
|
|
|
if (!node)
|
|
return;
|
|
|
|
b = node->browser;
|
|
ui = aob_ui_from_browser(b);
|
|
num_elm_shown = browser_num_elm_shown(b);
|
|
draw_area = brws_draw_area(b);
|
|
dpy = XtDisplay(draw_area);
|
|
elm = node->elements;
|
|
sm_font = ui->sm_font;
|
|
font_ascent = sm_font->max_bounds.ascent;
|
|
elm_shown = browser_get_elm_shown(b);
|
|
|
|
XtVaGetValues(draw_area,
|
|
XmNbackground, &bg,
|
|
XmNhighlightColor, &hc,
|
|
XmNhighlightPixmap, &hp,
|
|
NULL);
|
|
|
|
gcm = GCForeground | GCBackground | GCLineWidth;
|
|
gcv.line_width = BRWS_ELM_BORDER_WIDTH;
|
|
gcv.foreground = hc;
|
|
gcv.background = bg;
|
|
|
|
gcv.line_style = LineSolid;
|
|
gcm |= GCLineStyle;
|
|
|
|
highlightGC = XtGetGC(draw_area, gcm, &gcv);
|
|
|
|
/*
|
|
* Subtract 1 from width and height because XDrawRectangle draws
|
|
* the outline of the rectangle.
|
|
*/
|
|
XDrawRectangle(dpy, XtWindow(draw_area), highlightGC,
|
|
node->x + (BRWS_ELM_BORDER_WIDTH - 1),
|
|
node->y + (BRWS_ELM_BORDER_WIDTH - 1),
|
|
node->width - BRWS_ELM_BORDER_WIDTH,
|
|
node->height - BRWS_ELM_BORDER_WIDTH);
|
|
}
|
|
|
|
/*
|
|
* Erase the canvas of a browser.
|
|
*/
|
|
void
|
|
erase_viewer(Viewer *v)
|
|
{
|
|
XRectangle w_rect; /* widget width,height,x,y */
|
|
Widget draw_area;
|
|
|
|
draw_area = brws_draw_area(v);
|
|
|
|
XtVaGetValues(draw_area,
|
|
XtNwidth, &(w_rect.width),
|
|
XtNheight, &(w_rect.height),
|
|
NULL);
|
|
|
|
XClearArea(XtDisplay(draw_area), XtWindow(draw_area),
|
|
0, 0,
|
|
w_rect.width,
|
|
w_rect.height,
|
|
FALSE);
|
|
}
|
|
|
|
/*
|
|
* Erase a node.
|
|
*/
|
|
static void
|
|
erase_node
|
|
(
|
|
ViewerNode *node
|
|
)
|
|
{
|
|
Viewer *b;
|
|
Widget draw_area;
|
|
|
|
if (!node)
|
|
return;
|
|
|
|
b = node->browser;
|
|
|
|
draw_area = brws_draw_area(b);
|
|
|
|
XClearArea(XtDisplay(draw_area), XtWindow(draw_area), node->x, node->y,
|
|
node->width, node->height, FALSE);
|
|
}
|
|
|
|
static void
|
|
draw_collapsed_feedback
|
|
(
|
|
VNode node
|
|
)
|
|
{
|
|
Vwr v;
|
|
BrowserUiObj ui;
|
|
BrowserProps props;
|
|
Widget draw_area;
|
|
Display *dpy;
|
|
GC gc;
|
|
char dash_list[2] = {BRWS_DASH_WIDTH, BRWS_DASH_WIDTH};
|
|
XGCValues gcvalues;
|
|
|
|
if (!node)
|
|
return;
|
|
|
|
v = node->browser;
|
|
ui = aob_ui_from_browser(v);
|
|
props = aob_browser_properties(v);
|
|
draw_area = brws_draw_area(v);
|
|
dpy = XtDisplay(draw_area);
|
|
gc = ui->normal_gc;
|
|
|
|
gcvalues.line_style = LineOnOffDash;
|
|
XChangeGC(dpy, gc, GCLineStyle, &gcvalues);
|
|
|
|
XSetDashes(dpy, gc, 0, dash_list, 2);
|
|
if (props->orientation == BRWS_HORIZONTAL)
|
|
{
|
|
/*
|
|
* Horizontal
|
|
*/
|
|
|
|
XDrawLine(dpy, XtWindow(draw_area), gc,
|
|
node->x + node->width + BRWS_NODE_LINK_GAP,
|
|
node->y + (node->height/2),
|
|
node->x + node->width
|
|
+ BRWS_NODE_LINK_GAP
|
|
+ (((2 * BRWS_NUM_DASHES) - 1) * BRWS_DASH_WIDTH),
|
|
node->y + (node->height/2));
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Vertical
|
|
*/
|
|
XDrawLine(dpy, XtWindow(draw_area), gc,
|
|
node->x + (node->width/2),
|
|
node->y + node->height + BRWS_NODE_LINK_GAP,
|
|
node->x + (node->width/2),
|
|
node->y + node->height
|
|
+ BRWS_NODE_LINK_GAP
|
|
+ (((2 * BRWS_NUM_DASHES) - 1) * BRWS_DASH_WIDTH));
|
|
}
|
|
}
|
|
|
|
static void
|
|
compute_collapsed_feedback
|
|
(
|
|
VNode node,
|
|
int *max_x,
|
|
int *max_y
|
|
)
|
|
{
|
|
Vwr v;
|
|
BrowserProps props;
|
|
|
|
if (!node)
|
|
return;
|
|
|
|
v = node->browser;
|
|
props = aob_browser_properties(v);
|
|
|
|
if (props->orientation == BRWS_HORIZONTAL)
|
|
{
|
|
/*
|
|
* Horizontal
|
|
*/
|
|
*max_x += BRWS_NODE_LINK_GAP
|
|
+ (((2 * BRWS_NUM_DASHES) - 1) * BRWS_DASH_WIDTH);
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Vertical
|
|
*/
|
|
*max_y += BRWS_NODE_LINK_GAP
|
|
+ (((2 * BRWS_NUM_DASHES) - 1) * BRWS_DASH_WIDTH);
|
|
}
|
|
}
|