Milán Major

netscape-revival

1 branch
Code

cmd/xfe/outline/Outline.c

/* Outline.c: Methods for the Outline widget */
/* Copyright © 1994 Torgeir Veimo. */
/* See the README file for copyright details. */

#include <Xm/XmP.h>
#include <Xm/ArrowB.h>
#include <Xm/Label.h>
#include "OutlineP.h"

static void Initialize();
static void Resize();
static void ChangeManaged();
static void Redisplay();
static Boolean SetValues();
static XtGeometryResult GeometryManager();
static XtGeometryResult QueryGeometry();

static void PreferredSize(XmOutlineWidget,
			  Dimension *,
			  Dimension *);

static void DoLayout(XmOutlineWidget);


static XtResource resources[] = {
  { XmNindentation, XmCIndentation, 
      XmRDimension, sizeof(Dimension),
      XtOffset(XmOutlineWidget, outline.indentation), 
      XtRString, "5" },

  { XmNspacing, XmCSpacing, 
      XmRDimension, sizeof(Dimension),
      XtOffset(XmOutlineWidget, outline.spacing), 
      XtRImmediate, (caddr_t) 2 },
  
  { XmNoutline, XmCOutline, 
      XmRBoolean, sizeof(Boolean),
      XtOffset(XmOutlineWidget, outline.draw_outline), 
      XtRString, "False" },

  { XmNmarginWidth, XmCMarginWidth, 
      XmRVerticalDimension, sizeof(Dimension),
      XtOffset(XmOutlineWidget, outline.marginWidth), 
      XtRImmediate, (caddr_t) 0 },

  { XmNmarginHeight, XmCMarginHeight, 
      XmRHorizontalDimension, sizeof(Dimension),
      XtOffset(XmOutlineWidget, outline.marginHeight), 
      XtRImmediate, (caddr_t) 0 },

  { XmNspacing, XmCSpacing, 
      XmRDimension, sizeof(Dimension),
      XtOffset(XmOutlineWidget, outline.spacing), 
      XtRImmediate, (caddr_t) 0 },

};


XmOutlineClassRec xmOutlineClassRec = { 
{
  /* core_class members */
  (WidgetClass) &xmManagerClassRec, /* superclass         */
  "XmOutline",                      /* class_name         */
  sizeof (XmOutlineRec),            /* widget_size        */
  NULL,                             /* class_initialize   */
  NULL,                             /* class_part_init    */  
  FALSE,                            /* class_inited       */  
  Initialize,                       /* initialize         */
  NULL,                             /* initialize_hook    */  
  XtInheritRealize,                 /* realize            */
  NULL,                             /* actions            */
  0,                                /* num_actions        */  
  resources,                        /* resources          */
  XtNumber(resources),              /* num_resources      */
  NULLQUARK,                        /* xrm_class          */
  TRUE,                             /* compress_motion    */  
  XtExposeCompressMaximal,          /* compress_exposure  */  
  TRUE,                             /* compress_enterleave*/  
  FALSE,                            /* visible_interest   */
  NULL,                             /* destroy            */
  Resize,                           /* resize             */
  Redisplay,                        /* expose             */
  SetValues,                        /* set_values         */
  NULL,                             /* set_values_hook    */
  XtInheritSetValuesAlmost,         /* set_values_almost  */
  NULL,                             /* get_values_hook    */  
  NULL,                             /* accept_focus       */
  XtVersion,                        /* version            */  
  NULL,                             /* callback_private   */
  XtInheritTranslations,            /* tm_table           */
  QueryGeometry,                    /* query_geometry     */  
  NULL,                             /* display_accelerator*/
  NULL,                             /* extension          */
},
{
  /* composite_class members */
  GeometryManager,                  /* geometry_manager   */
  ChangeManaged,                    /* change_managed     */
  XtInheritInsertChild,             /* insert_child       */  
  XtInheritDeleteChild,             /* delete_child       */  
  NULL,                             /* extension          */
},
{      
  /* constraint_class fields */
  NULL,                             /* resource list       */   
  0,                                /* num resources       */   
  0,                                /* constraint size     */   
  NULL,                             /* init proc           */   
  NULL,                             /* destroy proc        */   
  NULL,                             /* set values proc     */   
  NULL,                             /* extension           */
},
{ 
  /* XmManager class */
  XtInheritTranslations,            /* translations         */
  NULL,                             /* syn resources        */
  0,                                /* num syn_resources    */
  NULL,                             /* syn_cont_resources     */
  0,                                /* num_syn_cont_resources */
  XmInheritParentProcess,           /* parent_process       */
  NULL,                             /* extension            */    
},
{
  /* Outline class members */
  0,                                /* empty                */  
}
};

WidgetClass xmOutlineWidgetClass = (WidgetClass) &xmOutlineClassRec;

static void Initialize(Widget request, Widget new,
		       ArgList args, Cardinal *numArgs) 
{
  if (XtWidth(new) <= 0) 
    XtWidth(new) = 1;
  
  if (XtWidth(new) <= 0) 
    XtHeight(new) = 1;
} 
 
   
static void Resize(Widget w) 
{
  DoLayout((XmOutlineWidget) w);
}

    
static void DoLayout(XmOutlineWidget ow) 
{
  Widget     child;
  int        i, indentation;
  Position   ypos;

  indentation = ow->outline.indentation + ow->outline.marginWidth;
  ypos = ow->outline.marginHeight;
  
  for (i = 0; i < ow->composite.num_children; i++) {

    child = ow -> composite.children[i];

    if (child->core.managed) {

      _XmConfigureObject(child, indentation, ypos,
			 XtWidth(child), XtHeight(child),
			 XtBorderWidth(child));
      
      ypos += (ow->outline.spacing + XtHeight(child));
    }
  }
  
  /* Since the drawn outline might have been made invalid by the possible 
     new layout, the window is cleared, signaling a redraw operation. 
     
     It would probably be possible to add some intelligence here, detecting
     the changes made and only remove the drawn outline for that specific
     part.

     I have yet to test the blink effect that this method causes when the 
     outline widget have a large number of children. */
  
  if (XtIsRealized(ow))
    XClearArea(XtDisplay(ow), XtWindow(ow), 0, 0, 0, 0, True);
}
                    
static Boolean SetValues(Widget current, 
			 Widget request, 
			 Widget new,
			 ArgList args, 
			 Cardinal numargs)
{
  XmOutlineWidget new_ow = (XmOutlineWidget) new;
  XmOutlineWidget cur_ow = (XmOutlineWidget) current;
  Boolean redraw = FALSE;

  if (new_ow->core.background_pixel != cur_ow->core.background_pixel)
    redraw = TRUE;
  
  if (new_ow->outline.indentation != cur_ow->outline.indentation)
    redraw = TRUE;
  
  if ((new_ow->outline.indentation != cur_ow->outline.indentation) ||
      (new_ow->outline.spacing != cur_ow->outline.spacing) ||
      (new_ow->outline.marginWidth != cur_ow->outline.marginWidth) ||
      (new_ow->outline.marginHeight != cur_ow->outline.marginHeight)) {

    Dimension w = 0, h = 0;
    
    PreferredSize(new_ow, &w, &h);
    
    if (w != XtWidth(new) || h != XtHeight(new)) {
      XtGeometryResult result;
      
      Dimension replyWidth, replyHeight;
      
      result = XtMakeResizeRequest(new, w, h, &replyWidth, &replyHeight);
      
      if (result == XtGeometryAlmost) 
	XtMakeResizeRequest(new,
			    replyWidth, replyHeight, 
			    NULL, NULL);       
    }     

    DoLayout(new_ow);
    
    redraw = FALSE; /* DoLayout takes care of this. */
  }
  return (redraw);
}


static void Redisplay(Widget w, 
		      XEvent *event, 
		      Region region) 
{
  int			x1, y1, x2, y2, i;
  XmOutlineWidget	ow = (XmOutlineWidget) w;
  Widget		child;
  Bool			draw = FALSE;

  /* Check wether we are visible or not, and return if not. */

  if (XmGetVisibility(w) == XmVISIBILITY_FULLY_OBSCURED)
    return;

  if (ow->outline.draw_outline) {

    x1 = ow->outline.indentation / 2 + ow->outline.marginWidth;
    x2 = ow->outline.indentation;
    y1 = ow->outline.marginHeight;

    for (i = 0; i < ow->composite.num_children; i++) {
      
      child = ow->composite.children[i];

      if (child->core.managed) {

	draw = TRUE; /* At least one managed child */
	
	y2 = XtY(child) + ow->outline.indentation / 2
	  + ow->outline.marginHeight;
	
	XDrawLine(XtDisplay(w), XtWindow(w),
		  ow->manager.highlight_GC,
		  x1, y2, x2, y2);
      }
    }
    if (draw)
      XDrawLine(XtDisplay(w), XtWindow(w),
		ow->manager.highlight_GC,
		x1, y1, x1, y2);
  }

  _XmRedisplayGadgets(w, event, region);
}
        
