http://www.newton-inc.com/dev/techinfo/qa/qa.htmprefsView and place a reference to the template for your preferences slip there (probably using the NTK GetLayout function.) When the user selects "Prefs" from the Info button in your application, the NewtApp framework will create and open a view based on the template in the prefsView slot.theApp in the preferences view. Use this reference to call the application's GetAppPreferences method. This method will return a frame containing your application's preferences. GetAppPreferences is a method provided by NewtApp and should not be overidden.'|Pref1:SIG|) or create a slot in the preferences frame using your developer signature and save all preferences in that frame. This will guarantee that you don't overwrite slots used by the NewtApp framework. preferencesSlip.viewSetupFormScript := func()
begin
prefs := theApp:GetAppPreferences();
if NOT HasSlot(prefs, kAppSymbol) then
prefs.(kAppSymbol) := {myPref1: nil, myPref2: nil};
end;
SaveAppState method: preferencesSlip.viewQuitScript := func()
theApp:SaveAppState(); // save prefs
internalStore. Setting this slot to true will force the NewtApp framework to save all new items on the internal store. aboutInfo. Place a frame in that slot with the following slots: {tagLine: "", // A tagline for your application
version: "", // The version number for the application
copyright: "", // Copyright information
trademarks: "", // Trademark information
}
aboutView containing a reference to a template for your about view (probably using the NTK GetLayout function.) A view will be created from that template and opened when the user selects "About" from the Info button's popup.
NewtSoup continues to get the FillNewSoup message, even when the soup already exists. Am I doing something wrong?FillNewSoup message needs to be sent. Check the "Setting the UserVisible Name With NewtSoup" Q&A for more details and a description of how to work around the problem.RegUnionSoup?newtSoup called MakeSoup which you can override. The MakeSoup method is responsible for calling RegUnionSoup (or otherwise making a soup) and then calling the FillNewSoup method if the soup is new/empty. MakeSoup is called normally as part of initializing the newtSoup object. Here is a sample MakeSoup method that will use a newly defined slot (from the newtSoup based template) for the user name.MakeSoup method. In particular, MakeSoup is used by the newtSoup implementation to initialize the object, so it needs to set up other internal slots. It's vital that the 'appSymbol slot in the message context be set to the passed argument, and that the 'theSoup slot be set to the soup or unionSoup that MakeSoup creates or gets. (Recall that RegUnionSoup returns the union soup, whether it previously existed or not.)GetSoupList method of union soups used in this code snippet returns an array with the member soups. It should be considered documented and supported. A newly created union will have no members, so FillNewSoup should be called. This is an improvement over the default MakeSoup method, which always calls FillNewSoup if the soup on the internal store is empty.'userName slot, which is looked up in the current context. As with soupName, soupDescr, etc, you should set a new userName slot in the frame in the allSoups frame in the newtApplication template. MakeSoup: func(appSymbol)
begin
self.appSymbol := appSymbol; // just do it...
self.theSoup := RegUnionSoup(appSymbol, {
name: soupName,
userName: userName,
ownerApp: appSymbol,
userDescr: soupDescr,
indexes: soupIndices,
});
if Length(theSoup:GetSoupList()) = 0 then
:FillNewSoup();
end;
allSoups frame, and then cause the application to refresh. The cursor that controls the sort order for the layout is built from the masterSoupSlot slot. Both the default and the overview layouts have a masterSoupSlot which points back to the relevant allSoups slot in the app base view. newtAppBase.allSoups & newtAppBase.allSoups.mySoup are writeable. (Since the frames reside in the package, they are in protected memory.)newtAppBase.allSoups.mySoup:SetupCursor() to create a new cursor using the new query spec.newtAppBase:RedoChildren() to display the items in the new sort order. if IsReadOnly (newtAppBase.allSoups) then
newtAppBase.allSoups := {_proto: newtAppBase.allSoups};
if IsReadOnly (newtAppBase.allSoups.mySoup) then
newtAppBase.allSoups.mySoup :={
_proto: newtAppBase.allSoups.mySoup};
newtAppBase.allSoups.mySoup.soupQuery :=
{indexpath: newKey}; // new sort order!
newtAppBase.allSoups.mySoup:SetupCursor();
newtAppBase:RedoChildren();newtApplication method NewtInstallScript is normally called in the part's InstallScript function. One thing the NewtInstallScript does is register the viewDefs in the NewtApp base view allViewDefs slot using the global function RegisterViewDef. RegisterViewDef requires that the data definition symbol be internal. If the symbol is on the card, then when the NewtRemoveScript tries to unregister the viewDef a reference to data on the card is encountered and the above error message will be shown. This bug will be fixed in a future ROM. InstallScript before calling NewtInstallScript: local mainLayout := partFrame.theForm;
if mainLayout.allViewDefs then
foreach dataDefSym,viewDefsFrame in mainLayout.allViewDefs do
foreach viewDef in viewDefsFrame do
RegisterViewDef (
viewDef, EnsureInternal (dataDefSym) );
partFrame.removeFrame :=
mainLayout:NewtInstallScript(mainLayout);
Note that it is OK to call RegisterViewDef more than once with the same view definition. RegisterViewDef will do nothing (and return NIL) if the template is already registered.newtLabelInputLines (and their variants) use to accomplish their work.'flavor slot of the newtLabelInputLine set of protos, which acts as a translator between the target data frame (or more typically a slot in that frame) and the text field which is visible to the user. For example, it's the filter for newtDateInputLines which translates the time-in-minutes value to a string for display, and translates the string into a time-in-minutes for the target data.newtFilter or one of the other specialized filters described in Chapter 4 of the Newton Programmer's Guide.newtLabelInputLine is opened, a new filter object is instantiated from the template found in the 'flavor slot for that input line. The instantiated filter can then be found in the filter slot of the view itself. The _parent slot of the instantiated filter will be set to the input line itself, which allows methods in the filter to get data from the current environment.inputLine part of the field, and the rest are methods which you can override or call as appropriate.recFlagsprotoLableInputLine. This provides the 'viewFlags settings for the inputLine part of the proto -- the field the user interacts with.recTextFlags'textFlags settings for the inputLine part of the proto.recConfig'recConfig settings for the inputLine part of the proto.dictionaries'dictionaries slot used in recognition, Provides custom dictionaries if vCustomDictionaries is on in the recFlags slot.PathToText()inputLine needs to be updated. The function should read data out of the appropriate slot in the 'target data frame (usually specified in the 'path slot) and return a user-visible string form of that data. For example, for numbers the function might look like func() NumberStr(target.(path))TextToPath(str)inputLine value changes. The result will be written into the appropriate slot in the 'target data frame. The string argument is the one the user has modified from the inputLine part of the proto. For example, for numbers the function might look like func(str) if StrFilled(str) then StringToNumber(str)Picker()PickActionScript message. If the picker is cancelled, send a PickCancelledScript message.labelCommands array.PickActionScript( newValue )Picker method. If you override this method be sure to call the inherited PickActionScript method. PickCancelledScript()Picker method. If you override this method be sure to call the inherited PickCancelledScript method. InitFilter()inputLine that uses this filter is first opened. This method can be used to get data from the current environment (for example, the 'path slot of the inputLine) and adjust other settings as appropriate.newtApplication slot called helpManual. You should store a reference to your help book in this slot.viewHelpTopic which you can use to dynamically change the location the help book is opened to. This slot should store the name of the topic to open to.newtEditView or newtROEditView, I cannot scroll through all the text of a large note. After a few pages it stops scrolling. What is going wrong?newtEditView and newtROEditView have a default scroll height of 2,000 pixels. To work around this limitation, you will need to add a slot called noteSize to your newt(RO)editView. This slot should hold an array of two elements. The first element is the scroll width. If you do not want horizontal scrolling, the scroll width should equal the view width. The second element is the scrollHeight.noteSize slot that you would use to create a newt(RO)EditView with a scroll height of 20,000 pixels. {
_proto: newtEditView,
noteSize: [viewWidth, 20000],
...
}newtApp-based application which does not use stationery. If I set the forceNewEntry slot to nil in my layout and open the application with a nil target, I can still see the entry view. How can I avoid this?newtApp framework will not open the stationery if a target does not exist.newtEntry(Roll/Page)Header proto has a PopIt method which opens the header. You will need to override the StatScript of your newtNewStationeryButton and send the header a PopIt message. Because PopIt is not defined prior to Newton 2.1 OS, you will need to check for its existence before calling it. Here is a code example: newtNewStationeryButton. StatScript: func( theStat )
begin
// Keep a copy of the inherited return value for use below
local result := inherited:?StatScript( theStat );
// Pass self as a parameter for the closure. This gives us a reference
// to the application so we can get the entry view.
AddDeferredCall( func( context )
begin
local entryView := context:GetTargetView();
// This code assumes that your header is declared to the entry
// view with the name theHeaderView
if entryView.theHeaderView.popIt then
entryView.theHeaderView:Popit( true );
end,
[self] );
result;
end;'default in its symbol slot. To change this behavior at run-time, you will need to override the StatScript method of your newtNewStationeryButton.StatScript method, you will set two slots in your application. The first slot is the preferredViewDef slot in your application's base view. The second is the viewDef slot of the current layout. Both of these slots should be set to the symbol of the viewDef that you want displayed. For instance, you might have the following StatScript:StatScript := func( theStat )
begin
preferredViewDef := 'myNewDefaultStationery;
layout.viewDef:= 'myNewDefaultStationery;
// Make sure we call the inherited method
inherited:?StatScript( theStat );
end;preferredViewDef slot or the layout's viewDef slot at any other time. Doing so could cause your application to not work on future versions of the Newton OS.newtEntryPageHeader which is declared to my newtLayout view. Each time I change entries in my application, the header does not get properly updated. What's going wrong?newtApplication views, they need to be declared to their parent. Declaring newtApplication views to a grandparent can cause undefined behavior.overviewTargetClass slot to your application (or any other layout that is a descendent of your newtOverLayout). Set this slot's value to be the symbol that represents your data class (for example, '|myData:SIG|), which must match the data class you use when registering your print format. The NewtApp overview will use overviewTargetClass instead of the default overview class ('newtOverview) supplied by newtOverLayout. usesCursors slot to true indicating that it will use the value target as a multiple item target and it will iterate over it using GetTargetCursor(target). For an example of a print format that can handle multiple items, see the MultiRoute DTS sample.'newtOverview) , see the Q&A "Limitations with NewtOverview Data Class".prefsCache slot of your NewtApp-based application. This slot is defined in your application's base view by the NewtApp framework. This frame will be saved to the system soup when the application closes. prefsCache frame, you must use your registered signature to avoid conflicting with slots that the framework may use. You can name each of your preferences with your signature, or we recommend adding a subframe in a slot named with your signature. For instance, you might have the following code:prefsCache.('|MyPrefs:MySIG|) := {pref1: 1, pref2: 2};newtCheckAllButton (@872) which you can use. This proto sends the CheckAll method to the layout. In Newton 2.1 OS, newtOverLayouts have two new methods, CheckAll and UncheckAll, which implement this behavior. However, none of this is present in Newton 2.0 OS .CheckAll and UncheckAll methods for your overview layout (or any other layout you wish to implement check all for.)protoCheckAllButton. These samples implement an earlier (and less useful) flavor of Check All. The old samples check all the items which are currently visible in the overview, while the Newton 2.1 OS checks all the items that are present in the currently selected folder/card filter. "Checkbook" (version 8 or later) or "WhoOwesWhom" (version 3 or later) will reflect the Newton 2.1 behavior.protoCheckAllButton from the older sample code, since that gives the correct look and button bounds, and modify it as follows:buttonClickScript should look something like this: func()
if newtAppBase.currentLayout = 'overView then
begin
if layout.checkAllPrimed then
layout:UnCheckAll()
else
layout:CheckAll();
layout.checkAllPrimed := NOT layout.checkAllPrimed;
end;
CheckAll:
func()
begin
local curse := dataCursor:Clone();
curse:Reset();
hilitedIndex := nil;
selected := MapCursor(curse, func(e) MakeEntryAlias(e));
AddUndoSend(layout, 'UnCheckAll, []);
layout:DoRetarget();
end;
UncheckAll:
func()
begin
hilitedIndex := nil;
selected := nil;
layout:DoRetarget();
end
hilitedIndex and selected. hilitedIndex is used internally by newtOverLayout to track the tapped item. You may set it to NIL (as above) to clear the value, but do not set it to some other value or rely on its current value. selected contains an array of aliases to soup entries representing the currently selected items, and will be used by the routing and filing buttons for processing entries. It is important to clear hilitedIndex when modifying the selected array in any way.menuRightButtons array for the status bar. The older sample code puts it on the left, however user interface discussions as part of the Newton 2.1 OS effort resulted in the decision to place the button on the right.newtApplication. allLayouts: {
default: GetLayout("default.t"), // see step 9 in the next section
overview: GetLayout("Overview.t"), // set step 4, overview section
} allSoups: {
mySoup: {
_proto: newtSoup,
soupName: "SoupName:SIG",
soupIndices: [],
soupQuery: {} } }
title: kAppName
4) Draw a newtClockFolderTab or newtFolderTab as a child of the newtApp.newtStatusBar as a child of the newtApp.newtStatusBar set the following slots: menuLeftButtons: [newtInfoButton]
menuRightButtons: [newtActionButton, newtFilingButton]
7) Save the layout file as "main.t" and add it to the project.newtLayout in the new layout file.viewJustify slot to the newtLayout and set it to parentRelativeFull horizontal and vertical.viewBounds of the newtLayout to: {top: 20, // leave room for the folder tab
bottom: -25, // leave room for the status bar
left: 0,
right: 0}
5) Draw a newtEntryView as a child of the newtLayout.viewJustify slot and set it to parentRelativeFull horizontal and vertical (necessary only until platform file is updated).viewBounds of the newtEntryView to: {top: 0, bottom: 0, right: 0, left: 0};
8) Draw slot views as children of the entry view to display slots from the soup entry. newtLabelInputLine as a child of the newtEntryView. label: "My Label"
path: 'myTextSlot
c) Draw a newtLabelNumInputLine as a child of the newtEntryView. label: "Number"
path: 'myNumberSlot
9) Save the layout file as "default.t" and add it to the project. Move it so that it is compiled before the main layout (use the Process Earlier menu item).newtOverLayout in the new layout file.Abstract slot to the newtOverLayout, for example: Abstract := func(item, bbox )
begin
local t := item.myTextSlot & ",";
if item.myNumberSlot then
t := t && NumberStr(item.myNumberSlot);
MakeText(t, bbox.left+18, bbox.top,
bbox.right, bbox.bottom - 18);
end;
4) Save the layout file as "overview.t" and add it to the project. Move it so that it is compiled before the main layout (use the Process Earlier menu item). InstallScript := func(partFrame) begin
partFrame.removeFrame :=
(partFrame.theForm):NewtInstallScript(partFrame.theForm);
end;
RemoveScript := func(partFrame) begin
(partFrame.removeFrame):
NewtRemoveScript(partFrame.removeFrame);
end;
2) Save the text file and add it to the project.callbackID parameter to the RegSoupChange global function. If you also use your application's symbol as the callbackID parameter, you will overwrite the NewtApp framework's registration. There are two ways to work around this problem.callbackID symbol in your call to RegSoupChange.NewtSoupChangedNotify method is called. It is passed the same four parameters as the callback function parameter of RegSoupChange.NewtSoupChangedNotify method, be sure to call the inherited method. application:NewtSoupChangedNotify(theName, appSym, changeType, changeData)
begin
// Do your stuff here
inherited:?NewtSoupChangedNotify( theName, appSym, changeType, changeData );
end;