# Windows GDI printing typeface management

The Sample.Windows.Printer item in the dm,devices, file is a printer device driver template that controls the behavior
of the various @() functions associated with Windows
GDI printing.

Note: To use this item, it must be copied to another item
with an ID no longer than 12 characters (see [assignfq (Windows) command](https://d3codex.com/tcl/assignfq-windows-command/)).

## Typeface selection control

The @(-340) function allows you to define which Windows typefaces
will be available when setting font characteristics for Windows GDI
printed output (specifically when invoking the @(-321) function which retrieves the typeface name by its relative position
within the @(-340) control string). The example
below illustrates the @(-340) control string of
comma-delimited fields:

```
f,x1b,x01,x40,ly,a,c],tf1,c],tf2,c],tf3,c],tf4,c],tf5,c],tf6,c],tf7,c],tf8,c],
tf9,c],tf10,c],tf11,c],lf12,m20,c&#39;Courier New&#39;,],c&#39;Lucida Console&#39;,],
c&#39;OCR A Extended&#39;,],c&#39;Arial&#39;,],c&#39;Calibri&#39;,],c&#39;Verdana&#39;,],c&#39;Times New Roman&#39;,]
,c&#39;Century&#39;,],c&#39;Lucida Bright&#39;,],c&#39;Brush Script MT&#39;,],c&#39;Edwardian Script ITC
&#39;,],c&#39;Freestyle Script&#39;,],c&#39;French Script MT&#39;,],c&#39;Kunstler Script&#39;,],
c&#39;Old English Text MT&#39;,],c&#39;Stencil&#39;,],c&#39;Onyx&#39;,],c&#39;Playbill&#39;,],c&#39;Ravie&#39;,]
,c&#39;Showcard Gothic&#39;,],x02,<
```
Note: We have broken this string apart (below) to illustrate
the control string fields that pertain to this discussion.

```
f,x1b,x01,x40,ly,a,c],tf1,c],tf2,c],tf3,c],tf4,c],tf5,c],tf6,c],tf7,c]
,tf8,c],tf9,c],tf10,c],tf11,c],lf12,m20
,c&#39;Courier New&#39;,]
,c&#39;Lucida Console&#39;,]
,c&#39;OCR A Extended&#39;,]
,c&#39;Arial&#39;,]
,c&#39;Calibri&#39;,]
,c&#39;Verdana&#39;,]
,c&#39;Times New Roman&#39;,]
,c&#39;Century&#39;,]
,c&#39;Lucida Bright&#39;,]
,c&#39;Brush Script MT&#39;,]
,c&#39;Edwardian Script ITC&#39;,]
,c&#39;Freestyle Script&#39;,]
,c&#39;French Script MT&#39;,]
,c&#39;Kunstler Script&#39;,]
,c&#39;Old English Text MT&#39;,]
,c&#39;Stencil&#39;,]
,c&#39;Onyx&#39;,]
,c&#39;Playbill&#39;,]
,c&#39;Ravie&#39;,]
,c&#39;Showcard Gothic&#39;,]
,x02,<
```
The 31st comma-delimited field above (known as the *max typeface* field) indicates to the function the number of available
typefaces. In this example, `m20` indicates that there
are 20 typefaces available. Immediately following this field are the
actual typefaces presented as a series of two-field pairs. The first
is `c'Courier New'` followed by a field containing
a right square bracket. This defines `Courier New` as
the first typeface. The second is `Lucida Console`, the third is `OCA A Extended`, and so on.

## Adding, replacing and deleting typefaces

You can use an editor to change the names of the typefaces, thereby
replacing one font with another. You can also use an editor to add
or remove typefaces from the list of available fonts. However, be
aware that as you add or remove fonts from the list, the max typeface
field must be updated to indicate the new number of available typefaces.
For example, if you were to add 2 new typefaces to the control string
illustrated above, you would also need to change the max typeface
field to `m22`.

It is also possible (and probably
preferable) to modify the control string programmatically. The example
illustrates a subroutine allows you to add, delete and replace typefaces
in winGDI devices file item:

```
subroutine winGDI_updTypeface.sub(deviceID,Typeface,Action)
*
* Add/delete/replace a typeface in a winGDI devices file item
*
* Arguments:
* deviceID ID of the item in dm,devices,
* Typeface Typeface name to be added to @(-340) string
* Action "add" to add
* "delete" to delete
* "replace##" to replace the ##th entry
*
 if not(assigned(deviceID)) then deviceID = ""
 if not(assigned(Typeface)) then Typeface = ""
 if not(assigned(Action)) then Action = ""
*
 if Typeface = "" then abort "Typeface name is null"
 begin case
 case Action[1,3] = "add"
 case Action[1,3] = "del"
 case Action[1,3] = "rep"
 case 1; abort "No valid Action defined"
 end case
*
 open &#39;dm,devices,&#39; to f.devices else abort 201,&#39;dm,devices,&#39;
 read devItem from f.devices,deviceID else
 abort 202,&#39;dm,devices, &#39;:deviceID
 end
*
 tfStr = "" ;* Extract @(-340) attribute from devices item
* PROGRAMMER&#39;S If the @(-340) string prefix in the devices file
* NOTE: item ever changes, make sure to change the prefix.
 tfStr_prefix = "f,x1b,x01,x40,ly,a,c],tf1,c],tf2,c],tf3,c],"
 tfStr_prefix := "tf4,c],tf5,c],tf6,c],tf7,c],tf8,c],tf9,c],"
 tfStr_prefix := "tf10,c],tf11,c],lf12,m"
 tfStr_pf_len = len(tfStr_prefix)
 tfStr_suffix = "x02,<"
*
 devItem_max = dcount(devItem, char(254))
 devItem_ax = 0
 for devItem_x = 1 to devItem_max
 if devItem<devItem_x>[1,tfStr_pf_len] = tfStr_prefix then
 devItem_ax = devItem_x
 tfStr = devItem<devItem_x>
 devItem_x = devItem_max
 end
 next devItem_x
*
 if tfStr = "" then abort "devices item typeface string not found"
*
 tfStr = tfStr[tfStr_pf_len+1,999]
 tfMax = field(tfStr,",",1)
 tfNames = ""
 for tfName_x = 1 to tfMax
 wIdx = index(tfStr,",C&#39;",tfName_x)
 wNme = field(tfStr[wIdx,999],"&#39;",2)
 tfNames<tfName_x> = wNme
 next tfName_x
*
 updateFlag = 0
 begin case
 case Action[1,3] = "add"
 locate Typeface in tfNames setting tfIdx else
 tfMax += 1
 tfNames<tfMax> = Typeface
 updateFlag = 1
 end
 case Action[1,3] = "del"
 locate Typeface in tfNames setting tfIdx then
 tfMax -= 1
 tfNames = delete(tfNames,tfIdx)
```

```
 updateFlag = 1
 end
 case Action[1,3] = "rep"
 tfIdx = Action &#39;cn&#39;
 if tfIdx >= 1 and tfIdx <= tfMax then
 tfNames<tfIdx> = Typeface
 updateFlag = 1
 end
 end case
*
 if updateFlag then
 tfStr = tfStr_prefix : tfMax : ","
 for tfName_x = 1 to tfMax
 tfStr := "c&#39;" : tfNames<tfName_x> : "&#39;,],"
 next tfName_x
 tfStr := tfStr_suffix
 devItem<devItem_ax> = tfStr
 write devItem on f.devices,deviceID
 end
 close f.devices
*
SubroutineMainExit:
 return
*
* End of source
```
Simple one-line examples of programs that call the above
routine are illustrated below. Note that these examples assume the
presence of a dm,devices, item called `WIN_GDI_PRTR` (which is a copy of the `Sample.Windows.Printer` item).

**To add a typeface:**

```
call winGDI_updTypeface.sub("WIN_GDI_PRTR","Arial","Add")
```
**To delete a typeface:**

```
call winGDI_updTypeface.sub("WIN_GDI_PRTR","Arial","Delete")
```
**To replace a typeface:**

```
call winGDI_updTypeface.sub("WIN_GDI_PRTR","Arial","Replace12")
```

## Available Windows typefaces

To view the
list of typefaces that are available to windows GDI printers, open
the control panel on the D3 Windows server and double-click the *Fonts* item. The Font Name (not the filename) is the name you
use when setting up a new font. You only need to reference the *base name* of the font name. For example, for the font name `Cambria Bold Italic (True Type)` you need only use `Cambria` since the Windows print driver will use your other
font weight and italic @() functions to choose
among the various `Cambria` fonts available in Windows.

---
Source: https://d3codex.com/tcl/windows-gdi-printing-typeface-managementt/ - part of the D3Codex reference.
