DIRECTORY Ascii, KeySymsKB, KeySymsSun, KeySymsOSF, KeySymsHP, Rope, Xl, XlAscii, XlCursor, XTk, XTkButtons, XTkCommon, XTkContainers, XlCutBuffers, XTkDelegation, XTkFields, XTkFriends, XTkLabels, XTkLabelsExtras, XTkInputFocus, XTkPopUps, XTkShellWidgets; XTkFieldsImpl: CEDAR MONITOR IMPORTS Rope, Xl, XlAscii, XlCutBuffers, XTkContainers, XTk, XTkButtons, XTkDelegation, XTkLabels, XTkLabelsExtras, XTkFields, XTkFriends, XTkInputFocus, XTkPopUps, XTkShellWidgets EXPORTS XTkFields = BEGIN debugging: BOOL ¬ FALSE; Widget: TYPE = XTk.Widget; WidgetSpec: TYPE = XTk.WidgetSpec; StyleSpec: TYPE = XTkCommon.StyleSpec; classImplementsFocus: XTk.ClassFlagKey ~ cf1; events: Xl.EventFilter ~ Xl.CreateEventFilter[keyPress, buttonPress, buttonRelease, clientMessage]; listOfSpecials: LIST OF Xl.KeySym ~ LIST[KeySymsSun.Paste, KeySymsOSF.Paste, KeySymsHP.Paste, KeySymsKB.Stop, KeySymsKB.Next, KeySymsKB.MoveRight]; fieldClass: PUBLIC XTk.Class ¬ MakeClass[]; MakeClass: PROC [] RETURNS [c: XTk.ImplementorClass] = { c ¬ XTkFriends.CreateClass[basicMethods: [ key: $Field, super: XTkLabels.labelClass, initInstPart: FieldInitInstPart, preferredSizeLR: FieldPreferredSize, wDataNum: 1, cursorKey: NEW[XlCursor.StandardFontCursors ¬ centerPtr] ]]; XTk.SetClassFlag[c, classImplementsFocus]; }; FieldData: TYPE = REF FieldDataRec; FieldDataRec: TYPE = RECORD [ pseudoBase: XTkPopUps.PseudoBase ¬ NIL, downPos: Xl.Point ¬ [0, 0] --for poor mans gesture recognition ]; EventProc: Xl.EventProcType = { ENABLE { Xl.XError => GOTO oops; }; widget: XTk.Widget ~ NARROW[clientData]; WITH event SELECT FROM keyPress: Xl.KeyPressEvent => { asRope: Rope.ROPE; char: CHAR; keysym: Xl.KeySym; matched: Xl.KeySym; isModifier: BOOL; [char: char, keysym: keysym, matched: matched, isModifier: isModifier] ¬ XlAscii.Convert[event.connection, keyPress.keyCode, keyPress.state, listOfSpecials]; IF isModifier THEN RETURN; IF matched = KeySymsSun.Paste OR matched = KeySymsOSF.Paste OR matched = KeySymsHP.Paste THEN { insert: Rope.ROPE ¬ XlCutBuffers.Get[event.connection]; InsertRope[widget, insert, FALSE]; RETURN }; IF matched = KeySymsKB.Next OR matched = KeySymsKB.MoveRight THEN { XTkInputFocus.SetFocus[XTkInputFocus.NextFocusTarget[widget]]; RETURN; }; IF matched = KeySymsKB.Stop THEN { XTkInputFocus.GiveUpFocus[widget, keyPress.timeStamp]; RETURN; }; asRope ¬ Rope.FromChar[char]; PushChar[widget, char, asRope]; XTkFriends.CallNotifiers[widget, $FieldCharInput, asRope, keyPress]; }; br: Xl.ButtonReleaseEvent => { pm: Xl.PointerMapping ~ Xl.GetPointerMapping[br.connection]; SELECT pm[br.button] FROM 1 => { fd: FieldData ¬ GetFieldData[widget]; IF ABS[fd.downPos.y-br.pos.y]>8 AND ABS[fd.downPos.x-br.pos.x]<8 --poor mans gesture recognition-- THEN { XTkPopUps.PopUpWithRegularShell[createMenu: menuClosure, registerData: widget, header: "Field values", screen: widget.screenDepth.screen] }; SELECT TRUE FROM br.state.control => {}; br.state.shift => XTkLabelsExtras.SetCharInsertionIndex[widget, 10000]; ENDCASE => XTkLabelsExtras.SetCharInsertionPos[widget, br.pos]; }; 2 => XTkLabelsExtras.SetCharInsertionIndex[widget, 10000]; ENDCASE => {}; XTkInputFocus.SetFocus[widget, br.timeStamp]; }; bp: Xl.ButtonPressEvent => { pm: Xl.PointerMapping ~ Xl.GetPointerMapping[bp.connection]; fd: FieldData ¬ GetFieldData[widget]; fd.downPos ¬ bp.pos; SELECT pm[bp.button] FROM 1 => { SELECT TRUE FROM bp.state.control => { XTkPopUps.PopUpWithRegularShell[createMenu: menuClosure, registerData: widget, header: "Field values", screen: widget.screenDepth.screen] }; ENDCASE => {}; }; 3 => { XTkPopUps.PopUpWithRegularShell[createMenu: menuClosure, registerData: widget, header: "Field values", screen: widget.screenDepth.screen]; }; ENDCASE => RETURN; }; cm: Xl.ClientMessageEvent => { a: Xl.XAtom ¬ Xl.MakeAtom[cm.connection, "PARC_Handwriting"]; IF cm.typeAtom=a AND cm.w[0]=Xl.AtomId[a] THEN { i: INT32 ~ LOOPHOLE[cm.w[1]]; stuffKey: INT32 ~ -1; nextKey: INT32 ~ -3; SELECT i FROM stuffKey => { text: Rope.ROPE ¬ XlCutBuffers.Get[cm.connection]; InsertRope[widget, text, TRUE]; }; nextKey => { XTkInputFocus.SetFocus[XTkInputFocus.NextFocusTarget[widget]]; }; ENDCASE => { SELECT TRUE FROM i<0 => { XTkFriends.CallNotifiers[widget, $HandwritingClientMessage, NEW[INT¬i], cm] }; i<=255 => PushChar[widget, VAL[i]]; ENDCASE => {}; }; }; }; ENDCASE => {}; EXITS oops => {}; }; FieldButtonChoice: XTk.WidgetNotifyProc ~ { ENABLE { Xl.XError => GOTO Oops; UNCAUGHT => IF ~debugging THEN GOTO Oops; }; field: XTk.Widget ~ NARROW[registerData]; time: Xl.TimeStamp ¬ Xl.LastTime[field.connection]; From: PROC [convention: ATOM] = { r: Rope.ROPE ¬ XlCutBuffers.Get[field.connection, convention]; ReplaceRope[field, r]; }; To: PROC [convention: ATOM] = { XlCutBuffers.Put[field.connection, XTkLabels.GetText[field], convention]; }; FromProp: PROC [prop: ATOM] = { WITH XTk.GetWidgetProp[field, prop] SELECT FROM r: Rope.ROPE => XTkLabels.SetText[field, r]; ENDCASE => {}; }; SELECT callData FROM $clear => { XTkLabels.SetText[field, NIL]; XTkInputFocus.SetFocus[field, time]; }; $PRIMARY => From[$PRIMARY]; $CLIPBOARD => From[$CLIPBOARD]; $CutBuffer0 => From[$CutBuffer0]; $previous => FromProp[$previous]; $default => FromProp[$default]; $putPRIMARY => To[$PRIMARY]; $putCLIPBOARD => To[$CLIPBOARD]; $putCutBuffer0 => To[$CutBuffer0]; $Dismiss => XTkShellWidgets.DestroyShell[XTk.RootWidget[widget]]; ENDCASE => {}; EXITS Oops => {}; }; menuList: XTkPopUps.ChoiceList ~ LIST[["empty", $clear], ["from primary selection", $PRIMARY], ["from clipboard", $CLIPBOARD], ["from cut buffer", $CutBuffer0], ["actually typed text", $previous], ["default text", $default], ["to primary", $putPRIMARY], ["to clipboard", $putCLIPBOARD], ["to cut buffer", $putCutBuffer0], ["Dismiss", $Dismiss]]; menuClosure: XTkPopUps.WidgetCreateClosure ~ XTkPopUps.WidgetCreateClosureFromChoiceList[list: menuList, defaultNotify: FieldButtonChoice]; CreateField: PUBLIC PROC [widgetSpec: XTk.WidgetSpec ¬ [], text: Rope.ROPE ¬ NIL, style: StyleSpec ¬ []] RETURNS [w: XTk.Widget] = { widgetSpec.class ¬ XTkFriends.InitClassField[widgetSpec.class, fieldClass]; w ¬ XTkLabels.CreateLabel[widgetSpec: widgetSpec, text: text, style: style]; XTk.PutWidgetProp[w, $default, text]; }; GetFieldData: PROC [widget: XTk.Widget] RETURNS [fieldData: FieldData] = INLINE { fieldData _ NARROW[XTkFriends.InstPart[widget, fieldClass]]; }; FieldInitInstPart: XTk.InitInstancePartProc = { fieldData: FieldData ~ NEW[FieldDataRec]; XTkFriends.AssignInstPart[widget, fieldClass, fieldData]; XTk.AddPermanentMatch[widget, [proc: EventProc, handles: events, tq: Xl.CreateTQ[], data: widget], [keyPress: TRUE, buttonPress: TRUE, buttonRelease: TRUE]]; }; PushChar: PROC [widget: XTk.Widget, ch: CHAR, asRope: Rope.ROPE ¬ NIL] = { SELECT ch FROM 0c, Ascii.LF, Ascii.CR => {}; 4c, Ascii.DEL => { ReplaceRope[widget, NIL]; }; Ascii.BS => { InsertBS[widget, TRUE]; } ENDCASE => { IF asRope=NIL THEN asRope ¬ Rope.FromChar[ch]; InsertRope[widget, asRope, TRUE]; }; }; InsertBS: PROC [widget: XTk.Widget, remember: BOOL] = { text: Rope.ROPE ¬ XTkLabels.GetText[widget]; ip: INT ¬ MIN[XTkLabelsExtras.GetCharInsertionIndex[widget], Rope.Length[text]]; IF ip>0 THEN { left: Rope.ROPE ¬ Rope.Substr[text, 0, ip-1]; right: Rope.ROPE ¬ Rope.Substr[text, ip, LAST[INT]]; text ¬ Rope.Concat[left, right]; ip ¬ ip-1; XTkLabels.SetText[widget, text]; XTkLabelsExtras.SetCharInsertionIndex[widget, ip]; IF remember THEN XTk.PutWidgetProp[widget, $previous, text]; }; }; InsertRope: PROC [widget: XTk.Widget, r: Rope.ROPE, remember: BOOL] = { text: Rope.ROPE ¬ XTkLabels.GetText[widget]; ip: INT ¬ MIN[XTkLabelsExtras.GetCharInsertionIndex[widget], Rope.Length[text]]; left: Rope.ROPE ¬ Rope.Substr[text, 0, ip]; right: Rope.ROPE ¬ Rope.Substr[text, ip, LAST[INT]]; text ¬ Rope.Cat[left, r, right]; ip ¬ Rope.Length[left]+Rope.Length[r]; XTkLabels.SetText[widget, text]; XTkLabelsExtras.SetCharInsertionIndex[widget, ip]; IF remember THEN XTk.PutWidgetProp[widget, $previous, text]; }; ReplaceRope: PROC [widget: XTk.Widget, r: Rope.ROPE] = { XTkLabels.SetText[widget, r]; XTkLabelsExtras.SetCharInsertionIndex[widget, LAST[INT]]; }; FieldPreferredSize: XTk.PreferredSizeProc = { preferred ¬ [ size: [widget.s.geometry.size.width, widget.s.geometry.size.height], pos: widget.s.geometry.pos, borderWidth: widget.s.geometry.borderWidth ]; IF preferred.borderWidth<0 THEN preferred.borderWidth ¬ 0; IF preferred.size.width<=0 THEN preferred.size.width ¬ 200; IF preferred.size.height<=0 THEN preferred.size.height ¬ 20; }; CreateLabeledField: PUBLIC PROC [widgetSpec: XTk.WidgetSpec ¬ [], label, init: Rope.ROPE ¬ NIL, style: StyleSpec ¬ [], labelWidth, fieldWidth: INT ¬ 0] RETURNS [w: XTk.Widget] = { lab, field: XTk.Widget; field ¬ XTkFields.CreateField[ widgetSpec: [geometry: [size: [width: (IF fieldWidth>0 THEN fieldWidth ELSE Xl.dontUse), height: widgetSpec.geometry.size.height]]], text: init, style: style ]; lab ¬ XTkButtons.CreateButton[ widgetSpec: [geometry: [size: [width: (IF labelWidth>0 THEN labelWidth ELSE Xl.dontUse), height: widgetSpec.geometry.size.height]]], text: Rope.Concat[label, " "], style: style, hitProc: LabeledFieldLabelHit, registerData: field ]; w ¬ XTkContainers.CreateXStack[widgetSpec, LIST[lab, field]]; XTkDelegation.Delegate[from: w, alternateKey: $TextDelegation, to: field]; XTkInputFocus.Delegate[w, field]; }; LabeledFieldLabelHit: XTk.WidgetNotifyProc ~ { field: XTk.Widget ~ NARROW[registerData]; time: Xl.TimeStamp ¬ Xl.LastTime[field.connection]; WITH event SELECT FROM br: Xl.ButtonReleaseEvent => { pm: Xl.PointerMapping ~ Xl.GetPointerMapping[field.connection]; SELECT pm[br.button] FROM 2 => XTkLabelsExtras.SetCharInsertionIndex[field, 10000]; 3 => XTkLabels.SetText[field, ""]; ENDCASE => {}; time ¬ br.timeStamp; }; ENDCASE => {}; XTkInputFocus.SetFocus[field, time]; }; END. H XTkFieldsImpl.mesa Copyright Σ 1991, 1992 by Xerox Corporation. All rights reserved. Created by Christian Jacobi, March 30, 1991 11:59:26 pm PST Christian Jacobi, October 21, 1992 9:22 am PDT XTkPopUps.PopUp[fd.pseudoBase, bp]; XTkPopUps.PopUp[fd.pseudoBase, bp]; BEGIN Commented out because using this would need ownwerGrabButtons TRUE and using the poor mans gesture recognition needs ownwerGrabButtons FALSE pseudoBase: XTkPopUps.PseudoBase ¬ XTkPopUps.CreatePseudoBase[widget]; XTkPopUps.SetMenuCreator[pseudoBase, menuClosure]; fieldData.pseudoBase ¬ pseudoBase; END; Κ •NewlineDelimiter –(cedarcode) style™code™Kšœ Οeœ7™BKšœ;™;K™.K™—šΟk œ˜ Kšœ˜Kšœ ˜ Kšœ ˜ Kšœ ˜ Kšœ ˜ Kšœ˜K˜Kšœ˜Kšœ ˜ Kšœ˜K˜ Kšœ ˜ Kšœ˜K˜ Kšœ˜Kšœ ˜ Kšœ ˜ Kšœ ˜ K˜Kšœ˜K˜ K˜K˜—šΟn œžœžœ˜Kšžœ­˜΄Kšžœ ˜—Kšžœ˜K˜Kšœ žœžœ˜K˜Kšœžœ˜Kšœ žœ˜"Kšœ žœ˜&K˜Kšœ-˜-K˜K˜cKšœžœžœ žœk˜“K˜šœ žœ˜+šŸ œžœžœ˜8˜*Kšœ ˜ Kšœ˜Kšœ!˜!Kšœ%˜%Kšœ ˜ Kšœ žœ*˜8Kšœ˜—Kšœ*˜*K˜—K˜—Kšœ žœžœ˜#šœžœžœ˜Kšœ#žœ˜'KšœΟc$˜?K˜K™—šŸ œ˜šžœ˜Kšœ žœ˜K˜—Kšœžœ ˜(šžœžœž˜šœ˜Kšœ žœ˜Kšœžœ5žœ˜DK˜Kšžœ žœžœ˜šžœžœžœžœ˜_Kšœ žœ&˜7Kšœžœ˜"Kšž˜K˜—šžœžœžœ˜CKšœ>˜>Kšžœ˜K˜—šžœžœ˜"Kšœ6˜6Kšžœ˜K˜—K˜K˜K˜DKšœ˜—šœ˜K˜<šžœž˜˜K˜%š žœžœžœžœ !œžœ˜iK˜‰K˜—šžœžœž˜K˜K˜GKšžœ8˜?—K˜—K˜:Kšžœ˜—K˜-Kšœ˜—˜K˜˜>K˜—šžœ˜ šžœžœž˜˜Kšœ<žœžœ ˜LK˜—Kšœžœ˜#Kšžœ˜—K˜——K˜—K˜—Kšžœ˜—Kšžœ ˜K˜K˜—šŸœ˜+šžœ˜Kšœ žœ˜Kšžœžœ žœžœ˜)K˜—Kšœžœ˜)K˜3šŸœžœžœ˜!Kšœžœ2˜>K˜Kšœ˜—šŸœžœžœ˜KšœI˜IKšœ˜—šŸœžœžœ˜šžœ žœž˜/Kšœžœ ˜,Kšžœ˜—Kšœ˜—šžœ ž˜˜ Kšœžœ˜Kšœ$˜$K˜—Kšœ˜Kšœ˜Kšœ!˜!Kšœ!˜!Kšœ˜Kšœ˜Kšœ ˜ Kšœ"˜"K˜AKšžœ˜—Kšžœ ˜Kšœ˜—K˜Kšœ!žœ΄˜ΩK˜K˜‹K˜š Ÿ œžœžœ.žœžœžœ˜„K˜KK˜LKšœ%˜%K˜—K˜šŸ œžœžœžœ˜QKšœ žœ*˜