PLplot
5.10.0
|
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