// Text of project ListPickerChange written on 5/23/96 at 9:50 AM // Beginning of text file ProjectData /* ** Newton Developer Technical Support Sample Code ** ** ListPicker, Demostratest the protoListPicker that uses and array with a popUp ** ** by Stephen Harris, Newton Developer Technical Support ** ** Copyright © 1993-1996 by Apple Computer, Inc. All rights reserved. ** ** You may incorporate this sample code into your applications without ** restriction. This sample code has been provided "AS IS" and the ** responsibility for its operation is 100% yours. You are not ** permitted to modify and redistribute the source as "DTS Sample Code." ** If you are going to re-distribute the source, we require that you ** make it clear in the source that the code was descended from ** Apple-provided sample code, but that you've made changes. */ //This sample demonstrates the use of a listPicker with a column that does a //popUp action of two current item and allows change. //The data for the listpicker is in an array that exist in the application. //App stuff constant kAppTitle := "The ListPicker"; //Define a basic entry frame for data DefConst('kCanonicalEntry, '{ first: nil, second: nil, }); //Generate the Random data for the Picker DefConst('kRandomDataGeneratorFunc, func() begin local item := clone(kCanonicalEntry); item.first := Capitalize(GetRandomWord(4, 12)); item.second := Capitalize(GetRandomWord(4, 12)); item; end); // End of text file ProjectData // Beginning of file editor.t // Before Script for "editBase" // Copyright © 1993-1996 by Apple Computer, Inc. All rights reserved. // this code will be executed before the template is processed editBase := {viewBounds: {left: -4, top: 46, right: 184, bottom: 138}, new: func(nameRef, editPaths, why, pickerDef, callback, context) begin local view := BuildContext(self); view.nameRef := nameRef; view.context := context; view.callback := callback; view.pickerDef := pickerDef; view.editPaths := editPaths; view.reasonForOpen := why; view:Open(); view; end, title: nil, viewSetupFormScript: func() begin // set a title that is what we are doing if reasonForOpen = 'new then title := "New " else title := "Edit " ; title := title & pickerDef.name ; end, callback: nil, context: nil, editPaths: nil, nameRef: nil, pickerDef: nil, reasonForOpen: nil, viewQuitScript: // must return the value of inherited:?viewQuitScript(); func() begin nameRef.first := Clone(first.entryLine.text) ; nameRef.second := Clone(second.entryLine.text) ; Perform(pickerDef, callback, [nameRef, editpaths, context, reasonForOpen]); nameRef := nil ; context := nil ; callback := nil ; pickerDef := nil ; editPaths := nil ; reasonForOpen := nil ; inherited:?viewQuitScript(); // this method is defined internally end, debug: "editBase", _proto: @180 }; _view000 := {viewBounds: {left: -2, top: 0, right: 78, bottom: 16}, _proto: @229}; AddStepForm(editBase, _view000); first := {viewBounds: {left: 8, top: 24, right: 168, bottom: 48}, label: "First", textSetup: func() begin if nameRef.first then Clone(nameRef.first) ; else Clone("") ; end, debug: "first", _proto: @189 }; AddStepForm(editBase, first); StepDeclare(editBase, first, 'first); second := {viewBounds: {left: 8, top: 56, right: 168, bottom: 80}, label: "Second", textSetup: func() begin if nameRef.second then Clone(nameRef.second) ; else Clone("") ; end, debug: "second", _proto: @189 }; AddStepForm(editBase, second); StepDeclare(editBase, second, 'second); constant |layout_editor.t| := editBase; // End of file editor.t // Beginning of text file pickerDef.f // Copyright © 1993-1996 by Apple Computer, Inc. All rights reserved. // listPicker defs // used to define the pickerDef at compile time. May include all of the slots for the pickerDef. // In the listPicker.pickerDef proto to this DataDef. DefConst('kMyBasicDataDef,{ _proto: protoNameRefDataDef, // required name: "My Data Editor", //name at top left of picker editTitle: "New Data for Second", //Title at top of defaultOpenEditor slip (optional) // method used to determine if a popup menu should appear MakePopup: func(nameRef, fieldPath) begin if fieldPath = 'second then begin local pop := array(3, nil); pop[0]:= Clone(nameRef.second); pop[1]:= 'pickSeparator; pop[2]:= "Change..."; pop; end; end, // default PopVal method assumes that the popup is an array of frames // specialize the method for a picked item that is just a string PopVal: func(item) begin if ClassOf(item) = 'frame then inherited:PopVal(item) ; else item; end, // support selecting edit of existing data from the popUp menu. The only way that you can edit // existing valid data from a listPicker is to call an openEditor function from a popUp menu. // called when an item is selected from a popup // NOTE: since only one column pops a menu we do not need to check which // popup a selection occured in PickActionScript: func(popIndex, tapInfo, context) begin local popup := tapInfo.popup; local nameRef := tapInfo.nameRef; local fieldPath := tapInfo.fieldPath; local value := self:PopVal(popup[popIndex]); //the item that is selected from the popUp list. if StrEqual(value,"Change...") AND (self.OpenEditor OR validationFrame) then begin // stash it so we can restore if they don't enter any info tapInfo.cryoNameRefData := deepClone(nameRef.(fieldPath)); nameRef.(fieldPath) := nil; tapInfo.editPaths := [fieldPath]; _selectOnly := true; // this is where you could call your own editor. if self.OpenEditor then self:OpenEditor(tapInfo, context, 'edit); else self:DefaultOpenEditor(tapInfo, context, 'edit); end else begin nameRef.(fieldPath) := value; context:Tapped('select); end; end, // the following stuff is required for validation Validate: func(nameRef, pathArray) begin // keep track of any paths that fail local failedPaths := []; foreach index, path in pathArray do begin // very simple test since each path is // is supposed to be a string // your test may be more complex and call // other methods to verify particular types of data if NOT :ValidateString(nameRef, path) then AddArraySlot(failedPaths, path) ; // return the failedPaths or an empty array end; return failedPaths ; end, // my own utility function to make sure the string is valid // used :Validate above ValidateString: func(nameRef, path) begin // try and get the data from the nameRef local realData := nameRef.(path) ; // if not data in the nameRef, try and get // the entry and get the data from it if NOT realData then begin entry := EntryFromObj(nameRef) ; if entry then begin realData := entry.(path) ; nameRef.(path) := realData ; end ; end ; // valid if the value is non-NIL and is a filled string return realData AND IsString(realData) AND StrFilled(realData) ; end, // provide this method to open an edit slip for // a new or editited item. OpenEditor: func(tapInfo, context, why) begin local valid := :Validate(tapInfo.nameRef, tapInfo.editPaths) ; // check to see if the nameRef is valid to figure out // what to do if (length(valid) > 0) then begin // if not valid, open the editor return GetLayout("editor.t"):New(tapinfo.nameRef, tapInfo.editPaths, why, self, 'EditDone, context) ; end else begin // just toggle the selection and return nil context:Tapped('toggle) ; return nil ; end ; end, // this is a utility method that is not part of the required // methods. Once the editor is closed, this method gets // called so we can update the listPicker appropriately EditDone: func(nameRef, editPaths, context, why) begin // check to see if the edited item is valid if NOT :Validate(nameRef, editPaths) then // not valid so remove the checkmark (if any) context:Tapped(nil); else begin // is valid, so see if editing or a new item if why = 'edit then begin // change the actual entry // an edit occurs when the entry that is clicked // on does not Validate. local entry := EntryFromObj(nameRef) ; if entry then begin entry.first := nameRef.first ; entry.second := nameRef.second ; EntryChangeXMIT(entry, kAppSymbol) ; end ; // The nameRef was valid, so select it. context:Tapped('select); end else begin // a new data item so add entry to soup local newEntry := Clone(kCanonicalEntry) ; newEntry.first := nameRef.first ; newEntry.second := nameRef.second ; GetUnionSoupAlways(kSoupName):AddToDefaultStoreXMIT(newEntry, kAppSymbol) ; // tell the listpicker to update its information context:Update() ; end ; end ; end, }); //************ /* removed validationFrame slot from data def */ // End of text file pickerDef.f // Beginning of file ListPickerChange.t appBase := {viewBounds: {left: 0, top: 0, right: 241, bottom: 301}, viewFlags: 1, declareSelf: 'base, viewJustify: 0, viewQuitScript: func() begin // memory reclamation project myListPicker.selected := nil; reOrienting:= nil; end, viewSetupFormScript: func() begin //set up app display local b := GetAppParams(); self.viewBounds := RelBounds(b.appAreaLeft, b.appAreaTop, b.appAreaWidth, b.appAreaHeight); //populate myListPicker if NOT reOrienting then :generateData(); end, GenerateData: func() begin // Create entries for the listPicker selected array. // the key function to use is makeNameRef(object, makeObjectthisClass) // which returns an object for the selectedArray. // Note: the object needs to be a subclass of nameRef or of class nameRef // If no class is specified, the object will be of class nameRef // Note: You could pass the class as the second arguement to makeNameRef // instead of using a class slot in the pickerDef local theListPicker := myListPicker; theListPicker.selected := Array(20,nil); for i := 0 to 19 do begin local item := theListPicker.pickerDef:MakeNameRef( call kRandomDataGeneratorFunc with (), nil); // set the state to not selected item._unselected := true; theListPicker.selected[i] := item; end; // select the first item in the listPicker. //*** Note that if singleSelect is set to true // you must make sure that you select only one item theListPicker.selected[0]._unselected := nil; end, title: kAppTitle, reOrienting: nil, ReorientToScreen: func() begin reOrienting:= true; //set to not rebuild the selected array during rotation :syncView(); // stop the selected array from being purged of // non-selected items when it closes myListPicker.dontPurge:= true; :RedoChildren(); // reset the purge slot so that listPicker // will purge when it closes normally myListPicker.dontPurge:= nil; reOrienting:= nil; //the rotation is completed end, OpenSecondEditor: func(value, callback) begin // using the parent as the middleman for message sends to the editor. secondEditor:OpenSecondEditor(value, callback); end, debug: "appBase", viewClass: 74 }; _view001 := {viewBounds: {left: 5, top: 0, right: 169, bottom: 20}, _proto: @229}; AddStepForm(appBase, _view001); mylistpicker := {viewFlags: 513, viewBounds: {left: 0, top: 20, right: 0, bottom: -45}, viewJustify: 240, pickerDef: { _proto: kmyBasicDataDef, // defined in the pickerDef.f file class: 'nameRef, // always include columns: [ // Column 1 { fieldPath: 'first, // field to display in column tapWidth: 100, // width for checkbox & name combined, offset from the right margin doRowHilite: true, }, // Column 2 { fieldPath: 'second, // field to display in column tapWidth: 0, // width from preceeding column to right bounds // do not hilite this row since it is a popup list doRowHilite: nil, }, ], }, selected: nil, suppressNew: true, suppressCloseBox: true, suppressFolderTabs: true, dontpurge: //this slot determines what the listPicker will do when the viewQuitScript is ran. //Set to true when the selected array will not be purged of unselected items when the //listpicker closes. nil, debug: "mylistpicker", _proto: @461 }; AddStepForm(appBase, mylistpicker); StepDeclare(appBase, mylistpicker, 'mylistpicker); _view002 := { buttonClickScript: func() begin whatSelected:open(); end, text: "What is selected", viewBounds: {left: 0, top: 6, right: 100, bottom: 24}, viewJustify: 8396950 , _proto: @226 }; AddStepForm(appBase, _view002); _view003 := {_proto: @401}; AddStepForm(appBase, _view003); whatSelected := {viewBounds: {left: 0, top: 72, right: 100, bottom: 188}, debug: "whatSelected", _proto: @180 }; AddStepForm(appBase, whatSelected); StepDeclare(appBase, whatSelected, 'whatSelected); _view004 := { buttonClickScript: func(textIndex) begin print("selected index " & textIndex); end, viewBounds: {left: 0, top: 0, right: 0, bottom: 116}, viewFont: ROM_fontSystem9, viewLines: 6, viewSetupFormScript: func() begin // call the getSelected fucntion with true to return only the items // that are currently selected' // NOTE: as items are selected nameRef's are created and put in the selected array. // GetSelected returns an array of the selected items and removes all other nameRef's local myArray := []; foreach item in myListPicker:getSelected(true) do AddArraySlot(myArray,(item.first && item.second)); self.listItems := myArray; :SetupList(); end, listItems: nil, viewJustify: 48, viewFormat: 1, useScrollers: true, _proto: @228 }; AddStepForm(whatSelected, _view004); secondEditor := {viewBounds: {left: 0, top: 80, right: 200, bottom: 140}, viewJustify: 16, OpenSecondEditor: func(value, callback) begin // the callBack is the myCallBack function defined in the openEditor of the pickerDef self.callback := callback; self:Open() end, viewQuitScript: func() begin if callback then call callback with (dataLine.entryLine.text); end, debug: "secondEditor", _proto: @180 }; AddStepForm(appBase, secondEditor); StepDeclare(appBase, secondEditor, 'secondEditor); _view005 := {title: "Second", viewBounds: {left: 0, top: 3, right: 100, bottom: 23}, _proto: @229 }; AddStepForm(secondEditor, _view005); dataline := {viewBounds: {left: 5, top: 5, right: -10, bottom: 35}, path: nil, label: "Second", viewJustify: 8388720, debug: "dataline", _proto: @189 }; AddStepForm(secondEditor, dataline); StepDeclare(secondEditor, dataline, 'dataline); // After Script for "appBase" thisView := appBase; // Copyright © 1993-1996 by Apple Computer, Inc. All rights reserved. // this code will be executed before the template is processed constant |layout_ListPickerChange.t| := appBase; // End of file ListPickerChange.t