|
re:.0
> If I make the window widget larger than the scroll window ...
> ...it overlays the scroll bars.
> I thought that the scroll window behaved similar to the main window
> widget in managing its children - i.e., when you specify a height
> and width of a main widget with menu bars, scroll bars, etc you
> are actually specifying the size of it's work area. Now matter
> how large you make the work area widget it doesn't overlay the
> scroll bars.....
Indeed, the scroll window is in charge of preventing this situation, i.e.
it places its designated children in the proper places and sizes them.
In your case, it sounds as if the scroll window doesn't know which of its
children is which. The scroll window provides 3 resources which allows
you to designate which child is which. There is a utility routine called
(something like) ScrollWindowSetAreas which allows you to tell the scroll
window which child is the vertical/horizontal scroll bars and the work area.
(You can set them via SetValues, but less efficiently.) Note that this
setting is provided in UIL/DRM via the scroll_window arguments in the example
code below. I believe the reason you don't see the same behavior in main
windows is that they are smart enough to set their own "areas". (There is
a similar "set areas" routine for main windows (MainWindowSetAreas?).)
Here is a UIL example. (I have included a routine at the end which properly
causes the work area to scroll for all scroll bar callback reasons.)
! Main window which uses a scroll_window as its work area.
test_MnWind : main_window
{
arguments
{
arguments gnc_main_window_args;
x = k_tst_test_MnWind_x;
y = k_tst_test_MnWind_y;
width = k_tst_test_MnWind_wid;
height = k_tst_test_MnWind_hei;
main_menu_bar = menu_bar test_MenuBar; !*** Set Main
main_work_window = scroll_window work_ScrWind; !*** Areas
};
controls
{
menu_bar test_MenuBar; !***
scroll_window work_ScrWind; !***
};
callbacks
{
help = procedure tst_help_proc (k_tst_test_MnWind_key);
create = procedure tst_create_proc (k_tst_test_MnWind);
focus = procedure tst_focus_proc (k_tst_test_MnWind);
}; !callbacks
}; ! test_MnWind
work_ScrWind : scroll_window
{
arguments
{
arguments gnc_scroll_window_args;
width = k_tst_work_ScrWind_wid;
height = k_tst_work_ScrWind_hei;
horizontal_scroll_bar = scroll_bar work_h_ScrBar; !** Set Areas
vertical_scroll_bar = scroll_bar work_v_ScrBar; !**
work_window = window work_area_window; !**
};
controls
{
scroll_bar work_h_ScrBar; !**
scroll_bar work_v_ScrBar; !**
window work_area_window; !**
};
callbacks
{
help = procedure tst_help_proc (k_tst_work_ScrWind_key);
create = procedure tst_create_proc (k_tst_work_ScrWind);
}; !callbacks
}; ! work_ScrWind
work_h_ScrBar : scroll_bar
{
arguments
{
arguments gnc_scroll_bar_args;
orientation = DwtOrientationHorizontal;
};
callbacks
{
help = procedure tst_help_proc (k_tst_work_h_ScrBar_key);
create = procedure tst_create_proc (k_tst_work_h_ScrBar);
drag = procedure tst_scroller_proc (k_tst_work_h_ScrBar);
value_changed = procedure tst_scroller_proc (k_tst_work_h_ScrBar);
page_dec = procedure tst_scroller_proc (k_tst_work_h_ScrBar);
page_inc = procedure tst_scroller_proc (k_tst_work_h_ScrBar);
to_bottom = procedure tst_scroller_proc (k_tst_work_h_ScrBar);
to_top = procedure tst_scroller_proc (k_tst_work_h_ScrBar);
unit_dec = procedure tst_scroller_proc (k_tst_work_h_ScrBar);
unit_inc = procedure tst_scroller_proc (k_tst_work_h_ScrBar);
}; !callbacks
}; ! work_h_ScrBar
work_v_ScrBar : scroll_bar
{
arguments
{
arguments gnc_scroll_bar_args;
orientation = DwtOrientationVertical;
};
callbacks
{
help = procedure tst_help_proc (k_tst_work_v_ScrBar_key);
create = procedure tst_create_proc (k_tst_work_v_ScrBar);
drag = procedure tst_scroller_proc (k_tst_work_v_ScrBar);
value_changed = procedure tst_scroller_proc (k_tst_work_v_ScrBar);
page_dec = procedure tst_scroller_proc (k_tst_work_v_ScrBar);
page_inc = procedure tst_scroller_proc (k_tst_work_v_ScrBar);
to_bottom = procedure tst_scroller_proc (k_tst_work_v_ScrBar);
to_top = procedure tst_scroller_proc (k_tst_work_v_ScrBar);
unit_dec = procedure tst_scroller_proc (k_tst_work_v_ScrBar);
unit_inc = procedure tst_scroller_proc (k_tst_work_v_ScrBar);
}; !callbacks
}; ! work_v_ScrBar
work_area_window : window
{
arguments
{
...
};
callbacks
{
...
}; !callbacks
}; ! work_area_window
------------------------------------------
Here is a segment from the tst_scroller routine, which calls the generic
scroll work area routine.
void tst_scroller_proc ( a_object, al_object_tag, a_cb_struct )
/*==========================================================================
** This callback routine is called for the reason(s): value_changed,
** page_dec, page_inc, to_bottom, to_top, unit_dec, unit_inc, drag.
**
** Parameters:*/
Widget a_object;
int *al_object_tag;
DwtScrollBarCallbackStruct *a_cb_struct;
/*
**-------------------------------------------------------------------------*/
{
switch ( *al_object_tag )
{
case k_tst_work_h_ScrBar:
case k_tst_work_v_ScrBar:
{
util_scroll_work_area ( a_object, a_cb_struct,
ra_object_ids[k_tst_work_area_window] ); /*widget id-work area*/
break;
};
...
The generic work area scroll routine:
int util_scroll_work_area ( a_scroll_bar , callbackdata , a_work_area )
/*==============================================================================
** This routine performs the movement of the work area widget relative to
** it's parent scroll_window, performing the user's scroll request from
** the scroll bar. It works on any of the 8 callback reasons currently
** returned by scroll_bars (drag, value_change, to_top, to_bottom,
** page_inc, page_dec, unit_inc, unit_dec).
** The actions performed by this routine are based on the V1/V2 behavior of
** the toolkit scroll_window, relying on its partial intelligence with
** respect to scroll_bars and work_area widgets. Future enhancements to
** scroll_window may eliminate the need for some (or all) of the actions
** in this routine.
** Assumptions:
** - The application wishes the scroll to be performed by simply changing
** the x or y coordinate of the work area widget (with respect to its
** parent, the scroll_window widget.)
** - The work_area widget is not able to be scrolled completely out of the
** parent (i.e. the some portion (or all) of the work_area widget fills
** scroll_window's viewable space.)
** - The scroll_bar's "long" dimension is a valid measure of the viewable
** area.
** - The scroll_bar's min_value is always less than max_value. (Both
** can be negative.)
**
** Parameters:
*/
Widget a_scroll_bar; /* The scroll_bar's widget id */
DwtScrollBarCallbackStruct *callbackdata; /* Structure returned to a */
/* scroll_bar's callback routine */
Widget a_work_area; /* Widget id of the target widget */
/*
** Fields: reason, *event, value(int), pixel
**----------------------------------------------------------------------------*/
{
int l_minval=0, l_maxval=0, l_shown=0, l_unit_inc=0, l_val=0, l_page_inc=0;
int l_value_range, l_new_val=0;
unsigned char v_orientation = (char) 0;
Dimension
w_scrbar_wid=0, w_scrbar_hei=0,
w_work_area_wid=0, w_work_area_hei=0;
Position
w_work_area_x=0, w_work_area_y=0;
Arg r_scrbar_args[]= {
{DwtNminValue,&l_minval},
{DwtNmaxValue,&l_maxval},
{DwtNwidth,&w_scrbar_wid},
{DwtNheight,&w_scrbar_hei},
{DwtNvalue,&l_val},
{DwtNorientation,&v_orientation},
{DwtNinc,&l_unit_inc},
{DwtNpageInc,&l_page_inc},
{DwtNshown,&l_shown} };
#define k_scrbar_args_size array_size(r_scrbar_args)
Arg r_work_area_args[]= {
{DwtNwidth,&w_work_area_wid},
{DwtNheight,&w_work_area_hei},
{DwtNx,&w_work_area_x},
{DwtNy,&w_work_area_y} };
#define k_work_area_args_size array_size(r_work_area_args)
Arg r_work_area_set_args[1]= {{DwtNy,0}};
/* The value returned by scroll_bar in the callback structure is a number
between 'minvalue' and 'maxvalue - shown'. Therefore, the (absolute) value
number (minus the minvalue) divided by this range is the percentage position
of the underlying work area relative to the scroll_bar. The range of
scrollability of the work_area in a particular (x or y) dimension is:
'linear dimension of work area - linear dimension of scroll_bar'.
(This is assuming that the work_area widget is not permitted to scroll out of
the parent's area of viewability, that in fact work_area's border will never
be visible within that area unless it is smaller than the viewable area.)
The linear scroll_bar dimension and the 'area of viewability' in the parent
widget are assumed to be identical (i.e. there are no gaps around the scroll
bar.) As such, the parent [scroll_window] need not be involved in the
calculations at all.
Summary:
% position = abs(value-min)/abs(max-min-shown)
x_range = 0 to -(work_area_wid - scrbar_wid)
y_range = 0 to -(work_area_hei - scrbar_hei)
Therefore, either x OR y of the work_area widget will be recomputed.
x = - (% position) * (x_range)
y = - (% position) * (y_range)
x = - (abs(value-min) * (work_area_wid - scr_wid))/abs(max-min-shown)
y = - (abs(value-min) * (work_area_hei - scr_hei))/abs(max-min-shown)
*/
/* Get the values from the two relevant widgets in the system. */
/* */
XtGetValues(a_scroll_bar,r_scrbar_args,k_scrbar_args_size);
XtGetValues(a_work_area,r_work_area_args,k_work_area_args_size);
/* Compute the breadth of 'value' span for this scroll bar. */
l_value_range = l_maxval - l_minval - l_shown;
switch (callbackdata->reason)
{
case DwtCRUnitInc:
case DwtCRUnitDec:
case DwtCRPageInc:
case DwtCRPageDec:
case DwtCRValueChanged:
case DwtCRDrag:
{
if (v_orientation == DwtOrientationHorizontal)
{
if (l_value_range <= 0) /* Area not scrollable, it fills the */
w_work_area_x = 0; /* viewable portion of scroll_window */
else
w_work_area_x = - abs(
( (callbackdata->value - l_minval) *
(int)(w_work_area_wid - w_scrbar_wid) ) /
l_value_range );
XtSetArg(r_work_area_set_args[0], DwtNx, w_work_area_x);
}
else /* v_orientation == DwtOrientationVertical */
{
if (l_value_range <= 0) /* Area not scrollable, it fills the */
w_work_area_y = 0; /* viewable portion of scroll_window */
else
w_work_area_y = - abs(
( (callbackdata->value - l_minval) *
(int)(w_work_area_hei - w_scrbar_hei) ) /
l_value_range );
XtSetArg(r_work_area_set_args[0], DwtNy, w_work_area_y);
};
XtSetValues(a_work_area,r_work_area_set_args,1);
break;
}; /* case of Incs/Decs/Drag/ValChanged */
case DwtCRToTop:
{
/* For top/bottom, both repositioning the work area AND changing
the slider position must be done. (Slider is automatic
for the 'other' callback reasons.) */
/* For top/bottom, the 'value' resource is not used in the
calculation of movement of the work area widget. The major
reason is that 'pixel' is a much more precise measure of what
portion of the viewing area the user wishes to have moved to
the top or bottom of the scroll_window. Movement is simply a
matter of adding/subtracting the pixel value to x/y. Secondly,
the 'value' number may have a "many to one" relationship with
screen coordinate space, meaning that the work area could be
moved a larger amount rather than the visible amount. Also,
the 'value' number is no longer restricted to the minValue and
maxValue range since the click can occur in any part of the
scroll_bar, not just the scroll-slider region. Determining
'bounds' using the 'value' becomes problematic. */
if (v_orientation == DwtOrientationHorizontal)
{
w_work_area_x = w_work_area_x - callbackdata->pixel;
if (w_work_area_x < (w_scrbar_wid - w_work_area_wid))
w_work_area_x = w_scrbar_wid - w_work_area_wid;
XtSetArg(r_work_area_set_args[0], DwtNx, w_work_area_x);
/* Set the 'value' on the scroll_bar to get it to reposition
slider. (The slider position is determined by 'value'.)
First check if the work area is even scrollable (i.e.
the work area is smaller or the same size as scroll_bar). */
if (w_scrbar_wid >= w_work_area_wid)
l_new_val = l_minval;
else
l_new_val = (((int)w_work_area_x * l_value_range)
/ (int)(w_scrbar_wid - w_work_area_wid) ) + l_minval;
}
else /* v_orientation == DwtOrientationVertical */
{
w_work_area_y = w_work_area_y - callbackdata->pixel;
if (w_work_area_y < (w_scrbar_hei - w_work_area_hei))
w_work_area_y = w_scrbar_hei - w_work_area_hei;
XtSetArg(r_work_area_set_args[0], DwtNy, w_work_area_y);
/* Set the 'value' on the scroll_bar to get it to reposition
slider. (The slider position is determined by 'value'.) */
if (w_scrbar_hei >= w_work_area_hei)
l_new_val = l_minval;
else
l_new_val = (((int)w_work_area_y * l_value_range)
/ (int)(w_scrbar_hei - w_work_area_hei) ) + l_minval;
};
XtSetValues(a_work_area,r_work_area_set_args,1);
/* Set the scroll slider to its proper position. If there will be
no change in the visible slider (value), don't bother to make
the call. */
if (l_val != l_new_val)
{
DwtScrollBarSetSlider(a_scroll_bar,l_new_val,l_shown,
l_unit_inc,l_page_inc,FALSE);
};
break;
};
case DwtCRToBottom:
{
if (v_orientation == DwtOrientationHorizontal)
{
w_work_area_x = w_work_area_x +
(w_scrbar_wid - callbackdata->pixel - 1);
if (w_work_area_x > 0) w_work_area_x = 0;
XtSetArg(r_work_area_set_args[0], DwtNx, w_work_area_x);
/* Set the 'value' on the scroll_bar to get it to reposition
slider. (The slider position is determined by 'value'.) */
if (w_scrbar_wid >= w_work_area_wid)
l_new_val = l_minval;
else
l_new_val = (((int)w_work_area_x * l_value_range)
/ (int)(w_scrbar_wid - w_work_area_wid) ) + l_minval;
}
else /* v_orientation == DwtOrientationVertical */
{
w_work_area_y = w_work_area_y +
(w_scrbar_hei - callbackdata->pixel - 1);
if (w_work_area_y > 0) w_work_area_y = 0;
XtSetArg(r_work_area_set_args[0], DwtNy, w_work_area_y);
/* Set the 'value' on the scroll_bar to get it to reposition
slider. (The slider position is determined by 'value'.) */
if (w_scrbar_hei >= w_work_area_hei)
l_new_val = l_minval;
else
l_new_val = ( ((int)w_work_area_y * l_value_range)
/ (int)(w_scrbar_hei - w_work_area_hei) ) + l_minval;
};
XtSetValues(a_work_area,r_work_area_set_args,1);
/* Set the scroll slider to its proper position. If there will be
no change in the visible slider (value), don't bother to make
the call. */
if (l_val != l_new_val)
{
DwtScrollBarSetSlider(a_scroll_bar,l_new_val,l_shown,
l_unit_inc,l_page_inc,FALSE);
};
break;
};
}; /* end of switch */
return 1;
}; /* end of util_scroll_work_area */
|