ControlsOuterImpl.mesa
Copyright Ó 1985, 1992 by Xerox Corporation. All rights reserved.
Bloomenthal, July 2, 1992 6:25 pm PDT
DIRECTORY Atom, Buttons, CedarProcess, Commander, Containers, Controls, ControlsPrivate, Convert, FileNames, G2dBasic, Imager, IO, Labels, PopUpSelection, ProcessProps, Real, Rope, TiogaExtraOps, TiogaOps, TIPUser, TypeScript, VFonts, ViewerClasses, ViewerIO, ViewerOps, ViewerSpecs, ViewerTools;
ControlsOuterImpl:
CEDAR
MONITOR
IMPORTS Atom, Buttons, CedarProcess, Containers, Controls, ControlsPrivate, Convert, FileNames, Imager, IO, Labels, PopUpSelection, ProcessProps, Real, Rope, TiogaExtraOps, TiogaOps, TIPUser, TypeScript, VFonts, ViewerIO, ViewerOps, ViewerSpecs, ViewerTools
Types
Button: TYPE ~ Controls.Button;
ButtonList: TYPE ~ Controls.ButtonList;
ButtonRep: TYPE ~ Controls.ButtonRep;
Choice: TYPE ~ Controls.Choice;
ClickProc: TYPE ~ Controls.ClickProc;
Column: TYPE ~ Controls.Column;
Control: TYPE ~ Controls.Control;
ControlList: TYPE ~ Controls.ControlList;
ControlSizes: TYPE ~ Controls.ControlSizes;
DestroyProc: TYPE ~ Controls.DestroyProc;
DrawProc: TYPE ~ Controls.DrawProc;
GraphicsData: TYPE ~ Controls.GraphicsData;
GraphicsDataRep: TYPE ~ Controls.GraphicsDataRep;
IntegerPair: TYPE ~ Controls.IntegerPair;
MouseButton: TYPE ~ Controls.MouseButton;
MouseProc: TYPE ~ Controls.MouseProc;
OuterData: TYPE ~ Controls.OuterData;
OuterDataRep: TYPE ~ Controls.OuterDataRep;
RealSequence: TYPE ~ Controls.RealSequence;
RealSequenceRep: TYPE ~ Controls.RealSequenceRep;
RopeSequence: TYPE ~ Controls.RopeSequence;
RopeSequenceRep: TYPE ~ Controls.RopeSequenceRep;
Request: TYPE ~ Controls.Request;
Triple: TYPE ~ Controls.Triple;
TSValue: TYPE ~ Controls.TSValue;
Typescript: TYPE ~ Controls.Typescript;
TypescriptRep: TYPE ~ Controls.TypescriptRep;
Font: TYPE ~ Imager.Font;
STREAM: TYPE ~ IO.STREAM;
ROPE: TYPE ~ Rope.ROPE;
IconFlavor: TYPE ~ ViewerClasses.IconFlavor;
Viewer: TYPE ~ ViewerClasses.Viewer;
Outer Procedures
AvailableHeight:
PROC [column: ViewerClasses.Column]
RETURNS [ht:
INTEGER] ~ {
nViewers: INTEGER ¬ 1; -- count oneself too
EnumProc: ViewerOps.EnumProc ~ {
IF v.column = column AND NOT v.iconic THEN nViewers ¬ nViewers+1;
};
ViewerOps.EnumerateViewers[EnumProc];
ht ¬ ViewerSpecs.openTopY-ViewerSpecs.openBottomY-nViewers*ViewerSpecs.captionHeight;
};
PaintOuter: ViewerClasses.PaintProc ~ {
Action:
PROC ~ {
o: OuterData ¬ NARROW[self.data];
Imager.MaskRectangleI[context, 0, self.wh-capHeight, self.ww, 1];
IF o.buttons # NIL THEN Imager.MaskRectangleI[context, 0, o.buttonsY, self.ww, 1];
IF o.typescript #
NIL
AND o.typescript.viewer #
NIL
THEN Imager.MaskRectangleI[context, 0, o.tsY, self.ww, 1];
IF o.graphics # NIL THEN Imager.MaskRectangleI[context, 0, o.graphicsY-1, self.ww, 1];
};
IF whatChanged = NIL THEN Imager.DoWithBuffer[context, Action, 0, 0, self.ww, self.wh];
};
AdjustProc: ViewerClasses.AdjustProc ~ {AdjustOuter[
NARROW[self.data], self.ww, self.wh]};
AdjustOuter:
PROC [o: OuterData, w, h:
INTEGER] ~ {
SetV: PROC[v: Viewer, x, y, w, h: INT] ~ {ViewerOps.EstablishViewerPosition[v,x,y,w,h]};
EstablishOuterChild: ViewerOps.EnumProc ~ {
Justify child with respect to top of parent viewer:
newY: INTEGER ¬ v.wy+h-o.outerH;
IF ViewerOps.FetchProp[v, $CreatedInOuterViewer] =
NIL
THEN SetV[v, v.wx, v.wy ¬ newY, v.ww, v.wh];
};
oldGraphicsH: INT ¬ o.graphicsH;
o.graphicsH ¬ h-capHeight-o.controlsH-o.buttonsH-o.tsH;
SetYs[o];
IF o.typescript #
NIL
AND o.typescript.viewer #
NIL
THEN SetV[o.typescript.viewer, 0, o.tsY+1, w, o.tsH-2];
IF o.buttons #
NIL
THEN FOR b: ButtonList ¬ o.buttons, b.rest
WHILE b #
NIL
DO
SetV[b.first.viewer, b.first.x, o.buttonsY+b.first.y, b.first.w, b.first.h];
ENDLOOP;
IF o.parent # NIL THEN ViewerOps.EnumerateChildren[o.parent, EstablishOuterChild];
IF o.graphics #
NIL
AND
NOT o.parent.iconic
THEN {
refWidth: REF ANY ¬ ViewerOps.FetchProp[o.graphics, $Width];
refHeight: REF ANY ¬ ViewerOps.FetchProp[o.graphics, $Height];
SetV[o.graphics, 0, o.graphicsY, w, o.graphicsH];
IF refWidth #
NIL
AND refHeight #
NIL
THEN {
EstablishGraphicsChild: ViewerOps.EnumProc ~ {
I: PROC [r: REAL] RETURNS [i: INT] ~ {i ¬ Real.Round[r]};
SetV[v, I[sx*v.wx], I[sy*v.wy], I[sx*v.ww], I[sy*v.wh]];
};
sx: REAL ¬ REAL[w]/REAL[NARROW[refWidth, REF INTEGER]];
sy: REAL ¬ REAL[o.graphicsH]/REAL[NARROW[refHeight, REF INTEGER]];
ViewerOps.EnumerateChildren[o.graphics, EstablishGraphicsChild];
};
ViewerOps.AddProp[o.graphics, $Width, NEW[INTEGER ¬ w]];
ViewerOps.AddProp[o.graphics, $Height, NEW[INTEGER ¬ o.graphicsH]];
};
o.outerH ¬ h;
};
CopyControlList:
PROC [controls: ControlList]
RETURNS [ControlList] ~ {
new: ControlList ¬ NIL;
FOR c: ControlList ¬ controls, c.rest
WHILE c #
NIL
DO
new ¬ Controls.Append[c.first, new];
ENDLOOP;
RETURN[new];
};
ChangeOuterViewer:
PUBLIC
PROC [outerData: OuterData, controls: ControlList] ~ {
NotInList:
PROC [controls: ControlList, control: Control]
RETURNS [
BOOL] ~ {
FOR c: ControlList ¬ controls, c.rest
WHILE c #
NIL
DO
IF c.first = control THEN RETURN[FALSE];
ENDLOOP;
RETURN[TRUE];
};
destroy: BOOL ¬ FALSE;
parent: Viewer ¬ outerData.parent;
oldControlHeight: INTEGER ¬ outerData.controlsH;
FOR c: ControlList ¬ outerData.controls, c.rest
WHILE c #
NIL
DO
-- do this everytime
IF NotInList[controls, c.first] THEN {destroy ¬ TRUE; EXIT};
ENDLOOP;
FOR c: ControlList ¬ outerData.controls, c.rest
WHILE c #
NIL
DO
ViewerOps.DestroyViewer[c.first.viewer, FALSE];
ViewerOps.DestroyViewer[c.first.title, FALSE];
ViewerOps.DestroyViewer[c.first.status, FALSE];
ENDLOOP;
outerData.controlsH ¬
Controls.ControlPositions[controls, outerData.controlSizes, ColumnWidth[outerData.column]];
IF outerData.controlsH # oldControlHeight
THEN {
SetOuterHeight[outerData];
AdjustOuter[outerData, outerData.parent.ww, outerData.outerH];
ViewerOps.SetOpenHeight[parent, outerData.outerH-capHeight+1];
ViewerOps.ComputeColumn[outerData.column, TRUE];
};
outerData.controls ¬ CopyControlList[controls];
FOR c: ControlList ¬ controls, c.rest
WHILE c #
NIL
DO
Controls.ControlViewer[parent, c.first, outerData.graphics, outerData];
ENDLOOP;
IF outerData.controlsH = oldControlHeight
AND destroy
THEN ViewerOps.PaintViewer[parent, client, TRUE, NIL];
};
OuterViewer:
PUBLIC
PROC [
name: ROPE ¬ NIL,
column: Column ¬ left,
buttons: ButtonList ¬ NIL,
controls: ControlList ¬ NIL,
controlSizes: ControlSizes ¬ [25, 200, 60, 25, 60, 150, 150],
graphicsHeight: INTEGER ¬ 0,
mouseProc: MouseProc ¬ NIL,
drawProc: DrawProc ¬ NIL,
destroyProc: DestroyProc ¬ NIL,
typescriptHeight: INTEGER ¬ 0,
biScrollable: BOOL ¬ FALSE,
clientData: REF ANY ¬ NIL,
noOpen: BOOL ¬ FALSE,
icon: IconFlavor ¬ document]
RETURNS [outerData: OuterData]
~ {
viewer: Viewer;
IF column = color AND ColorDisplayManager.NextState[].type = NIL THEN column ← left;
outerData ¬ OuterDataInit[
NIL, column, buttons, controls, controlSizes,
graphicsHeight, mouseProc, drawProc,
destroyProc, typescriptHeight, clientData];
viewer ¬ outerData.parent ¬ ViewerOps.CreateViewer[
flavor: $Outer,
paint: FALSE,
info: [
name: name,
data: outerData,
openHeight: MIN[AvailableHeight[column], outerData.outerH],
scrollable: FALSE,
column: column,
iconic: TRUE]
];
IF icon # document THEN viewer.icon ¬ icon;
ViewerOps.AddProp[viewer, $WorkingDirectory, ProcessProps.GetProp[$WorkingDirectory]];
SetYs[outerData];
IF outerData.tsH # 0
THEN {
ts: Typescript ¬ outerData.typescript ¬ NEW[TypescriptRep];
v: Viewer ¬ ts.viewer ¬ TypescriptViewer[viewer, outerData.tsH];
[ts.in, ts.out] ¬ ViewerIO.CreateViewerStreams[NIL, v];
};
IF graphicsHeight # 0
THEN {
outerData.graphics ¬ GraphicsViewer[viewer, outerData.controlsH, graphicsHeight, mouseProc, drawProc, biScrollable, outerData.clientData];
ViewerOps.AddProp[outerData.graphics, $Width, NEW[INTEGER ¬ viewer.ww]];
ViewerOps.AddProp[outerData.graphics, $Height, NEW[INTEGER ¬ graphicsHeight]];
outerData.graphicsData ¬ GetGraphicsData[outerData.graphics];
};
FOR b: ButtonList ¬ outerData.buttons, b.rest
WHILE b #
NIL
DO
v: Viewer ¬ b.first.viewer ¬ ButtonViewer[viewer, b.first];
IF b.first.type = click
AND b.first.style # $BlackOnWhite
THEN Buttons.SetDisplayStyle[b.first.viewer, b.first.style];
ENDLOOP;
FOR c: ControlList ¬ outerData.controls, c.rest
WHILE c #
NIL
DO
Controls.ControlViewer[viewer, c.first, outerData.graphics, outerData];
ENDLOOP;
IF NOT noOpen THEN ViewerOps.OpenIcon[viewer];
};
OuterDataInit:
PROC [
outerData: OuterData ¬ NIL, -- use if non-nil
column: Column ¬ left,
buttons: ButtonList ¬ NIL,
controls: ControlList ¬ NIL,
controlSizes: ControlSizes ¬ [25, 200, 60, 25, 60, 150, 150],
graphicsHeight: INTEGER ¬ 0,
mouseProc: MouseProc ¬ NIL,
drawProc: DrawProc ¬ NIL,
destroyProc: DestroyProc ¬ NIL,
typescriptHeight: INTEGER ¬ 0,
data: REF ANY ¬ NIL]
RETURNS [OuterData] ~ {
widthLim:
NAT ¬
SELECT column
FROM
left => ViewerSpecs.openLeftWidth,
right => ViewerSpecs.openRightWidth,
ENDCASE => ViewerSpecs.colorScreenWidth;
IF outerData = NIL THEN outerData ¬ NEW[OuterDataRep];
outerData.controls ¬ CopyControlList[controls];
outerData.buttons ¬ buttons;
outerData.clientData ¬ data;
outerData.destroyProc ¬ destroyProc;
outerData.controlSizes ¬ controlSizes;
outerData.directory ¬ FileNames.CurrentWorkingDirectory[];
outerData.cmdOut ¬
WITH ProcessProps.GetProp[$CommanderHandle]
SELECT
FROM
cmd: Commander.Handle => cmd.err,
ENDCASE => NIL;
outerData.controlsH ¬ Controls.ControlPositions[controls, controlSizes, ColumnWidth[column]];
outerData.graphicsH ¬ graphicsHeight;
outerData.tsH ¬ typescriptHeight;
outerData.buttonsH ¬ ButtonsPreparation[buttons, widthLim];
SetOuterHeight[outerData];
RETURN[outerData];
};
ColumnWidth:
PROC [column: Column]
RETURNS [
INTEGER] ~ {
RETURN[
SELECT column
FROM
color => ViewerSpecs.colorScreenWidth,
left => ViewerSpecs.openLeftWidth,
right => ViewerSpecs.openRightWidth,
ENDCASE => 600];
};
SetYs:
PROC [outerData: OuterData] ~ {
outerData.controlsY ¬ 0;
outerData.graphicsY ¬ outerData.controlsY+outerData.controlsH;
outerData.tsY ¬ outerData.graphicsY+outerData.graphicsH;
outerData.buttonsY ¬ outerData.tsY+outerData.tsH;
};
SetOuterHeight:
PROC [outerData: OuterData] ~ {
outerData.outerH ¬ outerData.controlsH+outerData.graphicsH+outerData.tsH+outerData.buttonsH+capHeight;
};
Graphics Procedures
gGraphicsData: REF ANY;
gGraphicsInput: LIST OF REF ANY;
newGraphicsInputBoolean: BOOL;
newGraphicsInputCondition:
CONDITION;
NotifyGraphics: ViewerClasses.NotifyProc ~ {
NewGraphicsInput[GetGraphicsData[self], input];
};
NewGraphicsInput:
ENTRY
PROC [data:
REF
ANY, input:
LIST
OF
REF
ANY] ~ {
gGraphicsData ¬ data;
gGraphicsInput ¬ input;
newGraphicsInputBoolean ¬ TRUE;
NOTIFY newGraphicsInputCondition;
};
GetGraphicsInput:
ENTRY
PROC
RETURNS [graphics: GraphicsData] ~ {
IF NOT newGraphicsInputBoolean THEN WAIT newGraphicsInputCondition;
newGraphicsInputBoolean ¬ FALSE;
graphics ¬ NARROW[gGraphicsData];
IF gGraphicsInput #
NIL
THEN graphics.mouse ¬ Controls.SetMouse[
atom: NARROW[gGraphicsInput.rest.first],
position:
WITH gGraphicsInput.first
SELECT
FROM
p: TIPUser.TIPScreenCoords => [p.mouseX, p.mouseY],
p: BiScrollers.ClientCoords => [Real.InlineRoundI[p.x], Real.InlineRoundI[p.y]],
ENDCASE => ERROR];
};
WatchGraphics:
CedarProcess.ForkableProc ~ {
DO
g: GraphicsData ¬ GetGraphicsInput[];
IF g.mouseProc # NIL THEN g.mouseProc[g.mouse, g.viewer, g.clientData];
ENDLOOP;
};
GetGraphicsData:
PROC [viewer: Viewer]
RETURNS [GraphicsData] ~ {
RETURN[IF BiScrollers.ViewerIsABiScroller[viewer]
THEN NARROW[BiScrollers.ClientDataOfViewer[viewer]]
ELSE NARROW[viewer.data]];
RETURN[NARROW[viewer.data]];
};
PaintGraphics: ViewerClasses.PaintProc ~ {
v: Viewer;
d: GraphicsData;
IF BiScrollers.ViewerIsABiScroller[self]
THEN {
d ← NARROW[BiScrollers.ClientDataOfViewer[self]];
v ← BiScrollers.QuaViewer[BiScrollers.QuaBiScroller[self], TRUE];
}
ELSE {
d ¬ NARROW[self.data];
v ¬ self;
};
IF d # NIL AND d.drawProc # NIL THEN d.drawProc[context, d.clientData, whatChanged, v];
};
GraphicsViewer:
PUBLIC
PROC [
parent: Viewer,
y, h: INTEGER ¬ 0,
mouseProc: MouseProc,
drawProc: DrawProc,
biScrollable: BOOL ¬ FALSE,
clientData: REF ANY]
RETURNS [viewer: Viewer]
~ {
graphicsData: GraphicsData ¬
NEW[GraphicsDataRep ¬ [
mouseProc: mouseProc, drawProc: drawProc, clientData: clientData, parent: parent]];
IF biScrollable
THEN {
bs: BiScrollers.BiScroller ← BiScrollers.GetStyle[].CreateBiScroller[
class: graphicsBiScrollerClass,
info: [
parent: parent,
wx: 0, wy: y,
ww: parent.ww,
wh: h,
data: graphicsData,
border: FALSE,
scrollable: FALSE],
paint: FALSE
];
viewer ← bs.QuaViewer[inner: FALSE];
}
--
ELSE -- viewer ¬ ViewerOps.CreateViewer[
flavor: $Graphics,
paint: FALSE,
info: [
data: graphicsData,
scrollable: FALSE,
ww: parent.ww,
wy: y,
wh: h,
border: FALSE,
parent: parent]];
graphicsData.viewer ¬ viewer;
ViewerOps.AddProp[viewer, $CreatedInOuterViewer, $True];
};
Button Procedures
ClickButton:
PUBLIC PROC [
name: ROPE ¬ NIL,
proc: ClickProc ¬ NIL,
clientData: REF ANY ¬ NIL,
row, x, y, w, h: INTEGER ¬ 0,
fork: BOOL ¬ TRUE,
guarded: BOOL ¬ FALSE,
documentation: ROPE ¬ NIL,
font: Font ¬ NIL,
style: ATOM ¬ $BlackOnWhite]
RETURNS [Button] ~ {
RETURN[NEW[ButtonRep ¬ [click, name, row, x, y, w, h, fork, guarded, documentation, font, NIL, clientData, proc, style]]];
};
TextButton:
PUBLIC PROC [
name: ROPE ¬ NIL,
text: ROPE ¬ NIL,
proc: ClickProc ¬ NIL,
clientData: REF ANY ¬ NIL,
row, x, y, w, h: INTEGER ¬ 0,
fork: BOOL ¬ TRUE,
documentation: ROPE ¬ NIL,
font: Font ¬ NIL]
RETURNS [b: Button]
~ {
b ¬ NEW[ButtonRep ¬ [text, name, row, x, y, w, h, fork,, documentation, font, NIL, clientData,,, text, proc]];
};
PopUpButton: PUBLIC PROC [
name: ROPE ← NIL,
proc: PopUpButtonProc ← NIL,
choices: ChoiceList ← NIL,
doc: ROPE ← NIL,
help: Help ← NIL,
clientData: REF ANY ← NIL,
row, x, y, w, h: INTEGER ← 0,
fork: BOOL ← TRUE,
guarded: BOOL ← FALSE,
documentation: ROPE ← NIL,
font: Font ← NIL]
RETURNS [Button] ~ {
RETURN[NEW[ButtonRep ← [popUp, name, row, x, y, w, h, fork, guarded, documentation, font,, clientData,,,,,, proc, choices, doc, help]]];
};
popUpButton: MouseButton ¬ none;
PopUpRequest:
PUBLIC
PROC [header: Request, requests:
LIST
OF Request]
RETURNS [i:
INT] ~ {
Reverse:
PROC [in:
LIST
OF
ROPE]
RETURNS [out:
LIST
OF
ROPE] ~ {
FOR r: LIST OF ROPE ¬ in, r.rest WHILE r # NIL DO out ¬ CONS[r.first, out]; ENDLOOP;
};
choices, docs: LIST OF ROPE ¬ NIL;
pos: REF ViewerClasses.MouseButton ¬ NEW[ViewerClasses.MouseButton];
FOR r:
LIST
OF Request ¬ requests, r.rest
WHILE r #
NIL
DO
choices ¬ CONS[r.first.choice, choices];
docs ¬ CONS[r.first.doc, docs];
ENDLOOP;
i ¬ PopUpSelection.Request[header.choice, Reverse[choices], header.doc, Reverse[docs],,, pos];
popUpButton ¬
IF i > 0
THEN
SELECT pos
FROM
red => left,
yellow => middle,
blue => right,
ENDCASE => none
ELSE none;
};
BoolRequest:
PUBLIC PROC [value:
BOOL, title:
ROPE]
RETURNS [req: Request] ~ {
req.choice ¬ IO.PutFR["%g is %g", IO.rope[title], IO.rope[IF value THEN "On" ELSE "Off"]];
req.doc ¬ IO.PutFR["Turn %g %g", IO.rope[IF value THEN "Off" ELSE "On"], IO.rope[title]];
};
IntRequest:
PUBLIC PROC [title, doc:
ROPE, value:
NAT]
RETURNS [Request] ~ {
RETURN[[IO.PutFR["%g (now %g)", IO.rope[title], IO.int[value]], doc]];
};
RealRequest:
PUBLIC PROC [title, doc:
ROPE, value:
REAL]
RETURNS [Request] ~ {
RETURN[[IO.PutFR["%g (now %6.3f)", IO.rope[title], IO.real[value]], doc]];
};
RopeRequest:
PUBLIC PROC [title, doc, value:
ROPE]
RETURNS [req: Request] ~ {
req ¬
IF value =
NIL
THEN [IO.PutFR1["%g", IO.rope[title]], doc]
ELSE [IO.PutFR["%g (now %g)", IO.rope[title], IO.rope[value]], doc];
};
MultiRequest:
PUBLIC PROC [header:
ROPE, choices:
LIST
OF Choice]
RETURNS [
INT] ~ {
Reverse:
PROC [in:
LIST
OF Request]
RETURNS [out:
LIST
OF Request] ~ {
FOR r: LIST OF Request ¬ in, r.rest WHILE r # NIL DO out ¬ CONS[r.first, out]; ENDLOOP;
};
id, choice, count: NAT ¬ 0;
status: ROPE ¬ NIL;
requests: LIST OF Request ¬ NIL;
FOR l:
LIST
OF Choice ¬ choices, l.rest
WHILE l #
NIL
DO
IF l.first.true
THEN status ¬ (
IF status =
NIL
THEN Rope.Concat[header, l.first.state]
ELSE Rope.Cat[status, ", ", l.first.state])
ELSE {
requests ¬ CONS[[Rope.Concat["Change to ", l.first.state]], requests];
l.first.privateId ¬ (id ¬ id+1);
};
ENDLOOP;
choice ¬ Controls.PopUpRequest[[status], Reverse[requests]];
FOR l:
LIST
OF Choice ¬ choices, l.rest
WHILE l #
NIL
DO
count ¬ count+1;
IF l.first.privateId = choice THEN RETURN[count];
ENDLOOP;
RETURN[-1];
};
GetPopUpButton:
PUBLIC
PROC
RETURNS [MouseButton] ~ {
RETURN[popUpButton]};
GetTextButtonText:
PUBLIC
PROC [outerData: OuterData, name:
ROPE]
RETURNS [t:
ROPE] ~ {
button: Button ¬ ButtonFind[outerData, name];
IF button =
NIL
THEN ControlError["Can't find named button"]
ELSE t ¬ ViewerTools.GetContents[button.textViewer];
};
GetTextButtonValue:
PUBLIC
PROC [outerData: OuterData, name:
ROPE]
RETURNS
[r:
REAL]
~ {
r ¬ Convert.RealFromRope[GetTextButtonText[outerData, name]];
};
GetTextButtonsTexts:
PUBLIC
PROC [outerData: OuterData, name:
ROPE]
RETURNS [ropes: RopeSequence]
~ {
IF outerData #
NIL
AND outerData.buttons #
NIL
THEN {
i: INT ¬ 0; FOR l: ButtonList ¬ outerData.buttons, l.rest WHILE l # NIL DO i¬i+1; ENDLOOP;
ropes ¬ NEW[RopeSequenceRep[i]];
i ¬ 0;
FOR l: ButtonList ¬ outerData.buttons, l.rest
WHILE l #
NIL
DO
ropes[i] ¬ ViewerTools.GetContents[l.first.textViewer];
i ¬ i+1;
ENDLOOP;
};
};
GetTextButtonsValues:
PUBLIC
PROC [outerData: OuterData, name:
ROPE]
RETURNS [reals: RealSequence]
~ {
IF outerData #
NIL
AND outerData.buttons #
NIL
THEN {
i: INT ¬ 0; FOR l: ButtonList ¬ outerData.buttons, l.rest WHILE l # NIL DO i¬i+1; ENDLOOP;
reals ¬ NEW[RealSequenceRep[i]];
i ¬ 0;
FOR l: ButtonList ¬ outerData.buttons, l.rest
WHILE l #
NIL
DO
reals[i] ¬Convert.RealFromRope[ViewerTools.GetContents[l.first.textViewer]];
i ¬ i+1;
ENDLOOP;
};
};
ButtonRelabel:
PUBLIC
PROC [outerData: OuterData, oldName, newName:
ROPE] ~ {
IF outerData #
NIL
THEN
FOR b: ButtonList ¬ outerData.buttons, b.rest
WHILE b #
NIL
DO
IF b.first.type = click
AND Rope.Equal[b.first.viewer.name, oldName]
THEN Buttons.ReLabel[b.first.viewer, newName];
ENDLOOP;
};
ButtonToggle:
PUBLIC PROC [outerData: OuterData, state:
BOOL, trueName, falseName:
ROPE]
~ {
IF state
THEN ButtonRelabel[outerData, falseName, trueName]
ELSE ButtonRelabel[outerData, trueName, falseName];
};
ButtonStyle:
PUBLIC
PROC [outerData: OuterData, name:
ROPE, style:
ATOM] ~ {
FOR b: ButtonList ¬ outerData.buttons, b.rest
WHILE b #
NIL
DO
IF b.first.type = click
AND Rope.Equal[b.first.viewer.name, name]
THEN Buttons.SetDisplayStyle[b.first.viewer, style];
ENDLOOP;
};
ButtonFind:
PUBLIC
PROC [outerData: OuterData, name:
ROPE]
RETURNS [Button] ~ {
FOR b: ButtonList ¬ outerData.buttons, b.rest
WHILE b #
NIL
DO
IF Rope.Equal[b.first.name, name] THEN RETURN[b.first];
ENDLOOP;
RETURN[NIL];
};
ButtonTextProc: ClickProc ~ {
outerData: OuterData ¬ NARROW[clientData];
button: Button ¬ ButtonFind[outerData, parent.name];
IF button.type # text THEN RETURN;
ViewerTools.SetSelection[button.textViewer];
When mouse focus moved from textViewer, button.textProc called by Controls.KillInputFocus
};
ButtonDummyProc: ClickProc ~ {};
-- otherwise Buttons.ButtonPusher dies
ButtonViewer:
PUBLIC
PROC [parent: Viewer, button: Button]
RETURNS [viewer: Viewer] ~ {
If button.proc is NIL, treat button as a non-bordered label.
SELECT button.type
FROM
click =>
viewer ¬
IF button.clickProc #
NIL
THEN
Buttons.Create[
info: [parent: parent, name: button.name, wx: button.x, wy: button.y],
proc: button.clickProc,
clientData: button.clientData,
fork: button.fork,
font: button.font,
documentation: button.documentation,
guarded: button.guarded
]
ELSE
Labels.Create[
info: [parent: parent, border:
FALSE, wx: button.x, wy: button.y,
ww: VFonts.StringWidth[button.name, button.font]+8, wh: button.h,
scrollable: FALSE, name: button.name],
font: button.font
];
text => {
labelW: INTEGER ¬ VFonts.StringWidth[button.name, button.font]+8;
v: Viewer ¬ viewer ¬ Containers.Create[info: [parent: parent, name: button.name, wx: button.x, wy: button.y+1, ww: button.w, wh: button.h, scrollable: FALSE]];
v ¬ Buttons.Create[
info: [parent: viewer, name: button.name, border: FALSE, wx: 0, wy: -1, ww: labelW],
proc: ButtonTextProc,
clientData: parent.data, -- should be outerData!!
fork: button.fork,
font: button.font,
documentation: IF button.guarded THEN button.text ELSE NIL,
guarded: button.guarded
];
button.textViewer ¬ ViewerTools.MakeNewTextViewer[
info: [parent: viewer, border: FALSE, wx: labelW, wy: 0, ww: button.w-labelW, wh: button.h, scrollable: FALSE, data: button.clientData]];
ViewerOps.AddProp[v, $CreatedInOuterViewer, $True];
ViewerOps.AddProp[button.textViewer, $CreatedInOuterViewer, $True];
ViewerOps.AddProp[button.textViewer, $ButtonText, button];
ViewerTools.SetContents[button.textViewer, button.text];
ControlsPrivate.ActivateViewer[button.textViewer];
};
popUp => {
class: PopUpButtons.Class ← PopUpButtons.MakeClass[[
classData: button.clientData,
proc: button.popUpProc,
choices: button.choices,
fork: button.fork,
guarded: button.guarded,
image: PopUpButtons.ImageForRope[button.name],
doc: button.doc,
help: button.help]];
viewer ← PopUpButtons.Instantiate[
class,
[parent: parent, name: button.name, border: button.popUpProc # NIL, wx: button.x, wy: button.y],
button.help];
};
ENDCASE;
ViewerOps.AddProp[viewer, $CreatedInOuterViewer, $True];
};
ButtonsPreparation:
PROC [buttons: ButtonList, widthLimit:
NAT]
RETURNS [buttonHeight: INTEGER]
~ {
margin: INTEGER ~ 4;
buttonRows: ARRAY [0..maxNRows) OF RECORD [x: INTEGER ¬ margin, y, h: INTEGER ¬ 0];
FOR b: ButtonList ¬ buttons, b.rest
WHILE b #
NIL
DO
font: Font ¬ b.first.font ¬ VFonts.DefaultFont[b.first.font];
IF b.first.h = 0 THEN b.first.h ¬ VFonts.FontHeight[font]+3;
IF b.first.w = 0 THEN b.first.w ¬ VFonts.StringWidth[b.first.name, font]+8;
IF b.first.type = text
THEN {
b.first.text ¬ Rope.Concat[b.first.text, " "]; -- MakeNewTextViewer needs padding
b.first.w ¬ b.first.w+VFonts.StringWidth[b.first.text, font]+8;
};
ENDLOOP;
FOR b: ButtonList ¬ buttons, b.rest
WHILE b #
NIL
DO
b.first.row ¬ MAX[0, MIN[maxNRows-1, b.first.row]];
DO
IF MAX[b.first.x, buttonRows[b.first.row].x]+b.first.w < widthLimit THEN EXIT;
IF b.first.row >= maxNRows-2 THEN EXIT;
b.first.row ¬ b.first.row+1;
ENDLOOP;
IF b.first.x = 0
THEN b.first.x ¬ buttonRows[b.first.row].x
ELSE buttonRows[b.first.row].x ¬ b.first.x;
buttonRows[b.first.row].x ¬ b.first.x+b.first.w+margin-1;
buttonRows[b.first.row].h ¬ MAX[buttonRows[b.first.row].h, b.first.h];
ENDLOOP;
buttonRows[0].y ¬ margin+1;
buttonHeight ¬ buttonRows[0].y+buttonRows[0].h+margin;
FOR n:
NAT
IN [1..maxNRows)
DO
IF buttonRows[n].h # 0 THEN buttonHeight ¬ buttonHeight+buttonRows[n].h+margin;
buttonRows[n].y ¬ buttonRows[n-1].y+buttonRows[n].h+margin;
ENDLOOP;
FOR b: ButtonList ¬ buttons, b.rest
WHILE b #
NIL
DO
IF b.first.y = 0 THEN b.first.y ¬ buttonRows[b.first.row].y;
ENDLOOP;
IF buttons = NIL THEN buttonHeight ¬ 0;
};
Typescript Procedures
TypescriptViewer:
PROC [parent: Viewer, tsHeight:
INTEGER]
RETURNS [ts: Viewer] ~ {
arg: ROPE ~ "0 pt restIndent";
ts ¬ TypeScript.Create[[parent: parent, wh: tsHeight, border: FALSE]];
ViewerOps.AddProp[ts, $CreatedInOuterViewer, $True];
TiogaExtraOps.PutProp[TiogaOps.LastWithin[TiogaOps.ViewerDoc[ts]], $Postfix, arg];
};
TypescriptClear:
PUBLIC PROC [ts: Typescript] ~ {
IF ts.out # NIL AND NOT ts.clear THEN IO.PutRope[ts.out, "\n"];
ts.clear ¬ TRUE;
};
TypescriptWrite:
PUBLIC PROC [ts: Typescript, rope:
ROPE] ~ {
IF ts.out = NIL THEN RETURN;
IO.PutRope[ts.out, rope ! IO.Error => CONTINUE];
IO.Flush[ts.out ! IO.Error => CONTINUE];
ts.clear ¬ Rope.FindBackward[rope, "\n"] = Rope.Length[rope]-1;
};
TypescriptRead:
PUBLIC
PROC [ts: Typescript, prompt:
ROPE ¬
NIL]
RETURNS [reply:
ROPE]
~ {
IF ts.in = NIL THEN RETURN[NIL];
IF ts.out #
NIL
AND prompt #
NIL
THEN {
IF NOT ts.clear THEN prompt ¬ Rope.Concat["\n", prompt];
TypescriptWrite[ts, prompt];
};
ViewerTools.SetSelection[ts.viewer];
reply ¬ IO.GetLineRope[ts.in ! IO.Rubout, IO.Error => CONTINUE];
IF reply = NIL THEN TypescriptWrite[ts, ". . . aborted.\n"];
ts.clear ¬ TRUE;
};
TypescriptReadFileName:
PUBLIC
PROC [ts: Typescript]
RETURNS [reply:
ROPE] ~ {
Inner: PROC ~ {reply ¬ FileNames.ResolveRelativePath[reply]};
workingDir: ROPE ~ NARROW[ViewerOps.FetchProp[ts.viewer.parent, $WorkingDirectory]];
reply ¬ TypescriptRead[ts, IO.PutFR1["Filename: (dir = %g) ", IO.rope[workingDir]]];
ProcessProps.AddPropList[Atom.PutPropOnList[NIL, $WorkingDirectory, workingDir], Inner];
The above doesn't always seem to work, so:
IF Rope.IsEmpty[reply] THEN RETURN[NIL];
IF Rope.Fetch[reply, 0] # '/ THEN reply ¬ Rope.Concat[workingDir, reply];
};
TypescriptReadValue:
PUBLIC
PROC [ts: Typescript, name:
ROPE, currentValue:
REAL]
RETURNS [newValue: REAL]
~ {
reply:
ROPE ¬
TypescriptRead[ts, IO.PutFR["%g (now %g): ", IO.rope[name], IO.real[currentValue]]];
newValue ¬ currentValue;
IF reply #
NIL
THEN newValue ¬ Convert.RealFromRope[reply !
Convert.Error => {TypescriptWrite[ts, "Bad format.\n"]; CONTINUE}];
};
TypescriptReadValues:
PUBLIC PROC [
ts: Typescript,
prompt: ROPE ¬ NIL,
tsValues: LIST OF TSValue]
RETURNS [reals: RealSequence]
~ {
ENABLE Convert.Error => GOTO BadFormat;
Test:
PROC [tsv: TSValue] ~ {
commaV: IO.Value ¬ IO.rope[IF prompt # NIL THEN ", " ELSE NIL];
prompt ¬
SELECT
TRUE
FROM
named
AND
NOT once =>
IO.PutFLR["%g%g%g (now %g)",
LIST[IO.rope[prompt], commaV, IO.rope[tsv.name], IO.real[tsv.value]]],
named
AND once =>
IO.PutFLR["%g%g%g (%g)",
LIST[IO.rope[prompt], commaV, IO.rope[tsv.name], IO.real[tsv.value]]],
ENDCASE => IO.PutFR["%g%g%g", IO.rope[prompt], commaV, IO.real[tsv.value]];
IF named AND NOT once THEN once ¬ TRUE;
};
NextRope:
PROC
RETURNS [
ROPE] ~ {
IF (n0 ¬ Rope.SkipOver[reply, n1, ", \t"]) = Rope.Length[reply] THEN RETURN[NIL];
n1 ¬ Rope.SkipTo[reply, n0, ", \t"];
RETURN[Rope.Substr[reply, n0, n1-n0]];
};
once: BOOL ¬ FALSE;
n0, n1, count: NAT ¬ 0;
reply: ROPE ¬ NIL;
named: BOOL ¬ FALSE;
FOR l:
LIST
OF TSValue ¬ tsValues, l.rest
WHILE l #
NIL
DO
count ¬ count+1;
IF l.first.name # NIL THEN named ¬ TRUE;
ENDLOOP;
IF NOT named THEN prompt ¬ Rope.Concat[prompt, "(now "];
FOR l: LIST OF TSValue ¬ tsValues, l.rest WHILE l # NIL DO Test[l.first]; ENDLOOP;
prompt ¬ Rope.Concat[prompt, IF named THEN "): " ELSE ": "];
IF (reply ¬ TypescriptRead[ts, prompt]) = NIL THEN RETURN;
reals ¬ NEW[RealSequenceRep[count]];
reals.length ¬ count;
count ¬ 0;
FOR l:
LIST
OF TSValue ¬ tsValues, l.rest
WHILE l #
NIL
DO
rope: ROPE ¬ NextRope[];
real: REAL ¬ IF rope # NIL THEN Convert.RealFromRope[rope] ELSE l.first.value;
reals[count] ¬ real;
count ¬ count+1;
ENDLOOP;
EXITS BadFormat => TypescriptWrite[ts, "Bad Format"];
};
GetReal:
PUBLIC PROC [ts: Typescript, prompt:
ROPE, in:
REAL]
RETURNS [out:
REAL] ~ {
reply: ROPE ¬ TypescriptRead[ts, IO.PutFR["%g (now %g): ", IO.rope[prompt], IO.real[in]]];
out ¬ in;
IF reply #
NIL
THEN out ¬ Convert.RealFromRope[reply !
Convert.Error => {TypescriptWrite[ts, ". . . bad format.\n"]; CONTINUE}];
};
GetNat:
PUBLIC PROC [ts: Typescript, prompt:
ROPE, in:
NAT]
RETURNS [out:
NAT] ~ {
reply: ROPE ¬ TypescriptRead[ts, IO.PutFR["%g (now %g): ", IO.rope[prompt], IO.card[in]]];
out ¬ in;
IF reply #
NIL
THEN out ¬ Convert.CardFromRope[reply !
Convert.Error => {TypescriptWrite[ts, ". . . bad format.\n"]; CONTINUE}];
};
GetIntegerPair:
PUBLIC PROC [ts: Typescript, prompt:
ROPE, in: IntegerPair]
RETURNS [out: IntegerPair]
~ {
ENABLE IO.EndOfStream, IO.Error => GOTO Bad;
reply:
ROPE ¬ TypescriptRead[ts,
IO.PutFR["%g: (now %g, %g) ",
IO.rope[prompt], IO.int[in.x], IO.int[in.y]]];
out ¬ in;
IF reply #
NIL
THEN {
s: STREAM ¬ IO.RIS[reply];
out.x ¬ IO.GetInt[s];
out.y ¬ IO.GetInt[s];
};
EXITS Bad => TypescriptWrite[ts, ". . . bad format.\n"];
};
GetTriple:
PUBLIC PROC [ts: Typescript, prompt:
ROPE, in: Triple]
RETURNS [out: Triple] ~ {
ENABLE IO.EndOfStream, IO.Error => GOTO Bad;
reply:
ROPE ¬ TypescriptRead[ts,
IO.PutFLR["%g: (now %g, %g, %g) ",
LIST[IO.rope[prompt], IO.real[in.x], IO.real[in.y], IO.real[in.z]]]];
out ¬ in;
IF reply #
NIL
THEN {
s: STREAM ¬ IO.RIS[reply];
out.x ¬ IO.GetReal[s];
out.y ¬ IO.GetReal[s];
out.z ¬ IO.GetReal[s];
};
EXITS Bad => TypescriptWrite[ts, ". . . bad format.\n"];
};
..