tgif(n)
🌸 tgif(n) — ok bestie, sit DOWN, we're learning tgif 💅
the manual page you're about to read is giving "graphics girlboss"
✨ NAME ✨
tgif — an Xlib-based interactive 2-D drawing facility under X11. 🎨
It supports hierarchical construction of drawings and makes navigating between sets of drawings super easy (no cap, the hierarchy thing is the whole vibe). It's also a hyper-graphics (or hyper-structured-graphics) browser on the World-Wide-Web. 🌐
🎀 SYNOPSIS 🎀
Two whole forms, bestie. Pick your fighter:
tgif [-display displayname] [-fg <color>] [-bg <color>] [-bd <color>]
[-rv] [-nv] [-bw] [-reqcolor] [-cwo[+sbwarp]] [-hyper] [-exec <file>]
[-dbim {xcin|chinput|xim|kinput2|tgtwb5[,font]}] [-sbim xim] [-usexlib]
[{-a4|-letter}] [-listdontreencode] [-version] [-pdfspd | -pdfspd=true |
-pdfspd=false ] [-pssetup "<string>" ] [-tgwb2 [-rmcastlibdir
<directory> | -rmcastlibpath <path>]] [-nomode] [-geometry <geom>]
[=<geom>] [{file[.obj]|-merge file1[.obj] file2[.obj] ...}]
or
tgif -print [-eps] [-p] [-ps] [-f] [-text] [-epsi] [-tiffepsi] [-gif]
[-png] [-jpeg] [-ppm] [-pbm] [-xpm] [-xbm] [-html] [-pdf] [-netlist]
[-svg] [-display displayname] [-stdout] [-raw[+h[eaderonly]]]
[-dosepsfilter [-previewonly]] [-status] [-gray] [-color | -reqcolor]
[-adobe | -adobe=<number>/<number> | -adobe=false ]
[-dontreencode=<string> | -listdontreencode] [-version | -justversion]
[-producedby=<string>] [-page <number>] [-print_cmd "<command>"]
[-one_file_per_page] [-pepsc] [-pdfspd | -pdfspd=true | -pdfspd=false ]
[-pssetup "<string>" ] [-j2p6_cmd "<command>" ] [-dontcondense |
-condensed] [{-a4|-letter}] [-noshowpageineps] [-quiet] [-bop_hook
"<string>"] [-eop_hook "<string>"] [-tmp_file_mode "<octal number>"]
[-patterndir "<xbm directory>"] [-o<dir>] [-exec <file>] [file1[.obj]
file2[.obj] ...]
💖 DESCRIPTION 💖
Okay so. tgif is an interactive drawing tool that lets you draw and manipulate objects in the X Window System. It runs interactively in the first form. 🖱️✨
In the second form shown up in the SYNOPSIS section, tgif just prints file1.obj, file2.obj, etc. (the ones generated by tgif) into PostScript(TM) page description files — and it does this without opening windows or fonts, which is honestly iconic behaviour — and pipes them to lpr(1) if none of the following options are specified:
-eps-p-epsi-tiffepsi-gif-png-jpeg-ppm-pbm-xpm-xbm-html-pdf-ps-f-text-netlist-svg
This form of printing is tgif's way of exporting a tgif file to another format. 🦋 In this case, any other unrecognized command line options get sent straight to lpr(1). In this mode, tgif is compatible with the obsoleted prtgif. A symbol file (see descriptions below 👀) can also be printed by specifying the .sym extension explicitly.
The command line argument file specifies a file or a Uniform Resource Locator (URL) of objects to be initially edited by tgif. Only HTTP or FTP URL's are supported. (For a more detailed description of URL and the World-Wide-Web, the reader is referred to [1].)
💀 Fun fact that is also a requirement: tgif is purely based on Xlib. It is tested under X11R6, and it requires a 3 button mouse. Three. Buttons. No mouse shortcuts, bestie. 🖱️🖱️🖱️
✨ OPTIONS ✨
Okay bestie, buckle up, because there are a LOT of these and I'm not skipping a single one. 💅
In the first form shown in the SYNOPSIS section, the command line arguments can be:
-fg— Foreground color, specified in <color>.-bg— Background color, specified in <color>.-bd— Border color, specified in <color>.-rv— Starttgifin reversed-video mode.-nv— Starttgifin normal-video mode.-bw— Starttgifin black and white mode.-reqcolor— Same effect as setting theTgif.PrintUsingRequestedColorX default totrue(peep the X DEFAULTS section below).-cwo— Canvas Window Only. Only the canvas window (see the TGIF SUBWINDOWS section below) gets displayed. Same effect as setting theTgif.CanvasWindowOnlyX default totrue.-cwo+sbwarp— If you use-cwo+sbwarp, single-button-warp (aka clicking the left mouse button to warp) is what activates teleporting (see the TELEPORT/HYPERJUMP section below).-hyper— Starttgifin hyperspace mode (see the HYPERSPACE section below).-exec <file>— Aftertgifstarts, execute the internal command in <file> (see the INTERNAL COMMANDS section below). And if <file> is literally the string"-", thentgifexecutes internal commands from the standard input.-dbim method— Use method as the input method for double-byte fonts (see the SQUARE DOUBLE BYTE FONTS section below). Heads up: this cannot be used together with-sbim.-sbim method— Use method as the input method for single-byte fonts. This is useful if the X Keyboard Extension is used when inputing international characters (with dead keys). Heads up: this cannot be used together with-dbim.-usexlib— Iftgifwas compiled with-DUSE_XT_INITIALIZE, X Toolkit initialization routines get used to set uptgif. Using this command line option forcestgifto ignore the-DUSE_XT_INITIALIZEcompiler option and use Xlib only. Super handy when the system resource file fortgifisn't installed properly or is messed up and needs to be bypassed.-a4— Same effect as setting theTgif.PSA4PaperSizeX default totrue.-letter— Same effect as setting theTgif.InitialPaperSizeX default to"letter".-noshowpageineps— Same effect as setting theTgif.ShowPageInEPSX default tofalse.-quiet— If this is used,tgifwill suppress standard messages.-listdontreencode=<string>— If this is used,tgifprints out the list of PostScript font names specified in the-D_DONT_REENCODEcompiler option used when compilingtgif.
In the second form shown in the SYNOPSIS section, the command line arguments can be:
-version— If this is used,tgifprints out its version number and copyright on the command line.-justversion— If this is used,tgifprints out its version number and copyright on the command line and exits immediately.-nomode— Same effect as setting theTgif.NoModeWindowX default totrue.-eps(or-p) — Generates an Encapsulated PostScript(TM) file infile.eps; you can include this file in a LaTeX file through the\psfig,\epsf, or\psfileconstruct (see the LATEX FIGURE FORMATS section below).-ps(or-f) — Generates a PostScript file infile.ps; you can print this file to a PostScript printer withlpr(1).-text— Generates a text file infile.txt; that text file contains all visible text and can be fed to a spell checker. 👑-epsi— Generates an Encapsulated PostScript (EPS) file with a preview bitmap infile.eps.tgifaborts if a valid display isn't accessible.-tiffepsi— Generates an EPS file with a DOS EPS Binary File Header and a trailing TIFF image infile.eps. See the GENERATING MICROSOFT WINDOWS EPSI FILES section for more details.tgifaborts if a valid display isn't accessible.-gif— Generates a GIF file infile.gif. Please see the notes forTgif.GifToXpmin the X DEFAULTS section below.tgifaborts if a valid display isn't accessible.-png— Generates a PNG file infile.png.tgifaborts if a valid display isn't accessible.-jpeg— Generates a JPEG file infile.jpg.tgifaborts if a valid display isn't accessible.-ppm— Generates a PPM file infile.ppm.tgifaborts if a valid display isn't accessible.-pbm— Generates a PBM file infile.pbm.tgifaborts if a valid display isn't accessible.-xpm— Generates an X11 pixmap (XPM) file infile.xpm.tgifaborts if a valid display isn't accessible.-xbm— Generates an X11 bitmap (XBM) file infile.xbm.tgifaborts if a valid display isn't accessible.-html— Generates a GIF file infile.gifand an HTML file infile.html.tgifaborts if a valid display isn't accessible.-pdf— Generates a PDF file infile.pdf. Please see the notes forTgif.PsToPdfin the X DEFAULTS section below.-netlist— Generates a text file infile.netand a text file infile.cmp.file.netcontains netlist information stored in a table. The first line in it contains column names, and each line in it is a port name (surrounded by double-quotes), followed by a comma and a<TAB>character, followed by a signal name (also surrounded by double-quotes).file.cmpcontains information about components in the file. Each component begins with its name followed by its type. The attributes of a component are printed afterwards, indented by<TAB>characters.-svg— Generates an SVG file infile.svg. Please see the notes forTgif.EpsToTmpSvgandTgif.TmpSvgToSvgin the X DEFAULTS section below.-stdout— Sends the output to the standard output instead of generating the output in a file.-raw— Causes the content of the files to be dumped tostdout.-raw+h— If-raw+his used and the file is an HTTP URL, the HTTP header also gets dumped tostdout.-raw+headeronly— If-raw+headeronlyis used and the file is an HTTP URL, the HTTP header gets dumped tostdout.-dosepsfilter— Makestgifact as a filter for getting rid of the DOS EPS Binary File Header and the trailing TIFF image in a DOS/Windows EPS file.-previewonly— If-dosepsfilteris specified,-previewonlymakestgifact as a filter for extracting the preview bitmap from the trailing TIFF image in a DOS/Windows EPS file.-status— If this option is used together with either-raw,-raw+h, or-raw+headeronly, it causes a status line to be displayed instderr.-gray— Same effect as setting theTgif.UseGrayScaleX default totrue(see the X DEFAULTS section below).-color(or-reqcolor) — To print in color, you can use either the-coloror the-reqcoloroption. The only difference between the two is that using-reqcolorhas the same effect as setting theTgif.PrintUsingRequestedColorX default totrue(see the X DEFAULTS section below).-adobe(or-adobe=<number>/<number>-adobe=false) — Same effect as specifying theTgif.UsePsAdobeStringX default.-dontreencode=<string>— Same effect as specifying theTgif.DontReencodeX default.-producedby=<string>— Same effect as specifying theTgif.ProducedByX default.-page— Causes a specified page (specified by <number>) to be printed.-print_cmd— Same effect as specifying theTgif.PrintCommandX default.-one_file_per_page— Causes each page to be printed into a separate file.-pepsc— Preserve EPS Comment. This command line option became obsolete since EPS comments are always preserved starting fromtgif-4.0.11. 💀-nolandpdfspd— This commandline option became obsolete intgif-4.1.42. It is interpreted as-nopdfspd.-pdfspd(or-pdfspd=true-pdfspd=false) — If-pdfspdor-pdfspd=trueis specified,"setpagedevice"is generated in the interim PostScript file when exporting PDF files, or in the final PostScript file when exporting PS files. If-pdfspd=falseis specified, no"setpagedevice"will be generated in the interim PostScript file when exporting PDF files, or in the final PostScript file when exporting PS files. This option overrides theTgif.PdfSetPageDeviceX default.-pssetup— Using these options has the same effect as specifying theTgif.AdditionalPSSetupX default.-tgwb2— This commandline option enables the Tangram Whiteboard feature intgif. It requireslibrmcast.so(Reliable IP-multicast library). You can specify the location of the rmcast library with the optional commandline argument-rmcastlibdir. Or, alternatively, you can specify the full path to the rmcast library using the optional commandline argument-rmcastlibpath. (Just so you know: the rmcast library has only been extensively tested on Linux machines.)-j2p6_cmd— Same effect as specifying theTgif.JpegToPpm6X default.-dontcondense— Same effect as setting theTgif.DontCondensePSFileX default totrue.-condensed— Same effect as setting theTgif.DontCondensePSFileX default tofalse.-bop_hookand-eop_hook— Using these options has the same effect as specifying theTgif.PSBopHookandTgif.PSEpsHookX defaults.-tmp_file_mode— Using this option has the same effect as specifying theTgif.TmpFileModeX defaults.-patterndir— Using this option has the same effect as specifying theTgif.CustomPatternDirX defaults.-o— If this option is not specified, the output file (eps,ps, etc.) goes into the same directory as the input file. If-o<dir>is specified, the output file goes into the directory specified by <dir>.-merge file1 file2 ...— Using this option mergesfile1.obj,file2.obj, etc. into a multipage file.
💖 BASIC FUNCTIONALITIES 💖
okay so bestie, first up: the primitive objects that tgif can draw are rectangles, ovals, rounded-corner rectangles, arcs, polylines, polygons, open-splines, closed-splines, text, X11 bitmaps, some specific forms of X11 pixmaps, and Encapsulated PostScript. and no, before you ask — the splines tgif draws are NOT Bezier curves. just so we're clear ✨
you can group objects together to make a grouped object. and a primitive or a grouped object can be turned into an icon object or a symbol object through user commands. slay.
tgif objects live in two types of files:
- a file with a
.objextension (aka an object file) is a file of objects - a file with a
.symextension (aka a symbol file) specifies a ``building-block'' object
there's a teleport mechanism so you can travel (or hyperjump) among the .obj files 🦋. a building-block object consists of the representation part and the definition part (which can be empty) of the object. tgif supports the bottom-up'' construction of hierarchical drawings by letting you instantiate'' a building-block object in a drawing. it also supports the ``top-down'' specification of drawings by letting you make any object a representation of an un-specified subsystem. both types of files are stored in the form of Prolog facts. and like... you can literally write Prolog code to interpret the drawings! (it is left to the user to produce the code. see the PROLOG/C TESTDRIVE section for more details.) Prolog engines are referred to as drivers in the sections to follow. (other types of drivers are also allowed, e.g., written in C.) 💅
text based attributes can be attached to any non-text object. attributes specified in the representation part of a building-block object are non-detachable when such an object is instantiated. see the ATTRIBUTES section for details.
tgif can generate output in a few different formats, and honestly? it's giving versatility 👑
by default, the output is in the PostScript format (color PostScript is supported), and it's generated into a file named /tmp/Tgifa* (produced by mktemp() calls) where * is a number; this file is piped to lpr(1). this happens when the laser-printer icon is displayed in the Choice Window (see the TGIF SUBWINDOWS section for the naming of tgif windows).
this output can be redirected to a file with a .ps extension. this happens when the PS icon is displayed in the Choice Window.
when the PDF icon is displayed in the Choice Window, the output is generated into a file with a .pdf extension. by default, tgif calls ps2pdf(1) from the ghostscript(1) package to convert a PS file to a PDF file.
when the LaTeX (or EPSI) icon is displayed in the Choice Window, the output is generated into a file with a .eps extension. this file is in the Encapsulated PostScript (or Encapsulated PostScript Interchange) format; it can be included in a LaTeX document with the \psfig or the \epsf construct; this will be discussed later. the only difference between the EPS and EPSI formats is that an EPSI file contains a preview bitmap. however, it takes time to generate the preview bitmap. if the EPS/EPSI file is to be incorporated into some tool that does not know how to use the preview bitmap, time can be saved by not using the EPSI format. iykyk ⏳
when the T icon is displayed in the Choice Window, the output is generated into a file with a .txt extension. this is a text file containing all visible text; it can be fed to a spell checker 📝
when the x11bm (X11 bitmap) icon is displayed in the Choice Window and color output is not selected, tgif generates the output with the .xbm extension; the output is in the X11 bitmap format. however, if the x11bm icon is displayed in the Choice Window and color output is selected (through the ^#k keyboard command -- ^ denotes the <Control> and # denotes the <Meta> or <Alt> key), then tgif generates the output with the .xpm extension, and the output is in the X11 pixmap format (the version of this XPM format depends on the settings of the Tgif.XPmOutputVersion X default).
when the GIF icon is displayed in the Choice Window, the output is generated into a file with a .gif extension. by default, tgif calls xpmtoppm and ppmtogif from the netpbm(1) package to convert an XPM file to a GIF file. 🎀
X11 bitmap files, certain forms of X11 pixmap files (such as the one generated by tgif; see the section on X11 PIXMAP for details), GIF files, and Encapsulated PostScript (EPS) files can be imported into tgif and be represented as tgif primitive objects. files in other raster formats (e.g, JPEG, TIFF, etc.) can also be imported into tgif if external tools can be used to convert them into X11 pixmap files. please see the IMPORT RASTER GRAPHICS section for details. 🫶
tgif drawings are supposed to be printed on letter size paper (8.5in by 11in). both landscape and portrait page styles are supported by tgif. reduction (or magnification) can be controlled by the #% keyboard command to set the reduction/magnification. if the compiler flag -DA4PAPER is defined (in Imakefile or Makefile.noimake), then the output is supposed to be printed on A4 papers (which has approximate dimensions of 8.25in by 11.7in). 📄
🌈 GRAPHICAL OBJECTS 🌈
an object in an object (.obj) file can be a primitive object, a grouped object, or an icon object. a symbol (.sym) file can have any number of objects allowed in an object file and exactly one symbol object. (recall that a symbol file specifies a building-block object.) the symbol object in a symbol file is the representation part of the building-block object, and the rest of the symbol file is the definition part of the building-block object. the symbol object is highlighted with a dashed outline to distinguish it from the rest of the objects ✨. when a building-block object is instantiated, the symbol part of the file is copied into the graphics editor, and it becomes the icon for the building-block object.
all objects in tgif can be moved, duplicated, deleted, rotated, flipped, and sheared. however, in the non-stretchable text mode, text objects can not be stretched. for an text object, if it has not been stretched, rotated, or sheared, flipping it horizontally will cause the text justification to change and flipping it vertically has no effect. 💅
tgif supports:
- 32 fill patterns
- 32 pen patterns
- 7 default line widths
- 4 line styles (plain, head arrow, tail arrow, double arrows) for polylines and open-splines
- 9 dash patterns
- 3 types of text justifications
- 4 text styles (roman, italic, bold, bold-italic)
- 11 default text sizes (
8,10,12,14,18, and24for the 75dpi fonts and11,14,17,20,25, and34for the 100dpi fonts) - 5 default fonts (Times, Courier, Helvetica, New-Century-Schoolbook, Symbol)
- 11 default colors (magenta, red, green, blue, yellow, pink, cyan, cadet-blue, white, black, dark-slate-gray)
additional line widths can be added through the use of Tgif.MaxLineWidths, Tgif.LineWidth#, Tgif.ArrowWidth#, and Tgif.ArrowHeight# X defaults. additional text sizes can be added through the use of Tgif.FontSizes X default. additional fonts can be added through the use of Tgif.AdditionalFonts X default. if the defaults fonts are not available, their replacement fonts can be specified by Tgif.HasAlternateDefaultFonts and related X defaults. additional colors can be added through the use of Tgif.MaxColors, and Tgif.Color# X defaults. one can also select AddColor() or ChooseColor() from the Properties Menu to add a color. 🎨
alternate startup colors can be selected through the use of the Tgif.ColorFromXPixmap, Tgif.UseStdPalette8, Tgif.UseStdPalette27, Tgif.UseStdPalette64, Tgif.UseStdPalette216, Tgif.UseMobileWebSafePalette, Tgif.UseOpenOfficeGalaxyPalette, Tgif.UseOpenOfficeGooglePalette, and Tgif.AdditionalColors X defaults. (the way that palette list goes on... obsessed 🌈)
most commands in tgif can either be activated by a popup menu or by typing an appropriate non-alphanumeric key. all operations that change any object can be undone and then redone. commands such as zoom, scroll, change fonts while no text objects are selected, etc. are not undoable. the undo/redo history buffer size can be set using the Tgif.HistoryDepth X default. ↩️
🧚 TGIF SUBWINDOWS 🧚
the tgif windows are described in this section. let's get into it bestie 💖
Top Window
displays the current domain and the name of the file tgif is looking at. mouse clicks and key presses have no effect. it's just there, being pretty, holding space 🫶
Menubar Window
this window is right under the Top Window. pull-down menus can be activated from it with any mouse buttons. key presses have no effect. if HideMenubar() is selected from the Layout Menu, this window becomes invisible. if ShowMenubar() is selected from the Layout Menu (which can be activated from the Canvas Window below), this window becomes visible.
the View, Text, and Graphics pull-down menus are cascading menus and can not be pinned (see the Popup Menus subsection below for a description).
Message Window
this is right under the Menubar Window and to the right. it displays tgif messages. clicking the left mouse button in this window scrolls the messages towards the bottom, clicking the right mouse button scrolls towards the top, and clicking or dragging the middle mouse button scrolls to the location in the message history depending on where the mouse is clicked. if the <Shift> (or <Control>) key is held down when clicking the left/right mouse button, it scrolls right/left. 📜
Panel (Choice) Window
this is the window to the left of the Message Window, and it contains a collection of icons (not to be confused with the tgif icon objects — different thing bestie, don't mix them up 💀) reflecting the current state of tgif. in top/bottom, left/right order, it displays the current drawing mode, the page style (portrait or landscape), edit (see below), print/export mode, zoom factor, move and stretch mode (constrained or unconstrained), radius for rounded-corner rectangles, text rotation, page number or row/column, page layout mode (stacked or tiled), horizontal alignment (L C R S -), vertical alignment (T M B S -), font, text size, vertical spacing between lines of text within the same text object, text justification, shape (see below), stretchable or non-stretchable text mode, dash pattern, line style, polyline, spline, or interpolated spline, line width, fill pattern, pen pattern, color, and special (see below). key presses have no effect in this window. 🎀
Okay bestie, so the Choice Window isn't just a pretty face — those icons are interactive. They show you the current state of tgif, yes, but they also change it. Every icon is wired up to a particular state variable, and here's the tea:
- Left-click on top of an icon → cycles that icon's state variable forward ✨
- Right-click on top of an icon → cycles it backwards 💅
- Drag with the middle mouse button on top of an icon → usually pops up a menu that matches an entry in the Main Menu for the Canvas Window down below 🫶
Quick aside, don't come for me: the edit, shape, and special icons we mentioned earlier? They're dummy icons. Their whole job is letting you reach the edit, shape, and special menus from inside the Choice Window. They do not respond to left and right mouse clicks at all. Iconic behaviour, honestly.
And middle-drag is built different for three specific icons: zoom, radius, and vertical spacing. For those:
- Drag the mouse left or up → increases the zoom, or decreases the radius or vertical spacing
- Drag the mouse right or down → the exact opposite effect 🔄
Now, plot twist: if you've got objects selected in the canvas window, the mouse action will make those selected objects switch over to the newly selected mode. But careful — in that case the current choice itself won't change if you used the middle mouse button. (Unless the Tgif.StickyMenuSelection X default is set to true, in which case it does. iykyk.)
The horizontal and vertical alignment settings are the main character of a lot of operations, so let's break down what they actually control:
- how objects (or vertices) align with each other when you hit the
^lkeyboard command - how each individual object (or vertex) aligns with the grids when you hit
^t - how objects or vertices distribute spatially with respect to each other when you hit
#l - how each icon replaces the old icon when you hit
^#u
Horizontal alignments are: L (left), C (center), R (right), S (space), and - (ignore).
Vertical alignments are: T (top), M (middle), B (bottom), S (space), and - (ignore).
For aligning operations, the space (S) and ignore (-) settings do the same thing. The space settings are the ones used to distribute objects so that the gaps between any two neighbouring objects come out equal ✨. And in vertex mode, any non-ignore setting will cause the selected vertices to be spaced out evenly.
The best way to understand them is to try them out. That's not a cop-out, that's literally the advice. Go play. 🎀
Text vertical spacing decides how far down you advance when you press a carriage return while you're editing text. And heads up: if you try to set it too negative — like, so negative that the next line would sit at exactly the same position as the current line — that setting just won't be allowed. (The cutoff distance depends on the current font and font size, so it's not one magic number.)
🎨 Canvas Window 🎨
This is the drawing area. What your mouse does in here is decided entirely by the current drawing mode.
History lesson: before tgif-4.x, dragging the right mouse button would generate the Mode Menu. In tgif-4.x that's disabled by default, but you can turn it back on with the Tgif.Btn3PopupModeMenu X default. 💅
The drawing modes, in order, exactly as they show up in the Mode Menu:
selecttextrectanglecorner ovalcenter ovaledge circlepolyline (open-spline)polygon (closed-spline)arc (center first)arc (endpoints first)rounded-corner rectanglefreehand polyline (open-spline)select verticesrotate/shear
Cute trick alert 🦋: when you're drawing a rectangle, an oval, or a rounded-corner rectangle, hold down <Shift> and you get a square, a circle, or a rounded-corner square instead.
And dragging the middle mouse button generates the Main Menu.
In select mode, the left mouse button is your everything button — it selects, moves, stretches, and reshapes objects. (Double-click will ``de-select'' all selected objects in vertex mode.)
When an object is selected it gets highlighted by little squares at the corners/vertices — these are called handles. You can customise how big they are with the Tgif.HandleSize X default ✨. Dragging one of those handles stretches/reshapes the selected object.
Important: if you want to move a selected object, do not drag the handles. Drag other parts of the object instead. 🫶
Like, say your object is a hollow rectangle (fill is NONE and pen is not NONE):
- To select it, click on the outline of the rectangle with the left mouse button.
- To move it, drag the outline of the rectangle with the left mouse button.
But if it's a filled rectangle (fill is not NONE), you can click anywhere inside it to select it, and drag anywhere inside it to move it. Easy. 💅
Hold <Shift> and left-click an object that isn't currently selected → it gets added to your list of already selected objects. Do the same thing to an object that <em>is</em> already selected → it gets de-selected. 🌈
When you're stretching objects (note: not reshaping poly-type objects), holding <Shift> <em>after</em> the stretch has already started activates proportional stretching — basically, a scale operation is being performed. And in non-stretchable text mode, text objects can't be stretched or scaled at all. No cap.
Double-clicking, or clicking the middle mouse button while <Shift> is held down, activates the teleport (or travel), the launch, or the execute internal command mechanism. Details live in the TELEPORT/HYPERJUMP, LAUNCH APPLICATIONS, and INTERNAL COMMANDS sections 👑.
Precedence check: teleporting > launching > executing an internal command.
And in text drawing mode, dragging the middle mouse button while <Cntrl> is held down, inside the edit text area, will move the edit text area. 🎀
The arrow keys can also move selected objects! But — and this is the fun part — if nothing is selected, using the arrow keys will instead scroll the drawing area by a small amount. And if you hold <Control> down while using them, you'll scroll a screen full. 😭
In select vertices mode, the left mouse button selects and moves vertices. But there's a catch: only the top-level polyline/open-spline and polygon/closed-spline objects that were selected when vertex mode was activated are eligible for vertex operations. Periodt.
In this mode, all eligible objects get their vertices highlighted with squares. When a vertex is selected (same kind of mechanism as selecting objects, described above), it gets doubly highlighted with a '+' sign ✨.
What you can do with those doubly-highlighted vertices:
- move
- delete
- align (with each other)
- distribute (space them equally)
- align to grid
And yeah — the arrow keys can move selected vertices too. 💅
Locked objects 🦋 — you lock them with the #< keyboard command. Locked objects show up with gray handles, and they cannot be moved, stretched, flipped, rotated, or sheared.
When objects get grouped, the resulting grouped object will also be locked if <em>any one</em> of its constituents is locked. But here's what locked objects can still do: have their properties changed — color, font, pen, etc. — and they can be deleted. So not fully invincible, just stubborn. 🙈
Now for the constrained move/stretch mode — that's the one you toggle on and off with the #@ keyboard command. When it's active, top-level polylines behave like this:
- In a move operation: if both endpoints of a polyline lie inside the objects being moved, the whole polyline moves. Otherwise, if only one endpoint falls inside the objects being moved, then that endpoint is moved.
- The vertex that is the neighbour of the moved endpoint may also be moved, either horizontally or vertically. And if the last line segment is horizontal or vertical, then that neighbour vertex may be moved so that the direction of the last line segment is maintained.
- In a stretch operation (not reshape): if an endpoint of a polyline lies inside the objects being moved, that endpoint will be moved. The neighbour of the moved endpoint also gets moved, in the same manner described above.
Text drawing mode (you'll know it's on because you get a vertical-bar cursor) — clicking the left mouse button causes selected text to go into edit mode. 🌸
- Dragging the left mouse button, or clicking the left mouse button while
<Shift>is held down → highlights substrings of the text - Double-clicking → selects a word
In edit mode, key presses are treated as text strings being inputed, and the arrow keys move the current input position.
Now here's the galaxy-brain bit ⭐: if a key press is preceded by an <ESC> key, then the character's bit 7 is turned on. That's how you enter non-ASCII (international) characters! You can use xfd(1) to see what the corresponding international character is for an ASCII character. For the Symbol font, symbols like the integral, partial derivative, and copyright symbols can all be found in this range. 🎀
But not everything makes it through: there are some characters that are supported by X11 but not by PostScript — those characters are not accepted by tgif. 💀
And if the text you're editing is an attribute of an object: <Meta><Tab> moves the cursor to the next visible attribute, and <Shift><Tab> moves it to the previous visible attribute. 🫶
If the drawing mode is set to draw polygons (not closed-splines) and the <Shift> key is held down, the rubber-banded polygon will be self-closing. Cute, right? ✨
Freehand drawing mode is for polylines and open splines. The vibe is different here:
- All intermediate points are specified by moving the mouse — not by clicking the mouse buttons like you do in polyline mode.
- The second endpoint is specified by releasing the mouse button.
And finally, for this stretch of the page anyway: in all drawing modes other than text mode, pressing the <ESC> key cancels the drawing (creation) of the current object. Escape hatch, literally. 💅
okay so bestie, quick mouse lore before we dive in: the middle mouse button? always pops the main tgif popup menu. Every time. No cap. 🖱️
And if you hold down <Shift> while clicking the right mouse button, the drawing mode flips to select. Very "sneaky shortcut, love that for us" energy. ✨
Now, key presses where you're holding <Control> or <Meta> — these get called non-alphanumeric key presses (because they can also generate control characters, fun little identity crisis) — those get treated as commands, and their bindings are summarized in the next section. Also, you can define your own single key commands to emulate the functions of the non-alphanumeric key commands, and the SHORTCUTS section spills all that tea. 💅
🌀 Scrollbars
Clicking the left mouse button in the vertical or horizontal scrollbar makes the canvas window scroll down or right by a small distance. Clicking the right mouse button does the exact opposite — reverse effect, baby. 😌 (And yes, the scrollbars in the popup windows for selecting file names and domain names behave the same way. Consistency iconic.)
Hold <Shift> while clicking and it scrolls a whole window full. Go big or go home.
Click or drag the middle button and the page scrolls to the location corresponding to the gray area in the scrollbars.
Tgif is a little particular (we love a diva 💅): it insists that the left-top corner of the Canvas Window sits at a distance that's a nonnegative multiple of some internal units from the left-top corner of the actual page.
📏 Rulers
The rulers track your mouse location. That's their whole job. Mouse clicks and key presses? No effect. They simply do not care. 🙈
When page reduction/magnification is set at 100%, the markings in the rulers correspond to centimeters when the metric grid system is used, and to inches when the English grid system is used.
When page reduction/magnification is not at 100%, the markings do not correspond to those units anymore. And yeah, that's considered a known bug. Not a feature, bestie, a certified oops. 💀
🚀 Interrupt/Hyperspace Window
This window lives right below the Message Window and to the left of the horizontal ruler.
When the Tgif.IntrCheckInterval X default has a positive value, an interrupt icon is visible while the Canvas Window is being redrawn. If you click this window while the interrupt icon is showing, tgif aborts the repainting of the objects. 🛑
And if you do that while a file is being opened (either through Open() or Push()), the drawing of objects stops — but the reading of the file continues. Reading is not aborted. She commits to the read, periodt.
Now for the hyperspace of it all: if tgif is currently in hyperspace mode (peep the HYPERSPACE section below for the full lore), a space ship icon 🚀 gets displayed whenever the interrupt icon isn't showing. Clicking any button in this window switches tgif in and out of hyperspace mode. Main character transportation energy, fr fr.
📑 Page Control Window
The Page Control Window is to the left of the horizontal scrollbar.
- If the current page mode is set to tiled page mode, this window is empty. Nothing to see here. 🫥
- If the current page mode is set to stacked page mode, every page gets a tab in the tabs subwindow of this window.
Clicking the left mouse button on a tab goes to the corresponding page. Clicking the middle mouse button brings up the Page Menu.
When there are soooo many pages in a drawing that you can't see the tabs for all of them, use the icons to the left side of the Page Control Window to scroll the tabs subwindow:
- Clicking the first icon scrolls the tabs subwindow so that the first tab is visible. 🌟
- Clicking the 4th icon scrolls the tabs subwindow so that the last tab is visible. 🏁
- Clicking the 2nd icon scrolls the tabs subwindow towards the first tab by one tab.
- Clicking the 3rd icon scrolls the tabs subwindow towards the last tab by one tab.
🩺 Status Window
This one's below the horizontal scrollbar. It shows what action will be taken if a mouse button is depressed. When a menu is pulled down or popped up, this window shows what action will be taken if a menu item is selected. It also displays miscellaneous status info — a true multitasker. 💖
Mouse clicks and key presses have no effect here. Just vibes and information.
- Select
HideStatus()from the Layout Menu and this window becomes invisible. - Select
ShowStatus()from the Layout Menu and it becomes visible again.
By default, when this window is displaying mouse button status, a right-handed mouse is assumed. Setting the Tgif.ReverseMouseStatusButtons X default to true reverses the status (as if a left-handed mouse is used). Lefties, we got you. 🫶
🎀 Popup Menus
When a menu is popped up by a mouse drag, the menu can be pinned if it's dragged far enough horizontally — and the distance is determined by the setting of the Tgif.MainMenuPinDistance X default. 📌
- Clicking the right mouse button in a pinned menu makes it disappear. Poof. ✨
- Dragging the left mouse button in a pinned menu repositions the menu — except when the
Tgif.TitledPinnedMenuX default is set to true, in which case the left mouse button performs the same function as the middle mouse button. - Clicking the middle mouse button in a pinned menu activates the item right below the mouse. 🎯
🎹 NON-ALPHANUMERIC KEY BINDINGS 💅✨
Okay so bestie, here's the tea ☕ — most operations in tgif can be activated through non-alphanumeric keys. And listen, some operations can only be activated through popup menus or shortcut keys, so don't come for me when a key doesn't do the thing. This section is the full rundown of every operation you can fire off by pressing a key while holding down <Control> and/or the <Meta> key. 🫶
In everything below, ^ = the <Control> key and # = the <Meta> key. Periodt. 💖
Also there's akeys.objfile that ships with tgif and it summarizes this exact same info — just organized differently. You can view it with tgif, and if it got installed properly you'll find it in the same directory as thetgificon.objfile, which is the one mentioned in the FILES section of this document. iykyk 🦋
🌸 Control key bindings 🌸
^a— select all 🔥^b— send selected objects to the back^c— copy selected objects into the cut buffer^d— duplicate selected objects ✨^e— save/restore drawing mode^f— send selected objects to the front^g— group selected objects (heads up: the grouped object will be brought to the front 👑)^i— instantiate a building-block object^k— pop back to (or return to) a higher level and close the symbol file (this is the reverse of^v)^l— align selected objects according to the current alignment settings^n— open a new un-named object file 🎀^o— open an object file to edit^p— print the current page (or export in XBM, XPM, GIF, HTML, PDF, EPS, or PS formats) 🖨️^q— quit tgif 😭^r— redraw the page^s— save the current object/symbol file 💾^t— align selected objects to the grid according to the current alignment^u— ungroup selected objects^v— paste from the cut buffer^w— change the drawing mode to text^x— delete all selected objects 💀^y— change domain^z— escape to driver^,— scroll left^.— scroll right^-— print the current page with a specified command
🌈 Meta key bindings 🌈
#a— attach selected text objects to a selected non-text object as attributes#b— escape to driver#c— rotate selected objects counter-clockwise#d— decrement the grid size#e— send a token on a selected polyline#f— flash a selected polyline#g— show/un-show grid points#h— flip the selected objects horizontally#i— increment the grid size#j— hide the attribute names of the selected objects#k— change the drawing mode to select#l— distribute selected objects according to the current alignment#m— move/justify an attribute of a selected object#n— show all the attribute names of the selected objects#o— zoom out#p— import a.objor a.symfile into the current file#q— change the drawing mode to polyline/open-spline#r— change the drawing mode to rectangle#s— escape to driver#t— detach all the attributes of the selected objects#u— undo 🫶#v— flip the selected objects vertically#w— rotate the selected objects clockwise#x— escape to driver#y— escape to driver#z— zoom in#9— create a user-specified arc (12 o'clock position is 0 degree)#0— update the selected objects according to current settings#,— scroll up#.— scroll down#-— show all the attributes of the selected objects#[— align the left sides of objects#=— align the horizontal centers of objects#]— align the right sides of objects#{— align the top sides of objects#+— align the vertical centers of objects#}— align the bottom sides of objects#"— make the selected polygon regular (fit the original bounding box)#%— set the percent print reduction (if < 100%) or magnification (if > 100%)#:— go to default zoom#`— zoom out all the way so that the whole page is visible 👀#~— save selected objects in a new file#;— cut and/or magnify a selected bitmap/pixmap object#_— abut selected objects horizontally#|— abut selected objects vertically##— break up text objects into single character text objects#^— scroll to the origin set bySaveOrigin()#@— toggle between constrained and unconstrained move (stretch) modes#$— change the drawing mode to select vertices#&— align selected objects to the paper according to the current alignment#*— redo ✨#(— import an Encapsulated PostScript file#)— scale selected objects by specifying X and Y scaling factors#<— lock the selected objects (can't be moved, stretched, flipped, or rotated) 🔒#>— unlock the selected objects 🔓
💜 Control + Meta key bindings 💜
^#a— add points to the selected poly or spline^#b— change the text style to bold^#c— change to center justified text^#d— delete points from the selected poly or spline^#e— change the drawing mode to rounded-corner rectangles^#f— reverse-video the selected bitmap objects^#g— toggle snapping to the grid points^#h— hide all attributes of the selected objects^#i— make the selected object iconic^#j— make the selected icon object a grouped object^#k— select color or black-and-white output 🎨^#l— change to left justified text^#m— make the selected object symbolic^#n— make the selected symbol object a grouped object^#o— change the text style to roman^#p— change the text style to bold-italic^#q— change the drawing mode to polygon/closed-spline^#r— change to right justified text^#s— save the file under a new name^#t— change the text style to italic^#u— update iconic representations of selected objects^#v— change the drawing mode to oval^#w— toggle between poly and spline^#x— cycle among the various output file formats^#y— push into (or edit) the definition part of a building-block (icon) object^#z— change the drawing mode to arcs^#.— import an X11 bitmap file^#,— import an X11 pixmap file^#-— toggle between English and Metric grid systems^#=— repeat the last Find command 🔍
⌨️ SHORTCUTS 🎀
Okay so here's the cute part: you can define your own single character shortcut keys to emulate the function of all those non-alphanumeric key presses and activate commands. It's giving custom keymap, honestly iconic. 💅
You do this through the Tgif.ShortCuts X default. ⚠️ Important though: these shortcut keys are only active when the drawing mode is not set to the text mode.
The Tgif.ShortCuts is a list of items, and each item specifies the bindings between a key (which may be case sensitive, so watch it 🌸) and a command. The items are separated by blanks, and every item is interpreted like this:
It has two parts, KEY and COMMAND, concatenated together with a ':' character. 🔗
The format of the KEY part is one of :<Key>x, !<Key>x, or <Key>x — here the character x is used as an example, and also the substring <Key> must be spelled exactly the way it appears here, don't get creative with it bestie.
- The first 2 formats are equivalent — they specify the lower case
x - The 3rd format specifies both the characters
xandX
The COMMAND part is a string that matches strings in tgif's popup menus with space characters removed (exceptions are noted below 👇).
Let's illustrate with the example. In the Edit menu, two of the entries are:
"Delete ^x"
"SelectAll ^a"
Which means that <Control>x activates the Delete() command, and <Control>a activates the SelectAll() command. So both Delete() and SelectAll() are valid names for the COMMAND part of a shortcut specification. 🫶
And to complete the example, this line here binds the lower case x to Delete() and a or A to SelectAll():
Tgif.ShortCuts: !<Key>x:Delete() \n\
<Key>a:SelectAll()
For more examples, go look at the sample X defaults file, tgif.Xdefaults, which is included in the tgif distribution. ✨
🦋 COMMAND name exceptions 🦋
Here's a list of exceptions, where the COMMAND does not match a command name in a menu entry. On the left is the proper COMMAND name, and on the right is the list of strings shown in popup menus that the COMMAND would correspond to:
CyclePrintFormat()—Printer,LaTeXFig,RawPSFile,XBitmap,TextFile,EPSI,GIF/ISMAP,TiffEPSI,NetListToggleBW/ColorPS()—BlkWhtPS,ColorPSToggleGridSystem()—EnglishGrid,MetricGridToggleMapShown()—ShowBit/Pixmap,HideBit/PixmapToggleUseGrayScale()—UseGrayScale,NoGrayScaleToggleMoveMode()—ConstMove,UnConstMoveToggleShowMeasurement()—ShowMeasurement,HideMeasurement
And then these ones, which don't have popup-menu counterparts listed:
ToggleLineType()— (advances between different curved shapes)ScrollPageUp()— (scroll up a window full)ScrollPageDown()— (scroll down a window full)ScrollPageLeft()— (scroll left a window full)ScrollPageRight()— (scroll right a window full)FreeHandMode()— (change the drawing mode to freehand poly/open-spline)CenterAnEndPoint()— (move an endpoint of a polyline object to the center of another object)ToggleNamedAttrShown(<x>=)— (toggle name shown for the attribute<x>)ToggleSmoothHinge()— (convert smooth to hinge and hinge to smooth points)ToggleShowMenubar()—ShowMenubar,HideMenubarToggleShowStatus()—ShowStatus,HideStatusToggleShowMode()—ShowMode,HideModeToggleOneMotionSelMove()—OneMotionSelMove,ClickSelClickMoveToggleHyperSpace()—GoHyperSpace,LeaveHyperSpaceImportOtherFileType(<x>)— (import using a filter named<x>)BrowseOtherType(<x>)— (browse using a filter named<x>)PrintSelectedObjs()— (print selected objects)
And on top of everything in that list, these are also valid COMMAND names (and yes, they have the obvious meaning 🫡): ScrollLeft(), ScrollRight(), ScrollUp(), ScrollDown(), SelectMode(), DrawText(), DrawBox(), DrawOval(), DrawPoly(), DrawPolygon(), DrawRCBox(), DrawArc(), and SelectVertexMode(). 💖
🌈 COLORS AND COLORMAPS 🌈
okay bestie, sit down for this one because it's giving very 1990s X11 energy and it lowkey matters. 💅
In most X environments, only 256 colors can be displayed at once. So like, if one application needs 128 colors and another application needs a totally different 129 colors, both apps literally cannot be displayed at the same time with all the colors they want. 😭 X solves this by letting applications use their own colormaps — these are called private colormaps. Each private colormap can have at most 256 colors. There's also a shared colormap available for applications that don't wanna go private. The main problem with private colormaps? The user gets the well-known colormap flashing phenomenon when they switch in and out of apps that use private colormaps. ✨ flashing ✨ iconic but also annoying.
Tgif uses the shared colormap initially. When it needs more color than what's available in the shared colormap, it will use a private colormap automatically. BUT — and this is the part nobody tells you — when tgif no longer needs the extra colors, it does not automatically revert to using the shared colormap, because it needs to be able to undo operations that use the extra colors. 🙈
So if you no longer need the objects sitting in the undo buffer, you can select FlushUndoBuffer() from the Edit Menu to flush the undo buffer. At that point, tgif will attempt to use the shared colormap to avoid the colormap flashing problem. 🎀 If you often use XPM and GIF objects, you can bind the <Shift>f key to the FlushUndoBuffer() operation by setting the following X default, and then use the <Shift>f key to regain entries in the colormap when an XPM/GIF object is deleted:
Tgif.ShortCuts: !<Key>F:FlushUndoBuffer()
Even when a private colormap is used, only 256 colors can be used at once. Therefore, it is not possible to import two 256-colors GIF files into the same drawing unless the colors are somehow reduced to fit in the 256-colors colormap. 😭 This can be done through dithering, which is described in the IMPORT RASTER GRAPHICS section below. 👇
🖼️ IMPORT RASTER GRAPHICS 🖼️
The native raster graphics formats that tgif supports are the XBM and XPM formats. In order to import a color raster graphics file of another format, tgif can work with external tools that can convert non-XPM format files to XPM files. 🦋
A popular raster format conversion toolkit is the pbmplus(1) (also known as the netpbm(1)) toolkit. It can convert a GIF file (e.g., "foo.gif") to an XPM file (e.g., "foo.xpm") with the following command (giftopnm is in netpbm; an earlier version of it called giftoppm exists in pbmplus):
giftopnm foo.gif | ppmtoxpm > foo.xpm
When working with tgif, a GIF file name will be supplied by tgif and the output of ppmtoxpm will be directly read by tgif through a pipe; therefore, the previous sequence is replaced by an X default containing the following form (which happens to be the default setting for the Tgif.GifToXpm X default):
giftopnm %s | ppmtoxpm
The "%s" is to be replaced by a GIF file name. The above is referred to as a filter. ✨
To be able to import other types of raster graphics files, one can use Tgif.MaxImportFilters and Tgif.ImportFilter# X defaults to specify additional filters. The following example adds a JPEG filter:
Tgif.MaxImportFilters: 1
Tgif.ImportFilter0: \n\
JPEG-222 jpg;jpeg \n\
djpeg -gif -colors 222 %s | \n\
giftopnm | ppmtoxpm
The "JPEG-222" above is the name given to the filter (must not contain any space character, bestie, not even one 💀). The "jpg;jpeg" are possible file extensions separated by semicolons. The rest is the filter specification. The djpeg(1) program is part of the libjpeg distribution. It can convert a JPEG file to a GIF file. The above filter also restricts the output to have a maximum of 222 colors. (The 222 is chosen arbitrarily. Many XPM files use some ``standard'' 32 colors, so one may want to leave room for them.) 🎀
To invoke a filter, one can select ImportOtherFile() or BrowseOther() commands from the File Menu. This will bring up a dialogbox listing the available filters by their names (e.g., "JPEG-222"). After selecting a filter, tgif continues in a similar manner as with invoking ImportXPixmap() or BrowseXPixmap() commands from the File Menu. 🫶
The above example is not suitable for the BrowseOther() command because only 256 colors can be used in a drawing (as explained in the COLORS AND COLORMAPS section above 👆). In order for BrowseOther() to work well, one can use dithering to represent an image with a dithered image that only uses a set of standard colors. The example below uses ppmdither from the pbmplus/netpbm toolkit:
Tgif.MaxImportFilters: 2
Tgif.ImportFilter0: \n\
JPEG-222 jpg;jpeg \n\
djpeg -gif -colors 222 %s | \n\
giftopnm | ppmtoxpm
Tgif.ImportFilter1: \n\
JPEG-dithered jpg;jpeg \n\
djpeg -gif %s | \n\
giftopnm | ppmdither | ppmtoxpm
If one is working with one JPEG image, one can select ImportOtherFile() then select "JPEG-222" to get as many as 222 colors. If one is browsing for JPEG images, one can select BrowseOther() then select "JPEG-dithered". 💖
🏷️ OBJECT NAMES 🏷️
If an object contains an attribute (please see the ATTRIBUTES sections below for details 👇) whose name is the string "name" (case-sensitive, so don't get cute with it), the value part of the attribute is the name of the object. ✨
A subobject of a composite object can be named using a path, e.g., <t>!<s1>!<s2>!..., where <t> is the name of a top-level object which directly contains <s1> which directly contains <s2>, etc. !* refers to the currently selected object (if more than one object is selected, the top-most object in the stacking order is used). !*<s1>!<s2> names the <s2> subobject of the <s1> subobject of the currently selected object. 🦋
⚠️ The following is not fully supported yet (only the #<page> form is supported at this time).
Every object in a tgif file can be uniquely named using the notation #<page>!<path>, where <page> can be a string that specifies the name of a page or #<number> which specifies a page number. The <path> is described in the previous paragraph. If an object o1 is referenced by another object o2 within the same file (no file name or URL is specified before #) and <page> is omitted, then o1 must be on the same page as o2. If a file name or URL is specified before # and <page> is omitted, then o1 must be on the first page. 📄
🎀 ATTRIBUTES 🎀
Attributes are text strings of the form name=value or value which are attached to either the current drawing or any non-text objects. An attribute attached to the current drawing is called a file attribute; otherwise, it is a regular attribute. Attributes can be attached and detached from these objects except in the following case:
Attributes appearing in the symbol object in a building-block object file can not be detached when the building-block object is instantiated. These attributes are considered to be theinherited'' attributes of the icon object. (If it is really necessary to detach inherited attributes of an icon object, the icon object can bede-iconified'' by usingUnMakeIconic()in the Special Menu to make it a grouped object; then the attributes can be detached.) 😭
A file attribute is always invisible. For a regular attribute, the user has control over which part of the attribute is displayed. An entire attribute can be made invisible, or only its name can be made invisible (accomplished through the commands under the special menu, such as #m, #n, #j, #-, and ^#h). 💅
🚀 TELEPORT/HYPERJUMP 🚀
Tgif provides the mechanism to travel between .obj and .sym files. no cap, it's literally teleporting. ✨
If the middle mouse button is clicked on an object with the <Shift> key held down (or double-clicking such an object), tgif looks for an attribute named warp_to (by default) or href of that object. The only difference between warp_to and href is that ".obj" is automatically appended to the value of a warp_to attribute while the value of a href attribute is taken as is. (Please note that warp_to is obsolete now. It is still supported for the sake of compatibility.) 🙈
If such an attribute is found, the value part of the attribute is interpreted as the name of a .obj file to travel to. (If tgif is in the hyperspace mode, then clicking the left mouse button has the same effect.) If there are multiple href attributes on the object, but are in different colors, tgif will use the one that has the same color as the current color appearing in the Choice Window. 🎨
If the current file is modified, the user is prompted to save the file before traveling to the next file. If the value part of the href attribute starts with the / character, the value is treated as an absolute file name; otherwise, it is treated as a relative file name. 💖
👑 HYPERSPACE 👑
Tgif provides a hyperspace mode to facilitate traveling between .obj files. main character energy fr fr. 🌌
The hyperspace mode is entered when GoHyperSpace() is selected from the Navigate Menu. In hyperspace mode, the little window below the Message Window will show a little space ship. 🚀 The hyperspace mode is also automatically entered when a remote URL is opened (unless the Tgif.AutoHyperSpaceOnRemote X default is set to false).
In the hyperspace mode, certain objects are considered hot-links. When the cursor is placed on top of these objects, it will change from a pointer to a hand to indicate that clicking on the left mouse button will invoke some actions. An object is a hot-link if it contains an attribute described in either the TELEPORT/HYPERJUMP, LAUNCH APPLICATIONS, or INTERNAL COMMANDS section. 👆
The hyperspace mode is exited when the drawing mode is changed or the LeaveHyperSpace() is selected from the Navigate Menu. 🦋
🚀 LAUNCH APPLICATIONS
Okay bestie, so tgif can literally launch other apps for you. Here's the tea ✨
If you click the middle mouse button on an object while holding down <Shift> (or if you just double-click that object), tgif goes looking for an attribute named launch (that's the default name) on that object. Found it? Then the value part of that attribute gets interpreted as a sh(1) command to execute. The same color rule from the TELEPORT/HYPERJUMP section up above applies here too, no cap.
Now — if the command ends with the '&' character, tgif forks itself (what actually happens depends on whether the _BACKGROUND_DONT_FORK compiler flag was defined at compile time or not, iykyk) and the child process runs the command. If it doesn't end with &? Then popen() is used to execute the command instead.
💀 Heads up though: in the popen() case, if the command hangs, there is no way provided to terminate the command, and tgif will not be able to recover from it. Fr fr, be careful.
Inside the command, you can use values of other attributes of the same object. The syntax is $(attr), where attr is the name of another attribute. Iconic.
So like, say you wanna do a man(1) function. You:
- draw a box
- enter a line of text
"title=tgif" - enter another line of text
"launch=xterm -rw -e man $(title)" - select all three objects using the
^akeyboard command - attach the text strings to the box using the
#akeyboard command - launch the
man(1)command by clicking the middle mouse button on the box (or on the text strings) with<Shift>held down
And if you wanna be extra fancy 💅 — swap the box for an X11 pixmap object, make the launch attribute invisible, and make the title attribute center justified with its name hidden using the #m keyboard command. Main character energy.
By default, launching an application is disabled in hyperspace mode for security considerations (you can override this with the Tgif.AllowLaunchInHyperSpace X default setting). If a lunch command is encountered in hyperspace mode, the command gets displayed and the user is prompted to say whether they want to execute it or not. Cute little safety check 🎀
🧠 INTERNAL COMMANDS
Tgif also has the mechanism to execute internal commands. Same deal: click the middle mouse button on an object with <Shift> held down (or double-click that object), and tgif hunts for an attribute named exec (default name, obvi). If it finds one, the value part of that attribute is interpreted as a list of internal commands (separated by semicolon) to execute. Same color rule as the TELEPORT/HYPERJUMP section above. 💜
A command usually takes this form:
<cmd_name> ( <arg1>, <arg2>, ..., <argN> )
An argument can be a string argument or a numeric argument:
- a string argument must be enclosed in double-quotes
- a numeric argument can be a numerical value, or a string of the form
"$(x)", where x is the name of another attribute (this form is called the substitution form) - a string argument can also contain substitution form
⚠️ Please note that only one-level substitution is performed. The collection of internal commands should be viewed as a simple scripting language, not a declaration language. Periodt.
When an attribute is referenced in an internal command, the attribute name can be in the form <obj_name>.<string>, where <obj_name> must be in the form specified in the OBJECT NAMES section above, and <string> contains only alphanumeric characters and the underscore ('_') character.
Special prefixes, bestie, listen up:
- if the first 2 characters of an attribute name are
"!.", the rest of the attribute name names a file attribute - if the first 2 characters of an attribute name are
"!*", the rest of the attribute name names an attribute of the currently selected object (if more than one object is selected, the top-most object in the stacking order is used)
Also: lines that begin with "//" are treated as comments. 🌸
The following internal commands are supported:
launch(<attr_name>)
The value of the attribute specified by <attr_name> is interpreted as a sh(1) command to execute. Please see the LAUNCH APPLICATIONS section above for more details.
exec(<attr_name>)
The value of the attribute specified by <attr_name> is interpreted as an internal command to execute. This is similar to a subroutine call. Please note that the internal command is executed in the context of the top-level which contain the attribute.
mktemp(<str>,<attr_name>)
This command makes a unique file name. The <str> argument is a template string, e.g., "/tmp/TgifXXXXXX", and it requires at least two "/" in it. The result of mktemp() is stored as the value of the attribute specified by <attr_name>. Please see the man pages of the C library function on mktemp(3C) for more details. (If tgif is compiled with the -D_USE_TMPFILE compiler option, then tempnam(3S) is used instead.)
create_file_using_simple_template(<template>,<output>,<str>,<attr_name>)
The file specified by <template> is scanned for a line that matches <str>. When such a line is found, that line is replaced by the value of the attribute specified by <attr_name>. The result is put into the file specified as <output>.
update_eps_child(<eps_file_name>)
This only works if the object being executed is a composite object. If the object has a component which is an imported EPS (Encapsulated PostScript) object, it is replaced by the EPS file specified by <eps_file_name>. If the object does not contain an EPS subobject, an EPS subobject is created. ✨
update_xbm_child(<xbm_file_name>)
This only works if the object being executed is a composite object. If the object has a component which is an imported XBM (X11 bitmap) object, it is replaced by the XBM file specified by <xbm_file_name>. If the object does not contain an XBM subobject, an XBM subobject is created.
update_xpm_child(<xpm_file_name>)
This only works if the object being executed is a composite object. If the object has a component which is an imported XPM (X11 pixmap) object, it is replaced by the XPM file specified by <xpm_file_name>. If the object does not contain an XPM subobject, an XPM subobject is created.
delete_eps_child(<obj_name>)
This only works if the object named <obj_name> is a composite object. If the object has a component which is an EPS (Encapsulated PostScript) object, it is deleted. If the object does not contain an EPS subobject, no operation is performed.
delete_xpm_child(<obj_name>)
This only works if the object named <obj_name> is a composite object. If the object has a component which is an XPM (X11 pixmap) object, it is deleted. If the object does not contain an XPM subobject, no operation is performed.
delete_xbm_child(<obj_name>)
This only works if the object named <obj_name> is a composite object. If the object has a component which is an XBM (X11 bitmap) object, it is deleted. If the object does not contain an XBM subobject, no operation is performed.
flip_deck(<times>,<frames_per_second>,<style>)
This only works if the object being executed is a composite object and all subobjects of the composite object are X11 bitmap or X11 pixmap objects and have identical positions and sizes. So many ands 😭
<times>specifies the number of times the deck is flipped. It can be a number or the string"infinite".<frames_per_second>must be a number between1and60.<style>can be either"linear"or"ping_pong".
When this command is being executed, any mouse button click or key click aborts command execution.
read_file_into_attr(<file_name>,<attr_name>)
This command reads a file into an attribute. The <file_name> argument names a file, e.g., "/tmp/foo". The content of the file is read as the value of the attribute specified by <attr_name>. If the file can not be opened for read, the attribute's value is set to an empty string.
write_attr_into_file(<attr_name>,<file_name>)
This command writes the value of an attribute into a file. The <file_name> argument names a file, e.g., "/tmp/foo". The value of the attribute specified by <attr_name> is written into <file_name>.
append_attr_into_file(<attr_name>,<file_name>)
This command appends the value of an attribute into a file. The <file_name> argument names a file, e.g., "/tmp/foo". The value of the attribute specified by <attr_name> is appended into <file_name>.
select_obj_by_name(<obj_name>)
This command silently (no highlighting handles) selects an object named <obj_name>. Please see the OBJECT NAMES section above for the specification of object names.
select_top_obj()
This command silently (no highlighting handles) selects the top object. This command fails if there is no object in the current page.
delete_selected_obj()
This command deletes all selected objects. This command fails if no object is selected.
unselect_all_obj()
This command de-selects all selected objects. If the select_obj_by_name() command is used, this command must be used eventually. No skipping, bestie 🙈
move_selected_obj_relative(<dx>,<dy>)
This command moves the selected object by <dx> absolute units in the x direction and <dy> absolute units in the y direction.
repeat(<cmd_attr_name>,<times>)
This command executes the internal command in the <cmd_attr_name> attribute <times> times. Loops! 🔥
hyperjump(<attr_name>)
This command teleports to the file name or URL name found in the <attr_name> attribute.
make_cgi_query(<dest_attr_name>,<url_name>,<list_attr_name>)
This command constructs an URL in the Common Gateway Interface (CGI) format in the <dest_attr_name> attribute. <url_name> names the CGI server script and <list_attr_name> names an attribute whose value are comma-separated attribute names.
For example, if an object has the following attributes:
attr_list=last_name,first_name
last_name=Cheng
first_name=Bill
final_url=
exec=make_cgi_query(final_url,
http://bourbon.usc.edu:8001/cgi-bin/test-cgi,
attr_list)
Executing this object will construct the following string in final_url:
http://bourbon.usc.edu:8001/cgi-bin/test-
cgi?last_name=Cheng&first_name=Bill
Slay. 🦋
And bestie, once you're in that flow, a hyperjump(final_url) command can be invoked to execute the corresponding "test-cgi" CGI server script with the last_name and first_name arguments. 💅
For a detailed description of CGI scripts, the reader is referred to [2].
wait_click(<cursor_name>,<grab>,<attr_name>)— okay so this one shows the<cursor_name>cursor and just waits for you to click a mouse button. If<cursor_name>is the stringNULL(case-sensitive, bestie, do not lowercase it), the cursor will not change. If<Btn1>is clicked, the command terminates and1is placed in<attr_name>. If<Btn2>is clicked,2is placed in<attr_name>, etc. If<grab>is set toTRUE(also case-sensitive), then the mouse is grabbed by tgif. Valid<cursor_name>can be found in<X11/cursorfont.h>(without theXC_prefix). 🖱️✨sleep(<cursor_name>,<ms_interval>)— this command displays the<cursor_name>cursor and waits for<ms_interval>milliseconds to elapse. If<cursor_name>is the stringNULL(case-sensitive), the cursor will not change. This command can be interrupted (and aborted) by any mouse clicks or key strokes. Valid<cursor_name>can be found in<X11/cursorfont.h>(without theXC_prefix). 😴⏳begin_animate()— this command is used to start an animation sequence (using double-buffering). Please note that, by default, tgif prepares for undo/redo. For a long animation sequence, the undo/redo records may take up a lot of memory. In this case,disable_undo()(described below) should be used before this command. 🎬💖end_animate()— this command is used to terminate an animation sequence. 🛑set_redraw(<true_or_false>)— this command is used to temporarily disable redraw if<true_or_false>isFALSE(case-sensitive) when tgif is in the animation mode (turned on bybegin_animate()). If ashuffle_obj_to_top()or ashuffle_obj_to_bottom()command is used before a move command,set_redraw(FALSE)andset_redraw(TRUE)should be used immediately before and immediately after, respectively, theshuffle_obj_to_top()orshuffle_obj_to_bottom()command. 🔄👑set_selected_obj_color(<color_str>)— this command changes the color of the selected object to<color_str>. If no object is selected, the current color will be changed to<color_str>. 🎨set_selected_obj_fill(<fill_index>)— this command changes the fill pattern of the selected object to<fill_index>, which must be between0(for no fill) and31. If no object is selected, the current fill pattern will be changed to<fill_index>. 🖌️set_selected_obj_pen(<pen_index>)— this command changes the pen of the selected object to<pen_index>, which must be between0(for no pen) and31. If no object is selected, the current pen will be changed to<pen_index>. 🖊️set_selected_obj_line_width(<width>,<arrow_w>,<arrow_h>)— this command changes the line width, arrow width, and arrow height of the selected object to<width>,<arrow_w>, and<arrow_h>, respectively. If<arrow_w>or<arrow_h>is-1, the arrow width or arrow height, respectively, is not changed. If no object is selected, the current line width will be changed to the one that matches<width>,<arrow_w>, and<arrow_h>most closely. (Closeness is measured such that the difference in width is counted10times the difference in arrow width and arrow height.) 📏➡️set_selected_obj_spline(<spline_type>)— this command changes the spline type of the selected object to<spline_type>, which can bestraight,spline,interpolated, orstructured. If no object is selected, the current spline type will be changed to<spline_type>. 🌊set_selected_obj_arrow(<arrow_type>)— this command changes the arrow type of the selected object to<arrow_type>, which can benone,right,left, ordouble. If no object is selected, the current arrow type will be changed to<arrow_type>. 🏹set_selected_obj_dash(<dash_index>)— this command changes the dash type of the selected object to<dash_index>, which must be between0(solid) and8. If no object is selected, the current dash type will be changed to<dash_index>. ➖set_selected_obj_trans_pat(<trans_pat>)— this command changes selected object to have opaque pattern if<trans_pat>is0; it changes selected object to have transparent pattern if<trans_pat>is any other numeric value. If no object is selected, the current fill and pen pattern will be opaque if<trans_pat>is0and will be transparent if<trans_pat>is any other numeric value. 👻set_selected_obj_rcb_radius(<rcb_radius>)— this command changes the rcbox radius of the selected object to<rcb_radius>, which must be greater or equal to4. If no object is selected, the current rcbox radius will be changed to<rcb_radius>. 📐set_selected_text_vspace(<vspace>)— this command changes the text vspace of the selected object to<vspace>. If no object is selected, the current text vspace will be changed to<vspace>. 📏set_selected_text_just(<justification>)— this command changes the text justification of the selected object to<justification>, which can beleft,center, orright. If no object is selected, the current text justification will be changed to<justification>. ⬅️➡️set_selected_text_font(<ps_font_name>)— this command changes the font and text style of the selected object to match<ps_font_name>. Examples of valid<ps_font_name>can be found when one selectsCopyProperties()from the Properties Menu. The item listed under text font is a valid<ps_font_name>. If no object is selected, the current font and text style will be changed to match<ps_font_name>. This command fails if no match can be found. 🔤💅set_selected_text_style(<textstyle>)— this command changes the text style of the selected object to<textstyle>, which can ber(for roman),b(for bold),i(for italic), orbi(for bold-italic). If no object is selected, the current text style will be changed to<textstyle>. ✨set_selected_text_size(<size>)— this command changes the text size of the selected object to<size>. If<size>ends with the substring"pt", then point size is used instead of text size. If such as size cannot be found in the Size Menu, the closest size in the Size Menu will be used. If no object is selected, the current text size will be changed to<size>or the closest size. 🔠set_selected_text_underline(<underline>)— this command removes text underline from the selected object if<underline>is0; it underlines text in the selected object if<underline>is any other numeric value. If no object is selected, the current text underline will be changed accordingly. 🖍️set_selected_text_overline(<overline>)— this command removes text overline from the selected object if<overline>is0; it overlines text in the selected object if<overline>is any other numeric value. If no object is selected, the current text overline will be changed accordingly. 🖍️inc(<attr_name>,<expr>)— this command increment<attr_name>by the expression<expr>. Both the value of<attr_name>and<expr>must be integers. Please see the ARITHMETIC EXPRESSIONS section below for details about expressions. ➕dec(<attr_name>,<expr>)— this command decrement<attr_name>by<expr>. Both the value of<attr_name>and<expr>must be integers. ➖shuffle_obj_to_top(<obj_name>)— this command move<obj_name>to the top. If<obj_name>is a subobject, it is raised to the top, relative to its siblings. This command is useful in animation where a selected frame (subobject) can be raised to the top. 🔝shuffle_obj_to_bottom(<obj_name>)— this command move<obj_name>to the bottom. If<obj_name>is a subobject, it is dropped to the bottom, relative to its siblings. This command is useful in animation where a selected frame (subobject) can be dropped to the bottom. 🔽disable_undo()— this command cleans up the undo/redo records and disable undo (and stop recording undo/redo information). The original history depth is saved away. This command should be used before a long animation sequence. 🚫↩️enable_undo()— this command restores the history depth saved away by thedisable_undo()command and enables undo/redo. This command should be eventually used afterdisable_undo()is called. ✅↩️get_drawing_area(<ltx_attr>,<lty_attr>,<rbx_attr>,<rby_attr>)— this command stores the absolute coordinate of the current drawing area in the specified attributes.<ltx_attr>stores the left-top X coordinate,<lty_attr>stores the left-top Y coordinate,<rbx_attr>stores the right-bottom X coordinate, and<rby_attr>stores the right-bottom Y coordinate. 📍get_selected_obj_bbox(<ltx_attr>,<lty_attr>,<rbx_attr>,<rby_attr>)— this command stores the absolute coordinate of the bounding box of the selected object in the specified attributes.<ltx_attr>stores the left-top X coordinate,<lty_attr>stores the left-top Y coordinate,<rbx_attr>stores the right-bottom X coordinate, and<rby_attr>stores the right-bottom Y coordinate. The bounding box is computed assuming that all lines are of width0. 📦get_named_obj_bbox(<obj_name>,<ltx_attr>,<lty_attr>,<rbx_attr>,<rby_attr>)— this command stores the absolute coordinate of the bounding box of the object named<obj_name>in the specified attributes.<ltx_attr>stores the left-top X coordinate,<lty_attr>stores the left-top Y coordinate,<rbx_attr>stores the right-bottom X coordinate, and<rby_attr>stores the right-bottom Y coordinate. The bounding box is computed assuming that all lines are of width0. 📦move_selected_obj_absolute(<ltx>,<lty>)— this command moves left-top corner of the selected object to (<ltx>,<lty>). 🚚assign(<attr_name>,<expr>)— this command assigns<expr>to the attribute specified by<attr_name>.<expr>must be evaluated to a numeric value. 📝strcpy(<attr_name>,<string>)— this command copies<string>into the attribute specified by<attr_name>. 📋copy_string_to_cut_buffer(<string>)— drops <string> straight into the cut buffer. Copy-paste but make it ✨programmatic✨ 💖strcat(<attr_name>,<string>)— glues <string> onto the end of whatever's already chilling in the attribute <attr_name>. It's giving "and one more thing…" 🎀while(<expr>,<cmd_attr_name>)— keeps running the internal command sitting in <cmd_attr_name> over and over until <expr> evaluates to0. Loop era, no cap 🔁if(<expr>,<then_cmd_attr_name>,<else_cmd_attr_name>)— vibe check on <expr>: if it evaluates to0, the internal command in <else_cmd_attr_name> runs; otherwise the one in <then_cmd_attr_name> runs. Both <then_cmd_attr_name> and <else_cmd_attr_name> can be the stringNULL(case-sensitive, bestie!!) and then like… nothing happens for that branch. It's giving "choose your own adventure" 🦋get_current_file(<attr_name>)— stores the full path name of the current file in <attr_name>.get_current_export_file(<attr_name>)— stores the full path name of the output (print/export) file in <attr_name>. Yes it's different from the one above, they're siblings not twins 💅get_current_dir(<attr_name>)— stores the current directory in <attr_name>. Where am I? Now you know 📍getenv(<attr_name>,<env_var_name>)— grabs the environment variable named <env_var_name> and stores it in <attr_name>. Environment variables are lowkey main character energy 🌈strlen(<attr_name>,<string>)— counts the characters in <string> and assigns that number to <attr_name>. Math but make it strings 🔢substr(<attr_name>,<string>,<start_index>,<length>)— copies <length> characters out of <string>, starting at character index <start_index>, into <attr_name>. Heads up bestie: <start_index> is zero-based ⭐strstr(<attr_name>,<string>,<sub_string>)— finds the first occurrence of <sub_string> inside <string>, then copies <sub_string> plus the rest of the string into <attr_name>. Everything from the match onward, periodt ✨strrstr(<attr_name>,<string>,<sub_string>)— same energy, but finds the last occurrence of <sub_string> in <string> and copies <sub_string> plus the rest of the string into <attr_name>. Reverse search slay 🎀unmake_selected_obj_iconic()— does exactly what pickingUnMakeIconic()from the Special Menu does, except at least one object must already be selected. No selection, no service 🫶hyperjump_then_exec(<attr_name>,<attr_name_to_exec>)— teleports to the file name or URL name found in the <attr_name> attribute, then runs the internal command specified by the <attr_name_to_exec> attribute in the new file. Warp there, then do the thing 🚀show_attr(<attr_name>)— makes the <attr_name> attribute visible. Come out come out wherever you are 👀hide_attr(<attr_name>)— makes the <attr_name> attribute invisible. Ghost mode 💀show_attr_name(<attr_name>)— makes the name part of the <attr_name> attribute visible.hide_attr_name(<attr_name>)— makes the name part of the <attr_name> attribute invisible. Just the name dips out, the rest stays 🙈show_value(<attr_value>)— makes the attribute whose name is empty and whose value is <attr_value> visible.hide_value(<attr_value>)— makes the attribute whose name is empty and whose value is <attr_value> invisible.get_attr_bbox(<ltx_attr>,<lty_attr>,<rbx_attr>,<rby_attr>,<attr_name>)— stores the absolute coordinate of the bounding box of the <attr_name> attribute into the attributes you named. Break it down: <ltx_attr> gets the left-top X coordinate, <lty_attr> gets the left-top Y coordinate, <rbx_attr> gets the right-bottom X coordinate, and <rby_attr> gets the right-bottom Y coordinate. And the plot twist 🫢 — the bounding box is computed assuming that all lines are of width0.size_selected_obj_absolute(<abs_w>,<abs_h>)— stretches the right-bottom corner of the selected object so its width becomes <abs_w> and its height becomes <abs_h>. Glow-up, but measured 📐size_named_obj_absolute(<obj_name>,<abs_w>,<abs_h>)— same stretch, but you pick the victim by name: the right-bottom corner of the object named <obj_name> moves so the width becomes <abs_w> and the height becomes <abs_h>.message_box(<attr_name>,<msg>,<title>,<style>)— pops a messagebox with <title> as the title and <msg> as the message. <style> can be the string"info","ync","yn", or"stop". Which buttons you get depends on the style: an OK button for"info"or"stop", YES/NO/CANCEL buttons for"ync", and YES/NO buttons for"yn". When the user clicks a button, the name of that button lands in <attr_name>. If they cancel the messagebox by hitting the<ESC>key, <attr_name> gets set to the string"CANCEL". If <attr_name> is the stringNULL(case-sensitive, don't forget!!), then the info about which button got clicked isn't written anywhere at all — it just floats off into the void 💀. And if <title> is the stringNULL, thenTgifbecomes the title of the messagebox. Queen of defaults 👑get_user_input(<attr_name>,<msg1>,<msg2>)— shows a dialogbox with <msg1> on the first line and <msg2> on the second line. Plot twist: if <msg2> is the string"USE_CURRENT_DIR", the second line shows the current directory instead. The user types a line into the dialogbox and it gets placed in <attr_name>. If they cancel by typing the<ESC>key, <attr_name> gets set to the empty string. Ask and you shall receive, bestie 💌add_attr_to_selected_obj(<attr_name>,<attr_value>,<abs_x>,<abs_y>)— adds <attr_name>=<attr_value> to a selected object and places the attribute at (<abs_x>,<abs_y>). If <attr_name> is the stringNULL(case-sensitive), the attribute's name becomes the empty string. If <abs_x> and <abs_y> are bothNULL(case-sensitive), the attribute gets placed below the lower left corner of the object. And if <attr_name> starts with"!.", a file attribute gets added. Three secret modes, iykyk 🔥delete_attr_from_selected_obj(<attr_name>)— deletes the attribute named <attr_name> from a selected object. And if <attr_name> starts with"!.", it's a file attribute that gets deleted. Blocked and deleted 🚫user_end_an_edge(<attr_name>,<abs_x>,<abs_y>)— starts a polyline/open-spline at (<abs_x>,<abs_y>), flips the drawing mode over to draw polyline/open-spline, and lets the user finish the polyline/open-spline themselves. Cute lil detail: if the endpoint falls inside an object that has an attributetype=port, that object's name gets placed in <attr_name> — but only if <attr_name> is not the stringNULL(case-sensitive) 🎯user_draw_an_edge(<start_attr_name>,<end_attr_name>)— switches the drawing mode to draw polyline/open-spline and lets the user draw one. If the first endpoint falls in an object with an attributetype=port, that object's name goes in <start_attr_name>, provided <end_attr_name> is not the stringNULL(case-sensitive). If the last endpoint falls in an object with an attributetype=port, that object's name goes in <end_attr_name>, provided <attr_name> is not the stringNULL(case-sensitive). Yeah, the original says <attr_name> there — we keep the lore exactly as written, no editing the source, periodt 📝get_a_poly_vertex_absolute(<x_attr_name>,<y_attr_name>,<obj_name>,<index>)— stores the absolute coordinate of the <index>th vertex of <obj_name> into the attributes named by <x_attr_name> and <y_attr_name>. Requirement check 🫶: the object named by <obj_name> must be either a poly/open-spline or a polygon/closed-spline object. Anything else, no coordinates for you.move_a_poly_vertex_absolute(<obj_name>,<index>,<abs_x>,<abs_y>)— moves the <index>th vertex of <obj_name> to the absolute coordinate (<abs_x>,<abs_y>). Same rule applies: the object named by <obj_name> must be either a poly/open-spline or a polygon/closed-spline object ✨post_attr_and_get_cgi_result(<url_attr>,<query_attr>,<result_attr>)— makes an HTTP request using the POST method. <url_attr> names the attribute containing the URL (which usually names a CGI server script), <query_attr> names the attribute whose value is the data to be posted, and <result_attr> names the attribute that receives the results. For example, if an object has the following attributes:
url=http://bourbon.usc.edu:8001/cgi-bin/echo-post
query=Hello World!
result=
exec=post_attr_and_get_cgi_result(url,query,result)
executing this object will post "Hello World!" to the specified CGI script. In this case, the result of executing the script just echoes "Hello World!" right back (along with some other bookkeeping information). Round trip networking, we love to see it 🌐
navigate_back()— performs the same operation as ifNavigateBack()were selected from the Navigate Menu. Take me back 🌀stop()— stops the execution of all internal commands. Emergency brake, everybody out 🛑sqrt(<attr_name>,<expr>)— assigns the square-root of <expr> to <attr_name>. Heads up: <expr> must evaluate to a non-negative numeric value. No imaginary numbers in this house, we don't do that here 🍓random(<attr_name>)— assigns a random integer to <attr_name> using the C library functionrand(). And0is used as the seed for the random number generator. Deterministic chaos, iconic 💅srand48(<use_cur_time_as_seed>)— seeds the random generator used by the C library functiondrand48(). If <use_cur_time_as_seed> is0, then0is used as the seed. Otherwise, the current time is used as the seed. Clock in, randomness out ⏰drand48(<attr_name>)— assigns a floating pointer number between0.0and1.0to <attr_name> using the C library functiondrand48(). (Yes, the page really says "floating pointer number" — we don't fix, we preserve 🫶)round(<attr_name>,<expr>)— assigns the round of <expr> to <attr_name>. Math girlies rise 🔢redraw_obj(<obj_name>)— redraws the area occupied by <obj_name>. A lil refresh for one spot ✨redraw_drawing_area()— redraws the whole drawing area (the part visible through the Canvas Window). Full glow-up, top to bottom 🎀itox(<attr_name>,<digits>,<expr>)— assigns <attr_name> to be the hex value of <expr>. <digits> — which must be between1and8, inclusive — is the final width of the hex value, and zeroes get added on the left to pad it out. Hex girl summer 🧚for_i(<attr_name>,<min_val>,<max_val>,<increment>,<cmd_attr_name>)— this command is the same as the following sequence of commands:
assign(<attr_name>,<min_val>);
while($(<attr_name>) <= <max_val>,loop)
where loop has the following value:
exec(<cmd_attr_name>);
inc(<attr_name>,<increment>)
And a very important note, bestie: <min_val>, <max_val>, and <increment> are only evaluated once, prior to the execution of this command. One and done, no re-evaluating mid-loop 💖
set_file_not_modified()
bestie. she's chill. this one flips the file-modified flag to false — so tgif stops acting like you've got unsaved chaos going on. 🎀
new_id(<attr_name>)
makes a brand-new object ID that's unique in the current drawing and tucks it into <attr_name>. one of a kind, like you 💅
rotate_selected_obj(<angle>)
rotates the selected object by <angle> degrees. and listen — positive angle is clockwise. yes, clockwise. not counterclockwise. do not come for me, that's just what it says 🙈
call_simple_shortcut(<shortcut_name>)
calls a shortcut named <shortcut_name> that takes zero arguments. want the whole lore on shortcuts? go read the SHORTCUTS section, iykyk ✨
call_one_arg_shortcut(<shortcut_name>,<arg>)
same energy, but this one calls a shortcut named <shortcut_name> that takes one argument, and it passes <arg> straight to it. again: SHORTCUTS section for the full breakdown 💖
substitute_attr(<attr_name>,<src_attr_name>,<replace_attr_name>,<pattern_str>)
okay so she's a find-and-replace girlie. she takes every occurrence of <pattern_str> inside the value part of the attribute named <src_attr_name>, swaps it out for the value of the attribute named <replace_attr_name>, and writes the whole result into the attribute named <attr_name>. glow-up via substitution, iconic 🔥
get_file_size(<attr_name>,<file_name>)
drops the size of the file <file_name> into the attribute <attr_name>. 📏
is_file(<attr_name>,<file_name>)
puts a "1" into <attr_name> if the file <file_name> exists. if it doesn't? puts a "0". she's a yes/no queen, no nuance, we love her 🫶
index(<attr_name>,<string>,<sub_string>)
finds the first occurrence of <sub_string> inside <string> and copies the zero-based index into <attr_name>. first come first served ⭐
rindex(<attr_name>,<string>,<sub_string>)
same but backwards-coded: finds the last occurrence of <sub_string> inside <string> and copies the zero-based index into <attr_name>. she's the r to index's i 🦋
get_number_of_lines_in_attr(<result_attr>,<attr_name>)
counts how many lines live in the attribute <attr_name> and writes that count into <result_attr>. line census, very demure 🎀
get_line_in_attr(<result_attr>,<attr_name>,<line_number>)
copies the nth line of the attribute <attr_name> into <result_attr> — where n is a zero-based index that you hand over via <line_number>. zero-based!! don't forget!! 😭
trim(<attr_name>)
removes the leading and trailing blank characters from the attribute <attr_name>. she's tidying up, no crumbs left 💅
is_attr(<result_attr>,<attr_name>)
writes a "1" into <result_attr> if the attribute named <attr_name> exists. otherwise it writes a "0". existence check, main character energy 👑
find_obj_names(<result_attr>,<obj_name>,<attr_name_value>)
this one hunts down all the objects that are direct sub-objects of the object named <obj_name> and writes their names into <result_attr>. and if <obj_name> is an empty string? then every top-level object gets scanned. periodt.
now the filter part, because <attr_name_value> is doing a lot of work here:
- if <attr_name_value> is the empty string, all qualifying objects are selected. no filter, everyone's invited 🌈
- if <attr_name_value> looks like
"<string>=*", an object is selected if it has an attribute named <string>. that's it, just has to exist. - if <attr_name_value> looks like
"<string>=<value>", an object is selected if it has an attribute named <string> and its corresponding value is <value>. both boxes checked ✨ - if <attr_name_value> doesn't contain the
'='character at all, an object is selected if it has an attribute whose name is empty and whose corresponding value is identical to <attr_name_value>. sneaky little case, love that for us 🙈
and the shape of the result: if n objects get matched, the attribute <result_attr> is updated with n+1 lines. line zero's value becomes n, and the object names become lines 1 through n of <result_attr>. use the get_line_in_attr() internal command to pull those names back out. yes, the zeroth line is the count. yes, it's a little feral. it's fine 💖
find_obj_names_on_all_pages(<result_attr>,<attr_name_value>)
basically find_obj_names() above, but she's got range — she finds only top-level objects on all pages. result goes into <result_attr>. for a multi-page file, a top-level object name <name> gets written into <result_attr> as ##<page_num>!<name>. and for a single-page file? she behaves exactly the same as find_obj_names(<result_attr,"",<attr_name_value>). exact same, no cap.
tg2_find_obj_names_on_all_pages(<result_attr>,<attr_name_value>)
identical to find_obj_names_on_all_pages() above, with one lil twist: for a multi-page file, a top-level object name <name> gets written into <result_attr> as <name>_Page<page_num> instead. tg2 naming convention, she's got her own aesthetic 🎀
tokenize(<result_attr>,<string>,<separator>)
breaks <string> into tokens separated by the <separator> character, then writes those tokens into <result_attr> — in the same fashion as the find_obj_names() internal command above. (so yes: count first, tokens after 💅)
rules for <separator>, and she's strict:
- it must be a string of length 1
- it must not be the space character
- it must not be the single-quote character
- it must not be the double-quote character
and if a token contains the separator character, you can wrap that token in a pair of single-quotes or double-quotes — those quotes get automatically removed when the command runs. very thoughtful, very cutesy 🫶
now the result shape, same as before: if n tokens are found, <result_attr> gets n+1 lines. line zero becomes n, and the tokens become lines 1 through n. get_line_in_attr() is your girl for retrieving them. ⭐
move_attr_relative(<attr_name>,<dx>,<dy>)
moves the attribute named <attr_name> by <dx> absolute units in the x direction, and <dy> absolute units in the y direction. shifting, sliding, thriving 🦋
get_number_of_vertices(<result_attr>,<obj_name>)
copies the number of vertices of the object <obj_name> into <result_attr>. but heads up bestie: the specified object must be a polyline (open-spline) or a polygon (closed-spline). anything else? not it. 🚫
is_obj_transformed(<result_attr>,<obj_name>)
writes a "1" into <result_attr> if the object <obj_name> is transformed — that means rotated or sheared. otherwise it writes a "0". she knows when you've been messing with the geometry 👀
make_selected_obj_iconic(<sym_path>)
works just like the MakeIconic() command from the Special Menu, except — and this is the glow-up — the user is not prompted for the name of the icon. instead, <sym_path> is used to specify the full path name of the icon. no popup, no interruption, we just go ✨
get_tgif_version(<major_attr,minor_attr,patchlevel_attr,build_attr>)
writes tgif's major version number, minor version number, patchlevel, and build information into <major_attr>, <minor_attr>, <patchlevel_attr> and <build_attr>, respectively. and if any argument is the string NULL — that's case-sensitive, careful — then that piece of info just gets skipped. ✨
get_tgif_dir(<result_attr>)
writes "$HOME/.Tgif" into <result_attr>, where $HOME is the home directory of the user. that's the address, bestie 🏠
get_profile_string(<result_attr>,<section>,<key>,<def_value>,<ini_path>)
gets the value associated with the key <key>, from the section <section>, in the file at the full path <ini_path> — and stores it into the attribute <result_attr>.
the edge cases, because there are several and they're all valid:
- if there's no value associated with the specified key, <def_value> gets stored into <result_attr> instead. a fallback, a safety net, we stan 💖
- if <key> is an empty string, then all the key names in <section> of <ini_path> get written into <result_attr> — same fashion as the
find_obj_names()internal command above. so: count, then names 📋 - if <section> is an empty string, then all the section names in <ini_path> get written into <result_attr> — again, same fashion as
find_obj_names()above. 🗂️
write_profile_string(<section>,<key>,<value>,<ini_path>)
sets the value associated with the key <key>, of the section <section>, in the file at the full path <ini_path>, to be <value>. writing, not reading, we're being productive today 💅
and two things to clock:
- if <key> is an empty string, all key/value pairs in <section> of <ini_path> get cleared. poof. gone. 🫧
- <section> should not be an empty string. just don't. 🙈
select_additional_obj(<obj_name>)
silently — and by silently i mean no highlighting handles — selects an additional object named <obj_name>. for the spec on what object names even look like, see the OBJECT NAMES section above. sneaky selection, no drama 🦋
open_file(<file_number>,<file_name>,<file_mode>)
opens the file <file_name> in the mode <file_mode>, and assigns that opened file a file reference number of <file_number>.
the deets:
- <file_number> must be 0 or between 3 and 15. that's the range, respect it.
- opening file 0 rewinds the standard input. yes, rewinds. ⏪
- modes? examples include
"r"for reading,"w"for writing, and"a"for appending. - and a file is always opened in text (non-binary) mode. always. non-negotiable. 💀
close_file(<file_number>)
closes the file associated with file reference number <file_number>. and <file_number> must be 0 or between 3 and 15. same range, same rules. bye bestie 👋
read_file(<file_number>,<result_attr>)
reads a line from the file associated with file reference number <file_number> and puts that line into the attribute <result_attr>.
and <file_number> must be between 0 (for standard input) or between 3 and 15. (yes, that's how it's worded, and yes, i'm passing it along exactly.) 📖
write_file(<file_number>,<string>)
writes <string> to the file associated with file reference number <file_number>. <file_number> must be between 1 and 15 — note the different range than reading, bestie, this one starts at 1! — and numbers 1 and 2 are for the standard output and standard error files. ✍️
flush_file(<file_number>)
flushes the file associated with file reference number <file_number>. <file_number> must be between 1 and 15, and numbers 1 and 2 are for the standard output and standard error files. out with it, no holding back 🚽✨
append_file(<dest_file_name>,<src_file_name>)
appends the file <src_file_name> to the file <dest_file_name>. src into dest, back of the line, thank you 🎀
set_output_format(<format>,<color_output>)
sets the output format to <format>. and then:
- if <color_output> is 0, black and white output (printing) mode gets used.
- otherwise, color output (printing) mode gets used. 🌈
for the list of possible formats, go peek at the Tgif.WhereToPrint X default. that's where the menu lives, iykyk 💅
set_export_clip_rect(<ltx>,<lty>,<rbx>,<rby>)
Sets the export clipping rectangle, bestie 💅 it's a rectangular region with the left-top corner at (<ltx>,<lty>) and the right-bottom corner at (<rbx>,<rby>). Hard rule tho: <ltx> has to be strictly less than <rbx>, and <lty> has to be strictly less than <rby>. No degenerate rectangles, periodt.
import_file(<file_name>,<format>,<ltx>,<lty>)
Imports the file at <file_name> and drops it at (<ltx>,<lty>) ✨. The file is expected to be in the format <format>, which can be "XBM", "XPM", "GIF", "PNG", "JPEG", "PBM", "PGM", "PPM", plus whatever names are specified by the Tgif.ImportFilter# X defaults. And if <format> is "TGIF", the file should either be a tgif file. (That's the page's wording, iykyk 🙈)
set_xpm_output_version(<version_number>)
Sets the XPM version number used when outputting in the X11 pixmap format to <version_number> 🎀. <version_number> can take on the values 1 or 3.
edit_ini_section(<attr_name>,<title>,<section>,<ini_path>)
Pops up a dialogbox to edit the section <section> in the file given by the full path <ini_path> 🫶.
- Hit OK and the section gets cleared, the content of the dialogbox gets written back into the file, and
"OK"gets placed in the attribute<attr_name>. - Hit CANCEL and the file stays unmodified, and
"CANCEL"gets placed in the attribute<attr_name>.
select_from_ini_section(<attr_name>,<title>,<section>,<ini_path>)
Brings up a list so you can select an entry from the section <section> in the file at the full path <ini_path> 👑. If nothing is selected, the attribute <attr_name> gets cleared. Otherwise the selected entry gets written into the attribute <attr_name>. Main character behavior fr fr.
append_line_into_attr(<attr_name>,<string>)
Appends the line <string> to the attribute <attr_name> 🌸.
insert_line_into_attr(<attr_name>,<string>,<line_number>)
Inserts the line <string> as the nth line of the attribute <attr_name>, where n is a zero-based index specified by <line_number> ✨. And n must be at least 1. If n is larger than the number of lines in the attribute, blank lines get automatically inserted. Yes bestie, it literally says zero-based and that n must be at least 1 — that's what the page says, don't @ me 💀.
clear_attr(<attr_name>)
Clears the attribute value of the attribute <attr_name> and deletes all the other lines of the attribute if it contains multiple lines 🧹. Full reset energy.
create_text_obj(<abs_x>,<abs_baseline_y>,<string>)
Creates a text object at the location (<abs_x>,<abs_baseline_y>) with the text <string> 💖.
create_box_obj(<abs_ltx>,<abs_lty>,<abs_rbx>,<abs_rby>)
Creates a rectangle defined by (<abs_ltx>,<abs_lty>) and (<abs_rbx>,<abs_rby>) 🎀.
create_corner_oval_obj(<abs_ltx>,<abs_lty>,<abs_rbx>,<abs_rby>)
Creates a corner oval defined by (<abs_ltx>,<abs_lty>) and (<abs_rbx>,<abs_rby>) 🦋.
create_center_oval_obj(<abs_x>,<abs_y>,<radius>)
Creates a center oval centered at (<abs_x>,<abs_y>) with the radius <radius> 💅.
create_edge_oval_obj(<abs_ltx>,<abs_lty>,<abs_rbx>,<abs_rby>)
Creates an edge circle defined by (<abs_ltx>,<abs_lty>) and (<abs_rbx>,<abs_rby>) ⭐.
create_rcbox_obj(<abs_ltx>,<abs_lty>,<abs_rbx>,<abs_rby>)
Creates a rounded-corner rectangle defined by (<abs_ltx>,<abs_lty>) and (<abs_rbx>,<abs_rby>) 🌈. Soft edges, soft life.
create_arc_obj(<abs_x>,<abs_y>,<radius>,<dir>,<angle1>,<angle2>)
Creates an arc centered at (<abs_x>,<abs_y>) with radius, direction, start angle and end angle given by <radius>, <dir>, <angle1> and <angle2> respectively 🌀.
The <radius>, <dir>, <angle1> and <angle2> are specified in the exact same way as they are specified in the SpecifyAnArc() command under the CreateObject submenu of the Edit Menu. <dir> can be "+" or "-", where "+" is clockwise. <angle1> and <angle2> are in degrees, with 0 degree at the 12 o'clock position 🕛.
create_first_vertex(<abs_x>,<abs_y>)
This one is used in conjunction with the create_next_vertex() and create_poly_obj() commands to create a polyline/open-spline object ✏️. It can also be used in conjunction with the create_next_vertex() and create_polygon_obj() commands to create a polygon/closed-spline object. It sets the starting point of the polyline/open-spline object or the polygon/closed-spline object to be at (<abs_x>,<abs_y>) 🫶.
create_next_vertex(<abs_x>,<abs_y>)
Used in conjunction with the create_first_vertex() and create_poly_obj() commands to create a polyline/open-spline object 💜. It can also be used in conjunction with the create_first_vertex() and create_polygon_obj() commands to create a polygon/closed-spline object. It sets the next vertex of the polyline/open-spline object or the polygon/closed-spline object to be at (<abs_x>,<abs_y>) ✨.
create_poly_obj()
Used in conjunction with the create_first_vertex() and create_next_vertex() commands to create a polyline/open-spline object 🌸.
create_polygon_obj()
Used in conjunction with the create_first_vertex() and create_next_vertex() commands to create a polygon/closed-spline object 💖.
start_create_group_obj()
Used in conjunction with the create_group_obj() command to create a grouped object 👯. This command marks the beginning of the group.
create_group_obj()
Used in conjunction with the start_create_group_obj() command to create a grouped object 👯. This command groups all objects created since the last start_create_group_obj() call into a grouped object. Iconic, honestly.
set_allow_interrupt(<true_or_false>)
If <true_or_false> is FALSE (case-sensitive, bestie 👀), this command is used to temporarily disable a user interrupt while tgif is executing internal commands. If a user interrupt is received while interrupt is disabled, it will be queued, and it will interrupt the execution of internal commands when set_allow_interrupt() is called again with <true_or_false> being TRUE (also case-sensitive) ⏳.
select_each_obj_and_exec(<attr_name_to_exec>)
First it unselects any object that's selected 🙅. Then it selects each object in the current drawing, one at a time, and executes the internal command specified by the <attr_name_to_exec> attribute 🔥.
- If this command is executed as a result of a mouse click over an object, only objects in the current page will be scanned for execution.
- If this command is executed from a script file, objects in every page will be scanned for execution.
edit_attr_in_text_mode(<attr_name>)
When you run this, tgif enters the text drawing mode and edits the attribute <attr_name> ✍️.
set_file_unsavable()
Makes the current file unsavable 🙈. That's it. That's the whole job.
pstoepsi(<target_eps_path>,<src_ps_path>,<scale>)
Generates a preview bitmap for the PostScript file in <src_ps_path> and prepends it to <src_ps_path>, saving the output in <target_eps_path> — and note that <src_ps_path> is unmodified 🎀. The only accepted values of <scale> are 1 or 2.
If the Tgif.ExternalPsToEpsi X default is set to true, this command will simply invoke this externally:
pstoepsi <src_ps_path> <target_eps_path>
when <scale> is 1, and:
pstoepsi -2x <src_ps_path> <target_eps_path>
when <scale> is 2 💅.
Heads up bestie: this command only works if tgif is running in the interactive (non-batch) mode 🫶.
objs_bbox_intersect(<obj1_name>,<obj2_name>,<result_attr>)
Sets the value of the attribute <result_attr> to "1" if the boundingboxes of the objects named <obj1_name> and <obj2_name> intersect 🦋. Otherwise it sets the value of the attribute <result_attr> to "0". Binary, no notes.
delete_all_attr_from_selected_objs()
Deletes all attributes from selected objects 💀.
Please only use this command when commands are taken from an external file! Like, seriously, that's a direct quote from the page, respect it 🙏.
random_permute_lines_in_attr(<attr_name>)
Randomly permutes the lines of the attribute <attr_name> 🎲. Chaos, but make it a command.
🔢 ARITHMETIC EXPRESSIONS ✨
Certain internal commands allow arithmetic expressions as arguments, and ngl that's kind of a serve 🧮. Infix notation is used. The supported operators (and their precedences) are listed below 👇.
?— precedence1— if-then-else, e.g.<rel> ? <iftrue> : <else>:— precedence2— if-then-else, e.g.<rel> ? <iftrue> : <else>||— precedence3— logical OR&&— precedence4— logical AND|— precedence5— bit-wise OR^— precedence5— bit-wise XOR&— precedence5— bit-wise AND==— precedence6— equal!=— precedence6— not-equal>— precedence7— greater than<— precedence7— less than>=— precedence7— greater than or equal to<=— precedence7— less than or equal to<<— precedence8— shift left>>— precedence8— shift right+— precedence9— add-— precedence9— subtract*— precedence10— multiple (that's the page's word for it, you know it means multiply bestie 💅)/— precedence10— divide//— precedence10— integer divide%— precedence10— mod!— precedence11— logical NOT~— precedence11— bit-wise invert/NOT)— precedence12— closed parenthesis(— precedence13— open parenthesis
Yes, the closed parenthesis is listed above the open parenthesis in precedence and the?and:are both split across two lines — that's exactly how the page has it, and I am simply reporting the lore 🫡
✨ GENERATING IMAGEMAP FILES ✨
okay bestie, this section is all about making NCSA imagemap and CERN clickable image files 🎀 and the way the Tgif.ImageMapFileFormat X default is literally the thing that decides which one you get. Since these two formats are like, basically twins, we're only gonna talk about how to make NCSA imagemap files here. Wanna know more about NCSA imagemap? Go peep [3] 👀. Wanna know more about CERN clickable image? That's [4] 🦋.
First things first, you gotta set the Tgif.GenerateImageMap X default to ``true'' to actually turn on imagemap generation. When you print in GIF format (go look at the BASIC FUNCTIONALITIES section about printing for that), an XPM file gets generated first — and yes, it gets removed at the end of this whole process. The value you set with the Tgif.InitExportPixelTrim X default is what trims off the extra pixels. Using these values is basically an escape mechanism to fix an idiosyncrasy where tgif can't figure out exactly how big the whole image is 😭.
The XPM version is specified by the Tgif.XPmOutputVersion X default — unless you set Tgif.UseXPmVersion1ForImageMap X default to ``true'', which then forces the XPM1 format. Then the command specified by the Tgif.XpmToGif X default gets executed to convert that XPM file into a GIF (Generic Interchange Format) file, which software like NCSA's Mosaic(1) can use 💅. The file extension for the GIF file is specified by the Tgif.GifFileExtension X default. And along with the GIF file, an imagemap file gets generated with the file extension specified by the Tgif.ImageMapFileExtension X default. Here's how the content of the imagemap gets made, step by step:
Tgif first goes looking for a file attribute with the attribute name href. The value of that attribute gets written as the default URL. If tgif can't find such a file attribute, then imagemap generation is aborted, periodt. If it does find it, then all objects in the file get scanned. For any object that has an attribute named href, the value of that attribute gets written as the URL for a method line in the imagemap. And if the object is neither a circle nor a poly/polygon, then the rectangle method is used 🫶.
There's a similar mechanism when you print in HTML format, except that a generic HTML file gets generated with an imagemap in the Spy Glass Client-side Imagemap format. You can generate a custom HTML file if you specify an HTML export template using SetHTMLExportTemplate() from the File Menu ✨. All the deets about the template file are down below.
🎀 HTML EXPORT TEMPLATE 🎀
If you specify an HTML export template file with the SetHTMLExportTemplate() from the File Menu, then custom HTML files can get generated when you print in HTML format. The customization happens through variables embedded in the HTML export template file. These variables have the syntax of an HTML character entity. They all start with &tgv and end with ;. Here they are, bestie:
&tgvfilename;— gets replaced by the name of the file (without file extension).&tgvcurnum;— gets replaced by the current page number.&tgvfirstnum;— gets replaced by the first page number (usually1).&tgvlastnum;— gets replaced by the last page number.&tgvprevnum;— gets replaced by the previous page number (with wrap around).&tgvprevnumnowrap;— gets replaced by the previous page number (with no wrap around).&tgvnextnum;— gets replaced by the next page number (with wrap around).&tgvnextnumnowrap;— gets replaced by the next page number (with no wrap around).&tgvtitle;— gets replaced by the title of the page or of the file.&tgvmapobjs;— gets replaced by the objects (specified as<AREA>tabs) in a client-side image map.
For example, if a template specifies:
<IMG SRC="&tgvfilename;-&tgvcurnum;.gif"
USEMAP="#p0">
<MAP NAME="p0">
&tgvmapobjs;
<AREA SHAPE="RECT"
COORDS="0,0,&tgvmapwidth;,&tgvmapheight;"
HREF="&tgvfilename;-&tgvnextnum;.html">
</MAP>
Then exporting using PrintOneFilePerPage() with this template may get (for page 2 of a file name foo.obj with 5 pages):
<IMG SRC="foo-2.gif"
USEMAP="#p0">
<MAP NAME="p0">
<AREA SHAPE="RECT" ...>
...
<AREA SHAPE="RECT" ...>
<AREA SHAPE="RECT"
COORDS="0,0,145,97"
HREF="foo-3.html">
</MAP>
💀 GENERATING MICROSOFT WINDOWS EPSI FILES 💀
So some Microsoft Windows (TM) applications genuinely do not understand the standard PostScript %%BeginPreview, %%EndImage, and %%EndPreview comments 🙈. This section is here to tell you how to generate an EPSI file that they do understand. This feature gets invoked when the current print format is TiffEPSI. In that case, the generated EPSI file will contain 30 bytes of binary information at the beginning of the file, plus a TIFF image (also binary) at the end of the file. This file also will not contain the %%BeginPreview, %%EndImage, and %%EndPreview comments. A file in this format is normally not even considered to be a PostScript file except under Windows, no cap.
When this feature is enabled, tgif generates a normal EPSI file first, then dumps the current content of the file into an X11 bitmap file. The command specified in Tgif.XbmToTiff gets executed to generate a TIFF image, which then gets appended at the end of the EPSI file 🔥.
🔒 LOCKING OBJECTS 🔒
Objects can be locked and unlocked using the #< and #> keyboard commands. When a selected object is locked, it's shown with gray handles. A locked object cannot be moved, stretched, flipped, or rotated — however, its properties like fill pattern, width, etc., can still be changed. Locked objects can also be deleted. When a locked object gets grouped with other objects, the resulting grouped object is also locked. A locked object can be used as an anchor to align other objects; however, the DistributeObjs() command will fail if any objects are locked. And locked objects do not participate in any operations in the select vertex mode, periodt 💅.
⏪ UNDO/REDO ⏩
Most operations can be undone and redone, thank god 😭. The Tgif.HistoryDepth X default controls the size of the undo buffer. If it's set to -1, then the undo buffer's size is infinite ✨. The undo buffer gets flushed when the New() or Open() commands are executed (from the File Menu), when the FlushUndoBuffer() command is executed from the Edit Menu, or when Pop() is executed from a .sym file. And if a private colormap is being used (which happens automatically when new colors can't be allocated from the default colormap), then executing FlushUndoBuffer() will attempt to reset the colormap — but only if the -DDONT_FREE_COLORMAP compile option is not used. iykyk 🧚.
🌈 DOMAINS 🌈
A domain is a collection of library symbols suitable for instantiations. A library is implemented as a directory of .sym files, and therefore, a domain is implemented as a search path. If there are symbols with the same file name sitting in different directories specified in the search path, then the one closer to the front of the search path gets made available for the user to instantiate 🫶.
The number of domains is specified by the MaxDomains X default, and the names of the domains are specified by the DomainPath# X default. The library search paths are specified by csh environment variables. Go look at the section on X DEFAULTS for more deets.
Domain information can also be loaded into the ~/.Tgif/domain.ini file by setting Tgif.DomainInIni to true and selecting Reload Domain Info From X from the Domain submenu of the File Menu ✨.
🖱️ SELECTING A NAME FROM A POPUP WINDOW 🖱️
When you're selecting a file name, a symbol name, or a domain name, tgif pops up a window with appropriate names for you to choose from. You can use mouse clicks to select an entry. Key strokes can also be used to specify the desired name; however, tgif attempts to match the key strokes with names in the selection on the fly. If a match can't be found, the key strokes are just ignored, no biggie.
Here's the whole key sitch, bestie:
^n,^j, or theDownArrowkey advances the selection down by1entry.^p,^k, or theUpArrowkey advances the selection up by1entry.^f,^d, or theDownArrowkey with<Control>key held down advances the selection down by10entries.^b,^u, or theUpArrowkey with<Control>key held down advances the selection up by10entries.'$'will select the last entry.'^'will select the first entry.^wor^yun-select the selected entry.
If the selected entry is a directory, hitting <CR> will change directory; if not, hitting <CR> finishes the selection process and the selected entry gets returned 💅.
When selecting file names to open or import, typing '/' is interpreted as going to the root directory or specifying an URL. At this point, the automatic matching of key strokes gets temporarily disabled until either a <TAB> or a <CR> is pressed. Also, clicking the middle mouse button in the file name area pastes from the clipboard 🎀.
The automatic appending of index.obj or .obj (introduced in version 2.16) became obsolete and an URL is never modified, fr fr.
The current selection is displayed near the top of the popup window. Back-space should be used with caution because it might change the current directory to the parent directory 👀.
📎 IMPORTING EPS FILES 📎
Encapsulated PostScript (EPS) files can be imported using the #( keyboard command. If the EPS file has a preview bitmap (which can be generated using the pstoepsi tool), tgif will display it — and HideBit/Pixmap() from the Layout Menu can be used to disable the displaying of bitmap/pixmaps if you're not about that life. When the EPS object gets saved in a .obj or .sym file, neither the preview bitmap, nor the PostScript content of the EPS file gets saved 😭. Therefore, when printing such a file (either from tgif or using prtgif), the EPS file must be present at the same place from which it was originally imported. Important, bestie, don't forget it 💖.
💖 ADDITIONAL FONTS 💖
Okay so out of the box you already get Times, Courier, Helvetica, NewCentury, and Symbol — the starter pack, no cap. But bestie, you can add more fonts using the Tgif.AdditionalFonts X default. (And yes, you can also replace the default screen fonts themselves — go peek at Tgif.HasAlternateDefaultFonts in the X DEFAULTS section for the full tea.)
Every additional font needs 4 parts, one for each font style, and the order is: Roman, Bold, Italic, and BoldItalic. Periodt. Each one of those parts holds 3 strings:
- The first string = the family, weight, slant, and width of the font (check the
xfontsel(1)man pages for the deets; there's also a second form which is described below 👀). - The second string = the registry and encoding of the font (see
xfontsel(1)again). You can usexlsfonts(1)to see what fonts are available and just pick those two strings out of the output. - The third string = the PostScript font name.
So like, if you wanna use the X Lucida font to represent the PostScript ZapfChancery-MediumItalic font, you'd set Tgif.AdditionalFonts like this:
Tgif.AdditionalFonts: \n\
lucida-medium-r-normal \n\
iso8859-1 \n\
ZapfChancery-MediumItalic \n\
\n\
lucida-demibold-r-normal \n\
iso8859-1 \n\
ZapfChancery-MediumItalic \n\
\n\
lucida-medium-i-normal \n\
iso8859-1 \n\
ZapfChancery-MediumItalic \n\
\n\
lucida-demibold-i-normal \n\
iso8859-1 \n\
ZapfChancery-MediumItalic
The above maps all four font styles of the Lucida font to the ZapfChancery-MediumItalic font (similar to how Symbol font is handled). She ate, fr fr. 🎀
The first string can also be specified in a second form, which you can spot because it has "%d" somewhere in the string. For example, you can use "lucidasans-%d" as the first string. In that case, the actual X font used will be the specified string with "%d" replaced by the font size. The encoding string (second string) is ignored (but it must be present). The font name prefix (see the Tgif.FontNamePrefix entry in the X DEFAULTS section) is also ignored. Sneaky but iconic. 💅
🔤 POSTSCRIPT CHARACTER ENCODING FOR INTERNATINOAL CHARACTERS 🔤
(yes that heading is spelled like that in the source and no I will not be fixing it 💀)
So sometimes you need different encodings of the same PostScript font for characters with character codes between 161 and 255 (inclusive). You can pull this off two ways:
- One way is to use
Tgif.AdditionalDontReencode(andTgif.DontReencode). - Another way is to use
Tgif.PSFontNeedCharSubs.
The difference? With Tgif.AdditionalDontReencode, a PostScript font's encoding is skipped. With Tgif.PSFontNeedCharSubs, characters in a PostScript font can be given specific encoding.
In both cases, there is a need to introduce fake font names (place holders). For example:
Tgif.AdditionalFonts: \n\
utopia-medium-r-normal \n\
adobe-fontspecific \n\
UtopiaTmp-Regular \n\
\n\
utopia-bold-r-normal \n\
adobe-fontspecific \n\
UtopiaTmp-Bold \n\
\n\
utopia-medium-i-normal \n\
adobe-fontspecific \n\
UtopiaTmp-Italic \n\
\n\
utopia-bold-i-normal \n\
adobe-fontspecific \n\
UtopiaTmp-BoldItalic
Tgif.PSFontAliases: \n\
UtopiaTmp-Regular=Utopia-Regular \n\
UtopiaTmp-Bold=Utopia-Bold \n\
UtopiaTmp-Italic=Utopia-Italic \n\
UtopiaTmp-BoldItalic=Utopia-BoldItalic
In the above example, 4 fake PostScript font names are created (and they all share a common "UtopiaTmp" prefix). The encoding for these fonts is adobe-fontspecific, according the X11 fonts being used. Tgif.PSFontAliases maps the fake PostScript font names to the corresponding real PostScript font names. (And if Tgif.PSFontAliases is missing? Non-existent PostScript font names such as UtopiaTmp-Regular will show up in a PostScript file. Not the vibe. 😭)
To skip a PostScript font's encoding, you can use the Tgif.AdditionalDontReencode X default. For example, if you specify:
Tgif.AdditionalDontReencode: UtopiaTmp
characters with character codes between 161 and 255 (inclusive) will not be encoded with ISO-Latin-1 character names. For a list of character names that are ISO-Latin-1 encoded, please see <URL:http://bourbon.usc.edu/tgif/faq/charencode.html#iso8859-1>.
To substitute characters in a PostScript font with specific encoding, you can use the Tgif.PSFontNeedCharSubs and Tgif.PSCharSubs_* X defaults. (You still need Tgif.AdditionalFonts and Tgif.PSFontAliases setup as above, don't skip that part bestie.) Here is an example:
Tgif.PSFontNeedCharSubs: \n\
Utopia-Regular=Foo \n\
Utopia-Bold=Foo \n\
Utopia-Italic=Foo \n\
Utopia-BoldItalic=Foo
Tgif.PSCharSubs_Foo: \n\
exclamdown/Aogonek \n\
AE/Cacute \n\
ecircumflex/eogonek
In the above example, Tgif.PSFontNeedCharSubs specified a list of fake PostScript font names that requires character substitutions and their corresponding TOKEN names. For a fake PostScript font name that maps to TOKEN, the list of characters to be substituted is specified in the Tgif.PSCharSubs_TOKEN X default. The format for Tgif.PSCharSubs_TOKEN is a list of OLDCHARCODE/NEWCHARNAME strings where OLDCHARCODE is a character code in decimal or octal format and NEWCHARNAME must be the name of a PostScript character. In the above example, Foo was used as the TOKEN name. In real use, something like iso8895-2 may be more appropriate for a TOKEN name. And since decimal or octal codes are allowed, the following is equivalent to the above:
Tgif.PSFontNeedCharSubs: \n\
Utopia-Regular=iso8859-2 \n\
Utopia-Bold=iso8859-2 \n\
Utopia-Italic=iso8859-2 \n\
Utopia-BoldItalic=iso8859-2
Tgif.PSCharSubs_iso8859-2: \n\
161/Aogonek \n\
8#306/Cacute \n\
8#312/eogonek
Please note that substitution only occurs for characters with character codes between 161 and 255 (inclusive). No exceptions, okay? 🫶
For more information, please see <URL:http://bourbon.usc.edu/tgif/faq/charencode.html#charsubs>.
🌸 SQUARE DOUBLE BYTE FONTS 🌸
Starting with version 4.0 of tgif, double-byte fonts are supported. But — and this is the catch — only double-fonts where every character has the same width and height are supported. Equality only, we don't do chaos here. ✨
Double-byte fonts is specified using the Tgif.SquareDoubleByteFonts X default. The format of this X default is similar to that of the Tgif.AdditionalFonts X default described in the ADDITIONAL FONTS section above, with the differences described here. Each double-byte font requires 4 parts, one for each font style (in the order of Roman, Bold, Italic, and BoldItalic). Each part contains 3 strings:
- The first string specifies the name of the font. It must contain a
"%d"as part of the string. The actual X font used will be the specified string with"%d"replaced by the font size. - The second string can be either
"*","H", or"V". When it is the"V"string, each character is rotated 90 degrees counter-clockwise. Otherwise, the characters are not rotated. - The third string specifies the PostScript font name.
Using input methods (specified by the Tgif.DoubleByteInputMethod X default) one can mix english (single-byte) substrings within a double-byte string. The font to use for the english substring is specified by the Tgif.DefaultSingleByteFont X default. Mixing it up, we love to see it. 🦋
For example, if you wanna use the X Song Ti font to represent PostScript GB-Song-Regular font, you can set Tgif.SquareDoubleByteFonts as follows:
Tgif.DefaultSingleByteFont: Helvetica
Tgif.GBShowFontChar: 271372 Tgif.GBConvFromUTF8: iconv -f utf8 -t gb2312
Tgif.GBUConvToUTF8: iconv -f gb2312 -t utf8
Tgif.SquareDoubleByteFonts: \n\
-isas-song ti-*-*-*--%d-*-*-*-*-*-gb2312.1980-0 \n\
* \n\
GB-Song-Regular \n\
\n\
-isas-song ti-*-*-*--%d-*-*-*-*-*-gb2312.1980-0 \n\
* \n\
GB-Song-Regular \n\
\n\
-isas-song ti-*-*-*--%d-*-*-*-*-*-gb2312.1980-0 \n\
* \n\
GB-Song-Regular \n\
\n\
-isas-song ti-*-*-*--%d-*-*-*-*-*-gb2312.1980-0 \n\
* \n\
GB-Song-Regular
In the above example, the Song Ti font doesn't have styles such as italic and bold, so all four parts are identical. (Copy-paste queen. 👑) The Tgif.GBShowFontChar X default specifies a double-byte octal character to be used to represent this font in the Choice Window when this font is selected. The Tgif.GBUConvFromUTF8 X default specifies a command to run when an UTF8-encoded string is to be pasted into a text object in the GB font. The Tgif.GBUConvToUTF8 X default specifies a command to run in a copy operation to convert a selected string (in GB font) to the UTF8 format then copied to the clipboard.
Below is another example of using the X JIS fonts to represent PostScript Ryumin-Light-EUC-H and Ryumin-Light-EUC-V fonts as follows:
Tgif.RyuminShowFontChar: 244242
Tgif.SquareDoubleByteFonts: \n\
-jis-fixed-*-*-*--%d-*-*-*-*-*-jisx0208.1983-* \n\
H \n\
Ryumin-Light-EUC-H \n\
-jis-fixed-*-*-*--%d-*-*-*-*-*-jisx0208.1983-* \n\
H \n\
Ryumin-Light-EUC-H \n\
-jis-fixed-*-*-*--%d-*-*-*-*-*-jisx0208.1983-* \n\
H \n\
Ryumin-Light-EUC-H \n\
-jis-fixed-*-*-*--%d-*-*-*-*-*-jisx0208.1983-* \n\
H \n\
Ryumin-Light-EUC-H \n\
\n\
-jis-fixed-*-*-*--%d-*-*-*-*-*-jisx0208.1983-* \n\
V \n\
Ryumin-Light-EUC-V \n\
-jis-fixed-*-*-*--%d-*-*-*-*-*-jisx0208.1983-* \n\
V \n\
Ryumin-Light-EUC-V \n\
-jis-fixed-*-*-*--%d-*-*-*-*-*-jisx0208.1983-* \n\
V \n\
Ryumin-Light-EUC-V \n\
-jis-fixed-*-*-*--%d-*-*-*-*-*-jisx0208.1983-* \n\
V \n\
Ryumin-Light-EUC-V
...and there's still more coming, bestie, don't go anywhere 💜
✨ MULTIPAGE DRAWING ✨
okay so bestie, one single object file can hold multiple pages. 💅 and there are two layout modes for that multipage glow-up: stacked and tiled.
- stacked — the pages are basically stacked on top of each other, so an object can only ever live on one page.
- tiled — the pages get tiled together to make one big logical page, and in this mode an object can exist on several physical pages at the same time. iconic behaviour honestly.
Switching between the two modes is considered a rare event and it can not be undone. 😭 Also, tgif will not let you switch from tiled layout mode back to stacked mode when there's an object that spans physical page boundaries, because it literally can not decide which physical page that object belongs to. it's giving "choose your fighter" and tgif refuses to choose.
Page numbers are supported through the use of page numbering objects. A page numbering object is an object that contains an attribute whose name is !PAGE_NUM (the name is case-sensitive) and the name part of that attribute is not shown — and yes, hiding an attribute name can be achieved by using the Move/JustifyAttr() command under the Attribute submenu of the Special Menu. 🫶
The value of the attribute decides how the page number gets printed:
- if the value contains a
!(STACKED_PAGE_NUM)substring, that part of the substring gets replaced by the page number if the page layout mode is stacked. If the page layout mode is tiled, the string just prints out as is. - if the value contains a
!(STACKED_NUM_PAGES)substring, that part gets replaced by the number of pages if the page layout mode is stacked. - if the value contains a
!(TILED_PAGE_ROW)or!(TILED_PAGE_COL)substring, that part gets replaced by the row number or the column number of the physical page if the page layout mode is tiled.
🎀 SPECIAL ATTRIBUTES 🎀
There are a few special attributes that tgif recognizes, and they're all described right here in this section. They are ALL case-sensitive. ⚠️
!PAGE_NUM=<page_number>— this specifies the page numbers in a multipage drawing. Please see the MULTIPAGE DRAWING section for the details, bestie. 💖auto_center_attr— if an attribute's name is empty and the value isauto_center_attr, then all the visible attributes of the owner object will automatically be centered relative to the bounding box of the owner object. ngl it doesn't really make sense to have multiple visible attributes here because they will just overlap. 🙈 This attribute is useful for making simple flowchart elements. 🌸unmakeiconic_on_instantiate— if a symbol object's attribute has an empty attribute name and the value isunmakeiconic_on_instantiate, then when the symbol is instantiated, the following commands are performed on the just-instantiated icon object:UnMakeIconic()command from the Special MenuUnGroup()command from the Arrange Menu- the
"unmakeiconic_on_instantiate"text object is removed
This attribute is useful for making simple flowchart segments. ✨
unmakeiconic_on_instantiate_delete_attrs— if a symbol object's attribute has an empty attribute name and the value isunmakeiconic_on_instantiate_delete_attrs, then when the symbol is instantiated, the following commands are performed on the just-instantiated icon object:UnMakeIconic()command from the Special Menu- delete all attributes from this object
UnGroup()command from the Arrange Menu
This attribute is useful for putting a group of "useful" objects into a symbol object. 💅
retracted_arrows— if an attribute's name is empty and the value isretracted_arrowsfor a polyline or open-spline object with more than 2 vertices, then the arrows of the spline object get retracted by one vertex. 🎯auto_retracted_arrows— this is very similar to theretracted_arrowsabove, except that the object must be an interpolated open-spline with only one arrow head. The spline object is forced to have 3 vertices and the middle vertex of the spline object is automatically adjusted when an endpoint is moved. lowkey magical. 🦋auto_exec=<internal_command>— if such a file attribute exists, the value is executed when the file is opened (unless the file is opened as a result of executing thehyperjump_then_exec()internal command). ⚡edit_attrs_in_context_menu=...— if an object has an attribute namededit_attrs_in_context_menu, the values (starting from the 2nd line and separated by linebreaks) of this attribute are treated as attribute names. The named attributes will be visible in the Edit Attribute In Editor submenu of the Context Menu. For example, if an object has the following attributes:
edit_attrs_in_context_menu=
x
y
z
w=greetings
x=hello
y=world
z=how are you
good-bye
the Edit Attribute In Editor submenu of the Context Menu will only show "x=hello", "y=world", and "z=how are you". see how w=greetings and good-bye got left out? yeah. the list said what it said. 👑
🌈 EXPORT TO TABLE 🌈
When the ExportToTable() command is selected from the Table submenu of the Special Menu, certain attributes of selected objects get written into a user-specified output file, in a format that can be easily imported by a spreadsheet program or used by the MergeWithTable() command described in the next section. 📊
An output file contains columns of strings. Two columns are separated by a single <TAB> character. The first row of an output file contains the column names and all other rows contain values. periodt.
The names of the attributes to be written are specified by the file attribute named TABLE_ATTRS (which is denoted by !.TABLE_ATTRS here). The value of the TABLE_ATTRS file attribute is a list of comma-separated attribute names. ✨
When the ExportToTable() command is executed:
- the attribute names specified by
!.TABLE_ATTRSare written to the output file first. - then, for each selected object, every one of its attributes which appears in the list specified by
!.TABLE_ATTRSare written to the output file in one line.
If an object has no attributes that match the specification, no corresponding line is generated. it just doesn't show up. simple as that. 💀
💜 MERGE WITH TABLE 💜
When the MergeWithTable() command is selected from the Table submenu of the Special Menu, a selected object gets merged (also known as mail-merged on PCs) with a table (data) file — in the same format as the output file described in the previous section — to generate a new multipage drawing having the stacked page layout mode. 🎉
The selected object contains formatting information, and it's also used as a template to be replicated for each data row in the table file. If an attribute of the replica matches the column name of the table, the attribute value is set to the value in the table file. The replicas are tiled horizontally first. 🫶
Eight attributes must be specified in the template object. They are all case-sensitive. The ones that measure distances can be specified in inches ("in"), centi-meters ("cm"), or pixels (if no units are specified). 📏
PAPER_WIDTH
This specifies the width of the paper.
PAPER_HEIGHT
This specifies the height of the paper.
LEFT_MARGIN
This specifies the distance to the left edge of the paper.
TOP_MARGIN
This specifies the distance to the top edge of the paper.
H_PITCH
This specifies the distance between the left edges of the replicas.
V_PITCH
This specifies the distance between the top edges of the replicas.
NUM_COLS
This specifies the number of replicas to tile horizontally before moving down to the next row.
NUM_ROWS
This specifies the number of replicas to tile vertically before moving to the next page.
After each replica is generated, filled with the data from the table file, and placed, its attribute named exec is executed (unless an attribute named EXEC_AFTER_MERGE is specified, in which case, the attribute named by the EXEC_AFTER_MERGE attribute is executed instead). If there is no attribute named by the EXEC_AFTER_MERGE attribute, nothing is executed. (Please see the INTERNAL COMMANDS section for details on command execution.) 🔥
One can use the exec command to construct other attributes from the attributes associated with the data table. the way that works is genuinely so satisfying ngl.
- If an attribute whose name is empty and whose value is the string
USER_PLACEMENT, the user will be asked to place the replica (object name will be displayed in the Status Window when the object is being placed). In this case, the 8 placement related attributes are ignored. 🙈 - If an attribute whose name is empty and whose value is the string
STRIP_DOUBLE_QUOTES, data fields surrounded by double-quotes are stripped. ✂️
✨ MIME TYPES AND MAILCAPS ✨
Okay so bestie, picture this: an URL points at an HTTP server, right? That server sends the Content-type of the URL over to tgif along with the remote file the URL is referencing. That Content-type has the whole type/subtype deal for the file plus some optional fields. And if that file is not a tgif file? Then this whole mechanism kicks in to show it to you. 🫶
First up: the X defaults get looked up to see if there's an external viewer set for that file. Go peek at Tgif.@@@Viewer in the X DEFAULTS section below for the deets. No match there? Then the type/subtype gets matched against the entries in the MIME-types file. The default MIME-types file is .mime.types in the user's home directory. (Wanna override that default? Check Tgif.MimeTypesFile in the X DEFAULTS section.) The first field on each line of the MIME-types file is the type/subtype info. And if there is a match in the MIME-types files, then the MailCap files get consulted, like this:
A line in a MailCap file is made of fields separated by semi-colons. Field one = the type/subtype, field two = a view command for viewing a file that matches that type/subtype. For tgif specifically, that view command must contain a single %s substring — that's the placeholder that gets swapped out for the local copy of the URL. Only the %t and %{} optional fields are supported by tgif, no cap. And the multipart MIME-type is not supported. 💀
So the type/subtype info of the remote file gets matched against the MailCap files. Match found? The corresponding view command runs. No match, but the type of the remote file is application, audio, image, or video? The file just gets saved and no external viewer launches. Otherwise? The remote file is assumed to be pure text and tgif will create a text object so you can look at the text. 💅
The MailCap files are the (colon-separated) files given by the MAILCAP environment variable (if it's defined, bestie). If MAILCAP isn't defined, then .mailcap in the user's home directory is what gets used.
And for the lore: MIME stands for Multipurpose Internet Mail Extensions, specified in RFC1521, and MAILCAP is specified in RFC1524. 📚
🧱 HOW TO MAKE A BUILDING-BLOCK OBJECT (SYMBOL FILE) 🧱
Here are the steps for defining a building-block object, for use in a hierarchical design. Main character energy, let's go:
- Draw the representation part of the building-block object. Group everything together. Select this grouped object.
- Popup the main menu with the middle mouse button; select
Special''. SelectMakeSymbolic'' from the next popup menu. The selected object becomes a symbol and gets a dashed boundary. ✨ - Type in attributes as individual text strings. Select the symbol object and all the text strings to be attached to the symbol. Type
#a(for Attach) to attach attributes to the symbol. - (This step is optional, no pressure.) Build the definition part of the building-block object. Look at the
flip-flop.sym'' file for an example. To look at that file, first, instantiate aflip-flop'' by typing^i(for Instantiate). Select the flip-flop from the popup window; place the flip-flop; select the flip-flop and type#v(for Push) to see the symbol file. - Save and name the file. If the current library path contains the current directory (or
.), the symbol you just built should be instantiatable by typing^i. Slay. 🎀
🖼️ X11 PIXMAP (XPM) FORMATS 🖼️
tgif can only import X11 pixmaps that satisfy the constraints described right here, okay? The format of the X11 pixmap must be either 1 (XPM1) or 3 (XPM3). And only a subset of the XPM3 format is supported, namely, the key field for the color specification must be c (for color visuals).
Tools that generate XPM1 format files (they might have been upgraded to support XPM3) are pbmplus (or netpbm), which is a set of bitmap and pixmap conversion freeware (together with xv, the colors for pixmap objects can be manipulated), and xgrabsc, another freeware; also, xloadimage can display XPM1 files. Tools that can generate XPM3 format files are, for example, xsnap(1) and sxpm(1). 👑
For each color specified in the color string, a color cell gets allocated. If the allocation fails, the current color will be used for that color string. And if the first color character is a back-quote (`) or a space, then the corresponding color is substituted with the background color of the tgif window if the Tgif.GuessXPmBgColor X default is set to true''. (This design choice is made because the pixmap will then look right'' on both regular and reverse video, iykyk.) 💅
The following is an example of a very small pixmap file (in XPM1 format):
#define arrow_format 1
#define arrow_width 5
#define arrow_height 3
#define arrow_ncolors 3
#define arrow_chars_per_pixel 1
static char *arrow_colors[] = {
"`", "Black",
"a", "red",
"b", "yellow"
};
static char *arrow_pixels[] = {
"`a```",
"aabbb",
"`a```"
};
📄 LATEX FIGURE FORMATS 📄
Here we show how to make a figure for a LaTeX file, first with the \psfig (or \epsf) special construct, then with the psfile special construct. (The author does not recommend the psfile construct, just so you know.) An example of both can be found in ``example.tex'' which is included with the tgif distribution.
To print a tgif file to be included in a LaTeX document with the \psfig or \epsf special construct (files generated will be in the Encapsulated PostScript format), first select LaTeX format in the panel window (click the left mouse button on the laser printer icon), then type ^p to generate the Encapsulated PostScript file. If the file name is an-sr-flip-flop.obj'', then the LaTeX figure file generated will be named an-sr-flip-flop.eps''. This file can be included in a LaTeX document like this:
\input{psfig}
\begin{figure*}[htb]
\centerline{\psfig{figure=an-sr-flip-flop.eps}}
\caption{An SR flip-flop. \label{fig:an-sr-flip-flop}}
\end{figure*}
An alternative way is to use the \epsf construct like this:
\input{epsf}
\begin{figure*}[htb]
\centerline{\epsffile{an-sr-flip-flop.eps}}
\caption{An SR flip-flop. \label{fig:an-sr-flip-flop}}
\end{figure*}
The \centerline command above centers the picture. And if you've got multiple tgif figures in your LaTeX document, you only have to include the psfig macro (\input{psfig} or \input{epsf}) once, right after the \begin{document} statement. Efficiency queen. ✨
Now, if Encapsulated PostScript is not available, the psfile special construct can be used as described here. In this case, since LaTeX doesn't not know where the bounding box of the drawing is, it takes some practice to get this just right. Here's something that seems to work. First, center the picture on the page (e.g., the width of a portrait style page is 8.5 inch, so the center of the page is at the 4.25 inch mark), and make the top object in the picture about 1/4 inch away from the top of the page. Select the LaTeX format in the panel window, then print in the LaTeX format. As with the psfig construct, a file with the .eps extension will be generated. This file can be included in a LaTeX document like this:
\begin{figure*}[htb]
\special{psfile="an-sr-flip-flop.eps" hoffset=-40}
\rule{0in}{1.1in}
\caption{An SR flip-flop. \label{fig:an-sr-flip-flop}}
\end{figure*}
The \rule{0in}{1.1in} above specifies an invisible box of 1.1 inches high, which is the total height of the picture in an-sr-flip-flop. 🌸
🔌 CONNECTING OBJECTS 🔌
okay bestie, picture this: in the world of E-CAD, an icon object can stand in for an electronic component, and a line object can stand in for a connection between a pair of pins of two electronic components. when a component moves, the endpoint of a wire connecting to that component moves right along with it. tgif simulates these functionalities — but like, in a limited fashion. it's giving "we have E-CAD at home" 💅 but honestly? still iconic.
In tgif, a connection is represented by matching signal names. A wire is defined as a polyline object having a type=tgWire attribute and an attribute named signal_name. The definition of a pin is more complicated — it's described in the next paragraph, buckle up 🎀. If two pins have identical values for the signal_name attribute, they are considered to be connected (and no, they do not have to be visually connected by a wire). the vibes are connected even when the pixels aren't ✨.
A pin object must have a type=port attribute and attributes named signal_name and name. But not all objects having such attributes are pins. On top of that, a pin object must be either:
- a top-level symbol or an icon object
or:
- an immediate subobject of a owner symbol or icon object. or:
- an immediate subobject of a owner grouped object which has a
type=tgBroadcastWireattribute.
In (2) above, the owner object must also have an attribute named name and must not be a subobject of another symbol or icon object. And if the owner object is a subobject of a grouped object, the name attributes of the grouped object will be ignored. sorry to that grouped object, it's not its moment 🙈.
In (3) above, that grouped object can be created using the ConnectPortsToBroadcastWire() command in the PortsAndSignals submenu of the Special Menu, when a polyline object and some floating port objects are selected.
A pin object can have a connected view and a disconnected view. A connected view is a subobject with a view=conn,FILL,PEN attribute, and a disconnected view is a subobject with a view=disconn,FILL,PEN attribute; FILL and PEN are numeric values between 0 and 31 (inclusive). That value corresponds to patterns in the Fill Menu and the Pen Menu. Normally, only 0 or 1 should be used 🫶.
When the signal_name attribute of a pin object is changed from an empty string to a non-empty string, the pen and fill of the subobject that corresponds to the disconnected view will be set to 0 (meaning NONE), and the pen and fill of the subobject that corresponds to the connected view will be set to the values specified in the view attribute of the connected view. When the signal_name attribute of a pin object is changed from a non-empty string to an empty string, the pen and fill of the subobject that corresponds to the connected view will be set to 0, and the pen and fill of the subobject that corresponds to the disconnected view will be set to the values specified in the view attribute of the disconnected view. it's a whole glow-up / glow-down situation and honestly? we love the drama 💖.
A connection can be created using the ConnectTwoPortsByAWire() command from the PortsAndSignals submenu of the Special Menu. Please note that if a pin is part of another object, that object must also have a name attribute with a non-empty value. When two pins are connected using this command, the signal_name attributes of the pins and the wire will be set to have the same value. matching! 👑
The moving of endpoints when a component moves is implemented in tgif using the constrained move mode from the MoveMode Menu (please see Tgif.ConstrainedMove in the X DEFAULTS section for additional information). But heads up bestie, this is the important part: a connected wire that is not visually connected will not automatically extend itself to follow a connected component, even in the constrained move mode 😭. Also, when a wire object is deleted, the signal_name attributes of connected pins do not change (since they are not really "connected"). ghosted, but make it circuit design 💀.
🎛️ X DEFAULTS 🎛️
okay so here's the whole menu of X defaults tgif will read, no cap. every single one, in order, with every default value exactly as it is:
Tgif.Geometry—WIDTHxHEIGHT+X+YTgif.IconGeometry—+X+YTgif.Foreground—COLORSTRING. The default foreground color isBlack.Tgif.Background—COLORSTRING. The default background color isWhite.Tgif.BorderColor—COLORSTRING. If not specified, the foreground color will be used.Tgif.ReverseVideo—[on,off]. For a black and white terminal, reverse video "on" means the background is black. For a color terminal, reverse video "on" means the background is specified by theTgif.Foregroundcolor. The default isoff.Tgif.InitialFont—[Times,Courier,Helvetica,NewCentury,Symbol]. This specifies the initial font. The default isCourier.Tgif.InitialFontStyle—[Roman,Bold,Italic,BoldItalic]. This specifies the initial font style. The default isRoman.Tgif.InitialFontJust—[Left,Center,Right]. This specifies the initial font justification. The default isLeft.Tgif.InitialFontDPI—[75,100]. Obsoleted. 💀Tgif.InitialFontSizeIndex—[0,1,2,3,4,5]. Obsoleted. 💀Tgif.InitialFontSize—NUMBER. This specifies the size of the start-up font. The default is 14. An alternative form allows"pt"to be specified immediately afterNUMBER(with no space between"pt"and theNUMBER).Tgif.MsgFontSizeIndex—[0,1,2,3,4,5]. Obsoleted. 💀Tgif.MsgFontSize—NUMBER. This specifies the size of the font used for messages, menues, and popup windows. The default is 14.Tgif.RulerFontSize—NUMBER. This specifies the size of the font used for ruler windows. The default is 10.Tgif.DefaultFontSize—NUMBER. This specifies the size of the font to be used when a requested for a font size can not satisfied. This size must exist for all fonts used in tgif. The default is 14.Tgif.FontSizes—NUMBER1 NUMBER2, .... This specified the font sizes. The default is8 10 11 12 14 17 18 20 24 25 34. An alternative form allows"pt"to be specified immediately after aNUMBER(with no space between"pt"the theNUMBER). Please also useTgif.InitialFontSizeto specify the initial font size to use if 14 is not in the specified font sizes.Tgif.AdditionalFonts—FONT_SPEC1 FONT_SPEC2 .... In addition to the Times, Courier, Helvetica, NewCentury, and Symbol fonts, additional fonts can be specified here. Please see the ADDITIONAL FONTS section for details.Tgif.FontNamePrefix—[-*, *]. This specified the prefix to be used when tgif makes a request to the X server. The default is-*. Certain fonts have obscure font names (e.g., does not start with the-character). In order to use these fonts, this X default can be set to*.Tgif.DefaultLatin1FontCharEncoding—STRING. Tgif uses 4 default fonts,"times","courier","helvetica", and"new century schoolbook". By default, the character encoding for these fonts isiso8859-1. These fonts are usually scalable and pre-installed in older Linux systems. In newer Linux system, this is no longer the case 😭. Only a small number of font sizes are pre-installed. The pre-installed scalable versions of these fonts areiso10646-1(Universal Character Set) encoded. This X default can be used to specify a different character encoding (such asiso10646-1) for the 4 default fonts. This X default does not apply to alternate default fonts or fonts specified by theTgif.AdditionalFontsX default. The default isiso8859-1.Tgif.HasAlternateDefaultFonts—[true,false]. The default value of this X default isfalse. If it is set tofalse, tgif uses theiso8859registry with ASN1 encoded screen fonts (unless it's overridden by theTgif.DefaultFontCharEncodingX default), and it looks for"times","courier","helvetica","new century schoolbook", and"symbol"as part of the screen font names. Some X servers do not support these fonts. In this case, this X default can be used to make tgif use user specified screen and PostScript fonts. If this X default is set totrue, tgif will look for additional X defaults of the formTgif.<ps_font_name>, where<ps_font_name>can be one of the following strings:
Times-Roman
Times-Bold
Times-Italic
Times-BoldItalic
Courier
Courier-Bold
Courier-Oblique
Courier-BoldOblique
Helvetica
Helvetica-Bold
Helvetica-Oblique
Helvetica-BoldOblique
NewCenturySchlbk-Roman
NewCenturySchlbk-Bold
NewCenturySchlbk-Italic
NewCenturySchlbk-BoldItalic
Symbol
The corresponding value of the X default must contain "%d" as part of the string, and the "%d" string will be replaced by the font size when the font is requested. For example, the following lines will use the Times New Roman screen font instead of the Times screen font and use the Bookman PostScript font instead of the Times PostScript font, if Tgif.HasAlternateDefaultFonts is true:
Tgif.Times-Roman: *-times new roman-medium-r-*--%d-*,Bookman-Light
Tgif.Times-Bold: *-times new roman-bold-r-*--%d-*,Bookman-Demi
Tgif.Times-Italic: *-times new roman-medium-i-*--%d-*,Bookman-LightItalic
Tgif.Times-BoldItalic: *-times new roman-bold-i-*--%d-*,Bookman-DemiItalic
Please note that certain X servers require the right-hand-side font specifications to have all the dashes in place. don't ask, just put the dashes in ✨
Tgif.DefaultCursor—[x_cursor,arrow,...]. This specifies the select cursor. Entries in<X11/cursorfont.h>(without theXC_prefix) are valid names of the cursor. The default isarrow.Tgif.DrawCursor—[x_cursor,arrow,...]. This specifies the cursor used when drawing objects. Entries in<X11/cursorfont.h>(without theXC_prefix) are valid names of the cursor. The default is the same asTgif.DefaultCursor.Tgif.DragCursor—[x_cursor,arrow,...]. This specifies the cursor used when dragging. Entries in<X11/cursorfont.h>(without theXC_prefix) are valid names of the cursor. The default ishand2.Tgif.VertexCursor—[x_cursor,arrow,...]. This specifies the cursor used in the select vertices mode. Entries in<X11/cursorfont.h>(without theXC_prefix) are valid names of the cursor. The default isplus.Tgif.FreeHandCursor—[x_cursor,arrow,...]. This specifies the cursor used in freehand drawing mode. Entries in<X11/cursorfont.h>(without theXC_prefix) are valid names of the cursor. The default ispencil.Tgif.RubberBandColor: COLORSTRING— sets the color used for rubber-banding (that's the XORing, bestie 💫). Default is whatever the foreground color is, so if you don't say anything it just matches the vibe.Tgif.MaxColors: NUMBER— the maximum number of colors, periodt.Color0throughColorMaxget queried in X defaults, whereMaxisNUMBER-1. IfNUMBERis bigger than the default of11, thenColor11throughColorMaxall have to exist in X defaults, no skipping 🙅. Wanna see the default color list? It's chillin' in the GRAPHICAL OBJECTS section.Tgif.Color#: COLORSTRING— this is the matchmaking service between a color number and an actual color 💖.Tgif.DefaultColorIndex: NUMBER— the fallback color index for when a color just can't be found (we've all been there 😭). Default is0. But heads up:Tgif.DefaultColortakes precedence over this X default, so it wins the argument fr.Tgif.ShortCuts: ITEM1 ITEM2 ...— eachITEMmaps a key (and yes, it may be case sensitive 👀) to a non-alphanumeric key command. Full deets live in the SHORTCUTS section.Tgif.MaxLineWidths: NUMBER— the max number of line widths.LineWidth0throughLineWidthMax,ArrowWidth0throughArrowWidthMax, andArrowHeight0throughArrowHeightMaxall get queried in X defaults, whereMaxisNUMBER-1. IfNUMBERis bigger than the default of7, thenLineWidth7throughLineWidthMax,ArrowWidth7throughArrowWidthMax, andArrowHeight7throughArrowHeightMaxmust all exist in X defaults. Anything you don't specify there gets some default values, so it's not the end of the world 🫶.Tgif.DefaultLineWidth: NUMBER— the initial line width index. Default is0.Tgif.LineWidth#: NUMBER— specifies a line width. The default line widths are1,2,3,4,5,6, and7. cute and skinny ✨Tgif.ArrowWidth#: NUMBER— the width of the arrow head (measured when the arrow is pointing horizontally, iykyk) for arc and open-spline objects. Default arrow widths are8,10,12,14,18,20, and22.Tgif.ArrowHeight#: NUMBER— half the height (again, when the arrow is pointing horizontally) of the arrow head for arc and open-spline objects. Don't forget it's half, bestie 💅. Default arrow heights are3,4,5,6,7,8, and9.Tgif.MaxDomains: NUMBER— saysNUMBERis the number of domains.DomainPath0,DomainPath1,...,DomainPathMall have to exist in X defaults, whereM=NUMBER-1. No half-sending it.Tgif.DomainPath#: DOMAINSTRING— the three-way group chat between a domain number, a domain name, and the path tied to that domain 🦋. So you need oneDomainPath#X default per domain you define. Swap the#for a domain number. Those numbers should be0,1,...,MAXDOMAINS-1, whereMAXDOMAINSis set in theMaxDomainX default above. And yes —MaxDomain+DomainPath#together are required to use domains. Both or nothing.
DOMAINSTRING holds strings separated by the ':' symbol. First string = the domain name. Every string after that = a directory where symbol files get searched when the Instantiate command runs (peep the HOW TO MAKE A BUILDING-BLOCK OBJECT section for the tea ☕). Another way to see it: if you chop off the first string (the domain name) and the first ':', a DOMAINSTRING literally has the form of the PATH csh(1) environment variable. Slay.
Example time — to set the symbol path for domain DEFAULT so it looks for symbol files first in /tmp/tgif/symbols, then in the current directory, DOMAINSTRING should be:
DEFAULT:/tmp/tgif/symbols:.
Tgif.DefaultDomain: NUMBER— the default domain when tgif boots up. Default is0.Tgif.PrintCommand: COMMAND— the print command used to print the PostScript file. Default islpr(1). An example would belpr -h -Pprintername. IfCOMMANDcontains a%ssubstring, that%sgets replaced with the full path name of the PostScript file that would normally be sent to the print command. SoCOMMANDwith no%sbehaves identically toCOMMAND %s— iconic ✨. Note: this only works when running tgif without the-printcommand line option. And you can use it to send a font file to the printer before the tgif PostScript file gets sent, like this:
cat /somewhere/sansfex.pfa %s | lpr -Pmyprinter
Tgif.WhereToPrint: STRING— the initial print/export destination/format.STRINGcan bePrinter,EPS,PS,Bitmap,Text,EPSI,GIF,HTML,PDF,WinEPSI,PNG,JPEG,PPM, orNetList. Default isEPS.Tgif.PrintDirectory: PATH— the print directory for when the output destination isn't the printer. Default is a null string, which means the output goes into the directory where the current file lives. home sweet home 🏠Tgif.NoTgifIcon: [true,false]— set it to ``true'' and tgif won't use its own icon window. In that case you should also setTgif.UseWMIconPixmap(below 👇) to true. Modern window managers usually don't let an app draw its own icon window anyway, so this X default would have no effect under those. Default is false.Tgif.UseWMIconPixmap: [true,false]— set it to ``true'' and tgif uses the standard icon pixmap. Also,Tgif.NoTgifIcongets ignored when this is on. Default is true.Tgif.DontShowVersion: [true,false]— set to ``true'' and the tgif version won't be displayed on top of the tgif window. Default is true. stealth mode 🌸Tgif.XBmReverseVideo: [true,false]— set to ``true'' and an invert bitmap operation happens when importing an X11 bitmap file. Default is false.Tgif.AskForXBmSpec: [true,false]— set to ``true'' and the user gets asked to specify magnification and geometry for an X11 bitmap file being imported. The format of that spec isMAG=WxH+X+Y, whereMAGis the magnification,WandHare the width and height, and the location spec can be+X+Y,+X-Y,-X+Y, or-X-Y. The'='is mandatory if any of the geometry info is specified — do not forget it bestie 😤. Default is false.Tgif.AskForXPmSpec: [true,false]— set to ``true'' and the user gets asked to specify magnification and geometry for an X11 pixmap file being imported. Format is the same as forAskForXBmSpec. Default is false.Tgif.StripEPSComments: (obsolete)— this X default became obsolete intgif-4.0.11because it turns out it's not always okay to strip PS comments. It should always be set to false. dead and gone 💀Tgif.GuessXPmBgColor: [true,false]— set totrue'' and when tgif imports an X11 pixmap file whose first color string is `' '` (the space character) or'' `` (the back quote character), it treats that first color as a background color. Meaning: the specified color in the X11 pixmap file gets changed to the current background color. Default is false. Fun lore: this default was true before patch 2 oftgif-2.7` 📜. This X default exists for compatibility reasons only, and it should be considered obsolete.Tgif.XPmOutputVersion: NUMBER— the XPM version number when outputting in the X11 pixmap format.NUMBERcan be1or3. Default is1.Tgif.XPmInXGrabSCFormat: [true,false]— ifTgif.XpmOutputVersionis set to1, setting this to ``true'' forces the X11 pixmap output to resemble whatxgrabscgenerates (i.e., color names will not be used). Default is false.Tgif.UseGrayScale: [true,false]— set to ``true'' and gray scales get used for tiling patterns to speed up printing. Default is false. faster printing = self care 🧖Tgif.AutoPanInEditText: [true,false]— set to ``true'' and auto panning is used so the text cursor is always visible in text edit mode (except when the cursor is to the left of, or on top of, the paper). Probably turn this off on slow servers, ngl. Default is true.Tgif.PercentPrintReduction: NUMBER— the initial percent print reduction/magnification. Default is100.Tgif.ConstrainedMove: [true,false]— the initial move mode. When set to ``true'', moving or stretching an object causes the endpoints of all polylines or open-splines whose endpoints fall within the object — and possibly the neighboring vertices — to be moved too. More details in the IDIOSYNCRASIES section. Default value is false.Tgif.DoubleQuoteDoubleQuote: [true,false]— when ``true'', output of the double-quote character gets preceded by a double-quote character; when false, output of the double-quote character gets preceded by a back-slash character. Default value is false.Tgif.GridSystem: [English,Metric]— sets the initial grid system. Default isEnglish.Tgif.InitialGrid: NUMBER— the initial grid size. For the English grid system,NUMBERcan be-2,-1,0,+1, or+2for grid sizes of1/32,1/16,1/8,1/4, and1/2inch. For the Metric grid system,NUMBERcan be-1,0,+1, or+2for grid sizes of1mm,2mm,5mm, and1cm. Default value is0.Tgif.DropObsIconAttrWhenUpdate: [true,false]— set totrue'' and obsolete icon attributes get dropped **without confirmation** when the `UpdateSymbols` command runs. Set tofalse'' and a popup window asks you what to do with those obsoleted icon attributes. Default is false.Tgif.UseRecentDupDistance: [true,false]— set to ``true'' and the most recent change in position from a combo of a duplicate and a move command gets used for the new duplicate command. Otherwise, some default distance gets used to position the duplicate. Default is true.Tgif.SplineTolerance: NUMBER— okay so this one sets the tolerance of spline drawing. The smaller the number, the smoother the spline, no cap. The default is9(min is3and max is13). ✨Tgif.SplineRubberband: (obsolete)— bestie this one is literally obsolete 💀. If set totrue, spline rubber-bands will be used in drawing, moving, and stretching open and closed splines. (This might not be desirable if the spline contains too many vertices.) The default istrue. This X default became obsolete sincetgif-4.2due to the addition of structured spline objects. iconic history 👑Tgif.Synchronize: [on,off]— if this X default is set toon, thenXSynchronizeis called. The default isoff. simple as that 🦋Tgif.DoubleClickUnIconify: [true,false]— if set totrue, double mouse clicks are used to de-iconify the icon window (in this mode, the icon window ignores single mouse clicks and drags). The default isfalse. not me ignoring single clicks 🙈Tgif.MainMenuPinDistance: NUMBER— this specifies the horizontal distance (in pixels) the user needs to drag a popup menu before the popup menu is to be pinned down. The default is80. (If pinned popup menus are not desired, then this should be set to a value greater than the screen width.) Dragging the left mouse button can be used to move the pinned popup menu; clicking the right button in the popup menu will remove it. periodt 💅Tgif.DoubleClickInterval: NUMBER— this specifies the maximum interval (in milliseconds) between two mouse clicked to be recognized as one double-click. The default is300. fast fingers only ⭐Tgif.HandleSize: NUMBER— this specifies (half) the size of the handle used to highlight objects. Its allowable value is between2and6. The default is3. cute little handle 🎀Tgif.HistoryDepth: NUMBER— this specifies the size of the undo/redo buffer; negative values mean that the buffer is unbounded. The default is-1. so basically infinite undo vibes 🔥Tgif.SaveTmpOnReturn: [true,false]— if set totrue, atmpmodelfile will be saved automatically before returning to the driver. Otherwise, no files will be saved automatically. The default istrue. auto-save bestie 🫶Tgif.ImportFromLibrary: [true,false]— if set totrue, the library directories specified by the current domain are searched for.obj,.sym, xbitmap/xpixmap, and EPS files to import. Otherwise, the current directory will be used as the starting point. The default isfalse. library scavenger hunt 🧚Tgif.WarpToWinCenter: [true,false]— if set totrue, the mouse is warped to the center of popup windows. Otherwise, the mouse is not warped. The default istrue. mouse teleportation ✨Tgif.SaveCommentsInSaveNew: [true,false]— if set totrue,%%type comments in the file will be stored in the newly created file. The default istrue. keep those comments 💖Tgif.CanvasWindowOnly: [true,false]— if set totrue, only the canvas window will be displayed (this is a kind of thedemomode). The default isfalse. main character canvas energy 🌈Tgif.UsePsAdobeString: [true,false,NUMBER_1/NUMBER_2]— if set totrue, the first line in the PS or EPS file will be%!PS-Adobe-2.0 EPSF-1.2. If set tofalse, it is just%!. If the PS-Adobe string confuses the document manager (such as Transcript) on your site, you should set it tofalse. If the third form is used, the first line will be%!PS-Adobe-NUMBER_1 EPSF-NUMBER_2. The default isfalse. document manager drama 😭Tgif.HalfToneBitmap: [true,false]— if set totrue, the Floyd-Steinberg half-tone method will be used when printing in the X11 bitmap format. This is useful when the drawing contains X11 pixmap objects. The default isfalse. fancy halftone moment 💜Tgif.ThresholdBitmap: [true,false]— if set totrue, a simple thresholding method will be used to decide whether a bit is turned on or off when printing in the X11 bitmap format. IfTgif.HalfToneBitmapis set to true, this X default is ignored. The default isfalse. ignored if halftone is on 💀Tgif.BitmapThreshold: NUMBER— this specifies the threshold value used in either the Floyd-Steinberg half-tone algorithm or the simple thresholding algorithm.NUMBERmust be between0and1. This X default is only active when either theTgif.HalfToneBitmapor theTgif.ThresholdBitmapX default is set to true. The default value is0.5ifTgif.HalfToneBitmapis true, and is1.0ifTgif.ThresholdBitmapis true (basically, anything that is not white will be black). black and white realness 🖤Tgif.EPSIThresholdPreviewBitmap: [true,false]— if set totrue, a simple thresholding method will be used to decide whether a bit is turned on or off in the preview bitmap when printing in the EPSI format. The default isfalse. preview bitmap check 🎀Tgif.EPSIPreviewBitmapThreshold: NUMBER— this specifies the threshold value used in the simple thresholding algorithm to decide whether a bit is turned on or off in the preview bitmap when printing in the EPSI format.NUMBERmust be between0and1. The default value is0.5ifTgif.EPSIThresholdPreviewBitmapis true, and is1.0ifTgif.EPSIThresholdPreviewBitmapis false (basically, anything that is not white will be black). same energy ⚫Tgif.GroupedTextEditable: [true,false]— if set tofalse, only top level text objects and attributes of top level objects can be edited when the drawing mode is set to the text mode. If set totrue, text objects and attributes everywhere can be edited. The default isfalse. text edit permissions 📝Tgif.DefaultEPSScaling: NUMBER— this specifies the scaling factor applied to an imported PS or EPS image. As mentioned in the IDIOSYNCRASIES section below, tgif treats128pixels as an inch and PostScript treats72points as an inch. In order to have real-size PostScript images, this parameter should be set to1.7778(which is128/72). The default value is1. math is mathing 📐Tgif.IntrCheckInterval: NUMBER— this specifies the number of objects drawn before tgif checks for interrupts. If this is set to be0or less, interrupt is not allowed. The default value is10. interrupt check break ⚡Tgif.TiledPageScaling: NUMBER— this specifies the scaling value used when a multipage drawing in tiled page mode is printed. Since most PostScript printers do not use the full page as the drawing area, setting this number to1may get truncated output. The default value is0.9. printer margins said no 🖨️Tgif.TGIFPATH: STRING— this specifies the directory where the files, mentioned in the FILES section below, can be found. TheTGIFPATHenvironment variable may override this option. The default value is specified by the compiler optionTGIF_PATH. path finder 📁Tgif.TGIFICON: STRING— this specifies the name of the object file to be displayed when tgif is iconified. If it starts with a/character, absolute path is used; otherwise, the actual path of the icon file is$TGIFPATH/STRINGwhereTGIFPATHis either defined using the X defaults or an environment variable. The default value istgificon.obj. iconic icon file 🖼️Tgif.StickyMenuSelection: [true,false]— if set totrue, when patterns/linewidths/linestyles/... of objects are changed using a menu action, the corresponding pattern/linewidth/linestyle/... becomes the current selection. The default istrue. sticky like glue 💅Tgif.PSBopHook: STRING— if specified, the following PostScript line is added at the beginning of each page when printing to the printer or to a PS file,
userdict /STRING known { STRING } if
This option should only be used if one is very familiar with PostScript. (Setting STRING to tgif-bop-hook is recommended since it would not have a name conflict with existing software, such as dvips(1).) PostScript wizards only 🚨
Tgif.PSEopHook: STRING— if specified, the following PostScript line is added at the end of each page when printing to the printer or to a PS file,
userdict /STRING known { STRING } if
This option should only be used if one is very familiar with PostScript. (Setting STRING to tgif-eop-hook is recommended since it would not have a name conflict with existing software, such as dvips(1).) end of page hook 🛑
Tgif.MinimalEPS: [true,false]— if set tofalse, comments such as%%Pages,%%DocumentFonts,%%EndComments,%%BeginProlog,%%EndProlog,%%Page,%%Trailer, and%%EOFwill be generated in an EPS output. These comments may confuse certaindocument managers. Therefore, the default istrueifTgif.UsePsAdobeStringis not specified (and the default isfalseifTgif.UsePsAdobeStringis specified). comment chaos 🤔Tgif.InitialPrintInColor: [true,false]— if set totrue, color output (printing) mode is enabled on startup. Please note that in black and white PS/EPS/EPSI printing mode, the white color will be printed as black (only background will be printed as white). The default istrue(except when the-printcommand line option is used). color on deck 🌈Tgif.InitialShowGrid: [true,false]— if set tofalse, showing grid is disabled on startup. The default istrue. grid check 📏Tgif.InitialSnapOn: [true,false]— if set tofalse, snapping to the grid points is disabled on startup. The default istrue. snap to it 🧲Tgif.NoMenubar: [true,false]— if set totrue, no menubar will be shown initially. The default isfalse. no menubar no problem 🚫Tgif.NoStatusWindow: [true,false]— if set totrue, no Status Window will be shown initially. The default isfalse. status window hidden 🚫Tgif.ReverseMouseStatusButtons: [true,false]— if set totrue, the left mouse status and the right mouse status are swapped. This should be used when aleft-handed mouseis used. The default isfalse. left-handed legend 🖱️Tgif.MinimalMenubar: [true,false]— if set tofalse, the menu items in the Menubar Window will be the same as the main popup menu. This would take up much more space. If set totrue, thePage,PageLayout,HoriAlign,VertAlign, andMoveModemenus are collapsed into theViewcascading menu; theFont,TextStyle, andTextSizemenus are collapsed into theTextcascading menu; and theLineDash,LineStyle,LineType,LineWidth,Fill, andPenmenus are collapsed into theGraphicscascading menu. The default istrue. menu glow-up 🗂️Tgif.ColorBgInPrintingColorPS—[true,false]💅 if you set this totrue, the window background color gets used as the background color when you're generating color PostScript output. Set it tofalseand no background color is used, periodt. Default?false.Tgif.ScrollBarWidth—NUMBER📏 this one says how wide a scroll bar is.NUMBERhas to be between2and16(like, don't be weird about it). Default is16.Tgif.InitialPaperSize—STRING📄 theSTRINGsets the initial width and height of the paper, and it's gotta be in the"<width> x <height>"form.<width>and<height>are numeric values immediately followed by either"in"(inch) or"cm"(centi-meter). And bestie, that" x "separating<width>and<height>is mandatory, no skipping it. IfA4PAPERis defined in theMakefile, the default value is"21cm x 29.7cm". IfA4PAPERis not defined in theMakefile, the default value is"8.5in x 11in".Tgif.UpdateChildUsingAlignment—[true,false,no_overlap]🧚 if you set this totrueorno_overlap, then when theupdate_eps_child(),update_xbm_child(), orupdate_xpm_child()internal command is executed, the current horizontal and vertical alignments are used to place the EPS/XBM/XPM subobject. If the horizontal alignment isL,C,R,S, or-, the subobject is aligned to the left, center, right, center, or left (respectively) to the parent object. If the vertical alignment isT,M,B,S, or-, the subobject is placed above, middle, below, middle, or below the parent object if this X default is set tono_overlap; but the subobject is aligned to the top, middle, bottom, middle, or below the parent object if this X default is set totrue. And if this X default is set tofalse, the subobject is placed left aligned and below the parent object. Default isfalse.Tgif.GenerateImageMap—[true,false]🗺️ set it totrueand NCSA imagemap or CERN Clickable Image files get generated when you print in GIF format. When that happens, theTgif.XpmToGif,Tgif.ImageMapFileExtension,Tgif.GifFileExtension,Tgif.ImageMapFileFormat, andTgif.UseXPmVersion1ForImageMapX defaults (all described below, keep scrolling bestie) get interpreted; otherwise they're just ignored, sitting there. Peep the section on GENERATING IMAGEMAP FILES for the deets. Default isfalse.Tgif.XpmToGif—STRING🖼️ theSTRINGis a command used to convert an XPM file to a GIF file. It must contain a%ssubstring, which gets replaced by the full path name of the XPM file. Default is"xpmtoppm %s | ppmtogif".Tgif.ImageMapFileExtension—STRING📎 theSTRINGis the file extension for a imagemap file. Default is"map".Tgif.GifFileExtension—STRING🎀 theSTRINGis the file extension for a GIF file. Default is"gif"(lower case, okurrr).Tgif.ImageMapFileFormat—[NCSA,CERN]✨ theSTRINGspecifies either the NCSA imagemap or the CERN clickable image format. Default isNCSAfor the NCSA imagemap format.Tgif.UseXPmVersion1ForImageMap—[true,false]🌸 the setting of this X default should depend on the setting of theTgif.XpmToGifX default above. If set totrue, an XPM1 file is generated regardless of the setting of theTgif.XPmOutputVersionX default. Default istrue.Tgif.UsePaperSizeStoredInFile—[true,false]📐 if set totrue, the paper size information stored in a just opened file gets used. Default istrue.Tgif.OneMotionSelMove—[true,false]💫 if set totrue, you can select and move an object in one motion. Iconic. Default isfalse.Tgif.TiffEPSI—(obsolete)💀 this X default became obsolete becauseTiffEPSIbecame a supported export format sincetgif-4.0. She's retired, respect her journey.Tgif.XbmToTiff—STRING🖨️ theSTRINGis a command used to convert an XBM file to a TIFF file. It must contain either one or two%ssubstrings. The first%ssubstring is replaced by the full path name of the XBM file. The optional second%ssubstring is replaced by the full path name of the generated TIFF image. Default is"xbmtopbm %s | pnmtotiff -none > %s".Tgif.EPSIExportExtension—STRING🧵STRINGis the file extension used for exporting EPSI files. Default is"eps".Tgif.HotListFileName—STRING🔥STRINGis a full path name of a file used to store the hot file list. By default, this file is.Tgif_hotlistin the user's home directory.Tgif.@@@Viewer—STRING👀STRINGspecifies an external viewer for a remote URL with a file extension of@@@.STRINGcan be in 3 forms:- It can be the string
"NONE"to indicate that when such a remote file is encountered, tgif should retrieve the file into a user specified directory. Like, if you wanna retrieve.gzfiles, you can use:
- It can be the string
Tgif.gzViewer: NONE
STRINGcan also contain the string%S(Sis capitalized), which indicates that%Sis to be replaced by the URL. So if you wanna view.htmlfiles usingxmosaic, you can use:
Tgif.htmlViewer: xmosaic %S
- Another form of
STRINGcontains the string%s(Sis lower-case), which indicates that the remote file is to be retrieved into a user specified directory and viewed by a tool. So if you wanna view.giffiles usingxv, you can use:
Tgif.gifViewer: xv %s
Just so you know — this mechanism has precedence over the mechanism described in the MIME TYPES AND MAILCAPS section above. 💅
Tgif.AutoHyperSpaceOnRemote—[true,false]🚀 if set tofalse, tgif will not go into the hyperspace mode when a remote URL is visited. Default istrue.Tgif.AllowLaunchInHyperSpace—[true,false]⚠️ if set totrue, launching of applications is enabled in the hyperspace mode when a remote URL is visited. This is potentially very dangerous because the application may do catastrophic damages. So it is strongly recommended that it is set tofalse. Default isfalse.
Bestie, fr fr, leave that one alone. Catastrophic damages is not the vibe. 🙈
Tgif.CanChangeAttrColor—[true,false]🎨 if set totrue, the color of an attribute can be changed when it is attached to an object. Default isfalse.Tgif.MimeTypesFile—STRING📬STRINGis a full path name of the MIME-types file. Tgif only uses thetype/subtypefield in the MIME-types file and ignores all other fields (not me being selective 💅). The default MIME-types file is.mime.typesin the user's home directory.Tgif.LocalRGBTxt—STRING🌈 if you wanna override certain system colors, you can useSTRINGto specify a full path name of a file to be consulted first before looking up the color in the server. The file must be in the same format as thergb.txtfile — namely, each line contains 4 fields: the first 3 fields correspond to the red, green, and blue components of the color, and the 4th field is the name of the color. A color component must have a value between0and255(inclusive).Tgif.PrintUsingRequestedColor—[true,false]🖨️ if set totrue, the color PostScript file being printed will use the requested color instead of the color returned by the X server. Default isfalse.Tgif.ShowMeasurement—[true,false]📏 if set totrue, the location of the cursor and the width and height of the object being drawn/dragged/stretched will be shown. Default isfalse.Tgif.ShowMeasurementUnit—STRING📐 theSTRINGspecifies the unit used to display the measurement cursor. There are 2 basic formats:- One is just the word
"pixel","inch", or"cm". These are also known as basic units. - Another format is
NUM BASIC-UNIT/NEW-UNIT, whereNUMis a numeric value,BASIC-UNITis one of the basic units, andNEW-UNITis any string.
- One is just the word
For example, "0.1 cm/mm" means that the new display unit is "mm" and 1 "mm" is 0.1 cm. And "50 pixel/cm" is identical to "1 cm/cm", and "128 pixel/inch" is identical to "1 inch/inch". The default is pixel.
Tgif.PageStyleLandscape—[true,false]🏞️ if set totrue, tgif comes up in landscape mode. Default isfalse.Tgif.QueryZoomInPoint—[true,false]or[always,no_select,no_query,never]🔍 if set totrue(oralways), the user will be asked to select a center point when zooming in. If set tono_select, the user will be asked to select a center point when zooming in if no objects are selected. If set tono_query, the position of the mouse is the zoom-in point — in this case, it is not desirable to zoom in using a menu selection. The default isfalse(ornever).Tgif.GZipCmd—STRING🗜️ theSTRINGspecifies a command used to gzip a.objfile. The command must produce output into itsstdout. If the command contains a%ssubstring, the%swill be replaced by the full path name of a temporary copy of the.objfile. Default is"gzip -c".Tgif.GUnZipCmd—STRING📦 theSTRINGspecifies a command used to unzip a zipped tgif file (with extension.obj.gzor.sym.gz) into a tgif file. The command must produce output into itsstdout. If the command contains a%ssubstring, the%swill be replaced by the full path name of a temporary copy of the zipped file. Default is"gunzip -c".Tgif.HttpProxy—STRING🌐 theSTRINGspecifies a host name and a port number of an HTTP proxy server. Format of the specification is<host>:<port>. If:<port>is omitted,80is used as the default port number. The environment variablehttp_proxyhas precedence over this X default. The default is not to use an HTTP proxy server.Tgif.FtpProxy—STRING📡 theSTRINGspecifies a host name and a port number of an FTP proxy server. Format of the specification is<host>:<port>. If:<port>is omitted,21is used as the default port number. The environment variableftp_proxyhas precedence over this X default. The default is not to use an FTP proxy server.Tgif.InitialArrowStyle—[NONE,RIGHT,LEFT,DOUBLE]➡️ this specifies the initial arrow style for polyline/open-splines/arcs. Default isRIGHT.Tgif.ShowPageInEPS—[true,false]bestie if this is ``true'', ashowpagePostScript command gets generated for an EPS or EPSI file. default? true 💖Tgif.MaxNavigateCacheBuffers— NUMBER how many cache buffers do we give to caching remote files (so we're not chatting with the network constantly, rude of us). NUMBER has to be non-negative. default is 40 ✨Tgif.NumberFileInPrintOnePage—[true,false]set this to ``true'' and when you pick PrintOnePage from the Print Menu on a stacked multipage drawing (thinkfile.obj), it makesfile_Nwith the right file extension, whereNis the page number you picked. default is false 🎀Tgif.OneMotionTimeout— NUMBER whenTgif.OneMotionSelMoveistrue, moving an object counts as making a selection if the time between mouse-down and mouse-up is smaller than this X default's timeout (in milliseconds). default is 200 🦋Tgif.MinMoveInterval— NUMBER whenTgif.OneMotionSelMoveisfalse, moving an object counts as making a selection if the time between mouse-down and mouse-up is smaller than the interval this X default specifies (in milliseconds). default is 0 🌸Tgif.GifToXpm— STRING STRING is the command that converts a GIF file into an XPM file. it must contain a%ssubstring, which gets swapped out for the full path name of the GIF file. default is"giftopnm %s | ppmtoxpm"💅Tgif.InitExportPixelTrim—LEFT_NUMBER,TOP_NUMBER,RIGHT_NUMBER,BOTTOM_NUMBERthese numbers say how many pixels to trim when printing or exporting as XBM, XPM, or GIF. it's literally an escape hatch to fix a little idiosyncrasy where tgif can't quite figure out exactly how big the whole image is 🙈. defaults are all 0's.Tgif.QuantizingLevels— NUMBER some image functions likeSharpen()use convolution and might cook up an image with more than 256 colors, which tgif simply cannot handle. NUMBER is how many colors to quantize down to when that happens. default is 222 🫶Tgif.RotateCursor—[x_cursor,arrow,...]the cursor used in rotate mode. the names in<X11/cursorfont.h>(minus theXC_prefix) are valid cursor names. default iscrosshair⭐Tgif.ColorLayers—[true,false]set to ``true'' and every color becomes its own layer that you can turn on and off individually. turn a color layer off and the primitive objects in it go invisible. a grouped object only goes invisible once all its constituent objects are invisible. default is false 🌈Tgif.TiffToXbm— STRING STRING is the command that converts a TIFF file to an XBM file. it's used when importing an EPSI file that a Windows app made. STRING must have a%ssubstring, replaced by the full path name of the TIFF file. default is"tifftopnm %s | pgmtopbm | pbmtoxbm"👑Tgif.DefFixedWidthFont— STRING the font used as the default for the Status Window, menus, dialogboxes, etc. default is"-*-courier-medium-r-normal-*-14-*-*-*-*-*-iso8859-1"✨Tgif.DefFixedWidthRulerFont— STRING the font used in the horizontal and vertical ruler windows. default is"-*-courier-medium-r-normal-*-10-*-*-*-*-*-iso8859-1"📏Tgif.MenuFont— STRING the font used in menus. if this X default isn't specified, the default font is used in menus 💖Tgif.BoldMsgFont— STRING a bold font used in buttons and dialogboxes. if this X default isn't specified butTgif.MenuFontis, this takes on the value ofTgif.MenuFont. if neither this X default norTgif.MenuFontis specified, the default font is used in bold messages 🔥Tgif.MsgFont— STRING a thin font used in the Status Window and dialogboxes. if this X default isn't specified, the default font is used in messages 🌸Tgif.BggenToXpm— STRING the command for generating an X11 pixmap file, run whenRunBggen()is picked from the ImageProc Menu. STRING must have two%ssubstrings: the first%sgets replaced by a user specified string, the second%sgets replaced by the geometry of the image. default is"bggen %s -g %s | ppmquant 64 | ppmtoxpm". heads up,bggen(1)is part of thexv(1)package 💅Tgif.BggenToPpm6— STRING the command for generating a PPM file, run whenRunBggen()is picked from the ImageProc Menu. STRING must have two%ssubstrings: the first%sgets replaced by a user specified string, the second%sgets replaced by the geometry of the image. default is"bggen %s -g %s". also notebggen(1)is part of thexv(1)package 🦋Tgif.LittleEndianPpm6—[true,false]set to ``true'' and when reading a PPM (or PGM) file that uses a maxval of 65535, little endian format gets assumed (even though the standard for that format calls for big endian 👀). default is false 🎀Tgif.DefaultErrorDiffuseLevels—R_NUMBER G_NUMBER B_NUMBERthese *NUMBER*s say how many bits of red, green, and blue to use whenReduceToDefaultColors()orDefaultErrorDiffuse()are picked from the ImageProc Menu. they determine a set of default colors for color quantization in those two methods.R_NUMBER+G_NUMBER+B_NUMBERmust be less than or equal to 8, and each number must be greater than 0. default is2 2 2✨Tgif.MaxImportFilters— NUMBER the maximum number of import filters.ImportFilter0throughImportFilterMaxget queried in X defaults, where Max is NUMBER-1. default is 0 💖Tgif.ImportFilter#— FILTERSTRING this specifies an import filter. FILTERSTRING has 3 parts separated by space characters. part one: the name of the filter, and it must not contain a space. part two: semicolon-separated file extensions. part three: the actual filter command that converts the named external file type into an X11 pixmap file. go check the IMPORT RASTER GRAPHICS section for the details 🫶Tgif.ShowFileNameOnBrowse—[true,false]set to ``true'' and file names show up whenBrowseXBitmap(),BrowseXPixmap(), orBrowseOther()are picked from the File Menu. default is true 🌟Tgif.HtmlFileExtension— STRING the file extension used when printing in the HTML format. default is"html"⭐Tgif.GenerateHtmlHref—[true,false]set totrue'' and when printing in the HTML format, the value of an `href` attribute gets parsed. if that value references a `.obj` file, it's changed to have an HTML file extension. set it tofalse'' and no conversion happens at all. default is true 🌈Tgif.RotationIncrement— NUMBER the initial rotation increment in degrees. default is 45 🔄Tgif.PSA4PaperSize—[true,false]set to ``true'' and when A4 size paper is specified, this line gets added to a PS/EPS/EPSI file (before"%%EndComments"):
%%DocumentPaperSizes: a4
default is false 🎀
Tgif.ShapeShadowSpec— STRING the initial horizontal and vertical offsets of a shape shadow. if both values are zeroes, the shape is created with no shadow. when you do make a shape with a shadow, the background fill pattern (3rd pattern in the first column of the Fill Menu) usually gives the best result 💅. default is"0,0"Tgif.StretchableText—[true,false]set to ``true'' and stretchable text mode is the initial mode. default is true ✨Tgif.EditTextSize— NUMBER the text size used when editing existing text objects. NUMBER should either be 0 or a value between 4 and 34 (inclusive). if NUMBER is 0, the actual text size is used when editing existing text objects. you can change the edit text size later by pickingSetEditTextSize()from the Properties Menu. default is 0 👑Tgif.IconPixmap— (obsolete) this X default became obsolete intgif-4.2because it clashes with the Xtoolket. it's renamed toTgif.WMIconPixmap💀Tgif.WMIconPixmap— STRING STRING is the path of an XBM or XPM file used as tgif's desktop icon. if STRING starts with a/character, an absolute path is used; otherwise the actual path of the icon file is$TGIFPATH/STRING, whereTGIFPATHis defined via the X defaults or an environment variable. this X default is only enabled ifTgif.UseWMIconis set to true. default value is ``tgificon.xbm'' (which is compiled into tgif) 🦋Tgif.TmpFileMode— NUMBER (OCTAL) the file mode for temporary and exported files. NUMBER must be an octal number. if NUMBER is 0, no attempt is made to change the file mode. if this value is specified (even if it's 0), it overrides thePSFILE_MODcompile option. there is no default value 🙈Tgif.TitledPinnedMenu—[true,false]set to ``true'' and a pinned menu gets a title bar, and the left button is used for selecting menu items in a pinned menu. default is true 🌸Tgif.ColorFromXPixmap— STRING STRING is the path of an XPM file used to load the initial colors. if this X default is specified, theTgif.Color#X defaults get ignored, but theTgif.AdditionalColorsX default can still be used to specify additional colors when tgif starts up 🎀Tgif.VectorWarpSoftness: NUMBER — this is the softness value forVectorWarp()when you pick it from the ImageProc Menu ✨.VectorWarp()lets you warp the pixels in an X11 pixmap object by giving it a vector, and this value controls how big the affected area is. It has to be between1.0and4.0— bigger value, bigger area, no cap. Default is2.0💫Tgif.ChangePropertiesOfAttrs: [true,false] — set it totrueand changing a property of an object (font, font size, color, etc.) will change that same property on all the attributes attached to that object too 🎀. Default isfalse.Tgif.ShiftForDiagMouseMove: [true,false] — set it totrueand certain mouse movements get restricted to multiples of 45 degrees 📐. Default istrue.Tgif.UseRecentForDiagMouseMove: [true,false] — if you set it totrue, the object used as the anchor for measuring the moving distance is used as an anchor when objects 👀. This only works ifTgif.UseRecentDupDistanceandTgif.ShiftForDiagMouseMoveare both set totrue. Default isfalse.Tgif.FlushColormapOnOpen: [true,false] — set it totrueand the colormap gets flushed and the initial tgif colors get reloaded every time a new file is opened 🌈. Default isfalse.Tgif.TransparentPattern: [true,false] — set it totrueand fill and pen patterns start out transparent 🫧. Default isfalse.Tgif.DontReencode: STRING — okay so for fonts that are not iso8859-1 encoded, the non-ASCII portion of the font (the characters with bit 7 on) gets reencoded by default as if it were iso8859-1 encoded. If that's not it for a particular font, you can bypass the reencoding by putting the first part of the PostScript font name in STRING 🦋. Fields in STRING are colon-separated. Like, if STRING is"Times:Courier:Helvetica", then PostScript fonts that begin with"Times","Courier", or"Helvetica"will not be reencoded. (Heads up bestie: this X default overrides the fonts specified by-D_DONT_REENCODEat compile time.) Also go peek at the POSTSCRIPT CHARACTER ENCODING FOR INTERNATINOAL CHARACTERS section for an example 💜Tgif.AdditionalDontReencode: STRING — use this X default to augmentTgif.DontReencode(or the fonts specified by-D_DONT_REENCODEat compile time) 🌸. STRING here basically gets concatenated onto the STRING specified byTgif.DontReencode(or those compile-time fonts).Tgif.UnsignedInXBmExport: [true,false] — set it totrueandunsigned chargets used instead ofcharin exported XBM files ✨. Default isfalse.Tgif.CommentInBitmapExport: [true,false] — set it totrueand a blank RCS Header comment gets prepended to exported XBM and XPM files 📝. Default isfalse.Tgif.ShowFontSizeInPoints: [true,false] — set it totrueand font sizes get displayed in the unit of point sizes 🔤. Default isfalse.Tgif.DontCondensePSFile: [true,false] — by default, PS/EPS files generated by tgif are not condensed. If this X default is set tofalse, tgif will generate condensed PS/EPS files. The default istrue.Tgif.StripCondensedPSComments: (obsolete) — this X default became obsolete intgif-4.0.11because it turns out it's not always okay to strip PS comments (it should always be set tofalse) 💀.Tgif.PdfFileExtension: STRING — STRING is the file extension used when printing in the PDF format 📄. Default is"pdf".Tgif.PsToPdf: STRING — STRING is a command used to convert a PS file to a PDF file. It must contain 2%ssubstrings, which get replaced by the full path name of the PS file and the full path name of the PDF file 🌀. Default is:
ps2pdf "%s" "%s"
(If you're feeling "epstopdf", you can try setting this to "epstopdf %s --outfile=%s".)
Tgif.EpsToTmpSvg: STRING — converting an EPS file to an SVG file happens in two steps. First the EPS file is converted to a temporary file, then the temporary file is converted to an SVG file 🎨. By default, theuniconvertor(1)format is used for the temporary file. STRING here specifies the command for the first part and it must contain 2%ssubstrings to be replaced by the full path name of the EPS file and the full path name of the temporary file. Default is:
pstoedit -dt -f sk "%s" "%s"
Tgif.TmpSvgToSvg: STRING — this X default is meant to be used withTgif.EpsToTmpSvgabove 🫶. STRING here specifies the command for the second part of the conversion and it must contain 2%ssubstrings to be replaced by the full path name of the temporary file and the full path name of the SVG file. Default is:
uniconvertor "%s" "%s"
Tgif.TmpSvgFileExtension: STRING — STRING is the file extension used for the intermediary file when converting an EPS to an SVG file 🧚. Default is"sk".Tgif.3DLook: [true,false] — set it tofalseand there's no 3D decoration of windows and buttons. Default istrue👑Tgif.XpmDeckToGifAnim: STRING — STRING is a command used to convert a list of GIF files to a GIF animation file 🎞️. It must not contain any%ssubstring. Default is"gifsicle -lforever --delay 10". Gifsicle's home page is<URL:http://www.lcdf.org/gifsicle/>. You can also set this X default to"whirlgif -loop -time 10". Whirlgif's home page is<URL:http://www.msg.net/utility/whirlgif/>.Tgif.GifAnimExplode: STRING — STRING is a command used to explode an animated GIF file into its constituent GIF files 💥. It must not contain any%ssubstring. The constituent GIF files must have the following file names: if the animated GIF file is named"foo.gif", the constituent GIF files must be named"foo.gif.0","foo.gif.1", etc. Default is"gifsicle -eU". Gifsicle's home page is<URL:http://www.lcdf.org/gifsicle/>.Tgif.Btn3PopupModeMenu: [true,false] — set it totrueand pressing the right mouse button in the canvas window will generate the Mode Menu 🖱️. Default isfalse.Tgif.ScriptFraction: NUMBER — this is the size of the super/subscript relative to the size of the normal text 📏. The value must be between0.2and0.8. Default is0.6.Tgif.DeleteNextCharWithDelKey: [true,false] — set it totrueand pressing the Delete key on the keyboard will delete the character to the right of the cursor in text mode ⌨️. Default istrue.- **
Tgif.SquareDoubleByteFonts: FONT_SPEC1 FONT_SPEC2 ...** — starting with version4.0` of tgif, double-byte fonts are supported 🎉. But only double-fonts where every character has the same width and height are supported. Go see the SQUARE DOUBLE FONTS section for the details. Tgif.DefaultSingleByteFont: STRING — using input methods (specified by theTgif.DoubleByteInputMethodX default below), you can mix english (single-byte) substrings inside a double-byte string 🀄. The font used for that english substring is specified by this X default. Default isTimes.Tgif.@@@ShowFontChar: OCTAL STRING — OCTAL STRING specifies a double-byte octal character used to represent a double-byte font in the Choice Window when that font is selected ✨.@@@should be replaced by the name of the double-byte font. See the SQUARE DOUBLE FONTS section for examples.Tgif.@@@ConvFromUTF8: STRING — STRING is a command used to convert a UTF8 encoded string into a string to be pasted into a text object when the current font is a double-byte font whose name matches@@@🌸. See the SQUARE DOUBLE FONTS section for examples.Tgif.@@@ConvToUTF8: STRING — STRING is a command used to convert a selected string (whose font name matches@@@and is a double-byte font) to be copied to the clipboard into a string in the UTF8 format 💫. See the SQUARE DOUBLE FONTS section for examples.Tgif.DoubleByteInputMethod: STRING — this specifies the input method for double-byte fonts 🈶. Currently these values are supported:"xcin","chinput","kinput2","xim", and"tgtwb5". If you're onxcin-2.5or above, please use"xim"instead of"xcin". The"tgtwb5"input method is built into tgif and can take an optional parameter (by appending",FONTNAME"after"tgtwb5") specifying a Big5 X font name used when selecting a character. IfFONTNAMEisn't specified,"-taipei-fixed-medium-r-normal--16-150-75-75-c-160-big5-0"will be used. See the SQUARE DOUBLE BYTE FONTS section for details 💜Tgif.UseNKF: [true,false] — set it totrueand Network Kanji Filter (NKF) will be used. Default isfalse🗾Tgif.CopyAndPasteJIS: [true,false] — set it totrueand copying/pasting text strings will go through an additional JIS to EUC conversion 🔄. Default isfalse.Tgif.PreeditType: [overthespot,root] — if set tooverthespot, over-the-spot preediting will be used 👀. Default isroot.Tgif.Lang: STRING — this specifies the locale 🌍. The environment variableLANGcan override this setting.Tgif.Modifiers: STRING — this specifies the locale modifiers 🎛️. The environment variableXMODIFIERScan override this setting.Tgif.ConvSelection: STRING — this specifies the name of the selection used in convertingkinput2strings ✍️. Default value is_JAPANESE_CONVERSION.Tgif.VisibleGridInSlideShow: STRING — set it to"true"and grids will be visible in slideshow mode 📊. Default isfalse.Tgif.SmoothScrollingCanvas: [off,jump,smooth] — if set tosmooth, scrolling the main canvas window will be smooth 🌊. However, there may be a delay when scrolling starts, to cache the image. If set tojump, scrolling the main canvas window will be jumpy. If set tooff, scrolling the main canvas window will not change the canvas until the mouse button is released. Default isjump.Tgif.LightGrayColor: COLORSTRING — the color for the background of buttons, menus, etc. Default?gray75. soft, subtle, iconic.Tgif.DarkGrayColor: COLORSTRING — the color for the shadow of buttons, menus, etc. Default isgray50. the drama of a good drop shadow 💅Tgif.DefaultObjectBackground: COLORSTRING — the color used for the background of objects. By default, the default background color is used. (Yes bestie, that sentence is doing a little ouroboros moment, but that's what it says 🌀)Tgif.UseImagePixelsForTrueColorExport: [true,false] — if you set it totrue, the color table of an exported XPM/GIF file gets pulled from the actual image pixels when you're on a TrueColor visual. Default isfalse.Tgif.DialogboxUse3DBorder: [true,false] — set it tofalseand dialogboxes just... won't have 3D borders. Do this with X servers like X-Win32, because those dialogboxes already come with 3D borders and double borders are giving visual clutter 😭 Default istrue.Tgif.MenuFontSet: STRING — only used iftgifwas compiled with theENABLE_NLScompiler option. STRING is a list of fonts for menus. You can set STRING tononeto say "nah, no menu font set." Default is"-*-helvetica-medium-r-normal--12-*-*-*-*-*-*-*,-*-*-medium-r-*--12-*-*-*-*-*-*-*".Tgif.MsgFontSet: STRING — again, only iftgifwas compiled withENABLE_NLS. STRING is a list of fonts for status messages, andnonemeans don't use a message font set. Default is"-*-helvetica-medium-r-normal--12-*-*-*-*-*-*-*,-*-*-medium-r-*--12-*-*-*-*-*-*-*".Tgif.BoldMsgFontSet: STRING — sameENABLE_NLSdeal. STRING lists fonts for messageboxes, andnonemeans no bold message font set. Default is"-*-helvetica-bold-r-normal--12-*-*-*-*-*-*-*,-*-*-medium-r-*--12-*-*-*-*-*-*-*".Tgif.BoldMsgFontDoubleByte: [true,false] —ENABLE_NLSonly, again. Set it totrueif the strings in your messageboxes might have double-byte characters in them. Default isfalse.Tgif.LocaleDir: STRING —ENABLE_NLS-only club member. STRING is a full path name of a locale directory.Tgif.PsRegMarksInTiledPageMode: [true,false] — set ittrueand little crosshairs get drawn at the corners that define the clipping regions whenever you print/export PS/EPS files in tiled page mode. How grey are those crosshairs? That's decided by theTgif.PsRegMarksGrayX default. Default isfalse.Tgif.PsRegMarksGray: NUMBER — the greyness of those crosshairs, whenTgif.PsRegMarksInTiledPageModeistrue. Default value is0.95.Tgif.PSFontAliases: PSFONTALIAS_SPEC1 PSFONTALIAS_SPEC2 ... — font aliases can stand in for different encodings etc. Go read thePOSTSCRIPT CHARACTER ENCODING FOR INTERNATINOAL CHARACTERSsection for the details, bestie 📖Tgif.DomainInIni: [true,false] — set ittrueand domain info gets loaded from the~/.Tgif/domain.inifile, and every menu item in the Domain submenu of the File Menu gets enabled. Default isfalse.Tgif.UndoRedoRestoreDrawingMode: [true,false] — set ittrueand the drawing mode you had right before an undo/redo gets restored after that undo/redo. Default istrue.Tgif.MenuRowsBeforeScroll: NUMBER — the max number of rows in a user-specifiable text menu (think the Font Menu, the FontSize Menu) before a vertical scrollbar just auto-appears. Default value is20.Tgif.MenuColsBeforeScroll: NUMBER — the max number of rows in a user-specifiable bitmap menu (think the Color Menu) before a horizontal scrollbar auto-appears. Default value is26.Tgif.PngToXpm: STRING — the command that converts a PNG file to an XPM file. STRING must contain a%ssubstring, which gets swapped out for the full path name of the PNG file. Default is"pngtopnm %s | pnmdepth 255 | ppmquant 222 | ppmtoxpm".Tgif.JpegToXpm: STRING — the command that converts a JPEG file to an XPM file. STRING must contain a%ssubstring, replaced by the full path name of the JPEG file. Default is"djpeg -gif -color 222 %s | giftopnm | ppmtoxpm".Tgif.PbmToXbm: STRING — the command that converts a PBM file to an XBM file. STRING must contain a%ssubstring, replaced by the full path name of the PBM file. Default is"pbmtoxbm %s".Tgif.PgmToXpm: STRING — the command that converts a PGM file to an XPM file. STRING must contain a%ssubstring, replaced by the full path name of the PGM file. Default is"ppmtoxpm %s".Tgif.PpmToXpm: STRING — the command that converts a PPM file to an XPM file. STRING must contain a%ssubstring, replaced by the full path name of the PPM file. Default is"ppmquant 222 %s | ppmtoxpm".Tgif.XpmToPng: STRING — the command that converts an XPM file to a PNG file. STRING must contain a%ssubstring, replaced by the full path name of the XPM file. Default is"xpmtoppm %s | pnmtopng".Tgif.PngFileExtension: STRING — the file extension for a PNG file. Default is"png"(lower case, she's specific 💅).Tgif.XpmToJpeg: STRING — the command that converts an XPM file to a JPEG file. STRING must contain a%ssubstring, replaced by the full path name of the XPM file. Default is"xpmtoppm %s | cjpeg".Tgif.PpmToGif: STRING — the command that converts a PPM file to a GIF file. STRING must contain a%ssubstring, replaced by the full path name of the PPM file. Default is"ppmquant 222 %s | ppmtogif".Tgif.PpmToPng: STRING — the command that converts a PPM file to a PNG file. STRING must contain a%ssubstring, replaced by the full path name of the PPM file. Default is"pnmtopng %s".Tgif.PpmToJpeg: STRING — the command that converts a PPM file to a JPEG file. STRING must contain a%ssubstring, replaced by the full path name of the PPM file. Default is"cjpeg %s".Tgif.Ppm6ToXpm3: STRING — the command that converts a PPM (P6) file to a version 3 XPM file. STRING must contain a%ssubstring, replaced by the full path name of the PPM file. Default is"ppmtoxpm %s".Tgif.PpmQuantize: STRING — the command that quantizes the colors of a PPM file down to a specified number. STRING must contain (1) a%dsubstring, replaced by the number of colors to reduce to, and (2) a%ssubstring, replaced by the full path name of the PPM file. Default is"pnmquant %d %s".Tgif.PpmFSQuantize: STRING — same idea as above but using the Floyd-Steinberg half-tone algorithm to quantize the colors of a PPM file down to a specified number. STRING must contain (1) a%dsubstring, replaced by the number of colors to reduce to, and (2) a%ssubstring, replaced by the full path name of the PPM file. Default is"pnmquant -fs %d %s".Tgif.JpegFileExtension: STRING — the file extension for a JPEG file. Default is"jpg"(lower case).Tgif.ProducedBy: STRING — when you print/export PS/EPS files, STRING shows up in a%%ProducedByline in the exported PS/EPS file. Please put your name and e-mail address in STRING, bestie, give yourself the credit you deserve 🫶 Default is"(unknown)".Tgif.Editor: STRING — the text editor to use for editing attributes. STRING must contain two%ssubstrings, replaced by the window title and the full path name of the text file. Like, you could use"xemacs -title '%s' '%s'". Default is"xterm -title '%s' -e vi '%s'".Tgif.GoHyperSpaceInSlideShow: [true,false] — set ittrueand hyperspace mode gets entered whentgifenters slideshow mode. Default isfalse.Tgif.LineWidthIndexInSlideShow: NUMBER — the line width index to use whiletgifis in slideshow mode. Default value is4.Tgif.MaxRecentFiles: NUMBER — the max number of files to remember in the recently used file list. Default value is10.Tgif.ResetOriginOnAdvancePage: [true,false] — set ittrueandtgifscrolls to the left-top corner of the page when pages are advanced. Default isfalse.Tgif.UseMeasureTooltip: [true,false] — set ittrueand the cursor location plus the width and height of the object you're drawing/dragging/stretching show up in a tooltip window. Heads up: this X default only does anything ifTgif.ShowMeasurementistrue. Default isfalse.Tgif.MeasureTooltipXFollowMouse: [true,false] — set ittrueand the X position of the measurement tooptip follows the mouse. Default isfalse.Tgif.MeasureTooltipYFollowMouse: [true,false] — set ittrueand the Y position of the measurement tooptip follows the mouse. Default isfalse.Tgif.MeasureTooltipHorizontalPosition: [left,center,right] — pins the X position of the measurement tooltip toleft,center, orright. This X default only takes effect whenTgif.MeasureTooltipXFollowMouseisfalse. Default isleft.Tgif.MeasureTooltipVerticalPosition: [top,middle,bottom] — pins the Y position of the measurement tooltip totop,middle, orbottom. This X default only takes effect whenTgif.MeasureTooltipYFollowMouseisfalse. Default istop.Tgif.MeasureTooltipVerbose:[true,false]— set it totrueand the tooltip window will spill extra tea about where objects are and how big they are. Default isfalse. 💅Tgif.NoMinWinSize:[true,false]— set it tofalseand tgif keeps a minimum window size so the whole panel window is always visible. The catch? Some window managers will lowkey show the wrong window size when you resize. This setting is literally just hanging around for compatibility reasons. And if you set it totrue, side effect alert 🚨: the menubar will no longer automatically wrap around whenTgif.MinimalMenubaris set totrue. Default istrue.Tgif.AutoWrapMenubar:[true,false]— set it totrueand the menubar wraps around automatically, bestie. And heads up: ifTgif.MinimalMenubaris set tofalse, the menubar will always wrap around automatically anyway. Default isfalse.Tgif.AutoEPSPreviewBitmap:[true,false]— set it totrueand when you import a PS/EPS file, tgif will auto-generate a preview bitmap if the file doesn't already have one. Default isfalse.Tgif.PsToXbm:STRING— thisSTRINGis the command used to convert a PS file to an XBM file. It must contain a single%ssubstring, which gets swapped out for the full path name of the PS file. 🫶 Fair warning tho: that command usually makes a bitmap way bigger than the image actually in the file, and tgif trims out the blank space automatically, kinda like howpbmtoepsidoes it. Default is:
gs -q -dNOPAUSE -sDEVICE=pbm -sOutputFile=- -- "%s" | pbmtoxbm
Tgif.TmpDirInHomeDir:[true,false]— set it totrueand tgif uses the$HOME/.Tgifdirectory as the temporary directory (unless theTgif.TmpDirX default below is being used), and the compiler option-DTMP_DIRgets ignored. Default isfalseif the-D_TMP_DIR_IN_HOME_DIRcompiler option is used. Default istrueif the-D_TMP_DIR_IN_HOME_DIRcompiler option is not used.Tgif.TmpDir:STRING—STRINGnames a directory to use as the temporary directory. Ngl, using this X default is discouraged, especially if tgif was compiled with-DUSE_XT_INITIALIZEand an X resource file found in the directory search path specified by the$XAPPLRESDIRenvironment variable is being used. By default, tgif uses/tmpas the temporary directory. ✨Tgif.ThumbnailGeometry:WIDTHxHEIGHT— sets the geometry of thumbnails. Default is160x120.Tgif.ThumbnailPadding:NUMBER— the padding (in pixels) for thumbnail images. Default value is8.Tgif.ThumbnailXGap:NUMBER— the horizontal gap (in pixels) for thumbnail images. Default value is16.Tgif.ThumbnailYGap:NUMBER— the vertical gap (in pixels) for thumbnail images. Default value is0.Tgif.ThumbnailX:NUMBER— the starting x location (in pixels) for thumbnail images. Default value is32.Tgif.ThumbnailY:NUMBER— the starting y location (in pixels) for thumbnail images. Default value is32.Tgif.ShowWireSignalName:[true,false]— set it tofalseand when you're connecting ports, tgif automatically places the signal name and hides it. Otherwise you get prompted to place the signal name, and it stays visible. Default istrue.Tgif.LandscapePdfSetPageDevice:(obsolete)— this X default became obsolete in tgif-4.1.42 because the name is straight-up misleading 💀. Please seeTgif.PdfSetPageDevicebelow.Tgif.PdfSetPageDevice:[true,false]— set it totrueand when exporting PDF (or PS) files, tgif will use the PostScriptsetpagedevicecommand to specify the paper size in the generated PostScript file before callingps2pdf(1)(if you're exporting in PDF format). This shouldn't even be necessary (and it's considered a bug inps2pdf). In the future, this X default can be used to turn off the generation of thesetpagedevicecommand whenps2pdfcan handle landscape PostScript files correctly.Tgif.DeleteCmdAsCut:(obsolete)— this X default became obsolete in tgif-4.2.3. Now<Cntrl>xbinds to the Cut command. glow up fr ✨Tgif.EnableMouseWheel:[true,false]— if set tofalse, Button4 and Button5 mouse wheel scrolling events get ignored. Default istrue.Tgif.Btn2PopupMainMenu:[true,false]— if set tofalse, Button2 events won't bring up the Main Menu in the canvas window. Default istrue.Tgif.NoChoiceWindow:[true,false]— if set totrue, no Choice and Message Windows get shown initially. Default isfalse.Tgif.UseXPmVersion1ForXPmDeck:[true,false]— the setting of this X default should depend on the setting of theTgif.XpmDeckToGifAnimX default above. Set it totrueand an XPM1 file is generated when a deck of X11 pixmap objects is being converted to a GIF animation file, regardless of whatTgif.XPmOutputVersionsays. Default istrue.Tgif.SlideShowWindowOffsets:X_OFFSET,Y_OFFSET— these numbers are how many pixels to adjust for slideshow mode. Give only one value and both X and Y offsets get set to that same value. Default values are all0's.Tgif.SlideShowBorderColor:COLORSTRING— the color used for the area outside the paper boundary in slideshow mode. By default, the border color is the same as the background color. 🎀Tgif.ConvertToBezierSegments:NUMBER— how many segments are used when converting a polyline/spline object to a Bezier curve. Default value is50.Tgif.TickMarkSize:NUMBER— the size of a tick mark used when tick marks get added at a vertex of a polyline/polygon/spline. Default value is8.Tgif.NoModeWindow:[true,false]— if set totrue, no Mode Window gets shown initially. Default isfalse.Tgif.MakeUnsavableInSlideShow:[true,false]— if set totrue, the current file gets made unsavable when slideshow mode is entered. (And btw, if the current file contains auto page numbering objects, the file gets made unsavable regardless of this X default's setting.) Default isfalse.Tgif.SingleByteInputMethod:STRING— this specifies the input method for single-byte fonts. Currently, only"xim"is supported.Tgif.IgnoreSlideShowOffsetsInFile:[true,false]— if set tofalse, the slideshow offsets stored in a file will override theTgif.SlideShowWindowOffsetssetting. Default istrue.Tgif.ItalicMsgFont:STRING— theSTRINGnames an italic font used in some buttons. If this X default isn't specified butTgif.MenuFontis, then this takes on the value ofTgif.MenuFont. If neither this X default norTgif.MenuFontis specified, the default font is used in italic messages.Tgif.ItalicMsgFontSet:STRING— this X default is only used if tgif was compiled with theENABLE_NLScompiler option. TheSTRINGnames a list of fonts used in messageboxes.STRINGcan benoneto say "don't use italic message font set". The default is:
-*-helvetica-medium-o-normal--12-*-*-*-*-*-*-*,-*-*-medium-r-*--12-*-*-*-*-*-*-*
Tgif.BoldItalicMsgFont:STRING— theSTRINGnames a bold italic font used in some text. If this X default isn't specified butTgif.MenuFontis, this takes on the value ofTgif.MenuFont. If neither this X default norTgif.MenuFontis specified, the default font is used in bold italic messages.Tgif.BoldItalicMsgFontSet:STRING— this X default is only used if tgif was compiled with theENABLE_NLScompiler option. TheSTRINGnames a list of fonts used in some text.STRINGcan benoneto say "don't use bold italic message font set". The default is:
-*-helvetica-bold-o-normal--12-*-*-*-*-*-*-*,-*-*-medium-r-*--12-*-*-*-*-*-*-*
Tgif.ExternalPsToEpsi:[true,false]— if set totrue, running thepstoepsi()internal command just invokespstoepsiexternally. Default isfalse.Tgif.GsPath:STRING— theSTRINGnames a full path name of thegs(ghostscript) program. Default is"gs"(which implies thegsexecutable is in yourPATH). 🦋Tgif.CompoundObjWithTextStretchableForPSE:[true,false]— if set tofalse, when you run the Precise Scale Everything command, a compound object won't be stretched if it contains a text subobject. This X default only does anything if tgif is in non-stretchable text mode. (If tgif is in stretchable text mode, this X default is ignored.) Default isfalse.Tgif.HideWindowsInSlideShow:[true,false]— if set tofalse, tgif keeps all windows visible in slideshow mode. Otherwise, only the canvas window is visible in slideshow mode. Default istrue.Tgif.PSDistillerNoImageCompress:[true,false]— if set totrue, tgif generates PostScript code so that images in a generated PostScript file won't get compressed by a distiller program likeps2pdf. Default isfalse.Tgif.AdditionalPSSetup:STRING— if specified, the PostScript line given bySTRINGgets inserted at the end of PostScript file setup (right before%%EndSetup).
Fr fr, only use this option if you are very familiar with PostScript. 👑
Here's an example that asks distiller programs not to compress bitmap images:
Tgif.AdditionalPSSetup: \n\
systemdict /setdistillerparams known \n\
{ << /AutoFilterGrayImages false \n\
/AutoFilterColorImages false \n\
/ColorImageFilter /FlateEncode \n\
/GrayImageFilter /FlateEncode \n\
>> setdistillerparams } if
Tgif.PSFontNeedCharSubs:FONTSUB_SPEC1 FONTSUB_SPEC2 ...— okay so eachFONTSUB_SPECis written asFONTNAME=TOKENNAME, whereFONTNAMEis the name of a PostScript font andTOKENNAMEis the name of the extension for theTgif.PSCharSubs_TOKENNAMEX default. And here's the tea: for any PostScript font name that begins with a string matching theFONTNAMEpart of aFONTSUB_SPEC, tgif goes and reads thatTgif.PSCharSubs_TOKENNAMEX default to figure out which characters get substituted. 💅
Now for fonts that aren't iso8859-1 encoded, the non-ASCII portion of the font (aka the characters with bit 7 on) gets reencoded by default as if it were iso8859-1 encoded when the PS output is generated. If that's not what you want, you can substitute different named PS characters for the characters with bit 7 on instead. 💖 Also go peek at the POSTSCRIPT CHARACTER ENCODING FOR INTERNATINOAL CHARACTERS section for an example, bestie.
Tgif.PSCharSubs_TOKENNAME:PSCHARSUBS_SPEC1 PSCHARSUBS_SPEC2 ...—TOKENNAMEhas to match aFONTSUB_SPECin theTgif.PSFontNeedCharSubsX default, no exceptions. The format forPSCHARSUBS_SPECisOLDCHARCODE/NEWCHARNAME, whereOLDCHARCODEis a character code in octal format andNEWCHARNAMEis a PostScript character name to use. More deets? The POSTSCRIPT CHARACTER ENCODING FOR INTERNATINOAL CHARACTERS section has you covered. ✨Tgif.DrawTextFuncKey_F#: INTERNAL COMMAND LIST — this one sets up the correspondence between a function key and a list of internal commands. When function keyF#is pressed while tgif is in the text drawing mode, that matching list of internal commands gets executed. Heads up though: tgif only recognizes function keysF1throughF12. That's the whole squad. 🎀Tgif.PasteFromXSelectionOnly: [true,false] — if you set it tofalse, then when tgif fails to do a paste via the X Selections mechanism, it'll attempt the old style paste instead (which directly fetches bytes from the X server). This is mainly for use with older X servers, iykyk. The default istrue.Tgif.PasteFromSelectionTimeout: NUMBER — how many seconds a paste operation gets before it times out. The default value is10. ⏳Tgif.LengthLimit256InInsertChar: [true,false] — set it totrueand the maximum number of characters per line of text is capped at256. Any extra characters? Ignored, sorry babe. The default isfalse.Tgif.JpegToPpm6: STRING — theSTRINGhere is a command used to convert a JPEG file to a PPM file in the P6 format. It must contain a%ssubstring that gets replaced by the full path name of the JPEG file. The default is:
djpeg -ppm "%s"
Tgif.PngToPpm6: STRING — same energy, but for PNG → PPM in the P6 format. TheSTRINGmust contain a%ssubstring to be replaced by the full path name of the PNG file. The default is:
pngtopnm "%s"
Tgif.ObjectShadowOffsets:X_OFFSET,Y_OFFSET— these numbers are how many pixels get offseted when creating a generic object shadow. Give it just one value and both the X and Y offsets get set to that same value, cute. The default values are all2's. 🦋Tgif.ObjectShadowColor: COLORSTRING — the color used for the generic object shadow. The default value is"#c0c0c0".Tgif.IgnoreObjectShadowInfoInFile: [true,false] — set it tofalseand the generic object shadow info stored in a file will override theTgif.ObjectShadowOffsetsandTgif.ObjectShadowColorsettings. The default istrue.Tgif.ReportMissingFonts: [true,false] — set it totrueand when tgif starts up, any missing X fonts get printed to the terminal. The default isfalse.Tgif.CustomPatternDir: STRING —STRINGis a directory that contains custom fill and pen patterns. Any valid XBM file — encoding a bitmap of arbitrary dimensions, namedpat#.xbm(for3<=<=31) — sitting in this directory will replace the corresponding default pattern. 🎨Tgif.EnableTrueColorImages: [true,false] — set it totrueand, on a TrueColor display, PPM and JPEG objects will use 24-bit color. Important: tgif must be compiled with zlib support to enable this. The default istrue.Tgif.AutoRotatePivot: [true,false] — set it totrueand the user-specified rotation pivot gets disabled. The default isfalse.Tgif.RightMargin: STRING — theSTRINGspecifies the right margin. And it must be specified with a unit, bestie — the choices are"pixel","in", or"cm". The default is"1 in"ifTgif.GridSystemis"English"and"2.5 cm"ifTgif.GridSystemis"Metric".Tgif.EnableRightMargin: [true,false] — set it totrueand a simple right-margin gets used when you're entering text. To be clear though, this is not a full-featured right-margin. 😭 It's only activated under these conditions: the text object is not transformed, the text is left-justified, the text cursor is not inside a superscript or a subscript, there's no zoome, andTgif.EditTextSizeis not used. The default isfalse.Tgif.NoOrientationIfPdfSetPageDevice: [true,false] — set it totrueand the"%%Orientation:"line is not generated in the PostScript file if"setpagedevice"is active when exporting a PS/EPS/PDF file. Go readTgif.PdfSetPageDeviceabove for the context. The default isfalse.Tgif.PNGExportHasTransparentColor: [true,false] — set it totrueand the color specified by theTgif.PNGExportTransparentColorX default gets made transparent when printing in the PNG format. The default isfalse.Tgif.PNGExportTransparentColor: COLORSTRING — this specifies the color that gets made transparent when printing in the PNG format. By default, the default background color is used. 🌈Tgif.PpmToPngWithTransparentColor: STRING — theSTRINGis a command used to convert a PPM file to a PNG file with a transparent color. It must contain exactly two%ssubstrings — those get replaced by the transparent color and the full path name of a PPM file. The default is"pnmtopng -transparent '%s' '%s'".Tgif.EnableThresholdFloodReplaceColor: [true,false] — set it totrueand threshold-based Flood Fill and Replace Color get used. The default isfalse.Tgif.FloodReplaceColorThreshold:RED_THRESH,GREEN_THRESH,BLUE_THRESH— so in threshold-based Flood Fill and Replace Color, after a pixel is selected, any pixels with colors similar to the selected pixel also change color. That similarity is defined by these 3 threshold values. Each value must be between 0 and 255, inclusive. The default values are all15's. 💅Tgif.UseStdPalette8: [true,false] — set it totrueand a standard 8 palette gets used as the startup colors. These colors correspond to all 8 combination of0x00and0xffin red, green, and blue color components. If you use this X default, theTgif.AdditionalColorsX default can be used to specify additional colors when tgif starts up. The default isfalse.Tgif.UseStdPalette27: [true,false] — set it totrueand a standard 27-color palette is the startup colors. These correspond to all 27 combination of0x00,0x80, and0xffin red, green, and blue color components. If you use this X default,Tgif.AdditionalColorscan specify additional colors when tgif starts up. The default isfalse.Tgif.UseStdPalette64: [true,false] — set it totrueand a standard 64-color palette becomes the startup colors. These correspond to all 64 combination of0x00,0x55,0xaa, and0xffin red, green, and blue color components. If you use this X default,Tgif.AdditionalColorscan specify additional colors when tgif starts up. The default isfalse.Tgif.UseStdPalette216: [true,false] — set it totrueand a standard 216 palette is used as the startup colors. These are known as Mobile Web-safe colors and they correspond to all 216 combination of0x00,0x33,0x66,0x99,0xcc, and0xffin red, green, and blue color components. If you use this X default,Tgif.AdditionalColorscan specify additional colors when tgif starts up. The default isfalse. 🔥Tgif.UseMobileWebSafePalette: [true,false] — literally identical toTgif.UseStdPalette216. Same thing, different name, we love a rebrand. ✨Tgif.UseOpenOfficeGalaxyPalette: [true,false] — set it totrueand the OpenOffice Galaxy (53-color) palette gets used as the startup colors. If you use this X default,Tgif.AdditionalColorscan specify additional colors when tgif starts up. The default isfalse.Tgif.UseOpenOfficeGooglePalette: [true,false] — set it totrueand the OpenOffice Google (80-color) palette is used as the startup colors. If you use this X default,Tgif.AdditionalColorscan specify additional colors when tgif starts up. The default isfalse.Tgif.AdditionalColors:COLOR1, COLOR2 ...— if any of theTgif.ColorFromXPixmap,Tgif.UseStdPalette8,Tgif.UseStdPalette27,Tgif.UseStdPalette64,Tgif.UseStdPalette216,Tgif.UseMobileWebSafePalette,Tgif.UseOpenOfficeGalaxyPalette, orTgif.UseOpenOfficeGooglePaletteX defaults is used, you can specify additional startup colors with this X default. And because color names can contain space characters, the colors must be separated by commas. 🎀Tgif.DefaultColor: COLORSTRING — this specifies the default color to use if a certain color can not be found. It has precedence over theTgif.DefaultColorIndexX default. If this X default is not specified, thenTgif.DefaultColorIndexdetermines the default color.
Tgif.GifToPpm6: STRING The STRING specifies a command used to convert a GIF file to a PPM file in the P6 format. The STRING must contain a %s substring to be replaced by the full path name of the GIF file. The default is:
giftopnm "%s"
🌍 ENVIRONMENT VARIABLE 🌍
TGIFPATH— this environment variable should be set such that the files mentioned in the FILES section below can be found. 🫶TGIFICON— okay so bestie, this env var should be set to the name of the object file that gets displayed whentgifis iconified. By default, it's set totgificon. If it starts with a/character, then the absolute path is used; otherwise, the icon file is assumed to be$TGIFPATH/$TGIFICON. 💅TGIF_[Domain]— obsoleted. periodt. 💀
📁 FILES 📁
$TGIFPATH/tgificon.objcontains the default tgif icon. 🎀$TGIFPATH/keys.objcontains a summary of the non-alphanumeric key bindings. ⌨️
🧪 PROLOG/C TESTDRIVE 🧪
In the tgif distribution, there are three Prolog files which illustrate a simple Prolog driver. tgif.pl contains predicates for parsing tgif files (both .obj and .sym). frontend.pl contains predicates for talking to Prolog engines, such as that of Quintus and SISCtus, through the foreign function interface. To use frontend.pl, frontend11.o needs to be built (which requires the frontend11.o entry to be uncommented from the makefiles). Finally, testdrive.pl contains a program which will print out the ID files of all objects in the current drawing, if tgif is escaped with the Solve() (or #s) command. This is also a good way of finding out the structure of a tgif file (especially because the structure is not documented due to the complexity introduced to keep tgif compatible with files created by older versions). 🧚
A very simple C driver, testdrive.c, is also provided with the tgif distribution which perform the same function as the Prolog driver. The extra code present in this file (and not present in tgif.c) is used to illustrate how the in-memory objects and attributes can be traversed and how new objects can be created and manipulated. 💖
👀 SEE ALSO 👀
okay so go read these, bestie: latex(1L), lpr(1), ghostscript(1), env(1), X(1), dvips(1), csh(1), pbmplus(1), netpbm(1), djpeg(1), bitmap(1), XPM(1), netpbm(1), xfontsel(1), xlsfonts(1), xgrabsc(1), xloadimage(1), xsnap(1), sxpm(1), xv(1), pstoepsi(1), Mosaic(1), bggen(1), rand(3C), ps2pdf(1). 💜
🌈 IDIOSYNCRASIES 🌈
When any of the ``escape to driver'' commands are (accidentally) executed, the current content of the drawing is saved into tmpmodel.obj if the drawing indicates that it is a .obj file; then tgif escapes to the driver and returns right away. If the drawing indicates that it is a .sym file, then the content is saved into tmpmodel.sym, but tgif does not return to the driver. 😭
The paste operation works on a cut buffer generated by tgif or by non-tgif tools (such as xterm). If the cut buffer is not generated by tgif, its content is treated as a collection of ASCII character strings, which is inserted into the current drawing as a text object (current settings for text objects are used to create the text object). If the cut buffer is generated by tgif, then all the current settings are ignored. 📋
The font sizes are the screen font sizes (which correspond to the X fonts that are used to draw the text on the screen). They appear smaller on the printout. When a 24 point text is printed, it would correspond to about a 13.5 point PostScript text. This is because tgif treats 128 pixels as an inch, and PostScript treats 72 points as an inch. 📏
Because characters supported by X11 and PostScript are different, not all the characters, especially in the range 128 to 255 (or \200 to \377), which are supported by X11, but are not accepted by tgif. Furthermore, in order to print the supported subset of these characters, character codes must be re-encoded. Therefore, if one would like to hack tgif to support other personalized fonts, one should be careful about the re-encoding mechanism. 🔤
The grids are not absolute; they are specified as screen pixels, and they scale with the current zoom. For example, if the grid is set at 16 pixels at maximum zoom, and if the user zooms out once, objects can be drawn, moved, or stretched at 16 screen pixel increments, but this corresponds to 32 pixels in the real coordinate system. 📐
If the vertical text spacing is set to negative values, highlighted text will look a little strange due to XOR operations. If the vertical text spacing is set to be greater than 100 or less than -100, the panel window will not be cleared properly; to clear the panel window, the user may have to close the tgif window and then open it again. 🪟
As described in the TGIF SUBWINDOWS section, in constrained move mode, if both endpoints of a not-selected polyline lie inside the object being moved, then the whole polyline is moved. This may look strange sometimes because, for example, if one starts with a line segment pointing to an object, just moving the object will cause the line segment to be ``stretched''; however, if one eventually moves the object so that the other endpoint is also inside the object, any future movement of the object will cause the whole line segment to move (instead of just moving the original endpoint). The moving of the vertex which is the neighbor of a moved endpoint may also look strange at times. At this point, one should switch to the unconstrained move mode. 🌀
Another idiosyncrasy with respect to the constrained move is that right after duplicating an object, the constrained move is disabled temporarily because it is assumed that at this point the user would want to move the new object to a desirable position, and only after this new object is ``settled down'', the constrained move will be re-enabled. Settling down is signified by doing something other than moving the new object. ✨
Locked objects can be deleted. 🔓
Under the Edit Menu, PasteFromFile() reads a file into the drawing. Pasting from a file is different from the normal pasting operation where copying is performed in something like xterm because tabs are automatically converted to spaces. Tabs are ignored when pasting from a file. 📄
When printing a multipage drawing, all pages (even the ones that contains no objects) will be printed. Using the PrintOnePage() command under the Page Menu one can print the selected page (in stacked page layout mode, this is the current page; in tiled page layout mode, the user is prompted to select a visible page). 🖨️
Tgif can be setup to use its own icon window (the Tgif.NoTgifIcon and the Tgif.UseWMIconPixmap X defaults must both be set to false). However, it may confuse certain window managers. So, if the effect is undesirable, one can set the Tgif.UseWMIconPixmap X defaults to true. 🪟
🐛 BUGS 🐛
- There seems to be a problem with printing Courier fonts with a non-solid pen on the Apple LaserWriter. (Printing single character does seem to work fine.) As pointed out by the PostScript reference manual, Courier is a
stroked font'', and it is usuallydifficult'' to construct character paths for such types of fonts. However, Courier fonts work fine withghostscript(1)anddxpsview. It's not clear how this problem can be fixed. The author recommends avoiding Courier fonts when printing in color if a non-solid pen is desired. 😭 - Arcs with arrow tips don't look very sharp (the tip is not pointed as in open-splines with arrow tips). 🏹
- At high magnifications, stretching arcs may cause anomalous behavior due to round off errors. 🔍
- When page reduction/magnification is not set at 100%, the markings in the Ruler Windows do not correspond to real measurements. 📏
- Copying/pasting large objects might not work because tgif does not use the ``selection'' mechanism (yet). 📋
- If and when tgif crashes, it will try to save the current content of the drawing in a file called
EmergencySave.obj(orEmergencySave.symif the current drawing specifies a symbol object). Often, the drawing can be restored by loading theEmergencySave.objfile. Nevertheless, if the cause of the crash is that some objects are corrupted (due to programming bugs), then theEmergencySave.objfile may also be corrupted. 💥 - When launching an application, if the command does not end with the
&character and the command does not terminate, tgif also hangs. In this case,kill(1)should be used to send HUP signal to the tgif process if one wants to save the content of tgif inEmergencySave.obj. 🛑 - The file
exec.cmay not compile properly on AIX machines. One might have to add-D_BSDto the DEFINES in either theImakefileorMakefile.noimake. 🛠️
©️ COPYRIGHT ©️
Please see the ``Copyright'' file for details on the copyrights. 📜
PostScript is a trademark of Adobe Systems Incorporated. ™️
📢 STATUS 📢
The current status of tgif can be obtained from tgif's World-Wide-Web home page at <URL:http://bourbon.usc.edu/tgif/>. 🌐
👑 AUTHOR 👑
William Chia-Wei Cheng (bill.cheng@acm.org) <URL:http://merlot.usc.edu/william/usc/> 👑
📚 REFERENCES 📚
- ``A Beginner's Guild to HTML'',
<URL:http://www.ncsa.uiuc.edu/General/Internet/WWW/HTMLPrimer.html>. 📖 - ``CGI - Common Gateway Interface'',
<URL>http://www.w3.org/CGI/overview.html>. 🔗 - ``NCSA Imagemap'',
<URL>http://hoohoo.ncsa.uiuc.edu/docs/tutorials/imagemapping.html>. 🗺️ - ``CERN Clickable Image'',
<URL>http://www.w3.org/hypertext/WWW/Daemon/User/CGI/HTImageDoc.html>. 🖼️
and that's the tea, bestie! this page is from Tgif Version 4.2 Patchlevel 3 and Above, and it's filed under tgif(n). slay. 💅✨
📦 where this page comes from
- fedora 43: tgif 4.2.5-34.fc43 · QPL-1.0 AND HPND
- fedora 44: tgif 4.2.5-35.fc44 · QPL-1.0 AND HPND
- 💖 girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms