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