PLplot  5.10.0
plframe.c
Go to the documentation of this file.
00001 //  Copyright 1993, 1994, 1995
00002 //  Maurice LeBrun                      mjl@dino.ph.utexas.edu
00003 //  Institute for Fusion Studies        University of Texas at Austin
00004 //
00005 //  Copyright (C) 2004  Joao Cardoso
00006 //  Copyright (C) 2004  Andrew Ross
00007 //
00008 //  This file is part of PLplot.
00009 //
00010 //  PLplot is free software; you can redistribute it and/or modify
00011 //  it under the terms of the GNU Library General Public License as published
00012 //  by the Free Software Foundation; either version 2 of the License, or
00013 //  (at your option) any later version.
00014 //
00015 //  PLplot is distributed in the hope that it will be useful,
00016 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 //  GNU Library General Public License for more details.
00019 //
00020 //  You should have received a copy of the GNU Library General Public License
00021 //  along with PLplot; if not, write to the Free Software
00022 //  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00023 //
00024 //
00025 //  Based upon tkFrame.c from the TK 3.2 distribution:
00026 //
00027 //  Copyright 1990 Regents of the University of California.
00028 //  Permission to use, copy, modify, and distribute this
00029 //  software and its documentation for any purpose and without
00030 //  fee is hereby granted, provided that the above copyright
00031 //  notice appear in all copies.  The University of California
00032 //  makes no representations about the suitability of this
00033 //  software for any purpose.  It is provided "as is" without
00034 //  express or implied warranty.
00035 //
00036 //--------------------------------------------------------------------------
00037 //
00038 //  This module implements "plframe" widgets for the Tk toolkit.  These are
00039 //  frames that have extra logic to allow them to be interfaced with the
00040 //  PLplot X driver.  These are then drawn into and respond to keyboard and
00041 //  mouse events.
00042 //
00043 //
00044 // #define DEBUG_ENTER
00045 // #define DEBUG
00046 //
00047 
00048 #define DEBUGx
00049 
00050 #define NEED_PLDEBUG
00051 #include "plserver.h"
00052 #include "plxwd.h"
00053 #include "tcpip.h"
00054 
00055 #ifdef PL_HAVE_UNISTD_H
00056 #include <unistd.h>
00057 #endif
00058 #include <fcntl.h>
00059 
00060 #undef HAVE_ITCL
00061 
00062 #define NDEV    100             // Max number of output device types in menu
00063 
00064 // If set, BUFFER_FIFO causes FIFO i/o to be buffered
00065 
00066 #define BUFFER_FIFO    1
00067 
00068 // If set, causes a file handler to be used with FIFO
00069 
00070 #define FH_FIFO    0
00071 
00072 // A handy command wrapper
00073 
00074 #define plframe_cmd( code ) \
00075     if ( ( code ) == TCL_ERROR ) return ( TCL_ERROR );
00076 
00077 // Backward compatibility junk
00078 
00079 #if TCL_MAJOR_VERSION <= 7 && TCL_MINOR_VERSION <= 4
00080 #define Tk_Cursor    Cursor
00081 #endif
00082 
00083 //
00084 // A data structure of the following type is kept for each
00085 // plframe that currently exists for this process:
00086 //
00087 
00088 typedef struct
00089 {
00090 // This is stuff taken from tkFrame.c
00091 
00092     Tk_Window tkwin;            // Window that embodies the frame.  NULL
00093                                 // means that the window has been destroyed
00094                                 // but the data structures haven't yet been
00095                                 // cleaned up.
00096     Display    *display;        // Display containing widget.  Used, among
00097                                 // other things, so that resources can be
00098                                 // freed even after tkwin has gone away.
00099     Tcl_Interp *interp;         // Interpreter associated with
00100                                 // widget.  Used to delete widget
00101                                 // command.
00102 #ifdef HAVE_ITCL
00103     Tcl_Command widgetCmd;      // Token for frame's widget command.
00104 #endif
00105     Tk_3DBorder border;         // Structure used to draw 3-D border and
00106                                 // background.
00107     int         borderWidth;    // Width of 3-D border (if any).
00108     int         relief;         // 3-d effect: TK_RELIEF_RAISED etc.
00109     int         width;          // Width to request for window.  <= 0 means
00110                                 // don't request any size.
00111     int         height;         // Height to request for window.  <= 0 means
00112                                 // don't request any size.
00113     Tk_Cursor   cursor;         // Current cursor for window, or None.
00114     int         flags;          // Various flags;  see below for
00115                                 // definitions.
00116 
00117 // These are new to plframe widgets
00118 
00119 // control stuff
00120 
00121     int      tkwin_initted;     // Set first time widget is mapped
00122     PLStream *pls;              // PLplot stream pointer
00123     PLINT    ipls;              // PLplot stream number
00124     PLINT    ipls_save;         // PLplot stream number, save files
00125 
00126     PLRDev   *plr;              // Renderer state information.  Malloc'ed
00127     XColor   *bgColor;          // Background color
00128     char     *plpr_cmd;         // Holds print command name.  Malloc'ed
00129 
00130 // Used to handle resize and expose events
00131 
00132     PLDisplay pldis;            // Info about the display window
00133     int       prevWidth;        // Previous window width
00134     int       prevHeight;       // Previous window height
00135 
00136 // Support for save operations
00137 
00138     char       *SaveFnam;       // File name we are currently saving to.
00139                                 // Malloc'ed.
00140     const char **devDesc;       // Descriptive names for file-oriented
00141                                 // devices.  Malloc'ed.
00142     const char **devName;       // Keyword names of file-oriented devices.
00143                                 // Malloc'ed.
00144 
00145 // Used in selecting & modifying plot or device area
00146 
00147     GC        xorGC;            // GC used for rubber-band drawing
00148     XPoint    pts[5];           // Points for rubber-band drawing
00149     int       continue_draw;    // Set when doing rubber-band draws
00150     Tk_Cursor xhair_cursor;     // cursor used for drawing
00151     PLFLT     xl, xr, yl, yr;   // Bounds on plot viewing area
00152     char      *xScrollCmd;      // Command prefix for communicating with
00153                                 // horizontal scrollbar.  NULL means no
00154                                 // command to issue.  Malloc'ed.
00155     char      *yScrollCmd;      // Command prefix for communicating with
00156                                 // vertical scrollbar.  NULL means no
00157                                 // command to issue.  Malloc'ed.
00158 
00159 // Used for flashing bop or eop condition
00160 
00161     char *bopCmd;               // Proc to call at bop
00162     char *eopCmd;               // Proc to call at eop
00163 
00164 // Used for drawing graphic crosshairs
00165 
00166     int    xhairs;              // Configuration option to turn on xhairs
00167     int    drawing_xhairs;      // Set if we are currently drawing xhairs
00168     XPoint xhair_x[2];          // Points for horizontal xhair line
00169     XPoint xhair_y[2];          // Points for vertical xhair line
00170 
00171 // Used for drawing a rubber band lilne segment
00172 
00173     int    rband;               // Configuration option to turn on rband
00174     int    drawing_rband;       // See if we are currently drawing rband
00175     XPoint rband_pt[2];         // Ends of rubber band line
00176 } PlFrame;
00177 
00178 //
00179 // Flag bits for plframes:
00180 //
00181 // REFRESH_PENDING:             Non-zero means a DoWhenIdle handler
00182 //                              has already been queued to refresh
00183 //                              this window.
00184 // RESIZE_PENDING;              Used to reschedule resize events
00185 // REDRAW_PENDING;              Used to redraw contents of plot buffer
00186 // UPDATE_V_SCROLLBAR:          Non-zero means vertical scrollbar needs
00187 //                              to be updated.
00188 // UPDATE_H_SCROLLBAR:          Non-zero means horizontal scrollbar needs
00189 //                              to be updated.
00190 //
00191 
00192 #define REFRESH_PENDING       1
00193 #define RESIZE_PENDING        2
00194 #define REDRAW_PENDING        4
00195 #define UPDATE_V_SCROLLBAR    8
00196 #define UPDATE_H_SCROLLBAR    16
00197 
00198 // Defaults for plframes:
00199 
00200 #define DEF_PLFRAME_BG_COLOR        "Black"
00201 #define DEF_PLFRAME_BG_MONO         "White"
00202 #define DEF_PLFRAME_BORDER_WIDTH    "0"
00203 #define DEF_PLFRAME_CURSOR          ( (char *) NULL )
00204 #define DEF_PLFRAME_HEIGHT          "0"
00205 #define DEF_PLFRAME_RELIEF          "flat"
00206 #define DEF_PLFRAME_WIDTH           "0"
00207 
00208 // Configuration info
00209 
00210 static Tk_ConfigSpec configSpecs[] = {
00211     { TK_CONFIG_BORDER,        "-background",     "background",     "Background",
00212       DEF_PLFRAME_BG_COLOR, Tk_Offset( PlFrame, border ),
00213       TK_CONFIG_COLOR_ONLY, NULL },
00214 //
00215 //  {TK_CONFIG_COLOR, (char *) NULL, (char *) NULL, (char *) NULL,
00216 //      (char *) NULL, Tk_Offset(PlFrame, bgColor),
00217 //      TK_CONFIG_COLOR_ONLY},
00218 //
00219 #ifndef MAC_TCL
00220     { TK_CONFIG_COLOR,         "-plbg",           "plbackground",   "Plbackground",
00221       DEF_PLFRAME_BG_COLOR, Tk_Offset( PlFrame, bgColor ),
00222       TK_CONFIG_COLOR_ONLY, NULL },
00223 #endif
00224     { TK_CONFIG_BORDER,        "-background",     "background",     "Background",
00225       DEF_PLFRAME_BG_MONO, Tk_Offset( PlFrame, border ),
00226       TK_CONFIG_MONO_ONLY, NULL },
00227 //
00228 //  {TK_CONFIG_COLOR, (char *) NULL, (char *) NULL, (char *) NULL,
00229 //      (char *) NULL, Tk_Offset(PlFrame, bgColor),
00230 //      TK_CONFIG_MONO_ONLY},
00231 //
00232 #ifndef MAC_TCL
00233     { TK_CONFIG_COLOR,         "-plbg",           (char *) NULL,    (char *) NULL,
00234       DEF_PLFRAME_BG_MONO, Tk_Offset( PlFrame, bgColor ),
00235       TK_CONFIG_MONO_ONLY, NULL },
00236 #endif
00237     { TK_CONFIG_SYNONYM,       "-bd",             "borderWidth",    (char *) NULL,
00238       (char *) NULL, 0, 0, NULL },
00239     { TK_CONFIG_SYNONYM,       "-bg",             "background",     (char *) NULL,
00240       (char *) NULL, 0, 0, NULL },
00241     { TK_CONFIG_PIXELS,        "-borderwidth",    "borderWidth",    "BorderWidth",
00242       DEF_PLFRAME_BORDER_WIDTH, Tk_Offset( PlFrame, borderWidth ), 0, NULL },
00243     { TK_CONFIG_ACTIVE_CURSOR, "-cursor",         "cursor",         "Cursor",
00244       DEF_PLFRAME_CURSOR, Tk_Offset( PlFrame, cursor ), TK_CONFIG_NULL_OK, NULL },
00245     { TK_CONFIG_STRING,        "-bopcmd",         "bopcmd",         "PgCommand",
00246       (char *) NULL, Tk_Offset( PlFrame, bopCmd ), TK_CONFIG_NULL_OK, NULL },
00247     { TK_CONFIG_STRING,        "-eopcmd",         "eopcmd",         "PgCommand",
00248       (char *) NULL, Tk_Offset( PlFrame, eopCmd ), TK_CONFIG_NULL_OK, NULL },
00249     { TK_CONFIG_PIXELS,        "-height",         "height",         "Height",
00250       DEF_PLFRAME_HEIGHT, Tk_Offset( PlFrame, height ), 0, NULL },
00251     { TK_CONFIG_RELIEF,        "-relief",         "relief",         "Relief",
00252       DEF_PLFRAME_RELIEF, Tk_Offset( PlFrame, relief ), 0, NULL },
00253     { TK_CONFIG_PIXELS,        "-width",          "width",          "Width",
00254       DEF_PLFRAME_WIDTH, Tk_Offset( PlFrame, width ), 0, NULL },
00255     { TK_CONFIG_BOOLEAN,       "-xhairs",         (char *) NULL,    (char *) NULL,
00256       "0", Tk_Offset( PlFrame, xhairs ), TK_CONFIG_DONT_SET_DEFAULT, NULL },
00257     { TK_CONFIG_BOOLEAN,       "-rubberband",     (char *) NULL,    (char *) NULL,
00258       "0", Tk_Offset( PlFrame, rband ), TK_CONFIG_DONT_SET_DEFAULT, NULL },
00259     { TK_CONFIG_STRING,        "-xscrollcommand", "xScrollCommand", "ScrollCommand",
00260       (char *) NULL, Tk_Offset( PlFrame, xScrollCmd ), TK_CONFIG_NULL_OK, NULL },
00261     { TK_CONFIG_STRING,        "-yscrollcommand", "yScrollCommand", "ScrollCommand",
00262       (char *) NULL, Tk_Offset( PlFrame, yScrollCmd ), TK_CONFIG_NULL_OK, NULL },
00263     { TK_CONFIG_END,           (char *) NULL,     (char *) NULL,    (char *) NULL,
00264       (char *) NULL, 0, 0, NULL }
00265 };
00266 
00267 // Forward declarations for procedures defined later in this file:
00268 
00269 // Externals
00270 
00271 int   plFrameCmd( ClientData, Tcl_Interp *, int, const char ** );
00272 
00273 // These are invoked by the TK dispatcher
00274 
00275 #if TK_MAJOR_VERSION < 4 || ( TK_MAJOR_VERSION == 4 && TK_MINOR_VERSION == 0 )
00276 #define FreeProcArg    ClientData
00277 #else
00278 #define FreeProcArg    char *
00279 #endif
00280 
00281 static void  DestroyPlFrame( FreeProcArg );
00282 static void  DisplayPlFrame( ClientData );
00283 static void  PlFrameInit( ClientData );
00284 static void  PlFrameConfigureEH( ClientData, XEvent * );
00285 static void  PlFrameExposeEH( ClientData, XEvent * );
00286 static void  PlFrameMotionEH( ClientData, register XEvent * );
00287 static void  PlFrameEnterEH( ClientData, register XEvent * );
00288 static void  PlFrameLeaveEH( ClientData, register XEvent * );
00289 static void  PlFrameKeyEH( ClientData, register XEvent * );
00290 static int   PlFrameWidgetCmd( ClientData, Tcl_Interp *, int, const char ** );
00291 static int   ReadData( ClientData, int );
00292 static void  Install_cmap( PlFrame *plFramePtr );
00293 
00294 // These are invoked by PlFrameWidgetCmd to process widget commands
00295 
00296 static int   Closelink( Tcl_Interp *, PlFrame *, int, const char ** );
00297 static int   Cmd( Tcl_Interp *, PlFrame *, int, const char ** );
00298 static int   ColorManip( Tcl_Interp *, PlFrame *, int, const char ** );
00299 static int   ConfigurePlFrame( Tcl_Interp *, PlFrame *, int, const char **, int );
00300 static int   Draw( Tcl_Interp *, PlFrame *, int, const char ** );
00301 static int   Info( Tcl_Interp *, PlFrame *, int, const char ** );
00302 static int   Openlink( Tcl_Interp *, PlFrame *, int, const char ** );
00303 static int   Orient( Tcl_Interp *, PlFrame *, int, const char ** );
00304 static int   Page( Tcl_Interp *, PlFrame *, int, const char ** );
00305 static int   Print( Tcl_Interp *, PlFrame *, int, const char ** );
00306 static int   Redraw( Tcl_Interp *, PlFrame *, int, const char ** );
00307 static int   Save( Tcl_Interp *, PlFrame *, int, const char ** );
00308 static int   View( Tcl_Interp *, PlFrame *, int, const char ** );
00309 static int   xScroll( Tcl_Interp *, PlFrame *, int, const char ** );
00310 static int   yScroll( Tcl_Interp *, PlFrame *, int, const char ** );
00311 static int   report( Tcl_Interp *, PlFrame *, int, const char ** );
00312 
00313 // Routines for manipulating graphic crosshairs
00314 
00315 static void  CreateXhairs( PlFrame * );
00316 static void  DestroyXhairs( PlFrame * );
00317 static void  DrawXhairs( PlFrame *, int, int );
00318 static void  UpdateXhairs( PlFrame * );
00319 
00320 // Routines for manipulating the rubberband line
00321 
00322 static void  CreateRband( PlFrame * );
00323 static void  DestroyRband( PlFrame * );
00324 static void  DrawRband( PlFrame *, int, int );
00325 static void  UpdateRband( PlFrame * );
00326 
00327 // Callbacks from plplot library
00328 
00329 static void  process_bop( void *, int * );
00330 static void  process_eop( void *, int * );
00331 
00332 // Utility routines
00333 
00334 static void  gbox( PLFLT *, PLFLT *, PLFLT *, PLFLT *, const char ** );
00335 static void  UpdateVScrollbar( register PlFrame * );
00336 static void  UpdateHScrollbar( register PlFrame * );
00337 
00338 //
00339 //--------------------------------------------------------------------------
00340 //
00341 // plFrameCmd --
00342 //
00343 //      This procedure is invoked to process the "plframe" Tcl
00344 //      command.  See the user documentation for details on what it
00345 //      does.
00346 //
00347 // Results:
00348 //      A standard Tcl result.
00349 //
00350 // Side effects:
00351 //      See the user documentation.
00352 //
00353 //--------------------------------------------------------------------------
00354 //
00355 
00356 int
00357 plFrameCmd( ClientData PL_UNUSED( clientData ), Tcl_Interp *interp,
00358             int argc, const char **argv )
00359 {
00360     Tk_Window        new;
00361     register PlFrame *plFramePtr;
00362     register PLRDev  *plr;
00363     int i, ndev;
00364 
00365     dbug_enter( "plFrameCmd" );
00366 
00367     if ( argc < 2 )
00368     {
00369         Tcl_AppendResult( interp, "wrong # args: should be \"",
00370             argv[0], " pathName ?options?\"", (char *) NULL );
00371         return TCL_ERROR;
00372     }
00373 
00374 // Create the window.
00375 
00376     new = Tk_CreateWindowFromPath( interp, Tk_MainWindow( interp ),
00377         argv[1], (char *) NULL );
00378     if ( new == NULL )
00379     {
00380         return TCL_ERROR;
00381     }
00382 
00383     plFramePtr = (PlFrame *) ckalloc( sizeof ( PlFrame ) );
00384 
00385     // Initialize in the same order as the members of the struct just
00386     // to keep track of what is initialized and what not.
00387 
00388     plFramePtr->tkwin   = new;
00389     plFramePtr->display = Tk_Display( new );
00390     plFramePtr->interp  = interp;
00391     //plFramePtr->widgetCMD    = <initialized below for HAVE_ITCL case>
00392     plFramePtr->border = NULL;
00393     //plFramePtr->borderWidth  = <uninitialized>
00394     //plFramePtr->relief       = <uninitialized>
00395     plFramePtr->width         = Tk_Width( plFramePtr->tkwin );
00396     plFramePtr->height        = Tk_Height( plFramePtr->tkwin );
00397     plFramePtr->cursor        = None;
00398     plFramePtr->flags         = 0;
00399     plFramePtr->tkwin_initted = 0;
00400     // Associate new PLplot stream with this widget
00401     plmkstrm( &plFramePtr->ipls );
00402     plgpls( &plFramePtr->pls );
00403     plFramePtr->ipls_save    = 0;
00404     plFramePtr->plr          = (PLRDev *) ckalloc( sizeof ( PLRDev ) );
00405     plFramePtr->bgColor      = NULL;
00406     plFramePtr->plpr_cmd     = NULL;
00407     plFramePtr->pldis.x      = 0;
00408     plFramePtr->pldis.y      = 0;
00409     plFramePtr->pldis.width  = 0;
00410     plFramePtr->pldis.height = 0;
00411     plFramePtr->prevWidth    = 0;
00412     plFramePtr->prevHeight   = 0;
00413     plFramePtr->SaveFnam     = NULL;
00414     // plFramePtr->devDesc     = <uninitialized, to be malloced?>;
00415     // plFramePtr->devName     = <uninitialized, to be malloced?>;
00416     plFramePtr->xorGC = NULL;
00417     // plFram Ptr->pts         = <uninitialized array>;
00418     plFramePtr->continue_draw  = 0;
00419     plFramePtr->xhair_cursor   = None;
00420     plFramePtr->xl             = 0.;
00421     plFramePtr->yl             = 0.;
00422     plFramePtr->xr             = 1.;
00423     plFramePtr->yr             = 1.;
00424     plFramePtr->xScrollCmd     = NULL;
00425     plFramePtr->yScrollCmd     = NULL;
00426     plFramePtr->bopCmd         = NULL;
00427     plFramePtr->eopCmd         = NULL;
00428     plFramePtr->xhairs         = 0;
00429     plFramePtr->drawing_xhairs = 0;
00430     // plFram Ptr->xhair_x     = <uninitialized array>;
00431     // plFram Ptr->xhair_y     = <uninitialized array>;
00432     plFramePtr->rband         = 0;
00433     plFramePtr->drawing_rband = 0;
00434     // plFram Ptr->rband_pt    = <uninitialized array>;
00435 
00436     plr         = plFramePtr->plr;
00437     plr->pdfs   = NULL;
00438     plr->at_bop = 0;
00439     plr->at_eop = 0;
00440     plr->iodev  = (PLiodev *) ckalloc( sizeof ( PLiodev ) );
00441     plr_start( plr );
00442 
00443 // Set up stuff for rubber-band drawing
00444 
00445     plFramePtr->xhair_cursor =
00446         Tk_GetCursor( plFramePtr->interp, plFramePtr->tkwin, "crosshair" );
00447 
00448 // Partially initialize X driver.
00449 
00450     pllib_init();
00451 
00452     plsdev( "xwin" );
00453     pllib_devinit();
00454     plP_esc( PLESC_DEVINIT, NULL );
00455 
00456 // Create list of valid device names and keywords for page dumps
00457 
00458     plFramePtr->devDesc = (const char **) ckalloc( NDEV * sizeof ( char ** ) );
00459     plFramePtr->devName = (const char **) ckalloc( NDEV * sizeof ( char ** ) );
00460     for ( i = 0; i < NDEV; i++ )
00461     {
00462         plFramePtr->devDesc[i] = NULL;
00463         plFramePtr->devName[i] = NULL;
00464     }
00465     ndev = NDEV;
00466     plgFileDevs( &plFramePtr->devDesc, &plFramePtr->devName, &ndev );
00467 
00468 // Start up event handlers and other good stuff
00469 
00470     Tk_SetClass( plFramePtr->tkwin, "Plframe" );
00471 
00472     Tk_CreateEventHandler( plFramePtr->tkwin, StructureNotifyMask,
00473         PlFrameConfigureEH, (ClientData) plFramePtr );
00474 
00475     Tk_CreateEventHandler( plFramePtr->tkwin, ExposureMask,
00476         PlFrameExposeEH, (ClientData) plFramePtr );
00477 
00478 #ifdef HAVE_ITCL
00479     plFramePtr->widgetCmd =
00480 #endif
00481     Tcl_CreateCommand( interp, Tk_PathName( plFramePtr->tkwin ),
00482         (Tcl_CmdProc *) PlFrameWidgetCmd, (ClientData) plFramePtr, (Tcl_CmdDeleteProc *) NULL );
00483 #ifdef HAVE_ITCL
00484     Itk_SetWidgetCommand( plFramePtr->tkwin, plFramePtr->widgetCmd );
00485 #endif
00486 
00487     if ( ConfigurePlFrame( interp, plFramePtr, argc - 2, argv + 2, 0 ) != TCL_OK )
00488     {
00489 #ifdef HAVE_ITCL
00490         Itk_SetWidgetCommand( plFramePtr->tkwin, (Tcl_Command) NULL );
00491 #endif
00492         Tk_DestroyWindow( plFramePtr->tkwin );
00493         return TCL_ERROR;
00494     }
00495     Tcl_SetResult( interp, Tk_PathName( plFramePtr->tkwin ), TCL_VOLATILE );
00496 
00497     return TCL_OK;
00498 }
00499 
00500 //
00501 //--------------------------------------------------------------------------
00502 //
00503 // PlFrameWidgetCmd --
00504 //
00505 //      This procedure is invoked to process the Tcl command that
00506 //      corresponds to a plframe widget.  See the user
00507 //      documentation for details on what it does.
00508 //
00509 // Results:
00510 //      A standard Tcl result.
00511 //
00512 // Side effects:
00513 //      See the user documentation.
00514 //
00515 //--------------------------------------------------------------------------
00516 //
00517 
00518 static int
00519 PlFrameWidgetCmd( ClientData clientData, Tcl_Interp *interp,
00520                   int argc, const char **argv )
00521 {
00522     register PlFrame *plFramePtr = (PlFrame *) clientData;
00523     int  result = TCL_OK;
00524     int  length;
00525     char c;
00526     char res[20];
00527 
00528     dbug_enter( "PlFrameWidgetCmd" );
00529 
00530 #ifdef DEBUG
00531     {
00532         int      i;
00533         PLStream *pls;
00534         plgpls( pls );
00535         printf( "Current stream %d, frame stream %d\n",
00536             pls->ipls, plFramePtr->ipls );
00537         printf( "PlFrameWidgetCmd: " );
00538         for ( i = 0; i < argc; i++ )
00539             printf( " %s", argv[i] );
00540         printf( "\n" );
00541     }
00542 #endif
00543 
00544     if ( argc < 2 )
00545     {
00546         Tcl_AppendResult( interp, "wrong # args: should be \"",
00547             argv[0], " option ?arg arg ...?\"", (char *) NULL );
00548         return TCL_ERROR;
00549     }
00550     Tk_Preserve( (ClientData) plFramePtr );
00551     c      = argv[1][0];
00552     length = (int) strlen( argv[1] );
00553 
00554 // First, before anything else, we have to set the stream to be the one that
00555 // corresponds to this widget.
00556     plsstrm( plFramePtr->ipls );
00557 
00558 // cmd -- issue a command to the PLplot library
00559 
00560     if ( ( c == 'c' ) && ( strncmp( argv[1], "cmd", (size_t) length ) == 0 ) )
00561     {
00562         result = Cmd( interp, plFramePtr, argc - 2, argv + 2 );
00563     }
00564 
00565 // cget
00566 
00567     else if ( ( c == 'c' ) && ( strncmp( argv[1], "cget", (size_t) length ) == 0 ) )
00568     {
00569         if ( argc > 2 )
00570         {
00571             Tcl_AppendResult( interp, "wrong # args: should be \"",
00572                 argv[0], " cget <option>\"", (char *) NULL );
00573             result = TCL_ERROR;
00574             goto done;
00575         }
00576         else
00577         {
00578             result = Tk_ConfigureInfo( interp, plFramePtr->tkwin, configSpecs,
00579                 (char *) plFramePtr, (char *) NULL, 0 );
00580         }
00581     }
00582 
00583 // configure
00584 
00585     else if ( ( c == 'c' ) && ( strncmp( argv[1], "configure", (size_t) length ) == 0 ) )
00586     {
00587         if ( argc == 2 )
00588         {
00589             result = Tk_ConfigureInfo( interp, plFramePtr->tkwin, configSpecs,
00590                 (char *) plFramePtr, (char *) NULL, 0 );
00591         }
00592         else if ( argc == 3 )
00593         {
00594             result = Tk_ConfigureInfo( interp, plFramePtr->tkwin, configSpecs,
00595                 (char *) plFramePtr, argv[2], 0 );
00596         }
00597         else
00598         {
00599             result = ConfigurePlFrame( interp, plFramePtr, argc - 2, argv + 2,
00600                 TK_CONFIG_ARGV_ONLY );
00601         }
00602     }
00603 
00604 // double buffering
00605 
00606     else if ( ( c == 'd' ) &&
00607               ( ( strncmp( argv[1], "db", (size_t) length ) == 0 ) ||
00608                 ( strncmp( argv[1], "doublebuffering", (size_t) length == 0 ) ) ) )
00609     {
00610         PLBufferingCB bcb;
00611 
00612         if ( argc == 3 )
00613         {
00614             if ( strcmp( argv[2], "on" ) == 0 )
00615             {
00616                 bcb.cmd = PLESC_DOUBLEBUFFERING_ENABLE;
00617                 pl_cmd( PLESC_DOUBLEBUFFERING, &bcb );
00618             }
00619             if ( strcmp( argv[2], "off" ) == 0 )
00620             {
00621                 bcb.cmd = PLESC_DOUBLEBUFFERING_DISABLE;
00622                 pl_cmd( PLESC_DOUBLEBUFFERING, &bcb );
00623             }
00624             if ( strcmp( argv[2], "query" ) == 0 )
00625             {
00626                 bcb.cmd = PLESC_DOUBLEBUFFERING_QUERY;
00627                 pl_cmd( PLESC_DOUBLEBUFFERING, &bcb );
00628                 snprintf( res, 20, "%d", bcb.result );
00629                 Tcl_SetResult( interp, res, TCL_VOLATILE );
00630             }
00631         }
00632 
00633         result = TCL_OK;
00634     }
00635 
00636 // closelink -- Close a binary data link previously opened with openlink
00637 
00638     else if ( ( c == 'c' ) && ( strncmp( argv[1], "closelink", (size_t) length ) == 0 ) )
00639     {
00640         if ( argc > 2 )
00641         {
00642             Tcl_AppendResult( interp, "wrong # args: should be \"",
00643                 argv[0], (char *) NULL );
00644             result = TCL_ERROR;
00645             goto done;
00646         }
00647         else
00648         {
00649             result = Closelink( interp, plFramePtr, argc - 2, argv + 2 );
00650         }
00651     }
00652 
00653 // draw -- rubber-band draw used in region selection
00654 
00655     else if ( ( c == 'd' ) && ( strncmp( argv[1], "draw", (size_t) length ) == 0 ) )
00656     {
00657         if ( argc == 2 )
00658         {
00659             Tcl_AppendResult( interp, "wrong # args: should be \"",
00660                 argv[0], " draw op ?options?\"", (char *) NULL );
00661             result = TCL_ERROR;
00662             goto done;
00663         }
00664         else
00665         {
00666             result = Draw( interp, plFramePtr, argc - 2, argv + 2 );
00667         }
00668     }
00669 
00670 // color-manipulating commands, grouped together for convenience
00671 
00672     else if ( ( ( c == 'g' ) && ( ( strncmp( argv[1], "gcmap0", (size_t) length ) == 0 ) ||
00673                                   ( strncmp( argv[1], "gcmap1", (size_t) length ) == 0 ) ) ) ||
00674               ( ( c == 's' ) && ( ( strncmp( argv[1], "scmap0", (size_t) length ) == 0 ) ||
00675                                   ( strncmp( argv[1], "scmap1", (size_t) length ) == 0 ) ||
00676                                   ( strncmp( argv[1], "scol0", (size_t) length ) == 0 ) ||
00677                                   ( strncmp( argv[1], "scol1", (size_t) length ) == 0 ) ) ) )
00678         result = ColorManip( interp, plFramePtr, argc - 1, argv + 1 );
00679 
00680 // info -- returns requested info
00681 
00682     else if ( ( c == 'i' ) && ( strncmp( argv[1], "info", (size_t) length ) == 0 ) )
00683     {
00684         result = Info( interp, plFramePtr, argc - 2, argv + 2 );
00685     }
00686 
00687 // orient -- Set plot orientation
00688 
00689     else if ( ( c == 'o' ) && ( strncmp( argv[1], "orient", (size_t) length ) == 0 ) )
00690     {
00691         result = Orient( interp, plFramePtr, argc - 2, argv + 2 );
00692     }
00693 
00694 // openlink -- Open a binary data link (FIFO or socket)
00695 
00696     else if ( ( c == 'o' ) && ( strncmp( argv[1], "openlink", (size_t) length ) == 0 ) )
00697     {
00698         if ( argc < 3 )
00699         {
00700             Tcl_AppendResult( interp, "wrong # args: should be \"",
00701                 argv[0], " option ?arg arg ...?\"", (char *) NULL );
00702             result = TCL_ERROR;
00703             goto done;
00704         }
00705         else
00706         {
00707             result = Openlink( interp, plFramePtr, argc - 2, argv + 2 );
00708         }
00709     }
00710 
00711 // page -- change or return output page setup
00712 
00713     else if ( ( c == 'p' ) && ( strncmp( argv[1], "page", (size_t) length ) == 0 ) )
00714     {
00715         result = Page( interp, plFramePtr, argc - 2, argv + 2 );
00716     }
00717 
00718 // print -- prints plot
00719 
00720     else if ( ( c == 'p' ) && ( strncmp( argv[1], "print", (size_t) length ) == 0 ) )
00721     {
00722         result = Print( interp, plFramePtr, argc - 2, argv + 2 );
00723     }
00724 
00725 // redraw -- redraw plot
00726 
00727     else if ( ( c == 'r' ) && ( strncmp( argv[1], "redraw", (size_t) length ) == 0 ) )
00728     {
00729         if ( argc > 2 )
00730         {
00731             Tcl_AppendResult( interp, "wrong # args: should be \"",
00732                 argv[0], " redraw\"", (char *) NULL );
00733             result = TCL_ERROR;
00734             goto done;
00735         }
00736         else
00737         {
00738             result = Redraw( interp, plFramePtr, argc - 2, argv + 2 );
00739         }
00740     }
00741 
00742 // report -- find out useful info about the plframe (GMF)
00743 
00744     else if ( ( c == 'r' ) && ( strncmp( argv[1], "report", (size_t) length ) == 0 ) )
00745     {
00746         result = report( interp, plFramePtr, argc - 2, argv + 2 );
00747     }
00748 
00749 // save -- saves plot to the specified plot file type
00750 
00751     else if ( ( c == 's' ) && ( strncmp( argv[1], "save", (size_t) length ) == 0 ) )
00752     {
00753         result = Save( interp, plFramePtr, argc - 2, argv + 2 );
00754     }
00755 
00756 // view -- change or return window into plot
00757 
00758     else if ( ( c == 'v' ) && ( strncmp( argv[1], "view", (size_t) length ) == 0 ) )
00759     {
00760         result = View( interp, plFramePtr, argc - 2, argv + 2 );
00761     }
00762 
00763 // xscroll -- horizontally scroll window into plot
00764 
00765     else if ( ( c == 'x' ) && ( strncmp( argv[1], "xscroll", (size_t) length ) == 0 ) )
00766     {
00767         if ( argc == 2 || argc > 3 )
00768         {
00769             Tcl_AppendResult( interp, "wrong # args: should be \"",
00770                 argv[0], " xscroll pixel\"", (char *) NULL );
00771             result = TCL_ERROR;
00772             goto done;
00773         }
00774         else
00775         {
00776             result = xScroll( interp, plFramePtr, argc - 2, argv + 2 );
00777         }
00778     }
00779 
00780 // yscroll -- vertically scroll window into plot
00781 
00782     else if ( ( c == 'y' ) && ( strncmp( argv[1], "yscroll", (size_t) length ) == 0 ) )
00783     {
00784         if ( argc == 2 || argc > 3 )
00785         {
00786             Tcl_AppendResult( interp, "wrong # args: should be \"",
00787                 argv[0], " yscroll pixel\"", (char *) NULL );
00788             result = TCL_ERROR;
00789             goto done;
00790         }
00791         else
00792         {
00793             result = yScroll( interp, plFramePtr, argc - 2, argv + 2 );
00794         }
00795     }
00796 
00797 // unrecognized widget command
00798 
00799     else
00800     {
00801         Tcl_AppendResult( interp, "bad option \"", argv[1],
00802             "\":  must be closelink, cmd, configure, draw, ",
00803             "gcmap0, gcmap1, ",
00804             "info, openlink, orient, page, print, redraw, save, ",
00805             "scmap0, scmap1, scol0, scol1, ",
00806             "view, xscroll, or yscroll", (char *) NULL );
00807 
00808         result = TCL_ERROR;
00809 #ifdef DEBUG
00810         printf( "bad option!\n" );
00811 #endif
00812     }
00813 
00814 #ifdef DEBUG
00815     printf( "result=%d current stream=%d\n", result, plsc->ipls );
00816 #endif
00817 
00818 done:
00819     Tk_Release( (ClientData) plFramePtr );
00820     return result;
00821 }
00822 
00823 //
00824 //--------------------------------------------------------------------------
00825 //
00826 // DestroyPlFrame --
00827 //
00828 //      This procedure is invoked by Tk_EventuallyFree or Tk_Release to
00829 //      clean up the internal structure of a plframe at a safe time
00830 //      (when no-one is using it anymore).
00831 //
00832 // Results:
00833 //      None.
00834 //
00835 // Side effects:
00836 //      Everything associated with the plframe is freed up.
00837 //
00838 //--------------------------------------------------------------------------
00839 //
00840 
00841 static void
00842 DestroyPlFrame( FreeProcArg clientData )
00843 {
00844     register PlFrame *plFramePtr = (PlFrame *) clientData;
00845     register PLRDev  *plr        = plFramePtr->plr;
00846 
00847     dbug_enter( "DestroyPlFrame" );
00848 
00849     if ( plFramePtr->border != NULL )
00850     {
00851         Tk_Free3DBorder( plFramePtr->border );
00852     }
00853     if ( plFramePtr->bgColor != NULL )
00854     {
00855         Tk_FreeColor( plFramePtr->bgColor );
00856     }
00857     if ( plFramePtr->plpr_cmd != NULL )
00858     {
00859         ckfree( (char *) plFramePtr->plpr_cmd );
00860     }
00861     if ( plFramePtr->cursor != None )
00862     {
00863         Tk_FreeCursor( plFramePtr->display, plFramePtr->cursor );
00864     }
00865     if ( plFramePtr->xhair_cursor != None )
00866     {
00867         Tk_FreeCursor( plFramePtr->display, plFramePtr->xhair_cursor );
00868     }
00869     if ( plFramePtr->xorGC != NULL )
00870     {
00871         Tk_FreeGC( plFramePtr->display, plFramePtr->xorGC );
00872     }
00873     if ( plFramePtr->yScrollCmd != NULL )
00874     {
00875         ckfree( (char *) plFramePtr->yScrollCmd );
00876     }
00877     if ( plFramePtr->xScrollCmd != NULL )
00878     {
00879         ckfree( (char *) plFramePtr->xScrollCmd );
00880     }
00881     if ( plFramePtr->SaveFnam != NULL )
00882     {
00883         ckfree( (char *) plFramePtr->SaveFnam );
00884     }
00885     if ( plFramePtr->devDesc != NULL )
00886     {
00887         ckfree( (char *) plFramePtr->devDesc );
00888     }
00889     if ( plFramePtr->devName != NULL )
00890     {
00891         ckfree( (char *) plFramePtr->devName );
00892     }
00893 
00894 // Clean up data connection
00895 
00896     pdf_close( plr->pdfs );
00897     ckfree( (char *) plFramePtr->plr->iodev );
00898 
00899 // Tell PLplot to clean up
00900 
00901     plsstrm( plFramePtr->ipls );
00902     plend1();
00903 
00904 // Delete main data structures
00905 
00906     ckfree( (char *) plFramePtr->plr );
00907     ckfree( (char *) plFramePtr );
00908 }
00909 
00910 //
00911 //--------------------------------------------------------------------------
00912 //
00913 // PlFrameConfigureEH --
00914 //
00915 //      Invoked by the Tk dispatcher on structure changes to a plframe.
00916 //
00917 // Results:
00918 //      None.
00919 //
00920 // Side effects:
00921 //      When the window gets deleted, internal structures get cleaned up.
00922 //      When it gets resized, it is redrawn.
00923 //
00924 //--------------------------------------------------------------------------
00925 //
00926 
00927 static void
00928 PlFrameConfigureEH( ClientData clientData, register XEvent *eventPtr )
00929 {
00930     register PlFrame   *plFramePtr = (PlFrame *) clientData;
00931     register Tk_Window tkwin       = plFramePtr->tkwin;
00932 
00933     dbug_enter( "PlFrameConfigureEH" );
00934 
00935     switch ( eventPtr->type )
00936     {
00937     case ConfigureNotify:
00938         pldebug( "PLFrameConfigureEH", "ConfigureNotify\n" );
00939         plFramePtr->flags |= RESIZE_PENDING;
00940         plFramePtr->width  = Tk_Width( tkwin );
00941         plFramePtr->height = Tk_Height( tkwin );
00942         if ( ( tkwin != NULL ) && !( plFramePtr->flags & REFRESH_PENDING ) )
00943         {
00944             Tk_DoWhenIdle( DisplayPlFrame, (ClientData) plFramePtr );
00945             plFramePtr->flags |= REFRESH_PENDING;
00946             plFramePtr->flags |= UPDATE_V_SCROLLBAR | UPDATE_H_SCROLLBAR;
00947         }
00948         break;
00949 
00950     case DestroyNotify:
00951         pldebug( "PLFrameConfigureEH", "DestroyNotify\n" );
00952 #ifdef HAVE_ITCL
00953         Itk_SetWidgetCommand( plFramePtr->tkwin, (Tcl_Command) NULL );
00954         Tcl_DeleteCommand2( plFramePtr->interp, plFramePtr->widgetCmd );
00955 #else
00956         Tcl_DeleteCommand( plFramePtr->interp, Tk_PathName( tkwin ) );
00957 #endif
00958         plFramePtr->tkwin = NULL;
00959         if ( plFramePtr->flags & REFRESH_PENDING )
00960         {
00961             Tk_CancelIdleCall( DisplayPlFrame, (ClientData) plFramePtr );
00962         }
00963         Tk_EventuallyFree( (ClientData) plFramePtr, DestroyPlFrame );
00964         break;
00965 
00966     case MapNotify:
00967         pldebug( "PLFrameConfigureEH", "MapNotify\n" );
00968         if ( plFramePtr->flags & REFRESH_PENDING )
00969         {
00970             Tk_CancelIdleCall( DisplayPlFrame, (ClientData) plFramePtr );
00971         }
00972 
00973         // For some reason, "." must be mapped or PlFrameInit will die (Note:
00974         // mapped & withdrawn or mapped in the withdrawn state is OK). Issuing
00975         // an update fixes this.  I'd love to know why this occurs.
00976         //
00977 
00978         if ( !plFramePtr->tkwin_initted )
00979         {
00980             Tcl_VarEval( plFramePtr->interp, "update", (char *) NULL );
00981         }
00982         Tk_DoWhenIdle( PlFrameInit, (ClientData) plFramePtr );
00983         break;
00984     }
00985 }
00986 
00987 //
00988 //--------------------------------------------------------------------------
00989 //
00990 // PlFrameExposeEH --
00991 //
00992 //      Invoked by the Tk dispatcher on exposes of a plframe.
00993 //
00994 // Results:
00995 //      None.
00996 //
00997 // Side effects:
00998 //      Widget is redisplayed.
00999 //
01000 // Note: it's customary in Tk to collapse multiple exposes, so for best
01001 // performance without losing the window contents, I keep track of the
01002 // smallest single rectangle that can satisfy all expose events.  If there
01003 // are any overlaid graphics (like crosshairs), however, we need to refresh
01004 // the entire plot in order to have a predictable outcome.
01005 //
01006 //--------------------------------------------------------------------------
01007 
01008 static void
01009 PlFrameExposeEH( ClientData clientData, register XEvent *eventPtr )
01010 {
01011     register PlFrame   *plFramePtr = (PlFrame *) clientData;
01012     XExposeEvent       *event      = (XExposeEvent *) eventPtr;
01013     register Tk_Window tkwin       = plFramePtr->tkwin;
01014 
01015     dbug_enter( "PlFrameExposeEH" );
01016 
01017     pldebug( "PLFrameExposeEH", "Expose\n" );
01018 
01019 // Set up the area to refresh
01020 
01021     if ( !( plFramePtr->drawing_xhairs || plFramePtr->drawing_rband ) )
01022     {
01023         int x0_old, x1_old, y0_old, y1_old, x0_new, x1_new, y0_new, y1_new;
01024 
01025         x0_old = (int) plFramePtr->pldis.x;
01026         y0_old = (int) plFramePtr->pldis.y;
01027         x1_old = x0_old + (int) plFramePtr->pldis.width;
01028         y1_old = y0_old + (int) plFramePtr->pldis.height;
01029 
01030         x0_new = event->x;
01031         y0_new = event->y;
01032         x1_new = x0_new + event->width;
01033         y1_new = y0_new + event->height;
01034 
01035         plFramePtr->pldis.x      = (unsigned int) MIN( x0_old, x0_new );
01036         plFramePtr->pldis.y      = (unsigned int) MIN( y0_old, y0_new );
01037         plFramePtr->pldis.width  = (unsigned int) MAX( x1_old, x1_new ) - plFramePtr->pldis.x;
01038         plFramePtr->pldis.height = (unsigned int) MAX( y1_old, y1_new ) - plFramePtr->pldis.y;
01039     }
01040 
01041 // Invoke DoWhenIdle handler to redisplay widget.
01042 
01043     if ( event->count == 0 )
01044     {
01045         if ( ( tkwin != NULL ) && !( plFramePtr->flags & REFRESH_PENDING ) )
01046         {
01047             Tk_DoWhenIdle( DisplayPlFrame, (ClientData) plFramePtr );
01048             plFramePtr->width  = Tk_Width( tkwin );
01049             plFramePtr->height = Tk_Height( tkwin );
01050             plFramePtr->flags |= REFRESH_PENDING;
01051         }
01052     }
01053 }
01054 
01055 //
01056 //--------------------------------------------------------------------------
01057 //
01058 // PlFrameMotionEH --
01059 //
01060 //      Invoked by the Tk dispatcher on MotionNotify events in a plframe.
01061 //      Not invoked unless we are drawing graphic crosshairs.
01062 //
01063 // Results:
01064 //      None.
01065 //
01066 // Side effects:
01067 //      Graphic crosshairs are drawn.
01068 //
01069 //--------------------------------------------------------------------------
01070 //
01071 
01072 static void
01073 PlFrameMotionEH( ClientData clientData, register XEvent *eventPtr )
01074 {
01075     register PlFrame *plFramePtr = (PlFrame *) clientData;
01076     XMotionEvent     *event      = (XMotionEvent *) eventPtr;
01077 
01078     dbug_enter( "PlFrameMotionEH" );
01079 
01080     if ( plFramePtr->drawing_xhairs )
01081     {
01082         DrawXhairs( plFramePtr, event->x, event->y );
01083     }
01084     if ( plFramePtr->drawing_rband )
01085     {
01086         DrawRband( plFramePtr, event->x, event->y );
01087     }
01088 }
01089 
01090 //
01091 //--------------------------------------------------------------------------
01092 //
01093 // PlFrameEnterEH --
01094 //
01095 //      Invoked by the Tk dispatcher on EnterNotify events in a plframe.
01096 //      Not invoked unless we are drawing graphic crosshairs.
01097 //
01098 // Results:
01099 //      None.
01100 //
01101 // Side effects:
01102 //      Graphic crosshairs are updated.
01103 //
01104 //--------------------------------------------------------------------------
01105 
01106 static void
01107 PlFrameEnterEH( ClientData clientData, register XEvent *eventPtr )
01108 {
01109     register PlFrame *plFramePtr    = (PlFrame *) clientData;
01110     XCrossingEvent   *crossingEvent = (XCrossingEvent *) eventPtr;
01111 
01112     dbug_enter( "PlFrameEnterEH" );
01113 
01114     if ( plFramePtr->xhairs )
01115     {
01116         DrawXhairs( plFramePtr, crossingEvent->x, crossingEvent->y );
01117         plFramePtr->drawing_xhairs = 1;
01118     }
01119     if ( plFramePtr->rband )
01120     {
01121         plFramePtr->drawing_rband = 1;
01122         UpdateRband( plFramePtr );
01123         DrawRband( plFramePtr, crossingEvent->x, crossingEvent->y );
01124     }
01125 }
01126 
01127 //
01128 //--------------------------------------------------------------------------
01129 //
01130 // PlFrameLeaveEH --
01131 //
01132 //      Invoked by the Tk dispatcher on LeaveNotify events in a plframe.
01133 //      Not invoked unless we are drawing graphic crosshairs.
01134 //
01135 // Results:
01136 //      None.
01137 //
01138 // Side effects:
01139 //      Graphic crosshairs are updated.
01140 //
01141 //--------------------------------------------------------------------------
01142 
01143 static void
01144 PlFrameLeaveEH( ClientData clientData, register XEvent * PL_UNUSED( eventPtr ) )
01145 {
01146     register PlFrame *plFramePtr = (PlFrame *) clientData;
01147 
01148     dbug_enter( "PlFrameLeaveEH" );
01149 
01150     if ( plFramePtr->drawing_xhairs )
01151     {
01152         UpdateXhairs( plFramePtr );
01153         plFramePtr->drawing_xhairs = 0;
01154     }
01155     if ( plFramePtr->drawing_rband )
01156     {
01157         UpdateRband( plFramePtr );
01158         plFramePtr->drawing_rband = 0;
01159     }
01160 }
01161 
01162 //
01163 //--------------------------------------------------------------------------
01164 //
01165 // PlFrameKeyEH --
01166 //
01167 //      Invoked by the Tk dispatcher on Keypress events in a plframe.
01168 //      Not invoked unless we are drawing graphic crosshairs.
01169 //
01170 // Results:
01171 //      None.
01172 //
01173 // Side effects:
01174 //      Keypress events get filtered.  If a cursor key is pushed, the
01175 //      graphic crosshairs are moved in the appropriate direction.  Using a
01176 //      modifier key multiplies the movement a factor of 5 for each key
01177 //      added.
01178 //
01179 //--------------------------------------------------------------------------
01180 //
01181 
01182 static void
01183 PlFrameKeyEH( ClientData clientData, register XEvent *eventPtr )
01184 {
01185     register PlFrame   *plFramePtr = (PlFrame *) clientData;
01186     XKeyEvent          *event      = (XKeyEvent *) eventPtr;
01187     register Tk_Window tkwin       = plFramePtr->tkwin;
01188 
01189     KeySym             keysym;
01190     int            nchars;
01191     char           string[11];
01192     XComposeStatus cs;
01193 
01194     dbug_enter( "PlFrameKeyEH" );
01195 
01196 #if !defined ( __WIN32__ )
01197     nchars = XLookupString( event, string, 10, &keysym, &cs );
01198 #else
01199     nchars = 0;
01200 #endif
01201     string[nchars] = '\0';
01202     pldebug( "PlFrameKeyEH", "Keysym %x, translation: %s\n", keysym, string );
01203 
01204     if ( IsModifierKey( keysym ) )
01205     {
01206         eventPtr->type = 0;
01207     }
01208     else if ( IsCursorKey( keysym ) )
01209     {
01210         int x1, y1, dx = 0, dy = 0;
01211         int x0   = event->x, y0 = event->y;
01212         int xmin = 0, xmax = Tk_Width( tkwin ) - 1;
01213         int ymin = 0, ymax = Tk_Height( tkwin ) - 1;
01214 
01215         switch ( keysym )
01216         {
01217         case XK_Left:
01218             dx = -1;
01219             break;
01220         case XK_Right:
01221             dx = 1;
01222             break;
01223         case XK_Up:
01224             dy = -1;
01225             break;
01226         case XK_Down:
01227             dy = 1;
01228             break;
01229         }
01230 
01231         // Each modifier key added increases the multiplication factor by 5
01232 
01233         // Shift
01234 
01235         if ( event->state & 0x01 )
01236         {
01237             dx *= 5;
01238             dy *= 5;
01239         }
01240 
01241         // Caps Lock
01242 
01243         if ( event->state & 0x02 )
01244         {
01245             dx *= 5;
01246             dy *= 5;
01247         }
01248 
01249         // Control
01250 
01251         if ( event->state & 0x04 )
01252         {
01253             dx *= 5;
01254             dy *= 5;
01255         }
01256 
01257         // Alt
01258 
01259         if ( event->state & 0x08 )
01260         {
01261             dx *= 5;
01262             dy *= 5;
01263         }
01264 
01265         // Bounds checking so that we don't send cursor out of window
01266 
01267         x1 = x0 + dx;
01268         y1 = y0 + dy;
01269 
01270         if ( x1 < xmin )
01271             dx = xmin - x0;
01272         if ( y1 < ymin )
01273             dy = ymin - y0;
01274         if ( x1 > xmax )
01275             dx = xmax - x0;
01276         if ( y1 > ymax )
01277             dy = ymax - y0;
01278 
01279         // Engage...
01280 
01281         XWarpPointer( plFramePtr->display, Tk_WindowId( tkwin ),
01282             None, 0, 0, 0, 0, dx, dy );
01283         eventPtr->type = 0;
01284     }
01285 }
01286 
01287 //--------------------------------------------------------------------------
01288 // CreateXhairs()
01289 //
01290 // Creates graphic crosshairs at current pointer location.
01291 //--------------------------------------------------------------------------
01292 
01293 static void
01294 CreateXhairs( PlFrame *plFramePtr )
01295 {
01296     register Tk_Window tkwin = plFramePtr->tkwin;
01297     Window             root, child;
01298     int root_x, root_y, win_x, win_y;
01299     unsigned int       mask;
01300 
01301 // Switch to crosshair cursor.
01302 
01303     Tk_DefineCursor( tkwin, plFramePtr->xhair_cursor );
01304 
01305 // Find current pointer location and draw graphic crosshairs if pointer is
01306 // inside our window.
01307 
01308     if ( XQueryPointer( plFramePtr->display, Tk_WindowId( tkwin ),
01309              &root, &child, &root_x, &root_y, &win_x, &win_y,
01310              &mask ) )
01311     {
01312         if ( win_x >= 0 && win_x < Tk_Width( tkwin ) &&
01313              win_y >= 0 && win_y < Tk_Height( tkwin ) )
01314         {
01315             DrawXhairs( plFramePtr, win_x, win_y );
01316             plFramePtr->drawing_xhairs = 1;
01317         }
01318     }
01319 
01320 // Catch PointerMotion and crossing events so we can update them properly
01321 
01322     if ( !plFramePtr->drawing_rband )
01323     {
01324         Tk_CreateEventHandler( tkwin, PointerMotionMask,
01325             PlFrameMotionEH, (ClientData) plFramePtr );
01326 
01327         Tk_CreateEventHandler( tkwin, EnterWindowMask,
01328             PlFrameEnterEH, (ClientData) plFramePtr );
01329 
01330         Tk_CreateEventHandler( tkwin, LeaveWindowMask,
01331             PlFrameLeaveEH, (ClientData) plFramePtr );
01332     }
01333 
01334 // Catch KeyPress events so we can filter them
01335 
01336     Tk_CreateEventHandler( tkwin, KeyPressMask,
01337         PlFrameKeyEH, (ClientData) plFramePtr );
01338 }
01339 
01340 //--------------------------------------------------------------------------
01341 // DestroyXhairs()
01342 //
01343 // Destroys graphic crosshairs.
01344 //--------------------------------------------------------------------------
01345 
01346 static void
01347 DestroyXhairs( PlFrame *plFramePtr )
01348 {
01349     register Tk_Window tkwin = plFramePtr->tkwin;
01350 
01351 // Switch back to boring old pointer
01352 
01353     Tk_DefineCursor( tkwin, plFramePtr->cursor );
01354 
01355 // Don't catch PointerMotion or crossing events any more
01356 
01357     if ( !plFramePtr->drawing_rband )
01358     {
01359         Tk_DeleteEventHandler( tkwin, PointerMotionMask,
01360             PlFrameMotionEH, (ClientData) plFramePtr );
01361 
01362         Tk_DeleteEventHandler( tkwin, EnterWindowMask,
01363             PlFrameEnterEH, (ClientData) plFramePtr );
01364 
01365         Tk_DeleteEventHandler( tkwin, LeaveWindowMask,
01366             PlFrameLeaveEH, (ClientData) plFramePtr );
01367     }
01368 
01369     Tk_DeleteEventHandler( tkwin, KeyPressMask,
01370         PlFrameKeyEH, (ClientData) plFramePtr );
01371 
01372 // This draw removes the last set of graphic crosshairs
01373 
01374     UpdateXhairs( plFramePtr );
01375     plFramePtr->drawing_xhairs = 0;
01376 }
01377 
01378 //--------------------------------------------------------------------------
01379 // DrawXhairs()
01380 //
01381 // Draws graphic crosshairs at (x0, y0).  The first draw erases the old set.
01382 //--------------------------------------------------------------------------
01383 
01384 static void
01385 DrawXhairs( PlFrame *plFramePtr, int x0, int y0 )
01386 {
01387     register Tk_Window tkwin = plFramePtr->tkwin;
01388     int xmin = 0, xmax = Tk_Width( tkwin ) - 1;
01389     int ymin = 0, ymax = Tk_Height( tkwin ) - 1;
01390 
01391     if ( plFramePtr->drawing_xhairs )
01392         UpdateXhairs( plFramePtr );
01393 
01394     plFramePtr->xhair_x[0].x = (short) xmin; plFramePtr->xhair_x[0].y = (short) y0;
01395     plFramePtr->xhair_x[1].x = (short) xmax; plFramePtr->xhair_x[1].y = (short) y0;
01396 
01397     plFramePtr->xhair_y[0].x = (short) x0; plFramePtr->xhair_y[0].y = (short) ymin;
01398     plFramePtr->xhair_y[1].x = (short) x0; plFramePtr->xhair_y[1].y = (short) ymax;
01399 
01400     UpdateXhairs( plFramePtr );
01401 }
01402 
01403 //--------------------------------------------------------------------------
01404 // UpdateXhairs()
01405 //
01406 // Updates graphic crosshairs.  If already there, they are erased.
01407 //--------------------------------------------------------------------------
01408 
01409 static void
01410 UpdateXhairs( PlFrame *plFramePtr )
01411 {
01412     register Tk_Window tkwin = plFramePtr->tkwin;
01413 
01414     XDrawLines( Tk_Display( tkwin ), Tk_WindowId( tkwin ),
01415         plFramePtr->xorGC, plFramePtr->xhair_x, 2,
01416         CoordModeOrigin );
01417 
01418     XDrawLines( Tk_Display( tkwin ), Tk_WindowId( tkwin ),
01419         plFramePtr->xorGC, plFramePtr->xhair_y, 2,
01420         CoordModeOrigin );
01421 }
01422 
01423 //--------------------------------------------------------------------------
01424 // CreateRband()
01425 //
01426 // Initiate rubber banding.
01427 //--------------------------------------------------------------------------
01428 
01429 static void
01430 CreateRband( PlFrame *plFramePtr )
01431 {
01432     register Tk_Window tkwin = plFramePtr->tkwin;
01433     Window             root, child;
01434     int root_x, root_y, win_x, win_y;
01435     unsigned int       mask;
01436 
01437 // Find current pointer location, and initiate rubber banding.
01438 
01439     if ( XQueryPointer( plFramePtr->display, Tk_WindowId( tkwin ),
01440              &root, &child, &root_x, &root_y, &win_x, &win_y,
01441              &mask ) )
01442     {
01443         if ( win_x >= 0 && win_x < Tk_Width( tkwin ) &&
01444              win_y >= 0 && win_y < Tk_Height( tkwin ) )
01445         {
01446             // Okay, pointer is in our window.
01447             plFramePtr->rband_pt[0].x = (short) win_x;
01448             plFramePtr->rband_pt[0].y = (short) win_y;
01449 
01450             DrawRband( plFramePtr, win_x, win_y );
01451             plFramePtr->drawing_rband = 1;
01452         }
01453         else
01454         {
01455             // Hmm, somehow they turned it on without even being in the window.
01456             // Just put the anchor in top left, they'll soon realize this is a
01457             // mistake...
01458 
01459             plFramePtr->rband_pt[0].x = 0;
01460             plFramePtr->rband_pt[0].y = 0;
01461 
01462             DrawRband( plFramePtr, win_x, win_y );
01463             plFramePtr->drawing_rband = 1;
01464         }
01465     }
01466 
01467 // Catch PointerMotion and crossing events so we can update them properly
01468 
01469     if ( !plFramePtr->drawing_xhairs )
01470     {
01471         Tk_CreateEventHandler( tkwin, PointerMotionMask,
01472             PlFrameMotionEH, (ClientData) plFramePtr );
01473 
01474         Tk_CreateEventHandler( tkwin, EnterWindowMask,
01475             PlFrameEnterEH, (ClientData) plFramePtr );
01476 
01477         Tk_CreateEventHandler( tkwin, LeaveWindowMask,
01478             PlFrameLeaveEH, (ClientData) plFramePtr );
01479     }
01480 }
01481 
01482 //--------------------------------------------------------------------------
01483 // DestroyRband()
01484 //
01485 // Turn off rubber banding.
01486 //--------------------------------------------------------------------------
01487 
01488 static void
01489 DestroyRband( PlFrame *plFramePtr )
01490 {
01491     register Tk_Window tkwin = plFramePtr->tkwin;
01492 
01493 // Don't catch PointerMotion or crossing events any more
01494 
01495     if ( !plFramePtr->drawing_xhairs )
01496     {
01497         Tk_DeleteEventHandler( tkwin, PointerMotionMask,
01498             PlFrameMotionEH, (ClientData) plFramePtr );
01499 
01500         Tk_DeleteEventHandler( tkwin, EnterWindowMask,
01501             PlFrameEnterEH, (ClientData) plFramePtr );
01502 
01503         Tk_DeleteEventHandler( tkwin, LeaveWindowMask,
01504             PlFrameLeaveEH, (ClientData) plFramePtr );
01505     }
01506 
01507 // This draw removes the residual rubber band.
01508 
01509     UpdateRband( plFramePtr );
01510     plFramePtr->drawing_rband = 0;
01511 }
01512 
01513 //--------------------------------------------------------------------------
01514 // DrawRband()
01515 //
01516 // Draws a rubber band from the anchor to the current cursor location.
01517 //--------------------------------------------------------------------------
01518 
01519 static void
01520 DrawRband( PlFrame *plFramePtr, int x0, int y0 )
01521 {
01522 // If the line is already up, clear it.
01523 
01524     if ( plFramePtr->drawing_rband )
01525         UpdateRband( plFramePtr );
01526 
01527     plFramePtr->rband_pt[1].x = (short) x0; plFramePtr->rband_pt[1].y = (short) y0;
01528 
01529     UpdateRband( plFramePtr );
01530 }
01531 
01532 //--------------------------------------------------------------------------
01533 // UpdateRband()
01534 //
01535 // Updates rubber band.  If already there, it is erased.
01536 //--------------------------------------------------------------------------
01537 
01538 static void
01539 UpdateRband( PlFrame *plFramePtr )
01540 {
01541     register Tk_Window tkwin = plFramePtr->tkwin;
01542 
01543     XDrawLines( Tk_Display( tkwin ), Tk_WindowId( tkwin ),
01544         plFramePtr->xorGC, plFramePtr->rband_pt, 2,
01545         CoordModeOrigin );
01546 }
01547 
01548 //
01549 //--------------------------------------------------------------------------
01550 //
01551 // PlFrameInit --
01552 //
01553 //      Invoked to handle miscellaneous initialization after window gets
01554 //      mapped.
01555 //
01556 // Results:
01557 //      None.
01558 //
01559 // Side effects:
01560 //      PLplot internal parameters and device driver are initialized.
01561 //
01562 //--------------------------------------------------------------------------
01563 
01564 static void
01565 PlFrameInit( ClientData clientData )
01566 {
01567     register PlFrame   *plFramePtr = (PlFrame *) clientData;
01568     register Tk_Window tkwin       = plFramePtr->tkwin;
01569 
01570 // Set up window parameters and arrange for window to be refreshed
01571 
01572     plFramePtr->flags |= REFRESH_PENDING;
01573     plFramePtr->flags |= UPDATE_V_SCROLLBAR | UPDATE_H_SCROLLBAR;
01574 
01575 // First-time initialization
01576 
01577     if ( !plFramePtr->tkwin_initted )
01578     {
01579         plsstrm( plFramePtr->ipls );
01580         plsxwin( (PLINT) Tk_WindowId( tkwin ) );
01581         plspause( 0 );
01582         plinit();
01583 // plplot_ccmap is statically defined in plxwd.h.  Note that
01584 // xwin.c also includes that header and uses that variable.
01585         if ( plplot_ccmap )
01586         {
01587             Install_cmap( plFramePtr );
01588         }
01589         if ( plFramePtr->bopCmd != NULL )
01590             plsbopH( process_bop, (void *) plFramePtr );
01591         if ( plFramePtr->eopCmd != NULL )
01592             plseopH( process_eop, (void *) plFramePtr );
01593 
01594         plbop();
01595 
01596         plFramePtr->tkwin_initted = 1;
01597         plFramePtr->width         = Tk_Width( tkwin );
01598         plFramePtr->height        = Tk_Height( tkwin );
01599         plFramePtr->prevWidth     = plFramePtr->width;
01600         plFramePtr->prevHeight    = plFramePtr->height;
01601     }
01602 
01603 // Draw plframe
01604 
01605     DisplayPlFrame( clientData );
01606 
01607     if ( plFramePtr->xhairs )
01608         CreateXhairs( plFramePtr );
01609 
01610     if ( plFramePtr->rband )
01611         CreateRband( plFramePtr );
01612 }
01613 
01614 //
01615 //--------------------------------------------------------------------------
01616 //
01617 // Install_cmap --
01618 //
01619 //      Installs X driver color map as necessary when custom color maps
01620 //      are used.
01621 //
01622 // Results:
01623 //      None.
01624 //
01625 // Side effects:
01626 //      Parent color maps may get changed.
01627 //
01628 //--------------------------------------------------------------------------
01629 //
01630 
01631 static void
01632 Install_cmap( PlFrame *plFramePtr )
01633 {
01634     XwDev *dev;
01635 
01636 #define INSTALL_COLORMAP_IN_TK
01637 #ifdef  INSTALL_COLORMAP_IN_TK
01638     dev = (XwDev *) plFramePtr->pls->dev;
01639     Tk_SetWindowColormap( Tk_MainWindow( plFramePtr->interp ), dev->xwd->map );
01640 
01641 //
01642 // If the colormap is local to this widget, the WM must be informed that
01643 // it should be installed when the widget gets the focus.  The top level
01644 // window must be added to the end of its own list, because otherwise the
01645 // window manager adds it to the front (as required by the ICCCM).  Thanks
01646 // to Paul Mackerras for providing this info in his TK photo widget.
01647 //
01648 
01649 #else
01650     int    count = 0;
01651     Window top, colormap_windows[5];
01652 
01653     top = Tk_WindowId( Tk_MainWindow( plFramePtr->interp ) );
01654 
01655     colormap_windows[count++] = Tk_WindowId( plFramePtr->tkwin );
01656     colormap_windows[count++] = top;
01657 
01658     if ( !XSetWMColormapWindows( plFramePtr->display,
01659              top, colormap_windows, count ) )
01660         fprintf( stderr, "Unable to set color map property!\n" );
01661 #endif
01662 }
01663 
01664 //
01665 //--------------------------------------------------------------------------
01666 //
01667 // DisplayPlFrame --
01668 //
01669 //      This procedure is invoked to display a plframe widget.
01670 //
01671 // Results:
01672 //      None.
01673 //
01674 // Side effects:
01675 //      Commands are output to X to display the plframe in its
01676 //      current mode.
01677 //
01678 //--------------------------------------------------------------------------
01679 //
01680 
01681 static void
01682 DisplayPlFrame( ClientData clientData )
01683 {
01684     register PlFrame   *plFramePtr = (PlFrame *) clientData;
01685     register Tk_Window tkwin       = plFramePtr->tkwin;
01686 
01687     dbug_enter( "DisplayPlFrame" );
01688 
01689 // Update scrollbars if needed
01690 
01691     if ( plFramePtr->flags & UPDATE_V_SCROLLBAR )
01692     {
01693         UpdateVScrollbar( plFramePtr );
01694     }
01695     if ( plFramePtr->flags & UPDATE_H_SCROLLBAR )
01696     {
01697         UpdateHScrollbar( plFramePtr );
01698     }
01699     plFramePtr->flags &= ~( UPDATE_V_SCROLLBAR | UPDATE_H_SCROLLBAR );
01700 
01701 // If not mapped yet, just return and cancel pending refresh
01702 
01703     if ( ( plFramePtr->tkwin == NULL ) || !Tk_IsMapped( tkwin ) )
01704     {
01705         plFramePtr->flags &= ~REFRESH_PENDING;
01706         return;
01707     }
01708 
01709 // Redraw border if necessary
01710 
01711     if ( ( plFramePtr->border != NULL ) &&
01712          ( plFramePtr->relief != TK_RELIEF_FLAT ) )
01713     {
01714 #if TK_MAJOR_VERSION >= 4 && TK_MINOR_VERSION >= 0
01715         Tk_Draw3DRectangle( plFramePtr->tkwin, Tk_WindowId( tkwin ),
01716             plFramePtr->border, 0, 0, Tk_Width( tkwin ), Tk_Height( tkwin ),
01717             plFramePtr->borderWidth, plFramePtr->relief );
01718 #else
01719         Tk_Draw3DRectangle( plFramePtr->display, Tk_WindowId( tkwin ),
01720             plFramePtr->border, 0, 0, Tk_Width( tkwin ), Tk_Height( tkwin ),
01721             plFramePtr->borderWidth, plFramePtr->relief );
01722 #endif
01723     }
01724 
01725 // All refresh events
01726 
01727     if ( plFramePtr->flags & REFRESH_PENDING )
01728     {
01729         plFramePtr->flags &= ~REFRESH_PENDING;
01730 
01731         // Reschedule resizes to avoid occasional ordering conflicts with
01732         // the packer's resize of the window (this call must come last).
01733 
01734         if ( plFramePtr->flags & RESIZE_PENDING )
01735         {
01736             plFramePtr->flags |= REFRESH_PENDING;
01737             plFramePtr->flags &= ~RESIZE_PENDING;
01738             Tk_DoWhenIdle( DisplayPlFrame, clientData );
01739             return;
01740         }
01741 
01742         // Redraw -- replay contents of plot buffer
01743 
01744         if ( plFramePtr->flags & REDRAW_PENDING )
01745         {
01746             plFramePtr->flags &= ~REDRAW_PENDING;
01747             plsstrm( plFramePtr->ipls );
01748             pl_cmd( PLESC_REDRAW, (void *) NULL );
01749         }
01750 
01751         // Resize -- if window bounds have changed
01752 
01753         else if ( ( plFramePtr->width != plFramePtr->prevWidth ) ||
01754                   ( plFramePtr->height != plFramePtr->prevHeight ) )
01755         {
01756             plFramePtr->pldis.width  = (unsigned int) plFramePtr->width;
01757             plFramePtr->pldis.height = (unsigned int) plFramePtr->height;
01758 
01759             plsstrm( plFramePtr->ipls );
01760             pl_cmd( PLESC_RESIZE, (void *) &( plFramePtr->pldis ) );
01761             plFramePtr->prevWidth  = plFramePtr->width;
01762             plFramePtr->prevHeight = plFramePtr->height;
01763         }
01764 
01765         // Expose -- if window bounds are unchanged
01766 
01767         else
01768         {
01769             plsstrm( plFramePtr->ipls );
01770             if ( plFramePtr->drawing_xhairs )
01771             {
01772                 XClearWindow( plFramePtr->display, Tk_WindowId( tkwin ) );
01773                 XFlush( plFramePtr->display );
01774                 pl_cmd( PLESC_EXPOSE, NULL );
01775             }
01776             else
01777             {
01778                 pl_cmd( PLESC_EXPOSE, (void *) &( plFramePtr->pldis ) );
01779             }
01780 
01781             // Reset window bounds so that next time they are set fresh
01782 
01783             plFramePtr->pldis.x      = (unsigned int) ( Tk_X( tkwin ) + Tk_Width( tkwin ) );
01784             plFramePtr->pldis.y      = (unsigned int) ( Tk_Y( tkwin ) + Tk_Height( tkwin ) );
01785             plFramePtr->pldis.width  = (unsigned int) ( -Tk_Width( tkwin ) );
01786             plFramePtr->pldis.height = (unsigned int) ( -Tk_Height( tkwin ) );
01787         }
01788 
01789         // Update graphic crosshairs if necessary
01790 
01791         if ( plFramePtr->drawing_xhairs )
01792         {
01793             UpdateXhairs( plFramePtr );
01794         }
01795 
01796         // Update rubber band if necessary.
01797 
01798         if ( plFramePtr->drawing_rband )
01799         {
01800             UpdateRband( plFramePtr );
01801         }
01802     }
01803 }
01804 
01805 //--------------------------------------------------------------------------
01806 // Routines to process widget commands.
01807 //--------------------------------------------------------------------------
01808 
01809 //--------------------------------------------------------------------------
01810 // scol0
01811 //
01812 // Sets a color in cmap0.
01813 //--------------------------------------------------------------------------
01814 
01815 static int
01816 scol0( Tcl_Interp *interp, register PlFrame *plFramePtr,
01817        int i, const char *col, int *p_changed )
01818 {
01819     PLStream *pls = plFramePtr->pls;
01820     XColor   xcol;
01821     PLINT    r, g, b;
01822 
01823     if ( col == NULL )
01824     {
01825         Tcl_AppendResult( interp, "color value not specified",
01826             (char *) NULL );
01827         return TCL_ERROR;
01828     }
01829 
01830     if ( !XParseColor( plFramePtr->display,
01831              Tk_Colormap( plFramePtr->tkwin ), col, &xcol ) )
01832     {
01833         Tcl_AppendResult( interp, "Couldn't parse color ", col,
01834             (char *) NULL );
01835         return TCL_ERROR;
01836     }
01837 
01838     r = (unsigned) ( xcol.red & 0xFF00 ) >> 8;
01839     g = (unsigned) ( xcol.green & 0xFF00 ) >> 8;
01840     b = (unsigned) ( xcol.blue & 0xFF00 ) >> 8;
01841 
01842     if ( ( pls->cmap0[i].r != r ) ||
01843          ( pls->cmap0[i].g != g ) ||
01844          ( pls->cmap0[i].b != b ) )
01845     {
01846         pls->cmap0[i].r = (unsigned char) r;
01847         pls->cmap0[i].g = (unsigned char) g;
01848         pls->cmap0[i].b = (unsigned char) b;
01849         *p_changed      = 1;
01850     }
01851 
01852     return TCL_OK;
01853 }
01854 
01855 //--------------------------------------------------------------------------
01856 // scol1
01857 //
01858 // Sets a color in cmap1.
01859 //--------------------------------------------------------------------------
01860 
01861 static int
01862 scol1( Tcl_Interp *interp, register PlFrame *plFramePtr,
01863        int i, const char *col, const char *pos, const char *rev, int *p_changed )
01864 {
01865     PLStream *pls = plFramePtr->pls;
01866     XColor   xcol;
01867     PLFLT    h, l, s, r, g, b, p;
01868     int      reverse;
01869 
01870     if ( col == NULL )
01871     {
01872         Tcl_AppendResult( interp, "color value not specified",
01873             (char *) NULL );
01874         return TCL_ERROR;
01875     }
01876 
01877     if ( pos == NULL )
01878     {
01879         Tcl_AppendResult( interp, "control point position not specified",
01880             (char *) NULL );
01881         return TCL_ERROR;
01882     }
01883 
01884     if ( rev == NULL )
01885     {
01886         Tcl_AppendResult( interp, "interpolation sense not specified",
01887             (char *) NULL );
01888         return TCL_ERROR;
01889     }
01890 
01891     if ( !XParseColor( plFramePtr->display,
01892              Tk_Colormap( plFramePtr->tkwin ), col, &xcol ) )
01893     {
01894         Tcl_AppendResult( interp, "Couldn't parse color ", col,
01895             (char *) NULL );
01896         return TCL_ERROR;
01897     }
01898 
01899     r = ( (unsigned) ( xcol.red & 0xFF00 ) >> 8 ) / 255.0;
01900     g = ( (unsigned) ( xcol.green & 0xFF00 ) >> 8 ) / 255.0;
01901     b = ( (unsigned) ( xcol.blue & 0xFF00 ) >> 8 ) / 255.0;
01902 
01903     plrgbhls( r, g, b, &h, &l, &s );
01904 
01905     p       = atof( pos ) / 100.0;
01906     reverse = atoi( rev );
01907 
01908     if ( ( pls->cmap1cp[i].h != h ) ||
01909          ( pls->cmap1cp[i].l != l ) ||
01910          ( pls->cmap1cp[i].s != s ) ||
01911          ( pls->cmap1cp[i].p != p ) ||
01912          ( pls->cmap1cp[i].alt_hue_path != reverse ) )
01913     {
01914         pls->cmap1cp[i].h            = h;
01915         pls->cmap1cp[i].l            = l;
01916         pls->cmap1cp[i].s            = s;
01917         pls->cmap1cp[i].p            = p;
01918         pls->cmap1cp[i].alt_hue_path = reverse;
01919         *p_changed = 1;
01920     }
01921     return TCL_OK;
01922 }
01923 
01924 //--------------------------------------------------------------------------
01925 // ColorManip
01926 //
01927 // Processes color manipulation widget commands.
01928 //
01929 // This provides an alternate API for the plplot color handling functions
01930 // (prepend a "pl" to get the corresponding plplot function).  They differ
01931 // from the versions in the Tcl API in the following ways:
01932 //
01933 //  - X11 conventions are used rather than plplot ones.  XParseColor is used
01934 //    to convert a string into its 3 rgb components.  This lets you use
01935 //    symbolic names or hex notation for color values.
01936 //
01937 //  - these expect/emit Tcl array values in lists rather than in tclmatrix
01938 //    form, like most "normal" Tcl tools.  For usage, see the examples in the
01939 //    palette tools (plcolor.tcl).
01940 //--------------------------------------------------------------------------
01941 
01942 static int
01943 ColorManip( Tcl_Interp *interp, register PlFrame *plFramePtr,
01944             int argc, const char **argv )
01945 {
01946     PLStream *pls = plFramePtr->pls;
01947     int      length;
01948     char     c;
01949     int      result = TCL_OK;
01950     char     *tmpstring;
01951 
01952 #ifdef DEBUG
01953     if ( pls->debug )
01954     {
01955         int i;
01956         fprintf( stderr, "There are %d arguments to ColorManip:", argc );
01957         for ( i = 0; i < argc; i++ )
01958         {
01959             fprintf( stderr, " %s", argv[i] );
01960         }
01961         fprintf( stderr, "\n" );
01962     }
01963 #else
01964     (void) argc;       // Cast to void to suppress compiler warning about unused parameter
01965 #endif
01966 
01967 // Make sure widget has been initialized before going any further
01968 
01969     if ( !plFramePtr->tkwin_initted )
01970     {
01971         Tcl_VarEval( plFramePtr->interp, "update", (char *) NULL );
01972     }
01973 
01974 // Set stream number and get ready to process the command
01975 
01976     plsstrm( plFramePtr->ipls );
01977 
01978     c      = argv[0][0];
01979     length = (int) strlen( argv[0] );
01980 
01981 // gcmap0 -- get color map 0
01982 // first arg is number of colors, the rest are hex number specifications
01983 
01984     if ( ( c == 'g' ) && ( strncmp( argv[0], "gcmap0", (size_t) length ) == 0 ) )
01985     {
01986         int           i;
01987         unsigned long plcolor;
01988         char          str[10];
01989 
01990         sprintf( str, "%d", (int) pls->ncol0 );
01991         Tcl_AppendElement( interp, str );
01992         for ( i = 0; i < pls->ncol0; i++ )
01993         {
01994             plcolor = (unsigned long) ( ( pls->cmap0[i].r << 16 ) |
01995                                         ( pls->cmap0[i].g << 8 ) |
01996                                         ( pls->cmap0[i].b ) );
01997 
01998             sprintf( str, "#%06lx", ( plcolor & 0xFFFFFF ) );
01999             Tcl_AppendElement( interp, str );
02000         }
02001         result = TCL_OK;
02002     }
02003 
02004 // gcmap1 -- get color map 1
02005 // first arg is number of control points
02006 // the rest are hex number specifications followed by positions (0-100)
02007 
02008     else if ( ( c == 'g' ) && ( strncmp( argv[0], "gcmap1", (size_t) length ) == 0 ) )
02009     {
02010         int           i;
02011         unsigned long plcolor;
02012         char          str[10];
02013         PLFLT         h, l, s, r, g, b;
02014         int           r1, g1, b1;
02015 
02016         sprintf( str, "%d", (int) pls->ncp1 );
02017         Tcl_AppendElement( interp, str );
02018         for ( i = 0; i < pls->ncp1; i++ )
02019         {
02020             h = pls->cmap1cp[i].h;
02021             l = pls->cmap1cp[i].l;
02022             s = pls->cmap1cp[i].s;
02023 
02024             plhlsrgb( h, l, s, &r, &g, &b );
02025 
02026             r1 = MAX( 0, MIN( 255, (int) ( 256. * r ) ) );
02027             g1 = MAX( 0, MIN( 255, (int) ( 256. * g ) ) );
02028             b1 = MAX( 0, MIN( 255, (int) ( 256. * b ) ) );
02029 
02030             plcolor = (unsigned long) ( ( r1 << 16 ) | ( g1 << 8 ) | ( b1 ) );
02031 
02032             sprintf( str, "#%06lx", ( plcolor & 0xFFFFFF ) );
02033             Tcl_AppendElement( interp, str );
02034 
02035             sprintf( str, "%02d", (int) ( 100 * pls->cmap1cp[i].p ) );
02036             Tcl_AppendElement( interp, str );
02037 
02038             sprintf( str, "%01d", (int) ( pls->cmap1cp[i].alt_hue_path ) );
02039             Tcl_AppendElement( interp, str );
02040         }
02041         result = TCL_OK;
02042     }
02043 
02044 // scmap0 -- set color map 0
02045 // first arg is number of colors, the rest are hex number specifications
02046 
02047     else if ( ( c == 's' ) && ( strncmp( argv[0], "scmap0", (size_t) length ) == 0 ) )
02048     {
02049         int  i, changed = 1, ncol0 = atoi( argv[1] );
02050         char *col;
02051 
02052         if ( ncol0 > 16 || ncol0 < 1 )
02053         {
02054             Tcl_AppendResult( interp, "illegal number of colors in cmap0: ",
02055                 argv[1], (char *) NULL );
02056             return TCL_ERROR;
02057         }
02058 
02059         pls->ncol0 = ncol0;
02060         tmpstring  = (char *) malloc( strlen( argv[2] ) + 1 );
02061         strcpy( tmpstring, argv[2] );
02062         col = strtok( tmpstring, " " );
02063         for ( i = 0; i < pls->ncol0; i++ )
02064         {
02065             if ( col == NULL )
02066                 break;
02067 
02068             if ( scol0( interp, plFramePtr, i, col, &changed ) != TCL_OK )
02069                 return TCL_ERROR;
02070 
02071             col = strtok( NULL, " " );
02072         }
02073         free( tmpstring );
02074 
02075         if ( changed )
02076             plP_state( PLSTATE_CMAP0 );
02077     }
02078 
02079 // scmap1 -- set color map 1
02080 // first arg is number of colors, the rest are hex number specifications
02081 
02082     else if ( ( c == 's' ) && ( strncmp( argv[0], "scmap1", (size_t) length ) == 0 ) )
02083     {
02084         int  i, changed = 1, ncp1 = atoi( argv[1] );
02085         char *col, *pos, *rev;
02086 
02087         if ( ncp1 > 32 || ncp1 < 1 )
02088         {
02089             Tcl_AppendResult( interp,
02090                 "illegal number of control points in cmap1: ",
02091                 argv[1], (char *) NULL );
02092             return TCL_ERROR;
02093         }
02094 
02095         tmpstring = (char *) malloc( strlen( argv[2] ) + 1 );
02096         strcpy( tmpstring, argv[2] );
02097         col = strtok( tmpstring, " " );
02098         pos = strtok( NULL, " " );
02099         rev = strtok( NULL, " " );
02100         for ( i = 0; i < ncp1; i++ )
02101         {
02102             if ( col == NULL )
02103                 break;
02104 
02105             if ( scol1( interp, plFramePtr,
02106                      i, col, pos, rev, &changed ) != TCL_OK )
02107                 return TCL_ERROR;
02108 
02109             col = strtok( NULL, " " );
02110             pos = strtok( NULL, " " );
02111             rev = strtok( NULL, " " );
02112         }
02113         free( tmpstring );
02114 
02115         if ( changed )
02116         {
02117             plFramePtr->pls->ncp1 = ncp1;
02118             plcmap1_calc();
02119         }
02120     }
02121 
02122 // scol0 -- set single color in cmap0
02123 // first arg is the color number, the next is the color in hex
02124 
02125     else if ( ( c == 's' ) && ( strncmp( argv[0], "scol0", (size_t) length ) == 0 ) )
02126     {
02127         int i = atoi( argv[1] ), changed = 1;
02128 
02129         if ( i > pls->ncol0 || i < 0 )
02130         {
02131             Tcl_AppendResult( interp, "illegal color number in cmap0: ",
02132                 argv[1], (char *) NULL );
02133             return TCL_ERROR;
02134         }
02135 
02136         if ( scol0( interp, plFramePtr, i, argv[2], &changed ) != TCL_OK )
02137             return TCL_ERROR;
02138 
02139         if ( changed )
02140             plP_state( PLSTATE_CMAP0 );
02141     }
02142 
02143 // scol1 -- set color of control point in cmap1
02144 // first arg is the control point, the next two are the color in hex and pos
02145 
02146     else if ( ( c == 's' ) && ( strncmp( argv[0], "scol1", (size_t) length ) == 0 ) )
02147     {
02148         int i = atoi( argv[1] ), changed = 1;
02149 
02150         if ( i > pls->ncp1 || i < 0 )
02151         {
02152             Tcl_AppendResult( interp, "illegal control point number in cmap1: ",
02153                 argv[1], (char *) NULL );
02154             return TCL_ERROR;
02155         }
02156 
02157         if ( scol1( interp, plFramePtr,
02158                  i, argv[2], argv[3], argv[4], &changed ) != TCL_OK )
02159             return TCL_ERROR;
02160 
02161         if ( changed )
02162             plcmap1_calc();
02163     }
02164 
02165     plflush();
02166     return result;
02167 }
02168 
02169 //--------------------------------------------------------------------------
02170 // Cmd
02171 //
02172 // Processes "cmd" widget command.
02173 // Handles commands that go more or less directly to the PLplot library.
02174 // Most of these come out of the PLplot Tcl API support file.
02175 //--------------------------------------------------------------------------
02176 
02177 static int
02178 Cmd( Tcl_Interp *interp, register PlFrame *plFramePtr,
02179      int argc, const char **argv )
02180 {
02181     int  result    = TCL_OK;
02182     char cmdlist[] = "";
02183 
02184 #ifdef DEBUG
02185     PLStream *pls = plFramePtr->pls;
02186     if ( pls->debug )
02187     {
02188         int i;
02189         fprintf( stderr, "There are %d arguments to Cmd:", argc );
02190         for ( i = 0; i < argc; i++ )
02191         {
02192             fprintf( stderr, " %s", argv[i] );
02193         }
02194         fprintf( stderr, "\n" );
02195     }
02196 #endif
02197 
02198 // no option -- return list of available PLplot commands
02199 
02200     if ( argc == 0 )
02201         return plTclCmd( cmdlist, interp, argc, argv );
02202 
02203 // Make sure widget has been initialized before going any further
02204 
02205     if ( !plFramePtr->tkwin_initted )
02206     {
02207         Tcl_VarEval( plFramePtr->interp, "update", (char *) NULL );
02208     }
02209 
02210 // Set stream number and get ready to process the command
02211 
02212     plsstrm( plFramePtr->ipls );
02213 
02214 // Process command
02215 
02216     result = plTclCmd( cmdlist, interp, argc, argv );
02217 
02218     plflush();
02219     return result;
02220 }
02221 
02222 //
02223 //--------------------------------------------------------------------------
02224 //
02225 // ConfigurePlFrame --
02226 //
02227 //      This procedure is called to process an argv/argc list, plus the Tk
02228 //      option database, in order to configure (or reconfigure) a
02229 //      plframe widget.
02230 //
02231 // Results:
02232 //      The return value is a standard Tcl result.  If TCL_ERROR is
02233 //      returned, then interp->result contains an error message.
02234 //
02235 // Side effects:
02236 //      Configuration information, such as text string, colors, font, etc.
02237 //      get set for plFramePtr; old resources get freed, if there were
02238 //      any.
02239 //
02240 //--------------------------------------------------------------------------
02241 //
02242 
02243 static int
02244 ConfigurePlFrame( Tcl_Interp *interp, register PlFrame *plFramePtr,
02245                   int argc, const char **argv, int flags )
02246 {
02247     register Tk_Window tkwin = plFramePtr->tkwin;
02248     PLStream           *pls  = plFramePtr->pls;
02249     XwDev              *dev  = (XwDev *) pls->dev;
02250     XwDisplay          *xwd  = (XwDisplay *) dev->xwd;
02251     XGCValues          gcValues;
02252     unsigned long      mask;
02253     int need_redisplay = 0;
02254 
02255 #ifdef DEBUG
02256     if ( pls->debug )
02257     {
02258         int i;
02259         fprintf( stderr, "Arguments to configure are:" );
02260         for ( i = 0; i < argc; i++ )
02261         {
02262             fprintf( stderr, " %s", argv[i] );
02263         }
02264         fprintf( stderr, "\n" );
02265     }
02266 #endif
02267 
02268     dbug_enter( "ConfigurePlFrame" );
02269 
02270     if ( Tk_ConfigureWidget( interp, tkwin, configSpecs,
02271              argc, (CONST char **) argv, (char *) plFramePtr, flags ) != TCL_OK )
02272     {
02273         return TCL_ERROR;
02274     }
02275 
02276 //
02277 // Set background color using xwin driver's pixel value.  Done this way so
02278 // that (a) we can use r/w color cells, and (b) the BG pixel values as set
02279 // here and in the xwin driver are consistent.
02280 //
02281 
02282     plsstrm( plFramePtr->ipls );
02283     plP_esc( PLESC_DEV2PLCOL, (void *) plFramePtr->bgColor );
02284     pl_cpcolor( &pls->cmap0[0], &pls->tmpcolor );
02285     plP_esc( PLESC_SETBGFG, NULL );
02286 
02287     Tk_SetWindowBackground( tkwin, xwd->cmap0[0].pixel );
02288     Tk_SetWindowBorder( tkwin, xwd->cmap0[0].pixel );
02289 
02290 // Set up GC for rubber-band draws
02291 
02292     gcValues.background = xwd->cmap0[0].pixel;
02293     gcValues.foreground = 0xFF;
02294     gcValues.function   = GXxor;
02295     mask = GCForeground | GCBackground | GCFunction;
02296 
02297     if ( plFramePtr->xorGC != NULL )
02298         Tk_FreeGC( plFramePtr->display, plFramePtr->xorGC );
02299 
02300     plFramePtr->xorGC = Tk_GetGC( plFramePtr->tkwin, mask, &gcValues );
02301 
02302 // Geometry settings
02303 
02304     Tk_SetInternalBorder( tkwin, plFramePtr->borderWidth );
02305     if ( ( plFramePtr->width > 0 ) || ( plFramePtr->height > 0 ) )
02306     {
02307         Tk_GeometryRequest( tkwin, plFramePtr->width, plFramePtr->height );
02308         if ( ( plFramePtr->width != plFramePtr->prevWidth ) ||
02309              ( plFramePtr->height != plFramePtr->prevHeight ) )
02310             need_redisplay = 1;
02311     }
02312 
02313 // Create or destroy graphic crosshairs as specified
02314 
02315     if ( Tk_IsMapped( tkwin ) )
02316     {
02317         if ( plFramePtr->xhairs )
02318         {
02319             if ( !plFramePtr->drawing_xhairs )
02320                 CreateXhairs( plFramePtr );
02321         }
02322         else
02323         {
02324             if ( plFramePtr->drawing_xhairs )
02325                 DestroyXhairs( plFramePtr );
02326         }
02327     }
02328 
02329 // Create or destroy rubber band as specified
02330 
02331     if ( Tk_IsMapped( tkwin ) )
02332     {
02333         if ( plFramePtr->rband )
02334         {
02335             if ( !plFramePtr->drawing_rband )
02336                 CreateRband( plFramePtr );
02337         }
02338         else
02339         {
02340             if ( plFramePtr->drawing_rband )
02341                 DestroyRband( plFramePtr );
02342         }
02343     }
02344 
02345 // Arrange for window to be refreshed if necessary
02346 
02347     if ( need_redisplay && Tk_IsMapped( tkwin )
02348          && !( plFramePtr->flags & REFRESH_PENDING ) )
02349     {
02350         Tk_DoWhenIdle( DisplayPlFrame, (ClientData) plFramePtr );
02351         plFramePtr->flags |= REFRESH_PENDING;
02352         plFramePtr->flags |= UPDATE_V_SCROLLBAR | UPDATE_H_SCROLLBAR;
02353     }
02354 
02355     return TCL_OK;
02356 }
02357 
02358 //--------------------------------------------------------------------------
02359 // Draw
02360 //
02361 // Processes "draw" widget command.
02362 // Handles rubber-band drawing.
02363 //--------------------------------------------------------------------------
02364 
02365 static int
02366 Draw( Tcl_Interp *interp, register PlFrame *plFramePtr,
02367       int argc, const char **argv )
02368 {
02369     register Tk_Window tkwin = plFramePtr->tkwin;
02370     int  result = TCL_OK;
02371     char c      = argv[0][0];
02372     int  length = (int) strlen( argv[0] );
02373 
02374 // Make sure widget has been initialized before going any further
02375 
02376     if ( !plFramePtr->tkwin_initted )
02377     {
02378         Tcl_VarEval( plFramePtr->interp, "update", (char *) NULL );
02379     }
02380 
02381 // init -- sets up for rubber-band drawing
02382 
02383     if ( ( c == 'i' ) && ( strncmp( argv[0], "init", (size_t) length ) == 0 ) )
02384     {
02385         Tk_DefineCursor( tkwin, plFramePtr->xhair_cursor );
02386     }
02387 
02388 // end -- ends rubber-band drawing
02389 
02390     else if ( ( c == 'e' ) && ( strncmp( argv[0], "end", (size_t) length ) == 0 ) )
02391     {
02392         Tk_DefineCursor( tkwin, plFramePtr->cursor );
02393         if ( plFramePtr->continue_draw )
02394         {
02395             XDrawLines( Tk_Display( tkwin ), Tk_WindowId( tkwin ),
02396                 plFramePtr->xorGC, plFramePtr->pts, 5,
02397                 CoordModeOrigin );
02398             XSync( Tk_Display( tkwin ), 0 );
02399         }
02400 
02401         plFramePtr->continue_draw = 0;
02402     }
02403 
02404 // rect -- draw a rectangle, used to select rectangular areas
02405 // first draw erases old outline
02406 
02407     else if ( ( c == 'r' ) && ( strncmp( argv[0], "rect", (size_t) length ) == 0 ) )
02408     {
02409         if ( argc < 5 )
02410         {
02411             Tcl_AppendResult( interp, "wrong # args: should be \"",
02412                 " draw rect x0 y0 x1 y1\"", (char *) NULL );
02413             result = TCL_ERROR;
02414         }
02415         else
02416         {
02417             int x0, y0, x1, y1;
02418             int xmin = 0, xmax = Tk_Width( tkwin ) - 1;
02419             int ymin = 0, ymax = Tk_Height( tkwin ) - 1;
02420 
02421             x0 = atoi( argv[1] );
02422             y0 = atoi( argv[2] );
02423             x1 = atoi( argv[3] );
02424             y1 = atoi( argv[4] );
02425 
02426             x0 = MAX( xmin, MIN( xmax, x0 ) );
02427             y0 = MAX( ymin, MIN( ymax, y0 ) );
02428             x1 = MAX( xmin, MIN( xmax, x1 ) );
02429             y1 = MAX( ymin, MIN( ymax, y1 ) );
02430 
02431             if ( plFramePtr->continue_draw )
02432             {
02433                 XDrawLines( Tk_Display( tkwin ), Tk_WindowId( tkwin ),
02434                     plFramePtr->xorGC, plFramePtr->pts, 5,
02435                     CoordModeOrigin );
02436                 XSync( Tk_Display( tkwin ), 0 );
02437             }
02438 
02439             plFramePtr->pts[0].x = (short) x0; plFramePtr->pts[0].y = (short) y0;
02440             plFramePtr->pts[1].x = (short) x1; plFramePtr->pts[1].y = (short) y0;
02441             plFramePtr->pts[2].x = (short) x1; plFramePtr->pts[2].y = (short) y1;
02442             plFramePtr->pts[3].x = (short) x0; plFramePtr->pts[3].y = (short) y1;
02443             plFramePtr->pts[4].x = (short) x0; plFramePtr->pts[4].y = (short) y0;
02444 
02445             XDrawLines( Tk_Display( tkwin ), Tk_WindowId( tkwin ),
02446                 plFramePtr->xorGC, plFramePtr->pts, 5,
02447                 CoordModeOrigin );
02448             XSync( Tk_Display( tkwin ), 0 );
02449 
02450             plFramePtr->continue_draw = 1;
02451         }
02452     }
02453 
02454     return result;
02455 }
02456 
02457 //--------------------------------------------------------------------------
02458 // Info
02459 //
02460 // Processes "info" widget command.
02461 // Returns requested info.
02462 //--------------------------------------------------------------------------
02463 
02464 static int
02465 Info( Tcl_Interp *interp, register PlFrame *plFramePtr,
02466       int argc, const char **argv )
02467 {
02468     int  length;
02469     char c;
02470     int  result = TCL_OK;
02471 
02472 // no option -- return list of available info commands
02473 
02474     if ( argc == 0 )
02475     {
02476         Tcl_SetResult( interp, "devkeys devnames", TCL_STATIC );
02477         return TCL_OK;
02478     }
02479 
02480     c      = argv[0][0];
02481     length = (int) strlen( argv[0] );
02482 
02483 // devkeys -- return list of supported device keywords
02484 
02485     if ( ( c == 'd' ) && ( strncmp( argv[0], "devkeys", (size_t) length ) == 0 ) )
02486     {
02487         int i = 0;
02488         while ( plFramePtr->devName[i] != NULL )
02489             Tcl_AppendElement( interp, plFramePtr->devName[i++] );
02490 
02491         result = TCL_OK;
02492     }
02493 
02494 // devkeys -- return list of supported device types
02495 
02496     else if ( ( c == 'd' ) && ( strncmp( argv[0], "devnames", (size_t) length ) == 0 ) )
02497     {
02498         int i = 0;
02499         while ( plFramePtr->devDesc[i] != NULL )
02500             Tcl_AppendElement( interp, plFramePtr->devDesc[i++] );
02501 
02502         result = TCL_OK;
02503     }
02504 
02505 // unrecognized
02506 
02507     else
02508     {
02509         Tcl_AppendResult( interp, "bad option to \"info\": must be ",
02510             "devkeys, devnames", (char *) NULL );
02511 
02512         result = TCL_ERROR;
02513     }
02514 
02515     return result;
02516 }
02517 
02518 //--------------------------------------------------------------------------
02519 // Openlink
02520 //
02521 // Processes "openlink" widget command.
02522 // Opens channel (FIFO or socket) for binary data transfer between client
02523 // and server.
02524 //--------------------------------------------------------------------------
02525 
02526 static int
02527 Openlink( Tcl_Interp *interp, register PlFrame *plFramePtr,
02528           int argc, const char **argv )
02529 {
02530     register PLRDev  *plr   = plFramePtr->plr;
02531     register PLiodev *iodev = plr->iodev;
02532 
02533     char             c = argv[0][0];
02534     int length         = (int) strlen( argv[0] );
02535 
02536     dbug_enter( "Openlink" );
02537 
02538 // Open fifo
02539 
02540     if ( ( c == 'f' ) && ( strncmp( argv[0], "fifo", (size_t) length ) == 0 ) )
02541     {
02542         if ( argc < 1 )
02543         {
02544             Tcl_AppendResult( interp, "bad command -- must be: ",
02545                 "openlink fifo <pathname>",
02546                 (char *) NULL );
02547             return TCL_ERROR;
02548         }
02549 #if !defined ( __WIN32__ )
02550         if ( ( iodev->fd = open( argv[1], O_RDONLY ) ) == -1 )
02551 #else
02552         if ( 1 )
02553 #endif
02554         {
02555             Tcl_AppendResult( interp, "cannot open fifo ", argv[1],
02556                 " for read", (char *) NULL );
02557             return TCL_ERROR;
02558         }
02559         iodev->type     = 0;
02560         iodev->typeName = "fifo";
02561 #if !defined ( __WIN32__ )
02562         iodev->file = fdopen( iodev->fd, "rb" );
02563 #else
02564         iodev->file = NULL;
02565 #endif
02566     }
02567 
02568 // Open socket
02569 
02570     else if ( ( c == 's' ) && ( strncmp( argv[0], "socket", (size_t) length ) == 0 ) )
02571     {
02572         if ( argc < 1 )
02573         {
02574             Tcl_AppendResult( interp, "bad command -- must be: ",
02575                 "openlink socket <sock-id>",
02576                 (char *) NULL );
02577             return TCL_ERROR;
02578         }
02579         iodev->type       = 1;
02580         iodev->typeName   = "socket";
02581         iodev->fileHandle = argv[1];
02582 
02583 #if TCL_MAJOR_VERSION < 7 || ( TCL_MAJOR_VERSION == 7 && TCL_MINOR_VERSION == 4 )
02584 #define FILECAST
02585 #else
02586 #define FILECAST    ( ClientData )
02587 #endif
02588 
02589 // Exclude UNIX-only feature
02590 #if !defined ( MAC_TCL ) && !defined ( __WIN32__ ) && !defined ( __CYGWIN__ )
02591         if ( Tcl_GetOpenFile( interp, iodev->fileHandle,
02592                  0, 1, FILECAST & iodev->file ) != TCL_OK )
02593         {
02594             return TCL_ERROR;
02595         }
02596 #endif
02597         iodev->fd = fileno( iodev->file );
02598     }
02599 
02600 // unrecognized
02601 
02602     else
02603     {
02604         Tcl_AppendResult( interp, "bad option to \"openlink\": must be ",
02605             "fifo or socket", (char *) NULL );
02606 
02607         return TCL_ERROR;
02608     }
02609 
02610     plr->pdfs = pdf_bopen( NULL, 4200 );
02611 // Sheesh, what a mess.  I don't see how Tk4.1's converter macro could
02612 // possibly work.
02613 #if TK_MAJOR_VERSION < 4 ||                               \
02614     ( TK_MAJOR_VERSION == 4 && TK_MINOR_VERSION == 0 ) || \
02615     TK_MAJOR_VERSION > 7
02616 #if !defined ( MAC_TCL ) && !defined ( __WIN32__ ) && !defined ( __CYGWIN__ )
02617     Tk_CreateFileHandler( iodev->fd, TK_READABLE, (Tk_FileProc *) ReadData,
02618         (ClientData) plFramePtr );
02619 #endif
02620 #else
02621 #if !defined ( MAC_TCL ) && !defined ( __WIN32__ ) && !defined ( __CYGWIN__ )
02622     Tcl_CreateFileHandler( Tcl_GetFile( (ClientData) iodev->fd, TCL_UNIX_FD ),
02623         TK_READABLE, (Tk_FileProc *) ReadData,
02624         (ClientData) plFramePtr );
02625 #endif
02626 #endif
02627 
02628     return TCL_OK;
02629 }
02630 
02631 //--------------------------------------------------------------------------
02632 // Closelink
02633 //
02634 // Processes "closelink" widget command.
02635 // CLoses channel previously opened with the "openlink" widget command.
02636 //--------------------------------------------------------------------------
02637 
02638 static int
02639 Closelink( Tcl_Interp *interp, register PlFrame *plFramePtr,
02640            int PL_UNUSED( argc ), const char ** PL_UNUSED( argv ) )
02641 {
02642     register PLRDev  *plr   = plFramePtr->plr;
02643     register PLiodev *iodev = plr->iodev;
02644 
02645     dbug_enter( "Closelink" );
02646 
02647     if ( iodev->fd == 0 )
02648     {
02649         Tcl_AppendResult( interp, "no link currently open", (char *) NULL );
02650         return TCL_ERROR;
02651     }
02652 
02653 #if TK_MAJOR_VERSION < 4 ||                               \
02654     ( TK_MAJOR_VERSION == 4 && TK_MINOR_VERSION == 0 ) || \
02655     TK_MAJOR_VERSION > 7
02656 #if !defined ( MAC_TCL ) && !defined ( __WIN32__ ) && !defined ( __CYGWIN__ )
02657     Tk_DeleteFileHandler( iodev->fd );
02658 #endif
02659 #else
02660 //    Tk_DeleteFileHandler( iodev->file );
02661 #if !defined ( MAC_TCL ) && !defined ( __WIN32__ ) && !defined ( __CYGWIN__ )
02662     Tcl_DeleteFileHandler( Tcl_GetFile( (ClientData) iodev->fd,
02663             TCL_UNIX_FD ) );
02664 #endif
02665 #endif
02666     pdf_close( plr->pdfs );
02667     iodev->fd = 0;
02668 
02669     return TCL_OK;
02670 }
02671 
02672 //--------------------------------------------------------------------------
02673 // process_data
02674 //
02675 // Utility function for processing data and other housekeeping.
02676 //--------------------------------------------------------------------------
02677 
02678 static int
02679 process_data( Tcl_Interp *interp, register PlFrame *plFramePtr )
02680 {
02681     register PLRDev  *plr   = plFramePtr->plr;
02682     register PLiodev *iodev = plr->iodev;
02683     int result = TCL_OK;
02684 
02685 // Process data
02686 
02687     if ( plr_process( plr ) == -1 )
02688     {
02689         Tcl_AppendResult( interp, "unable to read from ", iodev->typeName,
02690             (char *) NULL );
02691         result = TCL_ERROR;
02692     }
02693 
02694 // Signal bop if necessary
02695 
02696     if ( plr->at_bop && plFramePtr->bopCmd != NULL )
02697     {
02698         plr->at_bop = 0;
02699         if ( Tcl_Eval( interp, plFramePtr->bopCmd ) != TCL_OK )
02700             fprintf( stderr, "Command \"%s\" failed:\n\t %s\n",
02701                 plFramePtr->bopCmd, Tcl_GetStringResult( interp ) );
02702     }
02703 
02704 // Signal eop if necessary
02705 
02706     if ( plr->at_eop && plFramePtr->eopCmd != NULL )
02707     {
02708         plr->at_eop = 0;
02709         if ( Tcl_Eval( interp, plFramePtr->eopCmd ) != TCL_OK )
02710             fprintf( stderr, "Command \"%s\" failed:\n\t %s\n",
02711                 plFramePtr->eopCmd, Tcl_GetStringResult( interp ) );
02712     }
02713 
02714     return result;
02715 }
02716 
02717 //--------------------------------------------------------------------------
02718 // ReadData
02719 //
02720 // Reads & processes data.
02721 // Intended to be installed as a filehandler command.
02722 //--------------------------------------------------------------------------
02723 
02724 static int
02725 ReadData( ClientData clientData, int mask )
02726 {
02727     register PlFrame    *plFramePtr = (PlFrame *) clientData;
02728     register Tcl_Interp *interp     = plFramePtr->interp;
02729 
02730     register PLRDev     *plr   = plFramePtr->plr;
02731     register PLiodev    *iodev = plr->iodev;
02732     register PDFstrm    *pdfs  = plr->pdfs;
02733     int result = TCL_OK;
02734 
02735     if ( mask & TK_READABLE )
02736     {
02737         // Read from FIFO or socket
02738 
02739         plsstrm( plFramePtr->ipls );
02740         if ( pl_PacketReceive( interp, iodev, pdfs ) )
02741         {
02742             Tcl_AppendResult( interp, "Packet receive failed:\n\t %s\n",
02743                 (char *) NULL );
02744             return TCL_ERROR;
02745         }
02746 
02747         // If the packet isn't complete it will be put back and we just return.
02748         // Otherwise, the buffer pointer is saved and then cleared so that reads
02749         // from the buffer start at the beginning.
02750         //
02751         if ( pdfs->bp == 0 )
02752             return TCL_OK;
02753 
02754         plr->nbytes = (int) pdfs->bp;
02755         pdfs->bp    = 0;
02756         result      = process_data( interp, plFramePtr );
02757     }
02758 
02759     return result;
02760 }
02761 
02762 //--------------------------------------------------------------------------
02763 // Orient
02764 //
02765 // Processes "orient" widget command.
02766 // Handles orientation of plot.
02767 //--------------------------------------------------------------------------
02768 
02769 static int
02770 Orient( Tcl_Interp *interp, register PlFrame *plFramePtr,
02771         int argc, const char **argv )
02772 {
02773     int result = TCL_OK;
02774 
02775 // orient -- return orientation of current plot window
02776 
02777     plsstrm( plFramePtr->ipls );
02778 
02779     if ( argc == 0 )
02780     {
02781         PLFLT rot;
02782         char  result_str[128];
02783         plgdiori( &rot );
02784         sprintf( result_str, "%f", rot );
02785         Tcl_SetResult( interp, result_str, TCL_VOLATILE );
02786     }
02787 
02788 // orient <rot> -- Set orientation to <rot>
02789 
02790     else
02791     {
02792         plsdiori( atof( argv[0] ) );
02793         result = Redraw( interp, plFramePtr, argc - 1, argv + 1 );
02794     }
02795 
02796     return result;
02797 }
02798 
02799 //--------------------------------------------------------------------------
02800 // Print
02801 //
02802 // Processes "print" widget command.
02803 // Handles printing of plot, duh.
02804 //
02805 // Creates a temporary file, dumps the current plot to it in metafile
02806 // form, and then execs the "plpr" script to actually print it.  Since we
02807 // output it in metafile form here, plpr must invoke plrender to drive the
02808 // output to the appropriate file type.  The script is responsible for the
02809 // deletion of the plot metafile.
02810 //--------------------------------------------------------------------------
02811 
02812 static int
02813 Print( Tcl_Interp *interp, register PlFrame *plFramePtr,
02814        int PL_UNUSED( argc ), const char ** PL_UNUSED( argv ) )
02815 {
02816     PLINT ipls;
02817     int   result = TCL_OK;
02818     char  *sfnam;
02819     FILE  *sfile;
02820     pid_t pid;
02821 
02822 // Make sure widget has been initialized before going any further
02823 
02824     if ( !plFramePtr->tkwin_initted )
02825     {
02826         Tcl_AppendResult( interp, "Error -- widget not plotted to yet",
02827             (char *) NULL );
02828         return TCL_ERROR;
02829     }
02830 
02831 // Create stream for save
02832 
02833     plmkstrm( &ipls );
02834     if ( ipls < 0 )
02835     {
02836         Tcl_AppendResult( interp, "Error -- cannot create stream",
02837             (char *) NULL );
02838         return TCL_ERROR;
02839     }
02840 
02841 // Open file for writes
02842     sfnam = NULL;
02843 
02844     // Create and open temporary file
02845     if ( ( sfile = pl_create_tempfile( &sfnam ) ) == NULL )
02846     {
02847         Tcl_AppendResult( interp,
02848             "Error -- cannot open plot file for writing",
02849             (char *) NULL );
02850         plend1();
02851         if ( sfnam != NULL )
02852             free( sfnam );
02853         return TCL_ERROR;
02854     }
02855 
02856 // Initialize stream
02857 
02858     plsdev( "plmeta" );
02859     plsfile( sfile );
02860 // FIXME: plmeta/plrender need to honor these, needed to preserve the aspect ratio
02861     plspage( 0., 0., plFramePtr->width, plFramePtr->height, 0, 0 );
02862     plcpstrm( plFramePtr->ipls, 0 );
02863     pladv( 0 );
02864 
02865 // Remake current plot, close file, and switch back to original stream
02866 
02867     plreplot();
02868     plend1();
02869     plsstrm( plFramePtr->ipls );
02870 
02871 // So far so good.  Time to exec the print script.
02872 
02873     if ( plFramePtr->plpr_cmd == NULL )
02874         plFramePtr->plpr_cmd = plFindCommand( "plpr" );
02875 
02876 #if !defined ( __WIN32__ )
02877     if ( ( plFramePtr->plpr_cmd == NULL ) || ( pid = fork() ) < 0 )
02878 #else
02879     if ( 1 )
02880 #endif
02881     {
02882         Tcl_AppendResult( interp,
02883             "Error -- cannot fork print process",
02884             (char *) NULL );
02885         result = TCL_ERROR;
02886     }
02887     else if ( pid == 0 )
02888     {
02889 #if !defined ( __WIN32__ )
02890         if ( execl( plFramePtr->plpr_cmd, plFramePtr->plpr_cmd, sfnam,
02891                  (char *) 0 ) )
02892 #else
02893         if ( 1 )
02894 #endif
02895         {
02896             fprintf( stderr, "Unable to exec print command.\n" );
02897             free( sfnam );
02898             _exit( 1 );
02899         }
02900     }
02901 
02902     free( sfnam );
02903 
02904     return result;
02905 }
02906 
02907 //--------------------------------------------------------------------------
02908 // Page
02909 //
02910 // Processes "page" widget command.
02911 // Handles parameters such as margin, aspect ratio, and justification
02912 // of final plot.
02913 //--------------------------------------------------------------------------
02914 
02915 static int
02916 Page( Tcl_Interp *interp, register PlFrame *plFramePtr,
02917       int argc, const char **argv )
02918 {
02919 // page -- return current device window parameters
02920 
02921     plsstrm( plFramePtr->ipls );
02922 
02923     if ( argc == 0 )
02924     {
02925         PLFLT mar, aspect, jx, jy;
02926         char  result_str[128];
02927 
02928         plgdidev( &mar, &aspect, &jx, &jy );
02929         sprintf( result_str, "%g %g %g %g", mar, aspect, jx, jy );
02930         Tcl_SetResult( interp, result_str, TCL_VOLATILE );
02931         return TCL_OK;
02932     }
02933 
02934 // page <mar> <aspect> <jx> <jy> -- set up page
02935 
02936     if ( argc < 4 )
02937     {
02938         Tcl_AppendResult( interp, "wrong # args: should be \"",
02939             " page mar aspect jx jy\"", (char *) NULL );
02940         return TCL_ERROR;
02941     }
02942 
02943     plsdidev( atof( argv[0] ), atof( argv[1] ), atof( argv[2] ), atof( argv[3] ) );
02944     return ( Redraw( interp, plFramePtr, argc - 1, argv + 1 ) );
02945 }
02946 
02947 //--------------------------------------------------------------------------
02948 // Redraw
02949 //
02950 // Processes "redraw" widget command.
02951 // Turns loose a DoWhenIdle command to redraw plot by replaying contents
02952 // of plot buffer.
02953 //--------------------------------------------------------------------------
02954 
02955 static int
02956 Redraw( Tcl_Interp *PL_UNUSED( interp ), register PlFrame *plFramePtr,
02957         int PL_UNUSED( argc ), const char ** PL_UNUSED( argv ) )
02958 {
02959     dbug_enter( "Redraw" );
02960 
02961     plFramePtr->flags |= REDRAW_PENDING;
02962     if ( ( plFramePtr->tkwin != NULL ) &&
02963          !( plFramePtr->flags & REFRESH_PENDING ) )
02964     {
02965         Tk_DoWhenIdle( DisplayPlFrame, (ClientData) plFramePtr );
02966         plFramePtr->flags |= REFRESH_PENDING;
02967     }
02968 
02969     return TCL_OK;
02970 }
02971 
02972 //--------------------------------------------------------------------------
02973 // Save
02974 //
02975 // Processes "save" widget command.
02976 // Saves plot to a file.
02977 //--------------------------------------------------------------------------
02978 
02979 static int
02980 Save( Tcl_Interp *interp, register PlFrame *plFramePtr,
02981       int argc, const char **argv )
02982 {
02983     int  length;
02984     char c;
02985     FILE *sfile;
02986 
02987 // Make sure widget has been initialized before going any further
02988 
02989     if ( !plFramePtr->tkwin_initted )
02990     {
02991         Tcl_AppendResult( interp, "Error -- widget not plotted to yet",
02992             (char *) NULL );
02993         return TCL_ERROR;
02994     }
02995 
02996 // save -- save to already open file
02997 
02998     if ( argc == 0 )
02999     {
03000         if ( !plFramePtr->ipls_save )
03001         {
03002             Tcl_AppendResult( interp, "Error -- no current save file",
03003                 (char *) NULL );
03004             return TCL_ERROR;
03005         }
03006         plsstrm( plFramePtr->ipls_save );
03007         // Note: many drivers ignore these, needed to preserve the aspect ratio
03008         plspage( 0., 0., plFramePtr->width, plFramePtr->height, 0, 0 );
03009         plcpstrm( plFramePtr->ipls, 0 );
03010         pladv( 0 );
03011         plreplot();
03012         plflush();
03013         plsstrm( plFramePtr->ipls );
03014         return TCL_OK;
03015     }
03016 
03017     c      = argv[0][0];
03018     length = (int) strlen( argv[0] );
03019 
03020 // save to specified device & file
03021 
03022     if ( ( c == 'a' ) && ( strncmp( argv[0], "as", (size_t) length ) == 0 ) )
03023     {
03024         if ( argc < 3 )
03025         {
03026             Tcl_AppendResult( interp, "wrong # args: should be \"",
03027                 " save as device file\"", (char *) NULL );
03028             return TCL_ERROR;
03029         }
03030 
03031         // If save previously in effect, delete old stream
03032 
03033         if ( plFramePtr->ipls_save )
03034         {
03035             plsstrm( plFramePtr->ipls_save );
03036             plend1();
03037         }
03038 
03039         // Create stream for saves to selected device & file
03040 
03041         plmkstrm( &plFramePtr->ipls_save );
03042         if ( plFramePtr->ipls_save < 0 )
03043         {
03044             Tcl_AppendResult( interp, "Error -- cannot create stream",
03045                 (char *) NULL );
03046             plFramePtr->ipls_save = 0;
03047             return TCL_ERROR;
03048         }
03049 
03050         // Open file for writes
03051 
03052         if ( ( sfile = fopen( argv[2], "wb+" ) ) == NULL )
03053         {
03054             Tcl_AppendResult( interp, "Error -- cannot open file ", argv[2],
03055                 " for writing", (char *) NULL );
03056             plFramePtr->ipls_save = 0;
03057             plend1();
03058             return TCL_ERROR;
03059         }
03060 
03061         // Initialize stream
03062 
03063         plsdev( argv[1] );
03064         plsfile( sfile );
03065         // Note: many drivers ignore these, needed to preserve the aspect ratio
03066         plspage( 0., 0., plFramePtr->width, plFramePtr->height, 0, 0 );
03067         plcpstrm( plFramePtr->ipls, 0 );
03068         pladv( 0 );
03069 
03070         // Remake current plot and then switch back to original stream
03071 
03072         plreplot();
03073         plflush();
03074         plsstrm( plFramePtr->ipls );
03075     }
03076 
03077 // close save file
03078 
03079     else if ( ( c == 'c' ) && ( strncmp( argv[0], "close", (size_t) length ) == 0 ) )
03080     {
03081         if ( !plFramePtr->ipls_save )
03082         {
03083             Tcl_AppendResult( interp, "Error -- no current save file",
03084                 (char *) NULL );
03085             return TCL_ERROR;
03086         }
03087         else
03088         {
03089             plsstrm( plFramePtr->ipls_save );
03090             plend1();
03091             plFramePtr->ipls_save = 0;
03092             plsstrm( plFramePtr->ipls );
03093         }
03094     }
03095 
03096 // unrecognized
03097 
03098     else
03099     {
03100         Tcl_AppendResult( interp, "bad option to \"save\": must be ",
03101             "as or close", (char *) NULL );
03102 
03103         return TCL_ERROR;
03104     }
03105 
03106     return TCL_OK;
03107 }
03108 
03109 //--------------------------------------------------------------------------
03110 // View
03111 //
03112 // Processes "view" widget command.
03113 // Handles translation & scaling of view into plot.
03114 //--------------------------------------------------------------------------
03115 
03116 static int
03117 View( Tcl_Interp *interp, register PlFrame *plFramePtr,
03118       int argc, const char **argv )
03119 {
03120     int   length;
03121     char  c;
03122     PLFLT xl, xr, yl, yr;
03123 
03124 // view -- return current relative plot window coordinates
03125 
03126     plsstrm( plFramePtr->ipls );
03127 
03128     if ( argc == 0 )
03129     {
03130         char result_str[128];
03131         plgdiplt( &xl, &yl, &xr, &yr );
03132         sprintf( result_str, "%g %g %g %g", xl, yl, xr, yr );
03133         Tcl_SetResult( interp, result_str, TCL_VOLATILE );
03134         return TCL_OK;
03135     }
03136 
03137     c      = argv[0][0];
03138     length = (int) strlen( argv[0] );
03139 
03140 // view bounds -- return relative device coordinates of bounds on current
03141 // plot window
03142 
03143     if ( ( c == 'b' ) && ( strncmp( argv[0], "bounds", (size_t) length ) == 0 ) )
03144     {
03145         char result_str[128];
03146         xl = 0.; yl = 0.;
03147         xr = 1.; yr = 1.;
03148         pldip2dc( &xl, &yl, &xr, &yr );
03149         sprintf( result_str, "%g %g %g %g", xl, yl, xr, yr );
03150         Tcl_SetResult( interp, result_str, TCL_VOLATILE );
03151         return TCL_OK;
03152     }
03153 
03154 // view reset -- Resets plot
03155 
03156     if ( ( c == 'r' ) && ( strncmp( argv[0], "reset", (size_t) length ) == 0 ) )
03157     {
03158         xl = 0.; yl = 0.;
03159         xr = 1.; yr = 1.;
03160         plsdiplt( xl, yl, xr, yr );
03161     }
03162 
03163 // view select -- set window into plot space
03164 // Specifies in terms of plot window coordinates, not device coordinates
03165 
03166     else if ( ( c == 's' ) && ( strncmp( argv[0], "select", (size_t) length ) == 0 ) )
03167     {
03168         if ( argc < 5 )
03169         {
03170             Tcl_AppendResult( interp, "wrong # args: should be \"",
03171                 " view select xmin ymin xmax ymax\"",
03172                 (char *) NULL );
03173             return TCL_ERROR;
03174         }
03175         else
03176         {
03177             gbox( &xl, &yl, &xr, &yr, argv + 1 );
03178             plsdiplt( xl, yl, xr, yr );
03179         }
03180     }
03181 
03182 // view zoom -- set window into plot space incrementally (zoom)
03183 // Here we need to take the page (device) offsets into account
03184 
03185     else if ( ( c == 'z' ) && ( strncmp( argv[0], "zoom", (size_t) length ) == 0 ) )
03186     {
03187         if ( argc < 5 )
03188         {
03189             Tcl_AppendResult( interp, "wrong # args: should be \"",
03190                 " view zoom xmin ymin xmax ymax\"",
03191                 (char *) NULL );
03192             return TCL_ERROR;
03193         }
03194         else
03195         {
03196             gbox( &xl, &yl, &xr, &yr, argv + 1 );
03197             pldid2pc( &xl, &yl, &xr, &yr );
03198             plsdiplz( xl, yl, xr, yr );
03199         }
03200     }
03201 
03202 // unrecognized
03203 
03204     else
03205     {
03206         Tcl_AppendResult( interp, "bad option \"", argv[1],
03207             "\":  options to \"view\" are: bounds, reset, select, or zoom",
03208             (char *) NULL );
03209 
03210         return TCL_ERROR;
03211     }
03212 
03213 // Update plot window bounds and arrange for plot to be updated
03214 
03215     plgdiplt( &xl, &yl, &xr, &yr );
03216     plFramePtr->xl     = xl;
03217     plFramePtr->yl     = yl;
03218     plFramePtr->xr     = xr;
03219     plFramePtr->yr     = yr;
03220     plFramePtr->flags |= UPDATE_V_SCROLLBAR | UPDATE_H_SCROLLBAR;
03221 
03222     return ( Redraw( interp, plFramePtr, argc, argv ) );
03223 }
03224 
03225 //--------------------------------------------------------------------------
03226 // xScroll
03227 //
03228 // Processes "xscroll" widget command.
03229 // Handles horizontal scroll-bar invoked translation of view into plot.
03230 //--------------------------------------------------------------------------
03231 
03232 static int
03233 xScroll( Tcl_Interp *interp, register PlFrame *plFramePtr,
03234          int argc, const char **argv )
03235 {
03236     int   x0, width = Tk_Width( plFramePtr->tkwin );
03237     PLFLT xl, xr, yl, yr, xlen;
03238 
03239     plsstrm( plFramePtr->ipls );
03240 
03241     xlen = plFramePtr->xr - plFramePtr->xl;
03242     x0   = atoi( argv[0] );
03243     xl   = x0 / (double) width;
03244     xl   = MAX( 0., MIN( ( 1. - xlen ), xl ) );
03245     xr   = xl + xlen;
03246 
03247     yl = plFramePtr->yl;
03248     yr = plFramePtr->yr;
03249 
03250     plFramePtr->xl = xl;
03251     plFramePtr->xr = xr;
03252 
03253     plsdiplt( xl, yl, xr, yr );
03254 
03255     plFramePtr->flags |= UPDATE_V_SCROLLBAR | UPDATE_H_SCROLLBAR;
03256     return ( Redraw( interp, plFramePtr, argc, argv ) );
03257 }
03258 
03259 //--------------------------------------------------------------------------
03260 // yScroll
03261 //
03262 // Processes "yscroll" widget command.
03263 // Handles vertical scroll-bar invoked translation of view into plot.
03264 //--------------------------------------------------------------------------
03265 
03266 static int
03267 yScroll( Tcl_Interp *interp, register PlFrame *plFramePtr,
03268          int argc, const char **argv )
03269 {
03270     int   y0, height = Tk_Height( plFramePtr->tkwin );
03271     PLFLT xl, xr, yl, yr, ylen;
03272 
03273     plsstrm( plFramePtr->ipls );
03274 
03275     ylen = plFramePtr->yr - plFramePtr->yl;
03276     y0   = atoi( argv[0] );
03277     yr   = 1. - y0 / (double) height;
03278     yr   = MAX( 0. + ylen, MIN( 1., yr ) );
03279     yl   = yr - ylen;
03280 
03281     xl = plFramePtr->xl;
03282     xr = plFramePtr->xr;
03283 
03284     plFramePtr->yl = yl;
03285     plFramePtr->yr = yr;
03286 
03287     plsdiplt( xl, yl, xr, yr );
03288 
03289     plFramePtr->flags |= UPDATE_V_SCROLLBAR | UPDATE_H_SCROLLBAR;
03290     return ( Redraw( interp, plFramePtr, argc, argv ) );
03291 }
03292 
03293 //--------------------------------------------------------------------------
03294 // report
03295 //
03296 // 4/17/95 GMF
03297 // Processes "report" widget command.
03298 //--------------------------------------------------------------------------
03299 
03300 static int
03301 report( Tcl_Interp *interp, register PlFrame *plFramePtr,
03302         int argc, const char **argv )
03303 {
03304     PLFLT x, y;
03305     char  tmpstring[50];
03306 //    fprintf( stdout, "Made it into report, argc=%d\n", argc );
03307 
03308     if ( argc == 0 )
03309     {
03310         Tcl_SetResult( interp, "report what?", TCL_STATIC );
03311         return TCL_ERROR;
03312     }
03313 
03314     if ( !strcmp( argv[0], "wc" ) )
03315     {
03316         XwDev        *dev = (XwDev *) plFramePtr->pls->dev;
03317         PLGraphicsIn *gin = &( dev->gin );
03318 
03319         if ( argc != 3 )
03320         {
03321             Tcl_SetResult( interp, "Wrong # of args: report wc x y", TCL_STATIC );
03322             return TCL_ERROR;
03323         }
03324 
03325         x = atof( argv[1] );
03326         y = atof( argv[2] );
03327 
03328         gin->dX = (PLFLT) x / ( dev->width - 1 );
03329         gin->dY = 1.0 - (PLFLT) y / ( dev->height - 1 );
03330 
03331         // Try to locate cursor
03332 
03333         if ( plTranslateCursor( gin ) )
03334         {
03335             snprintf( tmpstring, 50, "%f %f", gin->wX, gin->wY );
03336             Tcl_SetResult( interp, tmpstring, TCL_VOLATILE );
03337             return TCL_OK;
03338         }
03339 
03340         Tcl_SetResult( interp, "Cannot locate", TCL_STATIC );
03341         return TCL_OK;
03342     }
03343 
03344     Tcl_SetResult( interp, "nonsensical request.", TCL_STATIC );
03345     return TCL_ERROR;
03346 }
03347 
03348 //--------------------------------------------------------------------------
03349 // Custom bop handler.
03350 // Mostly for support of multi-page Tcl scripts from plserver.
03351 //--------------------------------------------------------------------------
03352 
03353 static void
03354 process_bop( void *clientData, int * PL_UNUSED( skip_driver_bop ) )
03355 {
03356     register PlFrame *plFramePtr = (PlFrame *) clientData;
03357 
03358     if ( Tcl_Eval( plFramePtr->interp, plFramePtr->bopCmd ) != TCL_OK )
03359         fprintf( stderr, "Command \"%s\" failed:\n\t %s\n",
03360             plFramePtr->bopCmd, Tcl_GetStringResult( plFramePtr->interp ) );
03361 }
03362 
03363 //--------------------------------------------------------------------------
03364 // Custom eop handler.
03365 // Mostly for support of multi-page Tcl scripts from plserver.
03366 //--------------------------------------------------------------------------
03367 
03368 static void
03369 process_eop( void *clientData, int * PL_UNUSED( skip_driver_eop ) )
03370 {
03371     register PlFrame *plFramePtr = (PlFrame *) clientData;
03372 
03373     if ( Tcl_Eval( plFramePtr->interp, plFramePtr->eopCmd ) != TCL_OK )
03374         fprintf( stderr, "Command \"%s\" failed:\n\t %s\n",
03375             plFramePtr->eopCmd, Tcl_GetStringResult( plFramePtr->interp ) );
03376 }
03377 
03378 //--------------------------------------------------------------------------
03379 // Utility routines
03380 //--------------------------------------------------------------------------
03381 
03382 //--------------------------------------------------------------------------
03383 // UpdateVScrollbar
03384 //
03385 // Updates vertical scrollbar if needed.
03386 //--------------------------------------------------------------------------
03387 
03388 static void
03389 UpdateVScrollbar( register PlFrame *plFramePtr )
03390 {
03391     int  height = Tk_Height( plFramePtr->tkwin );
03392     char string[60];
03393     int  totalUnits, windowUnits, firstUnit, lastUnit, result;
03394 
03395     if ( plFramePtr->yScrollCmd == NULL )
03396         return;
03397 
03398     totalUnits  = height;
03399     firstUnit   = (int) ( 0.5 + (PLFLT) height * ( 1. - plFramePtr->yr ) );
03400     lastUnit    = (int) ( 0.5 + (PLFLT) height * ( 1. - plFramePtr->yl ) );
03401     windowUnits = lastUnit - firstUnit;
03402     sprintf( string, " %d %d %d %d",
03403         totalUnits, windowUnits, firstUnit, lastUnit );
03404 
03405     result = Tcl_VarEval( plFramePtr->interp, plFramePtr->yScrollCmd, string,
03406         (char *) NULL );
03407 
03408     if ( result != TCL_OK )
03409     {
03410         Tk_BackgroundError( plFramePtr->interp );
03411     }
03412 }
03413 
03414 //--------------------------------------------------------------------------
03415 // UpdateHScrollbar
03416 //
03417 // Updates horizontal scrollbar if needed.
03418 //--------------------------------------------------------------------------
03419 
03420 static void
03421 UpdateHScrollbar( register PlFrame *plFramePtr )
03422 {
03423     int  width = Tk_Width( plFramePtr->tkwin );
03424     char string[60];
03425     int  totalUnits, windowUnits, firstUnit, lastUnit, result;
03426 
03427     if ( plFramePtr->xScrollCmd == NULL )
03428         return;
03429 
03430     totalUnits  = width;
03431     firstUnit   = (int) ( 0.5 + (PLFLT) width * plFramePtr->xl );
03432     lastUnit    = (int) ( 0.5 + (PLFLT) width * plFramePtr->xr );
03433     windowUnits = lastUnit - firstUnit;
03434     sprintf( string, " %d %d %d %d",
03435         totalUnits, windowUnits, firstUnit, lastUnit );
03436 
03437     result = Tcl_VarEval( plFramePtr->interp, plFramePtr->xScrollCmd, string,
03438         (char *) NULL );
03439 
03440     if ( result != TCL_OK )
03441     {
03442         Tk_BackgroundError( plFramePtr->interp );
03443     }
03444 }
03445 
03446 //--------------------------------------------------------------------------
03447 // gbox
03448 //
03449 // Returns selection box coordinates.  It's best if the TCL script does
03450 // bounds checking on the input but I do it here as well just to be safe.
03451 //--------------------------------------------------------------------------
03452 
03453 static void
03454 gbox( PLFLT *xl, PLFLT *yl, PLFLT *xr, PLFLT *yr, const char **argv )
03455 {
03456     PLFLT x0, y0, x1, y1;
03457 
03458     x0 = atof( argv[0] );
03459     y0 = atof( argv[1] );
03460     x1 = atof( argv[2] );
03461     y1 = atof( argv[3] );
03462 
03463     x0 = MAX( 0., MIN( 1., x0 ) );
03464     y0 = MAX( 0., MIN( 1., y0 ) );
03465     x1 = MAX( 0., MIN( 1., x1 ) );
03466     y1 = MAX( 0., MIN( 1., y1 ) );
03467 
03468 // Only need two vertices, pick the lower left and upper right
03469 
03470     *xl = MIN( x0, x1 );
03471     *yl = MIN( y0, y1 );
03472     *xr = MAX( x0, x1 );
03473     *yr = MAX( y0, y1 );
03474 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines