http://www.newton-inc.com/dev/techinfo/qa/qa.htm
nil
'noBackdrop
slot to the base view will stop an application from becoming a backdrop application.viewIdleScript
. In general, applications should release the CPU now and then so the OS can do clean up operations.self
", you can speed things up by doing the lookup explicitly once before executing the loop, and using the call statement to execute the function within the body of the loop.
f1 := {myFn: func() 42};
f2 := {_parent: f1};
f3 := {_parent: f2};
f4 := {_parent: f3};
f5 := {_parent: f4};
f5.test1 := func ()
for i:=1 to 2000 do call myFn with ();
f5.test2 := func() begin
local fn := myFn;
for i:=1 to 2000 do call fn with ();
end
/* executes with a noticeable delay */
f5:test1();
/* executes noticeably faster */
f5:test2();
Use this technique only for functions that don't use inheritance or the self keyword.GetTrapAddress
to get a trap's real address and calling it directly to avoid the overhead of trap dispatch.2+3
will be replaced with 5
by the compiler.) In the meantime, you need to write your code as clearly as possible without relying too heavily on the ordering of functions inside expressions.kDebugMode
constant in your project and have in your application a statement conditioned by the value of kDebugMode
, the NTK compiler removes the entire if/then statement from your application code when the value of kDebugMode
is NIL. constant kDebugMode := true; // define in Project Data
if kDebugMode then Print(...); // in application code
kDebugMode
constant to NIL, then the compiler strips out the entire if/then statement. if getroot().|MyBaseView:MySIG| then
begin
getroot().|MyBaseView:MySIG|:TestThisView();
local s := getroot().|MyBaseView:MySIG|.BlahSize;
end;
installScript
, then in the viewSetupFormScript
for the application's base view. In your case, you can do some math on the frame returned from GetAppParams
to see if the screen is large enough to support your application.Notify
to tell the user why your application cannot run.viewBounds
so it does not appear, use RelBounds(-10, -10, 0, 0)
so the view will be off-screen.viewChildren
and stepChildren
slots to NIL.AddDeferredSend(self, 'Close, nil)
to close the view.protoCloseBox
or protoLargeCloseBox
then your close box will automatically hide itself if your application is the backdrop application. If you also use newtStatusBar
as your status bar proto, the appropriate buttons will shift to fill the gap left by the missing close box. Note that you do not have to use the NewtApp framework to use the newtStatusBar
proto.Close
and Hide
methods so your application cannot be closed.GetUserConfig('blessedApp)
.viewChangedScript
for the view will be called each time the user does something to modify the view. For keyboards, this means the script is called each time the user taps a key. This is the only notification that is provided to indicate the view contents have changed.viewQuitScript
or other custom code to explicitly notify the target that the keyboard is going away, but we do not recommend this. (There may be a hardware keyboard attached, a system keyboard may be open, or the user may be writing into your view. It is a mistake to assume that the only way to modify your view is through your own keyboard.)viewIdleScript
(or call it from the viewIdleScript
.) In the viewChangedScript
, if the 'text
slot has changed, use :SetupIdle(<delay>)
to arrange for the viewIdleScript
to be called in a little while.:SetupIdle(<delay>)
happens again before the first delay goes by (perhaps because the user typed another key,) the idle script will be called after the new delay. The older one is ignored. SetupIdle
resets the timer each time it's called.viewIdleScript
return NIL
so it won't be called repeatedly.GetRoot():BlessApp(appSymbol)
will close the current backdrop application and open the new backdrop application if necessary. Note that appSymbol
must be a valid application symbol of a current installed and active application. BlessApp
does NOT verify that an application can become the backdrop (for instance, it doesn't check the 'noBackdrop
flag for an application). For this reason, BlessApp
must only be used on your own applications. See the Newton DTS Q&A, "How to Prevent an Application from Becoming a Backdrop" for more information about the 'noBackdrop
flag.BlessApp
from within a part's installScript
or removeScript
. If you want to do something like this, use a delayed call to use BlessApp
. stepChildren
slot of the base view of the template file. If both the exported and importing template have children, they will both have a stepChildren
slot. The result is that the stepChildren
slot of the importing prototemplate is masking the one in the exported proto. The instantiated view does not collect all the children from the entire proto chain (though NTK does do this at compile time for user proto templates).stepChildren
is to add a viewSetupChildrenScript
to either your exported proto template or the importer that collects all of the stepChildren
into a runtime stepChildren
array.// AFTER setting up stepChildren, views which "import" this proto
// must call inherited:?viewSetupChildrenScript();
exporter.viewSetupChildrenScript := func()
begin
// get the current value of the "extra" kids
// ...unless the importer added NO kids, in which case, these are OURS
local extraKids := stepChildren;
local items := clone(extraKids);
local kids;
local whichFrame := self;
while (whichFrame) do
begin
// get kids, but NOT using inheritance
kids := GetSlot(whichFrame, 'stepChildren);
// copy any extra stepChildren (but if NO extra kids are defined, don't copy twice!)
if kids and kids <> extraKids then
ArrayMunger(items, 0, 0, kids, 0, nil);
// go deeper into the _proto chain (or set whichFrame to nil)
whichFrame := whichFrame._proto;
end;
stepChildren := items;
end;
stepAllocateContext
slot.GetRoot().buttons.soft
will be non-nil
if there is a "soft" button bar, that is, the button bar is located on the drawable screen. GetRoot():LocalBox()
returns the rectangle that encloses the screen and the tablet. GetAppParams
() returns information about the useful area of the screen, excluding the soft or hard button bar. Used together, this information will allow you to implement any combination of button bar disabling and/or button bar obscuring.KillStdButtonBar
. That API is designed for use when you want to actually remove the button bar so you can replace it - probably with a floating slip. It is a fairly expensive call and does a lot of things you don't need if all you want to do is take over the screen. We recommend avoiding that call if possible.) local params := GetAppParams();
if GetRoot().Buttons.soft then
self.viewBounds := OffsetRect(UnionRect(params.appArea, params.buttonBarBounds),
-params.appAreaGlobalLeft, -params.appAreaGlobalTop)
else
self.viewBounds := params.appArea;
appArea
and locating the rest of the application within that child.viewSetupFormScript
to cover the entire tablet: local params := GetAppParams();
self.viewBounds := GetRoot():LocalBox();
if params.appAreaGlobalLeft then
self.viewBounds := OffsetRect(self.viewBounds, -params.appAreaGlobalLeft, -params.appAreaGlobalTop);
'string
. Next, you need to use the global function BinaryMunger
to munge an empty string into the VBO. This will properly prepare the binary object to be used as a NewtonScript string.StrMunger
as often as needed to copy new string data into the VBO. Here is a code example:// Prepare a VBO to be the string
local myString := GetDefaultStore():NewVBO( 'string, Length("") );
BinaryMunger( myString, 0, nil, "", 0, nil );
StrMunger( myString, StrLen( myString ), nil, "My new string", 0, nil );
// Repeat with more data if necessary...
stdio
library function, the NewtonScript StrLen
function does not need to traverse the string to determine the string length, so you probably don't need to worry about performance hits from its usage.Stringer
global function or the & or && operators, the result is currently a non-VBO string. Be aware that if you accidentally create a very large non-VBO string, the code may throw a "out of NewtonScript heap memory" evt.ex.outofmem
exception.clEditView
every time some change is made, typing is very slow. So, when should it be saved?AddDelayedCall
or AddDelayedSend
can be used. The OS also provides AddProcrastinatedSend
and AddProcrastinatedCall
, which more or less implement the timer-resetting feature for you.viewIdleScript
. The viewIdleScript
is preferred over AddProcrastinatedCall/Send
because of better management of the event queue by the OS. When you call SetupIdle
to start an idle timer, any existing idle timer is reset. Procrastinated calls/sends aren't currently implemented by resetting an existing timer, but rather by creating a delayed event which fires for each call and then checking a flag when the timer expires to see if it's the last one.target
frame, which is usually a soup entry. The entry layer implements StartFlush
to start the timer, and EndFlush
is called when the timer expires and which should ensure that the data is saved to the soup.StartFlush
equivalent could be implemented something like this: StartFlush: func()
begin
self.entryDirty := TRUE;
:SetupIdle(5000); // 5 second delay
end;
viewIdleScript
would look something like this: viewIdleScript: func()
begin
:EndFlush();
nil; // return NIL to stop the idler until next StartFlush
end;
EndFlush
equivalent would look something like this: EndFlush: func()
if self.entryDirty then
begin
// getting data from editView may not
// be necessary at this point
myEntry.editViewData := <editView/self>.viewChildren;
EntryChangeXmit(myEntry, kAppSymbol);
self.entryDirty := nil;
end;
EndFlush
as a separate method rather than just putting the contents in the viewIdleScript
makes it easy to call the method from the viewQuitScript
or viewPostQuitScript
, to guarantee that changes are saved when the view is closed. (The viewIdleScript
may not have been called if the user makes a change then immediately taps the close box or overview or whatever.)DoNotInstall
function. This function is called when the package containing the part is activated for the first time as a result of downloading to the unit, putting away to the Extras Drawer, or installation with API functions such as SuckPackageFromBinary
or SuckPackageFromEndpoint
. The function is not called when the package is installed as a result of card insertion, resetting the unit, or moving the package from one store to another using the Extras Drawer filing. This function is incorrectly mentioned in the Newton Programmer's Guide and Newton Programmer's Reference as DoNotInstallScript
. The proper name of the function is simply DoNotInstall
. nil
, the entire package will not be installed on the device. This provides a convenient way to prevent installation on devices that do not support your package. It's considered bad form to simply fail to install and provide no notification to the user. We recommend at least using GetRoot():Notify(...)
to display a message explaining why you are not installing.EnsureInternal
anything this function leaves behind to avoid the "Grip of Death" problems (the error with the alert "The package 'MyApp' still needs the card you removed...").SetPartFrameSlot
. For example, to create a package that will not install on any unit after the year 2000 (because the world will have ended anyway), do the following: SetPartFrameSlot('DoNotInstall, func()
if Time() >= 50492160 then
begin
GetRoot():Notify(kNotifyAlert, "Millenial",
"This application, and all existence, has expired.");
true; // return non-nil to prevent install
end);
InstallScript
will execute in this case, but the part's DoNotInstall
function will not.SetPartFrameSlot('labels, '_extensions);
InstallScript
part method. InstallScript
for a form/application part only takes one argument, whereas the InstallScript
of an auto part takes two arguments. InstallScript
of a form/application part is EnsureInternal
'ed, an auto part's InstallScript
is not. DeletionScript
to my part, it doesn't get called when the user scrubs the package. Why is DeletionScript
not called?DeletionScript
to your part. The DeletionScript
must be defined in a manner different from the part's InstallScript
or RemoveScript
. You must explicitly set the DeletionScript
slot in your part frame using NTK's SetPartFrameSlot
global function. Here is an example:SetPartFrameSlot('DeletionScript, func() print("Howdy!") );
SetPartFrameSlot
for any part slot other than InstallScript
or RemoveScript
.