Logo Search packages:      
Sourcecode: xdvik-ja version File versions  Download package

xlwradio.c

/* adapted from xlwradio.c in the XEmacs distribution.
   Changes are Copyright (C) 2002-2004 the xdvik development team.

   Note SU: This widget doesn't work with Xaw3d, and I have little
   inclination to make it work - the design would need to be utterly
   different, e.g. the radio would need to be a diamond instead of a
   circle, since 3d-shadowed circles don't look circular; colormap
   issues would need to be settled, etc. And besides, I don't like Xaw3d ;)
   
   So instead, the caller should just do:

   myWidget = XtVaCreateManagedWidget("foo",
   #ifdef XAW
                                      radioWidgetClass,
   #else
                                      toggleWidgetClass,
   #endif
                                      ... arglist ...);

   Feel free to submit patches if you want this implemented.
   
   Original copyright follows:
*/

/* 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 "xdvi-config.h"
#include "xdvi.h"
#include "xdvi-debug.h"
#include "util.h"
#include "xaw_bitmaps.h" /* bitmaps for radio/checkbuttons */

#include "xlwradioP.h"

#ifndef MOTIF /* entire file */

#include <stdio.h>

#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Xos.h>
#include <X11/Xaw/Text.h>
#include <X11/Xaw/AsciiText.h>
/*  #include "../src/xmu.h" */

#define     BOX_SIZE    16
#define PIXMAP_OFFSET 2    /* additional space between pixmap and label */

#ifndef UNUSED
# define UNUSED(x) ((void)(x))
#endif

#ifndef     MAX
# define MAX(i, j)       ( (i) > (j) ? (i) : (j) )
#endif


#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) + PIXMAP_OFFSET + 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);
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 offset(field) XtOffset(RadioWidget, radio.field)

static XtResource resources[] = {
  {XtNisRadio,  XtCIsRadio, XtRBoolean, sizeof(Boolean),
   offset(isRadio), XtRImmediate, (XtPointer)True },
};
#undef offset

#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          */
    resources,                      /* resources            */
    XtNumber(resources),            /* resource_count */
    NULLQUARK,                      /* xrm_class            */
    TRUE,                     /* compress_motion      */
    TRUE,                     /* compress_exposure    */
    TRUE,                     /* compress_enterleave  */
    FALSE,                    /* visible_interest     */
    RadioDestroy,             /* 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     */
#ifndef HAVE_OLD_XAW
     , NULL  
#endif
  },  /* 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 */
      None,                   /* selected radiobutton */
      None,                   /* unselected radiobutton */
      None,                   /* selected menubutton */
      None,                   /* unselected menubutton */
      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;
  }

}




static void
RadioInit (Widget   request,
         Widget   new,
         ArgList  args,
         Cardinal *num_args)
{
    RadioWidget rw = (RadioWidget) new;
    RadioWidget rw_req = (RadioWidget) request;
    Dimension     w,h;

    UNUSED(args);
    UNUSED(num_args);

    /* FIXME: should pixmap initialization be here?? */

    /* 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);
    }
    /*
      FIXME: access to XtWindow(rw) fails in the init method, so
      I moved the bitmap creation here -- is there a better way??
    */
    /* create pixmaps */
    rclass(rw)->radio_class.sel_radio
      = XCreateBitmapFromData(XtDisplay(rw), RootWindowOfScreen(XtScreen(rw)),
                        (char *)button_radio_on_bits, BUTTON_BITMAP_W, BUTTON_BITMAP_H);
    rclass(rw)->radio_class.unsel_radio
      = XCreateBitmapFromData(XtDisplay(rw), RootWindowOfScreen(XtScreen(rw)),
                        (char *)button_radio_off_bits, BUTTON_BITMAP_W, BUTTON_BITMAP_H);
    rclass(rw)->radio_class.sel_menu
      = XCreateBitmapFromData(XtDisplay(rw), RootWindowOfScreen(XtScreen(rw)),
                        (char *)button_check_on_bits, BUTTON_BITMAP_W, BUTTON_BITMAP_H);
    rclass(rw)->radio_class.unsel_menu
      = XCreateBitmapFromData(XtDisplay(rw), RootWindowOfScreen(XtScreen(rw)),
                        (char *)button_check_off_bits, BUTTON_BITMAP_W, BUTTON_BITMAP_H);
}

/*    Function Name: RadioDestroy
 *    Description: Destroy Callback for radio widget.
 *    Arguments: w - the radio widget that is being destroyed.
 *    Returns: none.
 */

static void
RadioDestroy (Widget w)
{
    RadioWidget rw = (RadioWidget)w;
    /* de-allocate bitmaps */
    XFreePixmap(XtDisplay(w), rclass(rw)->radio_class.sel_radio);
    XFreePixmap(XtDisplay(w), rclass(rw)->radio_class.unsel_radio);
    XFreePixmap(XtDisplay(w), rclass(rw)->radio_class.sel_menu);
    XFreePixmap(XtDisplay(w), rclass(rw)->radio_class.unsel_menu);
}


/* 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,
                 1UL);
      }
      DrawDiamond(w);
      /* 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;

    UNUSED(request);
    UNUSED(args);
    UNUSED(num_args);
    
    /* 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);
    }

    /* The label set values routine can resize the widget. We need to
     * recalculate if this is true.
     */
    if (newrw->label.label_x != oldrw->label.label_x)
    {
      RadioResize (new);
    }
    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;
    UNUSED(event);
    UNUSED(params);
    UNUSED(num_params);
    
    DrawHighlight(w, rw->command.normal_GC);
}


static      void
RadioUnhighlight (Widget   w,
              XEvent   *event,
              String   *params,
              Cardinal *num_params)
{
    RadioWidget   rw = (RadioWidget)w;
    UNUSED(event);
    UNUSED(params);
    UNUSED(num_params);
    
    DrawHighlight(w, rw->command.inverse_GC);
}


void
RadioSet (Widget   w,
        XEvent   *event,
        String   *params,
        Cardinal *num_params)
{
    RadioWidget   rw = (RadioWidget)w;
    RadioWidgetClass class = (RadioWidgetClass) w->core.widget_class;

    UNUSED(event);
    UNUSED(params);
    UNUSED(num_params);
    
    if( rw->command.set )
      return;

    rw->command.set = TRUE;
    if( XtIsRealized(w) )
      class->radio_class.drawDiamond(w);
}


void
RadioUnset (Widget   w,
          XEvent   *event,
          String   *params,
          Cardinal *num_params)
{
    RadioWidget   rw = (RadioWidget)w;
    RadioWidgetClass class = (RadioWidgetClass) w->core.widget_class;

    UNUSED(event);
    UNUSED(params);
    UNUSED(num_params);
    
    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);
    
    Position x = rw->label.internal_width;
    Position y = rw->core.height/2;
    GC gc = XtIsSensitive(w) ? rw->command.normal_GC : rw->label.gray_GC;
    Pixmap selected, unselected;

    if (rw->radio.isRadio) { /* it's a radio button */
      selected = rclass(rw)->radio_class.sel_radio;
      unselected = rclass(rw)->radio_class.unsel_radio;
    }
    else {
      selected = rclass(rw)->radio_class.sel_menu;
      unselected = rclass(rw)->radio_class.unsel_menu;
    }
    
    ASSERT(selected != None, "");
    ASSERT(unselected != None, "");
    
    if(rw->command.set) {
      XCopyPlane(dpy, selected, win, gc,
               0, 0, BUTTON_BITMAP_H, BUTTON_BITMAP_W,
               x, y - BUTTON_BITMAP_H / 2, 1L);
    }
    else {
      XCopyPlane(dpy, unselected, win, gc,
               0, 0, BUTTON_BITMAP_H, BUTTON_BITMAP_W,
               x, y - BUTTON_BITMAP_H / 2, 1L);
    }
}


#else
/* silence `empty compilation unit' warnings */
static void bar(void); static void foo() { bar(); } static void bar(void) { foo(); }
#endif /* MOTIF */

Generated by  Doxygen 1.6.0   Back to index