// 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



