_PROGRAMMING PARADIGMS_ by Michael Swaine Listing One // Fungus -- A Mushroom Identification Program for Newton by Mike Swaine // Fungus presents a single screen of mushroom attributes, lets the user set // values for some or all of them, and tries to identify the mushroom based // on these values. NB: This is a demo of NewtonScript, not a useful app. // Its "advice" is NOT to be relied upon! The base view of the application is // a frame named Mushrooms. It's based on the protoapp proto. Mushrooms := { viewSetupFormScript: /* executed during view creation */ func() begin // Set view bounds relative to screen dimensions. local b := GetAppParams(); self.viewBounds.top := b.appAreaTop + 2; self.viewBounds.left := b.appAreaLeft + 2; self.viewBounds.bottom := self.viewBounds.top+b.appAreaHeight-4; self.viewBounds.right := self.viewBounds.left+b.appAreaWidth-4; end, title: "Mushroom Field Guide", viewflags: 5, /* visible, clickable, etc. */ viewFormat: 328017, /* pen, frame, etc. */ declareSelf: 'base, /* required for base view */ observations: /* attributes of mushroom to be identified */ {color : "", /* all initialized to emptiness */ size : 0, cap_shape : "", cap_surface : "", gill_type : "", gill_attachment : "", stem_position : "", stem_surface : "", veils : ""}, advisor: /* the mushroom identification engine */ func() begin // Dummy code. Could be extended to a humungous list of IF-THEN tests, // but plan is to replace with a simple expert system. Note: in // NewtonScript, all = tests on structured objects compare pointers, // while < and > tests compare contents. Hence variations in syntax. if strEqual(base.observations.color,"brown") AND base.observations.size > 3 AND strEqual(base.observations.gill_type,"absent") then base : advise("a Bolete",1); else if strEqual(base.observations.color,"brown") AND base.observations.size <= 3 then base : advise("an LBM (little brown mushroom)",1); else base : advise("too little data for a conclusion",0); end, advise: /* outputs the identification */ func(m,c) begin setValue(MessageBox,'text,"It looks like you have" && m & ". \n Confidence level:" && c & "."); end, showSize: /* updates Size display to current SizeSlider value */ func(n) begin setValue(Size,'text,n && "cm"); /* value shown as centimeters */ end, _proto: protoapp, /* proto inheritance link */ }; // Cap Shape, based on the protolabelinputline proto, is a child view of // base view. It displays a label and an input line. Tapping the label // shows a list of values. Tapping a value puts it in the input line. Cap Shape := { viewSetupFormScript: /* executed during view creation */ func() begin // This should set base-relative view bounds. // The protolabelinputline proto that this view is based on // has a child view, entryLine, responsible for the input line. // This is how its slots are accessed: entryLine.viewFont := userFont10; entryLine.text := ""; prevText := entryLine.text; /* save for undo */ end, label: "Cap Shape", /* the label */ labelCommands: /* the values displayed */ ["cylindrical", "conical", "bell", "convex", "flat", "concave"], textChanged: /* invoked when text in input line is changed */ func() begin // Store user selection in slot in observations frame. base.observations.cap_shape := entryline.text; // Register this method's undo method with the system // so the Undo button will know what to do. AddUndoAction('undoTextChange,[prevText]); end, labelClick: /* invoked when user taps the label */ func(unit) begin prevText := entryLine.text; /* save for undo */ return nil; /* otherwise method is not passed */ end, undoTextChange: /* the undo method for this method */ func(t) begin entryLine.text := t; base.observations.cap_shape := entryline.text; end, _proto: protolabelinputline, /* proto inheritance link */ }; // ...and so on. There are also frames for user input of Cap Surface, Gill // Type, etc., but they look like this frame for Cap Shape. // The frame(s) for input of Size, though, are a little different: // SizeSlider, SizeLabel, and Size are views that implement a kind of slider, // an alternative to the protolabelinputline used in Cap Shape. // SizeSlider is based on the protoslider proto. SizeSlider := { viewSetupFormScript: /* executed during view creation */ func() begin viewValue := 5; /* initial setting */ / Display initial slider setting in Size view. base : showSize(self.viewValue); prevValue := viewValue; /* save for undo */ end, // Slider settings are interpreted by interpolating between // minValue and maxValue. This app treats the result as centimeters. minValue: 0, maxValue: 24, changedSlider: /* invoked when slider is moved to a new position */ func() begin // Store user selection in slot in observations frame. base.observations.size := viewValue; // Register this method's undo method with the system // so the Undo button will know what to do. AddUndoAction('undoValueChange,[prevValue]); end, trackSlider: /* invoked as slider is moved */ func() begin // Display slider setting in Size view. base : showSize(self.viewValue); end, viewClickScript: /* invoked when user touches slider */ func(unit) begin prevValue := viewValue; /* save for undo */ return nil; /* otherwise method is not passed */ end, undoValueChange: /* the undo method for this method */ func(v) begin viewValue := v; base.observations.size := viewValue; end, _proto: protoslider, /* proto inheritance link */ }; // SizeLabel, based on the protostatictext proto, labels SizeSlider. SizeLabel := { text: "Size", _proto: protostatictext, /* proto inheritance link */ }; // Size displays the setting of SizeSlider numerically. // It's based on the protostatictext proto. Size := { text: "", _proto: protostatictext, /* proto inheritance link */ }; // View Size is accessible from Mushrooms. // Advise is the button pressed to start the identification. // It's based on the protopicturebutton proto. Advise := { icon: GetPictAsBits("Mushrooms", 1), buttonClickScript: /* invoked when button clicked */ func() begin base : advisor(); /* fire up the identification engine */ end, _proto: protopicturebutton, /* proto inheritance link */ }; // Messagebox displays messages to user. Based on clParagraphView view class. MessageBox := { text: /* initial value */ "Select the characteristics that best describe your find and tap the picture of the mushroom.", viewclass: 81, }; // View MessageBox is accessible from Mushrooms. Example 1: (a) viewBounds.top := b.appAreaTop + 2 (b) myFrame := { slot1 : 1000, frameSlot : { name : "David", game : "Life" }, methodSlot : fun() begin // method body; end } (c) observations := { cap := { cap_surface : "", cap_color : "", cap_shape : "" }, gills := { ... } }