http://www.newton-inc.com/dev/techinfo/qa/qa.htm
prefsView
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.recFlags
protoLableInputLine
. 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;