static void PreferredSize(XmOutlineWidget ow,
			  Dimension *w,
			  Dimension *h) 
{
  int i, nchildren = 0;
  Dimension width = 0, height = 0;
  XtWidgetGeometry preferred;

  for (i = 0; i < ow->composite.num_children; i++) {
    Widget child = ow->composite.children[i];
    
    if (child->core.managed) {

      XtQueryGeometry(child, NULL, &preferred);
      
      /* This is dangerous stuff! The preferred size isn't necessary
	 larger than the actual size, so we have to check both when
	 XmNpacking is set to XmPACK_NONE. Of course when XmNpacking
	 is set to XmPACK_TIGHT, the actual size should always be 
	 smaller or equal to the preferred size. */

      if (XtHeight(child) > preferred.height)
	height += XtHeight(child);
      else
	height += preferred.height;
      
      if (XtWidth(child) > preferred.width) {
	if (XtWidth(child) > width) 
	  width = XtWidth(child);
      } else {
	if (preferred.width > width)
	  width = preferred.width;
      }

      ++nchildren;
    }
  }

  width += (ow->outline.indentation + 2 * ow->outline.marginWidth);
  height += ((nchildren - 1) * ow->outline.spacing 
	     + 2 * ow->outline.marginHeight);
  
  *w = width; *h = height;
}


static XtGeometryResult QueryGeometry(Widget widget,
				      XtWidgetGeometry *intended,
				      XtWidgetGeometry *reply) 
{
  XmOutlineWidget ow = (XmOutlineWidget) widget;
  Dimension   w, h;
  
  if (intended->request_mode & (~(CWWidth | CWHeight))) 
      return  (XtGeometryYes);
  
  PreferredSize(ow, &w, &h);
  
  if (intended->request_mode & CWWidth &&
      intended->width == w &&
      intended->request_mode & CWHeight &&
      intended->height == h)
    return (XtGeometryYes);
  
  if (w == XtWidth(widget) &&
      h == XtHeight(widget))
    return (XtGeometryNo);
  
  reply->request_mode = CWWidth | CWHeight;
  reply->width = w;
  reply->height = h;
  return XtGeometryAlmost;
}
                                        
static XtGeometryResult GeometryManager(Widget widget, 
					XtWidgetGeometry *request,
					XtWidgetGeometry *reply) 
{
  XmOutlineWidget ow = (XmOutlineWidget) XtParent(widget);

  /* This is probably incomplete. It works for now though. */

  if (request->request_mode & (CWX | CWY)) 
    return (XtGeometryNo);
    
  if (request->request_mode & (CWWidth | CWHeight)) {
    Dimension w = 0, h = 0;
    int i, nchildren = 0;
        
    if (request->request_mode & CWWidth) 
      XtWidth(widget) = request->width;
    
    if (request->request_mode & CWHeight) 
      XtHeight(widget) = request->height;
    
    PreferredSize(ow, &w, &h);

    if (w != XtWidth(ow) || h != XtHeight(ow)) {
      XtGeometryResult result;
      
      Dimension replyWidth, replyHeight;
      
      result = XtMakeResizeRequest((Widget) ow, w, h,
				   &replyWidth,
				   &replyHeight);

      if (result == XtGeometryAlmost) 
	XtMakeResizeRequest((Widget) ow,
			    replyWidth, replyHeight, 
			    NULL, NULL);       
    }     
    DoLayout(ow);
  }
  return (XtGeometryYes);
}
                                                    
static void ChangeManaged(Widget child) 
{
  XmOutlineWidget ow = (XmOutlineWidget) child; 
  Dimension w, h;
  
  PreferredSize(ow, &w, &h);
  
  if (w != XtWidth(ow) || h != XtHeight(ow)) {
    XtGeometryResult result;
    Dimension replyWidth, replyHeight;
    
    result = XtMakeResizeRequest((Widget) ow, w, h,
				 &replyWidth, &replyHeight);
    if (result == XtGeometryAlmost) 
      XtMakeResizeRequest((Widget) ow,
			  replyWidth, replyHeight, 
			  NULL, NULL);   
  }
  
  DoLayout(ow);

  _XmNavigChangeManaged(child);    
  
}

Widget XmCreateOutline(Widget parent,
		       char *name,
		       ArgList arglist,
		       Cardinal argcount)  
{
  return (XtCreateWidget(name, xmOutlineWidgetClass, 
			 parent, arglist, argcount));
}