mirror of
git://git.code.sf.net/p/cdesktopenv/code
synced 2025-03-09 15:50:02 +00:00
1883 lines
37 KiB
C
1883 lines
37 KiB
C
/*
|
|
* CDE - Common Desktop Environment
|
|
*
|
|
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
|
|
*
|
|
* These libraries and programs are free software; you can
|
|
* redistribute them and/or modify them under the terms of the GNU
|
|
* Lesser General Public License as published by the Free Software
|
|
* Foundation; either version 2 of the License, or (at your option)
|
|
* any later version.
|
|
*
|
|
* These libraries and programs are distributed in the hope that
|
|
* they will be useful, but WITHOUT ANY WARRANTY; without even the
|
|
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
* PURPOSE. See the GNU Lesser General Public License for more
|
|
* details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with these librararies and programs; if not, write
|
|
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
|
|
* Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
/*
|
|
* $XConsortium: brws_utils.c /main/4 1996/10/02 10:59:00 drk $
|
|
*
|
|
* @(#)brws_utils.c 1.54 29 Mar 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 <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <X11/Xlib.h>
|
|
#include <Xm/Xm.h>
|
|
#include <Xm/DrawingA.h>
|
|
#include <ab_private/util.h>
|
|
#include <ab_private/obj.h>
|
|
#include <ab_private/trav.h>
|
|
#include <ab_private/brwsP.h>
|
|
#include <ab_private/proj.h>
|
|
#include <ab_private/x_util.h>
|
|
#include <ab_private/istr.h>
|
|
|
|
static ABBrowser get_browser_for_win(
|
|
AB_OBJ *project,
|
|
Window w
|
|
);
|
|
|
|
static void select_node(
|
|
VNode selected_node
|
|
);
|
|
|
|
static void deselect_node(
|
|
VNode selected_node
|
|
);
|
|
|
|
static void toggle_select_node(
|
|
VNode selected_node
|
|
);
|
|
|
|
static int select_fn(
|
|
VNode node
|
|
);
|
|
|
|
static int collapsed_fn(
|
|
VNode module
|
|
);
|
|
|
|
static void r_deselect_all_nodes(
|
|
VNode tree,
|
|
int flag
|
|
);
|
|
|
|
static void draw_area_snap (
|
|
Vwr v
|
|
);
|
|
|
|
static Boolean clipWindowWorkProc(
|
|
XtPointer client_data
|
|
);
|
|
|
|
static void clipwindowEventHandler(
|
|
Widget widget,
|
|
XtPointer client_data,
|
|
XEvent *event,
|
|
Boolean *cont_dispatch
|
|
);
|
|
|
|
static void clipwindowResizeCB(
|
|
Widget w,
|
|
XtPointer client_data,
|
|
XtPointer call_data
|
|
);
|
|
|
|
static char *ab_browser_project_name = "*module_name";
|
|
|
|
static int
|
|
select_fn(
|
|
VNode vnode
|
|
)
|
|
{
|
|
if (BRWS_NODE_STATE_IS_SET(vnode, BRWS_NODE_SELECTED))
|
|
return (1);
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
collapsed_fn(
|
|
VNode module
|
|
)
|
|
{
|
|
if (!BRWS_NODE_STATE_IS_SET(module, BRWS_NODE_EXPANDED))
|
|
return (1);
|
|
|
|
return (0);
|
|
}
|
|
|
|
|
|
static ABBrowser
|
|
get_browser_for_win(
|
|
AB_OBJ *project,
|
|
Window w
|
|
)
|
|
{
|
|
ABBrowser cur_browser;
|
|
Widget draw_area;
|
|
|
|
if (!project || !w)
|
|
return (NULL);
|
|
|
|
cur_browser = (ABBrowser)project->info.project.browsers;
|
|
|
|
while (cur_browser)
|
|
{
|
|
draw_area = brws_draw_area(cur_browser->module);
|
|
|
|
if ( draw_area && (w == XtWindow(draw_area)) )
|
|
return(cur_browser);
|
|
|
|
cur_browser = cur_browser->next;
|
|
}
|
|
|
|
return ((ABBrowser)NULL);
|
|
}
|
|
|
|
BOOL
|
|
aob_is_browser_win(
|
|
AB_OBJ *project,
|
|
Window w
|
|
)
|
|
{
|
|
return(get_browser_for_win(project, w) != NULL);
|
|
}
|
|
|
|
AB_OBJ *
|
|
aob_get_object_from_xy(
|
|
AB_OBJ *project,
|
|
Window w,
|
|
int x,
|
|
int y
|
|
)
|
|
{
|
|
ABBrowser cur_browser;
|
|
VNode found_node;
|
|
|
|
if (!project || !w)
|
|
return (NULL);
|
|
|
|
cur_browser = get_browser_for_win(project, w);
|
|
if (cur_browser != NULL)
|
|
{
|
|
found_node = vwr_locate_node(cur_browser->module, x, y);
|
|
|
|
if (found_node)
|
|
{
|
|
return((AB_OBJ *)found_node->obj_data);
|
|
}
|
|
}
|
|
return (NULL);
|
|
}
|
|
|
|
/*
|
|
* aob_find_bnode
|
|
* Searches for the ViewerNode on the AB_OBJ corresponding to the
|
|
* passed Viewer
|
|
*/
|
|
ViewerNode *
|
|
aob_find_bnode
|
|
(
|
|
AB_OBJ *obj,
|
|
Viewer *v
|
|
)
|
|
{
|
|
ViewerNode *bnodes,
|
|
*found = NULL;
|
|
ViewerMethods *m;
|
|
|
|
if (!v || !obj)
|
|
return (NULL);
|
|
|
|
m = v->methods;
|
|
|
|
if (!m)
|
|
return (NULL);
|
|
|
|
bnodes = (*m->get_viewer_data)(obj);
|
|
|
|
for (found = bnodes; found && (found->browser != v); found = found->next);
|
|
|
|
return (found);
|
|
}
|
|
|
|
/*
|
|
* Returns project from browser object
|
|
*/
|
|
AB_OBJ *
|
|
aob_project_from_browser(
|
|
Viewer *b
|
|
)
|
|
{
|
|
return (b ? (AB_OBJ *)b->obj_data : NULL);
|
|
}
|
|
|
|
/*
|
|
* Returns browser properties
|
|
*/
|
|
BrowserProperties *
|
|
aob_browser_properties(
|
|
Viewer *b
|
|
)
|
|
{
|
|
return (b ? (BrowserProperties *)b->properties : NULL);
|
|
}
|
|
|
|
/*
|
|
* Copies the properties of one browser to another
|
|
*/
|
|
void
|
|
aob_copy_props(
|
|
Viewer *from,
|
|
Viewer *to
|
|
)
|
|
{
|
|
BrowserProperties *from_prop,
|
|
*to_prop;
|
|
if (!from || !to)
|
|
return;
|
|
|
|
from_prop = aob_browser_properties(from);
|
|
to_prop = aob_browser_properties(to);
|
|
/*
|
|
* These are the only ones that matter now
|
|
*/
|
|
to_prop->orientation = from_prop->orientation;
|
|
to_prop->elements_shown = from_prop->elements_shown;
|
|
}
|
|
|
|
/*
|
|
* Get the UI handle from a browser
|
|
*/
|
|
BrowserUiObjects *
|
|
aob_ui_from_browser
|
|
(
|
|
Viewer *b
|
|
)
|
|
{
|
|
return (b ? (BrowserUiObjects *)b->ui_handle : NULL);
|
|
}
|
|
|
|
/*
|
|
* Get the shell widget for a browser
|
|
*/
|
|
Widget
|
|
aob_ui_shell
|
|
(
|
|
Viewer *b
|
|
)
|
|
{
|
|
BrowserUiObjects *ui;
|
|
|
|
if (!b)
|
|
return (NULL);
|
|
|
|
ui = aob_ui_from_browser(b);
|
|
|
|
return(ui ? ui->shell : NULL);
|
|
}
|
|
|
|
/*
|
|
* Get the draw area widget for a browser
|
|
*/
|
|
Widget
|
|
brws_draw_area
|
|
(
|
|
Viewer *b
|
|
)
|
|
{
|
|
VMethods m;
|
|
|
|
if (!b)
|
|
return (NULL);
|
|
|
|
m = b->methods;
|
|
|
|
return ((Widget)(*m->get_drawarea)(b));
|
|
}
|
|
|
|
/*
|
|
* Get the elements of a browser node
|
|
*/
|
|
ViewerNodeElm *
|
|
aob_bnode_elements(
|
|
ViewerNode *bnode
|
|
)
|
|
{
|
|
if (!bnode)
|
|
return (NULL);
|
|
|
|
return ((ViewerNodeElm *)bnode->elements);
|
|
}
|
|
|
|
/*
|
|
* Get the bit vector which contains info on
|
|
* what node elements of the bnodes are to be shown
|
|
*/
|
|
unsigned long
|
|
browser_get_elm_shown
|
|
(
|
|
Viewer *b
|
|
)
|
|
{
|
|
BrowserProperties *props;
|
|
|
|
props = aob_browser_properties(b);
|
|
|
|
return(props ? props->elements_shown : (unsigned long)NULL);
|
|
}
|
|
|
|
/*
|
|
* Return the count of node elements that are
|
|
* shown for the browser
|
|
*/
|
|
int
|
|
browser_num_elm_shown
|
|
(
|
|
Viewer *b
|
|
)
|
|
{
|
|
int i, count = 0;
|
|
unsigned long elm_shown;
|
|
|
|
elm_shown = browser_get_elm_shown(b);
|
|
|
|
for (i = 0; i < BRWS_NUM_ELM; ++i)
|
|
{
|
|
count += (elm_shown & 1);
|
|
|
|
elm_shown = elm_shown >> 1;
|
|
}
|
|
|
|
return (count);
|
|
}
|
|
|
|
|
|
/*
|
|
* Browser node selection
|
|
*/
|
|
void
|
|
brws_select
|
|
(
|
|
AB_OBJ *obj
|
|
)
|
|
{
|
|
AB_OBJ *project;
|
|
ABBrowser b_list;
|
|
AB_OBJ *root_obj = obj;
|
|
VNode selected_nodes;
|
|
Widget draw_area;
|
|
ViewerMethods *m;
|
|
|
|
if (!obj)
|
|
return;
|
|
|
|
/*
|
|
* Is this necessary ?
|
|
*/
|
|
root_obj = obj_get_root(obj);
|
|
|
|
if (!root_obj)
|
|
return;
|
|
|
|
selected_nodes = (VNode)root_obj->browser_data;
|
|
|
|
if (!selected_nodes)
|
|
return;
|
|
|
|
/*
|
|
* Get project/browser list
|
|
project = obj_get_project(obj);
|
|
b_list = (ABBrowser)project->info.project.browsers;
|
|
*/
|
|
|
|
while (selected_nodes)
|
|
{
|
|
BrowserProps prop =
|
|
aob_browser_properties(selected_nodes->browser);
|
|
|
|
if (prop->active)
|
|
select_node(selected_nodes);
|
|
|
|
selected_nodes = selected_nodes->next;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Browser node de-selection
|
|
*/
|
|
void
|
|
brws_deselect
|
|
(
|
|
AB_OBJ *obj
|
|
)
|
|
{
|
|
AB_OBJ *project;
|
|
ABBrowser b_list;
|
|
AB_OBJ *root_obj = obj;
|
|
VNode selected_nodes;
|
|
Widget draw_area;
|
|
ViewerMethods *m;
|
|
|
|
if (!obj)
|
|
return;
|
|
|
|
/*
|
|
* Is this necessary ?
|
|
*/
|
|
root_obj = obj_get_root(obj);
|
|
|
|
if (!root_obj)
|
|
return;
|
|
|
|
selected_nodes = (VNode)root_obj->browser_data;
|
|
|
|
if (!selected_nodes)
|
|
return;
|
|
|
|
/*
|
|
* Get project/browser list
|
|
project = obj_get_project(obj);
|
|
b_list = (ABBrowser)project->info.project.browsers;
|
|
*/
|
|
|
|
while (selected_nodes)
|
|
{
|
|
BrowserProps prop =
|
|
aob_browser_properties(selected_nodes->browser);
|
|
|
|
if (prop->active)
|
|
deselect_node(selected_nodes);
|
|
|
|
selected_nodes = selected_nodes->next;
|
|
}
|
|
}
|
|
|
|
void
|
|
brws_toggle_select
|
|
(
|
|
AB_OBJ *obj
|
|
)
|
|
{
|
|
AB_OBJ *root_obj = obj;
|
|
VNode selected_nodes;
|
|
Widget draw_area;
|
|
|
|
if (!obj)
|
|
return;
|
|
|
|
root_obj = obj_get_root(obj);
|
|
|
|
if (!root_obj)
|
|
return;
|
|
|
|
selected_nodes = (VNode)root_obj->browser_data;
|
|
|
|
if (!selected_nodes)
|
|
return;
|
|
|
|
while(selected_nodes)
|
|
{
|
|
BrowserProps prop =
|
|
aob_browser_properties(selected_nodes->browser);
|
|
|
|
if (prop->active)
|
|
toggle_select_node(selected_nodes);
|
|
|
|
selected_nodes = selected_nodes->next;
|
|
}
|
|
}
|
|
|
|
void
|
|
aob_deselect_all_objects(
|
|
AB_OBJ *project
|
|
)
|
|
{
|
|
ABBrowser browsers;
|
|
|
|
if (!project)
|
|
return;
|
|
|
|
browsers = (ABBrowser)project->info.project.browsers;
|
|
|
|
while (browsers)
|
|
{
|
|
aob_deselect_all_nodes(browsers->module, TRUE);
|
|
browsers = browsers->next;
|
|
}
|
|
}
|
|
|
|
static void
|
|
select_node
|
|
(
|
|
VNode selected_node
|
|
)
|
|
{
|
|
ViewerMethods *m;
|
|
Viewer *v;
|
|
ABObj obj;
|
|
|
|
if (!selected_node)
|
|
return;
|
|
|
|
v = selected_node->browser;
|
|
m = v->methods;
|
|
|
|
BRWS_NODE_SET_STATE(selected_node, BRWS_NODE_SELECTED);
|
|
|
|
obj = (AB_OBJ *)selected_node->obj_data;
|
|
|
|
if (!brwsP_node_is_collapsed(selected_node))
|
|
(*m->render_node)(selected_node, TRUE);
|
|
}
|
|
|
|
static void
|
|
deselect_node
|
|
(
|
|
VNode selected_node
|
|
)
|
|
{
|
|
ViewerMethods *m;
|
|
Viewer *v;
|
|
ABObj obj;
|
|
|
|
if (!selected_node)
|
|
return;
|
|
|
|
v = selected_node->browser;
|
|
m = v->methods;
|
|
|
|
BRWS_NODE_UNSET_STATE(selected_node, BRWS_NODE_SELECTED);
|
|
|
|
obj = (AB_OBJ *)selected_node->obj_data;
|
|
|
|
if (!brwsP_node_is_collapsed(selected_node))
|
|
(*m->render_node)(selected_node, FALSE);
|
|
}
|
|
|
|
|
|
/*
|
|
* Deselect all the nodes in the tree.
|
|
* The flag argument is to determine whether immediate refreshing
|
|
* in needed or not.
|
|
*/
|
|
void
|
|
aob_deselect_all_nodes
|
|
(
|
|
Viewer *b,
|
|
int flag
|
|
)
|
|
{
|
|
r_deselect_all_nodes(b->current_tree, flag);
|
|
}
|
|
|
|
static void
|
|
toggle_select_node
|
|
(
|
|
VNode selected_node
|
|
)
|
|
{
|
|
AB_OBJ *obj;
|
|
Viewer *b;
|
|
ViewerMethods *m;
|
|
Widget draw_area;
|
|
|
|
if (!selected_node)
|
|
return;
|
|
|
|
b = selected_node->browser;
|
|
m = b->methods;
|
|
obj = (AB_OBJ *)selected_node->obj_data;
|
|
draw_area = brws_draw_area(b);
|
|
|
|
if (BRWS_NODE_STATE_IS_SET(selected_node, BRWS_NODE_SELECTED))
|
|
{
|
|
BRWS_NODE_UNSET_STATE(selected_node, BRWS_NODE_SELECTED);
|
|
(*m->render_node)(selected_node, FALSE);
|
|
}
|
|
else
|
|
{
|
|
BRWS_NODE_SET_STATE(selected_node, BRWS_NODE_SELECTED);
|
|
(*m->render_node)(selected_node, TRUE);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Recusively deselect all the nodes in the tree.
|
|
*/
|
|
static void
|
|
r_deselect_all_nodes
|
|
(
|
|
ViewerNode *tree,
|
|
int flag
|
|
)
|
|
{
|
|
VMethods m;
|
|
VNode child;
|
|
VNode *selected_nodes = NULL;
|
|
int i, num_child, num_selected = 0;
|
|
|
|
if (!tree)
|
|
return;
|
|
|
|
vwr_get_cond(tree, &selected_nodes,
|
|
&num_selected, select_fn);
|
|
|
|
m = BNODE_METHODS(tree);
|
|
|
|
for (i=0; i < num_selected; ++i)
|
|
{
|
|
/*
|
|
* Make node state unselected
|
|
*/
|
|
BRWS_NODE_UNSET_STATE(selected_nodes[i], BRWS_NODE_SELECTED);
|
|
|
|
/*
|
|
* If flag is set, and node is expanded (== not collapsed),
|
|
* re-render node in unselected state
|
|
*/
|
|
if (flag && !brwsP_node_is_collapsed(selected_nodes[i]))
|
|
(*m->render_node)(selected_nodes[i], FALSE);
|
|
}
|
|
|
|
if (selected_nodes)
|
|
util_free(selected_nodes);
|
|
}
|
|
|
|
void
|
|
brws_set_module_name
|
|
(
|
|
Vwr b
|
|
)
|
|
{
|
|
BrowserUiObjects *ui;
|
|
DtbBrwsMainwindowInfo instance;
|
|
AB_OBJ *module_obj = NULL;
|
|
Widget shell,
|
|
project_label;
|
|
XmString xmlabel;
|
|
char *module_name = NULL;
|
|
char title[300];
|
|
|
|
if (!b)
|
|
return;
|
|
|
|
shell = aob_ui_shell(b);
|
|
|
|
if (b->tree)
|
|
module_obj = (ABObj)b->tree->obj_data;
|
|
|
|
if (module_obj)
|
|
{
|
|
if (obj_get_file(module_obj) != NULL)
|
|
{
|
|
char *fullpath, *filename;
|
|
|
|
fullpath = obj_get_file(module_obj);
|
|
|
|
/*
|
|
* Check return value of strrchr before adding 1 to it
|
|
*/
|
|
if (filename = strrchr(fullpath, '/'))
|
|
module_name = (STRING)strdup(filename + 1);
|
|
else
|
|
module_name = (STRING)strdup(fullpath);
|
|
|
|
}
|
|
else
|
|
{
|
|
module_name = util_strsafe(obj_get_name(module_obj));
|
|
}
|
|
}
|
|
|
|
if (module_name)
|
|
{
|
|
xmlabel = XmStringCreateLocalized(module_name);
|
|
|
|
sprintf(title, "Module Browser - %s", module_name);
|
|
}
|
|
else
|
|
{
|
|
xmlabel = XmStringCreateLocalized(" ");
|
|
sprintf(title, "Module Browser");
|
|
}
|
|
|
|
XtVaSetValues(shell, XtNtitle, title, NULL);
|
|
|
|
ui = aob_ui_from_browser(b);
|
|
instance = (DtbBrwsMainwindowInfo)ui->ip;
|
|
project_label = instance->module_name;
|
|
|
|
XtVaSetValues(project_label, XmNlabelString, xmlabel, NULL);
|
|
|
|
XmStringFree(xmlabel);
|
|
|
|
}
|
|
|
|
/*
|
|
* aob_preview
|
|
* Parameters:
|
|
* obj - which object to preview in the browser
|
|
* browser_window - which browser window to do the priviewing in
|
|
*
|
|
* Assumes:
|
|
* that x_conn_fullscreen_init() was called before this function
|
|
* is called and x_conn_fullscreen_cleanup() will be called after
|
|
* this function is called.
|
|
*/
|
|
extern void
|
|
aob_preview(
|
|
ABObj obj,
|
|
Window browser_window
|
|
)
|
|
{
|
|
#define AB_BROWSER_PREVIEW_MARGIN 2
|
|
Vwr b;
|
|
VNode bnode;
|
|
Display *dpy;
|
|
Widget draw_area;
|
|
Window root, child_win;
|
|
int root_x, root_y;
|
|
|
|
if (!obj || !browser_window)
|
|
return;
|
|
|
|
bnode = (VNode)obj->browser_data;
|
|
b = bnode->browser;
|
|
draw_area = brws_draw_area(b);
|
|
|
|
/*
|
|
* Search for the relevant bnode
|
|
* - there may be more than one browser visible
|
|
*/
|
|
while(bnode && (browser_window != XtWindow(draw_area)))
|
|
{
|
|
bnode = bnode->next;
|
|
if (bnode)
|
|
{
|
|
b = bnode->browser;
|
|
draw_area = brws_draw_area(b);
|
|
}
|
|
}
|
|
|
|
if (!bnode)
|
|
return;
|
|
|
|
dpy = XtDisplay(draw_area);
|
|
root = RootWindow(dpy, DefaultScreen(dpy));
|
|
|
|
XTranslateCoordinates(dpy, browser_window, root,
|
|
bnode->x, bnode->y, &root_x, &root_y, &child_win);
|
|
|
|
root_x -= AB_BROWSER_PREVIEW_MARGIN;
|
|
root_y -= AB_BROWSER_PREVIEW_MARGIN;
|
|
|
|
x_fullscreen_preview_box(draw_area, root,
|
|
root_x,
|
|
root_y,
|
|
root_x + bnode->width +
|
|
AB_BROWSER_PREVIEW_MARGIN +
|
|
AB_BROWSER_PREVIEW_MARGIN,
|
|
root_y + bnode->height +
|
|
AB_BROWSER_PREVIEW_MARGIN +
|
|
AB_BROWSER_PREVIEW_MARGIN);
|
|
|
|
#undef AB_BROWSER_PREVIEW_MARGIN
|
|
}
|
|
|
|
void
|
|
brws_update_node(
|
|
ABObj obj
|
|
)
|
|
{
|
|
Vwr v;
|
|
VNode update_nodes = NULL;
|
|
VMethods *m;
|
|
|
|
if (!obj)
|
|
return;
|
|
|
|
|
|
update_nodes = (VNode)obj->browser_data;
|
|
|
|
while (update_nodes)
|
|
{
|
|
vwr_init_elements(update_nodes);
|
|
|
|
v = update_nodes->browser;
|
|
|
|
if (obj_is_module(obj))
|
|
{
|
|
brws_set_module_name(v);
|
|
}
|
|
|
|
erase_viewer(v);
|
|
draw_viewer(v);
|
|
|
|
update_nodes = update_nodes->next;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* brws_get_browser_for_obj()
|
|
* Returns the browser for the passed obj.
|
|
* The browser list is searched for the module that contains the passed
|
|
* object. If none is found, a new browser is created, populated with
|
|
* the module and it is returned.
|
|
*
|
|
* If obj is NULL, an empty browser is searched for.
|
|
*/
|
|
ABBrowser
|
|
brws_get_browser_for_obj(
|
|
ABObj obj
|
|
)
|
|
{
|
|
ABObj module = NULL,
|
|
proj = NULL;
|
|
ABBrowser cur_b = NULL,
|
|
b_list = NULL;
|
|
ABObj project = proj_get_project();
|
|
|
|
if (obj)
|
|
{
|
|
module = obj_get_module(obj);
|
|
proj = obj_get_project(obj);
|
|
b_list = proj ? (ABBrowser)proj->info.project.browsers : NULL;
|
|
}
|
|
else
|
|
{
|
|
b_list = project ? (ABBrowser)project->info.project.browsers : NULL;
|
|
}
|
|
|
|
for (cur_b = b_list; cur_b; cur_b = cur_b->next)
|
|
{
|
|
if (cur_b->project->tree &&
|
|
((AB_OBJ *)cur_b->project->tree->obj_data == module))
|
|
break;
|
|
}
|
|
|
|
if (!cur_b)
|
|
{
|
|
cur_b = brws_create();
|
|
cur_b->next = b_list;
|
|
if (b_list)
|
|
b_list->previous = cur_b;
|
|
|
|
if (project)
|
|
project->info.project.browsers = cur_b;
|
|
|
|
if (module)
|
|
brws_add_objects_to_browser(cur_b, module);
|
|
}
|
|
|
|
return(cur_b);
|
|
}
|
|
|
|
/*
|
|
* brws_get_browser_shell_for_obj()
|
|
* Returns the browser shell for the passed obj.
|
|
* The browser list is searched for the module that contains the passed
|
|
* object. If found, its shell is returned.
|
|
*/
|
|
Widget
|
|
brws_get_browser_shell_for_obj(
|
|
ABObj obj
|
|
)
|
|
{
|
|
ABObj module = NULL,
|
|
proj = NULL;
|
|
ABBrowser cur_b = NULL,
|
|
b_list = NULL;
|
|
ABObj project = proj_get_project();
|
|
|
|
if (!obj)
|
|
return NULL;
|
|
|
|
module = obj_get_module(obj);
|
|
proj = obj_get_project(obj);
|
|
b_list = proj ? (ABBrowser)proj->info.project.browsers : NULL;
|
|
|
|
for (cur_b = b_list; cur_b; cur_b = cur_b->next)
|
|
{
|
|
if (cur_b->project->tree &&
|
|
((AB_OBJ *)cur_b->project->tree->obj_data == module))
|
|
break;
|
|
}
|
|
|
|
if (!cur_b)
|
|
return NULL;
|
|
|
|
return(aob_ui_shell(cur_b->module));
|
|
}
|
|
|
|
int
|
|
brwsP_select_fn(
|
|
VNode vnode
|
|
)
|
|
{
|
|
if (BRWS_NODE_STATE_IS_SET(vnode, BRWS_NODE_SELECTED))
|
|
return (1);
|
|
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* Synch up the toplevel and detailed view of browser
|
|
* The browser consists of the toplevel view and the
|
|
* detailed view. The toplevel view is used to control
|
|
* what is displayed in the detailed view. Selecting a node
|
|
* in the toplevel view (a basewindow for example), will
|
|
* show the node and it's children in the detailed view.
|
|
*
|
|
* If the 'select_at_least_one' flag is TRUE, and
|
|
* there are no nodes selected in the toplevel view,
|
|
* the first node will be selected, making the corresponding
|
|
* node in the detailed view visible.
|
|
* If the 'select_at_least_one' is FALSE, no special action
|
|
* is taken.
|
|
*/
|
|
void
|
|
brwsP_sync_views(
|
|
ABBrowser ab,
|
|
short select_at_least_one
|
|
)
|
|
{
|
|
Vwr toplevel,
|
|
detailed;
|
|
VNode toplevel_child,
|
|
detailed_child;
|
|
VMethods m;
|
|
int num_child,
|
|
num_selected = 0,
|
|
i;
|
|
|
|
if (!ab)
|
|
return;
|
|
|
|
/*
|
|
* Get toplevel/detailed view
|
|
*/
|
|
toplevel = ab->project;
|
|
detailed = ab->module;
|
|
|
|
if (!toplevel || !detailed)
|
|
return;
|
|
|
|
m = toplevel->methods;
|
|
|
|
/*
|
|
* Any nodes currently selected in toplevel view ?
|
|
*/
|
|
vwr_num_cond(toplevel->current_tree, &num_selected, brwsP_select_fn);
|
|
|
|
/*
|
|
* Get child count of toplevel view
|
|
*/
|
|
num_child = (*m->get_num_children)(toplevel->current_tree);
|
|
|
|
/*
|
|
* For every node in toplevel view
|
|
*/
|
|
for (i=0, toplevel_child = (*m->get_child)(toplevel->current_tree, 0);
|
|
(i < num_child);
|
|
toplevel_child = (*m->get_child)(toplevel->current_tree, ++i))
|
|
{
|
|
ABObj cur_obj;
|
|
|
|
if (!toplevel_child)
|
|
continue;
|
|
|
|
/*
|
|
* Get ABObj of current toplevel child node
|
|
*/
|
|
cur_obj = (ABObj)toplevel_child->obj_data;
|
|
|
|
/*
|
|
* From the ABObj, get the corresponding node in detailed
|
|
* view
|
|
*/
|
|
detailed_child = aob_find_bnode(cur_obj, detailed);
|
|
|
|
if (!detailed_child)
|
|
continue;
|
|
|
|
if (BRWS_NODE_STATE_IS_SET(toplevel_child, BRWS_NODE_SELECTED))
|
|
{
|
|
/*
|
|
* Node in toplevel view is selected.
|
|
* Make node in detailed view visible.
|
|
*/
|
|
BRWS_NODE_SET_STATE(detailed_child, BRWS_NODE_VISIBLE);
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Node in toplevel view is not selected.
|
|
*
|
|
* If 'select_at_least_one' flag set...
|
|
* Check first if there are no nodes selected.
|
|
* If there are none, make the first non selected node
|
|
* in the toplevel view selected and make the corresponding
|
|
* node in the detailed view visible.
|
|
*/
|
|
if (select_at_least_one && !num_selected)
|
|
{
|
|
BRWS_NODE_SET_STATE(toplevel_child, BRWS_NODE_SELECTED);
|
|
BRWS_NODE_SET_STATE(detailed_child, BRWS_NODE_VISIBLE);
|
|
++num_selected;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Make node in detailed view not visible
|
|
*/
|
|
BRWS_NODE_UNSET_STATE(detailed_child, BRWS_NODE_VISIBLE);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
* brwsP_node_is_collapsed()
|
|
* Returns TRUE if node is collapsed, FALSE otherwise.
|
|
* Note: on error conditions, TRUE is returned.
|
|
*/
|
|
int
|
|
brwsP_node_is_collapsed
|
|
(
|
|
VNode node
|
|
)
|
|
{
|
|
VNode parent;
|
|
VMethods m;
|
|
Vwr v;
|
|
ABObj obj;
|
|
|
|
if (!node)
|
|
return (TRUE);
|
|
|
|
obj = (AB_OBJ *)node->obj_data;
|
|
/*
|
|
fprintf(stderr, "brwsP_node_is_collapsed(%s), viewer = %p\n",
|
|
obj_get_name(obj),
|
|
node->browser);
|
|
*/
|
|
|
|
if (!(v = node->browser))
|
|
return (TRUE);
|
|
|
|
if (!(m = v->methods))
|
|
return (TRUE);
|
|
|
|
while (parent = (*m->get_parent)(node))
|
|
{
|
|
if (!BRWS_NODE_STATE_IS_SET(parent, BRWS_NODE_EXPANDED))
|
|
{
|
|
|
|
obj = (AB_OBJ *)parent->obj_data;
|
|
|
|
/*
|
|
fprintf(stderr, "parent node %s is collapsed\n", obj_get_name(obj));
|
|
*/
|
|
return (TRUE);
|
|
}
|
|
|
|
node = parent;
|
|
}
|
|
|
|
return (FALSE);
|
|
}
|
|
|
|
/*
|
|
* brwsP_node_is_visible()
|
|
* Returns TRUE if node is visible, FALSE otherwise.
|
|
* Note: on error conditions, TRUE is returned.
|
|
*/
|
|
int
|
|
brwsP_node_is_visible
|
|
(
|
|
VNode node
|
|
)
|
|
{
|
|
VNode parent;
|
|
VMethods m;
|
|
Vwr v;
|
|
ABObj obj;
|
|
|
|
if (!node)
|
|
return (FALSE);
|
|
|
|
if (!BRWS_NODE_STATE_IS_SET(node, BRWS_NODE_VISIBLE))
|
|
return (FALSE);
|
|
|
|
obj = (AB_OBJ *)node->obj_data;
|
|
/*
|
|
fprintf(stderr, "brwsP_node_is_visible(%s), viewer = %p\n",
|
|
obj_get_name(obj),
|
|
node->browser);
|
|
*/
|
|
|
|
if (!(v = node->browser))
|
|
return (TRUE);
|
|
|
|
if (!(m = v->methods))
|
|
return (TRUE);
|
|
|
|
while (parent = (*m->get_parent)(node))
|
|
{
|
|
if (!BRWS_NODE_STATE_IS_SET(parent, BRWS_NODE_VISIBLE))
|
|
{
|
|
|
|
obj = (AB_OBJ *)parent->obj_data;
|
|
|
|
/*
|
|
fprintf(stderr, "parent node %s is not visible\n", obj_get_name(obj));
|
|
*/
|
|
return (FALSE);
|
|
}
|
|
|
|
node = parent;
|
|
}
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
/*
|
|
* brwsP_make_drawarea_snap()
|
|
* Make the passed draw area 'snap' to be the size of it's parent
|
|
* whenever it's parent is resized.
|
|
* This function tries to take advantage of the fact that the parent
|
|
* in most cases is the clipwindow of a scrolled window which is
|
|
* also a draw area widget. In this case, a resize callback is
|
|
* registered. In other cases, an event handler is registered.
|
|
*/
|
|
void
|
|
brwsP_make_drawarea_snap(
|
|
Vwr v,
|
|
Widget draw_area
|
|
)
|
|
{
|
|
Widget clipwindow;
|
|
|
|
if (!v || !draw_area)
|
|
return;
|
|
|
|
clipwindow = XtParent(draw_area);
|
|
|
|
if (XmIsDrawingArea(clipwindow)) {
|
|
XtAddCallback(clipwindow, XmNresizeCallback,
|
|
clipwindowResizeCB, (XtPointer)v);
|
|
}
|
|
else
|
|
{
|
|
XtAddEventHandler(clipwindow,
|
|
StructureNotifyMask, False,
|
|
clipwindowEventHandler, (XtPointer)v);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Resize callback for parent of draw area
|
|
*/
|
|
static void
|
|
clipwindowResizeCB(
|
|
Widget w,
|
|
XtPointer client_data,
|
|
XtPointer call_data
|
|
)
|
|
{
|
|
/*
|
|
* Defer munging until we're out of the ScrolledWindow Resize callback
|
|
*/
|
|
XtAppAddWorkProc(XtWidgetToApplicationContext(w), clipWindowWorkProc, client_data);
|
|
}
|
|
|
|
/*
|
|
* Event handler for parent of draw area
|
|
*/
|
|
static void
|
|
clipwindowEventHandler(
|
|
Widget widget,
|
|
XtPointer client_data,
|
|
XEvent *event,
|
|
Boolean *cont_dispatch
|
|
)
|
|
{
|
|
if (event->type != ConfigureNotify)
|
|
return;
|
|
|
|
/*
|
|
* Defer munging until we're out of the ScrolledWindow Event Handler
|
|
*/
|
|
XtAppAddWorkProc(XtWidgetToApplicationContext(widget),
|
|
clipWindowWorkProc, client_data);
|
|
}
|
|
|
|
|
|
/*
|
|
* Work proc for clip window
|
|
* - make draw area snap to clip window's size.
|
|
*/
|
|
static Boolean
|
|
clipWindowWorkProc(
|
|
XtPointer client_data
|
|
)
|
|
{
|
|
draw_area_snap((Vwr)client_data);
|
|
return(True);
|
|
}
|
|
|
|
|
|
/*
|
|
* draw_area_snap()
|
|
* Make size of draw area snap to size of clipwindow.
|
|
* The clipwindow is the direct parent of the draw area.
|
|
* The preferred/minimum size of the draw area is stored in
|
|
* the viewer properties. This is the size needed to render
|
|
* whatever graphics is needed.
|
|
*
|
|
* Logic used:
|
|
* if clipwindow_width > min_width
|
|
* make draw area width == clip window width
|
|
* else
|
|
* if draw area width > minimum width (i.e. preferred width)
|
|
* make draw area width == minimum width
|
|
*
|
|
* Same logic used for height
|
|
*/
|
|
static void
|
|
draw_area_snap (
|
|
Vwr v
|
|
)
|
|
{
|
|
Widget clipwindow = NULL,
|
|
draw_area = NULL;
|
|
Dimension cw_width = 0,
|
|
cw_height = 0,
|
|
da_borderWidth = 0,
|
|
da_width = 0,
|
|
da_height = 0;
|
|
BrowserProps props = NULL;
|
|
Arg arg[4];
|
|
int num_args = 0;
|
|
|
|
if (!v)
|
|
return;
|
|
|
|
/*
|
|
* Get viewer properties
|
|
*/
|
|
if (!(props = aob_browser_properties(v)))
|
|
return;
|
|
|
|
/*
|
|
* Get draw area and clip window
|
|
*/
|
|
if (!(draw_area = brws_draw_area(v)))
|
|
return;
|
|
|
|
if (!(clipwindow = XtParent(draw_area)))
|
|
return;
|
|
|
|
/*
|
|
* Get clipwindow width/height, draw area
|
|
* width/height/border width
|
|
*/
|
|
XtVaGetValues(clipwindow,
|
|
XmNwidth, &cw_width,
|
|
XmNheight, &cw_height,
|
|
NULL);
|
|
XtVaGetValues(draw_area,
|
|
XmNborderWidth, &da_borderWidth,
|
|
XmNwidth, &da_width,
|
|
XmNheight, &da_height,
|
|
NULL);
|
|
|
|
if ((Dimension)cw_width > props->min_width)
|
|
{
|
|
/*
|
|
* Clip window width is more than minimum width
|
|
* -> expand draw area
|
|
* The dimension that we actually use must be offset by the
|
|
* border width to ensure a perfect fit in the clip window.
|
|
* Otherwise, this will trigger the scrollbar in the clipwindow.
|
|
*/
|
|
if (cw_width > 2u * da_borderWidth) {
|
|
cw_width -= 2u * da_borderWidth;
|
|
|
|
if (cw_width > 2)
|
|
{
|
|
XtSetArg(arg[num_args], XmNwidth, (cw_width - 2));
|
|
num_args++;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Clip window width is less than minimum width
|
|
* -> check if draw area width is more than it's minimum.
|
|
* If yes, shrink it back down to the minimum width.
|
|
*/
|
|
if ((Dimension)da_width > props->min_width)
|
|
{
|
|
XtSetArg(arg[num_args], XmNwidth, props->min_width);
|
|
num_args++;
|
|
}
|
|
}
|
|
|
|
|
|
if ((Dimension)cw_height > props->min_height)
|
|
{
|
|
/*
|
|
* Clip window height is more than minimum height
|
|
* -> expand draw area
|
|
* The dimension that we actually use must be offset by the
|
|
* border width to ensure a perfect fit in the clip window.
|
|
* Otherwise, this will trigger the scrollbar in the clipwindow.
|
|
*/
|
|
if (cw_height > 2u * da_borderWidth) {
|
|
cw_height -= 2u * da_borderWidth;
|
|
|
|
if (cw_height > 2)
|
|
{
|
|
XtSetArg(arg[num_args], XmNheight, (cw_height - 2));
|
|
num_args++;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Clip window height is less than minimum height
|
|
* -> check if draw area height is more than it's minimum.
|
|
* If yes, shrink it back down to the minimum height.
|
|
*/
|
|
if ((Dimension)da_height > props->min_height)
|
|
{
|
|
XtSetArg(arg[num_args], XmNheight, props->min_height);
|
|
num_args++;
|
|
}
|
|
}
|
|
|
|
if (num_args > 0)
|
|
XtSetValues(draw_area, arg, num_args);
|
|
}
|
|
|
|
void
|
|
brwsP_collapse_selected(
|
|
ABBrowser ab
|
|
)
|
|
{
|
|
Vwr v = NULL;
|
|
VNode *selected_nodes = NULL;
|
|
VMethods m;
|
|
int num_selected = 0,
|
|
i;
|
|
short redraw = FALSE;
|
|
|
|
|
|
if (!ab)
|
|
return;
|
|
|
|
if (!(v = ab->module))
|
|
return;
|
|
|
|
if (!(m = v->methods))
|
|
return;
|
|
|
|
/*
|
|
* Get nodes that are selected
|
|
*/
|
|
vwr_get_cond(v->current_tree, &selected_nodes,
|
|
&num_selected, select_fn);
|
|
|
|
/*
|
|
* Return if no selected nodes
|
|
*/
|
|
if (num_selected == 0) {
|
|
util_free(selected_nodes);
|
|
return;
|
|
}
|
|
|
|
for (i=0; i < num_selected; ++i)
|
|
{
|
|
/*
|
|
* For each selected node, check if they are expanded.
|
|
* If they are, mark them as collapsed.
|
|
*/
|
|
if (BRWS_NODE_STATE_IS_SET(selected_nodes[i], BRWS_NODE_EXPANDED))
|
|
{
|
|
BRWS_NODE_UNSET_STATE(selected_nodes[i], BRWS_NODE_EXPANDED);
|
|
redraw = TRUE;
|
|
}
|
|
}
|
|
|
|
if (redraw)
|
|
{
|
|
erase_viewer(v);
|
|
draw_viewer(v);
|
|
}
|
|
|
|
/*
|
|
* Free up node list if it contained anything
|
|
*/
|
|
if (selected_nodes)
|
|
util_free(selected_nodes);
|
|
}
|
|
|
|
|
|
void
|
|
brwsP_expand_selected(
|
|
ABBrowser ab
|
|
)
|
|
{
|
|
Vwr v = NULL;
|
|
VNode *selected_nodes = NULL;
|
|
VMethods m;
|
|
int num_selected = 0,
|
|
i;
|
|
short redraw = FALSE;
|
|
|
|
if (!ab)
|
|
return;
|
|
|
|
if (!(v = ab->module))
|
|
return;
|
|
|
|
if (!(m = v->methods))
|
|
return;
|
|
|
|
/*
|
|
* Get nodes that are selected
|
|
*/
|
|
vwr_get_cond(v->current_tree, &selected_nodes,
|
|
&num_selected, select_fn);
|
|
|
|
/*
|
|
* Return if no selected nodes
|
|
*/
|
|
if (num_selected == 0) {
|
|
util_free(selected_nodes);
|
|
return;
|
|
}
|
|
|
|
for (i=0; i < num_selected; ++i)
|
|
{
|
|
/*
|
|
* For each selected node, check if they are collapsed.
|
|
* If they are, mark them as expanded.
|
|
*/
|
|
if (!BRWS_NODE_STATE_IS_SET(selected_nodes[i], BRWS_NODE_EXPANDED))
|
|
{
|
|
BRWS_NODE_SET_STATE(selected_nodes[i], BRWS_NODE_EXPANDED);
|
|
redraw = TRUE;
|
|
}
|
|
}
|
|
|
|
if (redraw)
|
|
{
|
|
erase_viewer(v);
|
|
draw_viewer(v);
|
|
}
|
|
|
|
/*
|
|
* Free up node list if it contained anything
|
|
*/
|
|
if (selected_nodes)
|
|
util_free(selected_nodes);
|
|
}
|
|
|
|
|
|
void
|
|
brwsP_expand_collapsed(
|
|
ABBrowser ab
|
|
)
|
|
{
|
|
Vwr v = NULL;
|
|
VNode *collapsed_nodes = NULL;
|
|
VMethods m;
|
|
int num_collapsed = 0,
|
|
i;
|
|
short redraw = FALSE;
|
|
|
|
if (!ab)
|
|
return;
|
|
|
|
if (!(v = ab->module))
|
|
return;
|
|
|
|
if (!(m = v->methods))
|
|
return;
|
|
|
|
/*
|
|
* Get nodes that are collapsed
|
|
*/
|
|
vwr_get_cond(v->current_tree, &collapsed_nodes,
|
|
&num_collapsed, collapsed_fn);
|
|
|
|
/*
|
|
* Return if no collapsed nodes
|
|
*/
|
|
if (num_collapsed == 0) {
|
|
free(collapsed_nodes);
|
|
return;
|
|
}
|
|
|
|
for (i=0; i < num_collapsed; ++i)
|
|
{
|
|
/*
|
|
* For each collapsed node, mark them as expanded only if
|
|
* they are visible.
|
|
*/
|
|
if (brwsP_node_is_visible(collapsed_nodes[i]))
|
|
{
|
|
BRWS_NODE_SET_STATE(collapsed_nodes[i], BRWS_NODE_EXPANDED);
|
|
redraw = TRUE;
|
|
}
|
|
}
|
|
|
|
if (redraw)
|
|
{
|
|
erase_viewer(v);
|
|
draw_viewer(v);
|
|
}
|
|
|
|
/*
|
|
* Free up node list if it contained anything
|
|
*/
|
|
if (collapsed_nodes)
|
|
util_free(collapsed_nodes);
|
|
}
|
|
|
|
|
|
void
|
|
brwsP_tear_off_selected(
|
|
ABBrowser b
|
|
)
|
|
{
|
|
ABBrowser new_browser, b_list;
|
|
BrowserProps props, new_props;
|
|
AB_OBJ *project, *sel_obj;
|
|
VNode selected;
|
|
ViewerMethods *m;
|
|
|
|
if (!b || !b->module)
|
|
return;
|
|
|
|
project = (AB_OBJ *)b->module->obj_data;
|
|
|
|
if (!project)
|
|
return;
|
|
|
|
new_browser = brws_create();
|
|
|
|
|
|
/*
|
|
* Link this new browser with the rest
|
|
*/
|
|
b_list = (ABBrowser)project->info.project.browsers;
|
|
new_browser->next = b_list;
|
|
if (b_list)
|
|
b_list->previous = new_browser;
|
|
|
|
/*
|
|
* Make this new browser the first one on the list
|
|
*/
|
|
project->info.project.browsers = new_browser;
|
|
|
|
/*
|
|
* Add VNodes to the viewers of this browser
|
|
*/
|
|
m = new_browser->project->methods;
|
|
(*m->insert_tree)(new_browser->project, b->project->tree->obj_data);
|
|
|
|
m = new_browser->module->methods;
|
|
(*m->insert_tree)(new_browser->module, b->module->tree->obj_data);
|
|
|
|
brwsP_sync_views(new_browser, TRUE);
|
|
|
|
/*
|
|
* Code to make the root of the new browser the
|
|
* current selected node in the current browser
|
|
selected = node_selected(b->current_tree);
|
|
sel_obj = (AB_OBJ *)selected->obj_data;
|
|
|
|
new_browser->current_tree = aob_find_bnode(sel_obj, new_browser);
|
|
*/
|
|
|
|
aob_copy_props(b->project, new_browser->project);
|
|
aob_copy_props(b->module, new_browser->module);
|
|
|
|
recompute_viewer(new_browser->project);
|
|
recompute_viewer(new_browser->module);
|
|
|
|
brws_popup(new_browser);
|
|
}
|
|
|
|
void
|
|
brws_center_on_obj(
|
|
ABBrowser ab,
|
|
ABObj obj
|
|
)
|
|
{
|
|
Vwr top_level_view = NULL;
|
|
Vwr detailed_view = NULL;
|
|
|
|
if (!ab || !obj)
|
|
return;
|
|
|
|
/*
|
|
* Get top level and detailed tree view
|
|
*/
|
|
top_level_view = ab->project;
|
|
detailed_view = ab->module;
|
|
|
|
if (top_level_view && detailed_view)
|
|
{
|
|
BrowserUiObj ui;
|
|
DtbBrwsMainwindowInfo instance;
|
|
VNode detailed_node;
|
|
Widget vert_sb = (Widget)NULL;
|
|
Widget horiz_sb = (Widget)NULL;
|
|
int x, y, value, size, increment, page,
|
|
vert_max, horiz_max,
|
|
vert_min, horiz_min;
|
|
Dimension scroll_width, scroll_height;
|
|
BOOL redraw_needed = FALSE;
|
|
|
|
|
|
/*
|
|
* Get node in detailed view to center on
|
|
*/
|
|
detailed_node = aob_find_bnode(obj, detailed_view);
|
|
|
|
if (!detailed_node)
|
|
return;
|
|
|
|
/*
|
|
* If the node in the detailed view is not visible,
|
|
* make it visible first before proceeding.
|
|
* This is done by selecting the relevant node in the
|
|
* top level view and calling brwsP_sync_views().
|
|
*/
|
|
if (!brwsP_node_is_visible(detailed_node))
|
|
{
|
|
AB_TRAVERSAL trav;
|
|
VNode top_level_node;
|
|
ABObj module,
|
|
top_level_obj;
|
|
ViewerMethods *m;
|
|
|
|
module = obj_get_module(obj);
|
|
|
|
/*
|
|
* Look for direct child of module which is the
|
|
* ancestor of the centered object/node
|
|
*/
|
|
for (trav_open(&trav, module, AB_TRAV_CHILDREN);
|
|
(top_level_obj = trav_next(&trav)) != NULL; ) {
|
|
|
|
if (obj_is_descendant_of(obj, top_level_obj) ||
|
|
(obj == top_level_obj))
|
|
break;
|
|
}
|
|
trav_close(&trav);
|
|
|
|
if (!top_level_obj)
|
|
return;
|
|
|
|
/*
|
|
* Found top level ABObj - direct child of module which is
|
|
* the ancestor of 'obj'.
|
|
*
|
|
* Get the corresponding node in the top level view
|
|
*/
|
|
top_level_node = aob_find_bnode(top_level_obj, top_level_view);
|
|
|
|
if (!top_level_node)
|
|
return;
|
|
|
|
/*
|
|
* Select the top level node
|
|
*/
|
|
BRWS_NODE_SET_STATE(top_level_node, BRWS_NODE_SELECTED);
|
|
|
|
m = top_level_view->methods;
|
|
|
|
if (!m)
|
|
return;
|
|
|
|
/*
|
|
* Render it selected
|
|
*/
|
|
(*m->render_node)(top_level_node, TRUE);
|
|
|
|
/*
|
|
* Sync up the top level and detailed tree views
|
|
* After this the centered node will be 'visible'
|
|
*/
|
|
brwsP_sync_views(ab, FALSE);
|
|
|
|
/*
|
|
* Erase and recompute views
|
|
*/
|
|
erase_viewer(detailed_view);
|
|
recompute_viewer(detailed_view);
|
|
redraw_needed = TRUE;
|
|
}
|
|
|
|
ui = aob_ui_from_browser(detailed_view);
|
|
instance = (DtbBrwsMainwindowInfo)ui->ip;
|
|
|
|
if (!instance->detailed_drawarea)
|
|
return;
|
|
|
|
/*
|
|
* Get vertical/horizontal scrollbars of scrolled window
|
|
*/
|
|
XtVaGetValues(instance->detailed_drawarea_scrolledwin,
|
|
XmNverticalScrollBar, &vert_sb,
|
|
XmNhorizontalScrollBar, &horiz_sb,
|
|
XmNwidth, &scroll_width,
|
|
XmNheight, &scroll_height,
|
|
NULL);
|
|
|
|
/*
|
|
* If the scrolled area is smaller than the node, use the
|
|
* node's size as the scroll area - to prevent getting
|
|
* negative numbers in our calculations later on.
|
|
* BUG - am I casting properly here?
|
|
*/
|
|
if (scroll_width < (Dimension)detailed_node->width)
|
|
scroll_width = (Dimension)detailed_node->width;
|
|
if (scroll_height < (Dimension)detailed_node->height)
|
|
scroll_height = (Dimension)detailed_node->height;
|
|
|
|
/*
|
|
**********************************************************
|
|
* Center browser node to the middle of the scrolled window
|
|
**********************************************************
|
|
*/
|
|
|
|
/*
|
|
* Adjust vertical scrollbar
|
|
*/
|
|
|
|
|
|
if (vert_sb)
|
|
{
|
|
/*
|
|
* Get current scrollbar values
|
|
*/
|
|
XtVaGetValues(vert_sb,
|
|
XmNminimum, &vert_min,
|
|
XmNmaximum, &vert_max,
|
|
NULL);
|
|
XmScrollBarGetValues(vert_sb, &value, &size, &increment, &page);
|
|
|
|
/*
|
|
* Don't adjust if for some reason if the node is off the browser
|
|
*/
|
|
if (detailed_node->y < vert_max)
|
|
{
|
|
/*
|
|
* This adjusts the y position of the scrollbar so that
|
|
* the node is centered
|
|
*/
|
|
y = detailed_node->y - ((int)scroll_height - detailed_node->height)/2;
|
|
|
|
/*
|
|
* Check for illegal y value:
|
|
* Must make sure the y position does not exceed
|
|
* (XmNmaximum - XmNsliderSize)
|
|
*/
|
|
if (vert_max - y < size)
|
|
y = vert_max - size;
|
|
|
|
if (y < vert_min)
|
|
y = vert_min;
|
|
|
|
/*
|
|
* Set the scrollbar with new 'centered' y position
|
|
*/
|
|
XmScrollBarSetValues(vert_sb, (int)y, size, increment, page, True);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Adjust horizontal scrollbar
|
|
*/
|
|
|
|
if (horiz_sb)
|
|
{
|
|
/*
|
|
* Get current scrollbar values
|
|
*/
|
|
XtVaGetValues(horiz_sb,
|
|
XmNminimum, &horiz_min,
|
|
XmNmaximum, &horiz_max,
|
|
NULL);
|
|
XmScrollBarGetValues(horiz_sb, &value, &size, &increment, &page);
|
|
|
|
/*
|
|
* Don't adjust if for some reason if the node is off the browser
|
|
*/
|
|
if (detailed_node->x < horiz_max)
|
|
{
|
|
/*
|
|
* This adjusts the y position of the scrollbar so that
|
|
* the node is centered
|
|
*/
|
|
x = detailed_node->x - ((int)scroll_width - detailed_node->width)/2;
|
|
|
|
/*
|
|
* Check for illegal y value:
|
|
* Must make sure the y position does not exceed
|
|
* (XmNmaximum - XmNsliderSize)
|
|
*/
|
|
if (horiz_max - x < size)
|
|
x = horiz_max - size;
|
|
|
|
if (x < horiz_min)
|
|
x = horiz_min;
|
|
|
|
/*
|
|
* Set the scrollbar with new 'centered' y position
|
|
*/
|
|
XmScrollBarSetValues(horiz_sb, (int)x, size, increment, page, True);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Redraw if needed
|
|
*/
|
|
if (redraw_needed)
|
|
draw_viewer(detailed_view);
|
|
}
|
|
}
|