The following example adds the Motif ArrowButton widget to UNIX IDL in the form of an IDL program named widget_arrowb.pro.

The primary user interface to our arrow button widget is the WIDGET_ARROWB function. It presents an interface much like any of the built in WIDGET_* functions provided by IDL. WIDGET_ARROWB uses the MAKE_DLL procedure, and the AUTO_GLUE keyword to CALL_EXTERNAL to automatically build and load the C code required for this widget. This building and loading process is transparent to the IDL user, requiring only that you have a C compiler installed on your system. All the user has to do to use an arrow button widget is to call WIDGET_ARROWB

The WIDGET_ARROWB widget acts like a normal pushbutton. Events are sent when the button is pressed (VALUE=1) and released (VALUE=0). If the USE_OWN_SIZE keyword is set to zero, IDL performs its default sizing on the stub widget. A non-zero value causes a special routine provided by the WIDGET_ARROWB implementation to be registered to handle such sizing.

All of the code used in this example is available in the external/widstub directory of the UNIX IDL distribution. To run it, execute the following statements from IDL:

PUSHD, FILEPATH(’’, SUBDIRECTORY=[’external’,’widstub’]) 
WIDGET_ARROWB_TEST
POPD

When running WIDGET_ARROWB_TEST, you can specify the VERBOSE keyword to show you the compilation and linking steps it takes to build the sharable library from the C code. The use of PUSHD and POPD are due to the fact that your IDL search path (!PATH) is unlikely to have the directory containing these examples in it. PUSHD changes your working directory to the location where these files are found, and POPD restores it to its original location afterwards.

The IDL Program for WIDGET_ARROWB


The following text is the IDL program for WIDGET_ARROWB. It is found in the file named WIDGET_ARROWB.PRO:

FUNCTION WIDGET_ARROWB, parent, use_own_size, UVALUE=uvalue, $
            VERBOSE=verbose, _EXTRA=extra
 
; Uses WIDGET_STUB, and a sharable library containing
; the necessary C support code, to provide the IDL user
; with a Motif Arrow Button widget. The interface is consistent
; with that presented by the built in IDL widgets.
;
; If the sharable library does not exist, it is built using
; MAKE_DLL.
 
common WIDGET_ARROWB_BLK, shlib
 
; Build sharable lib if first call or lib 
; doesn’t exist 
 
build_lib = N_ELEMENTS(shlib) eq 0
IF (not build_lib) THEN build_lib = not FILE_TEST(shlib, /READ)
IF (build_lib) THEN BEGIN
 
  ; Location of the widget_arrowb files from IDL distribution 
   
  arrowb_dir = FILEPATH(’’,SUBDIRECTORY=[’external’,’widstub’])
   
  ; Use MAKE_DLL to build the widget_arrowb sharable library
  ; in the !MAKE_DLL.COMPILE_DIRECTORY directory.
  ;
  ; Normally, you wouldn’t use VERBOSE, or SHOW_ALL_OUTPUT
  ; once your work is debugged, but as a learning exercize it
  ; can be useful to see all the underlying work that gets
  ; done. If the user specified VERBOSE, then use those
  ; keywords to show what MAKE_DLL is doing. 
   
  MAKE_DLL,’widget_arrowb’, ’widget_arrowb’, $
     DLL_PATH=shlib, INPUT_DIR=arrowb_dir, $ 
     VERBOSE=verbose,SHOW_ALL_OUTPUT=verbose
ENDIF
 
; Use a stub widget along with the C code in the library to
; create an arrow button widget. The use of the AUTO_GLUE
; keyword simplifies the call to the sharable library by
; eliminating the need to use the CALL_EXTERNAL portable
; calling convention. 
 
l_parent = LONG(parent) 
l_use_own_size = $
   (n_elements(use_own_size) eq 0) ? 0L: LONG(use_own_size)
 
result = WIDGET_STUB(parent, _extra=extra)
 
IF (N_ELEMENTS(uvalue) ne 0) then $ 
   WIDGET_CONTROL, result, set_UVALUE=uvalue
JUNK = CALL_EXTERNAL(shlib, ’widget_arrowb’,l_parent,result,$ 
   l_use_own_size, VALUE=[1, 1, 1], /AUTO_GLUE)
RETURN, result 
END

 

The C Program for widget_arrowb.c


The C code invoked by the call to CALL_EXTERNAL in the above IDL code is contained in a file named widget_arrowb.c This file can be found in the widstub subdirectory of the external subdirectory of the IDL distribution. The contents of this file are shown below:

