diff options
Diffstat (limited to 'libgui/src')
-rw-r--r-- | libgui/src/Makefile.in | 9 | ||||
-rw-r--r-- | libgui/src/subcommand.c | 4 | ||||
-rw-r--r-- | libgui/src/tclgetdir.c | 6 | ||||
-rw-r--r-- | libgui/src/tclhelp.c | 43 | ||||
-rw-r--r-- | libgui/src/tclmain.c | 2 | ||||
-rw-r--r-- | libgui/src/tclmsgbox.c | 18 | ||||
-rw-r--r-- | libgui/src/tclsizebox.c | 4 | ||||
-rw-r--r-- | libgui/src/tclwinmode.c | 4 | ||||
-rw-r--r-- | libgui/src/tclwinpath.c | 4 | ||||
-rw-r--r-- | libgui/src/tclwinprint.c | 8 | ||||
-rw-r--r-- | libgui/src/tkCanvEdge.c | 21 | ||||
-rw-r--r-- | libgui/src/tkGraphCanvas.c | 6 | ||||
-rw-r--r-- | libgui/src/tkTable.tcl.h | 366 | ||||
-rw-r--r-- | libgui/src/tkTableCellSort.c | 400 | ||||
-rw-r--r-- | libgui/src/tkTableCmds.c | 1293 | ||||
-rw-r--r-- | libgui/src/tkTableEdit.c | 683 | ||||
-rw-r--r-- | libgui/src/tkTableInitScript.h | 90 | ||||
-rw-r--r-- | libgui/src/tkTablePs.c | 1299 | ||||
-rw-r--r-- | libgui/src/tkTableUtil.c | 340 | ||||
-rw-r--r-- | libgui/src/tkWinPrintCanvas.c | 14 | ||||
-rw-r--r-- | libgui/src/tkWinPrintText.c | 17 |
21 files changed, 4569 insertions, 62 deletions
diff --git a/libgui/src/Makefile.in b/libgui/src/Makefile.in index 637fa24f5d8..63e73211fdc 100644 --- a/libgui/src/Makefile.in +++ b/libgui/src/Makefile.in @@ -60,6 +60,7 @@ PRE_UNINSTALL = : POST_UNINSTALL = : host_alias = @host_alias@ host_triplet = @host@ +AR = @AR@ BFDHDIR = @BFDHDIR@ BFDLIB = @BFDLIB@ CC = @CC@ @@ -85,7 +86,6 @@ ITCLLIB = @ITCLLIB@ ITCLMKIDX = @ITCLMKIDX@ ITCLSH = @ITCLSH@ ITCL_BUILD_LIB_SPEC = @ITCL_BUILD_LIB_SPEC@ -ITCL_DIR = @ITCL_DIR@ ITCL_LIB_FILE = @ITCL_LIB_FILE@ ITCL_LIB_FULL_PATH = @ITCL_LIB_FULL_PATH@ ITCL_SH = @ITCL_SH@ @@ -110,6 +110,7 @@ SIMHDIR = @SIMHDIR@ SIMLIB = @SIMLIB@ TCLCONFIG = @TCLCONFIG@ TCLHDIR = @TCLHDIR@ +TCL_BIN_DIR = @TCL_BIN_DIR@ TCL_BUILD_LIB_SPEC = @TCL_BUILD_LIB_SPEC@ TCL_CFLAGS = @TCL_CFLAGS@ TCL_DEFS = @TCL_DEFS@ @@ -145,8 +146,7 @@ AUTOMAKE_OPTIONS = cygnus noinst_LIBRARIES = libgui.a -@INSTALL_LIBGUI_TRUE@include_HEADERS = \ -@INSTALL_LIBGUI_TRUE@\ +@INSTALL_LIBGUI_TRUE@include_HEADERS = @INSTALL_LIBGUI_TRUE@\ @INSTALL_LIBGUI_TRUE@ guitcl.h subcommand.h TBL_VERSION = 2.1 @@ -198,7 +198,6 @@ tclwinpath.$(OBJEXT) tclmsgbox.$(OBJEXT) tclcursor.$(OBJEXT) \ tkTable.$(OBJEXT) tkTableCmd.$(OBJEXT) tkTableCell.$(OBJEXT) \ tkTableTag.$(OBJEXT) tkTableWin.$(OBJEXT) tkWinPrintText.$(OBJEXT) \ tkWinPrintCanvas.$(OBJEXT) tkWarpPointer.$(OBJEXT) -AR = ar CFLAGS = @CFLAGS@ COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) @@ -210,7 +209,7 @@ DIST_COMMON = Makefile.am Makefile.in DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) -TAR = tar +TAR = gtar GZIP_ENV = --best SOURCES = $(libgui_a_SOURCES) OBJECTS = $(libgui_a_OBJECTS) diff --git a/libgui/src/subcommand.c b/libgui/src/subcommand.c index 29e7ea12f18..2ec51d339e6 100644 --- a/libgui/src/subcommand.c +++ b/libgui/src/subcommand.c @@ -26,7 +26,7 @@ subcommand_deleted (ClientData cd) if (data->delete) (*data->delete) (data->subdata); - Tcl_Free ((char *) data); + ckfree ((char *) data); } /* This function implements any Tcl command registered as having @@ -113,7 +113,7 @@ ide_create_command_with_subcommands (Tcl_Interp *interp, char *name, } } - data = (struct subcommand_clientdata *) Tcl_Alloc (sizeof *data); + data = (struct subcommand_clientdata *) ckalloc (sizeof *data); data->commands = table; data->subdata = subdata; data->delete = delete; diff --git a/libgui/src/tclgetdir.c b/libgui/src/tclgetdir.c index 7d70aef0012..f3b662f0dec 100644 --- a/libgui/src/tclgetdir.c +++ b/libgui/src/tclgetdir.c @@ -237,7 +237,7 @@ get_directory_command (ClientData cd, Tcl_Interp *interp, int argc, re-eval. This is a lot less efficient, but it doesn't really matter. */ - new_args = (char **) Tcl_Alloc ((argc + 2) * sizeof (char *)); + new_args = (char **) ckalloc ((argc + 2) * sizeof (char *)); new_args[0] = "tk_getOpenFile"; new_args[1] = "-choosedir"; @@ -249,8 +249,8 @@ get_directory_command (ClientData cd, Tcl_Interp *interp, int argc, merge = Tcl_Merge (argc + 2, new_args); result = Tcl_GlobalEval (interp, merge); - Tcl_Free (merge); - Tcl_Free ((char *) new_args); + ckfree (merge); + ckfree ((char *) new_args); return result; } diff --git a/libgui/src/tclhelp.c b/libgui/src/tclhelp.c index 199cff77d2e..d3f057a145e 100644 --- a/libgui/src/tclhelp.c +++ b/libgui/src/tclhelp.c @@ -109,12 +109,12 @@ help_command_deleted (ClientData cd) Tcl_DeleteExitHandler (help_command_atexit, cd); if (hdata->filename != NULL) - free (hdata->filename); + ckfree (hdata->filename); if (hdata->header_filename != NULL) - free (hdata->header_filename); + ckfree (hdata->header_filename); if (hdata->hash_initialized) Tcl_DeleteHashTable (&hdata->topic_hash); - Tcl_Free ((char *) hdata); + ckfree ((char *) hdata); } /* Initialize the help system: choose a window, and set up the topic @@ -223,8 +223,10 @@ help_initialize_command (ClientData cd, Tcl_Interp *interp, int argc, { struct help_command_data *hdata = (struct help_command_data *) cd; - hdata->filename = strdup (argv[2]); - hdata->header_filename = strdup (argv[3]); + hdata->filename = ckalloc (strlen (argv[2]) + 1); + strcpy (hdata->filename, argv[2]); + hdata->header_filename = ckalloc (strlen (argv[3]) + 1); + strcpy (hdata->header_filename, argv[3]); return TCL_OK; } @@ -301,7 +303,8 @@ help_display_file_command (ClientData cd, Tcl_Interp *interp, int argc, char **a { struct help_command_data *hdata = (struct help_command_data *) cd; FILE *e; - DWORD topic_id = 0; /* default topic id is 0 which brings up the find dialog */ + int id = 0; + DWORD topic_id; /* default topic id is 0 which brings up the find dialog */ /* We call Help initialize just to make sure the window handle is setup */ /* We don't care about the finding the main help file and checking the */ @@ -322,10 +325,11 @@ help_display_file_command (ClientData cd, Tcl_Interp *interp, int argc, char **a fclose (e); if (argc > 3) { - if ( Tcl_GetInt (interp, argv[3], &topic_id) != TCL_OK ) + if ( Tcl_GetInt (interp, argv[3], &id) != TCL_OK ) return TCL_ERROR; } + topic_id = (DWORD) id; if (! WinHelp (hdata->window, argv[2], HELP_CONTEXT, topic_id)) { char buf[200]; @@ -346,7 +350,7 @@ hdata_initialize () { struct help_command_data *hdata; - hdata = (struct help_command_data *) Tcl_Alloc (sizeof *hdata); + hdata = (struct help_command_data *) ckalloc (sizeof *hdata); hdata->filename = NULL; hdata->header_filename = NULL; @@ -387,14 +391,16 @@ help_command_deleted (ClientData cd) struct help_command_data *hdata = (struct help_command_data *) cd; if (hdata->filename != NULL) - free (hdata->filename); + ckfree (hdata->filename); if (hdata->header_filename != NULL) - free (hdata->header_filename); + ckfree (hdata->header_filename); + if (hdata->help_dir != NULL) + ckfree (hdata->help_dir); if (hdata->hash_initialized) Tcl_DeleteHashTable (&hdata->topic_hash); if (hdata->memory_block != NULL) - free (hdata->memory_block); - Tcl_Free ((char *) hdata); + ckfree (hdata->memory_block); + ckfree ((char *) hdata); } /* Implement the ide_help initialize command. */ @@ -405,9 +411,12 @@ help_initialize_command (ClientData cd, Tcl_Interp *interp, int argc, { struct help_command_data *hdata = (struct help_command_data *) cd; - hdata->filename = strdup (argv[2]); - hdata->header_filename = strdup (argv[3]); - hdata->help_dir = strdup (argv[4]); + hdata->filename = ckalloc (strlen (argv[2]) + 1); + strcpy (hdata->filename, argv[2]); + hdata->header_filename = ckalloc (strlen (argv[3]) + 1); + strcpy (hdata->header_filename, argv[3]); + hdata->help_dir = ckalloc (strlen (argv[4]) + 1); + strcpy (hdata->help_dir, argv[4]); return TCL_OK; } @@ -427,7 +436,7 @@ help_initialize (Tcl_Interp *interp, struct help_command_data *hdata) FILE *e; char buf[200], *block_start; - block_start = hdata->memory_block = malloc(6000); + block_start = hdata->memory_block = ckalloc(6000); e = fopen (hdata->header_filename, "r"); if (e == NULL) @@ -560,7 +569,7 @@ hdata_initialize () { struct help_command_data *hdata; - hdata = (struct help_command_data *) Tcl_Alloc (sizeof *hdata); + hdata = (struct help_command_data *) ckalloc (sizeof *hdata); hdata->filename = NULL; hdata->help_dir = NULL; diff --git a/libgui/src/tclmain.c b/libgui/src/tclmain.c index 1a962544998..28c2b8eb336 100644 --- a/libgui/src/tclmain.c +++ b/libgui/src/tclmain.c @@ -47,7 +47,7 @@ ide_main (int argc, char *argv[], Tcl_AppInitProc *appInitProc) args = Tcl_Merge (argc - 1, argv + 1); Tcl_SetVar (interp, "argv", args, TCL_GLOBAL_ONLY); - Tcl_Free (args); + ckfree (args); sprintf (buf, "%d", argc-1); Tcl_SetVar (interp, "argc", buf, TCL_GLOBAL_ONLY); diff --git a/libgui/src/tclmsgbox.c b/libgui/src/tclmsgbox.c index 8db081fb2a6..918363be0ae 100644 --- a/libgui/src/tclmsgbox.c +++ b/libgui/src/tclmsgbox.c @@ -155,7 +155,7 @@ msgbox_wndproc (HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) return DefWindowProc (hwnd, message, wparam, lparam); /* Queue up a Tcl event. */ - me = (struct msgbox_event *) Tcl_Alloc (sizeof *me); + me = (struct msgbox_event *) ckalloc (sizeof *me); me->header.proc = msgbox_eventproc; me->md = (struct msgbox_data *) lparam; Tcl_QueueEvent ((Tcl_Event *) me, TCL_QUEUE_TAIL); @@ -202,10 +202,10 @@ msgbox_eventproc (Tcl_Event *event, int flags) /* We are now done with the msgbox_data structure, so we can free the fields and the structure itself. */ - Tcl_Free (me->md->code); - Tcl_Free (me->md->message); - Tcl_Free (me->md->title); - Tcl_Free ((char *) me->md); + ckfree (me->md->code); + ckfree (me->md->message); + ckfree (me->md->title); + ckfree ((char *) me->md); if (ret != TCL_OK) Tcl_BackgroundError (me->md->interp); @@ -401,15 +401,15 @@ msgbox_internal (ClientData clientData, Tcl_Interp *interp, int argc, msgbox_init (); - md = (struct msgbox_data *) Tcl_Alloc (sizeof *md); + md = (struct msgbox_data *) ckalloc (sizeof *md); md->interp = interp; - md->code = Tcl_Alloc (strlen (code) + 1); + md->code = ckalloc (strlen (code) + 1); strcpy (md->code, code); md->hidden_hwnd = hidden_hwnd; md->hwnd = hWnd; - md->message = Tcl_Alloc (strlen (message) + 1); + md->message = ckalloc (strlen (message) + 1); strcpy (md->message, message); - md->title = Tcl_Alloc (strlen (title) + 1); + md->title = ckalloc (strlen (title) + 1); strcpy (md->title, title); md->flags = flags | modal; diff --git a/libgui/src/tclsizebox.c b/libgui/src/tclsizebox.c index 9a8d30559bf..c10e2e3f9c8 100644 --- a/libgui/src/tclsizebox.c +++ b/libgui/src/tclsizebox.c @@ -112,7 +112,7 @@ sizebox_event_proc (ClientData cd, XEvent *event_ptr) su = (struct sizebox_userdata *) GetWindowLong (hwnd, GWL_USERDATA); SetWindowLong (hwnd, GWL_USERDATA, 0); SetWindowLong (hwnd, GWL_WNDPROC, (LONG) su->wndproc); - Tcl_Free ((char *) su); + ckfree ((char *) su); DestroyWindow (hwnd); } } @@ -149,7 +149,7 @@ sizebox_create (Tk_Window tkwin, Window parent, ClientData cd) pt.x, pt.y, Tk_Width (tkwin), Tk_Height (tkwin), parhwnd, NULL, Tk_GetHINSTANCE (), NULL); - su = (struct sizebox_userdata *) Tcl_Alloc (sizeof *su); + su = (struct sizebox_userdata *) ckalloc (sizeof *su); su->tkwin = tkwin; su->wndproc = (WNDPROC) GetWindowLong (hwnd, GWL_WNDPROC); SetWindowLong (hwnd, GWL_USERDATA, (LONG) su); diff --git a/libgui/src/tclwinmode.c b/libgui/src/tclwinmode.c index 958d5c9c607..69c6c8082ef 100644 --- a/libgui/src/tclwinmode.c +++ b/libgui/src/tclwinmode.c @@ -61,11 +61,11 @@ seterrormode_command (ClientData cd, Tcl_Interp *interp, { Tcl_AppendResult (interp, "unrecognized key \"", list[i], "\"", (char *) NULL); - Tcl_Free ((char *) list); + ckfree ((char *) list); return TCL_ERROR; } } - Tcl_Free ((char *) list); + ckfree ((char *) list); val = SetErrorMode (val); diff --git a/libgui/src/tclwinpath.c b/libgui/src/tclwinpath.c index 2f9d5bdb612..ce75ab0dd7f 100644 --- a/libgui/src/tclwinpath.c +++ b/libgui/src/tclwinpath.c @@ -133,7 +133,7 @@ path_posix_to_win32_path_list (ClientData cd, Tcl_Interp *interp, int argc, char *buf; size = cygwin32_posix_to_win32_path_list_buf_size (argv[2]); - buf = Tcl_Alloc (size); + buf = ckalloc (size); cygwin32_posix_to_win32_path_list (argv[2], buf); Tcl_SetResult (interp, buf, TCL_DYNAMIC); return TCL_OK; @@ -149,7 +149,7 @@ path_win32_to_posix_path_list (ClientData cd, Tcl_Interp *interp, int argc, char *buf; size = cygwin32_win32_to_posix_path_list_buf_size (argv[2]); - buf = Tcl_Alloc (size); + buf = ckalloc (size); cygwin32_win32_to_posix_path_list (argv[2], buf); Tcl_SetResult (interp, buf, TCL_DYNAMIC); return TCL_OK; diff --git a/libgui/src/tclwinprint.c b/libgui/src/tclwinprint.c index 221cc14bf77..02843493511 100644 --- a/libgui/src/tclwinprint.c +++ b/libgui/src/tclwinprint.c @@ -126,10 +126,10 @@ winprint_command_deleted (ClientData cd) { /* FIXME: I don't know if we are supposed to free the hDevMode and hDevNames fields. */ - Tcl_Free ((char *) wd->page_setup); + ckfree ((char *) wd->page_setup); } - Tcl_Free ((char *) wd); + ckfree ((char *) wd); } /* Implement ide_winprint page_setup. */ @@ -216,7 +216,7 @@ winprint_page_setup_command (ClientData cd, Tcl_Interp *interp, int argc, } if (wd->page_setup == NULL) - wd->page_setup = (PAGESETUPDLG *) Tcl_Alloc (sizeof (PAGESETUPDLG)); + wd->page_setup = (PAGESETUPDLG *) ckalloc (sizeof (PAGESETUPDLG)); *wd->page_setup = psd; @@ -916,7 +916,7 @@ ide_create_winprint_command (Tcl_Interp *interp) { struct winprint_data *wd; - wd = (struct winprint_data *) Tcl_Alloc (sizeof *wd); + wd = (struct winprint_data *) ckalloc (sizeof *wd); wd->page_setup = NULL; wd->aborted = 0; diff --git a/libgui/src/tkCanvEdge.c b/libgui/src/tkCanvEdge.c index aa66702d768..a7977f0f904 100644 --- a/libgui/src/tkCanvEdge.c +++ b/libgui/src/tkCanvEdge.c @@ -179,8 +179,14 @@ static void TranslateEdge _ANSI_ARGS_((Tk_Canvas canvas, static Tk_CustomOption arrowShapeOption = { ParseArrowShape, PrintArrowShape, (ClientData) NULL}; -static Tk_CustomOption tagsOption = {Tk_CanvasTagsParseProc, - Tk_CanvasTagsPrintProc, (ClientData) NULL}; +/* + * The callbacks for tagsOption are initialized in ConfigureEdge() + */ + +static Tk_CustomOption tagsOption = +{ (Tk_OptionParseProc *) NULL, + (Tk_OptionPrintProc *) NULL, + (ClientData) NULL}; static Tk_ConfigSpec configSpecs[] = { {TK_CONFIG_UID, "-arrow", (char *) NULL, (char *) NULL, @@ -531,6 +537,17 @@ ConfigureEdge(interp, canvas, itemPtr, argc, argv, flags) tkwin = Tk_CanvasTkwin(canvas); bgBorder = ((TkCanvas *) canvas)->bgBorder; + /* + * Init callbacks in tagsOption before accessing configSpecs. + * This init can't be done statically when using Windows gcc + * since these symbols are imported from the Tk dll. + */ + + if (tagsOption.parseProc == NULL) { + tagsOption.parseProc = Tk_CanvasTagsParseProc; + tagsOption.printProc = Tk_CanvasTagsPrintProc; + } + if (Tk_ConfigureWidget(interp, tkwin, configSpecs, argc, argv, (char *) edgePtr, flags) != TCL_OK) { diff --git a/libgui/src/tkGraphCanvas.c b/libgui/src/tkGraphCanvas.c index c6ed1e71eef..eff3c6d8540 100644 --- a/libgui/src/tkGraphCanvas.c +++ b/libgui/src/tkGraphCanvas.c @@ -259,7 +259,8 @@ GetEdgeNodes(interp,canvasPtr,i,fp,tp) &argc, &argv) != TCL_OK) { return TCL_ERROR; } - *fp = strdup(argv[4]); + *fp = ckalloc (strlen (argv[4]) + 1); + strcpy(*fp, argv[4]); ckfree((char*)argv); /* Read the to node id of this edge. */ Tk_ConfigureInfo(interp, canvasPtr->tkwin, @@ -269,7 +270,8 @@ GetEdgeNodes(interp,canvasPtr,i,fp,tp) &argc, &argv) != TCL_OK) { return TCL_ERROR; } - *tp = strdup(argv[4]); + *tp = ckalloc(strlen (argv[4]) + 1); + strcpy(*tp, argv[4]); ckfree((char*)argv); Tcl_ResetResult(interp); return TCL_OK; diff --git a/libgui/src/tkTable.tcl.h b/libgui/src/tkTable.tcl.h new file mode 100644 index 00000000000..614106e98b5 --- /dev/null +++ b/libgui/src/tkTable.tcl.h @@ -0,0 +1,366 @@ +"proc tkTableClipboardKeysyms {copy cut paste} {\n" +" bind Table <$copy> {tk_tableCopy %W}\n" +" bind Table <$cut> {tk_tableCut %W}\n" +" bind Table <$paste> {tk_tablePaste %W}\n" +"}\n" +"bind Table <3> {\n" +" ## You might want to check for row returned if you want to\n" +" ## restrict the resizing of certain rows\n" +" %W border mark %x %y\n" +"}\n" +"bind Table <B3-Motion> { %W border dragto %x %y }\n" +"bind Table <1> {\n" +" if {[winfo exists %W]} {\n" +" tkTableBeginSelect %W [%W index @%x,%y]\n" +" focus %W\n" +" }\n" +"}\n" +"bind Table <B1-Motion> {\n" +" array set tkPriv {x %x y %y}\n" +" tkTableMotion %W [%W index @%x,%y]\n" +"}\n" +"bind Table <Double-1> {\n" +" # empty\n" +"}\n" +"bind Table <ButtonRelease-1> {\n" +" if {[winfo exists %W]} {\n" +" tkCancelRepeat\n" +" %W activate @%x,%y\n" +" }\n" +"}\n" +"bind Table <Shift-1> {tkTableBeginExtend %W [%W index @%x,%y]}\n" +"bind Table <Control-1> {tkTableBeginToggle %W [%W index @%x,%y]}\n" +"bind Table <B1-Enter> {tkCancelRepeat}\n" +"bind Table <B1-Leave> {\n" +" array set tkPriv {x %x y %y}\n" +" tkTableAutoScan %W\n" +"}\n" +"bind Table <2> {\n" +" %W scan mark %x %y\n" +" array set tkPriv {x %x y %y}\n" +" set tkPriv(mouseMoved) 0\n" +"}\n" +"bind Table <B2-Motion> {\n" +" if {(%x != $tkPriv(x)) || (%y != $tkPriv(y))} { set tkPriv(mouseMoved) 1 }\n" +" if $tkPriv(mouseMoved) { %W scan dragto %x %y }\n" +"}\n" +"bind Table <ButtonRelease-2> {\n" +" if {!$tkPriv(mouseMoved)} { tk_tablePaste %W [%W index @%x,%y] }\n" +"}\n" +"if {[string comp {} [info command event]]} {\n" +" tkTableClipboardKeysyms <Copy> <Cut> <Paste>\n" +"} else {\n" +" tkTableClipboardKeysyms Control-c Control-x Control-v\n" +"}\n" +"bind Table <Any-Tab> {\n" +" # empty to allow Tk focus movement\n" +"}\n" +"bind Table <FocusOut> {\n" +" catch {%W activate active}\n" +"}\n" +"bind Table <Shift-Up> {tkTableExtendSelect %W -1 0}\n" +"bind Table <Shift-Down> {tkTableExtendSelect %W 1 0}\n" +"bind Table <Shift-Left> {tkTableExtendSelect %W 0 -1}\n" +"bind Table <Shift-Right> {tkTableExtendSelect %W 0 1}\n" +"bind Table <Prior> {%W yview scroll -1 pages; %W activate @0,0}\n" +"bind Table <Next> {%W yview scroll 1 pages; %W activate @0,0}\n" +"bind Table <Control-Prior> {%W xview scroll -1 pages}\n" +"bind Table <Control-Next> {%W xview scroll 1 pages}\n" +"bind Table <Home> {%W see origin}\n" +"bind Table <End> {%W see end}\n" +"bind Table <Control-Home> {\n" +" %W selection clear all\n" +" %W activate origin\n" +" %W selection set active\n" +" %W see active\n" +"}\n" +"bind Table <Control-End> {\n" +" %W selection clear all\n" +" %W activate end\n" +" %W selection set active\n" +" %W see active\n" +"}\n" +"bind Table <Shift-Control-Home> {tkTableDataExtend %W origin}\n" +"bind Table <Shift-Control-End> {tkTableDataExtend %W end}\n" +"bind Table <Select> {tkTableBeginSelect %W [%W index active]}\n" +"bind Table <Shift-Select> {tkTableBeginExtend %W [%W index active]}\n" +"bind Table <Control-slash> {tkTableSelectAll %W}\n" +"bind Table <Control-backslash> {\n" +" if {[string match browse [%W cget -selectmode]]} {%W selection clear all}\n" +"}\n" +"bind Table <Up> {tkTableMoveCell %W -1 0}\n" +"bind Table <Down> {tkTableMoveCell %W 1 0}\n" +"bind Table <Left> {tkTableMoveCell %W 0 -1}\n" +"bind Table <Right> {tkTableMoveCell %W 0 1}\n" +"bind Table <Any-KeyPress> {\n" +" if {[string compare {} %A]} { %W insert active insert %A }\n" +"}\n" +"bind Table <BackSpace> {\n" +" set tkPriv(junk) [%W icursor]\n" +" if {[string compare {} $tkPriv(junk)] && $tkPriv(junk)} {\n" +" %W delete active [expr {$tkPriv(junk)-1}]\n" +" }\n" +"}\n" +"bind Table <Delete> {%W delete active insert}\n" +"bind Table <Escape> {%W reread}\n" +"bind Table <Return> {\n" +" %W insert active insert \"\n\"\n" +"}\n" +"bind Table <Control-Left> {%W icursor [expr {[%W icursor]-1}]}\n" +"bind Table <Control-Right> {%W icursor [expr {[%W icursor]+1}]}\n" +"bind Table <Control-e> {%W icursor end}\n" +"bind Table <Control-a> {%W icursor 0}\n" +"bind Table <Control-k> {%W delete active insert end}\n" +"bind Table <Control-equal> {tkTableChangeWidth %W active 1}\n" +"bind Table <Control-minus> {tkTableChangeWidth %W active -1}\n" +"proc tkTableBeginSelect {w el} {\n" +" global tkPriv\n" +" if {[scan $el %d,%d r c] != 2} return\n" +" switch [$w cget -selectmode] {\n" +" multiple {\n" +" if {[$w tag includes title $el]} {\n" +" ## in the title area\n" +" if {$r < [$w cget -titlerows]+[$w cget -roworigin]} {\n" +" ## We're in a column header\n" +" if {$c < [$w cget -titlecols]+[$w cget -colorigin]} {\n" +" ## We're in the topleft title area\n" +" set inc topleft\n" +" set el2 end\n" +" } else {\n" +" set inc [$w index topleft row],$c\n" +" set el2 [$w index end row],$c\n" +" }\n" +" } else {\n" +" ## We're in a row header\n" +" set inc $r,[$w index topleft col]\n" +" set el2 $r,[$w index end col]\n" +" }\n" +" } else {\n" +" set inc $el\n" +" set el2 $el\n" +" }\n" +" if [$w selection includes $inc] {\n" +" $w selection clear $el $el2\n" +" } else {\n" +" $w selection set $el $el2\n" +" }\n" +" }\n" +" extended {\n" +" $w selection clear all\n" +" if {[$w tag includes title $el]} {\n" +" if {$r < [$w cget -titlerows]+[$w cget -roworigin]} {\n" +" ## We're in a column header\n" +" if {$c < [$w cget -titlecols]+[$w cget -colorigin]} {\n" +" $w selection set origin end\n" +" } else {\n" +" $w selection set $el [$w index end row],$c\n" +" }\n" +" } else {\n" +" ## We're in a row header\n" +" $w selection set $el $r,[$w index end col]\n" +" }\n" +" } else {\n" +" $w selection set $el\n" +" }\n" +" $w selection anchor $el\n" +" set tkPriv(tablePrev) $el\n" +" }\n" +" default {\n" +" if {![$w tag includes title $el]} {\n" +" $w selection clear all\n" +" $w selection set $el\n" +" set tkPriv(tablePrev) $el\n" +" }\n" +" $w selection anchor $el\n" +" }\n" +" }\n" +"}\n" +"proc tkTableMotion {w el} {\n" +" global tkPriv\n" +" if {![info exists tkPriv(tablePrev)]} {\n" +" set tkPriv(tablePrev) $el\n" +" return\n" +" }\n" +" if {[string match $tkPriv(tablePrev) $el]} return\n" +" switch [$w cget -selectmode] {\n" +" browse {\n" +" $w selection clear all\n" +" $w selection set $el\n" +" set tkPriv(tablePrev) $el\n" +" }\n" +" extended {\n" +" scan $tkPriv(tablePrev) %d,%d r c\n" +" scan $el %d,%d elr elc\n" +" if {[$w tag includes title $el]} {\n" +" if {$r < [$w cget -titlerows]+[$w cget -roworigin]} {\n" +" ## We're in a column header\n" +" if {$c < [$w cget -titlecols]+[$w cget -colorigin]} {\n" +" ## We're in the topleft title area\n" +" $w selection clear anchor end\n" +" } else {\n" +" $w selection clear anchor [$w index end row],$c\n" +" }\n" +" $w selection set anchor [$w index end row],$elc\n" +" } else {\n" +" ## We're in a row header\n" +" $w selection clear anchor $r,[$w index end col]\n" +" $w selection set anchor $elr,[$w index end col]\n" +" }\n" +" } else {\n" +" $w selection clear anchor $tkPriv(tablePrev)\n" +" $w selection set anchor $el\n" +" }\n" +" set tkPriv(tablePrev) $el\n" +" }\n" +" }\n" +"}\n" +"proc tkTableBeginExtend {w el} {\n" +" if {[string match extended [$w cget -selectmode]] &&\n" +" [$w selection includes anchor]} {\n" +" tkTableMotion $w $el\n" +" }\n" +"}\n" +"proc tkTableBeginToggle {w el} {\n" +" global tkPriv\n" +" if {[string match extended [$w cget -selectmode]]} {\n" +" set tkPriv(tablePrev) $el\n" +" $w selection anchor $el\n" +" if [$w selection includes $el] {\n" +" $w selection clear $el\n" +" } else {\n" +" $w selection set $el\n" +" }\n" +" }\n" +"}\n" +"proc tkTableAutoScan {w} {\n" +" global tkPriv\n" +" if {![winfo exists $w]} return\n" +" set x $tkPriv(x)\n" +" set y $tkPriv(y)\n" +" if {$y >= [winfo height $w]} {\n" +" $w yview scroll 1 units\n" +" } elseif {$y < 0} {\n" +" $w yview scroll -1 units\n" +" } elseif {$x >= [winfo width $w]} {\n" +" $w xview scroll 1 units\n" +" } elseif {$x < 0} {\n" +" $w xview scroll -1 units\n" +" } else {\n" +" return\n" +" }\n" +" tkTableMotion $w [$w index @$x,$y]\n" +" set tkPriv(afterId) [after 50 tkTableAutoScan $w]\n" +"}\n" +"proc tkTableMoveCell {w x y} {\n" +" global tkPriv\n" +" if {[catch {$w index active row} r]} return\n" +" set c [$w index active col]\n" +" $w activate [incr r $x],[incr c $y]\n" +" $w see active\n" +" switch [$w cget -selectmode] {\n" +" browse {\n" +" $w selection clear all\n" +" $w selection set active\n" +" }\n" +" extended {\n" +" $w selection clear all\n" +" $w selection set active\n" +" $w selection anchor active\n" +" set tkPriv(tablePrev) [$w index active]\n" +" }\n" +" }\n" +"}\n" +"proc tkTableExtendSelect {w x y} {\n" +" if {[string compare extended [$w cget -selectmode]] ||\n" +" [catch {$w index active row} r]} return\n" +" set c [$w index active col]\n" +" $w activate [incr r $x],[incr c $y]\n" +" $w see active\n" +" tkTableMotion $w [$w index active]\n" +"}\n" +"proc tkTableDataExtend {w el} {\n" +" set mode [$w cget -selectmode]\n" +" if {[string match extended $mode]} {\n" +" $w activate $el\n" +" $w see $el\n" +" if [$w selection includes anchor] {tkTableMotion $w $el}\n" +" } elseif {[string match multiple $mode]} {\n" +" $w activate $el\n" +" $w see $el\n" +" }\n" +"}\n" +"proc tkTableSelectAll {w} {\n" +" if {[regexp {^(single|browse)$} [$w cget -selectmode]]} {\n" +" $w selection clear all\n" +" $w selection set active\n" +" tkTableHandleType $w [$w index active]\n" +" } else {\n" +" $w selection set origin end\n" +" }\n" +"}\n" +"proc tkTableChangeWidth {w i a} {\n" +" set tmp [$w index $i col]\n" +" if {[set width [$w width $tmp]] >= 0} {\n" +" $w width $tmp [incr width $a]\n" +" } else {\n" +" $w width $tmp [incr width -$a]\n" +" }\n" +"}\n" +"proc tk_tableCopy w {\n" +" if {[selection own -displayof $w] == \"$w\"} {\n" +" clipboard clear -displayof $w\n" +" catch {clipboard append -displayof $w [selection get -displayof $w]}\n" +" }\n" +"}\n" +"proc tk_tableCut w {\n" +" if {[selection own -displayof $w] == \"$w\"} {\n" +" clipboard clear -displayof $w\n" +" catch {\n" +" clipboard append -displayof $w [selection get -displayof $w]\n" +" $w cursel set {}\n" +" $w selection clear all\n" +" }\n" +" }\n" +"}\n" +"proc tk_tablePaste {w {cell {}}} {\n" +" if {[string compare {} $cell]} {\n" +" if {[catch {selection get -displayof $w} data]} return\n" +" } else {\n" +" if {[catch {selection get -displayof $w -selection CLIPBOARD} data]} {\n" +" return\n" +" }\n" +" set cell active\n" +" }\n" +" tk_tablePasteHandler $w [$w index $cell] $data\n" +" if {[$w cget -state] == \"normal\"} {focus $w}\n" +"}\n" +"proc tk_tablePasteHandler {w cell data} {\n" +" set rows [expr {[$w cget -rows]-[$w cget -roworigin]}]\n" +" set cols [expr {[$w cget -cols]-[$w cget -colorigin]}]\n" +" set r [$w index $cell row]\n" +" set c [$w index $cell col]\n" +" set rsep [$w cget -rowseparator]\n" +" set csep [$w cget -colseparator]\n" +" ## Assume separate rows are split by row separator if specified\n" +" ## If you were to want multi-character row separators, you would need:\n" +" # regsub -all $rsep $data <newline> data\n" +" # set data [join $data <newline>]\n" +" if {[string comp {} $rsep]} { set data [split $data $rsep] }\n" +" set row $r\n" +" foreach line $data {\n" +" if {$row > $rows} break\n" +" set col $c\n" +" ## Assume separate cols are split by col separator if specified\n" +" ## Unless a -separator was specified\n" +" if {[string comp {} $csep]} { set line [split $line $csep] }\n" +" ## If you were to want multi-character col separators, you would need:\n" +" # regsub -all $csep $line <newline> line\n" +" # set line [join $line <newline>]\n" +" foreach item $line {\n" +" if {$col > $cols} break\n" +" $w set $row,$col $item\n" +" incr col\n" +" }\n" +" incr row\n" +" }\n" +"}\n" diff --git a/libgui/src/tkTableCellSort.c b/libgui/src/tkTableCellSort.c new file mode 100644 index 00000000000..7afc4d754a1 --- /dev/null +++ b/libgui/src/tkTableCellSort.c @@ -0,0 +1,400 @@ +/* + * tkTableCell.c -- + * + * This module implements cell sort functions for table + * widgets. The MergeSort algorithm and other aux sorting + * functions were taken from tclCmdIL.c lsort command: + + * tclCmdIL.c -- + * + * This file contains the top-level command routines for most of + * the Tcl built-in commands whose names begin with the letters + * I through L. It contains only commands in the generic core + * (i.e. those that don't depend much upon UNIX facilities). + * + * Copyright (c) 1987-1993 The Regents of the University of California. + * Copyright (c) 1993-1997 Lucent Technologies. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. + * Copyright (c) 1998-1999 by Scriptics Corporation. + + * + * Copyright (c) 1998-1999 Jeffrey Hobbs + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + */ + +#include "tkTable.h" + +#ifndef UCHAR +#define UCHAR(c) ((unsigned char) (c)) +#endif + +/* + * During execution of the "lsort" command, structures of the following + * type are used to arrange the objects being sorted into a collection + * of linked lists. + */ + +typedef struct SortElement { + Tcl_Obj *objPtr; /* Object being sorted. */ + struct SortElement *nextPtr; /* Next element in the list, or + * NULL for end of list. */ +} SortElement; + +static int TableSortCompareProc _ANSI_ARGS_((CONST VOID *first, + CONST VOID *second)); +static SortElement * MergeSort _ANSI_ARGS_((SortElement *headPt)); +static SortElement * MergeLists _ANSI_ARGS_((SortElement *leftPtr, + SortElement *rightPtr)); +static int DictionaryCompare _ANSI_ARGS_((char *left, + char *right)); + +/* + *---------------------------------------------------------------------- + * + * TableSortCompareProc -- + * This procedure is invoked by qsort to determine the proper + * ordering between two elements. + * + * Results: + * < 0 means first is "smaller" than "second", > 0 means "first" + * is larger than "second", and 0 means they should be treated + * as equal. + * + * Side effects: + * None, unless a user-defined comparison command does something + * weird. + * + *---------------------------------------------------------------------- + */ +static int +TableSortCompareProc(first, second) + CONST VOID *first, *second; /* Elements to be compared. */ +{ + char *str1 = *((char **) first); + char *str2 = *((char **) second); + + return DictionaryCompare(str1, str2); +} + +/* + *---------------------------------------------------------------------- + * + * TableCellSort -- + * Sort a list of table cell elements (of form row,col) + * + * Results: + * Returns the sorted list of elements. Because Tcl_Merge allocs + * the space for result, it must later be Tcl_Free'd by caller. + * + * Side effects: + * Behaviour undefined for ill-formed input list of elements. + * + *---------------------------------------------------------------------- + */ +char * +TableCellSort(Table *tablePtr, char *str) +{ + int listArgc; + char **listArgv; + char *result; + + if (Tcl_SplitList(tablePtr->interp, str, &listArgc, &listArgv) != TCL_OK) { + return str; + } + /* Thread safety: qsort is reportedly not thread-safe... */ + qsort((VOID *) listArgv, (size_t) listArgc, sizeof (char *), + TableSortCompareProc); + result = Tcl_Merge(listArgc, listArgv); + ckfree((char *) listArgv); + return result; +} + +/* + *---------------------------------------------------------------------- + * + * DictionaryCompare - Not the Unicode version + * + * This function compares two strings as if they were being used in + * an index or card catalog. The case of alphabetic characters is + * ignored, except to break ties. Thus "B" comes before "b" but + * after "a". Also, integers embedded in the strings compare in + * numerical order. In other words, "x10y" comes after "x9y", not + * before it as it would when using strcmp(). + * + * Results: + * A negative result means that the first element comes before the + * second, and a positive result means that the second element + * should come first. A result of zero means the two elements + * are equal and it doesn't matter which comes first. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static int +DictionaryCompare(left, right) + char *left, *right; /* The strings to compare */ +{ + int diff, zeros; + int secondaryDiff = 0; + + while (1) { + if (isdigit(UCHAR(*right)) && isdigit(UCHAR(*left))) { + /* + * There are decimal numbers embedded in the two + * strings. Compare them as numbers, rather than + * strings. If one number has more leading zeros than + * the other, the number with more leading zeros sorts + * later, but only as a secondary choice. + */ + + zeros = 0; + while ((*right == '0') && (isdigit(UCHAR(right[1])))) { + right++; + zeros--; + } + while ((*left == '0') && (isdigit(UCHAR(left[1])))) { + left++; + zeros++; + } + if (secondaryDiff == 0) { + secondaryDiff = zeros; + } + + /* + * The code below compares the numbers in the two + * strings without ever converting them to integers. It + * does this by first comparing the lengths of the + * numbers and then comparing the digit values. + */ + + diff = 0; + while (1) { + if (diff == 0) { + diff = UCHAR(*left) - UCHAR(*right); + } + right++; + left++; + if (!isdigit(UCHAR(*right))) { + if (isdigit(UCHAR(*left))) { + return 1; + } else { + /* + * The two numbers have the same length. See + * if their values are different. + */ + + if (diff != 0) { + return diff; + } + break; + } + } else if (!isdigit(UCHAR(*left))) { + return -1; + } + } + continue; + } + diff = UCHAR(*left) - UCHAR(*right); + if (diff) { + if (isupper(UCHAR(*left)) && islower(UCHAR(*right))) { + diff = UCHAR(tolower(*left)) - UCHAR(*right); + if (diff) { + return diff; + } else if (secondaryDiff == 0) { + secondaryDiff = -1; + } + } else if (isupper(UCHAR(*right)) && islower(UCHAR(*left))) { + diff = UCHAR(*left) - UCHAR(tolower(UCHAR(*right))); + if (diff) { + return diff; + } else if (secondaryDiff == 0) { + secondaryDiff = 1; + } + } else { + return diff; + } + } + if (*left == 0) { + break; + } + left++; + right++; + } + if (diff == 0) { + diff = secondaryDiff; + } + return diff; +} + +/* + *---------------------------------------------------------------------- + * + * MergeLists - + * + * This procedure combines two sorted lists of SortElement structures + * into a single sorted list. + * + * Results: + * The unified list of SortElement structures. + * + * Side effects: + * None, unless a user-defined comparison command does something + * weird. + * + *---------------------------------------------------------------------- + */ + +static SortElement * +MergeLists(leftPtr, rightPtr) + SortElement *leftPtr; /* First list to be merged; may be + * NULL. */ + SortElement *rightPtr; /* Second list to be merged; may be + * NULL. */ +{ + SortElement *headPtr; + SortElement *tailPtr; + + if (leftPtr == NULL) { + return rightPtr; + } + if (rightPtr == NULL) { + return leftPtr; + } + if (DictionaryCompare(Tcl_GetString(leftPtr->objPtr), + Tcl_GetString(rightPtr->objPtr)) > 0) { + tailPtr = rightPtr; + rightPtr = rightPtr->nextPtr; + } else { + tailPtr = leftPtr; + leftPtr = leftPtr->nextPtr; + } + headPtr = tailPtr; + while ((leftPtr != NULL) && (rightPtr != NULL)) { + if (DictionaryCompare(Tcl_GetString(leftPtr->objPtr), + Tcl_GetString(rightPtr->objPtr)) > 0) { + tailPtr->nextPtr = rightPtr; + tailPtr = rightPtr; + rightPtr = rightPtr->nextPtr; + } else { + tailPtr->nextPtr = leftPtr; + tailPtr = leftPtr; + leftPtr = leftPtr->nextPtr; + } + } + if (leftPtr != NULL) { + tailPtr->nextPtr = leftPtr; + } else { + tailPtr->nextPtr = rightPtr; + } + return headPtr; +} + +/* + *---------------------------------------------------------------------- + * + * MergeSort - + * + * This procedure sorts a linked list of SortElement structures + * use the merge-sort algorithm. + * + * Results: + * A pointer to the head of the list after sorting is returned. + * + * Side effects: + * None, unless a user-defined comparison command does something + * weird. + * + *---------------------------------------------------------------------- + */ + +static SortElement * +MergeSort(headPtr) + SortElement *headPtr; /* First element on the list */ +{ + /* + * The subList array below holds pointers to temporary lists built + * during the merge sort. Element i of the array holds a list of + * length 2**i. + */ + +# define NUM_LISTS 30 + SortElement *subList[NUM_LISTS]; + SortElement *elementPtr; + int i; + + for(i = 0; i < NUM_LISTS; i++){ + subList[i] = NULL; + } + while (headPtr != NULL) { + elementPtr = headPtr; + headPtr = headPtr->nextPtr; + elementPtr->nextPtr = 0; + for (i = 0; (i < NUM_LISTS) && (subList[i] != NULL); i++){ + elementPtr = MergeLists(subList[i], elementPtr); + subList[i] = NULL; + } + if (i >= NUM_LISTS) { + i = NUM_LISTS-1; + } + subList[i] = elementPtr; + } + elementPtr = NULL; + for (i = 0; i < NUM_LISTS; i++){ + elementPtr = MergeLists(subList[i], elementPtr); + } + return elementPtr; +} + +#ifndef NO_SORT_CELLS +/* + *---------------------------------------------------------------------- + * + * TableCellSortObj -- + * Sorts a list of table cell elements (of form row,col) in place + * + * Results: + * Sorts list of elements in place. + * + * Side effects: + * Behaviour undefined for ill-formed input list of elements. + * + *---------------------------------------------------------------------- + */ +Tcl_Obj * +TableCellSortObj(Tcl_Interp *interp, Tcl_Obj *listObjPtr) +{ + int length, i; + Tcl_Obj *sortedObjPtr, **listObjPtrs; + SortElement *elementArray; + SortElement *elementPtr; + + if (Tcl_ListObjGetElements(interp, listObjPtr, + &length, &listObjPtrs) != TCL_OK) { + return NULL; + } + if (length <= 0) { + return listObjPtr; + } + + elementArray = (SortElement *) ckalloc(length * sizeof(SortElement)); + for (i=0; i < length; i++){ + elementArray[i].objPtr = listObjPtrs[i]; + elementArray[i].nextPtr = &elementArray[i+1]; + } + elementArray[length-1].nextPtr = NULL; + elementPtr = MergeSort(elementArray); + sortedObjPtr = Tcl_NewObj(); + for (; elementPtr != NULL; elementPtr = elementPtr->nextPtr){ + Tcl_ListObjAppendElement(NULL, sortedObjPtr, elementPtr->objPtr); + } + ckfree((char*) elementArray); + + return sortedObjPtr; +} +#endif diff --git a/libgui/src/tkTableCmds.c b/libgui/src/tkTableCmds.c new file mode 100644 index 00000000000..4fc7d3b374a --- /dev/null +++ b/libgui/src/tkTableCmds.c @@ -0,0 +1,1293 @@ +/* + * tkTableCmds.c -- + * + * This module implements general commands of a table widget, + * based on the major/minor command structure. + * + * Copyright (c) 1998-2000 Jeffrey Hobbs + * + * See the file "license.txt" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + */ + +#include "tkTable.h" + +/* + *-------------------------------------------------------------- + * + * Table_ActivateCmd -- + * This procedure is invoked to process the activate method + * that corresponds to a table widget managed by this module. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ +int +Table_ActivateCmd(ClientData clientData, register Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +{ + register Table *tablePtr = (Table *) clientData; + int result = TCL_OK; + int row, col; + + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "index"); + return TCL_ERROR; + } else if (TableGetIndexObj(tablePtr, objv[2], &row, &col) != TCL_OK) { + return TCL_ERROR; + } else { + int x, y, w, dummy; + char buf1[INDEX_BUFSIZE], buf2[INDEX_BUFSIZE]; + + /* convert to valid active index in real coords */ + row -= tablePtr->rowOffset; + col -= tablePtr->colOffset; + /* we do this regardless, to avoid cell commit problems */ + if ((tablePtr->flags & HAS_ACTIVE) && + (tablePtr->flags & TEXT_CHANGED)) { + tablePtr->flags &= ~TEXT_CHANGED; + TableSetCellValue(tablePtr, + tablePtr->activeRow+tablePtr->rowOffset, + tablePtr->activeCol+tablePtr->colOffset, + tablePtr->activeBuf); + } + if (row != tablePtr->activeRow || col != tablePtr->activeCol) { + if (tablePtr->flags & HAS_ACTIVE) { + TableMakeArrayIndex(tablePtr->activeRow+tablePtr->rowOffset, + tablePtr->activeCol+tablePtr->colOffset, + buf1); + } else { + buf1[0] = '\0'; + } + tablePtr->flags |= HAS_ACTIVE; + tablePtr->flags &= ~ACTIVE_DISABLED; + tablePtr->activeRow = row; + tablePtr->activeCol = col; + if (tablePtr->activeTagPtr != NULL) { + ckfree((char *) (tablePtr->activeTagPtr)); + tablePtr->activeTagPtr = NULL; + } + TableAdjustActive(tablePtr); + TableConfigCursor(tablePtr); + if (!(tablePtr->flags & BROWSE_CMD) && + tablePtr->browseCmd != NULL) { + Tcl_DString script; + tablePtr->flags |= BROWSE_CMD; + row = tablePtr->activeRow+tablePtr->rowOffset; + col = tablePtr->activeCol+tablePtr->colOffset; + TableMakeArrayIndex(row, col, buf2); + Tcl_DStringInit(&script); + ExpandPercents(tablePtr, tablePtr->browseCmd, row, col, + buf1, buf2, tablePtr->icursor, &script, 0); + result = Tcl_GlobalEval(interp, Tcl_DStringValue(&script)); + if (result == TCL_OK || result == TCL_RETURN) { + Tcl_ResetResult(interp); + } + Tcl_DStringFree(&script); + tablePtr->flags &= ~BROWSE_CMD; + } + } else { + char *p = Tcl_GetString(objv[2]); + + if ((tablePtr->activeTagPtr != NULL) && *p == '@' && + !(tablePtr->flags & ACTIVE_DISABLED) && + TableCellVCoords(tablePtr, row, col, &x, &y, &w, &dummy, 0)) { + /* we are clicking into the same cell + * If it was activated with @x,y indexing, + * find the closest char */ + Tk_TextLayout textLayout; + TableTag *tagPtr = tablePtr->activeTagPtr; + + /* no error checking because GetIndex did it for us */ + p++; + x = strtol(p, &p, 0) - x - tablePtr->activeX; + y = strtol(++p, &p, 0) - y - tablePtr->activeY; + + textLayout = Tk_ComputeTextLayout(tagPtr->tkfont, + tablePtr->activeBuf, -1, + (tagPtr->wrap) ? w : 0, + tagPtr->justify, 0, &dummy, &dummy); + + tablePtr->icursor = Tk_PointToChar(textLayout, x, y); + Tk_FreeTextLayout(textLayout); + TableRefresh(tablePtr, row, col, CELL|INV_FORCE); + } + } + tablePtr->flags |= HAS_ACTIVE; + } + return result; +} + +/* + *-------------------------------------------------------------- + * + * Table_AdjustCmd -- + * This procedure is invoked to process the width/height method + * that corresponds to a table widget managed by this module. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ +int +Table_AdjustCmd(ClientData clientData, register Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +{ + register Table *tablePtr = (Table *) clientData; + Tcl_HashEntry *entryPtr; + Tcl_HashSearch search; + Tcl_HashTable *hashTablePtr; + int i, widthType, dummy, value, posn, offset; + char buf1[INDEX_BUFSIZE]; + + widthType = (*(Tcl_GetString(objv[1])) == 'w'); + /* changes the width/height of certain selected columns */ + if (objc != 3 && (objc & 1)) { + Tcl_WrongNumArgs(interp, 2, objv, widthType ? + "?col? ?width col width ...?" : + "?row? ?height row height ...?"); + return TCL_ERROR; + } + if (widthType) { + hashTablePtr = tablePtr->colWidths; + offset = tablePtr->colOffset; + } else { + hashTablePtr = tablePtr->rowHeights; + offset = tablePtr->rowOffset; + } + + if (objc == 2) { + /* print out all the preset column widths or row heights */ + entryPtr = Tcl_FirstHashEntry(hashTablePtr, &search); + while (entryPtr != NULL) { + posn = ((int) Tcl_GetHashKey(hashTablePtr, entryPtr)) + offset; + value = (int) Tcl_GetHashValue(entryPtr); + sprintf(buf1, "%d %d", posn, value); + /* OBJECTIFY */ + Tcl_AppendElement(interp, buf1); + entryPtr = Tcl_NextHashEntry(&search); + } + } else if (objc == 3) { + /* get the width/height of a particular row/col */ + if (Tcl_GetIntFromObj(interp, objv[2], &posn) != TCL_OK) { + return TCL_ERROR; + } + /* no range check is done, why bother? */ + posn -= offset; + entryPtr = Tcl_FindHashEntry(hashTablePtr, (char *) posn); + if (entryPtr != NULL) { + Tcl_SetIntObj(Tcl_GetObjResult(interp), + (int) Tcl_GetHashValue(entryPtr)); + } else { + Tcl_SetIntObj(Tcl_GetObjResult(interp), widthType ? + tablePtr->defColWidth : tablePtr->defRowHeight); + } + } else { + for (i=2; i<objc; i++) { + /* set new width|height here */ + value = -999999; + if (Tcl_GetIntFromObj(interp, objv[i++], &posn) != TCL_OK || + (strcmp(Tcl_GetString(objv[i]), "default") && + Tcl_GetIntFromObj(interp, objv[i], &value) != TCL_OK)) { + return TCL_ERROR; + } + posn -= offset; + if (value == -999999) { + /* reset that field */ + entryPtr = Tcl_FindHashEntry(hashTablePtr, (char *) posn); + if (entryPtr != NULL) { + Tcl_DeleteHashEntry(entryPtr); + } + } else { + entryPtr = Tcl_CreateHashEntry(hashTablePtr, + (char *) posn, &dummy); + Tcl_SetHashValue(entryPtr, (ClientData) value); + } + } + TableAdjustParams(tablePtr); + /* rerequest geometry */ + TableGeometryRequest(tablePtr); + /* + * Invalidate the whole window as TableAdjustParams + * will only check to see if the top left cell has moved + * FIX: should just move from lowest order visible cell + * to edge of window + */ + TableInvalidateAll(tablePtr, 0); + } + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * Table_BboxCmd -- + * This procedure is invoked to process the bbox method + * that corresponds to a table widget managed by this module. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ +int +Table_BboxCmd(ClientData clientData, register Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +{ + register Table *tablePtr = (Table *) clientData; + int x, y, w, h, row, col, key; + Tcl_Obj *resultPtr; + + /* Returns bounding box of cell(s) */ + if (objc < 3 || objc > 4) { + Tcl_WrongNumArgs(interp, 2, objv, "first ?last?"); + return TCL_ERROR; + } else if (TableGetIndexObj(tablePtr, objv[2], &row, &col) == TCL_ERROR || + (objc == 4 && + TableGetIndexObj(tablePtr, objv[3], &x, &y) == TCL_ERROR)) { + return TCL_ERROR; + } + + resultPtr = Tcl_GetObjResult(interp); + if (objc == 3) { + row -= tablePtr->rowOffset; col -= tablePtr->colOffset; + if (TableCellVCoords(tablePtr, row, col, &x, &y, &w, &h, 0)) { + Tcl_ListObjAppendElement(NULL, resultPtr, Tcl_NewIntObj(x)); + Tcl_ListObjAppendElement(NULL, resultPtr, Tcl_NewIntObj(y)); + Tcl_ListObjAppendElement(NULL, resultPtr, Tcl_NewIntObj(w)); + Tcl_ListObjAppendElement(NULL, resultPtr, Tcl_NewIntObj(h)); + } + return TCL_OK; + } else { + int r1, c1, r2, c2, minX = 99999, minY = 99999, maxX = 0, maxY = 0; + + row -= tablePtr->rowOffset; col -= tablePtr->colOffset; + x -= tablePtr->rowOffset; y -= tablePtr->colOffset; + r1 = MIN(row,x); r2 = MAX(row,x); + c1 = MIN(col,y); c2 = MAX(col,y); + key = 0; + for (row = r1; row <= r2; row++) { + for (col = c1; col <= c2; col++) { + if (TableCellVCoords(tablePtr, row, col, &x, &y, &w, &h, 0)) { + /* Get max bounding box */ + if (x < minX) minX = x; + if (y < minY) minY = y; + if (x+w > maxX) maxX = x+w; + if (y+h > maxY) maxY = y+h; + key++; + } + } + } + if (key) { + Tcl_ListObjAppendElement(NULL, resultPtr, Tcl_NewIntObj(minX)); + Tcl_ListObjAppendElement(NULL, resultPtr, Tcl_NewIntObj(minY)); + Tcl_ListObjAppendElement(NULL, resultPtr, + Tcl_NewIntObj(maxX-minX)); + Tcl_ListObjAppendElement(NULL, resultPtr, + Tcl_NewIntObj(maxY-minY)); + } + } + return TCL_OK; +} + +static char *bdCmdNames[] = { + "mark", "dragto", (char *)NULL +}; +enum bdCmd { + BD_MARK, BD_DRAGTO +}; + +/* + *-------------------------------------------------------------- + * + * Table_BorderCmd -- + * This procedure is invoked to process the bbox method + * that corresponds to a table widget managed by this module. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ +int +Table_BorderCmd(ClientData clientData, register Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +{ + register Table *tablePtr = (Table *) clientData; + Tcl_HashEntry *entryPtr; + int x, y, w, h, row, col, key, dummy, value, cmdIndex; + char *rc = NULL; + Tcl_Obj *objPtr, *resultPtr; + + if (objc < 5 || objc > 6) { + Tcl_WrongNumArgs(interp, 2, objv, "mark|dragto x y ?row|col?"); + return TCL_ERROR; + } + if (Tcl_GetIndexFromObj(interp, objv[2], bdCmdNames, + "option", 0, &cmdIndex) != TCL_OK || + Tcl_GetIntFromObj(interp, objv[3], &x) != TCL_OK || + Tcl_GetIntFromObj(interp, objv[4], &y) != TCL_OK) { + return TCL_ERROR; + } + if (objc == 6) { + rc = Tcl_GetStringFromObj(objv[5], &w); + if ((w < 1) || (strncmp(rc, "row", w) && strncmp(rc, "col", w))) { + Tcl_WrongNumArgs(interp, 2, objv, "mark|dragto x y ?row|col?"); + return TCL_ERROR; + } + } + + resultPtr = Tcl_GetObjResult(interp); + switch ((enum bdCmd) cmdIndex) { + case BD_MARK: + /* Use x && y to determine if we are over a border */ + value = TableAtBorder(tablePtr, x, y, &row, &col); + /* Cache the row && col for use in DRAGTO */ + tablePtr->scanMarkRow = row; + tablePtr->scanMarkCol = col; + if (!value) { + return TCL_OK; + } + TableCellCoords(tablePtr, row, col, &x, &y, &dummy, &dummy); + tablePtr->scanMarkX = x; + tablePtr->scanMarkY = y; + if (objc == 5 || *rc == 'r') { + if (row < 0) { + objPtr = Tcl_NewStringObj("", 0); + } else { + objPtr = Tcl_NewIntObj(row+tablePtr->rowOffset); + } + Tcl_ListObjAppendElement(NULL, resultPtr, objPtr); + } + if (objc == 5 || *rc == 'c') { + if (col < 0) { + objPtr = Tcl_NewStringObj("", 0); + } else { + objPtr = Tcl_NewIntObj(col+tablePtr->colOffset); + } + Tcl_ListObjAppendElement(NULL, resultPtr, objPtr); + } + return TCL_OK; /* BORDER MARK */ + + case BD_DRAGTO: + /* check to see if we want to resize any borders */ + if (tablePtr->resize == SEL_NONE) { return TCL_OK; } + row = tablePtr->scanMarkRow; + col = tablePtr->scanMarkCol; + TableCellCoords(tablePtr, row, col, &w, &h, &dummy, &dummy); + key = 0; + if (row >= 0 && (tablePtr->resize & SEL_ROW)) { + /* row border was active, move it */ + value = y-h; + if (value < -1) value = -1; + if (value != tablePtr->scanMarkY) { + entryPtr = Tcl_CreateHashEntry(tablePtr->rowHeights, + (char *) row, &dummy); + /* -value means rowHeight will be interp'd as pixels, not + lines */ + Tcl_SetHashValue(entryPtr, (ClientData) MIN(0,-value)); + tablePtr->scanMarkY = value; + key++; + } + } + if (col >= 0 && (tablePtr->resize & SEL_COL)) { + /* col border was active, move it */ + value = x-w; + if (value < -1) value = -1; + if (value != tablePtr->scanMarkX) { + entryPtr = Tcl_CreateHashEntry(tablePtr->colWidths, + (char *) col, &dummy); + /* -value means colWidth will be interp'd as pixels, not + chars */ + Tcl_SetHashValue(entryPtr, (ClientData) MIN(0,-value)); + tablePtr->scanMarkX = value; + key++; + } + } + /* Only if something changed do we want to update */ + if (key) { + TableAdjustParams(tablePtr); + /* Only rerequest geometry if the basis is the #rows &| #cols */ + if (tablePtr->maxReqCols || tablePtr->maxReqRows) + TableGeometryRequest(tablePtr); + TableInvalidateAll(tablePtr, 0); + } + return TCL_OK; /* BORDER DRAGTO */ + } + return TCL_OK; +} + +/* clear subcommands */ +static char *clearNames[] = { + "all", "cache", "sizes", "tags", (char *)NULL +}; +enum clearCommand { + CLEAR_ALL, CLEAR_CACHE, CLEAR_SIZES, CLEAR_TAGS +}; + +/* + *-------------------------------------------------------------- + * + * Table_ClearCmd -- + * This procedure is invoked to process the clear method + * that corresponds to a table widget managed by this module. + * See the user documentation for details on what it does. + * + * Results: + * Cached info can be lost. Returns valid Tcl result. + * + * Side effects: + * Can cause redraw. + * See the user documentation. + * + *-------------------------------------------------------------- + */ +int +Table_ClearCmd(ClientData clientData, register Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +{ + register Table *tablePtr = (Table *) clientData; + int cmdIndex, redraw = 0; + + if (objc < 3 || objc > 5) { + Tcl_WrongNumArgs(interp, 2, objv, "option ?first? ?last?"); + return TCL_ERROR; + } + + if (Tcl_GetIndexFromObj(interp, objv[2], clearNames, + "clear option", 0, &cmdIndex) != TCL_OK) { + return TCL_ERROR; + } + + if (objc == 3) { + if (cmdIndex == CLEAR_TAGS || cmdIndex == CLEAR_ALL) { + Tcl_DeleteHashTable(tablePtr->rowStyles); + Tcl_DeleteHashTable(tablePtr->colStyles); + Tcl_DeleteHashTable(tablePtr->cellStyles); + Tcl_DeleteHashTable(tablePtr->flashCells); + Tcl_DeleteHashTable(tablePtr->selCells); + + /* style hash tables */ + Tcl_InitHashTable(tablePtr->rowStyles, TCL_ONE_WORD_KEYS); + Tcl_InitHashTable(tablePtr->colStyles, TCL_ONE_WORD_KEYS); + Tcl_InitHashTable(tablePtr->cellStyles, TCL_STRING_KEYS); + + /* special style hash tables */ + Tcl_InitHashTable(tablePtr->flashCells, TCL_STRING_KEYS); + Tcl_InitHashTable(tablePtr->selCells, TCL_STRING_KEYS); + } + + if (cmdIndex == CLEAR_SIZES || cmdIndex == CLEAR_ALL) { + Tcl_DeleteHashTable(tablePtr->colWidths); + Tcl_DeleteHashTable(tablePtr->rowHeights); + + /* style hash tables */ + Tcl_InitHashTable(tablePtr->colWidths, TCL_ONE_WORD_KEYS); + Tcl_InitHashTable(tablePtr->rowHeights, TCL_ONE_WORD_KEYS); + } + + if (cmdIndex == CLEAR_CACHE || cmdIndex == CLEAR_ALL) { + Tcl_DeleteHashTable(tablePtr->cache); + Tcl_InitHashTable(tablePtr->cache, TCL_STRING_KEYS); + /* If we were caching and we have no other data source, + * invalidate all the cells */ + if (tablePtr->dataSource == DATA_CACHE) { + TableGetActiveBuf(tablePtr); + } + } + redraw = 1; + } else { + int row, col, r1, r2, c1, c2; + Tcl_HashEntry *entryPtr; + char buf[INDEX_BUFSIZE]; + + if (TableGetIndexObj(tablePtr, objv[3], &row, &col) != TCL_OK || + ((objc == 5) && + TableGetIndexObj(tablePtr, objv[4], &r2, &c2) != TCL_OK)) { + return TCL_ERROR; + } + if (objc == 4) { + r1 = r2 = row; + c1 = c2 = col; + } else { + r1 = MIN(row,r2); r2 = MAX(row,r2); + c1 = MIN(col,c2); c2 = MAX(col,c2); + } + for (row = r1; row <= r2; row++) { + /* Note that *Styles entries are user based (no offset) + * while size entries are 0-based (real) */ + if ((cmdIndex == CLEAR_TAGS || cmdIndex == CLEAR_ALL) && + (entryPtr = Tcl_FindHashEntry(tablePtr->rowStyles, + (char *) row))) { + Tcl_DeleteHashEntry(entryPtr); + redraw = 1; + } + + if ((cmdIndex == CLEAR_SIZES || cmdIndex == CLEAR_ALL) && + (entryPtr = Tcl_FindHashEntry(tablePtr->rowHeights, + (char *) row-tablePtr->rowOffset))) { + Tcl_DeleteHashEntry(entryPtr); + redraw = 1; + } + + for (col = c1; col <= c2; col++) { + TableMakeArrayIndex(row, col, buf); + + if (cmdIndex == CLEAR_TAGS || cmdIndex == CLEAR_ALL) { + if ((row == r1) && + (entryPtr = Tcl_FindHashEntry(tablePtr->colStyles, + (char *) col))) { + Tcl_DeleteHashEntry(entryPtr); + redraw = 1; + } + if ((entryPtr = Tcl_FindHashEntry(tablePtr->cellStyles, + buf))) { + Tcl_DeleteHashEntry(entryPtr); + redraw = 1; + } + if ((entryPtr = Tcl_FindHashEntry(tablePtr->flashCells, + buf))) { + Tcl_DeleteHashEntry(entryPtr); + redraw = 1; + } + if ((entryPtr = Tcl_FindHashEntry(tablePtr->selCells, + buf))) { + Tcl_DeleteHashEntry(entryPtr); + redraw = 1; + } + } + + if ((cmdIndex == CLEAR_SIZES || cmdIndex == CLEAR_ALL) && + row == r1 && + (entryPtr = Tcl_FindHashEntry(tablePtr->colWidths, (char *) + col-tablePtr->colOffset))) { + Tcl_DeleteHashEntry(entryPtr); + redraw = 1; + } + + if ((cmdIndex == CLEAR_CACHE || cmdIndex == CLEAR_ALL) && + (entryPtr = Tcl_FindHashEntry(tablePtr->cache, buf))) { + Tcl_DeleteHashEntry(entryPtr); + /* if the cache is our data source, + * we need to invalidate the cells changed */ + if ((tablePtr->dataSource == DATA_CACHE) && + (row-tablePtr->rowOffset == tablePtr->activeRow && + col-tablePtr->colOffset == tablePtr->activeCol)) + TableGetActiveBuf(tablePtr); + redraw = 1; + } + } + } + } + /* This could be more sensitive about what it updates, + * but that can actually be a lot more costly in some cases */ + if (redraw) { + if (cmdIndex == CLEAR_SIZES || cmdIndex == CLEAR_ALL) { + TableAdjustParams(tablePtr); + /* rerequest geometry */ + TableGeometryRequest(tablePtr); + } + TableInvalidateAll(tablePtr, 0); + } + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * Table_CurselectionCmd -- + * This procedure is invoked to process the bbox method + * that corresponds to a table widget managed by this module. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ +int +Table_CurselectionCmd(ClientData clientData, register Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +{ + register Table *tablePtr = (Table *) clientData; + Tcl_HashEntry *entryPtr; + Tcl_HashSearch search; + char *value = NULL; + int row, col; + + if (objc > 3) { + Tcl_WrongNumArgs(interp, 2, objv, "?value?"); + return TCL_ERROR; + } + if (objc == 3) { + /* make sure there is a data source to accept a set value */ + if ((tablePtr->state == STATE_DISABLED) || + (tablePtr->dataSource == DATA_NONE)) { + return TCL_OK; + } + value = Tcl_GetString(objv[2]); + for (entryPtr = Tcl_FirstHashEntry(tablePtr->selCells, &search); + entryPtr != NULL; entryPtr = Tcl_NextHashEntry(&search)) { + TableParseArrayIndex(&row, &col, + Tcl_GetHashKey(tablePtr->selCells, entryPtr)); + TableSetCellValue(tablePtr, row, col, value); + row -= tablePtr->rowOffset; + col -= tablePtr->colOffset; + if (row == tablePtr->activeRow && col == tablePtr->activeCol) { + TableGetActiveBuf(tablePtr); + } + TableRefresh(tablePtr, row, col, CELL); + } + } else { + Tcl_Obj *objPtr = Tcl_NewObj(); + + for (entryPtr = Tcl_FirstHashEntry(tablePtr->selCells, &search); + entryPtr != NULL; entryPtr = Tcl_NextHashEntry(&search)) { + value = Tcl_GetHashKey(tablePtr->selCells, entryPtr); + Tcl_ListObjAppendElement(NULL, objPtr, + Tcl_NewStringObj(value, -1)); + } + Tcl_SetObjResult(interp, TableCellSortObj(interp, objPtr)); + } + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * Table_CurvalueCmd -- + * This procedure is invoked to process the curvalue method + * that corresponds to a table widget managed by this module. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ +int +Table_CurvalueCmd(ClientData clientData, register Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +{ + register Table *tablePtr = (Table *) clientData; + + if (objc > 3) { + Tcl_WrongNumArgs(interp, 2, objv, "?<value>?"); + return TCL_ERROR; + } else if (!(tablePtr->flags & HAS_ACTIVE)) { + return TCL_OK; + } + + if (objc == 3) { + char *value; + int len; + + value = Tcl_GetStringFromObj(objv[2], &len); + if (STREQ(value, tablePtr->activeBuf)) { + Tcl_SetObjResult(interp, objv[2]); + return TCL_OK; + } + /* validate potential new active buffer contents + * only accept if validation returns acceptance. */ + if (tablePtr->validate && + TableValidateChange(tablePtr, + tablePtr->activeRow+tablePtr->rowOffset, + tablePtr->activeCol+tablePtr->colOffset, + tablePtr->activeBuf, + value, tablePtr->icursor) != TCL_OK) { + return TCL_OK; + } + tablePtr->activeBuf = (char *)ckrealloc(tablePtr->activeBuf, len+1); + strcpy(tablePtr->activeBuf, value); + /* mark the text as changed */ + tablePtr->flags |= TEXT_CHANGED; + TableSetActiveIndex(tablePtr); + /* check for possible adjustment of icursor */ + TableGetIcursor(tablePtr, "insert", (int *)0); + TableRefresh(tablePtr, tablePtr->activeRow, tablePtr->activeCol, CELL); + } + + Tcl_SetStringObj(Tcl_GetObjResult(interp), tablePtr->activeBuf, -1); + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * Table_GetCmd -- + * This procedure is invoked to process the bbox method + * that corresponds to a table widget managed by this module. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ +int +Table_GetCmd(ClientData clientData, register Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +{ + register Table *tablePtr = (Table *) clientData; + int result = TCL_OK; + int r1, c1, r2, c2, row, col; + + if (objc < 3 || objc > 4) { + Tcl_WrongNumArgs(interp, 2, objv, "first ?last?"); + result = TCL_ERROR; + } else if (TableGetIndexObj(tablePtr, objv[2], &row, &col) == TCL_ERROR) { + result = TCL_ERROR; + } else if (objc == 3) { + Tcl_SetObjResult(interp, + Tcl_NewStringObj(TableGetCellValue(tablePtr, row, col), -1)); + } else if (TableGetIndexObj(tablePtr, objv[3], &r2, &c2) == TCL_ERROR) { + result = TCL_ERROR; + } else { + Tcl_Obj *objPtr = Tcl_NewObj(); + + r1 = MIN(row,r2); r2 = MAX(row,r2); + c1 = MIN(col,c2); c2 = MAX(col,c2); + for ( row = r1; row <= r2; row++ ) { + for ( col = c1; col <= c2; col++ ) { + Tcl_ListObjAppendElement(NULL, objPtr, + Tcl_NewStringObj(TableGetCellValue(tablePtr, + row, col), -1)); + } + } + Tcl_SetObjResult(interp, objPtr); + } + return result; +} + +/* + *-------------------------------------------------------------- + * + * Table_ScanCmd -- + * This procedure is invoked to process the scan method + * that corresponds to a table widget managed by this module. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ +int +Table_ScanCmd(ClientData clientData, register Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +{ + register Table *tablePtr = (Table *) clientData; + int x, y, row, col, cmdIndex; + + if (objc != 5) { + Tcl_WrongNumArgs(interp, 2, objv, "mark|dragto x y"); + return TCL_ERROR; + } else if (Tcl_GetIndexFromObj(interp, objv[2], bdCmdNames, + "option", 0, &cmdIndex) != TCL_OK || + Tcl_GetIntFromObj(interp, objv[3], &x) == TCL_ERROR || + Tcl_GetIntFromObj(interp, objv[4], &y) == TCL_ERROR) { + return TCL_ERROR; + } + switch ((enum bdCmd) cmdIndex) { + case BD_MARK: + TableWhatCell(tablePtr, x, y, &row, &col); + tablePtr->scanMarkRow = row-tablePtr->topRow; + tablePtr->scanMarkCol = col-tablePtr->leftCol; + tablePtr->scanMarkX = x; + tablePtr->scanMarkY = y; + break; + + case BD_DRAGTO: { + int oldTop = tablePtr->topRow, oldLeft = tablePtr->leftCol; + y += (5*(y-tablePtr->scanMarkY)); + x += (5*(x-tablePtr->scanMarkX)); + + TableWhatCell(tablePtr, x, y, &row, &col); + + /* maintain appropriate real index */ + tablePtr->topRow = BETWEEN(row-tablePtr->scanMarkRow, + tablePtr->titleRows, tablePtr->rows-1); + tablePtr->leftCol = BETWEEN(col-tablePtr->scanMarkCol, + tablePtr->titleCols, tablePtr->cols-1); + + /* Adjust the table if new top left */ + if (oldTop != tablePtr->topRow || oldLeft != tablePtr->leftCol) { + TableAdjustParams(tablePtr); + } + break; + } + } + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * Table_SelAnchorCmd -- + * This procedure is invoked to process the selection anchor method + * that corresponds to a table widget managed by this module. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ +int +Table_SelAnchorCmd(ClientData clientData, register Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +{ + register Table *tablePtr = (Table *) clientData; + int row, col; + + if (objc != 4) { + Tcl_WrongNumArgs(interp, 3, objv, "index"); + return TCL_ERROR; + } else if (TableGetIndexObj(tablePtr, objv[3], &row, &col) != TCL_OK) { + return TCL_ERROR; + } + tablePtr->flags |= HAS_ANCHOR; + /* maintain appropriate real index */ + if (tablePtr->selectTitles) { + tablePtr->anchorRow = BETWEEN(row-tablePtr->rowOffset, + 0, tablePtr->rows-1); + tablePtr->anchorCol = BETWEEN(col-tablePtr->colOffset, + 0, tablePtr->cols-1); + } else { + tablePtr->anchorRow = BETWEEN(row-tablePtr->rowOffset, + tablePtr->titleRows, tablePtr->rows-1); + tablePtr->anchorCol = BETWEEN(col-tablePtr->colOffset, + tablePtr->titleCols, tablePtr->cols-1); + } + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * Table_SelClearCmd -- + * This procedure is invoked to process the selection clear method + * that corresponds to a table widget managed by this module. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ +int +Table_SelClearCmd(ClientData clientData, register Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +{ + register Table *tablePtr = (Table *) clientData; + int result = TCL_OK; + char buf1[INDEX_BUFSIZE]; + int row, col, key, clo=0,chi=0,r1,c1,r2,c2; + Tcl_HashEntry *entryPtr; + + if (objc < 4 || objc > 5) { + Tcl_WrongNumArgs(interp, 3, objv, "all|<first> ?<last>?"); + return TCL_ERROR; + } + if (STREQ(Tcl_GetString(objv[3]), "all")) { + Tcl_HashSearch search; + for(entryPtr = Tcl_FirstHashEntry(tablePtr->selCells, &search); + entryPtr != NULL; entryPtr = Tcl_NextHashEntry(&search)) { + TableParseArrayIndex(&row, &col, + Tcl_GetHashKey(tablePtr->selCells,entryPtr)); + Tcl_DeleteHashEntry(entryPtr); + TableRefresh(tablePtr, row-tablePtr->rowOffset, + col-tablePtr->colOffset, CELL); + } + return TCL_OK; + } + if (TableGetIndexObj(tablePtr, objv[3], &row, &col) == TCL_ERROR || + (objc==5 && + TableGetIndexObj(tablePtr, objv[4], &r2, &c2) == TCL_ERROR)) { + return TCL_ERROR; + } + key = 0; + if (objc == 4) { + r1 = r2 = row; + c1 = c2 = col; + } else { + r1 = MIN(row,r2); r2 = MAX(row,r2); + c1 = MIN(col,c2); c2 = MAX(col,c2); + } + switch (tablePtr->selectType) { + case SEL_BOTH: + clo = c1; chi = c2; + c1 = tablePtr->colOffset; + c2 = tablePtr->cols-1+c1; + key = 1; + goto CLEAR_CELLS; + CLEAR_BOTH: + key = 0; + c1 = clo; c2 = chi; + case SEL_COL: + r1 = tablePtr->rowOffset; + r2 = tablePtr->rows-1+r1; + break; + case SEL_ROW: + c1 = tablePtr->colOffset; + c2 = tablePtr->cols-1+c1; + break; + } + /* row/col are in user index coords */ +CLEAR_CELLS: + for ( row = r1; row <= r2; row++ ) { + for ( col = c1; col <= c2; col++ ) { + TableMakeArrayIndex(row, col, buf1); + entryPtr = Tcl_FindHashEntry(tablePtr->selCells, buf1); + if (entryPtr != NULL) { + Tcl_DeleteHashEntry(entryPtr); + TableRefresh(tablePtr, row-tablePtr->rowOffset, + col-tablePtr->colOffset, CELL); + } + } + } + if (key) goto CLEAR_BOTH; + return result; +} + +/* + *-------------------------------------------------------------- + * + * Table_SelIncludesCmd -- + * This procedure is invoked to process the selection includes method + * that corresponds to a table widget managed by this module. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ +int +Table_SelIncludesCmd(ClientData clientData, register Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +{ + register Table *tablePtr = (Table *) clientData; + int row, col; + + if (objc != 4) { + Tcl_WrongNumArgs(interp, 3, objv, "index"); + return TCL_ERROR; + } else if (TableGetIndexObj(tablePtr, objv[3], &row, &col) == TCL_ERROR) { + return TCL_ERROR; + } else { + char buf[INDEX_BUFSIZE]; + TableMakeArrayIndex(row, col, buf); + Tcl_SetBooleanObj(Tcl_GetObjResult(interp), + (Tcl_FindHashEntry(tablePtr->selCells, buf)!=NULL)); + } + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * Table_SelSetCmd -- + * This procedure is invoked to process the selection set method + * that corresponds to a table widget managed by this module. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ +int +Table_SelSetCmd(ClientData clientData, register Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +{ + register Table *tablePtr = (Table *) clientData; + int row, col, dummy, key; + char buf1[INDEX_BUFSIZE]; + Tcl_HashSearch search; + Tcl_HashEntry *entryPtr; + + int clo=0, chi=0, r1, c1, r2, c2, firstRow, firstCol, lastRow, lastCol; + if (objc < 4 || objc > 5) { + Tcl_WrongNumArgs(interp, 3, objv, "first ?last?"); + return TCL_ERROR; + } + if (TableGetIndexObj(tablePtr, objv[3], &row, &col) == TCL_ERROR || + (objc==5 && + TableGetIndexObj(tablePtr, objv[4], &r2, &c2) == TCL_ERROR)) { + return TCL_ERROR; + } + key = 0; + lastRow = tablePtr->rows-1+tablePtr->rowOffset; + lastCol = tablePtr->cols-1+tablePtr->colOffset; + if (tablePtr->selectTitles) { + firstRow = tablePtr->rowOffset; + firstCol = tablePtr->colOffset; + } else { + firstRow = tablePtr->titleRows+tablePtr->rowOffset; + firstCol = tablePtr->titleCols+tablePtr->colOffset; + } + /* maintain appropriate user index */ + CONSTRAIN(row, firstRow, lastRow); + CONSTRAIN(col, firstCol, lastCol); + if (objc == 4) { + r1 = r2 = row; + c1 = c2 = col; + } else { + CONSTRAIN(r2, firstRow, lastRow); + CONSTRAIN(c2, firstCol, lastCol); + r1 = MIN(row,r2); r2 = MAX(row,r2); + c1 = MIN(col,c2); c2 = MAX(col,c2); + } + switch (tablePtr->selectType) { + case SEL_BOTH: + if (firstCol > lastCol) c2--; /* No selectable columns in table */ + if (firstRow > lastRow) r2--; /* No selectable rows in table */ + clo = c1; chi = c2; + c1 = firstCol; + c2 = lastCol; + key = 1; + goto SET_CELLS; + SET_BOTH: + key = 0; + c1 = clo; c2 = chi; + case SEL_COL: + r1 = firstRow; + r2 = lastRow; + if (firstCol > lastCol) c2--; /* No selectable columns in table */ + break; + case SEL_ROW: + c1 = firstCol; + c2 = lastCol; + if (firstRow>lastRow) r2--; /* No selectable rows in table */ + break; + } +SET_CELLS: + entryPtr = Tcl_FirstHashEntry(tablePtr->selCells, &search); + for ( row = r1; row <= r2; row++ ) { + for ( col = c1; col <= c2; col++ ) { + TableMakeArrayIndex(row, col, buf1); + if (Tcl_FindHashEntry(tablePtr->selCells, buf1) == NULL) { + Tcl_CreateHashEntry(tablePtr->selCells, buf1, &dummy); + TableRefresh(tablePtr, row-tablePtr->rowOffset, + col-tablePtr->colOffset, CELL); + } + } + } + if (key) goto SET_BOTH; + + /* Adjust the table for top left, selection on screen etc */ + TableAdjustParams(tablePtr); + + /* If the table was previously empty and we want to export the + * selection, we should grab it now */ + if (entryPtr == NULL && tablePtr->exportSelection) { + Tk_OwnSelection(tablePtr->tkwin, XA_PRIMARY, TableLostSelection, + (ClientData) tablePtr); + } + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * Table_ViewCmd -- + * This procedure is invoked to process the x|yview method + * that corresponds to a table widget managed by this module. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ +int +Table_ViewCmd(ClientData clientData, register Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +{ + register Table *tablePtr = (Table *) clientData; + int row, col, value; + char *xy; + + /* Check xview or yview */ + if (objc > 5) { + Tcl_WrongNumArgs(interp, 2, objv, "?args?"); + return TCL_ERROR; + } + xy = Tcl_GetString(objv[1]); + + if (objc == 2) { + Tcl_Obj *resultPtr; + int diff, x, y, w, h; + double first, last; + + resultPtr = Tcl_GetObjResult(interp); + TableGetLastCell(tablePtr, &row, &col); + TableCellVCoords(tablePtr, row, col, &x, &y, &w, &h, 0); + if (*xy == 'y') { + if (row < tablePtr->titleRows) { + first = 0; + last = 1; + } else { + diff = tablePtr->rowStarts[tablePtr->titleRows]; + last = (double) (tablePtr->rowStarts[tablePtr->rows]-diff); + first = (tablePtr->rowStarts[tablePtr->topRow]-diff) / last; + last = (h+tablePtr->rowStarts[row]-diff) / last; + } + } else { + if (col < tablePtr->titleCols) { + first = 0; + last = 1; + } else { + diff = tablePtr->colStarts[tablePtr->titleCols]; + last = (double) (tablePtr->colStarts[tablePtr->cols]-diff); + first = (tablePtr->colStarts[tablePtr->leftCol]-diff) / last; + last = (w+tablePtr->colStarts[col]-diff) / last; + } + } + Tcl_ListObjAppendElement(NULL, resultPtr, Tcl_NewDoubleObj(first)); + Tcl_ListObjAppendElement(NULL, resultPtr, Tcl_NewDoubleObj(last)); + } else { + /* cache old topleft to see if it changes */ + int oldTop = tablePtr->topRow, oldLeft = tablePtr->leftCol; + + if (objc == 3) { + if (Tcl_GetIntFromObj(interp, objv[2], &value) != TCL_OK) { + return TCL_ERROR; + } + if (*xy == 'y') { + tablePtr->topRow = value + tablePtr->titleRows; + } else { + tablePtr->leftCol = value + tablePtr->titleCols; + } + } else { + int result; + double frac; +#if (TK_MINOR_VERSION > 0) /* 8.1+ */ + result = Tk_GetScrollInfoObj(interp, objc, objv, &frac, &value); +#else + int i; + char **argv = (char **) ckalloc((objc + 1) * sizeof(char *)); + for (i = 0; i < objc; i++) { + argv[i] = Tcl_GetString(objv[i]); + } + argv[i] = NULL; + result = Tk_GetScrollInfo(interp, objc, argv, &frac, &value); + ckfree ((char *) argv); +#endif + switch (result) { + case TK_SCROLL_ERROR: + return TCL_ERROR; + case TK_SCROLL_MOVETO: + if (frac < 0) frac = 0; + if (*xy == 'y') { + tablePtr->topRow = (int)(frac*tablePtr->rows) + +tablePtr->titleRows; + } else { + tablePtr->leftCol = (int)(frac*tablePtr->cols) + +tablePtr->titleCols; + } + break; + case TK_SCROLL_PAGES: + TableGetLastCell(tablePtr, &row, &col); + if (*xy == 'y') { + tablePtr->topRow += value * (row-tablePtr->topRow+1); + } else { + tablePtr->leftCol += value * (col-tablePtr->leftCol+1); + } + break; + case TK_SCROLL_UNITS: + if (*xy == 'y') { + tablePtr->topRow += value; + } else { + tablePtr->leftCol += value; + } + break; + } + } + /* maintain appropriate real index */ + CONSTRAIN(tablePtr->topRow, tablePtr->titleRows, tablePtr->rows-1); + CONSTRAIN(tablePtr->leftCol, tablePtr->titleCols, tablePtr->cols-1); + /* Do the table adjustment if topRow || leftCol changed */ + if (oldTop != tablePtr->topRow || oldLeft != tablePtr->leftCol) { + TableAdjustParams(tablePtr); + } + } + + return TCL_OK; +} + +#if 0 +/* + *-------------------------------------------------------------- + * + * Table_Cmd -- + * This procedure is invoked to process the CMD method + * that corresponds to a table widget managed by this module. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ +int +Table_Cmd(ClientData clientData, register Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +{ + register Table *tablePtr = (Table *) clientData; + int result = TCL_OK; + + return result; +} +#endif diff --git a/libgui/src/tkTableEdit.c b/libgui/src/tkTableEdit.c new file mode 100644 index 00000000000..3fd6d4879b0 --- /dev/null +++ b/libgui/src/tkTableEdit.c @@ -0,0 +1,683 @@ +/* + * tkTableEdit.c -- + * + * This module implements editing functions of a table widget. + * + * Copyright (c) 1998-2000 Jeffrey Hobbs + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id$ + */ + +#include "tkTable.h" + +static void TableModifyRC _ANSI_ARGS_((register Table *tablePtr, + int doRows, int movetag, + Tcl_HashTable *tagTblPtr, Tcl_HashTable *dimTblPtr, + int offset, int from, int to, int lo, int hi, + int outOfBounds)); + +/* insert/delete subcommands */ +static char *modCmdNames[] = { + "active", "cols", "rows", (char *)NULL +}; +enum modCmd { + MOD_ACTIVE, MOD_COLS, MOD_ROWS +}; + +/* insert/delete row/col switches */ +static char *rcCmdNames[] = { + "-keeptitles", "-holddimensions", "-holdselection", + "-holdtags", "-holdwindows", "--", + (char *) NULL +}; +enum rcCmd { + OPT_TITLES, OPT_DIMS, OPT_SEL, + OPT_TAGS, OPT_WINS, OPT_LAST +}; + +#define HOLD_TITLES 1<<0 +#define HOLD_DIMS 1<<1 +#define HOLD_TAGS 1<<2 +#define HOLD_WINS 1<<3 +#define HOLD_SEL 1<<4 + + +/* + *-------------------------------------------------------------- + * + * Table_EditCmd -- + * This procedure is invoked to process the insert/delete method + * that corresponds to a table widget managed by this module. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ +int +Table_EditCmd(ClientData clientData, register Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +{ + register Table *tablePtr = (Table *) clientData; + int doInsert, cmdIndex, first, last; + + if (objc < 4) { + Tcl_WrongNumArgs(interp, 2, objv, + "option ?switches? arg ?arg?"); + return TCL_ERROR; + } + if (Tcl_GetIndexFromObj(interp, objv[2], modCmdNames, + "option", 0, &cmdIndex) != TCL_OK) { + return TCL_ERROR; + } + + doInsert = (*(Tcl_GetString(objv[1])) == 'i'); + switch ((enum modCmd) cmdIndex) { + case MOD_ACTIVE: + if (doInsert) { + /* INSERT */ + if (objc != 5) { + Tcl_WrongNumArgs(interp, 3, objv, "index string"); + return TCL_ERROR; + } + if (TableGetIcursorObj(tablePtr, objv[3], &first) != TCL_OK) { + return TCL_ERROR; + } else if ((tablePtr->flags & HAS_ACTIVE) && + !(tablePtr->flags & ACTIVE_DISABLED) && + tablePtr->state == STATE_NORMAL) { + TableInsertChars(tablePtr, first, Tcl_GetString(objv[4])); + } + } else { + /* DELETE */ + if (objc > 5) { + Tcl_WrongNumArgs(interp, 3, objv, "first ?last?"); + return TCL_ERROR; + } + if (TableGetIcursorObj(tablePtr, objv[3], &first) != TCL_OK) { + return TCL_ERROR; + } + if (objc == 4) { + last = first+1; + } else if (TableGetIcursorObj(tablePtr, objv[4], + &last) != TCL_OK) { + return TCL_ERROR; + } + if ((last >= first) && (tablePtr->flags & HAS_ACTIVE) && + !(tablePtr->flags & ACTIVE_DISABLED) && + tablePtr->state == STATE_NORMAL) { + TableDeleteChars(tablePtr, first, last-first); + } + } + break; /* EDIT ACTIVE */ + + case MOD_COLS: + case MOD_ROWS: { + /* + * ROW/COL INSERTION/DELETION + * FIX: This doesn't handle spans + */ + int i, lo, hi, argsLeft, offset, minkeyoff, doRows; + int maxrow, maxcol, maxkey, minkey, flags, count, *dimPtr; + Tcl_HashTable *tagTblPtr, *dimTblPtr; + Tcl_HashSearch search; + + doRows = (cmdIndex == MOD_ROWS); + flags = 0; + for (i = 3; i < objc; i++) { + if (*(Tcl_GetString(objv[i])) != '-') { + break; + } + if (Tcl_GetIndexFromObj(interp, objv[i], rcCmdNames, + "switch", 0, &cmdIndex) != TCL_OK) { + return TCL_ERROR; + } + if (cmdIndex == OPT_LAST) { + i++; + break; + } + switch (cmdIndex) { + case OPT_TITLES: + flags |= HOLD_TITLES; + break; + case OPT_DIMS: + flags |= HOLD_DIMS; + break; + case OPT_SEL: + flags |= HOLD_SEL; + break; + case OPT_TAGS: + flags |= HOLD_TAGS; + break; + case OPT_WINS: + flags |= HOLD_WINS; + break; + } + } + argsLeft = objc - i; + if (argsLeft < 1 || argsLeft > 2) { + Tcl_WrongNumArgs(interp, 3, objv, "?switches? index ?count?"); + return TCL_ERROR; + } + + count = 1; + maxcol = tablePtr->cols-1+tablePtr->colOffset; + maxrow = tablePtr->rows-1+tablePtr->rowOffset; + if (strcmp(Tcl_GetString(objv[i]), "end") == 0) { + /* allow "end" to be specified as an index */ + first = (doRows) ? maxrow : maxcol; + } else if (Tcl_GetIntFromObj(interp, objv[i], &first) != TCL_OK) { + return TCL_ERROR; + } + if (argsLeft == 2 && + Tcl_GetIntFromObj(interp, objv[++i], &count) != TCL_OK) { + return TCL_ERROR; + } + if (count == 0 || (tablePtr->state == STATE_DISABLED)) { + return TCL_OK; + } + + if (doRows) { + maxkey = maxrow; + minkey = tablePtr->rowOffset; + minkeyoff = tablePtr->rowOffset+tablePtr->titleRows; + offset = tablePtr->rowOffset; + tagTblPtr = tablePtr->rowStyles; + dimTblPtr = tablePtr->rowHeights; + dimPtr = &(tablePtr->rows); + lo = tablePtr->colOffset + + ((flags & HOLD_TITLES) ? tablePtr->titleCols : 0); + hi = maxcol; + } else { + maxkey = maxcol; + minkey = tablePtr->colOffset; + minkeyoff = tablePtr->colOffset+tablePtr->titleCols; + offset = tablePtr->colOffset; + tagTblPtr = tablePtr->colStyles; + dimTblPtr = tablePtr->colWidths; + dimPtr = &(tablePtr->cols); + lo = tablePtr->rowOffset + + ((flags & HOLD_TITLES) ? tablePtr->titleRows : 0); + hi = maxrow; + } + + /* constrain the starting index */ + if (first > maxkey) { + first = maxkey; + } else if (first < minkey) { + first = minkey; + } + if (doInsert) { + /* +count means insert after index, + * -count means insert before index */ + if (count < 0) { + count = -count; + } else { + first++; + } + if ((flags & HOLD_TITLES) && (first < minkeyoff)) { + count -= minkeyoff-first; + if (count <= 0) { + return TCL_OK; + } + first = minkeyoff; + } + if (!(flags & HOLD_DIMS)) { + maxkey += count; + *dimPtr += count; + } + for (i = maxkey; i >= first; i--) { + /* move row/col style && width/height here */ + TableModifyRC(tablePtr, doRows, flags, tagTblPtr, dimTblPtr, + offset, i, i-count, lo, hi, ((i-count) < first)); + } + } else { + /* (index = i && count = 1) == (index = i && count = -1) */ + if (count < 0) { + /* if the count is negative, make sure that the col count will + * delete no greater than the original index */ + if (first+count < minkey) { + if (first-minkey < abs(count)) { + /* + * In this case, the user is asking to delete more rows + * than exist before the minkey, so we have to shrink + * the count down to the existing rows up to index. + */ + count = first-minkey; + } else { + count += first-minkey; + } + first = minkey; + } else { + first += count; + count = -count; + } + } + if ((flags & HOLD_TITLES) && (first <= minkeyoff)) { + count -= minkeyoff-first; + if (count <= 0) { + return TCL_OK; + } + first = minkeyoff; + } + if (count > maxkey-first+1) { + count = maxkey-first+1; + } + if (!(flags & HOLD_DIMS)) { + *dimPtr -= count; + } + for (i = first; i <= maxkey; i++) { + TableModifyRC(tablePtr, doRows, flags, tagTblPtr, dimTblPtr, + offset, i, i+count, lo, hi, ((i+count) > maxkey)); + } + } + if (!(flags & HOLD_SEL) && + Tcl_FirstHashEntry(tablePtr->selCells, &search) != NULL) { + /* clear selection - forceful, but effective */ + Tcl_DeleteHashTable(tablePtr->selCells); + Tcl_InitHashTable(tablePtr->selCells, TCL_STRING_KEYS); + } + + /* + * Make sure that the modified dimension is actually legal + * after removing all that stuff. + */ + *dimPtr = MAX(1, *dimPtr); + + TableAdjustParams(tablePtr); + /* change the geometry */ + TableGeometryRequest(tablePtr); + /* FIX: + * This has to handle when the previous rows/cols resize because + * of the *stretchmode. InvalidateAll does that, but could be + * more efficient. + */ + TableInvalidateAll(tablePtr, 0); + break; + } + + } + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * TableDeleteChars -- + * Remove one or more characters from an table widget. + * + * Results: + * None. + * + * Side effects: + * Memory gets freed, the table gets modified and (eventually) + * redisplayed. + * + *---------------------------------------------------------------------- + */ +void +TableDeleteChars(tablePtr, index, count) + register Table *tablePtr; /* Table widget to modify. */ + int index; /* Index of first character to delete. */ + int count; /* How many characters to delete. */ +{ +#ifdef TCL_UTF_MAX + int byteIndex, byteCount, newByteCount, numBytes, numChars; + char *new, *string; + + string = tablePtr->activeBuf; + numBytes = strlen(string); + numChars = Tcl_NumUtfChars(string, numBytes); + if ((index + count) > numChars) { + count = numChars - index; + } + if (count <= 0) { + return; + } + + byteIndex = Tcl_UtfAtIndex(string, index) - string; + byteCount = Tcl_UtfAtIndex(string + byteIndex, count) + - (string + byteIndex); + + newByteCount = numBytes + 1 - byteCount; + new = (char *) ckalloc((unsigned) newByteCount); + memcpy(new, string, (size_t) byteIndex); + strcpy(new + byteIndex, string + byteIndex + byteCount); +#else + int oldlen; + char *new; + + /* this gets the length of the string, as well as ensuring that + * the cursor isn't beyond the end char */ + TableGetIcursor(tablePtr, "end", &oldlen); + + if ((index+count) > oldlen) + count = oldlen-index; + if (count <= 0) + return; + + new = (char *) ckalloc((unsigned)(oldlen-count+1)); + strncpy(new, tablePtr->activeBuf, (size_t) index); + strcpy(new+index, tablePtr->activeBuf+index+count); + /* make sure this string is null terminated */ + new[oldlen-count] = '\0'; +#endif + /* This prevents deletes on BREAK or validation error. */ + if (tablePtr->validate && + TableValidateChange(tablePtr, tablePtr->activeRow+tablePtr->rowOffset, + tablePtr->activeCol+tablePtr->colOffset, + tablePtr->activeBuf, new, index) != TCL_OK) { + ckfree(new); + return; + } + + ckfree(tablePtr->activeBuf); + tablePtr->activeBuf = new; + + /* mark the text as changed */ + tablePtr->flags |= TEXT_CHANGED; + + if (tablePtr->icursor >= index) { + if (tablePtr->icursor >= (index+count)) { + tablePtr->icursor -= count; + } else { + tablePtr->icursor = index; + } + } + + TableSetActiveIndex(tablePtr); + + TableRefresh(tablePtr, tablePtr->activeRow, tablePtr->activeCol, CELL); +} + +/* + *---------------------------------------------------------------------- + * + * TableInsertChars -- + * Add new characters to the active cell of a table widget. + * + * Results: + * None. + * + * Side effects: + * New information gets added to tablePtr; it will be redisplayed + * soon, but not necessarily immediately. + * + *---------------------------------------------------------------------- + */ +void +TableInsertChars(tablePtr, index, value) + register Table *tablePtr; /* Table that is to get the new elements. */ + int index; /* Add the new elements before this element. */ + char *value; /* New characters to add (NULL-terminated + * string). */ +{ +#ifdef TCL_UTF_MAX + int oldlen, byteIndex, byteCount; + char *new, *string; + + byteCount = strlen(value); + if (byteCount == 0) { + return; + } + + /* Is this an autoclear and this is the first update */ + /* Note that this clears without validating */ + if (tablePtr->autoClear && !(tablePtr->flags & TEXT_CHANGED)) { + /* set the buffer to be empty */ + tablePtr->activeBuf = (char *)ckrealloc(tablePtr->activeBuf, 1); + tablePtr->activeBuf[0] = '\0'; + /* the insert position now has to be 0 */ + index = 0; + tablePtr->icursor = 0; + } + + string = tablePtr->activeBuf; + byteIndex = Tcl_UtfAtIndex(string, index) - string; + + oldlen = strlen(string); + new = (char *) ckalloc((unsigned)(oldlen + byteCount + 1)); + memcpy(new, string, (size_t) byteIndex); + strcpy(new + byteIndex, value); + strcpy(new + byteIndex + byteCount, string + byteIndex); + + /* validate potential new active buffer */ + /* This prevents inserts on either BREAK or validation error. */ + if (tablePtr->validate && + TableValidateChange(tablePtr, tablePtr->activeRow+tablePtr->rowOffset, + tablePtr->activeCol+tablePtr->colOffset, + tablePtr->activeBuf, new, byteIndex) != TCL_OK) { + ckfree(new); + return; + } + + /* + * The following construction is used because inserting improperly + * formed UTF-8 sequences between other improperly formed UTF-8 + * sequences could result in actually forming valid UTF-8 sequences; + * the number of characters added may not be Tcl_NumUtfChars(string, -1), + * because of context. The actual number of characters added is how + * many characters were are in the string now minus the number that + * used to be there. + */ + + if (tablePtr->icursor >= index) { + tablePtr->icursor += Tcl_NumUtfChars(new, oldlen+byteCount) + - Tcl_NumUtfChars(tablePtr->activeBuf, oldlen); + } + + ckfree(string); + tablePtr->activeBuf = new; + +#else + int oldlen, newlen; + char *new; + + newlen = strlen(value); + if (newlen == 0) return; + + /* Is this an autoclear and this is the first update */ + /* Note that this clears without validating */ + if (tablePtr->autoClear && !(tablePtr->flags & TEXT_CHANGED)) { + /* set the buffer to be empty */ + tablePtr->activeBuf = (char *)ckrealloc(tablePtr->activeBuf, 1); + tablePtr->activeBuf[0] = '\0'; + /* the insert position now has to be 0 */ + index = 0; + } + oldlen = strlen(tablePtr->activeBuf); + /* get the buffer to at least the right length */ + new = (char *) ckalloc((unsigned)(oldlen+newlen+1)); + strncpy(new, tablePtr->activeBuf, (size_t) index); + strcpy(new+index, value); + strcpy(new+index+newlen, (tablePtr->activeBuf)+index); + /* make sure this string is null terminated */ + new[oldlen+newlen] = '\0'; + + /* validate potential new active buffer */ + /* This prevents inserts on either BREAK or validation error. */ + if (tablePtr->validate && + TableValidateChange(tablePtr, tablePtr->activeRow+tablePtr->rowOffset, + tablePtr->activeCol+tablePtr->colOffset, + tablePtr->activeBuf, new, index) != TCL_OK) { + ckfree(new); + return; + } + ckfree(tablePtr->activeBuf); + tablePtr->activeBuf = new; + + if (tablePtr->icursor >= index) { + tablePtr->icursor += newlen; + } +#endif + + /* mark the text as changed */ + tablePtr->flags |= TEXT_CHANGED; + + TableSetActiveIndex(tablePtr); + + TableRefresh(tablePtr, tablePtr->activeRow, tablePtr->activeCol, CELL); +} + +/* + *---------------------------------------------------------------------- + * + * TableModifyRC -- + * Helper function that does the core work of moving rows/cols + * and associated tags. + * + * Results: + * None. + * + * Side effects: + * Moves cell data and possibly tag data + * + *---------------------------------------------------------------------- + */ +static void +TableModifyRC(tablePtr, doRows, flags, tagTblPtr, dimTblPtr, + offset, from, to, lo, hi, outOfBounds) + Table *tablePtr; /* Information about text widget. */ + int doRows; /* rows (1) or cols (0) */ + int flags; /* flags indicating what to move */ + Tcl_HashTable *tagTblPtr, *dimTblPtr; /* Pointers to the row/col tags + * and width/height tags */ + int offset; /* appropriate offset */ + int from, to; /* the from and to row/col */ + int lo, hi; /* the lo and hi col/row */ + int outOfBounds; /* the boundary check for shifting items */ +{ + int j, new; + char buf[INDEX_BUFSIZE], buf1[INDEX_BUFSIZE]; + Tcl_HashEntry *entryPtr, *newPtr; + TableEmbWindow *ewPtr; + + /* + * move row/col style && width/height here + * If -holdtags is specified, we don't move the user-set widths/heights + * of the absolute rows/columns, otherwise we enter here to move the + * dimensions appropriately + */ + if (!(flags & HOLD_TAGS)) { + entryPtr = Tcl_FindHashEntry(tagTblPtr, (char *)from); + if (entryPtr != NULL) { + Tcl_DeleteHashEntry(entryPtr); + } + entryPtr = Tcl_FindHashEntry(dimTblPtr, (char *)from-offset); + if (entryPtr != NULL) { + Tcl_DeleteHashEntry(entryPtr); + } + if (!outOfBounds) { + entryPtr = Tcl_FindHashEntry(tagTblPtr, (char *)to); + if (entryPtr != NULL) { + newPtr = Tcl_CreateHashEntry(tagTblPtr, (char *)from, &new); + Tcl_SetHashValue(newPtr, Tcl_GetHashValue(entryPtr)); + Tcl_DeleteHashEntry(entryPtr); + } + entryPtr = Tcl_FindHashEntry(dimTblPtr, (char *)to-offset); + if (entryPtr != NULL) { + newPtr = Tcl_CreateHashEntry(dimTblPtr, (char *)from-offset, + &new); + Tcl_SetHashValue(newPtr, Tcl_GetHashValue(entryPtr)); + Tcl_DeleteHashEntry(entryPtr); + } + } + } + for (j = lo; j <= hi; j++) { + if (doRows /* rows */) { + TableMakeArrayIndex(from, j, buf); + TableMakeArrayIndex(to, j, buf1); + TableMoveCellValue(tablePtr, to, j, buf1, from, j, buf, + outOfBounds); + } else { + TableMakeArrayIndex(j, from, buf); + TableMakeArrayIndex(j, to, buf1); + TableMoveCellValue(tablePtr, j, to, buf1, j, from, buf, + outOfBounds); + } + /* + * If -holdselection is specified, we leave the selected cells in the + * absolute cell values, otherwise we enter here to move the + * selection appropriately + */ + if (!(flags & HOLD_SEL)) { + entryPtr = Tcl_FindHashEntry(tablePtr->selCells, buf); + if (entryPtr != NULL) { + Tcl_DeleteHashEntry(entryPtr); + } + if (!outOfBounds) { + entryPtr = Tcl_FindHashEntry(tablePtr->selCells, buf1); + if (entryPtr != NULL) { + Tcl_CreateHashEntry(tablePtr->selCells, buf, &new); + Tcl_DeleteHashEntry(entryPtr); + } + } + } + /* + * If -holdtags is specified, we leave the tags in the + * absolute cell values, otherwise we enter here to move the + * tags appropriately + */ + if (!(flags & HOLD_TAGS)) { + entryPtr = Tcl_FindHashEntry(tablePtr->cellStyles, buf); + if (entryPtr != NULL) { + Tcl_DeleteHashEntry(entryPtr); + } + if (!outOfBounds) { + entryPtr = Tcl_FindHashEntry(tablePtr->cellStyles, buf1); + if (entryPtr != NULL) { + newPtr = Tcl_CreateHashEntry(tablePtr->cellStyles, buf, + &new); + Tcl_SetHashValue(newPtr, Tcl_GetHashValue(entryPtr)); + Tcl_DeleteHashEntry(entryPtr); + } + } + } + /* + * If -holdwindows is specified, we leave the windows in the + * absolute cell values, otherwise we enter here to move the + * windows appropriately + */ + if (!(flags & HOLD_WINS)) { + /* + * Delete whatever window might be in our destination + */ + Table_WinDelete(tablePtr, buf); + if (!outOfBounds) { + /* + * buf1 is where the window is + * buf is where we want it to be + * + * This is an adaptation of Table_WinMove, which we can't + * use because we are intermediately fiddling with boundaries + */ + entryPtr = Tcl_FindHashEntry(tablePtr->winTable, buf1); + if (entryPtr != NULL) { + /* + * If there was a window in our source, + * get the window pointer to move it + */ + ewPtr = (TableEmbWindow *) Tcl_GetHashValue(entryPtr); + /* and free the old hash table entry */ + Tcl_DeleteHashEntry(entryPtr); + + entryPtr = Tcl_CreateHashEntry(tablePtr->winTable, buf, + &new); + /* + * We needn't check if a window was in buf, since the + * Table_WinDelete above should guarantee that no window + * is there. Just set the new entry's value. + */ + Tcl_SetHashValue(entryPtr, (ClientData) ewPtr); + ewPtr->hPtr = entryPtr; + } + } + } + } +} diff --git a/libgui/src/tkTableInitScript.h b/libgui/src/tkTableInitScript.h new file mode 100644 index 00000000000..1084717757b --- /dev/null +++ b/libgui/src/tkTableInitScript.h @@ -0,0 +1,90 @@ +/* + * tkTableInitScript.h -- + * + * This file contains common init script for tkTable + * + * Copyright (c) 1998 Jeffrey Hobbs + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + */ + +/* + * The following string is the startup script executed when the table is + * loaded. It looks on disk in several different directories for a script + * "TBL_RUNTIME" (as defined in Makefile) that is compatible with this + * version of tkTable. The sourced script has all key bindings defined. + */ + +static char tkTableInitScript[] = "if {[info proc tkTableInit]==\"\"} {\n\ + proc tkTableInit {} {\n\ + global tk_library tcl_pkgPath errorInfo env\n\ + rename tkTableInit {}\n\ + set errors {}\n\ + if {![info exists env(TK_TABLE_LIBRARY_FILE)]} {\n\ + set env(TK_TABLE_LIBRARY_FILE) " TBL_RUNTIME "\n\ + }\n\ + if {[info exists env(TK_TABLE_LIBRARY)]} {\n\ + lappend dirs $env(TK_TABLE_LIBRARY)\n\ + }\n\ + lappend dirs " TBL_RUNTIME_DIR "\n\ + if {[info exists tcl_pkgPath]} {\n\ + foreach i $tcl_pkgPath {\n\ + lappend dirs [file join $i Tktable" TBL_VERSION "] \\\n\ + [file join $i Tktable] $i\n\ + }\n\ + }\n\ + lappend dirs $tk_library [pwd]\n\ + foreach i $dirs {\n\ + set try [file join $i $env(TK_TABLE_LIBRARY_FILE)]\n\ + if {[file exists $try]} {\n\ + if {![catch {uplevel #0 [list source $try]} msg]} {\n\ + set env(TK_TABLE_LIBRARY) $i\n\ + return\n\ + } else {\n\ + append errors \"$try: $msg\n$errorInfo\n\"\n\ + }\n\ + }\n\ + }\n" +#ifdef NO_EMBEDDED_RUNTIME +" set msg \"Can't find a $env(TK_TABLE_LIBRARY_FILE) in the following directories: \n\"\n\ + append msg \" $dirs\n\n$errors\n\n\"\n\ + append msg \"This probably means that TkTable wasn't installed properly.\"\n\ + return -code error $msg\n" +#else +" set env(TK_TABLE_LIBRARY) EMBEDDED_RUNTIME\n" +# ifdef MAC_TCL +" source -rsrc tkTable" +# else +" uplevel #0 {" +# include "tkTable.tcl.h" +" }" +# endif +#endif +" }\n\ +}\n\ +tkTableInit"; + +/* + * The init script can't make certain calls in a safe interpreter, + * so we always have to use the embedded runtime for it + */ +static char tkTableSafeInitScript[] = "if {[info proc tkTableInit]==\"\"} {\n\ + proc tkTableInit {} {\n\ + set env(TK_TABLE_LIBRARY) EMBEDDED_RUNTIME\n" +#ifdef NO_EMBEDDED_RUNTIME +" append msg \"tkTable requires embedded runtime to be compiled for\"\n\ + append msg \" use in safe interpreters\"\n\ + return -code error $msg\n" +#endif +# ifdef MAC_TCL +" source -rsrc tkTable" +# else +" uplevel #0 {" +# include "tkTable.tcl.h" +" }" +# endif +" }\n\ +}\n\ +tkTableInit"; + diff --git a/libgui/src/tkTablePs.c b/libgui/src/tkTablePs.c new file mode 100644 index 00000000000..018f0791ec3 --- /dev/null +++ b/libgui/src/tkTablePs.c @@ -0,0 +1,1299 @@ +/* + * tkTablePs.c -- + * + * This module implements postscript output for table widgets. + * Based off of Tk8.1a2 tkCanvPs.c. + * + * Copyright (c) 1991-1994 The Regents of the University of California. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. + * changes 1998 Copyright (c) 1998 Jeffrey Hobbs + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + */ + +#include "tkTable.h" + +/* This is for Tcl_DStringAppendAll */ +#if defined(__STDC__) || defined(HAS_STDARG) +#include <stdarg.h> +#else +#include <varargs.h> +#endif + +#ifndef TCL_INTEGER_SPACE +/* This appears in 8.1 */ +#define TCL_INTEGER_SPACE 24 +#endif + +/* + * One of the following structures is created to keep track of Postscript + * output being generated. It consists mostly of information provided on + * the widget command line. + */ + +typedef struct TkPostscriptInfo { + int x, y, width, height; /* Area to print, in table pixel + * coordinates. */ + int x2, y2; /* x+width and y+height. */ + char *pageXString; /* String value of "-pagex" option or NULL. */ + char *pageYString; /* String value of "-pagey" option or NULL. */ + double pageX, pageY; /* Postscript coordinates (in points) + * corresponding to pageXString and + * pageYString. Don't forget that y-values + * grow upwards for Postscript! */ + char *pageWidthString; /* Printed width of output. */ + char *pageHeightString; /* Printed height of output. */ + double scale; /* Scale factor for conversion: each pixel + * maps into this many points. */ + Tk_Anchor pageAnchor; /* How to anchor bbox on Postscript page. */ + int rotate; /* Non-zero means output should be rotated + * on page (landscape mode). */ + char *fontVar; /* If non-NULL, gives name of global variable + * containing font mapping information. + * Malloc'ed. */ + char *colorVar; /* If non-NULL, give name of global variable + * containing color mapping information. + * Malloc'ed. */ + char *colorMode; /* Mode for handling colors: "monochrome", + * "gray", or "color". Malloc'ed. */ + int colorLevel; /* Numeric value corresponding to colorMode: + * 0 for mono, 1 for gray, 2 for color. */ + char *fileName; /* Name of file in which to write Postscript; + * NULL means return Postscript info as + * result. Malloc'ed. */ + char *channelName; /* If -channel is specified, the name of + * the channel to use. */ + Tcl_Channel chan; /* Open channel corresponding to fileName. */ + Tcl_HashTable fontTable; /* Hash table containing names of all font + * families used in output. The hash table + * values are not used. */ + char *first, *last; /* table indices to start and end at */ +} TkPostscriptInfo; + +/* + * The table below provides a template that's used to process arguments + * to the table "postscript" command and fill in TkPostscriptInfo + * structures. + */ + +static Tk_ConfigSpec configSpecs[] = { + {TK_CONFIG_STRING, "-colormap", (char *) NULL, (char *) NULL, "", + Tk_Offset(TkPostscriptInfo, colorVar), 0}, + {TK_CONFIG_STRING, "-colormode", (char *) NULL, (char *) NULL, "", + Tk_Offset(TkPostscriptInfo, colorMode), 0}, + {TK_CONFIG_STRING, "-file", (char *) NULL, (char *) NULL, "", + Tk_Offset(TkPostscriptInfo, fileName), 0}, + {TK_CONFIG_STRING, "-channel", (char *) NULL, (char *) NULL, "", + Tk_Offset(TkPostscriptInfo, channelName), 0}, + {TK_CONFIG_STRING, "-first", (char *) NULL, (char *) NULL, "", + Tk_Offset(TkPostscriptInfo, first), 0}, + {TK_CONFIG_STRING, "-fontmap", (char *) NULL, (char *) NULL, "", + Tk_Offset(TkPostscriptInfo, fontVar), 0}, + {TK_CONFIG_PIXELS, "-height", (char *) NULL, (char *) NULL, "", + Tk_Offset(TkPostscriptInfo, height), 0}, + {TK_CONFIG_STRING, "-last", (char *) NULL, (char *) NULL, "", + Tk_Offset(TkPostscriptInfo, last), 0}, + {TK_CONFIG_ANCHOR, "-pageanchor", (char *) NULL, (char *) NULL, "", + Tk_Offset(TkPostscriptInfo, pageAnchor), 0}, + {TK_CONFIG_STRING, "-pageheight", (char *) NULL, (char *) NULL, "", + Tk_Offset(TkPostscriptInfo, pageHeightString), 0}, + {TK_CONFIG_STRING, "-pagewidth", (char *) NULL, (char *) NULL, "", + Tk_Offset(TkPostscriptInfo, pageWidthString), 0}, + {TK_CONFIG_STRING, "-pagex", (char *) NULL, (char *) NULL, "", + Tk_Offset(TkPostscriptInfo, pageXString), 0}, + {TK_CONFIG_STRING, "-pagey", (char *) NULL, (char *) NULL, "", + Tk_Offset(TkPostscriptInfo, pageYString), 0}, + {TK_CONFIG_BOOLEAN, "-rotate", (char *) NULL, (char *) NULL, "", + Tk_Offset(TkPostscriptInfo, rotate), 0}, + {TK_CONFIG_PIXELS, "-width", (char *) NULL, (char *) NULL, "", + Tk_Offset(TkPostscriptInfo, width), 0}, + {TK_CONFIG_PIXELS, "-x", (char *) NULL, (char *) NULL, "", + Tk_Offset(TkPostscriptInfo, x), 0}, + {TK_CONFIG_PIXELS, "-y", (char *) NULL, (char *) NULL, "", + Tk_Offset(TkPostscriptInfo, y), 0}, + {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, + (char *) NULL, 0, 0} +}; + +/* + * The prolog data. Generated by str2c from prolog.ps + * This was split in small chunks by str2c because + * some C compiler have limitations on the size of static strings. + * (str2c is a small tcl script in tcl's tool directory (source release)) + */ +/* + * This is a stripped down version of that found in tkCanvPs.c of Tk8.1a2. + * Comments, and stuff pertaining to stipples and other unused entities + * have been removed + */ +static CONST char * CONST prolog[]= { + /* Start of part 1 */ + "%%BeginProlog\n\ +50 dict begin\n\ +\n\ +% This is standard prolog for Postscript generated by Tk's table widget.\n\ +% Based of standard prolog for Tk's canvas widget.\n\ +\n\ +% INITIALIZING VARIABLES\n\ +\n\ +/baseline 0 def\n\ +/height 0 def\n\ +/justify 0 def\n\ +/cellHeight 0 def\n\ +/cellWidth 0 def\n\ +/spacing 0 def\n\ +/strings 0 def\n\ +/xoffset 0 def\n\ +/yoffset 0 def\n\ +/x 0 def\n\ +/y 0 def\n\ +\n\ +% Define the array ISOLatin1Encoding, if it isn't already present.\n\ +\n\ +systemdict /ISOLatin1Encoding known not {\n\ + /ISOLatin1Encoding [\n\ + /space /space /space /space /space /space /space /space\n\ + /space /space /space /space /space /space /space /space\n\ + /space /space /space /space /space /space /space /space\n\ + /space /space /space /space /space /space /space /space\n\ + /space /exclam /quotedbl /numbersign /dollar /percent /ampersand\n\ + /quoteright\n\ + /parenleft /parenright /asterisk /plus /comma /minus /period /slash\n\ + /zero /one /two /three /four /five /six /seven\n\ + /eight /nine /colon /semicolon /less /equal /greater /question\n\ + /at /A /B /C /D /E /F /G\n\ + /H /I /J /K /L /M /N /O\n\ + /P /Q /R /S /T /U /V /W\n\ + /X /Y /Z /bracketleft /backslash /bracketright /asciicircum /underscore\n\ + /quoteleft /a /b /c /d /e /f /g\n\ + /h /i /j /k /l /m /n /o\n\ + /p /q /r /s /t /u /v /w\n\ + /x /y /z /braceleft /bar /braceright /asciitilde /space\n\ + /space /space /space /space /space /space /space /space\n\ + /space /space /space /space /space /space /space /space\n\ + /dotlessi /grave /acute /circumflex /tilde /macron /breve /dotaccent\n\ + /dieresis /space /ring /cedilla /space /hungarumlaut /ogonek /caron\n\ + /space /exclamdown /cent /sterling /currency /yen /brokenbar /section\n\ + /dieresis /copyright /ordfem", + + "inine /guillemotleft /logicalnot /hyphen\n\ + /registered /macron\n\ + /degree /plusminus /twosuperior /threesuperior /acute /mu /paragraph\n\ + /periodcentered\n\ + /cedillar /onesuperior /ordmasculine /guillemotright /onequarter\n\ + /onehalf /threequarters /questiondown\n\ + /Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla\n\ + /Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex\n\ + /Idieresis\n\ + /Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply\n\ + /Oslash /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn\n\ + /germandbls\n\ + /agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla\n\ + /egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex\n\ + /idieresis\n\ + /eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis /divide\n\ + /oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn\n\ + /ydieresis\n\ + ] def\n\ +} if\n", + + "\n\ +% font ISOEncode font\n\ +% This procedure changes the encoding of a font from the default\n\ +% Postscript encoding to ISOLatin1. It's typically invoked just\n\ +% before invoking \"setfont\". The body of this procedure comes from\n\ +% Section 5.6.1 of the Postscript book.\n\ +\n\ +/ISOEncode {\n\ + dup length dict begin\n\ + {1 index /FID ne {def} {pop pop} ifelse} forall\n\ + /Encoding ISOLatin1Encoding def\n\ + currentdict\n\ + end\n\ +\n\ + % I'm not sure why it's necessary to use \"definefont\" on this new\n\ + % font, but it seems to be important; just use the name \"Temporary\"\n\ + % for the font.\n\ +\n\ + /Temporary exch definefont\n\ +} bind def\n\ +\n\ +% -- AdjustColor --\n\ +% Given a color value already set for output by the caller, adjusts\n\ +% that value to a grayscale or mono value if requested by the CL variable.\n\ +\n\ +/AdjustColor {\n\ + setrgbcolor\n\ + CL 2 lt {\n\ + currentgray\n\ + CL 0 eq {\n\ + .5 lt {0} {1} ifelse\n\ + } if\n\ + setgray\n\ + } if\n\ +} bind def\n\ +\n\ +% pointSize fontName SetFont\n\ +% The ISOEncode shouldn't be done to Symbol fonts...\n\ +/SetFont {\n\ + findfont exch scalefont ISOEncode setfont\n\ +} def\n\ +\n", + + "% x y strings spacing xoffset yoffset justify ... DrawText --\n\ +% This procedure does all of the real work of drawing text. The\n\ +% color and font must already have been set by the caller, and the\n\ +% following arguments must be on the stack:\n\ +%\n\ +% x, y - Coordinates at which to draw text.\n\ +% strings - An array of strings, one for each line of the text item,\n\ +% in order from top to bottom.\n\ +% spacing - Spacing between lines.\n\ +% xoffset - Horizontal offset for text bbox relative to x and y: 0 for\n\ +% nw/w/sw anchor, -0.5 for n/center/s, and -1.0 for ne/e/se.\n\ +% yoffset - Vertical offset for text bbox relative to x and y: 0 for\n\ +% nw/n/ne anchor, +0.5 for w/center/e, and +1.0 for sw/s/se.\n\ +% justify - 0 for left justification, 0.5 for center, 1 for right justify.\n\ +% cellWidth - width for this cell\n\ +% cellHeight - height for this cell\n\ +%\n\ +% Also, when this procedure is invoked, the color and font must already\n\ +% have been set for the text.\n\ +\n", + + "/DrawCellText {\n\ + /cellHeight exch def\n\ + /cellWidth exch def\n\ + /justify exch def\n\ + /yoffset exch def\n\ + /xoffset exch def\n\ + /spacing exch def\n\ + /strings exch def\n\ + /y exch def\n\ + /x exch def\n\ +\n\ + % Compute the baseline offset and the actual font height.\n\ +\n\ + 0 0 moveto (TXygqPZ) false charpath\n\ + pathbbox dup /baseline exch def\n\ + exch pop exch sub /height exch def pop\n\ + newpath\n\ +\n\ + % Translate coordinates first so that the origin is at the upper-left\n\ + % corner of the text's bounding box. Remember that x and y for\n\ + % positioning are still on the stack.\n\ +\n\ + col0 x sub row0 y sub translate\n\ + cellWidth xoffset mul\n\ + strings length 1 sub spacing mul height add yoffset mul translate\n\ +\n\ + % Now use the baseline and justification information to translate so\n\ + % that the origin is at the baseline and positioning point for the\n\ + % first line of text.\n\ +\n\ + justify cellWidth mul baseline neg translate\n\ +\n\ + % Iterate over each of the lines to output it. For each line,\n\ + % compute its width again so it can be properly justified, then\n\ + % display it.\n\ +\n\ + strings {\n\ + dup stringwidth pop\n\ + justify neg mul 0 moveto\n\ + show\n\ + 0 spacing neg translate\n\ + } forall\n\ +} bind def\n\ +\n", + + "%\n\ +% x, y - Coordinates at which to draw text.\n\ +% strings - An array of strings, one for each line of the text item,\n\ +% in order from top to bottom.\n\ +% spacing - Spacing between lines.\n\ +% xoffset - Horizontal offset for text bbox relative to x and y: 0 for\n\ +% nw/w/sw anchor, -0.5 for n/center/s, and -1.0 for ne/e/se.\n\ +% yoffset - Vertical offset for text bbox relative to x and y: 0 for\n\ +% nw/n/ne anchor, +0.5 for w/center/e, and +1.0 for sw/s/se.\n\ +% justify - 0 for left justification, 0.5 for center, 1 for right justify.\n\ +% cellWidth - width for this cell\n\ +% cellHeight - height for this cell\n\ +%\n\ +% Also, when this procedure is invoked, the color and font must already\n\ +% have been set for the text.\n\ +\n\ +/DrawCellTextOld {\n\ + /cellHeight exch def\n\ + /cellWidth exch def\n\ + /justify exch def\n\ + /yoffset exch def\n\ + /xoffset exch def\n\ + /spacing exch def\n\ + /strings exch def\n\ +\n\ + % Compute the baseline offset and the actual font height.\n\ +\n\ + 0 0 moveto (TXygqPZ) false charpath\n\ + pathbbox dup /baseline exch def\n\ + exch pop exch sub /height exch def pop\n\ + newpath\n\ +\n\ + % Translate coordinates first so that the origin is at the upper-left\n\ + % corner of the text's bounding box. Remember that x and y for\n\ + % positioning are still on the stack.\n\ +\n\ + translate\n\ + cellWidth xoffset mul\n\ + strings length 1 sub spacing mul height add yoffset mul translate\n\ +\n\ + % Now use the baseline and justification information to translate so\n\ + % that the origin is at the baseline and positioning point for the\n\ + % first line of text.\n\ +\n\ + justify cellWidth mul baseline neg translate\n\ +\n\ + % Iterate over each of the lines to output it. For each line,\n\ + % compute its width again so it can be properly justified, then\n\ + % display it.\n\ +\n\ + strings {\n\ + dup stringwidth pop\n\ + justify neg mul 0 moveto\n\ + show\n\ + 0 spacing neg translate\n\ + } forall\n\ +} bind def\n\ +\n\ +%%EndProlog\n\ +", + /* End of part 5 */ + + NULL /* End of data marker */ +}; + +/* + * Forward declarations for procedures defined later in this file: + */ + +static int GetPostscriptPoints _ANSI_ARGS_((Tcl_Interp *interp, + char *string, double *doublePtr)); +int Tk_TablePsFont _ANSI_ARGS_((Tcl_Interp *interp, + Table *tablePtr, Tk_Font tkfont)); +int Tk_TablePsColor _ANSI_ARGS_((Tcl_Interp *interp, + Table *tablePtr, XColor *colorPtr)); +static int TextToPostscript _ANSI_ARGS_((Tcl_Interp *interp, + Table *tablePtr, TableTag *tagPtr, int tagX, int tagY, + int width, int height, int row, int col, + Tk_TextLayout textLayout)); + +/* + * Tcl could really use some more convenience routines... + * This is just Tcl_DStringAppend for multiple lines, including + * the full text of each line + */ +void +Tcl_DStringAppendAll TCL_VARARGS_DEF(Tcl_DString *, arg1) +{ + va_list argList; + Tcl_DString *dstringPtr; + char *string; + + dstringPtr = TCL_VARARGS_START(Tcl_DString *, arg1, argList); + while ((string = va_arg(argList, char *)) != NULL) { + Tcl_DStringAppend(dstringPtr, string, -1); + } + va_end(argList); +} + +/* + *-------------------------------------------------------------- + * + * Table_PostscriptCmd -- + * + * This procedure is invoked to process the "postscript" options + * of the widget command for table widgets. See the user + * documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Table_PostscriptCmd(clientData, interp, objc, objv) + ClientData clientData; /* Information about table widget. */ + Tcl_Interp *interp; /* Current interpreter. */ + int objc; /* Number of argument objects. */ + Tcl_Obj *CONST objv[]; +{ +#ifdef _WIN32 + /* + * At the moment, it just doesn't like this code... + */ + return TCL_OK; +#else + register Table *tablePtr = (Table *) clientData; + TkPostscriptInfo psInfo, *oldInfoPtr; + int result; + int row, col, firstRow, firstCol, lastRow, lastCol; + /* dimensions of first and last cell to output */ + int x0, y0, w0, h0, xn, yn, wn, hn; + int x, y, w, h, i; +#define STRING_LENGTH 400 + char string[STRING_LENGTH+1], *p, **argv; + size_t length; + int deltaX = 0, deltaY = 0; /* Offset of lower-left corner of area to + * be marked up, measured in table units + * from the positioning point on the page + * (reflects anchor position). Initial + * values needed only to stop compiler + * warnings. */ + Tcl_HashSearch search; + Tcl_HashEntry *hPtr; + CONST char * CONST *chunk; + Tk_TextLayout textLayout = NULL; + char *value; + int rowHeight, total, *colWidths, iW, iH; + TableTag *tagPtr, *colPtr, *rowPtr, *titlePtr; + Tcl_DString postscript, buffer; + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 2, objv, "?option value ...?"); + return TCL_ERROR; + } + + /* + *---------------------------------------------------------------- + * Initialize the data structure describing Postscript generation, + * then process all the arguments to fill the data structure in. + *---------------------------------------------------------------- + */ + + Tcl_DStringInit(&postscript); + Tcl_DStringInit(&buffer); + oldInfoPtr = tablePtr->psInfoPtr; + tablePtr->psInfoPtr = &psInfo; + /* This is where in the window that we start printing from */ + psInfo.x = 0; + psInfo.y = 0; + psInfo.width = -1; + psInfo.height = -1; + psInfo.pageXString = NULL; + psInfo.pageYString = NULL; + psInfo.pageX = 72*4.25; + psInfo.pageY = 72*5.5; + psInfo.pageWidthString = NULL; + psInfo.pageHeightString = NULL; + psInfo.scale = 1.0; + psInfo.pageAnchor = TK_ANCHOR_CENTER; + psInfo.rotate = 0; + psInfo.fontVar = NULL; + psInfo.colorVar = NULL; + psInfo.colorMode = NULL; + psInfo.colorLevel = 0; + psInfo.fileName = NULL; + psInfo.channelName = NULL; + psInfo.chan = NULL; + psInfo.first = NULL; + psInfo.last = NULL; + Tcl_InitHashTable(&psInfo.fontTable, TCL_STRING_KEYS); + + /* + * The magic StringifyObjects + */ + argv = (char **) ckalloc((objc + 1) * sizeof(char *)); + for (i = 0; i < objc; i++) + argv[i] = Tcl_GetString(objv[i]); + argv[i] = NULL; + + result = Tk_ConfigureWidget(interp, tablePtr->tkwin, configSpecs, + objc-2, argv+2, (char *) &psInfo, + TK_CONFIG_ARGV_ONLY); + if (result != TCL_OK) { + goto cleanup; + } + + if (psInfo.first == NULL) { + firstRow = 0; + firstCol = 0; + } else if (TableGetIndex(tablePtr, psInfo.first, &firstRow, &firstCol) + != TCL_OK) { + result = TCL_ERROR; + goto cleanup; + } + if (psInfo.last == NULL) { + lastRow = tablePtr->rows-1; + lastCol = tablePtr->cols-1; + } else if (TableGetIndex(tablePtr, psInfo.last, &lastRow, &lastCol) + != TCL_OK) { + result = TCL_ERROR; + goto cleanup; + } + + if (psInfo.fileName != NULL) { + /* Check that -file and -channel are not both specified. */ + if (psInfo.channelName != NULL) { + Tcl_AppendResult(interp, "can't specify both -file", + " and -channel", (char *) NULL); + result = TCL_ERROR; + goto cleanup; + } + + /* + * Check that we are not in a safe interpreter. If we are, disallow + * the -file specification. + */ + if (Tcl_IsSafe(interp)) { + Tcl_AppendResult(interp, "can't specify -file in a", + " safe interpreter", (char *) NULL); + result = TCL_ERROR; + goto cleanup; + } + + p = Tcl_TranslateFileName(interp, psInfo.fileName, &buffer); + if (p == NULL) { + result = TCL_ERROR; + goto cleanup; + } + psInfo.chan = Tcl_OpenFileChannel(interp, p, "w", 0666); + Tcl_DStringFree(&buffer); + Tcl_DStringInit(&buffer); + if (psInfo.chan == NULL) { + result = TCL_ERROR; + goto cleanup; + } + } + + if (psInfo.channelName != NULL) { + int mode; + /* + * Check that the channel is found in this interpreter and that it + * is open for writing. + */ + psInfo.chan = Tcl_GetChannel(interp, psInfo.channelName, &mode); + if (psInfo.chan == (Tcl_Channel) NULL) { + result = TCL_ERROR; + goto cleanup; + } + if ((mode & TCL_WRITABLE) == 0) { + Tcl_AppendResult(interp, "channel \"", psInfo.channelName, + "\" wasn't opened for writing", (char *) NULL); + result = TCL_ERROR; + goto cleanup; + } + } + + if (psInfo.colorMode == NULL) { + psInfo.colorLevel = 2; + } else { + length = strlen(psInfo.colorMode); + if (strncmp(psInfo.colorMode, "monochrome", length) == 0) { + psInfo.colorLevel = 0; + } else if (strncmp(psInfo.colorMode, "gray", length) == 0) { + psInfo.colorLevel = 1; + } else if (strncmp(psInfo.colorMode, "color", length) == 0) { + psInfo.colorLevel = 2; + } else { + Tcl_AppendResult(interp, "bad color mode \"", psInfo.colorMode, + "\": must be monochrome, gray or color", (char *) NULL); + goto cleanup; + } + } + + TableCellCoords(tablePtr, firstRow, firstCol, &x0, &y0, &w0, &h0); + TableCellCoords(tablePtr, lastRow, lastCol, &xn, &yn, &wn, &hn); + psInfo.x = x0; + psInfo.y = y0; + if (psInfo.width == -1) { + psInfo.width = xn+wn; + } + if (psInfo.height == -1) { + psInfo.height = yn+hn; + } + psInfo.x2 = psInfo.x + psInfo.width; + psInfo.y2 = psInfo.y + psInfo.height; + + if (psInfo.pageXString != NULL) { + if (GetPostscriptPoints(interp, psInfo.pageXString, + &psInfo.pageX) != TCL_OK) { + goto cleanup; + } + } + if (psInfo.pageYString != NULL) { + if (GetPostscriptPoints(interp, psInfo.pageYString, + &psInfo.pageY) != TCL_OK) { + goto cleanup; + } + } + if (psInfo.pageWidthString != NULL) { + if (GetPostscriptPoints(interp, psInfo.pageWidthString, + &psInfo.scale) != TCL_OK) { + goto cleanup; + } + psInfo.scale /= psInfo.width; + } else if (psInfo.pageHeightString != NULL) { + if (GetPostscriptPoints(interp, psInfo.pageHeightString, + &psInfo.scale) != TCL_OK) { + goto cleanup; + } + psInfo.scale /= psInfo.height; + } else { + psInfo.scale = (72.0/25.4)*WidthMMOfScreen(Tk_Screen(tablePtr->tkwin)) + / WidthOfScreen(Tk_Screen(tablePtr->tkwin)); + } + switch (psInfo.pageAnchor) { + case TK_ANCHOR_NW: + case TK_ANCHOR_W: + case TK_ANCHOR_SW: + deltaX = 0; + break; + case TK_ANCHOR_N: + case TK_ANCHOR_CENTER: + case TK_ANCHOR_S: + deltaX = -psInfo.width/2; + break; + case TK_ANCHOR_NE: + case TK_ANCHOR_E: + case TK_ANCHOR_SE: + deltaX = -psInfo.width; + break; + } + switch (psInfo.pageAnchor) { + case TK_ANCHOR_NW: + case TK_ANCHOR_N: + case TK_ANCHOR_NE: + deltaY = - psInfo.height; + break; + case TK_ANCHOR_W: + case TK_ANCHOR_CENTER: + case TK_ANCHOR_E: + deltaY = -psInfo.height/2; + break; + case TK_ANCHOR_SW: + case TK_ANCHOR_S: + case TK_ANCHOR_SE: + deltaY = 0; + break; + } + + /* + *-------------------------------------------------------- + * Make a PREPASS over all of the tags + * to collect information about all the fonts in use, so that + * we can output font information in the proper form required + * by the Document Structuring Conventions. + *-------------------------------------------------------- + */ + + Tk_TablePsFont(interp, tablePtr, tablePtr->defaultTag.tkfont); + Tcl_ResetResult(interp); + for (hPtr = Tcl_FirstHashEntry(tablePtr->tagTable, &search); + hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { + tagPtr = (TableTag *) Tcl_GetHashValue(hPtr); + if (tagPtr->tkfont != NULL) { + Tk_TablePsFont(interp, tablePtr, tagPtr->tkfont); + } + } + Tcl_ResetResult(interp); + + /* + *-------------------------------------------------------- + * Generate the header and prolog for the Postscript. + *-------------------------------------------------------- + */ + + sprintf(string, " %d,%d => %d,%d\n", firstRow, firstCol, lastRow, lastCol); + Tcl_DStringAppendAll(&postscript, + "%!PS-Adobe-3.0 EPSF-3.0\n", + "%%Creator: Tk Table Widget ", TBL_VERSION, "\n", + "%%Title: Window ", + Tk_PathName(tablePtr->tkwin), string, + "%%BoundingBox: ", + (char *) NULL); + if (!psInfo.rotate) { + sprintf(string, "%d %d %d %d\n", + (int) (psInfo.pageX + psInfo.scale*deltaX), + (int) (psInfo.pageY + psInfo.scale*deltaY), + (int) (psInfo.pageX + psInfo.scale*(deltaX + psInfo.width) + + 1.0), + (int) (psInfo.pageY + psInfo.scale*(deltaY + psInfo.height) + + 1.0)); + } else { + sprintf(string, "%d %d %d %d\n", + (int) (psInfo.pageX - psInfo.scale*(deltaY + psInfo.height)), + (int) (psInfo.pageY + psInfo.scale*deltaX), + (int) (psInfo.pageX - psInfo.scale*deltaY + 1.0), + (int) (psInfo.pageY + psInfo.scale*(deltaX + psInfo.width) + + 1.0)); + } + Tcl_DStringAppendAll(&postscript, string, + "%%Pages: 1\n%%DocumentData: Clean7Bit\n", + "%%Orientation: ", + psInfo.rotate?"Landscape\n":"Portrait\n", + (char *) NULL); + p = "%%DocumentNeededResources: font "; + for (hPtr = Tcl_FirstHashEntry(&psInfo.fontTable, &search); + hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { + sprintf(string, "%s%s\n", p, Tcl_GetHashKey(&psInfo.fontTable, hPtr)); + Tcl_DStringAppend(&postscript, string, -1); + p = "%%+ font "; + } + Tcl_DStringAppend(&postscript, "%%EndComments\n\n", -1); + + /* + * Insert the prolog + */ + for (chunk=prolog; *chunk; chunk++) { + Tcl_DStringAppend(&postscript, *chunk, -1); + } + + if (psInfo.chan != NULL) { + Tcl_Write(psInfo.chan, Tcl_DStringValue(&postscript), -1); + Tcl_DStringFree(&postscript); + Tcl_DStringInit(&postscript); + } + + /* + * Document setup: set the color level and include fonts. + * This is where we start using &postscript + */ + + sprintf(string, "/CL %d def\n", psInfo.colorLevel); + Tcl_DStringAppendAll(&postscript, "%%BeginSetup\n", string, (char *) NULL); + for (hPtr = Tcl_FirstHashEntry(&psInfo.fontTable, &search); + hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { + sprintf(string, "%s%s\n", "%%IncludeResource: font ", + Tcl_GetHashKey(&psInfo.fontTable, hPtr)); + Tcl_DStringAppend(&postscript, string, -1); + } + Tcl_DStringAppend(&postscript, "%%EndSetup\n\n", -1); + + /* + * Page setup: move to page positioning point, rotate if + * needed, set scale factor, offset for proper anchor position, + * and set clip region. + */ + + sprintf(string, "%.1f %.1f translate\n", + psInfo.pageX, psInfo.pageY); + Tcl_DStringAppendAll(&postscript, "%%Page: 1 1\nsave\n", + string, psInfo.rotate?"90 rotate\n":"", + (char *) NULL); + sprintf(string, "%.4g %.4g scale\n%d %d translate\n", + psInfo.scale, psInfo.scale, deltaX - psInfo.x, deltaY); + Tcl_DStringAppend(&postscript, string, -1); + sprintf(string, "%d %.15g moveto %d %.15g lineto %d %.15g lineto %d %.15g", + psInfo.x, (double) psInfo.y2-psInfo.y, + psInfo.x2,(double) psInfo.y2-psInfo.y, + psInfo.x2, 0.0, psInfo.x, 0.0); + Tcl_DStringAppend(&postscript, string, -1); + Tcl_DStringAppend(&postscript, " lineto closepath clip newpath\n", -1); + if (psInfo.chan != NULL) { + Tcl_Write(psInfo.chan, Tcl_DStringValue(&postscript), -1); + Tcl_DStringFree(&postscript); + Tcl_DStringInit(&postscript); + } + + /* + * Go through each cell, calculating full desired height + */ + result = TCL_OK; + + hPtr = Tcl_FindHashEntry(tablePtr->tagTable, "title"); + titlePtr = (TableTag *) Tcl_GetHashValue(hPtr); + + total = 0; + colWidths = (int *) ckalloc((lastCol-firstCol) * sizeof(int)); + for (col = 0; col <= lastCol-firstCol; col++) colWidths[col] = 0; + Tcl_DStringAppend(&buffer, "gsave\n", -1); + for (row = firstRow; row <= lastRow; row++) { + rowHeight = 0; + rowPtr = FindRowColTag(tablePtr, row+tablePtr->rowOffset, ROW); + for (col = firstCol; col <= lastCol; col++) { + /* get the coordinates for the cell */ + TableCellCoords(tablePtr, row, col, &x, &y, &w, &h); + if ((x >= psInfo.x2) || (x+w < psInfo.x) || + (y >= psInfo.y2) || (y+h < psInfo.y)) { + continue; + } + + if (row == tablePtr->activeRow && col == tablePtr->activeCol) { + value = tablePtr->activeBuf; + } else { + value = TableGetCellValue(tablePtr, row+tablePtr->rowOffset, + col+tablePtr->colOffset); + } + if (!strlen(value)) { + continue; + } + + /* Create the tag here */ + tagPtr = TableNewTag(); + /* First, merge in the default tag */ + TableMergeTag(tagPtr, &(tablePtr->defaultTag)); + + colPtr = FindRowColTag(tablePtr, col+tablePtr->colOffset, COL); + if (colPtr != (TableTag *) NULL) TableMergeTag(tagPtr, colPtr); + if (rowPtr != (TableTag *) NULL) TableMergeTag(tagPtr, rowPtr); + /* Am I in the titles */ + if (row < tablePtr->topRow || col < tablePtr->leftCol) { + TableMergeTag(tagPtr, titlePtr); + } + /* Does this have a cell tag */ + TableMakeArrayIndex(row+tablePtr->rowOffset, + col+tablePtr->colOffset, string); + hPtr = Tcl_FindHashEntry(tablePtr->cellStyles, string); + if (hPtr != NULL) { + TableMergeTag(tagPtr, (TableTag *) Tcl_GetHashValue(hPtr)); + } + + /* + * the use of -1 instead of Tcl_NumUtfChars means we don't + * pass NULLs to postscript + */ + textLayout = Tk_ComputeTextLayout(tagPtr->tkfont, value, -1, + (tagPtr->wrap>0) ? w : 0, + tagPtr->justify, + (tagPtr->multiline>0) ? 0 : + TK_IGNORE_NEWLINES, &iW, &iH); + + rowHeight = MAX(rowHeight, iH); + colWidths[col-firstCol] = MAX(colWidths[col-firstCol], iW); + + result = TextToPostscript(interp, tablePtr, tagPtr, + x, y, iW, iH, row, col, textLayout); + Tk_FreeTextLayout(textLayout); + if (result != TCL_OK) { + char msg[64 + TCL_INTEGER_SPACE]; + + sprintf(msg, "\n (generating Postscript for cell %s)", + string); + Tcl_AddErrorInfo(interp, msg); + goto cleanup; + } + Tcl_DStringAppend(&buffer, Tcl_GetStringResult(interp), -1); + } + sprintf(string, "/row%d %d def\n", + row, tablePtr->psInfoPtr->y2 - total); + Tcl_DStringAppend(&postscript, string, -1); + total += rowHeight + 2*tablePtr->defaultTag.bd; + } + Tcl_DStringAppend(&buffer, "grestore\n", -1); + sprintf(string, "/row%d %d def\n", row, tablePtr->psInfoPtr->y2 - total); + Tcl_DStringAppend(&postscript, string, -1); + + total = tablePtr->defaultTag.bd; + for (col = firstCol; col <= lastCol; col++) { + sprintf(string, "/col%d %d def\n", col, total); + Tcl_DStringAppend(&postscript, string, -1); + total += colWidths[col-firstCol] + 2*tablePtr->defaultTag.bd; + } + sprintf(string, "/col%d %d def\n", col, total); + Tcl_DStringAppend(&postscript, string, -1); + + Tcl_DStringAppend(&postscript, Tcl_DStringValue(&buffer), -1); + + /* + * Output to channel at the end of it all + * This should more incremental, but that can't be avoided in order + * to post-define width/height of the cols/rows + */ + if (psInfo.chan != NULL) { + Tcl_Write(psInfo.chan, Tcl_DStringValue(&postscript), -1); + Tcl_DStringFree(&postscript); + Tcl_DStringInit(&postscript); + } + + /* + *--------------------------------------------------------------------- + * Output page-end information, such as commands to print the page + * and document trailer stuff. + *--------------------------------------------------------------------- + */ + + Tcl_DStringAppend(&postscript, + "restore showpage\n\n%%Trailer\nend\n%%EOF\n", -1); + if (psInfo.chan != NULL) { + Tcl_Write(psInfo.chan, Tcl_DStringValue(&postscript), -1); + Tcl_DStringFree(&postscript); + Tcl_DStringInit(&postscript); + } + + /* + * Clean up psInfo to release malloc'ed stuff. + */ + +cleanup: + ckfree((char *) argv); + Tcl_DStringResult(interp, &postscript); + Tcl_DStringFree(&postscript); + Tcl_DStringFree(&buffer); + if (psInfo.first != NULL) { + ckfree(psInfo.first); + } + if (psInfo.last != NULL) { + ckfree(psInfo.last); + } + if (psInfo.pageXString != NULL) { + ckfree(psInfo.pageXString); + } + if (psInfo.pageYString != NULL) { + ckfree(psInfo.pageYString); + } + if (psInfo.pageWidthString != NULL) { + ckfree(psInfo.pageWidthString); + } + if (psInfo.pageHeightString != NULL) { + ckfree(psInfo.pageHeightString); + } + if (psInfo.fontVar != NULL) { + ckfree(psInfo.fontVar); + } + if (psInfo.colorVar != NULL) { + ckfree(psInfo.colorVar); + } + if (psInfo.colorMode != NULL) { + ckfree(psInfo.colorMode); + } + if (psInfo.fileName != NULL) { + ckfree(psInfo.fileName); + } + if ((psInfo.chan != NULL) && (psInfo.channelName == NULL)) { + Tcl_Close(interp, psInfo.chan); + } + if (psInfo.channelName != NULL) { + ckfree(psInfo.channelName); + } + Tcl_DeleteHashTable(&psInfo.fontTable); + tablePtr->psInfoPtr = oldInfoPtr; + return result; +#endif +} + +/* + *-------------------------------------------------------------- + * + * Tk_TablePsColor -- + * + * This procedure is called by individual table items when + * they want to set a color value for output. Given information + * about an X color, this procedure will generate Postscript + * commands to set up an appropriate color in Postscript. + * + * Results: + * Returns a standard Tcl return value. If an error occurs + * then an error message will be left in the interp's result. + * If no error occurs, then additional Postscript will be + * appended to the interp's result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +int +Tk_TablePsColor(interp, tablePtr, colorPtr) + Tcl_Interp *interp; /* Interpreter for returning Postscript + * or error message. */ + Table *tablePtr; /* Information about table. */ + XColor *colorPtr; /* Information about color. */ +{ + TkPostscriptInfo *psInfoPtr = tablePtr->psInfoPtr; + int tmp; + double red, green, blue; + char string[200]; + + /* + * If there is a color map defined, then look up the color's name + * in the map and use the Postscript commands found there, if there + * are any. + */ + + if (psInfoPtr->colorVar != NULL) { + char *cmdString; + + cmdString = Tcl_GetVar2(interp, psInfoPtr->colorVar, + Tk_NameOfColor(colorPtr), 0); + if (cmdString != NULL) { + Tcl_AppendResult(interp, cmdString, "\n", (char *) NULL); + return TCL_OK; + } + } + + /* + * No color map entry for this color. Grab the color's intensities + * and output Postscript commands for them. Special note: X uses + * a range of 0-65535 for intensities, but most displays only use + * a range of 0-255, which maps to (0, 256, 512, ... 65280) in the + * X scale. This means that there's no way to get perfect white, + * since the highest intensity is only 65280 out of 65535. To + * work around this problem, rescale the X intensity to a 0-255 + * scale and use that as the basis for the Postscript colors. This + * scheme still won't work if the display only uses 4 bits per color, + * but most diplays use at least 8 bits. + */ + + tmp = colorPtr->red; + red = ((double) (tmp >> 8))/255.0; + tmp = colorPtr->green; + green = ((double) (tmp >> 8))/255.0; + tmp = colorPtr->blue; + blue = ((double) (tmp >> 8))/255.0; + sprintf(string, "%.3f %.3f %.3f AdjustColor\n", + red, green, blue); + Tcl_AppendResult(interp, string, (char *) NULL); + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * Tk_TablePsFont -- + * + * This procedure is called by individual table items when + * they want to output text. Given information about an X + * font, this procedure will generate Postscript commands + * to set up an appropriate font in Postscript. + * + * Results: + * Returns a standard Tcl return value. If an error occurs + * then an error message will be left in the interp's result. + * If no error occurs, then additional Postscript will be + * appended to the interp's result. + * + * Side effects: + * The Postscript font name is entered into psInfoPtr->fontTable + * if it wasn't already there. + * + *-------------------------------------------------------------- + */ + +int +Tk_TablePsFont(interp, tablePtr, tkfont) + Tcl_Interp *interp; /* Interpreter for returning Postscript + * or error message. */ + Table *tablePtr; /* Information about table. */ + Tk_Font tkfont; /* Information about font in which text + * is to be printed. */ +{ + TkPostscriptInfo *psInfoPtr = tablePtr->psInfoPtr; + char *end; + char pointString[TCL_INTEGER_SPACE]; + Tcl_DString ds; + int i, points; + + /* + * First, look up the font's name in the font map, if there is one. + * If there is an entry for this font, it consists of a list + * containing font name and size. Use this information. + */ + + Tcl_DStringInit(&ds); + + if (psInfoPtr->fontVar != NULL) { + char *list, **argv; + int objc; + double size; + char *name; + + name = Tk_NameOfFont(tkfont); + list = Tcl_GetVar2(interp, psInfoPtr->fontVar, name, 0); + if (list != NULL) { + if (Tcl_SplitList(interp, list, &objc, &argv) != TCL_OK) { + badMapEntry: + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "bad font map entry for \"", name, + "\": \"", list, "\"", (char *) NULL); + return TCL_ERROR; + } + if (objc != 2) { + goto badMapEntry; + } + size = strtod(argv[1], &end); + if ((size <= 0) || (*end != 0)) { + goto badMapEntry; + } + + Tcl_DStringAppend(&ds, argv[0], -1); + points = (int) size; + + ckfree((char *) argv); + goto findfont; + } + } + + points = Tk_PostscriptFontName(tkfont, &ds); + +findfont: + sprintf(pointString, "%d", points); + Tcl_AppendResult(interp, pointString, " /", Tcl_DStringValue(&ds), + " SetFont\n", (char *) NULL); + Tcl_CreateHashEntry(&psInfoPtr->fontTable, Tcl_DStringValue(&ds), &i); + Tcl_DStringFree(&ds); + + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * GetPostscriptPoints -- + * + * Given a string, returns the number of Postscript points + * corresponding to that string. + * + * Results: + * The return value is a standard Tcl return result. If + * TCL_OK is returned, then everything went well and the + * screen distance is stored at *doublePtr; otherwise + * TCL_ERROR is returned and an error message is left in + * the interp's result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static int +GetPostscriptPoints(interp, string, doublePtr) + Tcl_Interp *interp; /* Use this for error reporting. */ + char *string; /* String describing a screen distance. */ + double *doublePtr; /* Place to store converted result. */ +{ + char *end; + double d; + + d = strtod(string, &end); + if (end == string) { + error: + Tcl_AppendResult(interp, "bad distance \"", string, + "\"", (char *) NULL); + return TCL_ERROR; + } +#define UCHAR(c) ((unsigned char) (c)) + while ((*end != '\0') && isspace(UCHAR(*end))) { + end++; + } + switch (*end) { + case 'c': + d *= 72.0/2.54; + end++; + break; + case 'i': + d *= 72.0; + end++; + break; + case 'm': + d *= 72.0/25.4; + end++; + break; + case 0: + break; + case 'p': + end++; + break; + default: + goto error; + } + while ((*end != '\0') && isspace(UCHAR(*end))) { + end++; + } + if (*end != 0) { + goto error; + } + *doublePtr = d; + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * TextToPostscript -- + * + * This procedure is called to generate Postscript for + * text items. + * + * Results: + * The return value is a standard Tcl result. If an error + * occurs in generating Postscript then an error message is + * left in the interp's result, replacing whatever used + * to be there. If no error occurs, then Postscript for the + * item is appended to the result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static int +TextToPostscript(interp, tablePtr, tagPtr, tagX, tagY, width, height, + row, col, textLayout) + Tcl_Interp *interp; /* Leave Postscript or error message here. */ + Table *tablePtr; /* Information about overall canvas. */ + TableTag *tagPtr; /* */ + int tagX, tagY; /* */ + int width, height; /* */ + int row, col; /* */ + Tk_TextLayout textLayout; /* */ +{ + int x, y; + Tk_FontMetrics fm; + char *justify; + char buffer[500]; + Tk_3DBorder fg = tagPtr->fg; + + if (fg == NULL) { + fg = tablePtr->defaultTag.fg; + } + + if (Tk_TablePsFont(interp, tablePtr, tagPtr->tkfont) != TCL_OK) { + return TCL_ERROR; + } + if (Tk_TablePsColor(interp, tablePtr, Tk_3DBorderColor(fg)) != TCL_OK) { + return TCL_ERROR; + } + + sprintf(buffer, "%% %.15g %.15g [\n", (tagX+width)/2.0, + tablePtr->psInfoPtr->y2 - ((tagY+height)/2.0)); + Tcl_AppendResult(interp, buffer, (char *) NULL); + sprintf(buffer, "col%d row%d [\n", col, row); + Tcl_AppendResult(interp, buffer, (char *) NULL); + + Tk_TextLayoutToPostscript(interp, textLayout); + + x = 0; y = 0; justify = NULL; /* lint. */ + switch (tagPtr->anchor) { + case TK_ANCHOR_NW: x = 0; y = 0; break; + case TK_ANCHOR_N: x = 1; y = 0; break; + case TK_ANCHOR_NE: x = 2; y = 0; break; + case TK_ANCHOR_E: x = 2; y = 1; break; + case TK_ANCHOR_SE: x = 2; y = 2; break; + case TK_ANCHOR_S: x = 1; y = 2; break; + case TK_ANCHOR_SW: x = 0; y = 2; break; + case TK_ANCHOR_W: x = 0; y = 1; break; + case TK_ANCHOR_CENTER: x = 1; y = 1; break; + } + switch (tagPtr->justify) { + case TK_JUSTIFY_RIGHT: justify = "1"; break; + case TK_JUSTIFY_CENTER: justify = "0.5";break; + case TK_JUSTIFY_LEFT: justify = "0"; + } + + Tk_GetFontMetrics(tagPtr->tkfont, &fm); + sprintf(buffer, "] %d %g %g %s %d %d DrawCellText\n", + fm.linespace, (x / -2.0), (y / 2.0), justify, + width, height); + Tcl_AppendResult(interp, buffer, (char *) NULL); + + return TCL_OK; +} diff --git a/libgui/src/tkTableUtil.c b/libgui/src/tkTableUtil.c new file mode 100644 index 00000000000..29e2f143456 --- /dev/null +++ b/libgui/src/tkTableUtil.c @@ -0,0 +1,340 @@ +/* + * tkTableUtil.c -- + * + * This module contains utility functions for table widgets. + * + * Copyright (c) 2000 Jeffrey Hobbs + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id$ + */ + +#include "tkTable.h" + +static char * Cmd_GetName _ANSI_ARGS_((const Cmd_Struct *cmds, int val)); +static int Cmd_GetValue _ANSI_ARGS_((const Cmd_Struct *cmds, + const char *arg)); +static void Cmd_GetError _ANSI_ARGS_((Tcl_Interp *interp, + const Cmd_Struct *cmds, const char *arg)); + + +/* + *---------------------------------------------------------------------- + * + * TableOptionBdSet -- + * + * This routine configures the borderwidth value for a tag. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * It may adjust the tag struct values of bd[0..4] and borders. + * + *---------------------------------------------------------------------- + */ + +int +TableOptionBdSet(clientData, interp, tkwin, value, widgRec, offset) + ClientData clientData; /* Type of struct being set. */ + Tcl_Interp *interp; /* Used for reporting errors. */ + Tk_Window tkwin; /* Window containing table widget. */ + char *value; /* Value of option. */ + char *widgRec; /* Pointer to record for item. */ + int offset; /* Offset into item. */ +{ + char **borderStr; + int *bordersPtr, *bdPtr; + int type = (int) clientData; + int result = TCL_OK; + int argc; + char **argv; + + + if ((type == BD_TABLE) && (value[0] == '\0')) { + /* + * NULL strings aren't allowed for the table global -bd + */ + Tcl_AppendResult(interp, "borderwidth value may not be empty", + (char *) NULL); + return TCL_ERROR; + } + + if ((type == BD_TABLE) || (type == BD_TABLE_TAG)) { + TableTag *tagPtr = (TableTag *) (widgRec + offset); + borderStr = &(tagPtr->borderStr); + bordersPtr = &(tagPtr->borders); + bdPtr = tagPtr->bd; + } else if (type == BD_TABLE_WIN) { + TableEmbWindow *tagPtr = (TableEmbWindow *) widgRec; + borderStr = &(tagPtr->borderStr); + bordersPtr = &(tagPtr->borders); + bdPtr = tagPtr->bd; + } else { + panic("invalid type given to TableOptionBdSet\n"); + return TCL_ERROR; /* lint */ + } + + result = Tcl_SplitList(interp, value, &argc, &argv); + if (result == TCL_OK) { + int i, bd[4]; + + if (((type == BD_TABLE) && (argc == 0)) || (argc == 3) || (argc > 4)) { + Tcl_AppendResult(interp, + "1, 2 or 4 values must be specified for borderwidth", + (char *) NULL); + result = TCL_ERROR; + } else { + /* + * We use the shadow bd array first, in case we have an error + * parsing arguments half way through. + */ + for (i = 0; i < argc; i++) { + if (Tk_GetPixels(interp, tkwin, argv[i], &(bd[i])) != TCL_OK) { + result = TCL_ERROR; + break; + } + } + /* + * If everything is OK, store the parsed and given values for + * easy retrieval. + */ + if (result == TCL_OK) { + for (i = 0; i < argc; i++) { + bdPtr[i] = MAX(0, bd[i]); + } + if (*borderStr) { + ckfree(*borderStr); + } + if (value) { + *borderStr = (char *) ckalloc(strlen(value) + 1); + strcpy(*borderStr, value); + } else { + *borderStr = NULL; + } + *bordersPtr = argc; + } + } + ckfree ((char *) argv); + } + + return result; +} + +/* + *---------------------------------------------------------------------- + * + * TableOptionBdGet -- + * + * Results: + * Value of the -bd option. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +char * +TableOptionBdGet(clientData, tkwin, widgRec, offset, freeProcPtr) + ClientData clientData; /* Type of struct being set. */ + Tk_Window tkwin; /* Window containing canvas widget. */ + char *widgRec; /* Pointer to record for item. */ + int offset; /* Offset into item. */ + Tcl_FreeProc **freeProcPtr; /* Pointer to variable to fill in with + * information about how to reclaim + * storage for return string. */ +{ + register int type = (int) clientData; + + if (type == BD_TABLE) { + return ((TableTag *) (widgRec + offset))->borderStr; + } else if (type == BD_TABLE_TAG) { + return ((TableTag *) widgRec)->borderStr; + } else if (type == BD_TABLE_WIN) { + return ((TableEmbWindow *) widgRec)->borderStr; + } else { + panic("invalid type given to TableOptionBdSet\n"); + return NULL; /* lint */ + } +} + +/* + *---------------------------------------------------------------------- + * + * TableTagConfigureBd -- + * This routine configures the border values based on a tag. + * The previous value of the bd string (oldValue) is assumed to + * be a valid value for this tag. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * It may adjust the value used by -bd. + * + *---------------------------------------------------------------------- + */ + +int +TableTagConfigureBd(Table *tablePtr, TableTag *tagPtr, + char *oldValue, int nullOK) +{ + int i, argc, result = TCL_OK; + char **argv; + + /* + * First check to see if the value really changed. + */ + if (strcmp(tagPtr->borderStr ? tagPtr->borderStr : "", + oldValue ? oldValue : "") == 0) { + return TCL_OK; + } + + tagPtr->borders = 0; + if (!nullOK && ((tagPtr->borderStr == NULL) + || (*(tagPtr->borderStr) == '\0'))) { + /* + * NULL strings aren't allowed for this tag + */ + result = TCL_ERROR; + } else if (tagPtr->borderStr) { + result = Tcl_SplitList(tablePtr->interp, tagPtr->borderStr, + &argc, &argv); + if (result == TCL_OK) { + if ((!nullOK && (argc == 0)) || (argc == 3) || (argc > 4)) { + Tcl_SetResult(tablePtr->interp, + "1, 2 or 4 values must be specified to -borderwidth", + TCL_STATIC); + result = TCL_ERROR; + } else { + for (i = 0; i < argc; i++) { + if (Tk_GetPixels(tablePtr->interp, tablePtr->tkwin, + argv[i], &(tagPtr->bd[i])) != TCL_OK) { + result = TCL_ERROR; + break; + } + tagPtr->bd[i] = MAX(0, tagPtr->bd[i]); + } + tagPtr->borders = argc; + } + ckfree ((char *) argv); + } + } + + if (result != TCL_OK) { + if (tagPtr->borderStr) { + ckfree ((char *) tagPtr->borderStr); + } + if (oldValue != NULL) { + size_t length = strlen(oldValue) + 1; + /* + * We are making the assumption that oldValue is correct. + * We have to reparse in case the bad new value had a couple + * of correct args before failing on a bad pixel value. + */ + Tcl_SplitList(tablePtr->interp, oldValue, &argc, &argv); + for (i = 0; i < argc; i++) { + Tk_GetPixels(tablePtr->interp, tablePtr->tkwin, + argv[i], &(tagPtr->bd[i])); + } + ckfree ((char *) argv); + tagPtr->borders = argc; + tagPtr->borderStr = (char *) ckalloc(length); + memcpy(tagPtr->borderStr, oldValue, length); + } else { + tagPtr->borders = 0; + tagPtr->borderStr = (char *) NULL; + } + } + + return result; +} + +/* + *---------------------------------------------------------------------- + * + * Cmd_OptionSet -- + * + * + * Results: + * A standard Tcl result. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +Cmd_OptionSet(ClientData clientData, Tcl_Interp *interp, + Tk_Window unused, char *value, char *widgRec, int offset) +{ + Cmd_Struct *p = (Cmd_Struct *)clientData; + int mode = Cmd_GetValue(p,value); + if (!mode) { + Cmd_GetError(interp,p,value); + return TCL_ERROR; + } + *((int*)(widgRec+offset)) = mode; + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * Cmd_OptionGet -- + * + * + * Results: + * Value of the option. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +char * +Cmd_OptionGet(ClientData clientData, Tk_Window unused, + char *widgRec, int offset, Tcl_FreeProc **freeProcPtr) +{ + Cmd_Struct *p = (Cmd_Struct *)clientData; + int mode = *((int*)(widgRec+offset)); + return Cmd_GetName(p,mode); +} + +/* + * simple Cmd_Struct lookup functions + */ + +char * +Cmd_GetName(const Cmd_Struct *cmds, int val) +{ + for(;cmds->name && cmds->name[0];cmds++) { + if (cmds->value==val) return cmds->name; + } + return NULL; +} + +int +Cmd_GetValue(const Cmd_Struct *cmds, const char *arg) +{ + unsigned int len = strlen(arg); + for(;cmds->name && cmds->name[0];cmds++) { + if (!strncmp(cmds->name, arg, len)) return cmds->value; + } + return 0; +} + +void +Cmd_GetError(Tcl_Interp *interp, const Cmd_Struct *cmds, const char *arg) +{ + int i; + Tcl_AppendResult(interp, "bad option \"", arg, "\" must be ", (char *) 0); + for(i=0;cmds->name && cmds->name[0];cmds++,i++) { + Tcl_AppendResult(interp, (i?", ":""), cmds->name, (char *) 0); + } +} diff --git a/libgui/src/tkWinPrintCanvas.c b/libgui/src/tkWinPrintCanvas.c index 5b7bc41830a..029c6687f52 100644 --- a/libgui/src/tkWinPrintCanvas.c +++ b/libgui/src/tkWinPrintCanvas.c @@ -52,20 +52,20 @@ PrintCanvasCmd(clientData, interp, argc, argv) int tiles_wide,tiles_high; int tile_y, tile_x; int screenX1, screenX2, screenY1, screenY2, width, height; - DOCINFO *lpdi = malloc(sizeof(DOCINFO)); + DOCINFO *lpdi = (DOCINFO *) ckalloc(sizeof(DOCINFO)); if (argc < 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " canvas \"", (char *) NULL); - return TCL_ERROR; + goto error; } /* The second arg is the canvas widget */ if (!Tcl_GetCommandInfo(interp, argv[1], &canvCmd)) { Tcl_AppendResult(interp, "couldn't get canvas information for \"", argv[1], "\"", (char *) NULL); - return TCL_ERROR; + goto error; } memset(&dm,0,sizeof(DEVMODE)); @@ -74,7 +74,7 @@ PrintCanvasCmd(clientData, interp, argc, argv) memset(lpdi,0,sizeof(DOCINFO)); lpdi->cbSize=sizeof(DOCINFO); - lpdi->lpszDocName=malloc(255); + lpdi->lpszDocName= (LPCSTR) ckalloc(255); sprintf((char*)lpdi->lpszDocName,"SN - Printing\0"); lpdi->lpszOutput=NULL; @@ -164,8 +164,12 @@ PrintCanvasCmd(clientData, interp, argc, argv) EndDoc(pd.hDC); done: + ckfree ((char*) lpdi->lpszDocName); + ckfree ((char*) lpdi); return TCL_OK; - error: +error: + ckfree ((char*) lpdi->lpszDocName); + ckfree ((char*) lpdi); return TCL_ERROR; } diff --git a/libgui/src/tkWinPrintText.c b/libgui/src/tkWinPrintText.c index a9ffd36bfb9..88ed8b8884d 100644 --- a/libgui/src/tkWinPrintText.c +++ b/libgui/src/tkWinPrintText.c @@ -212,7 +212,8 @@ typedef struct TextStyle { -void DisplayDLineToDrawable(TkText *textPtr, DLine *dlPtr, DLine *prevPtr, TkWinDrawable *drawable); +static void +DisplayDLineToDrawable(TkText *textPtr, DLine *dlPtr, DLine *prevPtr, TkWinDrawable *drawable); /* *-------------------------------------------------------------- @@ -248,7 +249,7 @@ PrintTextCmd(clientData, interp, argc, argv) Pixmap pixmap; int bottomY = 0; /* Initialization needed only to stop * compiler warnings. */ - DOCINFO *lpdi = malloc(sizeof(DOCINFO)); + DOCINFO *lpdi = (DOCINFO *) ckalloc(sizeof(DOCINFO)); TkTextIndex first, last; int numLines; HDC hDCpixmap; @@ -272,7 +273,7 @@ PrintTextCmd(clientData, interp, argc, argv) Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " text \"", (char *) NULL); - return TCL_ERROR; + goto error; } /* @@ -281,7 +282,7 @@ PrintTextCmd(clientData, interp, argc, argv) if (!Tcl_GetCommandInfo(interp, argv[1], &textCmd)) { Tcl_AppendResult(interp, "couldn't get text information for \"", argv[1], "\"", (char *) NULL); - return TCL_ERROR; + goto error; } memset(&dm,0,sizeof(DEVMODE)); @@ -290,7 +291,7 @@ PrintTextCmd(clientData, interp, argc, argv) memset(lpdi,0,sizeof(DOCINFO)); lpdi->cbSize=sizeof(DOCINFO); - lpdi->lpszDocName=malloc(255); + lpdi->lpszDocName = (LPCSTR) ckalloc(255); sprintf((char*)lpdi->lpszDocName,"SN - Printing\0"); lpdi->lpszOutput=NULL; @@ -445,8 +446,12 @@ PrintTextCmd(clientData, interp, argc, argv) textPtr->dInfoPtr->flags|=DINFO_OUT_OF_DATE; done: + ckfree ((char*) lpdi->lpszDocName); + ckfree ((char*) lpdi); return TCL_OK; - error: +error: + ckfree ((char*) lpdi->lpszDocName); + ckfree ((char*) lpdi); return TCL_ERROR; } |