IconsImpl.mesa; Written by S. McGregor
Edited by McGregor on August 8, 1983 9:46 am
Last Edited by: Maxwell, January 3, 1983 12:53 pm
Last Edited by: Plass, April 20, 1983 10:00 am
Last Edited by: Wyatt, September 30, 1983 6:49 pm
DIRECTORY
CIFS USING [Close, Error, GetFC, Open, OpenFile, read],
Environment USING [wordsPerPage],
File USING [Capability, GetSize],
Imager USING [black, Context, DrawBitmap, IntegerClipRectangle, IntegerMaskRectangle, IntegerSetXY, SetColor, ShowCharacters, white],
Icons,
Rope USING [Concat, Fetch, Length, Map, ROPE, Substr],
Space USING [Create, Delete, Handle, LongPointer, Map, PageCount, virtualMemory],
UserProfile USING [Token],
VFonts USING [EstablishFont, FONT, FontAscent, RopeWidth];
IconsImpl: CEDAR MONITOR
IMPORTS CIFS, File, Imager, Rope, Space, UserProfile, VFonts
EXPORTS Icons =
BEGIN OPEN Icons;
DrawIcon: PUBLIC ENTRY DrawIconProc = BEGIN
leading: INTEGER = 3;
iconInfo: IconRef ← icons[LOOPHOLE[flavor]];
prefix: Rope.ROPENIL;
IF iconInfo.proc=NIL THEN BEGIN
Imager.SetColor[context, Imager.white];
Imager.IntegerMaskRectangle[context, 0, 0, iconW, iconH];
Imager.SetColor[context, Imager.black];
TRUSTED {Imager.DrawBitmap[context, LOOPHOLE[iconInfo--bits first in record--], iconW/16, [x,y,iconW,iconH]]};
IF iconInfo.label THEN BEGIN
iconFont: VFonts.FONT;
fontHeight: INTEGER;
iy: INTEGER ← y+iconInfo.ly+iconInfo.lh;
segments: LIST OF Rope.ROPE;
IF VFonts.RopeWidth[label, bigIconFont] <= iconInfo.lw THEN BEGIN
iconFont ← bigIconFont;
fontHeight ← bigFontHeight;
segments ← LIST[label];
END
ELSE BEGIN
iconFont ← smallIconFont;
fontHeight ← smallFontHeight;
segments ← Decompose[label, iconInfo.lw, iconFont];
END;
Imager.IntegerClipRectangle[context,
x+iconInfo.lx, y+iconInfo.ly, iconInfo.lw, iy-(y+iconInfo.ly)];
IF iconInfo.invertLabel THEN Imager.SetColor[context, Imager.white];
WHILE segments#NIL DO
segment: Rope.ROPE ← segments.first;
suffix: Rope.ROPEIF segments.rest=NIL OR
segment.Fetch[segment.Length[]-1]='\040 OR
segments.rest.first.Fetch[0]='. THEN NIL ELSE "-";
iy ← iy-fontHeight;
Imager.IntegerSetXY[context, x+iconInfo.lx, iy];
iy ← iy - leading;
Imager.ShowCharacters[context, prefix.Concat[segment.Concat[suffix]], iconFont];
prefix ← " ";
segments ← segments.rest;
ENDLOOP;
END;
END
ELSE iconInfo.proc[flavor, context, x, y, label];
END;
GetFonts: ENTRY PROC = BEGIN
bigIconFont ← VFonts.EstablishFont["Helvetica", 8];
smallIconFont ← VFonts.EstablishFont["Helvetica", 7];
bigFontHeight ← VFonts.FontAscent[bigIconFont];
smallFontHeight ← VFonts.FontAscent[smallIconFont];
END;
bigIconFont: VFonts.FONT;
bigFontHeight: INTEGER;
smallIconFont: VFonts.FONT;
smallFontHeight: INTEGER;
wSlop: INTEGER = 5;
Decompose: PROC [name: Rope.ROPE, width: REAL, font: VFonts.FONT] RETURNS [segments: LIST OF Rope.ROPENIL] =
BEGIN
candidate, useMe: Rope.ROPENIL;
end: INT ← 0;
len: INT ← Rope.Length[name];
haveExtension, inWord: BOOLFALSE;
SkipToNextWord: PROC [c: CHAR] RETURNS [BOOL] = CHECKED {
IF c IN ['A..'Z] OR c = '/ OR c IN ['0..'9] THEN { IF inWord THEN RETURN[TRUE] }
ELSE inWord ← TRUE;
IF c='. THEN RETURN[haveExtension ← TRUE];
end ← end+1; RETURN[FALSE]; };
Build: PROC[start: INT] RETURNS [LIST OF Rope.ROPE] = {
IF start>=len THEN RETURN[NIL];
end ← start+1;
inWord ← FALSE;
IF haveExtension THEN end ← len
ELSE [] ← Rope.Map[base: name, start: end, action: SkipToNextWord];
RETURN[CONS[name.Substr[start, end-start], Build[end]]]; };
Coalesce: PROC[segs: LIST OF Rope.ROPE] RETURNS [LIST OF Rope.ROPE] = {
c: Rope.ROPE;
IF segs=NIL OR segs.rest=NIL THEN RETURN[segs];
IF segs.rest.first.Fetch[0]#'. AND
VFonts.RopeWidth[c ← segs.first.Concat[segs.rest.first], font]<=width
THEN RETURN[Coalesce[CONS[c, segs.rest.rest]]];
RETURN[CONS[segs.first, Coalesce[segs.rest]]]; };
width ← width+wSlop; -- allow small amount of clipping.
RETURN[Coalesce[Build[0]]];
END;
maxIcons: CARDINAL = 64;
icons: ARRAY [0..maxIcons) OF IconRef ;
nextFlavor: IconFlavor ← document;
NewFlavor: ENTRY PROC RETURNS [newFlavor: IconFlavor] = BEGIN
newFlavor ← nextFlavor;
nextFlavor ← SUCC[newFlavor];
IF LOOPHOLE[nextFlavor, CARDINAL] >= maxIcons THEN ERROR;
END;
NewIcon: PUBLIC PROC [info: IconRef] RETURNS [newFlavor: IconFlavor] = BEGIN
newFlavor ← NewFlavor[];
icons[LOOPHOLE[newFlavor]] ← info;
END;
IconsFromFile: PROC [file: Rope.ROPE] RETURNS [first: IconFlavor, nRead: INTEGER] =
TRUSTED BEGIN
iconBase: LONG POINTER TO IconFileFormat;
fh: CIFS.OpenFile;
fileC: File.Capability;
size: Space.PageCount;
space: Space.Handle;
fileC ← CIFS.GetFC[fh ← CIFS.Open[file, CIFS.read]];
size ← File.GetSize[fileC];
space ← Space.Create[size: size, parent: Space.virtualMemory];
Space.Map[space: space, window: [file: fileC, base: 1]]; -- first page is 1!
iconBase ← Space.LongPointer[space];
first ← nextFlavor;
nRead ← size/(SIZE[IconFileFormat]/Environment.wordsPerPage);
FOR n: INTEGER IN [0..nRead) DO
[] ← NewIcon[NEW[IconRep ← [iconBase.bits, iconBase.label, iconBase.invertLabel,
0--filler--, iconBase.lx, iconBase.ly, iconBase.lw, iconBase.lh]]];
iconBase ← iconBase+SIZE[IconFileFormat];
ENDLOOP;
Space.Delete[space];
CIFS.Close[fh];
END;
NewIconFromFile: PUBLIC PROC [file: Rope.ROPE, n: CARDINAL] RETURNS [newFlavor: IconFlavor] =
TRUSTED BEGIN
iconBase: LONG POINTER TO IconFileFormat;
fh: CIFS.OpenFile;
fileC: File.Capability;
space: Space.Handle;
fileC ← CIFS.GetFC[fh ← CIFS.Open[file, CIFS.read]];
space ← Space.Create[size: File.GetSize[fileC], parent: Space.virtualMemory];
Space.Map[space: space, window: [file: fileC, base: 1]]; -- first page is 1!
iconBase ← Space.LongPointer[space] + (n*SIZE[IconFileFormat]);
newFlavor ← NewIcon[NEW[IconRep ← [iconBase.bits, iconBase.label, iconBase.invertLabel,
0--filler--, iconBase.lx, iconBase.ly, iconBase.lw, iconBase.lh]]];
Space.Delete[space];
CIFS.Close[fh];
END;
iconFile: Rope.ROPE ← UserProfile.Token["Icons", "/Indigo/CedarViewers/Viewers/Standard.icons"];
GetFonts[];
[] ← IconsFromFile[iconFile ! CIFS.Error => -- maybe IVY has something we can use
{iconFile ← "/Ivy/CedarViewers/Viewers/Standard.icons"; RETRY}];
END.