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