/*
* widget_arrowb.c - This file contains C code to be called from
* UNIX IDL via CALL_EXTERNAL. It uses the IDL stub widget to add
* a Motif ArrowButton to an IDL created widget hierarchy. The
* button issues a WIDGET_STUB_EVENT every time the button is
* released.
*
* While this code is Motif-centric, the principles apply across 
* platforms and could be adapted to Microsoft Windows.
*/
 
#include <stdio.h>
#include <X11/keysym.h> /* Keysyms for text widget events */
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>
#include <Xm/ArrowB.h>
#include "idl_export.h"
 
/*ARGSUSED*/
static void arrowb_CB(Widget w, caddr_t client_data, 
   caddr_t call_data)
{
  char *rec; 
  XmArrowButtonCallbackStruct *abcs;
   
  IDL_WidgetStubLock(TRUE);
if (rec = IDL_WidgetStubLookup((unsigned long) client_data)) 
   { 
   abcs = (XmArrowButtonCallbackStruct *) call_data; 
   IDL_WidgetIssueStubEvent(rec, abcs->reason == XmCR_ARM);
   }
   IDL_WidgetStubLock(FALSE);
}
 
 
static void arrowb_size_func(IDL_ULONG stub, int width, 
   int height)
{
char *stub_rec;
unsigned long t_id, b_id;
char buf[128];
 
IDL_WidgetStubLock(TRUE);
if (stub_rec = IDL_WidgetStubLookup(stub)) { 
   IDL_WidgetGetStubIds(stub_rec, &t_id, &b_id);
   sprintf(buf, "Setting WIDGET %d to width %d and height %d",
       stub, width, height);
   IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, buf);
   XtVaSetValues((Widget) b_id, XmNwidth, width, XmNheight, 
      height, NULL);
   }
   IDL_WidgetStubLock(FALSE);
   }
 
 
int widget_arrowb(IDL_LONG parent, IDL_LONG stub, IDL_LONG
   use_own_size_func)
{
  Widget parent_w; 
  Widget stub_w; 
  char *parent_rec; 
  char *stub_rec;
  unsigned long t_id, b_id;
 
IDL_WidgetStubLock(TRUE);
 
if ((parent_rec = IDL_WidgetStubLookup(parent))
   && (stub_rec = IDL_WidgetStubLookup(stub))) {
   /* Bottom widget of parent is parent to arrow button */ 
   IDL_WidgetGetStubIds(parent_rec, &t_id, &b_id);
   parent_w = (Widget) b_id;
   stub_w = XtVaCreateManagedWidget("arrowb"
      xmArrowButtonWidgetClass, 
      parent_w, NULL);
 
IDL_WidgetSetStubIds(stub_rec, (unsigned long) stub_w,
   (unsigned long) stub_w); 
XtAddCallback(stub_w, XmNarmCallback,
   (XtCallbackProc) arrowb_CB, (XtPointer) stub);
XtAddCallback(stub_w, XmNdisarmCallback,
   (XtCallbackProc) arrowb_CB, (XtPointer) stub);
if (use_own_size_func) 
   IDL_WidgetStubSetSizeFunc(stub_rec, arrowb_size_func);
   } 
   IDL_WidgetStubLock(FALSE); 
   return stub;
}
 

An IDL Program to Test the External Widget


This is an IDL widget program to test the ARROWB widget. This program is found in the file widget_arrowb_test.pro in the IDL distribution:

PRO widget_arrowb_test_event, ev 
   WIDGET_CONTROL, GET_UVALUE=val, ev.id 
   IF (val EQ 0) THEN BEGIN
      WIDGET_CONTROL, /DESTROY, ev.top
   ENDIF ELSE BEGIN
      HELP, /STRUCT, ev
      IF (ev.value EQ 1) THEN BEGIN 
         WIDGET_CONTROL, val, SET_VALUE=’New label string’ 
         tmp = WIDGET_INFO(ev.id, /GEOMETRY) 
         WIDGET_CONTROL, XSIZE=tmp.xsize+25, $
            YSIZE=tmp.ysize+25, ev.id
      ENDIF 
   ENDELSE
END
 
 
PRO widget_arrowb_test, VERBOSE=verbose 
  a = WIDGET_BASE(/COLUMN)
  b = WIDGET_BUTTON(a, VALUE=’Done’, UVALUE=0)
  label = WIDGET_LABEL(a, VALUE=’A label’)
  arrow_w = WIDGET_ARROWB(a, 0, XSIZE=100, YSIZE=100, $
     UVALUE=label, VERBOSE=verbose)
  arrow_w = WIDGET_ARROWB(a, 1, XSIZE=100, YSIZE=50, $
     UVALUE=label, VERBOSE=verbose)
  WIDGET_CONTROL,/REAL, a
  xmanager, ’WIDGET_ARROWB_TEST’, a, /NO_BLOCK
end