diff lwlib/xlwradio.c @ 398:74fd4e045ea6 r21-2-29

Import from CVS: tag r21-2-29
author cvs
date Mon, 13 Aug 2007 11:13:30 +0200
parents
children b8cc9ab3f761
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lwlib/xlwradio.c	Mon Aug 13 11:13:30 2007 +0200
@@ -0,0 +1,590 @@
+/* Radio Widget for XEmacs.
+   Copyright (C) 1999 Edward A. Falk
+
+This file is part of XEmacs.
+
+XEmacs is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+XEmacs is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with XEmacs; see the file COPYING.  If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+/* Synched up with: Radio.c 1.1 */
+
+/*
+ * Radio.c - Radio button widget
+ *
+ * Author: Edward A. Falk
+ *         falk@falconer.vip.best.com
+ *  
+ * Date:   June 30, 1997
+ *
+ *
+ * Overview:  This widget is identical to the Toggle widget in behavior,
+ * but completely different in appearance.  This widget looks like a small
+ * diamond-shaped button with a label to the right.
+ *
+ * To make this work, we subclass the Toggle widget to inherit its behavior
+ * and to inherit the label-drawing function from which Toggle is
+ * subclassed.  We then completely replace the Expose, Set, Unset
+ * and Highlight member functions.
+ *
+ * The Set and Unset actions are slightly unorthodox.  In Toggle's
+ * ClassInit function, Toggle searches the Command actions list and
+ * "steals" the Set and Unset functions, caching pointers to them in its
+ * class record.  It then calls these functions from its own ToggleSet
+ * and Toggle actions.
+ *
+ * We, in turn, override the Set() and Unset() actions in our own ClassRec.
+ */
+
+
+#include <config.h>
+#include <stdio.h>
+
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include ATHENA_INCLUDE(XawInit.h)
+#include "../src/xmu.h"
+#include "xlwradioP.h"
+
+#define	BOX_SIZE	13
+
+#define	rclass(w)	((RadioWidgetClass)((w)->core.widget_class))
+
+
+#ifdef	_ThreeDP_h
+#define	swid(rw)	((rw)->threeD.shadow_width)
+#else
+#define	swid(rw)	((rw)->core.border_width)
+#endif
+
+#define	bsize(rw)	(rclass(rw)->radio_class.dsize)
+#define	bs(rw)		(bsize(rw) + 2*swid(rw))
+
+
+
+/****************************************************************
+ *
+ * Full class record constant
+ *
+ ****************************************************************/
+
+	/* The translations table from Toggle do not need to be
+	 * overridden by Radio
+	 */
+
+
+	/* Member functions */
+
+static void RadioInit (Widget, Widget, ArgList, Cardinal *);
+static void RadioExpose (Widget, XEvent *, Region);
+static void RadioResize (Widget);
+static void RadioDestroy (Widget, XtPointer, XtPointer);
+static void RadioClassInit (void);
+static void RadioClassPartInit (WidgetClass);
+static Boolean RadioSetValues (Widget, Widget, Widget, ArgList, Cardinal *);
+static void DrawDiamond (Widget);
+static XtGeometryResult RadioQueryGeometry (Widget, XtWidgetGeometry *,
+					    XtWidgetGeometry *);
+
+	/* Action procs */
+
+static void RadioHighlight   (Widget, XEvent *, String *, Cardinal *);
+static void RadioUnhighlight (Widget, XEvent *, String *, Cardinal *);
+
+	/* internal privates */
+
+static void RadioSize (RadioWidget, Dimension *, Dimension *);
+
+	/* The actions table from Toggle is almost perfect, but we need
+	 * to override Highlight, Set, and Unset.
+	 */
+
+static XtActionsRec actionsList[] =
+{
+  {"highlight",		RadioHighlight},
+  {"unhighlight",	RadioUnhighlight},
+};
+
+#define SuperClass ((ToggleWidgetClass)&toggleClassRec)
+
+RadioClassRec radioClassRec = {
+  {
+    (WidgetClass) SuperClass,		/* superclass		*/	
+    "Radio",				/* class_name		*/
+    sizeof(RadioRec),			/* size			*/
+    RadioClassInit,			/* class_initialize	*/
+    RadioClassPartInit,			/* class_part_initialize  */
+    FALSE,				/* class_inited		*/
+    RadioInit,				/* initialize		*/
+    NULL,				/* initialize_hook	*/
+    XtInheritRealize,			/* realize		*/
+    actionsList,			/* actions		*/
+    XtNumber(actionsList),		/* num_actions		*/
+    NULL,				/* resources		*/
+    0,					/* resource_count	*/
+    NULLQUARK,				/* xrm_class		*/
+    TRUE,				/* compress_motion	*/
+    TRUE,				/* compress_exposure	*/
+    TRUE,				/* compress_enterleave	*/
+    FALSE,				/* visible_interest	*/
+    NULL,				/* destroy		*/
+    RadioResize,			/* resize		*/
+    RadioExpose,			/* expose		*/
+    RadioSetValues,			/* 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		*/
+    RadioQueryGeometry,			/* query_geometry	*/
+    XtInheritDisplayAccelerator,	/* display_accelerator	*/
+    NULL				/* extension		*/
+  },  /* CoreClass fields initialization */
+  {
+    XtInheritChangeSensitive		/* change_sensitive	*/ 
+  },  /* SimpleClass fields initialization */
+#ifdef	_ThreeDP_h
+  {
+    XtInheritXaw3dShadowDraw		/* field not used	*/
+  },  /* ThreeDClass fields initialization */
+#endif
+  {
+    0					  /* field not used	*/
+  },  /* LabelClass fields initialization */
+  {
+    0					  /* field not used	*/
+  },  /* CommandClass fields initialization */
+  {
+      RadioSet,				/* Set Procedure.	*/
+      RadioUnset,			/* Unset Procedure.	*/
+      NULL				/* extension.		*/
+  },  /* ToggleClass fields initialization */
+  {
+      BOX_SIZE,
+      DrawDiamond,			/* draw procedure */
+      NULL				/* extension. */
+  }  /* RadioClass fields initialization */
+};
+
+  /* for public consumption */
+WidgetClass radioWidgetClass = (WidgetClass) &radioClassRec;
+
+
+
+
+
+
+/****************************************************************
+ *
+ * Class Methods
+ *
+ ****************************************************************/
+
+static void
+RadioClassInit (void)
+{
+  XawInitializeWidgetSet();
+}
+
+static	void
+RadioClassPartInit (WidgetClass class)
+{
+  RadioWidgetClass c     = (RadioWidgetClass) class ;
+  RadioWidgetClass super = (RadioWidgetClass)c->core_class.superclass ;
+
+  if( c->radio_class.drawDiamond == NULL  ||
+      c->radio_class.drawDiamond == XtInheritDrawDiamond )
+  {
+    c->radio_class.drawDiamond = super->radio_class.drawDiamond ;
+  }
+}
+
+
+
+
+/*ARGSUSED*/
+static void
+RadioInit (Widget   request,
+	   Widget   new,
+	   ArgList  args,
+	   Cardinal *num_args)
+{
+    RadioWidget rw = (RadioWidget) new;
+    RadioWidget rw_req = (RadioWidget) request;
+    Dimension	w,h ;
+
+    /* Select initial size for the widget */
+    if( rw_req->core.width == 0  ||  rw_req->core.height == 0 )
+    {
+      RadioSize(rw, &w,&h) ;
+      if( rw_req->core.width == 0 )
+	rw->core.width = w ;
+      if( rw_req->core.height == 0 )
+	rw->core.height = h ;
+      rw->core.widget_class->core_class.resize(new) ;
+    }
+}
+
+/*	Function Name: RadioDestroy
+ *	Description: Destroy Callback for radio widget.
+ *	Arguments: w - the radio widget that is being destroyed.
+ *                 junk, grabage - not used.
+ *	Returns: none.
+ */
+
+/* ARGSUSED */
+static void
+RadioDestroy (Widget w,
+	      XtPointer junk,
+	      XtPointer garbage)
+{
+	/* TODO: get rid of this */
+}
+
+
+/* React to size change from manager.  Label widget will compute some internal
+ * stuff, but we need to override.  This code requires knowledge of the
+ * internals of the Label widget.
+ */
+
+static	void
+RadioResize (Widget w)
+{
+    RadioWidget rw = (RadioWidget)w ;
+
+    /* call parent resize proc */
+    SuperClass->core_class.resize(w) ;
+
+    /* override label offset */
+
+    switch( rw->label.justify ) {
+      case XtJustifyLeft:
+	rw->label.label_x += bs(rw) + rw->label.internal_width ;
+	break ;
+      case XtJustifyRight:
+	break ;
+      case XtJustifyCenter:
+      default:
+	rw->label.label_x += (bs(rw) + rw->label.internal_width)/2 ;
+	break ;
+    }
+}
+
+
+/*
+ * Repaint the widget window.
+ */
+
+static	void
+RadioExpose (Widget w,
+	     XEvent *event,
+	     Region region)
+{
+	RadioWidget	rw = (RadioWidget) w ;
+	Display		*dpy = XtDisplay(w) ;
+	Window		win = XtWindow(w) ;
+	GC		gc ;
+	Pixmap		left_bitmap ;
+	extern WidgetClass labelWidgetClass ;
+
+	/* Note: the Label widget examines the region to decide if anything
+	 * needs to be drawn.  I'm not sure that this is worth the effort,
+	 * but it bears thinking on.
+	 */
+
+	/* Command widget may sometimes override the label GC in order
+	 * to draw inverse video.  We don't use inverse video, so we need
+	 * to restore the label's normal GC.
+	 */
+	rw->label.normal_GC = rw->command.normal_GC ;
+
+
+	/* Let label widget draw the label.  If there was an lbm_x
+	 * field, we could let Label draw the bitmap too.  But there
+	 * isn't, so we need to temporarily remove the bitmap and
+	 * draw it ourself later.
+	 */
+	left_bitmap = rw->label.left_bitmap ;
+	rw->label.left_bitmap = None ;
+	labelWidgetClass->core_class.expose(w,event,region) ;
+	rw->label.left_bitmap = left_bitmap ;
+
+	/* now manually draw the left bitmap.  TODO: 3-d look, xaw-xpm */
+	gc = XtIsSensitive(w) ? rw->label.normal_GC : rw->label.gray_GC ;
+	if( left_bitmap != None && rw->label.lbm_width > 0 )
+	{
+	  /* TODO: handle pixmaps */
+	  XCopyPlane(dpy, left_bitmap, win, gc,
+	  	0,0, rw->label.lbm_width, rw->label.lbm_height,
+		(int) rw->label.internal_width*2 + bs(rw),
+		(int) rw->label.internal_height + rw->label.lbm_y,
+		(u_long) 1L) ;
+	}
+
+	/* Finally, the button itself */
+	((RadioWidgetClass)(w->core.widget_class))->radio_class.drawDiamond(w) ;
+}
+
+
+
+
+/************************************************************
+ *
+ * Set specified arguments into widget
+ *
+ ***********************************************************/
+
+
+/* ARGSUSED */
+static Boolean
+RadioSetValues (Widget   current,
+		Widget   request,
+		Widget   new,
+		ArgList  args,
+		Cardinal *num_args)
+{
+    RadioWidget oldrw = (RadioWidget) current;
+    RadioWidget newrw = (RadioWidget) new;
+
+    /* Need to find out if the size of the widget changed.  Set new size
+     * if it did and resize is permitted.  One way to determine of the
+     * widget changed size would be to scan the args list.  Another way
+     * is to compare the old and new widgets and see if any of several
+     * size-related fields have been changed.  The Label widget chose the
+     * former method, but I choose the latter.
+     */
+
+    if( newrw->label.resize &&
+	( newrw->core.width != oldrw->core.width ||
+	  newrw->core.height != oldrw->core.height ||
+	  newrw->core.border_width != oldrw->core.border_width ) )
+    {
+      RadioSize(newrw, &newrw->core.width, &newrw->core.height) ;
+    }
+
+    return FALSE ;
+}
+
+static XtGeometryResult
+RadioQueryGeometry (Widget w,
+		    XtWidgetGeometry *intended,
+		    XtWidgetGeometry *preferred)
+{
+    RadioWidget rw = (RadioWidget) w;
+
+    preferred->request_mode = CWWidth | CWHeight;
+    RadioSize(rw, &preferred->width, &preferred->height) ;
+
+    if (  ((intended->request_mode & (CWWidth | CWHeight))
+	   	== (CWWidth | CWHeight)) &&
+	  intended->width == preferred->width &&
+	  intended->height == preferred->height)
+	return XtGeometryYes;
+    else if (preferred->width == w->core.width &&
+	     preferred->height == w->core.height)
+	return XtGeometryNo;
+    else
+	return XtGeometryAlmost;
+}
+
+
+
+
+
+/************************************************************
+ *
+ *  Action Procedures
+ *
+ ************************************************************/
+
+/*
+ * Draw the highlight border around the widget.  The Command widget
+ * did this by drawing through a mask.  We do it by just drawing the
+ * border.
+ */
+
+static void 
+DrawHighlight (Widget w,
+	       GC gc)
+{
+	RadioWidget	rw = (RadioWidget)w;
+	XRectangle	rects[4] ;
+	Dimension	ht = rw->command.highlight_thickness ;
+
+	if( ht <= 0 ||
+	    ht > rw->core.width/2  ||
+	    ht > rw->core.height/2 )
+	  return ;
+
+	if( ! XtIsRealized(w) )
+	  return ;
+
+	rects[0].x = 0 ; rects[0].y = 0 ;
+	rects[0].width = rw->core.width ; rects[0].height = ht ;
+	rects[1].x = 0 ; rects[1].y = rw->core.height - ht ;
+	rects[1].width = rw->core.width ; rects[1].height = ht ;
+	rects[2].x = 0 ; rects[2].y = ht ;
+	rects[2].width = ht ; rects[2].height = rw->core.height - ht*2 ;
+	rects[3].x = rw->core.width - ht ; rects[3].y = ht ;
+	rects[3].width = ht ; rects[3].height = rw->core.height - ht*2 ;
+	XFillRectangles( XtDisplay(w), XtWindow(w), gc, rects, 4) ;
+}
+
+static	void
+RadioHighlight (Widget   w,
+		XEvent   *event,
+		String   *params,
+		Cardinal *num_params)
+{
+    RadioWidget	rw = (RadioWidget)w;
+    DrawHighlight(w, rw->command.normal_GC) ;
+}
+
+
+static	void
+RadioUnhighlight (Widget   w,
+		  XEvent   *event,
+		  String   *params,
+		  Cardinal *num_params)
+{
+    RadioWidget	rw = (RadioWidget)w;
+    DrawHighlight(w, rw->command.inverse_GC) ;
+}
+
+
+/* ARGSUSED */
+void 
+RadioSet (Widget   w,
+	  XEvent   *event,
+	  String   *params,     /* unused */
+	  Cardinal *num_params) /* unused */
+{
+    RadioWidget	rw = (RadioWidget)w;
+    RadioWidgetClass class = (RadioWidgetClass) w->core.widget_class ;
+
+    if( rw->command.set )
+      return ;
+
+    rw->command.set = TRUE ;
+    if( XtIsRealized(w) )
+      class->radio_class.drawDiamond(w) ;
+}
+
+
+/* ARGSUSED */
+void 
+RadioUnset (Widget   w,
+	    XEvent   *event,
+	    String   *params,     /* unused */
+	    Cardinal *num_params) /* unused */
+{
+    RadioWidget	rw = (RadioWidget)w;
+    RadioWidgetClass class = (RadioWidgetClass) w->core.widget_class ;
+
+    if( ! rw->command.set )
+      return ;
+
+    rw->command.set = FALSE ;
+    if( XtIsRealized(w) )
+      class->radio_class.drawDiamond(w) ;
+}
+
+
+
+
+/************************************************************
+ *
+ *  Internal Procedures
+ *
+ ************************************************************/
+
+
+/* Size of widget.  Width is size of box plus width of border around
+ * box plus width of label plus three margins plus the size of the left
+ * bitmap, if any.  Height is max(box,bitmap,label) plus two margins.
+ */
+
+static	void
+RadioSize (RadioWidget rw,
+	   Dimension   *w,
+	   Dimension   *h)
+{
+	*w = rw->label.label_width + bs(rw) + LEFT_OFFSET(rw) +
+		3 * rw->label.internal_width ;
+	*h = Max( rw->label.label_height, bs(rw) ) +
+		2 * rw->label.internal_width ;
+}
+
+
+static	void
+DrawDiamond (Widget w)
+{
+	RadioWidget	rw = (RadioWidget) w ;
+	Display		*dpy = XtDisplay(w) ;
+	Window		win = XtWindow(w) ;
+	GC		gc, gci ;
+
+	XPoint		pts[5] ;
+	Dimension	del = bsize(rw)/2 ;
+	Position	x,y ;		/* diamond center */
+#ifdef _ThreeDP_h
+	int i=0;
+	Dimension	s = swid(rw) ;
+	GC		top, bot, ctr ;
+#endif
+	gc = XtIsSensitive(w) ? rw->command.normal_GC : rw->label.gray_GC ;
+
+	gci = rw->command.set ? rw->command.normal_GC : rw->command.inverse_GC ;
+
+	x = rw->label.internal_width + bs(rw)/2 ;
+	y = rw->core.height/2 ;
+
+#ifdef	_ThreeDP_h
+	if( ! rw->command.set ) {
+	  top = rw->threeD.top_shadow_GC ;
+	  bot = rw->threeD.bot_shadow_GC ;
+	  ctr = gc ;		/* TODO */
+	} else {
+	  top = rw->threeD.bot_shadow_GC ;
+	  bot = rw->threeD.top_shadow_GC ;
+	  ctr = gc ;		/* TODO */
+	}
+#endif
+
+	pts[0].x = x - del ;
+	pts[0].y = y ;
+	pts[1].x = x ;
+	pts[1].y = y - del ;
+	pts[2].x = x + del ;
+	pts[2].y = y ;
+	pts[3].x = x ;
+	pts[3].y = y + del ;
+	pts[4] = pts[0] ;
+	XFillPolygon(dpy,win,gci, pts,4, Convex, CoordModeOrigin) ;
+
+#ifdef	_ThreeDP_h
+	for(i=0; i<s; ++i) {
+	  XDrawLine(dpy,win,bot, x-i-del,y, x,y+del+i) ;
+	  XDrawLine(dpy,win,bot, x+del+i,y, x,y+del+i) ;
+	}
+	for(i=0; i<s; ++i) {
+	  XDrawLine(dpy,win,top, x-del-i,y, x,y-del-i) ;
+	  XDrawLine(dpy,win,top, x+del+i,y, x,y-del-i) ;
+	}
+#else
+	XDrawLines(dpy,win,gc, pts,5, CoordModeOrigin) ;
+#endif
+}