PLplot 5.15.0
Loading...
Searching...
No Matches
plframe.c
Go to the documentation of this file.
1// Copyright 1993, 1994, 1995
2// Maurice LeBrun mjl@dino.ph.utexas.edu
3// Institute for Fusion Studies University of Texas at Austin
4//
5// Copyright (C) 2004 Joao Cardoso
6// Copyright (C) 2004 Andrew Ross
7//
8// This file is part of PLplot.
9//
10// PLplot is free software; you can redistribute it and/or modify
11// it under the terms of the GNU Library General Public License as published
12// by the Free Software Foundation; either version 2 of the License, or
13// (at your option) any later version.
14//
15// PLplot is distributed in the hope that it will be useful,
16// but WITHOUT ANY WARRANTY; without even the implied warranty of
17// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18// GNU Library General Public License for more details.
19//
20// You should have received a copy of the GNU Library General Public License
21// along with PLplot; if not, write to the Free Software
22// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23//
24//
25// Based upon tkFrame.c from the TK 3.2 distribution:
26//
27// Copyright 1990 Regents of the University of California.
28// Permission to use, copy, modify, and distribute this
29// software and its documentation for any purpose and without
30// fee is hereby granted, provided that the above copyright
31// notice appear in all copies. The University of California
32// makes no representations about the suitability of this
33// software for any purpose. It is provided "as is" without
34// express or implied warranty.
35//
36//--------------------------------------------------------------------------
37//
38// This module implements "plframe" widgets for the Tk toolkit. These are
39// frames that have extra logic to allow them to be interfaced with the
40// PLplot X driver. These are then drawn into and respond to keyboard and
41// mouse events.
42//
43//
44// #define DEBUG_ENTER
45// #define DEBUG
46//
47
48#define DEBUGx
49
50#define NEED_PLDEBUG
51#include "plserver.h"
52#include "plxwd.h"
53#include "tcpip.h"
54
55#ifdef PL_HAVE_UNISTD_H
56#include <unistd.h>
57#endif
58#include <fcntl.h>
59
60#undef HAVE_ITCL
61
62#define NDEV 100 // Max number of output device types in menu
63
64// If set, BUFFER_FIFO causes FIFO i/o to be buffered
65
66#define BUFFER_FIFO 1
67
68// If set, causes a file handler to be used with FIFO
69
70#define FH_FIFO 0
71
72// A handy command wrapper
73
74#define plframe_cmd( code ) \
75 if ( ( code ) == TCL_ERROR ) return ( TCL_ERROR );
76
77// Backward compatibility junk
78
79#if TCL_MAJOR_VERSION <= 7 && TCL_MINOR_VERSION <= 4
80#define Tk_Cursor Cursor
81#endif
82
83//
84// A data structure of the following type is kept for each
85// plframe that currently exists for this process:
86//
87
88typedef struct
89{
90// This is stuff taken from tkFrame.c
91
92 Tk_Window tkwin; // Window that embodies the frame. NULL
93 // means that the window has been destroyed
94 // but the data structures haven't yet been
95 // cleaned up.
96 Display *display; // Display containing widget. Used, among
97 // other things, so that resources can be
98 // freed even after tkwin has gone away.
99 Tcl_Interp *interp; // Interpreter associated with
100 // widget. Used to delete widget
101 // command.
102#ifdef HAVE_ITCL
103 Tcl_Command widgetCmd; // Token for frame's widget command.
104#endif
105 Tk_3DBorder border; // Structure used to draw 3-D border and
106 // background.
107 int borderWidth; // Width of 3-D border (if any).
108 int relief; // 3-d effect: TK_RELIEF_RAISED etc.
109 int width; // Width to request for window. <= 0 means
110 // don't request any size.
111 int height; // Height to request for window. <= 0 means
112 // don't request any size.
113 Tk_Cursor cursor; // Current cursor for window, or None.
114 int flags; // Various flags; see below for
115 // definitions.
116
117// These are new to plframe widgets
118
119// control stuff
120
121 int tkwin_initted; // Set first time widget is mapped
122 PLStream *pls; // PLplot stream pointer
123 PLINT ipls; // PLplot stream number
124 PLINT ipls_save; // PLplot stream number, save files
125
126 PLRDev *plr; // Renderer state information. Malloc'ed
127 XColor *bgColor; // Background color
128 char *plpr_cmd; // Holds print command name. Malloc'ed
129
130// Used to handle resize and expose events
131
132 PLDisplay pldis; // Info about the display window
133 int prevWidth; // Previous window width
134 int prevHeight; // Previous window height
135
136// Support for save operations
137
138 char *SaveFnam; // File name we are currently saving to.
139 // Malloc'ed.
140 const char **devDesc; // Descriptive names for file-oriented
141 // devices. Malloc'ed.
142 const char **devName; // Keyword names of file-oriented devices.
143 // Malloc'ed.
144
145// Used in selecting & modifying plot or device area
146
147 GC xorGC; // GC used for rubber-band drawing
148 XPoint pts[5]; // Points for rubber-band drawing
149 int continue_draw; // Set when doing rubber-band draws
150 Tk_Cursor xhair_cursor; // cursor used for drawing
151 PLFLT xl, xr, yl, yr; // Bounds on plot viewing area
152 char *xScrollCmd; // Command prefix for communicating with
153 // horizontal scrollbar. NULL means no
154 // command to issue. Malloc'ed.
155 char *yScrollCmd; // Command prefix for communicating with
156 // vertical scrollbar. NULL means no
157 // command to issue. Malloc'ed.
158
159// Used for flashing bop or eop condition
160
161 char *bopCmd; // Proc to call at bop
162 char *eopCmd; // Proc to call at eop
163
164// Used for drawing graphic crosshairs
165
166 int xhairs; // Configuration option to turn on xhairs
167 int drawing_xhairs; // Set if we are currently drawing xhairs
168 XPoint xhair_x[2]; // Points for horizontal xhair line
169 XPoint xhair_y[2]; // Points for vertical xhair line
170
171// Used for drawing a rubber band lilne segment
172
173 int rband; // Configuration option to turn on rband
174 int drawing_rband; // See if we are currently drawing rband
175 XPoint rband_pt[2]; // Ends of rubber band line
176} PlFrame;
177
178//
179// Flag bits for plframes:
180//
181// REFRESH_PENDING: Non-zero means a DoWhenIdle handler
182// has already been queued to refresh
183// this window.
184// RESIZE_PENDING; Used to reschedule resize events
185// REDRAW_PENDING; Used to redraw contents of plot buffer
186// UPDATE_V_SCROLLBAR: Non-zero means vertical scrollbar needs
187// to be updated.
188// UPDATE_H_SCROLLBAR: Non-zero means horizontal scrollbar needs
189// to be updated.
190//
191
192#define REFRESH_PENDING 1
193#define RESIZE_PENDING 2
194#define REDRAW_PENDING 4
195#define UPDATE_V_SCROLLBAR 8
196#define UPDATE_H_SCROLLBAR 16
197
198// Defaults for plframes:
199
200#define DEF_PLFRAME_BG_COLOR "Black"
201#define DEF_PLFRAME_BG_MONO "White"
202#define DEF_PLFRAME_BORDER_WIDTH "0"
203#define DEF_PLFRAME_CURSOR ( (char *) NULL )
204#define DEF_PLFRAME_HEIGHT "0"
205#define DEF_PLFRAME_RELIEF "flat"
206#define DEF_PLFRAME_WIDTH "0"
207
208// Configuration info
209
210static Tk_ConfigSpec configSpecs[] = {
211 { TK_CONFIG_BORDER, "-background", "background", "Background",
212 DEF_PLFRAME_BG_COLOR, Tk_Offset( PlFrame, border ),
213 TK_CONFIG_COLOR_ONLY, NULL },
214//
215// {TK_CONFIG_COLOR, (char *) NULL, (char *) NULL, (char *) NULL,
216// (char *) NULL, Tk_Offset(PlFrame, bgColor),
217// TK_CONFIG_COLOR_ONLY},
218//
219#ifndef MAC_TCL
220 { TK_CONFIG_COLOR, "-plbg", "plbackground", "Plbackground",
221 DEF_PLFRAME_BG_COLOR, Tk_Offset( PlFrame, bgColor ),
222 TK_CONFIG_COLOR_ONLY, NULL },
223#endif
224 { TK_CONFIG_BORDER, "-background", "background", "Background",
225 DEF_PLFRAME_BG_MONO, Tk_Offset( PlFrame, border ),
226 TK_CONFIG_MONO_ONLY, NULL },
227//
228// {TK_CONFIG_COLOR, (char *) NULL, (char *) NULL, (char *) NULL,
229// (char *) NULL, Tk_Offset(PlFrame, bgColor),
230// TK_CONFIG_MONO_ONLY},
231//
232#ifndef MAC_TCL
233 { TK_CONFIG_COLOR, "-plbg", (char *) NULL, (char *) NULL,
234 DEF_PLFRAME_BG_MONO, Tk_Offset( PlFrame, bgColor ),
235 TK_CONFIG_MONO_ONLY, NULL },
236#endif
237 { TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL,
238 (char *) NULL, 0, 0, NULL },
239 { TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL,
240 (char *) NULL, 0, 0, NULL },
241 { TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
242 DEF_PLFRAME_BORDER_WIDTH, Tk_Offset( PlFrame, borderWidth ), 0, NULL },
243 { TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor",
244 DEF_PLFRAME_CURSOR, Tk_Offset( PlFrame, cursor ), TK_CONFIG_NULL_OK, NULL },
245 { TK_CONFIG_STRING, "-bopcmd", "bopcmd", "PgCommand",
246 (char *) NULL, Tk_Offset( PlFrame, bopCmd ), TK_CONFIG_NULL_OK, NULL },
247 { TK_CONFIG_STRING, "-eopcmd", "eopcmd", "PgCommand",
248 (char *) NULL, Tk_Offset( PlFrame, eopCmd ), TK_CONFIG_NULL_OK, NULL },
249 { TK_CONFIG_PIXELS, "-height", "height", "Height",
250 DEF_PLFRAME_HEIGHT, Tk_Offset( PlFrame, height ), 0, NULL },
251 { TK_CONFIG_RELIEF, "-relief", "relief", "Relief",
252 DEF_PLFRAME_RELIEF, Tk_Offset( PlFrame, relief ), 0, NULL },
253 { TK_CONFIG_PIXELS, "-width", "width", "Width",
254 DEF_PLFRAME_WIDTH, Tk_Offset( PlFrame, width ), 0, NULL },
255 { TK_CONFIG_BOOLEAN, "-xhairs", (char *) NULL, (char *) NULL,
256 "0", Tk_Offset( PlFrame, xhairs ), TK_CONFIG_DONT_SET_DEFAULT, NULL },
257 { TK_CONFIG_BOOLEAN, "-rubberband", (char *) NULL, (char *) NULL,
258 "0", Tk_Offset( PlFrame, rband ), TK_CONFIG_DONT_SET_DEFAULT, NULL },
259 { TK_CONFIG_STRING, "-xscrollcommand", "xScrollCommand", "ScrollCommand",
260 (char *) NULL, Tk_Offset( PlFrame, xScrollCmd ), TK_CONFIG_NULL_OK, NULL },
261 { TK_CONFIG_STRING, "-yscrollcommand", "yScrollCommand", "ScrollCommand",
262 (char *) NULL, Tk_Offset( PlFrame, yScrollCmd ), TK_CONFIG_NULL_OK, NULL },
263 { TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
264 (char *) NULL, 0, 0, NULL }
265};
266
267// Forward declarations for procedures defined later in this file:
268
269// Externals
270
271int plFrameCmd( ClientData, Tcl_Interp *, int, const char ** );
272
273// These are invoked by the TK dispatcher
274
275#if TK_MAJOR_VERSION < 4 || ( TK_MAJOR_VERSION == 4 && TK_MINOR_VERSION == 0 )
276#define FreeProcArg ClientData
277#else
278#define FreeProcArg char *
279#endif
280
281static void DestroyPlFrame( FreeProcArg );
282static void DisplayPlFrame( ClientData );
283static void PlFrameInit( ClientData );
284static void PlFrameConfigureEH( ClientData, XEvent * );
285static void PlFrameExposeEH( ClientData, XEvent * );
286static void PlFrameMotionEH( ClientData, register XEvent * );
287static void PlFrameEnterEH( ClientData, register XEvent * );
288static void PlFrameLeaveEH( ClientData, register XEvent * );
289static void PlFrameKeyEH( ClientData, register XEvent * );
290static int PlFrameWidgetCmd( ClientData, Tcl_Interp *, int, const char ** );
291static int ReadData( ClientData, int );
292static void Install_cmap( PlFrame *plFramePtr );
293
294// These are invoked by PlFrameWidgetCmd to process widget commands
295
296static int Closelink( Tcl_Interp *, PlFrame *, int, const char ** );
297static int Cmd( Tcl_Interp *, PlFrame *, int, const char ** );
298static int ColorManip( Tcl_Interp *, PlFrame *, int, const char ** );
299static int ConfigurePlFrame( Tcl_Interp *, PlFrame *, int, const char **, int );
300static int Draw( Tcl_Interp *, PlFrame *, int, const char ** );
301static int Info( Tcl_Interp *, PlFrame *, int, const char ** );
302static int Openlink( Tcl_Interp *, PlFrame *, int, const char ** );
303static int Orient( Tcl_Interp *, PlFrame *, int, const char ** );
304static int Page( Tcl_Interp *, PlFrame *, int, const char ** );
305static int Print( Tcl_Interp *, PlFrame *, int, const char ** );
306static int Redraw( Tcl_Interp *, PlFrame *, int, const char ** );
307static int Save( Tcl_Interp *, PlFrame *, int, const char ** );
308static int View( Tcl_Interp *, PlFrame *, int, const char ** );
309static int xScroll( Tcl_Interp *, PlFrame *, int, const char ** );
310static int yScroll( Tcl_Interp *, PlFrame *, int, const char ** );
311static int report( Tcl_Interp *, PlFrame *, int, const char ** );
312
313// Routines for manipulating graphic crosshairs
314
315static void CreateXhairs( PlFrame * );
316static void DestroyXhairs( PlFrame * );
317static void DrawXhairs( PlFrame *, int, int );
318static void UpdateXhairs( PlFrame * );
319
320// Routines for manipulating the rubberband line
321
322static void CreateRband( PlFrame * );
323static void DestroyRband( PlFrame * );
324static void DrawRband( PlFrame *, int, int );
325static void UpdateRband( PlFrame * );
326
327// Callbacks from plplot library
328
329static void process_bop( void *, int * );
330static void process_eop( void *, int * );
331
332// Utility routines
333
334static void gbox( PLFLT *, PLFLT *, PLFLT *, PLFLT *, const char ** );
335static void UpdateVScrollbar( register PlFrame * );
336static void UpdateHScrollbar( register PlFrame * );
337
338//
339//--------------------------------------------------------------------------
340//
341// plFrameCmd --
342//
343// This procedure is invoked to process the "plframe" Tcl
344// command. See the user documentation for details on what it
345// does.
346//
347// Results:
348// A standard Tcl result.
349//
350// Side effects:
351// See the user documentation.
352//
353//--------------------------------------------------------------------------
354//
355
356int
357plFrameCmd( ClientData PL_UNUSED( clientData ), Tcl_Interp *interp,
358 int argc, const char **argv )
359{
360 Tk_Window new;
361 register PlFrame *plFramePtr;
362 register PLRDev *plr;
363 int i, ndev;
364
365 dbug_enter( "plFrameCmd" );
366
367 if ( argc < 2 )
368 {
369 Tcl_AppendResult( interp, "wrong # args: should be \"",
370 argv[0], " pathName ?options?\"", (char *) NULL );
371 return TCL_ERROR;
372 }
373
374// Create the window.
375
376 new = Tk_CreateWindowFromPath( interp, Tk_MainWindow( interp ),
377 argv[1], (char *) NULL );
378 if ( new == NULL )
379 {
380 return TCL_ERROR;
381 }
382
383 plFramePtr = (PlFrame *) ckalloc( sizeof ( PlFrame ) );
384
385 // Initialize in the same order as the members of the struct just
386 // to keep track of what is initialized and what not.
387
388 plFramePtr->tkwin = new;
389 plFramePtr->display = Tk_Display( new );
390 plFramePtr->interp = interp;
391 //plFramePtr->widgetCMD = <initialized below for HAVE_ITCL case>
392 plFramePtr->border = NULL;
393 //plFramePtr->borderWidth = <uninitialized>
394 //plFramePtr->relief = <uninitialized>
395 plFramePtr->width = Tk_Width( plFramePtr->tkwin );
396 plFramePtr->height = Tk_Height( plFramePtr->tkwin );
397 plFramePtr->cursor = None;
398 plFramePtr->flags = 0;
399 plFramePtr->tkwin_initted = 0;
400 // Associate new PLplot stream with this widget
401 plmkstrm( &plFramePtr->ipls );
402 plgpls( &plFramePtr->pls );
403 plFramePtr->ipls_save = 0;
404 plFramePtr->plr = (PLRDev *) ckalloc( sizeof ( PLRDev ) );
405 plFramePtr->bgColor = NULL;
406 plFramePtr->plpr_cmd = NULL;
407 plFramePtr->pldis.x = 0;
408 plFramePtr->pldis.y = 0;
409 plFramePtr->pldis.width = 0;
410 plFramePtr->pldis.height = 0;
411 plFramePtr->prevWidth = 0;
412 plFramePtr->prevHeight = 0;
413 plFramePtr->SaveFnam = NULL;
414 // plFramePtr->devDesc = <uninitialized, to be malloced?>;
415 // plFramePtr->devName = <uninitialized, to be malloced?>;
416 plFramePtr->xorGC = NULL;
417 // plFram Ptr->pts = <uninitialized array>;
418 plFramePtr->continue_draw = 0;
419 plFramePtr->xhair_cursor = None;
420 plFramePtr->xl = 0.;
421 plFramePtr->yl = 0.;
422 plFramePtr->xr = 1.;
423 plFramePtr->yr = 1.;
424 plFramePtr->xScrollCmd = NULL;
425 plFramePtr->yScrollCmd = NULL;
426 plFramePtr->bopCmd = NULL;
427 plFramePtr->eopCmd = NULL;
428 plFramePtr->xhairs = 0;
429 plFramePtr->drawing_xhairs = 0;
430 // plFram Ptr->xhair_x = <uninitialized array>;
431 // plFram Ptr->xhair_y = <uninitialized array>;
432 plFramePtr->rband = 0;
433 plFramePtr->drawing_rband = 0;
434 // plFram Ptr->rband_pt = <uninitialized array>;
435
436 plr = plFramePtr->plr;
437 plr->pdfs = NULL;
438 plr->at_bop = 0;
439 plr->at_eop = 0;
440 plr->iodev = (PLiodev *) ckalloc( sizeof ( PLiodev ) );
441 plr_start( plr );
442
443// Set up stuff for rubber-band drawing
444
445 plFramePtr->xhair_cursor =
446 Tk_GetCursor( plFramePtr->interp, plFramePtr->tkwin, "crosshair" );
447
448// Partially initialize X driver.
449
450 pllib_init();
451
452 plsdev( "xwin" );
454 plP_esc( PLESC_DEVINIT, NULL );
455
456// Create list of valid device names and keywords for page dumps
457
458 plFramePtr->devDesc = (const char **) ckalloc( NDEV * sizeof ( char ** ) );
459 plFramePtr->devName = (const char **) ckalloc( NDEV * sizeof ( char ** ) );
460 for ( i = 0; i < NDEV; i++ )
461 {
462 plFramePtr->devDesc[i] = NULL;
463 plFramePtr->devName[i] = NULL;
464 }
465 ndev = NDEV;
466 plgFileDevs( &plFramePtr->devDesc, &plFramePtr->devName, &ndev );
467
468// Start up event handlers and other good stuff
469
470 Tk_SetClass( plFramePtr->tkwin, "Plframe" );
471
472 Tk_CreateEventHandler( plFramePtr->tkwin, StructureNotifyMask,
473 PlFrameConfigureEH, (ClientData) plFramePtr );
474
475 Tk_CreateEventHandler( plFramePtr->tkwin, ExposureMask,
476 PlFrameExposeEH, (ClientData) plFramePtr );
477
478#ifdef HAVE_ITCL
479 plFramePtr->widgetCmd =
480#endif
481 Tcl_CreateCommand( interp, Tk_PathName( plFramePtr->tkwin ),
482 (Tcl_CmdProc *) PlFrameWidgetCmd, (ClientData) plFramePtr, (Tcl_CmdDeleteProc *) NULL );
483#ifdef HAVE_ITCL
484 Itk_SetWidgetCommand( plFramePtr->tkwin, plFramePtr->widgetCmd );
485#endif
486
487 if ( ConfigurePlFrame( interp, plFramePtr, argc - 2, argv + 2, 0 ) != TCL_OK )
488 {
489#ifdef HAVE_ITCL
490 Itk_SetWidgetCommand( plFramePtr->tkwin, (Tcl_Command) NULL );
491#endif
492 Tk_DestroyWindow( plFramePtr->tkwin );
493 return TCL_ERROR;
494 }
495 Tcl_SetResult( interp, Tk_PathName( plFramePtr->tkwin ), TCL_VOLATILE );
496
497 return TCL_OK;
498}
499
500//
501//--------------------------------------------------------------------------
502//
503// PlFrameWidgetCmd --
504//
505// This procedure is invoked to process the Tcl command that
506// corresponds to a plframe widget. See the user
507// documentation for details on what it does.
508//
509// Results:
510// A standard Tcl result.
511//
512// Side effects:
513// See the user documentation.
514//
515//--------------------------------------------------------------------------
516//
517
518static int
519PlFrameWidgetCmd( ClientData clientData, Tcl_Interp *interp,
520 int argc, const char **argv )
521{
522 register PlFrame *plFramePtr = (PlFrame *) clientData;
523 int result = TCL_OK;
524 int length;
525 char c;
526 char res[20];
527
528 dbug_enter( "PlFrameWidgetCmd" );
529
530#ifdef DEBUG
531 {
532 int i;
533 PLStream *pls;
534 plgpls( pls );
535 printf( "Current stream %d, frame stream %d\n",
536 pls->ipls, plFramePtr->ipls );
537 printf( "PlFrameWidgetCmd: " );
538 for ( i = 0; i < argc; i++ )
539 printf( " %s", argv[i] );
540 printf( "\n" );
541 }
542#endif
543
544 if ( argc < 2 )
545 {
546 Tcl_AppendResult( interp, "wrong # args: should be \"",
547 argv[0], " option ?arg arg ...?\"", (char *) NULL );
548 return TCL_ERROR;
549 }
550 Tk_Preserve( (ClientData) plFramePtr );
551 c = argv[1][0];
552 length = (int) strlen( argv[1] );
553
554// First, before anything else, we have to set the stream to be the one that
555// corresponds to this widget.
556 plsstrm( plFramePtr->ipls );
557
558// cmd -- issue a command to the PLplot library
559
560 if ( ( c == 'c' ) && ( strncmp( argv[1], "cmd", (size_t) length ) == 0 ) )
561 {
562 result = Cmd( interp, plFramePtr, argc - 2, argv + 2 );
563 }
564
565// cget
566
567 else if ( ( c == 'c' ) && ( strncmp( argv[1], "cget", (size_t) length ) == 0 ) )
568 {
569 if ( argc > 2 )
570 {
571 Tcl_AppendResult( interp, "wrong # args: should be \"",
572 argv[0], " cget <option>\"", (char *) NULL );
573 result = TCL_ERROR;
574 goto done;
575 }
576 else
577 {
578 result = Tk_ConfigureInfo( interp, plFramePtr->tkwin, configSpecs,
579 (char *) plFramePtr, (char *) NULL, 0 );
580 }
581 }
582
583// configure
584
585 else if ( ( c == 'c' ) && ( strncmp( argv[1], "configure", (size_t) length ) == 0 ) )
586 {
587 if ( argc == 2 )
588 {
589 result = Tk_ConfigureInfo( interp, plFramePtr->tkwin, configSpecs,
590 (char *) plFramePtr, (char *) NULL, 0 );
591 }
592 else if ( argc == 3 )
593 {
594 result = Tk_ConfigureInfo( interp, plFramePtr->tkwin, configSpecs,
595 (char *) plFramePtr, argv[2], 0 );
596 }
597 else
598 {
599 result = ConfigurePlFrame( interp, plFramePtr, argc - 2, argv + 2,
600 TK_CONFIG_ARGV_ONLY );
601 }
602 }
603
604// double buffering
605
606 else if ( ( c == 'd' ) &&
607 ( ( strncmp( argv[1], "db", (size_t) length ) == 0 ) ||
608 ( strncmp( argv[1], "doublebuffering", (size_t) length == 0 ) ) ) )
609 {
610 PLBufferingCB bcb;
611
612 if ( argc == 3 )
613 {
614 if ( strcmp( argv[2], "on" ) == 0 )
615 {
618 }
619 if ( strcmp( argv[2], "off" ) == 0 )
620 {
623 }
624 if ( strcmp( argv[2], "query" ) == 0 )
625 {
628 snprintf( res, 20, "%d", bcb.result );
629 Tcl_SetResult( interp, res, TCL_VOLATILE );
630 }
631 }
632
633 result = TCL_OK;
634 }
635
636// closelink -- Close a binary data link previously opened with openlink
637
638 else if ( ( c == 'c' ) && ( strncmp( argv[1], "closelink", (size_t) length ) == 0 ) )
639 {
640 if ( argc > 2 )
641 {
642 Tcl_AppendResult( interp, "wrong # args: should be \"",
643 argv[0], (char *) NULL );
644 result = TCL_ERROR;
645 goto done;
646 }
647 else
648 {
649 result = Closelink( interp, plFramePtr, argc - 2, argv + 2 );
650 }
651 }
652
653// draw -- rubber-band draw used in region selection
654
655 else if ( ( c == 'd' ) && ( strncmp( argv[1], "draw", (size_t) length ) == 0 ) )
656 {
657 if ( argc == 2 )
658 {
659 Tcl_AppendResult( interp, "wrong # args: should be \"",
660 argv[0], " draw op ?options?\"", (char *) NULL );
661 result = TCL_ERROR;
662 goto done;
663 }
664 else
665 {
666 result = Draw( interp, plFramePtr, argc - 2, argv + 2 );
667 }
668 }
669
670// color-manipulating commands, grouped together for convenience
671
672 else if ( ( ( c == 'g' ) && ( ( strncmp( argv[1], "gcmap0", (size_t) length ) == 0 ) ||
673 ( strncmp( argv[1], "gcmap1", (size_t) length ) == 0 ) ) ) ||
674 ( ( c == 's' ) && ( ( strncmp( argv[1], "scmap0", (size_t) length ) == 0 ) ||
675 ( strncmp( argv[1], "scmap1", (size_t) length ) == 0 ) ||
676 ( strncmp( argv[1], "scol0", (size_t) length ) == 0 ) ||
677 ( strncmp( argv[1], "scol1", (size_t) length ) == 0 ) ) ) )
678 result = ColorManip( interp, plFramePtr, argc - 1, argv + 1 );
679
680// info -- returns requested info
681
682 else if ( ( c == 'i' ) && ( strncmp( argv[1], "info", (size_t) length ) == 0 ) )
683 {
684 result = Info( interp, plFramePtr, argc - 2, argv + 2 );
685 }
686
687// orient -- Set plot orientation
688
689 else if ( ( c == 'o' ) && ( strncmp( argv[1], "orient", (size_t) length ) == 0 ) )
690 {
691 result = Orient( interp, plFramePtr, argc - 2, argv + 2 );
692 }
693
694// openlink -- Open a binary data link (FIFO or socket)
695
696 else if ( ( c == 'o' ) && ( strncmp( argv[1], "openlink", (size_t) length ) == 0 ) )
697 {
698 if ( argc < 3 )
699 {
700 Tcl_AppendResult( interp, "wrong # args: should be \"",
701 argv[0], " option ?arg arg ...?\"", (char *) NULL );
702 result = TCL_ERROR;
703 goto done;
704 }
705 else
706 {
707 result = Openlink( interp, plFramePtr, argc - 2, argv + 2 );
708 }
709 }
710
711// page -- change or return output page setup
712
713 else if ( ( c == 'p' ) && ( strncmp( argv[1], "page", (size_t) length ) == 0 ) )
714 {
715 result = Page( interp, plFramePtr, argc - 2, argv + 2 );
716 }
717
718// print -- prints plot
719
720 else if ( ( c == 'p' ) && ( strncmp( argv[1], "print", (size_t) length ) == 0 ) )
721 {
722 result = Print( interp, plFramePtr, argc - 2, argv + 2 );
723 }
724
725// redraw -- redraw plot
726
727 else if ( ( c == 'r' ) && ( strncmp( argv[1], "redraw", (size_t) length ) == 0 ) )
728 {
729 if ( argc > 2 )
730 {
731 Tcl_AppendResult( interp, "wrong # args: should be \"",
732 argv[0], " redraw\"", (char *) NULL );
733 result = TCL_ERROR;
734 goto done;
735 }
736 else
737 {
738 result = Redraw( interp, plFramePtr, argc - 2, argv + 2 );
739 }
740 }
741
742// report -- find out useful info about the plframe (GMF)
743
744 else if ( ( c == 'r' ) && ( strncmp( argv[1], "report", (size_t) length ) == 0 ) )
745 {
746 result = report( interp, plFramePtr, argc - 2, argv + 2 );
747 }
748
749// save -- saves plot to the specified plot file type
750
751 else if ( ( c == 's' ) && ( strncmp( argv[1], "save", (size_t) length ) == 0 ) )
752 {
753 result = Save( interp, plFramePtr, argc - 2, argv + 2 );
754 }
755
756// view -- change or return window into plot
757
758 else if ( ( c == 'v' ) && ( strncmp( argv[1], "view", (size_t) length ) == 0 ) )
759 {
760 result = View( interp, plFramePtr, argc - 2, argv + 2 );
761 }
762
763// xscroll -- horizontally scroll window into plot
764
765 else if ( ( c == 'x' ) && ( strncmp( argv[1], "xscroll", (size_t) length ) == 0 ) )
766 {
767 if ( argc == 2 || argc > 3 )
768 {
769 Tcl_AppendResult( interp, "wrong # args: should be \"",
770 argv[0], " xscroll pixel\"", (char *) NULL );
771 result = TCL_ERROR;
772 goto done;
773 }
774 else
775 {
776 result = xScroll( interp, plFramePtr, argc - 2, argv + 2 );
777 }
778 }
779
780// yscroll -- vertically scroll window into plot
781
782 else if ( ( c == 'y' ) && ( strncmp( argv[1], "yscroll", (size_t) length ) == 0 ) )
783 {
784 if ( argc == 2 || argc > 3 )
785 {
786 Tcl_AppendResult( interp, "wrong # args: should be \"",
787 argv[0], " yscroll pixel\"", (char *) NULL );
788 result = TCL_ERROR;
789 goto done;
790 }
791 else
792 {
793 result = yScroll( interp, plFramePtr, argc - 2, argv + 2 );
794 }
795 }
796
797// unrecognized widget command
798
799 else
800 {
801 Tcl_AppendResult( interp, "bad option \"", argv[1],
802 "\": must be closelink, cmd, configure, draw, ",
803 "gcmap0, gcmap1, ",
804 "info, openlink, orient, page, print, redraw, save, ",
805 "scmap0, scmap1, scol0, scol1, ",
806 "view, xscroll, or yscroll", (char *) NULL );
807
808 result = TCL_ERROR;
809#ifdef DEBUG
810 printf( "bad option!\n" );
811#endif
812 }
813
814#ifdef DEBUG
815 printf( "result=%d current stream=%d\n", result, plsc->ipls );
816#endif
817
818done:
819 Tk_Release( (ClientData) plFramePtr );
820 return result;
821}
822
823//
824//--------------------------------------------------------------------------
825//
826// DestroyPlFrame --
827//
828// This procedure is invoked by Tk_EventuallyFree or Tk_Release to
829// clean up the internal structure of a plframe at a safe time
830// (when no-one is using it anymore).
831//
832// Results:
833// None.
834//
835// Side effects:
836// Everything associated with the plframe is freed up.
837//
838//--------------------------------------------------------------------------
839//
840
841static void
843{
844 register PlFrame *plFramePtr = (PlFrame *) clientData;
845 register PLRDev *plr = plFramePtr->plr;
846
847 dbug_enter( "DestroyPlFrame" );
848
849 if ( plFramePtr->border != NULL )
850 {
851 Tk_Free3DBorder( plFramePtr->border );
852 }
853 if ( plFramePtr->bgColor != NULL )
854 {
855 Tk_FreeColor( plFramePtr->bgColor );
856 }
857 if ( plFramePtr->plpr_cmd != NULL )
858 {
859 ckfree( (char *) plFramePtr->plpr_cmd );
860 }
861 if ( plFramePtr->cursor != None )
862 {
863 Tk_FreeCursor( plFramePtr->display, plFramePtr->cursor );
864 }
865 if ( plFramePtr->xhair_cursor != None )
866 {
867 Tk_FreeCursor( plFramePtr->display, plFramePtr->xhair_cursor );
868 }
869 if ( plFramePtr->xorGC != NULL )
870 {
871 Tk_FreeGC( plFramePtr->display, plFramePtr->xorGC );
872 }
873 if ( plFramePtr->yScrollCmd != NULL )
874 {
875 ckfree( (char *) plFramePtr->yScrollCmd );
876 }
877 if ( plFramePtr->xScrollCmd != NULL )
878 {
879 ckfree( (char *) plFramePtr->xScrollCmd );
880 }
881 if ( plFramePtr->SaveFnam != NULL )
882 {
883 ckfree( (char *) plFramePtr->SaveFnam );
884 }
885 if ( plFramePtr->devDesc != NULL )
886 {
887 ckfree( (char *) plFramePtr->devDesc );
888 }
889 if ( plFramePtr->devName != NULL )
890 {
891 ckfree( (char *) plFramePtr->devName );
892 }
893
894// Clean up data connection
895
896 pdf_close( plr->pdfs );
897 ckfree( (char *) plFramePtr->plr->iodev );
898
899// Tell PLplot to clean up
900
901 plsstrm( plFramePtr->ipls );
902 plend1();
903
904// Delete main data structures
905
906 ckfree( (char *) plFramePtr->plr );
907 ckfree( (char *) plFramePtr );
908}
909
910//
911//--------------------------------------------------------------------------
912//
913// PlFrameConfigureEH --
914//
915// Invoked by the Tk dispatcher on structure changes to a plframe.
916//
917// Results:
918// None.
919//
920// Side effects:
921// When the window gets deleted, internal structures get cleaned up.
922// When it gets resized, it is redrawn.
923//
924//--------------------------------------------------------------------------
925//
926
927static void
928PlFrameConfigureEH( ClientData clientData, register XEvent *eventPtr )
929{
930 register PlFrame *plFramePtr = (PlFrame *) clientData;
931 register Tk_Window tkwin = plFramePtr->tkwin;
932
933 dbug_enter( "PlFrameConfigureEH" );
934
935 switch ( eventPtr->type )
936 {
937 case ConfigureNotify:
938 pldebug( "PLFrameConfigureEH", "ConfigureNotify\n" );
939 plFramePtr->flags |= RESIZE_PENDING;
940 plFramePtr->width = Tk_Width( tkwin );
941 plFramePtr->height = Tk_Height( tkwin );
942 if ( ( tkwin != NULL ) && !( plFramePtr->flags & REFRESH_PENDING ) )
943 {
944 Tk_DoWhenIdle( DisplayPlFrame, (ClientData) plFramePtr );
945 plFramePtr->flags |= REFRESH_PENDING;
946 plFramePtr->flags |= UPDATE_V_SCROLLBAR | UPDATE_H_SCROLLBAR;
947 }
948 break;
949
950 case DestroyNotify:
951 pldebug( "PLFrameConfigureEH", "DestroyNotify\n" );
952#ifdef HAVE_ITCL
953 Itk_SetWidgetCommand( plFramePtr->tkwin, (Tcl_Command) NULL );
954 Tcl_DeleteCommand2( plFramePtr->interp, plFramePtr->widgetCmd );
955#else
956 Tcl_DeleteCommand( plFramePtr->interp, Tk_PathName( tkwin ) );
957#endif
958 plFramePtr->tkwin = NULL;
959 if ( plFramePtr->flags & REFRESH_PENDING )
960 {
961 Tk_CancelIdleCall( DisplayPlFrame, (ClientData) plFramePtr );
962 }
963 Tk_EventuallyFree( (ClientData) plFramePtr, DestroyPlFrame );
964 break;
965
966 case MapNotify:
967 pldebug( "PLFrameConfigureEH", "MapNotify\n" );
968 if ( plFramePtr->flags & REFRESH_PENDING )
969 {
970 Tk_CancelIdleCall( DisplayPlFrame, (ClientData) plFramePtr );
971 }
972
973 // For some reason, "." must be mapped or PlFrameInit will die (Note:
974 // mapped & withdrawn or mapped in the withdrawn state is OK). Issuing
975 // an update fixes this. I'd love to know why this occurs.
976 //
977
978 if ( !plFramePtr->tkwin_initted )
979 {
980 Tcl_VarEval( plFramePtr->interp, "update", (char *) NULL );
981 }
982 Tk_DoWhenIdle( PlFrameInit, (ClientData) plFramePtr );
983 break;
984 }
985}
986
987//
988//--------------------------------------------------------------------------
989//
990// PlFrameExposeEH --
991//
992// Invoked by the Tk dispatcher on exposes of a plframe.
993//
994// Results:
995// None.
996//
997// Side effects:
998// Widget is redisplayed.
999//
1000// Note: it's customary in Tk to collapse multiple exposes, so for best
1001// performance without losing the window contents, I keep track of the
1002// smallest single rectangle that can satisfy all expose events. If there
1003// are any overlaid graphics (like crosshairs), however, we need to refresh
1004// the entire plot in order to have a predictable outcome.
1005//
1006//--------------------------------------------------------------------------
1007
1008static void
1009PlFrameExposeEH( ClientData clientData, register XEvent *eventPtr )
1010{
1011 register PlFrame *plFramePtr = (PlFrame *) clientData;
1012 XExposeEvent *event = (XExposeEvent *) eventPtr;
1013 register Tk_Window tkwin = plFramePtr->tkwin;
1014
1015 dbug_enter( "PlFrameExposeEH" );
1016
1017 pldebug( "PLFrameExposeEH", "Expose\n" );
1018
1019// Set up the area to refresh
1020
1021 if ( !( plFramePtr->drawing_xhairs || plFramePtr->drawing_rband ) )
1022 {
1023 int x0_old, x1_old, y0_old, y1_old, x0_new, x1_new, y0_new, y1_new;
1024
1025 x0_old = (int) plFramePtr->pldis.x;
1026 y0_old = (int) plFramePtr->pldis.y;
1027 x1_old = x0_old + (int) plFramePtr->pldis.width;
1028 y1_old = y0_old + (int) plFramePtr->pldis.height;
1029
1030 x0_new = event->x;
1031 y0_new = event->y;
1032 x1_new = x0_new + event->width;
1033 y1_new = y0_new + event->height;
1034
1035 plFramePtr->pldis.x = (unsigned int) MIN( x0_old, x0_new );
1036 plFramePtr->pldis.y = (unsigned int) MIN( y0_old, y0_new );
1037 plFramePtr->pldis.width = (unsigned int) MAX( x1_old, x1_new ) - plFramePtr->pldis.x;
1038 plFramePtr->pldis.height = (unsigned int) MAX( y1_old, y1_new ) - plFramePtr->pldis.y;
1039 }
1040
1041// Invoke DoWhenIdle handler to redisplay widget.
1042
1043 if ( event->count == 0 )
1044 {
1045 if ( ( tkwin != NULL ) && !( plFramePtr->flags & REFRESH_PENDING ) )
1046 {
1047 Tk_DoWhenIdle( DisplayPlFrame, (ClientData) plFramePtr );
1048 plFramePtr->width = Tk_Width( tkwin );
1049 plFramePtr->height = Tk_Height( tkwin );
1050 plFramePtr->flags |= REFRESH_PENDING;
1051 }
1052 }
1053}
1054
1055//
1056//--------------------------------------------------------------------------
1057//
1058// PlFrameMotionEH --
1059//
1060// Invoked by the Tk dispatcher on MotionNotify events in a plframe.
1061// Not invoked unless we are drawing graphic crosshairs.
1062//
1063// Results:
1064// None.
1065//
1066// Side effects:
1067// Graphic crosshairs are drawn.
1068//
1069//--------------------------------------------------------------------------
1070//
1071
1072static void
1073PlFrameMotionEH( ClientData clientData, register XEvent *eventPtr )
1074{
1075 register PlFrame *plFramePtr = (PlFrame *) clientData;
1076 XMotionEvent *event = (XMotionEvent *) eventPtr;
1077
1078 dbug_enter( "PlFrameMotionEH" );
1079
1080 if ( plFramePtr->drawing_xhairs )
1081 {
1082 DrawXhairs( plFramePtr, event->x, event->y );
1083 }
1084 if ( plFramePtr->drawing_rband )
1085 {
1086 DrawRband( plFramePtr, event->x, event->y );
1087 }
1088}
1089
1090//
1091//--------------------------------------------------------------------------
1092//
1093// PlFrameEnterEH --
1094//
1095// Invoked by the Tk dispatcher on EnterNotify events in a plframe.
1096// Not invoked unless we are drawing graphic crosshairs.
1097//
1098// Results:
1099// None.
1100//
1101// Side effects:
1102// Graphic crosshairs are updated.
1103//
1104//--------------------------------------------------------------------------
1105
1106static void
1107PlFrameEnterEH( ClientData clientData, register XEvent *eventPtr )
1108{
1109 register PlFrame *plFramePtr = (PlFrame *) clientData;
1110 XCrossingEvent *crossingEvent = (XCrossingEvent *) eventPtr;
1111
1112 dbug_enter( "PlFrameEnterEH" );
1113
1114 if ( plFramePtr->xhairs )
1115 {
1116 DrawXhairs( plFramePtr, crossingEvent->x, crossingEvent->y );
1117 plFramePtr->drawing_xhairs = 1;
1118 }
1119 if ( plFramePtr->rband )
1120 {
1121 plFramePtr->drawing_rband = 1;
1122 UpdateRband( plFramePtr );
1123 DrawRband( plFramePtr, crossingEvent->x, crossingEvent->y );
1124 }
1125}
1126
1127//
1128//--------------------------------------------------------------------------
1129//
1130// PlFrameLeaveEH --
1131//
1132// Invoked by the Tk dispatcher on LeaveNotify events in a plframe.
1133// Not invoked unless we are drawing graphic crosshairs.
1134//
1135// Results:
1136// None.
1137//
1138// Side effects:
1139// Graphic crosshairs are updated.
1140//
1141//--------------------------------------------------------------------------
1142
1143static void
1144PlFrameLeaveEH( ClientData clientData, register XEvent * PL_UNUSED( eventPtr ) )
1145{
1146 register PlFrame *plFramePtr = (PlFrame *) clientData;
1147
1148 dbug_enter( "PlFrameLeaveEH" );
1149
1150 if ( plFramePtr->drawing_xhairs )
1151 {
1152 UpdateXhairs( plFramePtr );
1153 plFramePtr->drawing_xhairs = 0;
1154 }
1155 if ( plFramePtr->drawing_rband )
1156 {
1157 UpdateRband( plFramePtr );
1158 plFramePtr->drawing_rband = 0;
1159 }
1160}
1161
1162//
1163//--------------------------------------------------------------------------
1164//
1165// PlFrameKeyEH --
1166//
1167// Invoked by the Tk dispatcher on Keypress events in a plframe.
1168// Not invoked unless we are drawing graphic crosshairs.
1169//
1170// Results:
1171// None.
1172//
1173// Side effects:
1174// Keypress events get filtered. If a cursor key is pushed, the
1175// graphic crosshairs are moved in the appropriate direction. Using a
1176// modifier key multiplies the movement a factor of 5 for each key
1177// added.
1178//
1179//--------------------------------------------------------------------------
1180//
1181
1182static void
1183PlFrameKeyEH( ClientData clientData, register XEvent *eventPtr )
1184{
1185 register PlFrame *plFramePtr = (PlFrame *) clientData;
1186 XKeyEvent *event = (XKeyEvent *) eventPtr;
1187 register Tk_Window tkwin = plFramePtr->tkwin;
1188
1189 KeySym keysym;
1190 int nchars;
1191 char string[11];
1192 XComposeStatus cs;
1193
1194 dbug_enter( "PlFrameKeyEH" );
1195
1196#if !defined ( _WIN32 )
1197 nchars = XLookupString( event, string, 10, &keysym, &cs );
1198#else
1199 nchars = 0;
1200#endif
1201 string[nchars] = '\0';
1202 pldebug( "PlFrameKeyEH", "Keysym %x, translation: %s\n", keysym, string );
1203
1204 if ( IsModifierKey( keysym ) )
1205 {
1206 eventPtr->type = 0;
1207 }
1208 else if ( IsCursorKey( keysym ) )
1209 {
1210 int x1, y1, dx = 0, dy = 0;
1211 int x0 = event->x, y0 = event->y;
1212 int xmin = 0, xmax = Tk_Width( tkwin ) - 1;
1213 int ymin = 0, ymax = Tk_Height( tkwin ) - 1;
1214
1215 switch ( keysym )
1216 {
1217 case XK_Left:
1218 dx = -1;
1219 break;
1220 case XK_Right:
1221 dx = 1;
1222 break;
1223 case XK_Up:
1224 dy = -1;
1225 break;
1226 case XK_Down:
1227 dy = 1;
1228 break;
1229 }
1230
1231 // Each modifier key added increases the multiplication factor by 5
1232
1233 // Shift
1234
1235 if ( event->state & 0x01 )
1236 {
1237 dx *= 5;
1238 dy *= 5;
1239 }
1240
1241 // Caps Lock
1242
1243 if ( event->state & 0x02 )
1244 {
1245 dx *= 5;
1246 dy *= 5;
1247 }
1248
1249 // Control
1250
1251 if ( event->state & 0x04 )
1252 {
1253 dx *= 5;
1254 dy *= 5;
1255 }
1256
1257 // Alt
1258
1259 if ( event->state & 0x08 )
1260 {
1261 dx *= 5;
1262 dy *= 5;
1263 }
1264
1265 // Bounds checking so that we don't send cursor out of window
1266
1267 x1 = x0 + dx;
1268 y1 = y0 + dy;
1269
1270 if ( x1 < xmin )
1271 dx = xmin - x0;
1272 if ( y1 < ymin )
1273 dy = ymin - y0;
1274 if ( x1 > xmax )
1275 dx = xmax - x0;
1276 if ( y1 > ymax )
1277 dy = ymax - y0;
1278
1279 // Engage...
1280
1281 XWarpPointer( plFramePtr->display, Tk_WindowId( tkwin ),
1282 None, 0, 0, 0, 0, dx, dy );
1283 eventPtr->type = 0;
1284 }
1285}
1286
1287//--------------------------------------------------------------------------
1288// CreateXhairs()
1289//
1290// Creates graphic crosshairs at current pointer location.
1291//--------------------------------------------------------------------------
1292
1293static void
1294CreateXhairs( PlFrame *plFramePtr )
1295{
1296 register Tk_Window tkwin = plFramePtr->tkwin;
1297 Window root, child;
1298 int root_x, root_y, win_x, win_y;
1299 unsigned int mask;
1300
1301// Switch to crosshair cursor.
1302
1303 Tk_DefineCursor( tkwin, plFramePtr->xhair_cursor );
1304
1305// Find current pointer location and draw graphic crosshairs if pointer is
1306// inside our window.
1307
1308 if ( XQueryPointer( plFramePtr->display, Tk_WindowId( tkwin ),
1309 &root, &child, &root_x, &root_y, &win_x, &win_y,
1310 &mask ) )
1311 {
1312 if ( win_x >= 0 && win_x < Tk_Width( tkwin ) &&
1313 win_y >= 0 && win_y < Tk_Height( tkwin ) )
1314 {
1315 DrawXhairs( plFramePtr, win_x, win_y );
1316 plFramePtr->drawing_xhairs = 1;
1317 }
1318 }
1319
1320// Catch PointerMotion and crossing events so we can update them properly
1321
1322 if ( !plFramePtr->drawing_rband )
1323 {
1324 Tk_CreateEventHandler( tkwin, PointerMotionMask,
1325 PlFrameMotionEH, (ClientData) plFramePtr );
1326
1327 Tk_CreateEventHandler( tkwin, EnterWindowMask,
1328 PlFrameEnterEH, (ClientData) plFramePtr );
1329
1330 Tk_CreateEventHandler( tkwin, LeaveWindowMask,
1331 PlFrameLeaveEH, (ClientData) plFramePtr );
1332 }
1333
1334// Catch KeyPress events so we can filter them
1335
1336 Tk_CreateEventHandler( tkwin, KeyPressMask,
1337 PlFrameKeyEH, (ClientData) plFramePtr );
1338}
1339
1340//--------------------------------------------------------------------------
1341// DestroyXhairs()
1342//
1343// Destroys graphic crosshairs.
1344//--------------------------------------------------------------------------
1345
1346static void
1348{
1349 register Tk_Window tkwin = plFramePtr->tkwin;
1350
1351// Switch back to boring old pointer
1352
1353 Tk_DefineCursor( tkwin, plFramePtr->cursor );
1354
1355// Don't catch PointerMotion or crossing events any more
1356
1357 if ( !plFramePtr->drawing_rband )
1358 {
1359 Tk_DeleteEventHandler( tkwin, PointerMotionMask,
1360 PlFrameMotionEH, (ClientData) plFramePtr );
1361
1362 Tk_DeleteEventHandler( tkwin, EnterWindowMask,
1363 PlFrameEnterEH, (ClientData) plFramePtr );
1364
1365 Tk_DeleteEventHandler( tkwin, LeaveWindowMask,
1366 PlFrameLeaveEH, (ClientData) plFramePtr );
1367 }
1368
1369 Tk_DeleteEventHandler( tkwin, KeyPressMask,
1370 PlFrameKeyEH, (ClientData) plFramePtr );
1371
1372// This draw removes the last set of graphic crosshairs
1373
1374 UpdateXhairs( plFramePtr );
1375 plFramePtr->drawing_xhairs = 0;
1376}
1377
1378//--------------------------------------------------------------------------
1379// DrawXhairs()
1380//
1381// Draws graphic crosshairs at (x0, y0). The first draw erases the old set.
1382//--------------------------------------------------------------------------
1383
1384static void
1385DrawXhairs( PlFrame *plFramePtr, int x0, int y0 )
1386{
1387 register Tk_Window tkwin = plFramePtr->tkwin;
1388 int xmin = 0, xmax = Tk_Width( tkwin ) - 1;
1389 int ymin = 0, ymax = Tk_Height( tkwin ) - 1;
1390
1391 if ( plFramePtr->drawing_xhairs )
1392 UpdateXhairs( plFramePtr );
1393
1394 plFramePtr->xhair_x[0].x = (short) xmin; plFramePtr->xhair_x[0].y = (short) y0;
1395 plFramePtr->xhair_x[1].x = (short) xmax; plFramePtr->xhair_x[1].y = (short) y0;
1396
1397 plFramePtr->xhair_y[0].x = (short) x0; plFramePtr->xhair_y[0].y = (short) ymin;
1398 plFramePtr->xhair_y[1].x = (short) x0; plFramePtr->xhair_y[1].y = (short) ymax;
1399
1400 UpdateXhairs( plFramePtr );
1401}
1402
1403//--------------------------------------------------------------------------
1404// UpdateXhairs()
1405//
1406// Updates graphic crosshairs. If already there, they are erased.
1407//--------------------------------------------------------------------------
1408
1409static void
1410UpdateXhairs( PlFrame *plFramePtr )
1411{
1412 register Tk_Window tkwin = plFramePtr->tkwin;
1413
1414 XDrawLines( Tk_Display( tkwin ), Tk_WindowId( tkwin ),
1415 plFramePtr->xorGC, plFramePtr->xhair_x, 2,
1416 CoordModeOrigin );
1417
1418 XDrawLines( Tk_Display( tkwin ), Tk_WindowId( tkwin ),
1419 plFramePtr->xorGC, plFramePtr->xhair_y, 2,
1420 CoordModeOrigin );
1421}
1422
1423//--------------------------------------------------------------------------
1424// CreateRband()
1425//
1426// Initiate rubber banding.
1427//--------------------------------------------------------------------------
1428
1429static void
1430CreateRband( PlFrame *plFramePtr )
1431{
1432 register Tk_Window tkwin = plFramePtr->tkwin;
1433 Window root, child;
1434 int root_x, root_y, win_x, win_y;
1435 unsigned int mask;
1436
1437// Find current pointer location, and initiate rubber banding.
1438
1439 if ( XQueryPointer( plFramePtr->display, Tk_WindowId( tkwin ),
1440 &root, &child, &root_x, &root_y, &win_x, &win_y,
1441 &mask ) )
1442 {
1443 if ( win_x >= 0 && win_x < Tk_Width( tkwin ) &&
1444 win_y >= 0 && win_y < Tk_Height( tkwin ) )
1445 {
1446 // Okay, pointer is in our window.
1447 plFramePtr->rband_pt[0].x = (short) win_x;
1448 plFramePtr->rband_pt[0].y = (short) win_y;
1449
1450 DrawRband( plFramePtr, win_x, win_y );
1451 plFramePtr->drawing_rband = 1;
1452 }
1453 else
1454 {
1455 // Hmm, somehow they turned it on without even being in the window.
1456 // Just put the anchor in top left, they'll soon realize this is a
1457 // mistake...
1458
1459 plFramePtr->rband_pt[0].x = 0;
1460 plFramePtr->rband_pt[0].y = 0;
1461
1462 DrawRband( plFramePtr, win_x, win_y );
1463 plFramePtr->drawing_rband = 1;
1464 }
1465 }
1466
1467// Catch PointerMotion and crossing events so we can update them properly
1468
1469 if ( !plFramePtr->drawing_xhairs )
1470 {
1471 Tk_CreateEventHandler( tkwin, PointerMotionMask,
1472 PlFrameMotionEH, (ClientData) plFramePtr );
1473
1474 Tk_CreateEventHandler( tkwin, EnterWindowMask,
1475 PlFrameEnterEH, (ClientData) plFramePtr );
1476
1477 Tk_CreateEventHandler( tkwin, LeaveWindowMask,
1478 PlFrameLeaveEH, (ClientData) plFramePtr );
1479 }
1480}
1481
1482//--------------------------------------------------------------------------
1483// DestroyRband()
1484//
1485// Turn off rubber banding.
1486//--------------------------------------------------------------------------
1487
1488static void
1489DestroyRband( PlFrame *plFramePtr )
1490{
1491 register Tk_Window tkwin = plFramePtr->tkwin;
1492
1493// Don't catch PointerMotion or crossing events any more
1494
1495 if ( !plFramePtr->drawing_xhairs )
1496 {
1497 Tk_DeleteEventHandler( tkwin, PointerMotionMask,
1498 PlFrameMotionEH, (ClientData) plFramePtr );
1499
1500 Tk_DeleteEventHandler( tkwin, EnterWindowMask,
1501 PlFrameEnterEH, (ClientData) plFramePtr );
1502
1503 Tk_DeleteEventHandler( tkwin, LeaveWindowMask,
1504 PlFrameLeaveEH, (ClientData) plFramePtr );
1505 }
1506
1507// This draw removes the residual rubber band.
1508
1509 UpdateRband( plFramePtr );
1510 plFramePtr->drawing_rband = 0;
1511}
1512
1513//--------------------------------------------------------------------------
1514// DrawRband()
1515//
1516// Draws a rubber band from the anchor to the current cursor location.
1517//--------------------------------------------------------------------------
1518
1519static void
1520DrawRband( PlFrame *plFramePtr, int x0, int y0 )
1521{
1522// If the line is already up, clear it.
1523
1524 if ( plFramePtr->drawing_rband )
1525 UpdateRband( plFramePtr );
1526
1527 plFramePtr->rband_pt[1].x = (short) x0; plFramePtr->rband_pt[1].y = (short) y0;
1528
1529 UpdateRband( plFramePtr );
1530}
1531
1532//--------------------------------------------------------------------------
1533// UpdateRband()
1534//
1535// Updates rubber band. If already there, it is erased.
1536//--------------------------------------------------------------------------
1537
1538static void
1539UpdateRband( PlFrame *plFramePtr )
1540{
1541 register Tk_Window tkwin = plFramePtr->tkwin;
1542
1543 XDrawLines( Tk_Display( tkwin ), Tk_WindowId( tkwin ),
1544 plFramePtr->xorGC, plFramePtr->rband_pt, 2,
1545 CoordModeOrigin );
1546}
1547
1548//
1549//--------------------------------------------------------------------------
1550//
1551// PlFrameInit --
1552//
1553// Invoked to handle miscellaneous initialization after window gets
1554// mapped.
1555//
1556// Results:
1557// None.
1558//
1559// Side effects:
1560// PLplot internal parameters and device driver are initialized.
1561//
1562//--------------------------------------------------------------------------
1563
1564static void
1565PlFrameInit( ClientData clientData )
1566{
1567 register PlFrame *plFramePtr = (PlFrame *) clientData;
1568 register Tk_Window tkwin = plFramePtr->tkwin;
1569
1570// Set up window parameters and arrange for window to be refreshed
1571
1572 plFramePtr->flags |= REFRESH_PENDING;
1573 plFramePtr->flags |= UPDATE_V_SCROLLBAR | UPDATE_H_SCROLLBAR;
1574
1575// First-time initialization
1576
1577 if ( !plFramePtr->tkwin_initted )
1578 {
1579 plsstrm( plFramePtr->ipls );
1580 plsxwin( (PLINT) Tk_WindowId( tkwin ) );
1581 plspause( 0 );
1582 plinit();
1583// plplot_ccmap is statically defined in plxwd.h. Note that
1584// xwin.c also includes that header and uses that variable.
1585 if ( plplot_ccmap )
1586 {
1587 Install_cmap( plFramePtr );
1588 }
1589 if ( plFramePtr->bopCmd != NULL )
1590 plsbopH( process_bop, (void *) plFramePtr );
1591 if ( plFramePtr->eopCmd != NULL )
1592 plseopH( process_eop, (void *) plFramePtr );
1593
1594 plbop();
1595
1596 plFramePtr->tkwin_initted = 1;
1597 plFramePtr->width = Tk_Width( tkwin );
1598 plFramePtr->height = Tk_Height( tkwin );
1599 plFramePtr->prevWidth = plFramePtr->width;
1600 plFramePtr->prevHeight = plFramePtr->height;
1601 }
1602
1603// Draw plframe
1604
1605 DisplayPlFrame( clientData );
1606
1607 if ( plFramePtr->xhairs )
1608 CreateXhairs( plFramePtr );
1609
1610 if ( plFramePtr->rband )
1611 CreateRband( plFramePtr );
1612}
1613
1614//
1615//--------------------------------------------------------------------------
1616//
1617// Install_cmap --
1618//
1619// Installs X driver color map as necessary when custom color maps
1620// are used.
1621//
1622// Results:
1623// None.
1624//
1625// Side effects:
1626// Parent color maps may get changed.
1627//
1628//--------------------------------------------------------------------------
1629//
1630
1631static void
1632Install_cmap( PlFrame *plFramePtr )
1633{
1634 XwDev *dev;
1635
1636#define INSTALL_COLORMAP_IN_TK
1637#ifdef INSTALL_COLORMAP_IN_TK
1638 dev = (XwDev *) plFramePtr->pls->dev;
1639 Tk_SetWindowColormap( Tk_MainWindow( plFramePtr->interp ), dev->xwd->map );
1640
1641//
1642// If the colormap is local to this widget, the WM must be informed that
1643// it should be installed when the widget gets the focus. The top level
1644// window must be added to the end of its own list, because otherwise the
1645// window manager adds it to the front (as required by the ICCCM). Thanks
1646// to Paul Mackerras for providing this info in his TK photo widget.
1647//
1648
1649#else
1650 int count = 0;
1651 Window top, colormap_windows[5];
1652
1653 top = Tk_WindowId( Tk_MainWindow( plFramePtr->interp ) );
1654
1655 colormap_windows[count++] = Tk_WindowId( plFramePtr->tkwin );
1656 colormap_windows[count++] = top;
1657
1658 if ( !XSetWMColormapWindows( plFramePtr->display,
1659 top, colormap_windows, count ) )
1660 fprintf( stderr, "Unable to set color map property!\n" );
1661#endif
1662}
1663
1664//
1665//--------------------------------------------------------------------------
1666//
1667// DisplayPlFrame --
1668//
1669// This procedure is invoked to display a plframe widget.
1670//
1671// Results:
1672// None.
1673//
1674// Side effects:
1675// Commands are output to X to display the plframe in its
1676// current mode.
1677//
1678//--------------------------------------------------------------------------
1679//
1680
1681static void
1682DisplayPlFrame( ClientData clientData )
1683{
1684 register PlFrame *plFramePtr = (PlFrame *) clientData;
1685 register Tk_Window tkwin = plFramePtr->tkwin;
1686
1687 dbug_enter( "DisplayPlFrame" );
1688
1689// Update scrollbars if needed
1690
1691 if ( plFramePtr->flags & UPDATE_V_SCROLLBAR )
1692 {
1693 UpdateVScrollbar( plFramePtr );
1694 }
1695 if ( plFramePtr->flags & UPDATE_H_SCROLLBAR )
1696 {
1697 UpdateHScrollbar( plFramePtr );
1698 }
1699 plFramePtr->flags &= ~( UPDATE_V_SCROLLBAR | UPDATE_H_SCROLLBAR );
1700
1701// If not mapped yet, just return and cancel pending refresh
1702
1703 if ( ( plFramePtr->tkwin == NULL ) || !Tk_IsMapped( tkwin ) )
1704 {
1705 plFramePtr->flags &= ~REFRESH_PENDING;
1706 return;
1707 }
1708
1709// Redraw border if necessary
1710
1711 if ( ( plFramePtr->border != NULL ) &&
1712 ( plFramePtr->relief != TK_RELIEF_FLAT ) )
1713 {
1714#if TK_MAJOR_VERSION >= 4 && TK_MINOR_VERSION >= 0
1715 Tk_Draw3DRectangle( plFramePtr->tkwin, Tk_WindowId( tkwin ),
1716 plFramePtr->border, 0, 0, Tk_Width( tkwin ), Tk_Height( tkwin ),
1717 plFramePtr->borderWidth, plFramePtr->relief );
1718#else
1719 Tk_Draw3DRectangle( plFramePtr->display, Tk_WindowId( tkwin ),
1720 plFramePtr->border, 0, 0, Tk_Width( tkwin ), Tk_Height( tkwin ),
1721 plFramePtr->borderWidth, plFramePtr->relief );
1722#endif
1723 }
1724
1725// All refresh events
1726
1727 if ( plFramePtr->flags & REFRESH_PENDING )
1728 {
1729 plFramePtr->flags &= ~REFRESH_PENDING;
1730
1731 // Reschedule resizes to avoid occasional ordering conflicts with
1732 // the packer's resize of the window (this call must come last).
1733
1734 if ( plFramePtr->flags & RESIZE_PENDING )
1735 {
1736 plFramePtr->flags |= REFRESH_PENDING;
1737 plFramePtr->flags &= ~RESIZE_PENDING;
1738 Tk_DoWhenIdle( DisplayPlFrame, clientData );
1739 return;
1740 }
1741
1742 // Redraw -- replay contents of plot buffer
1743
1744 if ( plFramePtr->flags & REDRAW_PENDING )
1745 {
1746 plFramePtr->flags &= ~REDRAW_PENDING;
1747 plsstrm( plFramePtr->ipls );
1748 pl_cmd( PLESC_REDRAW, (void *) NULL );
1749 }
1750
1751 // Resize -- if window bounds have changed
1752
1753 else if ( ( plFramePtr->width != plFramePtr->prevWidth ) ||
1754 ( plFramePtr->height != plFramePtr->prevHeight ) )
1755 {
1756 plFramePtr->pldis.width = (unsigned int) plFramePtr->width;
1757 plFramePtr->pldis.height = (unsigned int) plFramePtr->height;
1758
1759 plsstrm( plFramePtr->ipls );
1760 pl_cmd( PLESC_RESIZE, (void *) &( plFramePtr->pldis ) );
1761 plFramePtr->prevWidth = plFramePtr->width;
1762 plFramePtr->prevHeight = plFramePtr->height;
1763 }
1764
1765 // Expose -- if window bounds are unchanged
1766
1767 else
1768 {
1769 plsstrm( plFramePtr->ipls );
1770 if ( plFramePtr->drawing_xhairs )
1771 {
1772 XClearWindow( plFramePtr->display, Tk_WindowId( tkwin ) );
1773 XFlush( plFramePtr->display );
1774 pl_cmd( PLESC_EXPOSE, NULL );
1775 }
1776 else
1777 {
1778 pl_cmd( PLESC_EXPOSE, (void *) &( plFramePtr->pldis ) );
1779 }
1780
1781 // Reset window bounds so that next time they are set fresh
1782
1783 plFramePtr->pldis.x = (unsigned int) ( Tk_X( tkwin ) + Tk_Width( tkwin ) );
1784 plFramePtr->pldis.y = (unsigned int) ( Tk_Y( tkwin ) + Tk_Height( tkwin ) );
1785 plFramePtr->pldis.width = (unsigned int) ( -Tk_Width( tkwin ) );
1786 plFramePtr->pldis.height = (unsigned int) ( -Tk_Height( tkwin ) );
1787 }
1788
1789 // Update graphic crosshairs if necessary
1790
1791 if ( plFramePtr->drawing_xhairs )
1792 {
1793 UpdateXhairs( plFramePtr );
1794 }
1795
1796 // Update rubber band if necessary.
1797
1798 if ( plFramePtr->drawing_rband )
1799 {
1800 UpdateRband( plFramePtr );
1801 }
1802 }
1803}
1804
1805//--------------------------------------------------------------------------
1806// Routines to process widget commands.
1807//--------------------------------------------------------------------------
1808
1809//--------------------------------------------------------------------------
1810// scol0
1811//
1812// Sets a color in cmap0.
1813//--------------------------------------------------------------------------
1814
1815static int
1816scol0( Tcl_Interp *interp, register PlFrame *plFramePtr,
1817 int i, const char *col, int *p_changed )
1818{
1819 PLStream *pls = plFramePtr->pls;
1820 XColor xcol;
1821 PLINT r, g, b;
1822
1823 if ( col == NULL )
1824 {
1825 Tcl_AppendResult( interp, "color value not specified",
1826 (char *) NULL );
1827 return TCL_ERROR;
1828 }
1829
1830 if ( !XParseColor( plFramePtr->display,
1831 Tk_Colormap( plFramePtr->tkwin ), col, &xcol ) )
1832 {
1833 Tcl_AppendResult( interp, "Couldn't parse color ", col,
1834 (char *) NULL );
1835 return TCL_ERROR;
1836 }
1837
1838 r = (unsigned) ( xcol.red & 0xFF00 ) >> 8;
1839 g = (unsigned) ( xcol.green & 0xFF00 ) >> 8;
1840 b = (unsigned) ( xcol.blue & 0xFF00 ) >> 8;
1841
1842 if ( ( pls->cmap0[i].r != r ) ||
1843 ( pls->cmap0[i].g != g ) ||
1844 ( pls->cmap0[i].b != b ) )
1845 {
1846 pls->cmap0[i].r = (unsigned char) r;
1847 pls->cmap0[i].g = (unsigned char) g;
1848 pls->cmap0[i].b = (unsigned char) b;
1849 *p_changed = 1;
1850 }
1851
1852 return TCL_OK;
1853}
1854
1855//--------------------------------------------------------------------------
1856// scol1
1857//
1858// Sets a color in cmap1.
1859//--------------------------------------------------------------------------
1860
1861static int
1862scol1( Tcl_Interp *interp, register PlFrame *plFramePtr,
1863 int i, const char *col, const char *pos, const char *rev, int *p_changed )
1864{
1865 PLStream *pls = plFramePtr->pls;
1866 XColor xcol;
1867 PLFLT h, l, s, r, g, b, p;
1868 int reverse;
1869
1870 if ( col == NULL )
1871 {
1872 Tcl_AppendResult( interp, "color value not specified",
1873 (char *) NULL );
1874 return TCL_ERROR;
1875 }
1876
1877 if ( pos == NULL )
1878 {
1879 Tcl_AppendResult( interp, "control point position not specified",
1880 (char *) NULL );
1881 return TCL_ERROR;
1882 }
1883
1884 if ( rev == NULL )
1885 {
1886 Tcl_AppendResult( interp, "interpolation sense not specified",
1887 (char *) NULL );
1888 return TCL_ERROR;
1889 }
1890
1891 if ( !XParseColor( plFramePtr->display,
1892 Tk_Colormap( plFramePtr->tkwin ), col, &xcol ) )
1893 {
1894 Tcl_AppendResult( interp, "Couldn't parse color ", col,
1895 (char *) NULL );
1896 return TCL_ERROR;
1897 }
1898
1899 r = ( (unsigned) ( xcol.red & 0xFF00 ) >> 8 ) / 255.0;
1900 g = ( (unsigned) ( xcol.green & 0xFF00 ) >> 8 ) / 255.0;
1901 b = ( (unsigned) ( xcol.blue & 0xFF00 ) >> 8 ) / 255.0;
1902
1903 plrgbhls( r, g, b, &h, &l, &s );
1904
1905 p = atof( pos ) / 100.0;
1906 reverse = atoi( rev );
1907
1908 if ( ( pls->cmap1cp[i].c1 != h ) ||
1909 ( pls->cmap1cp[i].c2 != l ) ||
1910 ( pls->cmap1cp[i].c3 != s ) ||
1911 ( pls->cmap1cp[i].p != p ) ||
1912 ( pls->cmap1cp[i].alt_hue_path != reverse ) )
1913 {
1914 pls->cmap1cp[i].c1 = h;
1915 pls->cmap1cp[i].c2 = l;
1916 pls->cmap1cp[i].c3 = s;
1917 pls->cmap1cp[i].p = p;
1918 pls->cmap1cp[i].alt_hue_path = reverse;
1919 *p_changed = 1;
1920 }
1921 return TCL_OK;
1922}
1923
1924//--------------------------------------------------------------------------
1925// ColorManip
1926//
1927// Processes color manipulation widget commands.
1928//
1929// This provides an alternate API for the plplot color handling functions
1930// (prepend a "pl" to get the corresponding plplot function). They differ
1931// from the versions in the Tcl API in the following ways:
1932//
1933// - X11 conventions are used rather than plplot ones. XParseColor is used
1934// to convert a string into its 3 rgb components. This lets you use
1935// symbolic names or hex notation for color values.
1936//
1937// - these expect/emit Tcl array values in lists rather than in tclmatrix
1938// form, like most "normal" Tcl tools. For usage, see the examples in the
1939// palette tools (plcolor.tcl).
1940//--------------------------------------------------------------------------
1941
1942static int
1943ColorManip( Tcl_Interp *interp, register PlFrame *plFramePtr,
1944 int argc, const char **argv )
1945{
1946 PLStream *pls = plFramePtr->pls;
1947 int length;
1948 char c;
1949 int result = TCL_OK;
1950 char *tmpstring;
1951
1952#ifdef DEBUG
1953 if ( pls->debug )
1954 {
1955 int i;
1956 fprintf( stderr, "There are %d arguments to ColorManip:", argc );
1957 for ( i = 0; i < argc; i++ )
1958 {
1959 fprintf( stderr, " %s", argv[i] );
1960 }
1961 fprintf( stderr, "\n" );
1962 }
1963#else
1964 (void) argc; // Cast to void to suppress compiler warning about unused parameter
1965#endif
1966
1967// Make sure widget has been initialized before going any further
1968
1969 if ( !plFramePtr->tkwin_initted )
1970 {
1971 Tcl_VarEval( plFramePtr->interp, "update", (char *) NULL );
1972 }
1973
1974// Set stream number and get ready to process the command
1975
1976 plsstrm( plFramePtr->ipls );
1977
1978 c = argv[0][0];
1979 length = (int) strlen( argv[0] );
1980
1981// gcmap0 -- get color map 0
1982// first arg is number of colors, the rest are hex number specifications
1983
1984 if ( ( c == 'g' ) && ( strncmp( argv[0], "gcmap0", (size_t) length ) == 0 ) )
1985 {
1986 int i;
1987 unsigned long plcolor;
1988 char str[10];
1989
1990 sprintf( str, "%d", (int) pls->ncol0 );
1991 Tcl_AppendElement( interp, str );
1992 for ( i = 0; i < pls->ncol0; i++ )
1993 {
1994 plcolor = (unsigned long) ( ( pls->cmap0[i].r << 16 ) |
1995 ( pls->cmap0[i].g << 8 ) |
1996 ( pls->cmap0[i].b ) );
1997
1998 sprintf( str, "#%06lx", ( plcolor & 0xFFFFFF ) );
1999 Tcl_AppendElement( interp, str );
2000 }
2001 result = TCL_OK;
2002 }
2003
2004// gcmap1 -- get color map 1
2005// first arg is number of control points
2006// the rest are hex number specifications followed by positions (0-100)
2007
2008 else if ( ( c == 'g' ) && ( strncmp( argv[0], "gcmap1", (size_t) length ) == 0 ) )
2009 {
2010 int i;
2011 unsigned long plcolor;
2012 char str[10];
2013 PLFLT h, l, s, r, g, b;
2014 int r1, g1, b1;
2015
2016 sprintf( str, "%d", (int) pls->ncp1 );
2017 Tcl_AppendElement( interp, str );
2018 for ( i = 0; i < pls->ncp1; i++ )
2019 {
2020 h = pls->cmap1cp[i].c1;
2021 l = pls->cmap1cp[i].c2;
2022 s = pls->cmap1cp[i].c3;
2023
2024 plhlsrgb( h, l, s, &r, &g, &b );
2025
2026 r1 = MAX( 0, MIN( 255, (int) ( 256. * r ) ) );
2027 g1 = MAX( 0, MIN( 255, (int) ( 256. * g ) ) );
2028 b1 = MAX( 0, MIN( 255, (int) ( 256. * b ) ) );
2029
2030 plcolor = (unsigned long) ( ( r1 << 16 ) | ( g1 << 8 ) | ( b1 ) );
2031
2032 sprintf( str, "#%06lx", ( plcolor & 0xFFFFFF ) );
2033 Tcl_AppendElement( interp, str );
2034
2035 sprintf( str, "%02d", (int) ( 100 * pls->cmap1cp[i].p ) );
2036 Tcl_AppendElement( interp, str );
2037
2038 sprintf( str, "%01d", (int) ( pls->cmap1cp[i].alt_hue_path ) );
2039 Tcl_AppendElement( interp, str );
2040 }
2041 result = TCL_OK;
2042 }
2043
2044// scmap0 -- set color map 0
2045// first arg is number of colors, the rest are hex number specifications
2046
2047 else if ( ( c == 's' ) && ( strncmp( argv[0], "scmap0", (size_t) length ) == 0 ) )
2048 {
2049 int i, changed = 1, ncol0 = atoi( argv[1] );
2050 char *col;
2051
2052 if ( ncol0 > 16 || ncol0 < 1 )
2053 {
2054 Tcl_AppendResult( interp, "illegal number of colors in cmap0: ",
2055 argv[1], (char *) NULL );
2056 return TCL_ERROR;
2057 }
2058
2059 pls->ncol0 = ncol0;
2060 tmpstring = (char *) malloc( strlen( argv[2] ) + 1 );
2061 strcpy( tmpstring, argv[2] );
2062 col = strtok( tmpstring, " " );
2063 for ( i = 0; i < pls->ncol0; i++ )
2064 {
2065 if ( col == NULL )
2066 break;
2067
2068 if ( scol0( interp, plFramePtr, i, col, &changed ) != TCL_OK )
2069 return TCL_ERROR;
2070
2071 col = strtok( NULL, " " );
2072 }
2073 free( tmpstring );
2074
2075 if ( changed )
2077 }
2078
2079// scmap1 -- set color map 1
2080// first arg is number of colors, the rest are hex number specifications
2081
2082 else if ( ( c == 's' ) && ( strncmp( argv[0], "scmap1", (size_t) length ) == 0 ) )
2083 {
2084 int i, changed = 1, ncp1 = atoi( argv[1] );
2085 char *col, *pos, *rev;
2086
2087 if ( ncp1 > 32 || ncp1 < 1 )
2088 {
2089 Tcl_AppendResult( interp,
2090 "illegal number of control points in cmap1: ",
2091 argv[1], (char *) NULL );
2092 return TCL_ERROR;
2093 }
2094
2095 tmpstring = (char *) malloc( strlen( argv[2] ) + 1 );
2096 strcpy( tmpstring, argv[2] );
2097 col = strtok( tmpstring, " " );
2098 pos = strtok( NULL, " " );
2099 rev = strtok( NULL, " " );
2100 for ( i = 0; i < ncp1; i++ )
2101 {
2102 if ( col == NULL )
2103 break;
2104
2105 if ( scol1( interp, plFramePtr,
2106 i, col, pos, rev, &changed ) != TCL_OK )
2107 return TCL_ERROR;
2108
2109 col = strtok( NULL, " " );
2110 pos = strtok( NULL, " " );
2111 rev = strtok( NULL, " " );
2112 }
2113 free( tmpstring );
2114
2115 if ( changed )
2116 {
2117 plFramePtr->pls->ncp1 = ncp1;
2118 plcmap1_calc();
2119 }
2120 }
2121
2122// scol0 -- set single color in cmap0
2123// first arg is the color number, the next is the color in hex
2124
2125 else if ( ( c == 's' ) && ( strncmp( argv[0], "scol0", (size_t) length ) == 0 ) )
2126 {
2127 int i = atoi( argv[1] ), changed = 1;
2128
2129 if ( i > pls->ncol0 || i < 0 )
2130 {
2131 Tcl_AppendResult( interp, "illegal color number in cmap0: ",
2132 argv[1], (char *) NULL );
2133 return TCL_ERROR;
2134 }
2135
2136 if ( scol0( interp, plFramePtr, i, argv[2], &changed ) != TCL_OK )
2137 return TCL_ERROR;
2138
2139 if ( changed )
2141 }
2142
2143// scol1 -- set color of control point in cmap1
2144// first arg is the control point, the next two are the color in hex and pos
2145
2146 else if ( ( c == 's' ) && ( strncmp( argv[0], "scol1", (size_t) length ) == 0 ) )
2147 {
2148 int i = atoi( argv[1] ), changed = 1;
2149
2150 if ( i > pls->ncp1 || i < 0 )
2151 {
2152 Tcl_AppendResult( interp, "illegal control point number in cmap1: ",
2153 argv[1], (char *) NULL );
2154 return TCL_ERROR;
2155 }
2156
2157 if ( scol1( interp, plFramePtr,
2158 i, argv[2], argv[3], argv[4], &changed ) != TCL_OK )
2159 return TCL_ERROR;
2160
2161 if ( changed )
2162 plcmap1_calc();
2163 }
2164
2165 plflush();
2166 return result;
2167}
2168
2169//--------------------------------------------------------------------------
2170// Cmd
2171//
2172// Processes "cmd" widget command.
2173// Handles commands that go more or less directly to the PLplot library.
2174// Most of these come out of the PLplot Tcl API support file.
2175//--------------------------------------------------------------------------
2176
2177static int
2178Cmd( Tcl_Interp *interp, register PlFrame *plFramePtr,
2179 int argc, const char **argv )
2180{
2181 int result = TCL_OK;
2182 char cmdlist[] = "";
2183
2184#ifdef DEBUG
2185 PLStream *pls = plFramePtr->pls;
2186 if ( pls->debug )
2187 {
2188 int i;
2189 fprintf( stderr, "There are %d arguments to Cmd:", argc );
2190 for ( i = 0; i < argc; i++ )
2191 {
2192 fprintf( stderr, " %s", argv[i] );
2193 }
2194 fprintf( stderr, "\n" );
2195 }
2196#endif
2197
2198// no option -- return list of available PLplot commands
2199
2200 if ( argc == 0 )
2201 return plTclCmd( cmdlist, interp, argc, argv );
2202
2203// Make sure widget has been initialized before going any further
2204
2205 if ( !plFramePtr->tkwin_initted )
2206 {
2207 Tcl_VarEval( plFramePtr->interp, "update", (char *) NULL );
2208 }
2209
2210// Set stream number and get ready to process the command
2211
2212 plsstrm( plFramePtr->ipls );
2213
2214// Process command
2215
2216 result = plTclCmd( cmdlist, interp, argc, argv );
2217
2218 plflush();
2219 return result;
2220}
2221
2222//
2223//--------------------------------------------------------------------------
2224//
2225// ConfigurePlFrame --
2226//
2227// This procedure is called to process an argv/argc list, plus the Tk
2228// option database, in order to configure (or reconfigure) a
2229// plframe widget.
2230//
2231// Results:
2232// The return value is a standard Tcl result. If TCL_ERROR is
2233// returned, then interp->result contains an error message.
2234//
2235// Side effects:
2236// Configuration information, such as text string, colors, font, etc.
2237// get set for plFramePtr; old resources get freed, if there were
2238// any.
2239//
2240//--------------------------------------------------------------------------
2241//
2242
2243static int
2244ConfigurePlFrame( Tcl_Interp *interp, register PlFrame *plFramePtr,
2245 int argc, const char **argv, int flags )
2246{
2247 register Tk_Window tkwin = plFramePtr->tkwin;
2248 PLStream *pls = plFramePtr->pls;
2249 XwDev *dev = (XwDev *) pls->dev;
2250 XwDisplay *xwd = (XwDisplay *) dev->xwd;
2251 XGCValues gcValues;
2252 unsigned long mask;
2253 int need_redisplay = 0;
2254
2255#ifdef DEBUG
2256 if ( pls->debug )
2257 {
2258 int i;
2259 fprintf( stderr, "Arguments to configure are:" );
2260 for ( i = 0; i < argc; i++ )
2261 {
2262 fprintf( stderr, " %s", argv[i] );
2263 }
2264 fprintf( stderr, "\n" );
2265 }
2266#endif
2267
2268 dbug_enter( "ConfigurePlFrame" );
2269
2270 if ( Tk_ConfigureWidget( interp, tkwin, configSpecs,
2271 argc, (CONST char **) argv, (char *) plFramePtr, flags ) != TCL_OK )
2272 {
2273 return TCL_ERROR;
2274 }
2275
2276//
2277// Set background color using xwin driver's pixel value. Done this way so
2278// that (a) we can use r/w color cells, and (b) the BG pixel values as set
2279// here and in the xwin driver are consistent.
2280//
2281
2282 plsstrm( plFramePtr->ipls );
2283 plP_esc( PLESC_DEV2PLCOL, (void *) plFramePtr->bgColor );
2284 pl_cpcolor( &pls->cmap0[0], &pls->tmpcolor );
2285 plP_esc( PLESC_SETBGFG, NULL );
2286
2287 Tk_SetWindowBackground( tkwin, xwd->cmap0[0].pixel );
2288 Tk_SetWindowBorder( tkwin, xwd->cmap0[0].pixel );
2289
2290// Set up GC for rubber-band draws
2291
2292 gcValues.background = xwd->cmap0[0].pixel;
2293 gcValues.foreground = 0xFF;
2294 gcValues.function = GXxor;
2295 mask = GCForeground | GCBackground | GCFunction;
2296
2297 if ( plFramePtr->xorGC != NULL )
2298 Tk_FreeGC( plFramePtr->display, plFramePtr->xorGC );
2299
2300 plFramePtr->xorGC = Tk_GetGC( plFramePtr->tkwin, mask, &gcValues );
2301
2302// Geometry settings
2303
2304 Tk_SetInternalBorder( tkwin, plFramePtr->borderWidth );
2305 if ( ( plFramePtr->width > 0 ) || ( plFramePtr->height > 0 ) )
2306 {
2307 Tk_GeometryRequest( tkwin, plFramePtr->width, plFramePtr->height );
2308 if ( ( plFramePtr->width != plFramePtr->prevWidth ) ||
2309 ( plFramePtr->height != plFramePtr->prevHeight ) )
2310 need_redisplay = 1;
2311 }
2312
2313// Create or destroy graphic crosshairs as specified
2314
2315 if ( Tk_IsMapped( tkwin ) )
2316 {
2317 if ( plFramePtr->xhairs )
2318 {
2319 if ( !plFramePtr->drawing_xhairs )
2320 CreateXhairs( plFramePtr );
2321 }
2322 else
2323 {
2324 if ( plFramePtr->drawing_xhairs )
2325 DestroyXhairs( plFramePtr );
2326 }
2327 }
2328
2329// Create or destroy rubber band as specified
2330
2331 if ( Tk_IsMapped( tkwin ) )
2332 {
2333 if ( plFramePtr->rband )
2334 {
2335 if ( !plFramePtr->drawing_rband )
2336 CreateRband( plFramePtr );
2337 }
2338 else
2339 {
2340 if ( plFramePtr->drawing_rband )
2341 DestroyRband( plFramePtr );
2342 }
2343 }
2344
2345// Arrange for window to be refreshed if necessary
2346
2347 if ( need_redisplay && Tk_IsMapped( tkwin )
2348 && !( plFramePtr->flags & REFRESH_PENDING ) )
2349 {
2350 Tk_DoWhenIdle( DisplayPlFrame, (ClientData) plFramePtr );
2351 plFramePtr->flags |= REFRESH_PENDING;
2352 plFramePtr->flags |= UPDATE_V_SCROLLBAR | UPDATE_H_SCROLLBAR;
2353 }
2354
2355 return TCL_OK;
2356}
2357
2358//--------------------------------------------------------------------------
2359// Draw
2360//
2361// Processes "draw" widget command.
2362// Handles rubber-band drawing.
2363//--------------------------------------------------------------------------
2364
2365static int
2366Draw( Tcl_Interp *interp, register PlFrame *plFramePtr,
2367 int argc, const char **argv )
2368{
2369 register Tk_Window tkwin = plFramePtr->tkwin;
2370 int result = TCL_OK;
2371 char c = argv[0][0];
2372 int length = (int) strlen( argv[0] );
2373
2374// Make sure widget has been initialized before going any further
2375
2376 if ( !plFramePtr->tkwin_initted )
2377 {
2378 Tcl_VarEval( plFramePtr->interp, "update", (char *) NULL );
2379 }
2380
2381// init -- sets up for rubber-band drawing
2382
2383 if ( ( c == 'i' ) && ( strncmp( argv[0], "init", (size_t) length ) == 0 ) )
2384 {
2385 Tk_DefineCursor( tkwin, plFramePtr->xhair_cursor );
2386 }
2387
2388// end -- ends rubber-band drawing
2389
2390 else if ( ( c == 'e' ) && ( strncmp( argv[0], "end", (size_t) length ) == 0 ) )
2391 {
2392 Tk_DefineCursor( tkwin, plFramePtr->cursor );
2393 if ( plFramePtr->continue_draw )
2394 {
2395 XDrawLines( Tk_Display( tkwin ), Tk_WindowId( tkwin ),
2396 plFramePtr->xorGC, plFramePtr->pts, 5,
2397 CoordModeOrigin );
2398 XSync( Tk_Display( tkwin ), 0 );
2399 }
2400
2401 plFramePtr->continue_draw = 0;
2402 }
2403
2404// rect -- draw a rectangle, used to select rectangular areas
2405// first draw erases old outline
2406
2407 else if ( ( c == 'r' ) && ( strncmp( argv[0], "rect", (size_t) length ) == 0 ) )
2408 {
2409 if ( argc < 5 )
2410 {
2411 Tcl_AppendResult( interp, "wrong # args: should be \"",
2412 " draw rect x0 y0 x1 y1\"", (char *) NULL );
2413 result = TCL_ERROR;
2414 }
2415 else
2416 {
2417 int x0, y0, x1, y1;
2418 int xmin = 0, xmax = Tk_Width( tkwin ) - 1;
2419 int ymin = 0, ymax = Tk_Height( tkwin ) - 1;
2420
2421 x0 = atoi( argv[1] );
2422 y0 = atoi( argv[2] );
2423 x1 = atoi( argv[3] );
2424 y1 = atoi( argv[4] );
2425
2426 x0 = MAX( xmin, MIN( xmax, x0 ) );
2427 y0 = MAX( ymin, MIN( ymax, y0 ) );
2428 x1 = MAX( xmin, MIN( xmax, x1 ) );
2429 y1 = MAX( ymin, MIN( ymax, y1 ) );
2430
2431 if ( plFramePtr->continue_draw )
2432 {
2433 XDrawLines( Tk_Display( tkwin ), Tk_WindowId( tkwin ),
2434 plFramePtr->xorGC, plFramePtr->pts, 5,
2435 CoordModeOrigin );
2436 XSync( Tk_Display( tkwin ), 0 );
2437 }
2438
2439 plFramePtr->pts[0].x = (short) x0; plFramePtr->pts[0].y = (short) y0;
2440 plFramePtr->pts[1].x = (short) x1; plFramePtr->pts[1].y = (short) y0;
2441 plFramePtr->pts[2].x = (short) x1; plFramePtr->pts[2].y = (short) y1;
2442 plFramePtr->pts[3].x = (short) x0; plFramePtr->pts[3].y = (short) y1;
2443 plFramePtr->pts[4].x = (short) x0; plFramePtr->pts[4].y = (short) y0;
2444
2445 XDrawLines( Tk_Display( tkwin ), Tk_WindowId( tkwin ),
2446 plFramePtr->xorGC, plFramePtr->pts, 5,
2447 CoordModeOrigin );
2448 XSync( Tk_Display( tkwin ), 0 );
2449
2450 plFramePtr->continue_draw = 1;
2451 }
2452 }
2453
2454 return result;
2455}
2456
2457//--------------------------------------------------------------------------
2458// Info
2459//
2460// Processes "info" widget command.
2461// Returns requested info.
2462//--------------------------------------------------------------------------
2463
2464static int
2465Info( Tcl_Interp *interp, register PlFrame *plFramePtr,
2466 int argc, const char **argv )
2467{
2468 int length;
2469 char c;
2470 int result = TCL_OK;
2471
2472// no option -- return list of available info commands
2473
2474 if ( argc == 0 )
2475 {
2476 Tcl_SetResult( interp, "devkeys devnames", TCL_STATIC );
2477 return TCL_OK;
2478 }
2479
2480 c = argv[0][0];
2481 length = (int) strlen( argv[0] );
2482
2483// devkeys -- return list of supported device keywords
2484
2485 if ( ( c == 'd' ) && ( strncmp( argv[0], "devkeys", (size_t) length ) == 0 ) )
2486 {
2487 int i = 0;
2488 while ( plFramePtr->devName[i] != NULL )
2489 Tcl_AppendElement( interp, plFramePtr->devName[i++] );
2490
2491 result = TCL_OK;
2492 }
2493
2494// devkeys -- return list of supported device types
2495
2496 else if ( ( c == 'd' ) && ( strncmp( argv[0], "devnames", (size_t) length ) == 0 ) )
2497 {
2498 int i = 0;
2499 while ( plFramePtr->devDesc[i] != NULL )
2500 Tcl_AppendElement( interp, plFramePtr->devDesc[i++] );
2501
2502 result = TCL_OK;
2503 }
2504
2505// unrecognized
2506
2507 else
2508 {
2509 Tcl_AppendResult( interp, "bad option to \"info\": must be ",
2510 "devkeys, devnames", (char *) NULL );
2511
2512 result = TCL_ERROR;
2513 }
2514
2515 return result;
2516}
2517
2518//--------------------------------------------------------------------------
2519// Openlink
2520//
2521// Processes "openlink" widget command.
2522// Opens channel (FIFO or socket) for binary data transfer between client
2523// and server.
2524//--------------------------------------------------------------------------
2525
2526static int
2527Openlink( Tcl_Interp *interp, register PlFrame *plFramePtr,
2528 int argc, const char **argv )
2529{
2530 register PLRDev *plr = plFramePtr->plr;
2531 register PLiodev *iodev = plr->iodev;
2532
2533 char c = argv[0][0];
2534 int length = (int) strlen( argv[0] );
2535
2536 dbug_enter( "Openlink" );
2537
2538// Open fifo
2539
2540 if ( ( c == 'f' ) && ( strncmp( argv[0], "fifo", (size_t) length ) == 0 ) )
2541 {
2542 if ( argc < 1 )
2543 {
2544 Tcl_AppendResult( interp, "bad command -- must be: ",
2545 "openlink fifo <pathname>",
2546 (char *) NULL );
2547 return TCL_ERROR;
2548 }
2549#if !defined ( _WIN32 )
2550 if ( ( iodev->fd = open( argv[1], O_RDONLY ) ) == -1 )
2551#else
2552 if ( 1 )
2553#endif
2554 {
2555 Tcl_AppendResult( interp, "cannot open fifo ", argv[1],
2556 " for read", (char *) NULL );
2557 return TCL_ERROR;
2558 }
2559 iodev->type = 0;
2560 iodev->typeName = "fifo";
2561#if !defined ( _WIN32 )
2562 iodev->file = fdopen( iodev->fd, "rb" );
2563#else
2564 iodev->file = NULL;
2565#endif
2566 }
2567
2568// Open socket
2569
2570 else if ( ( c == 's' ) && ( strncmp( argv[0], "socket", (size_t) length ) == 0 ) )
2571 {
2572 if ( argc < 1 )
2573 {
2574 Tcl_AppendResult( interp, "bad command -- must be: ",
2575 "openlink socket <sock-id>",
2576 (char *) NULL );
2577 return TCL_ERROR;
2578 }
2579 iodev->type = 1;
2580 iodev->typeName = "socket";
2581 iodev->fileHandle = argv[1];
2582
2583#if TCL_MAJOR_VERSION < 7 || ( TCL_MAJOR_VERSION == 7 && TCL_MINOR_VERSION == 4 )
2584#define FILECAST
2585#else
2586#define FILECAST ( ClientData )
2587#endif
2588
2589// Exclude UNIX-only feature
2590#if !defined ( MAC_TCL ) && !defined ( _WIN32 ) && !defined ( __CYGWIN__ )
2591 if ( Tcl_GetOpenFile( interp, iodev->fileHandle,
2592 0, 1, FILECAST & iodev->file ) != TCL_OK )
2593 {
2594 return TCL_ERROR;
2595 }
2596#endif
2597 iodev->fd = fileno( iodev->file );
2598 }
2599
2600// unrecognized
2601
2602 else
2603 {
2604 Tcl_AppendResult( interp, "bad option to \"openlink\": must be ",
2605 "fifo or socket", (char *) NULL );
2606
2607 return TCL_ERROR;
2608 }
2609
2610 plr->pdfs = pdf_bopen( NULL, 4200 );
2611// Sheesh, what a mess. I don't see how Tk4.1's converter macro could
2612// possibly work.
2613#if TK_MAJOR_VERSION < 4 || \
2614 ( TK_MAJOR_VERSION == 4 && TK_MINOR_VERSION == 0 ) || \
2615 TK_MAJOR_VERSION > 7
2616#if !defined ( MAC_TCL ) && !defined ( _WIN32 ) && !defined ( __CYGWIN__ )
2617 Tk_CreateFileHandler( iodev->fd, TK_READABLE, (Tk_FileProc *) ReadData,
2618 (ClientData) plFramePtr );
2619#endif
2620#else
2621#if !defined ( MAC_TCL ) && !defined ( _WIN32 ) && !defined ( __CYGWIN__ )
2622 Tcl_CreateFileHandler( Tcl_GetFile( (ClientData) iodev->fd, TCL_UNIX_FD ),
2623 TK_READABLE, (Tk_FileProc *) ReadData,
2624 (ClientData) plFramePtr );
2625#endif
2626#endif
2627
2628 return TCL_OK;
2629}
2630
2631//--------------------------------------------------------------------------
2632// Closelink
2633//
2634// Processes "closelink" widget command.
2635// CLoses channel previously opened with the "openlink" widget command.
2636//--------------------------------------------------------------------------
2637
2638static int
2639Closelink( Tcl_Interp *interp, register PlFrame *plFramePtr,
2640 int PL_UNUSED( argc ), const char ** PL_UNUSED( argv ) )
2641{
2642 register PLRDev *plr = plFramePtr->plr;
2643 register PLiodev *iodev = plr->iodev;
2644
2645 dbug_enter( "Closelink" );
2646
2647 if ( iodev->fd == 0 )
2648 {
2649 Tcl_AppendResult( interp, "no link currently open", (char *) NULL );
2650 return TCL_ERROR;
2651 }
2652
2653#if TK_MAJOR_VERSION < 4 || \
2654 ( TK_MAJOR_VERSION == 4 && TK_MINOR_VERSION == 0 ) || \
2655 TK_MAJOR_VERSION > 7
2656#if !defined ( MAC_TCL ) && !defined ( _WIN32 ) && !defined ( __CYGWIN__ )
2657 Tk_DeleteFileHandler( iodev->fd );
2658#endif
2659#else
2660// Tk_DeleteFileHandler( iodev->file );
2661#if !defined ( MAC_TCL ) && !defined ( _WIN32 ) && !defined ( __CYGWIN__ )
2662 Tcl_DeleteFileHandler( Tcl_GetFile( (ClientData) iodev->fd,
2663 TCL_UNIX_FD ) );
2664#endif
2665#endif
2666 pdf_close( plr->pdfs );
2667 iodev->fd = 0;
2668
2669 return TCL_OK;
2670}
2671
2672//--------------------------------------------------------------------------
2673// process_data
2674//
2675// Utility function for processing data and other housekeeping.
2676//--------------------------------------------------------------------------
2677
2678static int
2679process_data( Tcl_Interp *interp, register PlFrame *plFramePtr )
2680{
2681 register PLRDev *plr = plFramePtr->plr;
2682 register PLiodev *iodev = plr->iodev;
2683 int result = TCL_OK;
2684
2685// Process data
2686
2687 if ( plr_process( plr ) == -1 )
2688 {
2689 Tcl_AppendResult( interp, "unable to read from ", iodev->typeName,
2690 (char *) NULL );
2691 result = TCL_ERROR;
2692 }
2693
2694// Signal bop if necessary
2695
2696 if ( plr->at_bop && plFramePtr->bopCmd != NULL )
2697 {
2698 plr->at_bop = 0;
2699 if ( Tcl_Eval( interp, plFramePtr->bopCmd ) != TCL_OK )
2700 fprintf( stderr, "Command \"%s\" failed:\n\t %s\n",
2701 plFramePtr->bopCmd, Tcl_GetStringResult( interp ) );
2702 }
2703
2704// Signal eop if necessary
2705
2706 if ( plr->at_eop && plFramePtr->eopCmd != NULL )
2707 {
2708 plr->at_eop = 0;
2709 if ( Tcl_Eval( interp, plFramePtr->eopCmd ) != TCL_OK )
2710 fprintf( stderr, "Command \"%s\" failed:\n\t %s\n",
2711 plFramePtr->eopCmd, Tcl_GetStringResult( interp ) );
2712 }
2713
2714 return result;
2715}
2716
2717//--------------------------------------------------------------------------
2718// ReadData
2719//
2720// Reads & processes data.
2721// Intended to be installed as a filehandler command.
2722//--------------------------------------------------------------------------
2723
2724static int
2725ReadData( ClientData clientData, int mask )
2726{
2727 register PlFrame *plFramePtr = (PlFrame *) clientData;
2728 register Tcl_Interp *interp = plFramePtr->interp;
2729
2730 register PLRDev *plr = plFramePtr->plr;
2731 register PLiodev *iodev = plr->iodev;
2732 register PDFstrm *pdfs = plr->pdfs;
2733 int result = TCL_OK;
2734
2735 if ( mask & TK_READABLE )
2736 {
2737 // Read from FIFO or socket
2738
2739 plsstrm( plFramePtr->ipls );
2740 if ( pl_PacketReceive( interp, iodev, pdfs ) )
2741 {
2742 Tcl_AppendResult( interp, "Packet receive failed:\n\t %s\n",
2743 (char *) NULL );
2744 return TCL_ERROR;
2745 }
2746
2747 // If the packet isn't complete it will be put back and we just return.
2748 // Otherwise, the buffer pointer is saved and then cleared so that reads
2749 // from the buffer start at the beginning.
2750 //
2751 if ( pdfs->bp == 0 )
2752 return TCL_OK;
2753
2754 plr->nbytes = (int) pdfs->bp;
2755 pdfs->bp = 0;
2756 result = process_data( interp, plFramePtr );
2757 }
2758
2759 return result;
2760}
2761
2762//--------------------------------------------------------------------------
2763// Orient
2764//
2765// Processes "orient" widget command.
2766// Handles orientation of plot.
2767//--------------------------------------------------------------------------
2768
2769static int
2770Orient( Tcl_Interp *interp, register PlFrame *plFramePtr,
2771 int argc, const char **argv )
2772{
2773 int result = TCL_OK;
2774
2775// orient -- return orientation of current plot window
2776
2777 plsstrm( plFramePtr->ipls );
2778
2779 if ( argc == 0 )
2780 {
2781 PLFLT rot;
2782 char result_str[128];
2783 plgdiori( &rot );
2784 sprintf( result_str, "%f", rot );
2785 Tcl_SetResult( interp, result_str, TCL_VOLATILE );
2786 }
2787
2788// orient <rot> -- Set orientation to <rot>
2789
2790 else
2791 {
2792 plsdiori( atof( argv[0] ) );
2793 result = Redraw( interp, plFramePtr, argc - 1, argv + 1 );
2794 }
2795
2796 return result;
2797}
2798
2799//--------------------------------------------------------------------------
2800// Print
2801//
2802// Processes "print" widget command.
2803// Handles printing of plot, duh.
2804//
2805// Creates a temporary file, dumps the current plot to it in metafile
2806// form, and then execs the "plpr" script to actually print it. Since we
2807// output it in metafile form here, plpr must invoke plrender to drive the
2808// output to the appropriate file type. The script is responsible for the
2809// deletion of the plot metafile.
2810//--------------------------------------------------------------------------
2811
2812static int
2813Print( Tcl_Interp *interp, register PlFrame *plFramePtr,
2814 int PL_UNUSED( argc ), const char ** PL_UNUSED( argv ) )
2815{
2816 PLINT ipls;
2817 int result = TCL_OK;
2818 char *sfnam;
2819 FILE *sfile;
2820 pid_t pid;
2821
2822// Make sure widget has been initialized before going any further
2823
2824 if ( !plFramePtr->tkwin_initted )
2825 {
2826 Tcl_AppendResult( interp, "Error -- widget not plotted to yet",
2827 (char *) NULL );
2828 return TCL_ERROR;
2829 }
2830
2831// Create stream for save
2832
2833 plmkstrm( &ipls );
2834 if ( ipls < 0 )
2835 {
2836 Tcl_AppendResult( interp, "Error -- cannot create stream",
2837 (char *) NULL );
2838 return TCL_ERROR;
2839 }
2840
2841// Open file for writes
2842 sfnam = NULL;
2843
2844 // Create and open temporary file
2845 if ( ( sfile = pl_create_tempfile( &sfnam ) ) == NULL )
2846 {
2847 Tcl_AppendResult( interp,
2848 "Error -- cannot open plot file for writing",
2849 (char *) NULL );
2850 plend1();
2851 if ( sfnam != NULL )
2852 free( sfnam );
2853 return TCL_ERROR;
2854 }
2855
2856// Initialize stream
2857
2858 plsdev( "plmeta" );
2859 plsfile( sfile );
2860// FIXME: plmeta/plrender need to honor these, needed to preserve the aspect ratio
2861 plspage( 0., 0., plFramePtr->width, plFramePtr->height, 0, 0 );
2862 plcpstrm( plFramePtr->ipls, 0 );
2863 pladv( 0 );
2864
2865// Remake current plot, close file, and switch back to original stream
2866
2867 plreplot();
2868 plend1();
2869 plsstrm( plFramePtr->ipls );
2870
2871// So far so good. Time to exec the print script.
2872
2873 if ( plFramePtr->plpr_cmd == NULL )
2874 plFramePtr->plpr_cmd = plFindCommand( "plpr" );
2875
2876#if !defined ( _WIN32 )
2877 if ( ( plFramePtr->plpr_cmd == NULL ) || ( pid = fork() ) < 0 )
2878#else
2879 if ( 1 )
2880#endif
2881 {
2882 Tcl_AppendResult( interp,
2883 "Error -- cannot fork print process",
2884 (char *) NULL );
2885 result = TCL_ERROR;
2886 }
2887 else if ( pid == 0 )
2888 {
2889#if !defined ( _WIN32 )
2890 if ( execl( plFramePtr->plpr_cmd, plFramePtr->plpr_cmd, sfnam,
2891 (char *) 0 ) )
2892#else
2893 if ( 1 )
2894#endif
2895 {
2896 fprintf( stderr, "Unable to exec print command.\n" );
2897 free( sfnam );
2898 _exit( 1 );
2899 }
2900 }
2901
2902 free( sfnam );
2903
2904 return result;
2905}
2906
2907//--------------------------------------------------------------------------
2908// Page
2909//
2910// Processes "page" widget command.
2911// Handles parameters such as margin, aspect ratio, and justification
2912// of final plot.
2913//--------------------------------------------------------------------------
2914
2915static int
2916Page( Tcl_Interp *interp, register PlFrame *plFramePtr,
2917 int argc, const char **argv )
2918{
2919// page -- return current device window parameters
2920
2921 plsstrm( plFramePtr->ipls );
2922
2923 if ( argc == 0 )
2924 {
2925 PLFLT mar, aspect, jx, jy;
2926 char result_str[128];
2927
2928 plgdidev( &mar, &aspect, &jx, &jy );
2929 sprintf( result_str, "%g %g %g %g", mar, aspect, jx, jy );
2930 Tcl_SetResult( interp, result_str, TCL_VOLATILE );
2931 return TCL_OK;
2932 }
2933
2934// page <mar> <aspect> <jx> <jy> -- set up page
2935
2936 if ( argc < 4 )
2937 {
2938 Tcl_AppendResult( interp, "wrong # args: should be \"",
2939 " page mar aspect jx jy\"", (char *) NULL );
2940 return TCL_ERROR;
2941 }
2942
2943 plsdidev( atof( argv[0] ), atof( argv[1] ), atof( argv[2] ), atof( argv[3] ) );
2944 return ( Redraw( interp, plFramePtr, argc - 1, argv + 1 ) );
2945}
2946
2947//--------------------------------------------------------------------------
2948// Redraw
2949//
2950// Processes "redraw" widget command.
2951// Turns loose a DoWhenIdle command to redraw plot by replaying contents
2952// of plot buffer.
2953//--------------------------------------------------------------------------
2954
2955static int
2956Redraw( Tcl_Interp *PL_UNUSED( interp ), register PlFrame *plFramePtr,
2957 int PL_UNUSED( argc ), const char ** PL_UNUSED( argv ) )
2958{
2959 dbug_enter( "Redraw" );
2960
2961 plFramePtr->flags |= REDRAW_PENDING;
2962 if ( ( plFramePtr->tkwin != NULL ) &&
2963 !( plFramePtr->flags & REFRESH_PENDING ) )
2964 {
2965 Tk_DoWhenIdle( DisplayPlFrame, (ClientData) plFramePtr );
2966 plFramePtr->flags |= REFRESH_PENDING;
2967 }
2968
2969 return TCL_OK;
2970}
2971
2972//--------------------------------------------------------------------------
2973// Save
2974//
2975// Processes "save" widget command.
2976// Saves plot to a file.
2977//--------------------------------------------------------------------------
2978
2979static int
2980Save( Tcl_Interp *interp, register PlFrame *plFramePtr,
2981 int argc, const char **argv )
2982{
2983 int length;
2984 char c;
2985 FILE *sfile;
2986
2987// Make sure widget has been initialized before going any further
2988
2989 if ( !plFramePtr->tkwin_initted )
2990 {
2991 Tcl_AppendResult( interp, "Error -- widget not plotted to yet",
2992 (char *) NULL );
2993 return TCL_ERROR;
2994 }
2995
2996// save -- save to already open file
2997
2998 if ( argc == 0 )
2999 {
3000 if ( !plFramePtr->ipls_save )
3001 {
3002 Tcl_AppendResult( interp, "Error -- no current save file",
3003 (char *) NULL );
3004 return TCL_ERROR;
3005 }
3006 plsstrm( plFramePtr->ipls_save );
3007 // Note: many drivers ignore these, needed to preserve the aspect ratio
3008 plspage( 0., 0., plFramePtr->width, plFramePtr->height, 0, 0 );
3009 plcpstrm( plFramePtr->ipls, 0 );
3010 pladv( 0 );
3011 plreplot();
3012 plflush();
3013 plsstrm( plFramePtr->ipls );
3014 return TCL_OK;
3015 }
3016
3017 c = argv[0][0];
3018 length = (int) strlen( argv[0] );
3019
3020// save to specified device & file
3021
3022 if ( ( c == 'a' ) && ( strncmp( argv[0], "as", (size_t) length ) == 0 ) )
3023 {
3024 if ( argc < 3 )
3025 {
3026 Tcl_AppendResult( interp, "wrong # args: should be \"",
3027 " save as device file\"", (char *) NULL );
3028 return TCL_ERROR;
3029 }
3030
3031 // If save previously in effect, delete old stream
3032
3033 if ( plFramePtr->ipls_save )
3034 {
3035 plsstrm( plFramePtr->ipls_save );
3036 plend1();
3037 }
3038
3039 // Create stream for saves to selected device & file
3040
3041 plmkstrm( &plFramePtr->ipls_save );
3042 if ( plFramePtr->ipls_save < 0 )
3043 {
3044 Tcl_AppendResult( interp, "Error -- cannot create stream",
3045 (char *) NULL );
3046 plFramePtr->ipls_save = 0;
3047 return TCL_ERROR;
3048 }
3049
3050 // Open file for writes
3051
3052 if ( ( sfile = fopen( argv[2], "wb+" ) ) == NULL )
3053 {
3054 Tcl_AppendResult( interp, "Error -- cannot open file ", argv[2],
3055 " for writing", (char *) NULL );
3056 plFramePtr->ipls_save = 0;
3057 plend1();
3058 return TCL_ERROR;
3059 }
3060
3061 // Initialize stream
3062
3063 plsdev( argv[1] );
3064 plsfile( sfile );
3065 // Note: many drivers ignore these, needed to preserve the aspect ratio
3066 plspage( 0., 0., plFramePtr->width, plFramePtr->height, 0, 0 );
3067 plcpstrm( plFramePtr->ipls, 0 );
3068 pladv( 0 );
3069
3070 // Remake current plot and then switch back to original stream
3071
3072 plreplot();
3073 plflush();
3074 plsstrm( plFramePtr->ipls );
3075 }
3076
3077// close save file
3078
3079 else if ( ( c == 'c' ) && ( strncmp( argv[0], "close", (size_t) length ) == 0 ) )
3080 {
3081 if ( !plFramePtr->ipls_save )
3082 {
3083 Tcl_AppendResult( interp, "Error -- no current save file",
3084 (char *) NULL );
3085 return TCL_ERROR;
3086 }
3087 else
3088 {
3089 plsstrm( plFramePtr->ipls_save );
3090 plend1();
3091 plFramePtr->ipls_save = 0;
3092 plsstrm( plFramePtr->ipls );
3093 }
3094 }
3095
3096// unrecognized
3097
3098 else
3099 {
3100 Tcl_AppendResult( interp, "bad option to \"save\": must be ",
3101 "as or close", (char *) NULL );
3102
3103 return TCL_ERROR;
3104 }
3105
3106 return TCL_OK;
3107}
3108
3109//--------------------------------------------------------------------------
3110// View
3111//
3112// Processes "view" widget command.
3113// Handles translation & scaling of view into plot.
3114//--------------------------------------------------------------------------
3115
3116static int
3117View( Tcl_Interp *interp, register PlFrame *plFramePtr,
3118 int argc, const char **argv )
3119{
3120 int length;
3121 char c;
3122 PLFLT xl, xr, yl, yr;
3123
3124// view -- return current relative plot window coordinates
3125
3126 plsstrm( plFramePtr->ipls );
3127
3128 if ( argc == 0 )
3129 {
3130 char result_str[128];
3131 plgdiplt( &xl, &yl, &xr, &yr );
3132 sprintf( result_str, "%g %g %g %g", xl, yl, xr, yr );
3133 Tcl_SetResult( interp, result_str, TCL_VOLATILE );
3134 return TCL_OK;
3135 }
3136
3137 c = argv[0][0];
3138 length = (int) strlen( argv[0] );
3139
3140// view bounds -- return relative device coordinates of bounds on current
3141// plot window
3142
3143 if ( ( c == 'b' ) && ( strncmp( argv[0], "bounds", (size_t) length ) == 0 ) )
3144 {
3145 char result_str[128];
3146 xl = 0.; yl = 0.;
3147 xr = 1.; yr = 1.;
3148 pldip2dc( &xl, &yl, &xr, &yr );
3149 sprintf( result_str, "%g %g %g %g", xl, yl, xr, yr );
3150 Tcl_SetResult( interp, result_str, TCL_VOLATILE );
3151 return TCL_OK;
3152 }
3153
3154// view reset -- Resets plot
3155
3156 if ( ( c == 'r' ) && ( strncmp( argv[0], "reset", (size_t) length ) == 0 ) )
3157 {
3158 xl = 0.; yl = 0.;
3159 xr = 1.; yr = 1.;
3160 plsdiplt( xl, yl, xr, yr );
3161 }
3162
3163// view select -- set window into plot space
3164// Specifies in terms of plot window coordinates, not device coordinates
3165
3166 else if ( ( c == 's' ) && ( strncmp( argv[0], "select", (size_t) length ) == 0 ) )
3167 {
3168 if ( argc < 5 )
3169 {
3170 Tcl_AppendResult( interp, "wrong # args: should be \"",
3171 " view select xmin ymin xmax ymax\"",
3172 (char *) NULL );
3173 return TCL_ERROR;
3174 }
3175 else
3176 {
3177 gbox( &xl, &yl, &xr, &yr, argv + 1 );
3178 plsdiplt( xl, yl, xr, yr );
3179 }
3180 }
3181
3182// view zoom -- set window into plot space incrementally (zoom)
3183// Here we need to take the page (device) offsets into account
3184
3185 else if ( ( c == 'z' ) && ( strncmp( argv[0], "zoom", (size_t) length ) == 0 ) )
3186 {
3187 if ( argc < 5 )
3188 {
3189 Tcl_AppendResult( interp, "wrong # args: should be \"",
3190 " view zoom xmin ymin xmax ymax\"",
3191 (char *) NULL );
3192 return TCL_ERROR;
3193 }
3194 else
3195 {
3196 gbox( &xl, &yl, &xr, &yr, argv + 1 );
3197 pldid2pc( &xl, &yl, &xr, &yr );
3198 plsdiplz( xl, yl, xr, yr );
3199 }
3200 }
3201
3202// unrecognized
3203
3204 else
3205 {
3206 Tcl_AppendResult( interp, "bad option \"", argv[1],
3207 "\": options to \"view\" are: bounds, reset, select, or zoom",
3208 (char *) NULL );
3209
3210 return TCL_ERROR;
3211 }
3212
3213// Update plot window bounds and arrange for plot to be updated
3214
3215 plgdiplt( &xl, &yl, &xr, &yr );
3216 plFramePtr->xl = xl;
3217 plFramePtr->yl = yl;
3218 plFramePtr->xr = xr;
3219 plFramePtr->yr = yr;
3220 plFramePtr->flags |= UPDATE_V_SCROLLBAR | UPDATE_H_SCROLLBAR;
3221
3222 return ( Redraw( interp, plFramePtr, argc, argv ) );
3223}
3224
3225//--------------------------------------------------------------------------
3226// xScroll
3227//
3228// Processes "xscroll" widget command.
3229// Handles horizontal scroll-bar invoked translation of view into plot.
3230//--------------------------------------------------------------------------
3231
3232static int
3233xScroll( Tcl_Interp *interp, register PlFrame *plFramePtr,
3234 int argc, const char **argv )
3235{
3236 int x0, width = Tk_Width( plFramePtr->tkwin );
3237 PLFLT xl, xr, yl, yr, xlen;
3238
3239 plsstrm( plFramePtr->ipls );
3240
3241 xlen = plFramePtr->xr - plFramePtr->xl;
3242 x0 = atoi( argv[0] );
3243 xl = x0 / (double) width;
3244 xl = MAX( 0., MIN( ( 1. - xlen ), xl ) );
3245 xr = xl + xlen;
3246
3247 yl = plFramePtr->yl;
3248 yr = plFramePtr->yr;
3249
3250 plFramePtr->xl = xl;
3251 plFramePtr->xr = xr;
3252
3253 plsdiplt( xl, yl, xr, yr );
3254
3255 plFramePtr->flags |= UPDATE_V_SCROLLBAR | UPDATE_H_SCROLLBAR;
3256 return ( Redraw( interp, plFramePtr, argc, argv ) );
3257}
3258
3259//--------------------------------------------------------------------------
3260// yScroll
3261//
3262// Processes "yscroll" widget command.
3263// Handles vertical scroll-bar invoked translation of view into plot.
3264//--------------------------------------------------------------------------
3265
3266static int
3267yScroll( Tcl_Interp *interp, register PlFrame *plFramePtr,
3268 int argc, const char **argv )
3269{
3270 int y0, height = Tk_Height( plFramePtr->tkwin );
3271 PLFLT xl, xr, yl, yr, ylen;
3272
3273 plsstrm( plFramePtr->ipls );
3274
3275 ylen = plFramePtr->yr - plFramePtr->yl;
3276 y0 = atoi( argv[0] );
3277 yr = 1. - y0 / (double) height;
3278 yr = MAX( 0. + ylen, MIN( 1., yr ) );
3279 yl = yr - ylen;
3280
3281 xl = plFramePtr->xl;
3282 xr = plFramePtr->xr;
3283
3284 plFramePtr->yl = yl;
3285 plFramePtr->yr = yr;
3286
3287 plsdiplt( xl, yl, xr, yr );
3288
3289 plFramePtr->flags |= UPDATE_V_SCROLLBAR | UPDATE_H_SCROLLBAR;
3290 return ( Redraw( interp, plFramePtr, argc, argv ) );
3291}
3292
3293//--------------------------------------------------------------------------
3294// report
3295//
3296// 4/17/95 GMF
3297// Processes "report" widget command.
3298//--------------------------------------------------------------------------
3299
3300static int
3301report( Tcl_Interp *interp, register PlFrame *plFramePtr,
3302 int argc, const char **argv )
3303{
3304 PLFLT x, y;
3305 char tmpstring[50];
3306// fprintf( stdout, "Made it into report, argc=%d\n", argc );
3307
3308 if ( argc == 0 )
3309 {
3310 Tcl_SetResult( interp, "report what?", TCL_STATIC );
3311 return TCL_ERROR;
3312 }
3313
3314 if ( !strcmp( argv[0], "wc" ) )
3315 {
3316 XwDev *dev = (XwDev *) plFramePtr->pls->dev;
3317 PLGraphicsIn *gin = &( dev->gin );
3318
3319 if ( argc != 3 )
3320 {
3321 Tcl_SetResult( interp, "Wrong # of args: report wc x y", TCL_STATIC );
3322 return TCL_ERROR;
3323 }
3324
3325 x = atof( argv[1] );
3326 y = atof( argv[2] );
3327
3328 gin->dX = (PLFLT) x / ( dev->width - 1 );
3329 gin->dY = 1.0 - (PLFLT) y / ( dev->height - 1 );
3330
3331 // Try to locate cursor
3332
3333 if ( plTranslateCursor( gin ) )
3334 {
3335 snprintf( tmpstring, 50, "%f %f", gin->wX, gin->wY );
3336 Tcl_SetResult( interp, tmpstring, TCL_VOLATILE );
3337 return TCL_OK;
3338 }
3339
3340 Tcl_SetResult( interp, "Cannot locate", TCL_STATIC );
3341 return TCL_OK;
3342 }
3343
3344 Tcl_SetResult( interp, "nonsensical request.", TCL_STATIC );
3345 return TCL_ERROR;
3346}
3347
3348//--------------------------------------------------------------------------
3349// Custom bop handler.
3350// Mostly for support of multi-page Tcl scripts from plserver.
3351//--------------------------------------------------------------------------
3352
3353static void
3354process_bop( void *clientData, int * PL_UNUSED( skip_driver_bop ) )
3355{
3356 register PlFrame *plFramePtr = (PlFrame *) clientData;
3357
3358 if ( Tcl_Eval( plFramePtr->interp, plFramePtr->bopCmd ) != TCL_OK )
3359 fprintf( stderr, "Command \"%s\" failed:\n\t %s\n",
3360 plFramePtr->bopCmd, Tcl_GetStringResult( plFramePtr->interp ) );
3361}
3362
3363//--------------------------------------------------------------------------
3364// Custom eop handler.
3365// Mostly for support of multi-page Tcl scripts from plserver.
3366//--------------------------------------------------------------------------
3367
3368static void
3369process_eop( void *clientData, int * PL_UNUSED( skip_driver_eop ) )
3370{
3371 register PlFrame *plFramePtr = (PlFrame *) clientData;
3372
3373 if ( Tcl_Eval( plFramePtr->interp, plFramePtr->eopCmd ) != TCL_OK )
3374 fprintf( stderr, "Command \"%s\" failed:\n\t %s\n",
3375 plFramePtr->eopCmd, Tcl_GetStringResult( plFramePtr->interp ) );
3376}
3377
3378//--------------------------------------------------------------------------
3379// Utility routines
3380//--------------------------------------------------------------------------
3381
3382//--------------------------------------------------------------------------
3383// UpdateVScrollbar
3384//
3385// Updates vertical scrollbar if needed.
3386//--------------------------------------------------------------------------
3387
3388static void
3389UpdateVScrollbar( register PlFrame *plFramePtr )
3390{
3391 int height = Tk_Height( plFramePtr->tkwin );
3392 char string[60];
3393 int totalUnits, windowUnits, firstUnit, lastUnit, result;
3394
3395 if ( plFramePtr->yScrollCmd == NULL )
3396 return;
3397
3398 totalUnits = height;
3399 firstUnit = (int) ( 0.5 + (PLFLT) height * ( 1. - plFramePtr->yr ) );
3400 lastUnit = (int) ( 0.5 + (PLFLT) height * ( 1. - plFramePtr->yl ) );
3401 windowUnits = lastUnit - firstUnit;
3402 sprintf( string, " %d %d %d %d",
3403 totalUnits, windowUnits, firstUnit, lastUnit );
3404
3405 result = Tcl_VarEval( plFramePtr->interp, plFramePtr->yScrollCmd, string,
3406 (char *) NULL );
3407
3408 if ( result != TCL_OK )
3409 {
3410 Tk_BackgroundError( plFramePtr->interp );
3411 }
3412}
3413
3414//--------------------------------------------------------------------------
3415// UpdateHScrollbar
3416//
3417// Updates horizontal scrollbar if needed.
3418//--------------------------------------------------------------------------
3419
3420static void
3421UpdateHScrollbar( register PlFrame *plFramePtr )
3422{
3423 int width = Tk_Width( plFramePtr->tkwin );
3424 char string[60];
3425 int totalUnits, windowUnits, firstUnit, lastUnit, result;
3426
3427 if ( plFramePtr->xScrollCmd == NULL )
3428 return;
3429
3430 totalUnits = width;
3431 firstUnit = (int) ( 0.5 + (PLFLT) width * plFramePtr->xl );
3432 lastUnit = (int) ( 0.5 + (PLFLT) width * plFramePtr->xr );
3433 windowUnits = lastUnit - firstUnit;
3434 sprintf( string, " %d %d %d %d",
3435 totalUnits, windowUnits, firstUnit, lastUnit );
3436
3437 result = Tcl_VarEval( plFramePtr->interp, plFramePtr->xScrollCmd, string,
3438 (char *) NULL );
3439
3440 if ( result != TCL_OK )
3441 {
3442 Tk_BackgroundError( plFramePtr->interp );
3443 }
3444}
3445
3446//--------------------------------------------------------------------------
3447// gbox
3448//
3449// Returns selection box coordinates. It's best if the TCL script does
3450// bounds checking on the input but I do it here as well just to be safe.
3451//--------------------------------------------------------------------------
3452
3453static void
3454gbox( PLFLT *xl, PLFLT *yl, PLFLT *xr, PLFLT *yr, const char **argv )
3455{
3456 PLFLT x0, y0, x1, y1;
3457
3458 x0 = atof( argv[0] );
3459 y0 = atof( argv[1] );
3460 x1 = atof( argv[2] );
3461 y1 = atof( argv[3] );
3462
3463 x0 = MAX( 0., MIN( 1., x0 ) );
3464 y0 = MAX( 0., MIN( 1., y0 ) );
3465 x1 = MAX( 0., MIN( 1., x1 ) );
3466 y1 = MAX( 0., MIN( 1., y1 ) );
3467
3468// Only need two vertices, pick the lower left and upper right
3469
3470 *xl = MIN( x0, x1 );
3471 *yl = MIN( y0, y1 );
3472 *xr = MAX( x0, x1 );
3473 *yr = MAX( y0, y1 );
3474}
#define b1
Definition defines.h:18
#define MIN(a, b)
Definition dsplint.c:29
#define MAX(a, b)
Definition dsplint.c:28
int pdf_close(PDFstrm *pdfs)
Definition pdfutils.c:238
PDFstrm * pdf_bopen(U_CHAR *buffer, size_t bufmax)
Definition pdfutils.c:152
void pllib_init()
Definition plcore.c:2262
void plP_state(PLINT op)
Definition plcore.c:256
void pldip2dc(PLFLT *xmin, PLFLT *ymin, PLFLT *xmax, PLFLT *ymax)
Definition plcore.c:1737
void plgpls(PLStream **p_pls)
Definition plcore.c:3693
void pl_cpcolor(PLColor *to, PLColor *from)
Definition plcore.c:2738
void plsxwin(PLINT window_id)
Definition plcore.c:3978
void plsfile(FILE *file)
Definition plcore.c:3802
void plsbopH(void(*handler)(void *, int *), void *handler_data)
Definition plcore.c:3735
void pldid2pc(PLFLT *xmin, PLFLT *ymin, PLFLT *xmax, PLFLT *ymax)
Definition plcore.c:1691
void plseopH(void(*handler)(void *, int *), void *handler_data)
Definition plcore.c:3744
void plP_esc(PLINT op, void *ptr)
Definition plcore.c:273
void plgFileDevs(const char ***p_menustr, const char ***p_devname, int *p_ndev)
Definition plcore.c:3530
void pllib_devinit()
Definition plcore.c:2874
static PLStream * pls[PL_NSTREAMS]
Definition plcore.h:88
static PLINT ipls
Definition plcore.h:86
void plcmap1_calc(void)
Bin up cmap 1 space and assign colors to make inverse mapping easy.
Definition plctrl.c:764
char * plFindCommand(PLCHAR_VECTOR fn)
Definition plctrl.c:2146
void pl_cmd(PLINT op, void *ptr)
Definition plctrl.c:2118
static int Save(Tcl_Interp *, PlFrame *, int, const char **)
#define FreeProcArg
Definition plframe.c:276
static void DrawRband(PlFrame *, int, int)
Definition plframe.c:1520
static int Page(Tcl_Interp *, PlFrame *, int, const char **)
static void PlFrameEnterEH(ClientData, register XEvent *)
Definition plframe.c:1107
static void UpdateXhairs(PlFrame *)
Definition plframe.c:1410
static void DisplayPlFrame(ClientData)
Definition plframe.c:1682
static int Orient(Tcl_Interp *, PlFrame *, int, const char **)
static void CreateXhairs(PlFrame *)
Definition plframe.c:1294
static int ConfigurePlFrame(Tcl_Interp *, PlFrame *, int, const char **, int)
static int Print(Tcl_Interp *, PlFrame *, int, const char **)
int plFrameCmd(ClientData, Tcl_Interp *, int, const char **)
static int xScroll(Tcl_Interp *, PlFrame *, int, const char **)
#define DEF_PLFRAME_CURSOR
Definition plframe.c:203
#define REDRAW_PENDING
Definition plframe.c:194
static void PlFrameInit(ClientData)
Definition plframe.c:1565
#define UPDATE_H_SCROLLBAR
Definition plframe.c:196
static void CreateRband(PlFrame *)
Definition plframe.c:1430
#define FILECAST
static int Info(Tcl_Interp *, PlFrame *, int, const char **)
static Tk_ConfigSpec configSpecs[]
Definition plframe.c:210
#define DEF_PLFRAME_HEIGHT
Definition plframe.c:204
static void UpdateHScrollbar(register PlFrame *)
Definition plframe.c:3421
static int report(Tcl_Interp *, PlFrame *, int, const char **)
static int View(Tcl_Interp *, PlFrame *, int, const char **)
#define UPDATE_V_SCROLLBAR
Definition plframe.c:195
static void UpdateRband(PlFrame *)
Definition plframe.c:1539
#define REFRESH_PENDING
Definition plframe.c:192
static void Install_cmap(PlFrame *plFramePtr)
Definition plframe.c:1632
static int ColorManip(Tcl_Interp *, PlFrame *, int, const char **)
static void DestroyXhairs(PlFrame *)
Definition plframe.c:1347
static int process_data(Tcl_Interp *interp, register PlFrame *plFramePtr)
Definition plframe.c:2679
static void PlFrameConfigureEH(ClientData, XEvent *)
static int Draw(Tcl_Interp *, PlFrame *, int, const char **)
static int Cmd(Tcl_Interp *, PlFrame *, int, const char **)
#define DEF_PLFRAME_BORDER_WIDTH
Definition plframe.c:202
static int scol1(Tcl_Interp *interp, register PlFrame *plFramePtr, int i, const char *col, const char *pos, const char *rev, int *p_changed)
Definition plframe.c:1862
#define DEF_PLFRAME_RELIEF
Definition plframe.c:205
static void PlFrameLeaveEH(ClientData, register XEvent *)
#define DEF_PLFRAME_BG_COLOR
Definition plframe.c:200
static int Closelink(Tcl_Interp *, PlFrame *, int, const char **)
static void gbox(PLFLT *, PLFLT *, PLFLT *, PLFLT *, const char **)
Definition plframe.c:3454
static int scol0(Tcl_Interp *interp, register PlFrame *plFramePtr, int i, const char *col, int *p_changed)
Definition plframe.c:1816
static void DestroyRband(PlFrame *)
Definition plframe.c:1489
static int Redraw(Tcl_Interp *, PlFrame *, int, const char **)
static void process_eop(void *, int *)
static void DestroyPlFrame(FreeProcArg)
Definition plframe.c:842
#define NDEV
Definition plframe.c:62
static int ReadData(ClientData, int)
Definition plframe.c:2725
#define RESIZE_PENDING
Definition plframe.c:193
static int yScroll(Tcl_Interp *, PlFrame *, int, const char **)
#define DEF_PLFRAME_BG_MONO
Definition plframe.c:201
#define Tk_Cursor
Definition plframe.c:80
static void UpdateVScrollbar(register PlFrame *)
Definition plframe.c:3389
static void PlFrameKeyEH(ClientData, register XEvent *)
Definition plframe.c:1183
static void PlFrameExposeEH(ClientData, XEvent *)
static void DrawXhairs(PlFrame *, int, int)
Definition plframe.c:1385
#define DEF_PLFRAME_WIDTH
Definition plframe.c:206
static void PlFrameMotionEH(ClientData, register XEvent *)
Definition plframe.c:1073
static int PlFrameWidgetCmd(ClientData, Tcl_Interp *, int, const char **)
Definition plframe.c:519
static int Openlink(Tcl_Interp *, PlFrame *, int, const char **)
static void process_bop(void *, int *)
PLINT plTranslateCursor(PLGraphicsIn *plg)
Definition plpage.c:259
#define PLSTATE_CMAP0
Definition plplotP.h:366
#define snprintf
Definition plplotP.h:235
#define PLESC_EXPOSE
Definition plplot.h:274
#define plgdiplt
Definition plplot.h:732
#define plinit
Definition plplot.h:755
#define PLESC_DOUBLEBUFFERING_QUERY
Definition plplot.h:578
#define PLESC_DEV2PLCOL
Definition plplot.h:294
float PLFLT
Definition plplot.h:163
#define plrgbhls
Definition plplot.h:789
#define plbop
Definition plplot.h:696
#define plgdidev
Definition plplot.h:730
#define PLESC_SETBGFG
Definition plplot.h:295
#define plgdiori
Definition plplot.h:731
#define plspause
Definition plplot.h:834
#define PLESC_DEVINIT
Definition plplot.h:296
#define plhlsrgb
Definition plplot.h:752
#define plsdev
Definition plplot.h:806
#define PL_UNUSED(x)
Definition plplot.h:138
#define plsdiplz
Definition plplot.h:811
#define plsdiori
Definition plplot.h:809
#define plspage
Definition plplot.h:831
#define PLESC_DOUBLEBUFFERING_DISABLE
Definition plplot.h:577
#define PLESC_RESIZE
Definition plplot.h:275
#define plsstrm
Definition plplot.h:835
#define plsdiplt
Definition plplot.h:810
#define plcpstrm
Definition plplot.h:707
#define plmkstrm
Definition plplot.h:772
#define pladv
Definition plplot.h:692
int PLINT
Definition plplot.h:181
#define plend1
Definition plplot.h:710
#define plsdidev
Definition plplot.h:807
#define PLESC_DOUBLEBUFFERING
Definition plplot.h:285
#define plflush
Definition plplot.h:719
#define plreplot
Definition plplot.h:788
#define PLESC_DOUBLEBUFFERING_ENABLE
Definition plplot.h:576
#define PLESC_REDRAW
Definition plplot.h:276
int plr_process(PLRDev *plr)
Definition plr.c:115
void plr_start(PLRDev *plr)
Definition plr.c:95
static int child
Definition plserver.c:45
FILE * pl_create_tempfile(char **fname)
Definition plstdio.c:240
PLDLLIMPEXP_TCLTK int plTclCmd(char *cmdlist, Tcl_Interp *interp, int argc, const char **argv)
Definition tclAPI.c:289
static int plplot_ccmap
Definition plxwd.h:37
static int argc
Definition qt.cpp:48
static char ** argv
Definition qt.cpp:49
Definition pdf.h:50
size_t bp
Definition pdf.h:56
PLINT cmd
Definition plplot.h:572
PLFLT wX
Definition plplot.h:443
PLFLT wY
Definition plplot.h:443
PLFLT dY
Definition plplot.h:442
PLFLT dX
Definition plplot.h:442
int at_eop
Definition plserver.h:22
int at_bop
Definition plserver.h:22
int nbytes
Definition plserver.h:21
PLiodev * iodev
Definition plserver.h:20
PDFstrm * pdfs
Definition plserver.h:19
Definition pdf.h:62
int fd
Definition pdf.h:63
int type
Definition pdf.h:67
FILE * file
Definition pdf.h:64
const char * fileHandle
Definition pdf.h:66
const char * typeName
Definition pdf.h:68
char * bopCmd
Definition plframe.c:161
XColor * bgColor
Definition plframe.c:127
Tcl_Interp * interp
Definition plframe.c:99
Tk_Cursor xhair_cursor
Definition plframe.c:150
int continue_draw
Definition plframe.c:149
char * eopCmd
Definition plframe.c:162
GC xorGC
Definition plframe.c:147
const char ** devDesc
Definition plframe.c:140
int relief
Definition plframe.c:108
int tkwin_initted
Definition plframe.c:121
char * SaveFnam
Definition plframe.c:138
const char ** devName
Definition plframe.c:142
PLRDev * plr
Definition plframe.c:126
int height
Definition plframe.c:111
Tk_Window tkwin
Definition plframe.c:92
int borderWidth
Definition plframe.c:107
Tk_Cursor cursor
Definition plframe.c:113
PLStream * pls
Definition plframe.c:122
int drawing_xhairs
Definition plframe.c:167
int xhairs
Definition plframe.c:166
int rband
Definition plframe.c:173
Display * display
Definition plframe.c:96
int prevHeight
Definition plframe.c:134
PLINT ipls_save
Definition plframe.c:124
int flags
Definition plframe.c:114
int width
Definition plframe.c:109
char * plpr_cmd
Definition plframe.c:128
int prevWidth
Definition plframe.c:133
char * xScrollCmd
Definition plframe.c:152
int drawing_rband
Definition plframe.c:174
char * yScrollCmd
Definition plframe.c:155
PLINT ipls
Definition plframe.c:123
Tk_3DBorder border
Definition plframe.c:105
PLFLT xl
Definition plframe.c:151
PLDisplay pldis
Definition plframe.c:132
Definition plxwd.h:68
unsigned width
Definition plxwd.h:82
XwDisplay * xwd
Definition plxwd.h:69
unsigned height
Definition plxwd.h:82
PLGraphicsIn gin
Definition plxwd.h:97
Colormap map
Definition plxwd.h:51
XColor * cmap0
Definition plxwd.h:58
#define dbug_enter(a)
Definition tclMatrix.c:59
PLDLLIMPEXP_TCLTK int pl_PacketReceive(Tcl_Interp *interp, PLiodev *iodev, PDFstrm *pdfs)
static Tcl_Interp * interp
Definition tkMain.c:120