• Main Page
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

plplotter.c

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

Generated on Wed Oct 12 2011 20:42:22 for PLplot by  doxygen 1.7.1