<<

AGUIDETOWORKWITH SQUEAKMORPHCLASSES Author: OnurAytar NortheasternUniversity CSIS Date: November2002 Squeak !3 . 0

Complimentary file:

_V`^aGb cMd1e;f+gMhTi j fkb

fmlnpoHeRgMhTq9r¦o/oMnpokrqq4hq0rq)qFsPr s+fU`^l rpatvuUf/omhTq

n r lEwh?gM`¨xylMom` r3gMhgOr sz

x?x?xXi nnTqi lh¦ei hg©e{¨c`;_VhT{©rt,s2rpa¦{

¢¡¤£¦¥¨§©£ ¡¥¡©   £ ¨ ¦ !#"$&%¨£(')!&§+*,£-©£§/.0 1*©¥¨§2 3£4#56¡  £¦¥¨§ !

78 78 8

.9;:<;=?>)¨A@B%<§2 £¢*,)CED=F;£G-*§H¡; ¡G  1I

J J

8 8

.<¡K¥$C( %1 6§©*4!L BCM¡N¥¨§/£F¡9%<§2 ©CO=P£ © 3: !0I .<¡K¥$C %1Q &§R;£ @S*T£T§U¥?;=6§/.<¡K¥

8 8 8 8

C< %1 &§ *,V9§W X§+*,Y9 §¤E Z% ¥ ©C[CM¡2£ §/: !\*;¥?*$Q 3£ .]*,)C^¡K¥T ¨I

2 TableofContents: Syntaxandterms 4 PartI-WorkingwithSqueakMorphClass 5 PartII-TheMakingofaSimpleButton 7 PartIII-TheMakingofaSpectrum 13 PartIV-TheMakingofaShapeButton 17 PartV-TheMakingofaListBox 34 Farewell 48 SqueakMorphClassReference 49

3 Syntax: _assignment “comment” <>thereaderwillselectthetextinsidethetags ^return Terms: Action : codetoevaluate Event : auserinterrupt Morphclass : aclassinSqueak!Withdisplayproperties. class : anysubclassofMorphclass. Timer : aclockinterruptataspecifiedinterval

4 PartI–WorkingwithSqueakMorphClasses 1.WhatistheMorphClass? Morphclassisanobjectwithatwodimensionaldisplayandvisualproperties. Therootofallmorphicobjectscanbefoundatthedirectory“Morphic–Kernel” inSqueakSystemBrowser(thegreenwindow) 2.Whatdoesamorphicobjectdo? Amorphicobjectcanhandleusereventsandcancontainothermorphs.Italso “steps”meaningthatitcanactaccordingtotime.Besidesthese,haveI mentionedthatitisdisplayedonthescreen? 3.HowtodisplayaMorph? AmorphmustbeopenedinaSqueakWorldinordertobedisplayed.Themost commonwaytodothisistousethe“openInWorld”method.Thefollowingisan examplewrittenintheWorkSpace(thepinkwindow) m_Morphnew. “Createanewmorphinstance” mopenInWorld. “Showtheinstance” Thiswilldisplayamorphwhendone.Todoit:selectallthetextaboveinthe Workspace,rightclickandclickon‘doit’. 4.Howtochangethevisualpropertiesofamorph? Amorphhasvisualpropertiesregardingtoitscolor,sizeandposition.The followingmethodscanbeusedtoaltertheseproperties: • color:aColor • extent:aPoint • height:aNumber • width:aNumber • position:aPoint • top:aNumber • left:aNumber Let’schangethepropertiesofm,whichweopenedintheprevioussection. AgainintheWorkSpace: mcolor:Colorblack. “Makethemorphblack” mextent:200@150. “Makeitthisbig” mheight:170. “Ididn’tlikeit,let’smakeittaller” mwidth:170. “Onthesecondthought,asquarewouldseemnicer” mposition:100@100. “Move,Ican’tseeathing” mleft:50. “Alittlemoretotheleft,okay”

5 mtop:50. “Alittlemoreupwards,that’sgood” 5–Whatisasubmorph? Asubmorphisamorphwhichiscontainedbyanothermorph.Thissounds betterintheotherdirection:Amorphcannestothermorphsandthemorphsit nestsarecalleditssubmorphs. Allmorphshaveaninstancevariablecalledsubmorphs.Thevariable submorphsisinitializedtobeanOrderedCollectionandusedtotrackthe morphscontained. Allsubmorphsaredependedtotheirowner.Theirpositionschangewhenthe owner’spositionchanges.Theirvisibilityisalsodependenttotheirowner.They aredeletedwhentheownerisdeleted. Anotherissueinsubmorphsistheirz-order,meaningwhichmorphisonthe frontandwhichisattheback.Thez-orderfollowstheoppositeorderinthe OrderedCollectionsubmorphs.Firstitemonthefront,lastitemontheback. ThefollowingaresomecommonsubmorphmethodsoftheMorphobject: • addMorph:aMorph • addMorphFront:aMorph • addMorphBack:aMorph • aMorphdelete • removeAllMorphs • submorphs Let’saddsomesubmorphstom.Yeah,misgettingpopular.AgainintheWork Space: b_BorderedMorphnew. “CreateanewBorderedMorphinstance” maddMorph:b. “Addtheinstancetom” Now,probablybisnotinsidem.Trytomovem,youwillseebismovingalong withit.Butwedefinitelywantbtobeinsidem. bposition:mposition+(20@20). Allright,itisdone. Now,let’saddanothermorph. r_RectangleMorphnew. maddMorph:r. rposition:mposition+[20@20).

6 Okay,weaddeditbutwheredidbgo?bisactuallyatthebackofrnow.Idon’t knowyou,butIwantedittobeinthefrontline.Hence, rdelete. “Goodbyer” r_RectangleMorphnew. maddMorphBack:r. rposition:mposition+[20@20). rextent:70@70. NowthiswaswhatIwantedtodo.Why?…Ijustdid. 6–Thisisit?Arewedone? Nope,wearenotdone.ButthisisallfortheWorkSpaceaction.Thenextstep willbe“TheMakingofaButtoninSqueak”andwewillbecreatinganobject whichcanhandleevents.

7 PartII–TheMakingofaButtonwithSqueak Inthissectionwewillcreateanewbuttonobjectforouruse.Ournewobject willdemonstrateinheritanceboththroughextensionandmapping.Howeverwe wouldliketokeepeverythingorganized.Sowestartwiththebasics. 1–HowtocreateanewobjectcategoryinSqueak Inordertoaccomplishthistask,weshouldfirstopenthegreenwindow,the SystemBrowser.OnthetopleftpaneoftheSystemBrowser: • Rightclick • Select“additem…” • Enteracategoryname. 2–HowtocreateanewobjectinSqueak Tocreateanewobject,wemustbebrowsingacategory.So,clickonthe categoryyoujustcreated.Thebigbottompanewillchangetothefollowing: Objectsubclass:#NameOfSubclass instanceVariableNames:‘’ classVariableNames:‘’ poolDictionaries:‘’ category:‘’ Herewecanenterthenameofourobjectanddecidewhichobjectitis extending.Alsowecandeclareinstancevariables. Firstletsdeterminewhatweneedforourbutton. • Anameforthebuttonobject • Alabel • Aborder • Anactionforclickevent • Anactionfordoubleclickevent Wewillcallourbutton:SimpleButton. Thenameisokay,butwestillneedbordersandalabel. InordertohaveborderswecanextendBorderedMorphclass.Itwillgiveusall weneedforbackground. Asforlabel,ourobjectmusthaveasubmorphwhichcandisplaystrings. Thereforewewillhaveaninstancevariablecalledlabel.

8 ForactionswewillhavetwootherinstancevariablescalledclickActionand doubleClickAction. Finallywecancreateourbutton. BorderedMorphsubclass:#SimpleButton instanceVariableNames:‘labelclickActiondoubleClickAction‘ classVariableNames:‘’ poolDictionaries:‘’ category:‘’ AndpressALT+stoacceptthechangeswemade.OurButtontakesitsplace ontheobjectlist.Welldone. NowthatweextendedtheBorderedMorph,ourButtonhasallofitsmethods. MoreoverwewilldeclarelabelasaStringMorph,whichwillallowustouseall ofitsmethodstoo. 3–AddingmethodstotheSimpleButton WealreadyhaveaSimpleButtonwithlotsofmethodsinheritedfromthesuper classBorderedMorph.Howeverthisisnotenough.Tohaveafullyfunctional buttonwewilladdthefollowingmethodstoourSimpleButton. • clickAction “gettheclickAction” • clickAction:aBlock “settheclickAction” • doubleClickAction “getthedoubleClickAction” • doubleClickAction:aBlock “setthedoubleClickAction” • foreColor “getforeColor–maptoStringMorph” • foreColor:aColor “setforeColor–maptoStringMorph” • label “getlabel–maptoStringMorph” • label:aString “setlabel–maptoStringMorph” • refresh “centerlabel” Moreoverwewillneedtooverridethemethodslistedbelow • click:evt “doclickActionifexists” • doubleClick:evt “dodoubleClickActionifexists” • extent:aPoint “setextentandrefresh” • handlesMouseDown:evt “yeswehandleit” • height:aNumber “setheightandrefresh” • width:aNumber “setwidthandrefresh” Toaddmethods,wehavetoselecttheSimpleButtonfromtheSystemWindow andthenselectaclassificationfromthenextpane.Thenwecanenterthe methodcodeatthebottompane.

9 4–ThemethodsofSimpleButton click:evt “WhenclickeddoclickActionifitisnotnil” clickAction~=nil ifTrue:[clickActionvalue]!! clickAction ^clickAction clickAction:aBlock clickAction_aBlock doubleClick:evt “WhendoubleclickeddodoubleClickActionifitisnotnil” doubleClickAction~=nil ifTrue:[doubleClickActionvalue] doubleClickAction ^doubleClickAction doubleClickAction:aBlock doubleClickAction_aBlock extent:aPoint “Letthesuperclassdotheworkthencenterthelabel” superextent:aPoint. selfrefresh foreColor ^labelcolor foreColor:aColor labelcolor:aColor handlesMouseDown:evt “Yes,Ihandlemousepressevents” ^true height:aNumber superheight:aNumber. selfrefresh. initialize “Initializemypropertiesandinstancevariables” superinitialize. “initializedallpropertiesandinstancevariablesinheritedfromsuperclass” “Nowinitializemyspecificpropertiesandinstancevariables” selfcolor:ColorlightGray. selfborderColor:Colorblack.

10 label_StringMorphnew. labelcontents:‘SimpleButton’. selfaddMorph:label. selfextent:80@25 label ^labelcontents label:aString “LettheStringMorphdotheworkthencenterthelabel. StringMorhautomaticallyresizetofitcontents.” labelcontents:aString. Selfrefresh mouseDown:evt “waitforotherevents” evthandwaitForClicksOrDrag:selfevent:evt refresh “centerlabel” labeltop:selftop+((selfheight–labelheight)//2). labelleft:selfleft+((selfwidth–labelwidth)//2) width:aNumber superwidth:aNumber. selfrefresh That’sallthemethodsweneedtowriteforSimpleButton 5–TestingtheSimpleButton WenowhaveaSimpleButton,whynotuseit.WecanusetheWorkSpacefor testingourbutton. s_SimpleButtonnew. sopenInWorld. slabel:‘Window’. sclickAction:[SystemWindownewopenInWorld]. Okay,thebuttonisthereanditopensanewSystemWindowwhenweclickon it. Canwechangetheborderwidthofthebutton? sborderWidth:1. Yes,itreallychanges.Althoughwehaven’twrittenaborderWidthmethod, SimpleButtoninheriteditfromitssuperclassBorderedMorph.

11 6–Arewedone? Well,weareclosetocompletethebasicinformationrequiredforusingmorphic objectsinSqueak.Nextchapterisaboutstepsandtimeintervals.Itisaneasy concepttocover.Yet,thereisalotmoretobelearnedinordertobeabletosay wearedone.

12 PartIII–TheMakingofaSpectrum 1–Arewereallymakingaspectrumanalyzer? No,wearenot.IwishIknewalotmoreaboutsoundpatterns,unfortunatelyI don’t.WhatwearegoingtodoisaMorphwhichactslikeaSpectrumanalyzer usingrandomvalues. Whyarewedoingthis?Todemonstratethestepmethodofcourse.Inthispart wewillexaminehowthetimerworksforaMorphobject. 2–Theregularstufffirst Thispartisreallyaneasyone,wewillcreateasimpleDemonstrationMorph object,whichhastwoinstancevariables: • interval “Howfrequentthedisplaywillchange” • rand “Arandomnumbergenerator” intervalisanumberbetween0an1000.randwillbeaRandomobject. Herearetheclassdefinitionandtheinitializemethod Morphsubclass:#DemonstrationMorph instanceVariableNames:‘intervalrand‘ classVariableNames:‘’ poolDictionaries:‘’ category:‘Aytar–CommonControls’ initialize superinitialize. rand_Randomnew. superextent:10@60. selfcolor:Colorblack. selfinterval:200. Now,ifyounoticedtheboldlineintheinitializemethod,thereissomething wrongaboutit.Itsays:“superextent:10@60”Whydowecallthesuperclass. Simplybecausewewilldisableresizing,whichisournextdiscussion. 3–Notallowingdirectresizing Ournewspectrumwillbeafixedobjectlackingflexibility.Sowewouldbetter disablesomeofitsmethods.SinceweextendedMorphclass,ournewobject hasalotofmethodsbydefault.Lookatthefollowingmethods. extent:aPoint “donothing”

13 height:aNumber “donothing” width:aNumber “donothing” Wehaveoverriddenextent,heightandwidthmethods,andtheynowdo nothing.So,ifanyonecallsthemdirectly,nothingwillhappen. Thiswaswhyweused“superextent:10@60”intheinitializemethod.Thisway wecalledtheextentmethodfromtheMorphclass. 4–Moreoverridingfortimer Intheprevioussection,wehaveoverriddenmethodstodisablethem.Nowwe willoverrideothermethodstoenablethem. ThestepandstepTimemethodsareusedfortimingbyMorphclasses.Inthe Morphclasstheyarenotworkingbydefault.Wearegoingtooverridethemas below: stepTime ^interval step selfdrawRectangles stepTimemethodspecifieshowfrequentlythestepmethodwillbeinvoked.The measurementunitsaremilliseconds,soifintervalis1000,thenthestep methodwillbeinvokedonceeverysecond. WehaveoverriddenthestepmethodtocalldrawRectanglesmethodevery interval*milliseconds. 5–Someothertimermethodsthatwedon’tneedinthisobject Therearesomeotherimportanttimermethods,whichareusefultoknow. • startStepping–startsthetimer • stop–stopsthetimer • isStepping–returnswhetherthetimerisactiveornot. AllthesemethodsareinheritedfromMorphclass,asweextenditandthereis noneedtooverridethem. 6–Whatisleftforthespectrum? Westillneedtoimplementthevisualpartsandpropertyset/getmethods.Here theyarewithcomments.

14 drawRectangles “redrawthespectrum” |rncurrentTop| “firstclearallcurrentrectangles” selfremoveAllMorphs. “nowredrawthem” currentTop_selftop+selfheight–5. N_randnextInt:12. (1to:n) do:[:i| r_selfnewElement:i. rtop:currentTop. Rleft:selfleft. SelfaddMorph:r. currentTop_currentTop–5. ]. newElement:n “CreateanewRectangleMorphwiththecoloraccordingtoitsposition” |r| r_RectangleMorphnew. Rextent:10@4. “ifnislessthen5,rectangleislightgreen” n<5 ifTrue:[ rcolor:Colorgreen. RborderColor:ColorlightGreen. ^r ]. “ifnisgreaterthan8,rectangleisorange” n>8 ifTrue:[ rcolor:Colororange. RborderColor:Colororange. ^r ]. “Otherwiserectangleisyellow” rcolor:Coloryellow. RborderColor:Coloryellow. ^r interval ^interval interval:aNumber interval_aNumber Andthereweare.Wehaveauselessbutnicelookingobject.Ouraimwasto learnthesteppingmechanismanyway.Aslongaswereachourgoal,writinga littleobjectisnotaloss.

15 7–Arewedoneyet? YounowhaveallthebasicinformationyouneedtouseMorphclasses. Congratulations. ThetutorialwillcontinuewithmakingofaShapeButtonandaListBox.Both thosecontrolsaremuchmoresophisticatedbuttheyhavethesameidea behindthem. Youhavetwochoices:eitheryoucancontinuereadingthetutorial,oryoucan golookattheclassesyourself.Ifyouaregoingonyourowndonotforgetto clickon“?”intheSystemBrowser.Itcontainsvaluableinformationaboutthe designofobjects.

16 PartIV–TheMakingofaShapeButton Inthispartwearegettingdowntothebusiness.WewillcreateaMorph subclasswith25instancevariables,over70instancemethodsand4class methodsofitsown.Thenumbersmayseemscarybut,ourpathissmoothand clean.Nevertheless,firstthingsfirst. 1-WhatwilltheShapeButtondo? Beforecreatinganobjectwemustdefineaspecificationdocumentforthat object,whichpointstherequirementstheobjectmeets. ShapeButtonSpecifications 1. VisualAspects: • TheShapeButtonshouldbeablehaverectangular,oval orroundedshapes. • TheShapeButtonshouldbeabletohaveaborder. • TheShapeButtonshouldbeabletohaveahover(mouse over)state. • TheShapeButtonshouldbeabletohaveadown(mouse down)state. • TheShapeButtonmusthavealabel. • Thelabelmusthavealignmentoptions. • Hoveranddownstatesmustenabletheusertoswitch themoffandon. 2. Functionality: • TheShapeButtonmustbeabletohandleallmouse eventsexceptdrag&drop. • TheShapeButtonmusthaveanindexvalueincaseifit isneeded. Herewego,ifwetaketheunderlinedexpressionsfromthespecifications,we willseethatthereisalottodowiththisobject. 2–DesignDecisions 2.1.Whichclasstoextend? Now,thisisatoughquestion.WeknowthattheShapeButtonrequiresborders, butaBorderedMorphoraRectangleMorphisoutofquestion,since ShapeButtonmayhaveanovalshapetoo.Fromthesamepointofview, extendingEllipseMorphclassisalsoimpossible. Therefore,wearegoingtoextenttheMorphclassitself,andusemappingfor theshape.Whatwasmapping?Mappingislinkinganobject’smethodstosome ofitssub-objects.

17 2.2.Decidingonsubmorphs. Sofarsogood;nowthatwehavedecidedtousemappingformostofthevisual properties,weshouldselectthesubmorphsandcreateinstancevariablesfor them. AswedidinSimpleButton,wewilluseaStringMorphforthelabel. Inadditionwewillhaveaninstancevariablecalled“mask”,whichwillbecomea RectangleMorphoranEllipseMorphonrequest. Sowehavetwoinstancevariablesforsubmorphs: • label • mask 2.3.Problemsinmappingduetothestates Normally,wecouldmapmethodslikecolor,borderColortothemaskweare usingasbelow: color:aColor maskcolor:aColor color ^maskcolor However,thiswillnotworkduetothehoveranddownstates.Wemustkeep theoriginalcolorandothervariablesoftheShapeButton.Soweneedthe followinginstancevariables: • normalBorderColor • normalBorderWidth • normalColor • normalForeColor 2.4.Issuesabouthoveranddownstates Fromthespecificationsweknowthatthesestatescanbeturnedonandoff.

Yes,weneedtwoadditionalinstancevariableswhichare eystrovalues: • hasHoverEffect • hasMouseDownEffect Besideswewillneedtostorethevisualpropertiesofthesestates.Yes,even moreinstancevariables:

18 • hoverBorderColor • hoverBorderWidth • hoverColor • hoverForeColor • downBorderColor • downBorderWidth • downColor • downForeColor Wow,thisisalot.Butitcan’tbehelped. 2.5.Actionsuponmouseevents IguessyourememberwhatwedidforSimpleButton.WehadaclickActionand adoubleClickActioninstancevariables.Thistimeweneedalotmore,sincethe specificationsstatethattheShapeButtonmustbeabletohandleallmouse eventsexceptdrag&drop.Belowisthelistofactionvariables,whichwillbe blocks. • clickAction Actiontobetakenwhenclicked • doubleClickAction Actiontobetakenwhendoubleclicked • mouseDownAction Actiontobetakenwhenmouseispressed • mouseUpAction Actiontobetakenwhenmouseisreleased • mouseStillDownAction Actiontobetakenifmouseisstillpressed • mouseOverAction Actiontobetakenwhenhover • mouseLeaveAction Actiontobetakenwhenrolloff. TheseeventsareallimplementedinMorphclass,however,wewillneedto overridethemtousetheseinstancevariables. 2.6.Didwemisssomething? Unfortunatelywedid.Westillneedanindexandanalignmentvariable.Sothe finaltwoinstancevariablesare: • index • alignment indexwillsimplybeanumber,alignmentwillbeanumberbetween1and3. Welldone,wehavecompletedtheinstancevariables. 2.7.Whataboutmethods? Well,wehave25instancevariables.Thatmeanswewillhave50methodsfor settingandretrievingtheirvalues.

19 Plus,wewillneedtooverridetheeventmethodsandsizingmethodsaswedid inSimpleButton. Andofcoursewewillhaveinitializationandprivatemethods,someofwhichwe willputintotheclassratherthantheinstance. 2.8.Whyputmethodsintheclass? Firstofallwedon’t(Idon’tknowyou,butIdon’t)wantthesemethodscalledby theuserinruntimeeasily. Besideswealreadyhavealotofmethods,wereallyshouldnotpopulatearound withunusablemethods. 2.9.Methodcategories Sincewehavealotofmethods,itwillbeusefultocategorizethem.Tocreatea newcategoryformethods,weneedtoright-clickonthethirdpanefromtheleft intheSystemBrowserandselect“newcategory…”.Wewillhavethefollowing categories: • eventhandling • events–processing • hovereffect • initialization • mousedowneffect • visualproperties NaturallywewillcreatethesecategoriesafterwecreatetheShapeButtonobject, speakingofwhichwenowarereadyfor. 3–ThecreationofShapeButton Morphsubclass:#ShapeButton instanceVariableNames:‘labelhasHoverEffecthasMouseDownEffect normalColornormalForeColornormalBorderColornormalBorderWidth hoverColorhoverForeColorhoverBorderColorhoverBorderWidthdownColor downForeColordownBorderColordownBorderWidthmouseOverAction mouseLeaveActionmouseDownActionmouseStillDownActionmouseUpAction clickActiondoubleClickActionmaskalignmentindex‘ classVariableNames:‘’ poolDictionaries:‘’ category:‘’ Therewego,byacceptingthisweofficiallycreatetheShapeButton.

20 4–InstancemethodsofShapeButton Assumingthatyoualreadyreadthepreviouschapter,Ibelievethatyoualready knowhowwemapmethods,howwesetandgetvariables.Therefore,wewill onlydiscusstheimportantmethods,whichareintroducedforthefirsttime.All ofthemethodscanbefoundattheendofthischapter. 4.1.Handlingmouseover handlesMouseOver:evt ^true. ByoverridingthismethodofMorphclass,wearestatingthattheShapeButton handlesmouseoverevent. 4.2.Handlingmousestilldown handlesMouseStillDown:evt ^true. Thesameasmouseover,wearestatingthatShapeButtonhandlesthisevent too. 4.3.Whattodouponevents Wewilloverridethemethodsbelow: • click:evt whattodowhenclicked • doubleClick:evt whattodowhendoubleclicked • mouseDown:evt whattodowhenmouseispressed • mouseEnter:evt whattodowhenmouseisover • mouseLeave:evt whattodowhenmouseleaves • mouseStillDown:evt whattodoifmouseisstillpressed • mouseUp:evt whattodowhenmouseisreleased FormouseDown,mouseUp,mouseEnterandmouseLeaveeventswewillneedto implementthehoveranddowneffects.Hereisthecodeandexplanations. mouseDown:evt hasMouseDownEffect ifTrue:[ selfcolor:downColor. SelfborderColor:downBorderColor. SelfforeColor:downForeColor. SelfborderWidth:downBorderWidth. ]. mouseDownAction~=nil ifTrue:[mouseDownActionvalue]. EvthandwaitForClicksOrDrag:selfevent:evt

21 IfhasMouseDownEffectistrue,thenthevisualpropertiesaresettothedown statesettings. Afterthat,ifanactionhasbeenassignedtotheevent,thatactionisinvoked. mouseUp:evt hasMouseDownEffect ifTrue:[ selfcolor:normalColor. SelfborderColor:normalBorderColor. SelfforeColor:normalForeColor. SelfborderWidth:normalBorderWidth. ]. mouseUpAction~=nil ifTrue:[mouseUpActionvalue]. Whenmouseisreleased,thenthebuttonisnotindownstateanymore.Sowe settheoriginalvaluesback. Andofcourseweinvoketheactionifitexists. ThisisthesameforthemouseEnterandmouseLeaveevents,asitcanbeseen intheirmethods.Theonlydifferenceisthatweareswitchingthehoverand normalstate. mouseEnter:evt hasHoverEffect ifTrue:[ selfcolor:hoverColor. SelfborderColor:hoverBorderColor. SelfforeColor:hoverForeColor. SelfborderWidth:hoverBorderWidth. ]. mouseOverAction~=nil ifTrue:[mouseOverActionvalue]. mouseLeave:evt hasHoverEffect ifTrue:[ selfcolor:normalColor. SelfborderColor:normalBorderColor. SelfforeColor:normalForeColor. SelfborderWidth:normalBorderWidth. ]. mouseLeaveAction~=nil ifTrue:[mouseLeaveActionvalue] Thestatesarecompletebutwestillhaveotheractions.Heretheyare: click:evt clickAction~=nil ifTrue:[clickActionvalue]

22 doubleClick:evt doubleClickAction~=nil ifTrue:[doubleClickActionvalue] mouseStillDown:evt mouseStillDownAction~=nil ifTrue:[mouseStillDownActionvalue] Hereweare,wecompletedallevents. 4.4.Overcomingthemappingproblem Aswediscussedearlier,directmappingdoesnotworkinourcase.Thereforewe willwritemultiplemethodsandkeepourvariables. color:aColor maskcolor:aColor. color ^maskcolor. TheseandrelatedmethodssuchasborderWidthwillbeoverriddentoavoid problemsfrominheritance. normalColor:aColor normalColor_aColor. Selfcolor:aColor. normalColor ^normalColor hoverColor:aColor hoverColor_aColor hoverColor ^hoverColor mouseDownColor:aColor downColor_aColor mouseDownColor ^downColor Thisisthewaywewillstoreourvariables.AndnotethatsettingnormalColor automaticallysetsthecolorofthemask.Otherrelatedmethodscanbefoundat theendofthischapter. 4.5.Theinstancemethodscooperatingwithclassmethods Someofourinstancemethodswillcooperatewithclassmethods.Asmentioned earlier,classmethodsaresameforallinstances.Youcanalsothinkastheyare staticmethodsinaJavaobjectclass.

23 initialize “initializethecontrolwithdefaultproperties.” Superinitialize. Supercolor:Colortransparent. Selfshape:3. Alignment_3. Label_StringMorphnew. Labelinitialize. Selflabel:‘ShapeButton’. SelfaddMorph:label. ShapeButtondefaultProperties:self. Selfrefresh. Thebottomboldlineiswheretheclassmethodiscalled.Theinstancesimply passesitselftothemethodandtheclassshapesuptheinstance. Anotherimportantissuehereisthatwesetthecolorofthesuperclassto transparent.Whydowedothat?Well,sincewemapcolortothemask,andthe maskmaynotcoveralloftheShapeButtonarea,itisgoodfortheShapeButton itselftobetransparent.Don’tyouthinkso? Shape:anInteger “Settheshapeofthebutton.1–Rectangle,2–Oval,3–RoundedRectangle” anInteger<1 ifTrue:[^false]. anInteger>3 ifTrue:[^false]. Mask~=nil ifTrue:[maskdelete]. anInteger=1 ifTrue:[ mask_ShapeButtonshapeRectangle:self. SelfaddMorphBack:mask. ^true ]. anInteger=2 ifTrue:[ mask_ShapeButtonshapeOval:self. SelfaddMorphBack:mask. ^true ]. anInteger=3 ifTrue:[ mask_ShapeButtonshapeRoundedRectangle:self. MaskcornerStyle:#rounded. SelfaddMorphBack:mask. ^true ]. LabelcomeToFront. Onceagaintheboldlinescallclassmethods.Howevershapemethodisan importantmethodaswediscussedindesigndecisions.

24 Shape:methoddeletescurrentmaskandreplacesitwiththenewoneusing deleteandaddMorphBackmethods,whichwediscussedinthefirstchapter. IdonotknowwhyIused“labelcomeToFront”,sinceIused“addMorphBack”, but“comeToFront”setsz-orderofasubmorphto1. 5.Classmethods Wearealmostdone.Therearenotmanyclassmethodsandtheyaresimple enough.Theybasicallydosomeregulartasksforallinstances. defaultProperties:aShapeButton |s| s_aShapeButton. snormalColor:Colorgray. snormalBorderColor:Colorblack. snormalForeColor:Colorblack. snormalBorderWidth:1. shoverColor:Colorgray. shoverBorderWidth:2. shoverForeColor:Colorblack. shoverBorderColor:Colorblack. smouseDownColor:Colorblack. smouseDownForeColor:Colorgray. smouseDownBorderWidth:2. smouseDownBorderColor:Colorwhite. sturnOnHoverEffect. sturnOnMouseDownEffect. sextent:80@30. defaultPropertiessimplygivesaninstancearegularsetofvalues,andmakeit lookgoodenoughwheninitializedandopened. shapeOval:aShapeButton |m| m_EllipseMorphnew. mextent=aShapeButtonextent. mposition=aShapeButtonposition. aShapeButtonextent=mextent. ^m shapeRectangle:aShapeButton |m| m_RectangleMorphnew. mextent:aShapeButtonextent. mposition:aShapeButtonposition. ^m shapeRoundedRectangle:aShapeButton |m| m_RectangleMorphnew. mcornerStyle:#rounded. mextent:aShapeButtonextent.

25 Mposition:aShapeButtonposition. ^m ThesethreemethodscreatenewRectangleMorphorEllipseMorphinstances andsendthembacktotheShapeButtoninstancetowearasamask. See,thereisreallynothingsophisticatedaboutclassmethodsexceptthatthey arecalledbytheclassname. 6–Chaptersummary Inthischapterwecopedwithmappingandextendingproblems.Wecoveredall mouseeventsexceptdrag&dropandwehandledtwosubmorphswithz-order. Finally,wemadeanintroductiontoclassmethods. Now,wehaveaversatileShapeButton,whichinthenextchapterwewillusefor atotallydifferentpurpose.Iftherewillbeanextchapter. ThispartendswiththemethodsofShapeButton,butyouwillprobablylookat themfromtheSystemBrowser.Justincasetheyarehere. 7–AllmethodsofShapeButton InstanceMethods methodsFor:‘eventhandling’ click:evt clickAction~=nil ifTrue:[clickActionvalue] doubleClick:evt doubleClickAction~=nil ifTrue:[doubleClickActionvalue] handlesMouseDown:evt ^true. handlesMouseOver:evt ^true. handlesMouseStillDown:evt ^true. mouseDown:evt hasMouseDownEffect ifTrue:[ selfcolor:downColor. selfborderColor:downBorderColor. selfforeColor:downForeColor. selfborderWidth:downBorderWidth. ].

26 mouseDownAction~=nil ifTrue:[mouseDownActionvalue]. evthandwaitForClicksOrDrag:selfevent:evt mouseEnter:evt hasHoverEffect ifTrue:[ selfcolor:hoverColor. selfborderColor:hoverBorderColor. selfforeColor:hoverForeColor. selfborderWidth:hoverBorderWidth. ]. mouseOverAction~=nil ifTrue:[mouseOverActionvalue]. mouseLeave:evt hasHoverEffect ifTrue:[ selfcolor:normalColor. selfborderColor:normalBorderColor. selfforeColor:normalForeColor. selfborderWidth:normalBorderWidth. ]. mouseLeaveAction~=nil ifTrue:[mouseLeaveActionvalue] mouseStillDown:evt mouseStillDownAction~=nil ifTrue:[mouseStillDownActionvalue] mouseUp:evt hasMouseDownEffect ifTrue:[ selfcolor:normalColor. selfborderColor:normalBorderColor. selfforeColor:normalForeColor. selfborderWidth:normalBorderWidth. ]. mouseUpAction~=nil ifTrue:[mouseUpActionvalue]. methodsFor:‘events-processing’ clickAction ^clickAction clickAction:aBlock clickAction_aBlock doubleClickAction ^doubleClickAction doubleClickAction:aBlock doubleClickAction_aBlock

27 mouseDownAction ^mouseDownAction mouseDownAction:aBlock mouseDownAction_aBlock mouseEnterAction ^mouseOverAction mouseEnterAction:aBlock mouseOverAction_aBlock mouseLeaveAction ^mouseLeaveAction mouseLeaveAction:aBlock mouseLeaveAction_aBlock mouseStillDownAction ^mouseStillDownAction mouseStillDownAction:aBlock mouseStillDownAction_aBlock mouseUpAction ^mouseUpAction mouseUpAction:aBlock mouseUpAction_aBlock methodsFor:‘hovereffect’ hasHoverEffect hasHoverEffect=nil ifTrue:[hasHoverEffect_false]. ^hasHoverEffect hoverBorderColor ^hoverBorderColor hoverBorderColor:aColor hoverBorderColor_aColor hoverBorderWidth ^hoverBorderWidth hoverBorderWidth:aNumber hoverBorderWidth_aNumber hoverColor ^hoverColor

28 hoverColor:aColor hoverColor_aColor hoverForeColor ^hoverForeColor hoverForeColor:aColor hoverForeColor_aColor normalBorderColor ^normalBorderColor normalBorderColor:aColor normalBorderColor_aColor. selfborderColor:aColor normalBorderWidth ^normalBorderWidth normalBorderWidth:aNumber normalBorderWidth_aNumber. selfborderWidth:aNumber normalColor ^normalColor normalColor:aColor normalColor_aColor. selfcolor:aColor normalForeColor ^normalForeColor normalForeColor:aColor normalForeColor_aColor. selfforeColor:aColor turnOffHoverEffect hasHoverEffect_false turnOnHoverEffect hasHoverEffect_true

methodsFor:‘initialization’ index ^index index:aNumber index_aNumber.

29 initialize “initializethecontolwithdefaultproperties.” superinitialize. supercolor:Colortransparent. selfshape:3. alignment_3. label_StringMorphnew. labelinitialize. selflabel:‘ShapeButton’. selfaddMorph:label. ShapeButtondefaultProperties:self. selfrefresh

methodsFor:‘mousedowneffect’ hasMouseDownEffect hasMouseDownEffect=nil ifTrue:[hasMouseDownEffect_false]. ^hasMouseDownEffect mouseDownBorderColor ^downBorderColor mouseDownBorderColor:aColor downBorderColor_aColor mouseDownBorderWidth ^downBorderWidth mouseDownBorderWidth:aNumber downBorderWidth_aNumber mouseDownColor ^downColor mouseDownColor:aColor downColor_aColor mouseDownForeColor ^downForeColor mouseDownForeColor:aColor downForeColor_aColor turnOffMouseDownEffect hasMouseDownEffect_false turnOnMouseDownEffect hasMouseDownEffect_true methodsFor:‘visualproperties’

30 alignCenter selfalignment:3 alignLeft selfalignment:1 alignRight selfalignment:2 alignment ^alignment alignment:aNumber “1–Leftaligned,2–Rightaligned,3–Center” alignment_aNumber. selfrefresh. borderColor ^normalBorderColor borderColor:aColor maskborderColor:aColor borderWidth ^normalBorderWidth borderWidth:aNumber maskborderWidth:aNumber color ^normalColor color:aColor maskcolor:aColor extent:aPoint superextent:aPoint. selfrefresh foreColor ^normalForeColor foreColor:aColor labelcolor:aColor height:anInteger superheight:anInteger. selfrefresh label ^labelcontents label:aString labelcontents:aString. selfrefresh

31 refresh label~=nil ifTrue:[ alignment=1 ifTrue:[ labelleft:selfleft+2 ]. alignment=2 ifTrue:[ labelleft:selfleft+selfwidth–labelwidth–2. ]. alignment=3 ifTrue:[ labelleft:selfleft+((selfwidth–labelwidth)//2). ]. labeltop:selftop+((selfheight–labelheight)//2). ]. mask~=nil ifTrue:[ maskextent:selfextent. maskposition:selfposition. ] shape:anInteger “Settheshapeofthebutton.1–Rectangle,2–Oval,3–RoundedRectangle” anInteger<1 ifTrue:[^false]. anInteger>3 ifTrue:[^false]. mask~=nil ifTrue:[maskdelete]. anInteger=1 ifTrue:[ mask_ShapeButtonshapeRectangle:self. selfaddMorphBack:mask. ^true ]. anInteger=2 ifTrue:[ mask_ShapeButtonshapeOval:self. selfaddMorphBack:mask. ^true ]. anInteger=3 ifTrue:[ mask_ShapeButtonshapeRoundedRectangle:self. maskcornerStyle:#rounded. selfaddMorphBack:mask. ^true ]. labelcomeToFront width:anInteger superwidth:anInteger. selfrefresh

32 ClassMethods methodsFor:‘Shapes’ shapeOval:aShapeButton |m| m_EllipseMorphnew. mextent=aShapeButtonextent. mposition=aShapeButtonposition. aShapeButtonextent=mextent. ^m shapeRectangle:aShapeButton |m| m_RectangleMorphnew. mextent:aShapeButtonextent. mposition:aShapeButtonposition. ^m shapeRoundedRectangle:aShapeButton |m| m_RectangleMorphnew. mcornerStyle:#rounded. mextent:aShapeButtonextent. mposition:aShapeButtonposition. ^m methodsFor:‘instancecreation’ defaultProperties:aShapeButton |s| s_aShapeButton. snormalColor:Colorgray. snormalBorderColor:Colorblack. snormalForeColor:Colorblack. snormalBorderWidth:1. shoverColor:Colorgray. shoverBorderWidth:2. shoverForeColor:Colorblack. shoverBorderColor:Colorblack. smouseDownColor:Colorblack. smouseDownForeColor:Colorgray. smouseDownBorderWidth:2. smouseDownBorderColor:Colorwhite. sturnOnHoverEffect. sturnOnMouseDownEffect. sextent:80@30

33 PartV–TheMakingofaListBox InthisfinalpartwewillcreateourselvesaListBoxcontrolwhichdetectsmost mouseeventsthroughitssubmorphsbutrespondstokeyboardevents.Wewill coverthecursorPointmethod,eventhoughitisnotreallysafetouseinalist box,andwewilldiscoversomescrollbarfacts. AlthoughtheListBoxismoresophisticatedthentheShapeButton,youwillbe amazedthatittakesshortertowritethanwritingShapeButton.Thereasonis simple:wearegoingtouseShapeButtonsinsidetheListBoxandhavethemdo allthedirtyworkforus.WeputalotofeffortintothatShapeButtonafterall. Nowitispaybacktime. 1–TheScrollBar Badnews:Thebuilt-inscrollbarinSqueakworksonlywithModelMorph subclasses. Evidentially,thecreatorsofSqueakhadreasonstodoitthisway.Howeverwe maystillwanttouseScrollBarswithothermorphicobjectsaswell. Thereisanobviousthingtodo:wewillextendtheScrollBar,andoverrideits methodwhereitactuallydoesthescrollingofaModelMorph. ScrollBarsubclass:#ScrollBarForNonModels instanceVariableNames:‘’ classVariableNames:‘’ poolDictionaries:‘’ category:‘’ Andthemethodtobeoverriddenis: setValue:newValue “sendthevaluetoyourowner” |v| v_newValueroundTo:scrollDelta. ownerscrollBarValue:v. Ifyouarecurious,hereistheoriginalmethodwithcomments setValue:newValue “UsingroundTo:insteadoftruncateTo:ensuresthatscrollUpwillscrollthe samedistanceasscrollDown.” ^supersetValue:(newValueroundTo:scrollDelta) Ehm,it’snothere.WehavetolookattheSliderclass. setValue:newValue “Calledinternallyforpropagationtomodel”

34 selfvalue:newValue. selfuse:setValueSelectororMakeModelSelectorFor:‘Value:’ in:[:sel|setValueSelector_sel.Modelperform:selwith:value] What???Whatdoesthecommandinboldmean??? ItisamethodinheritedfromModelMorphclass. use:cachedSelectororMakeModelSelectorFor:selectorBodyin:selectorBlock Itisindeedacomplicatedmethod.Itcompilesanewmethod,withanullreturn valueifthemodeldoesnotsupportcertainactions,ifitsupportstheactions,it doesthedesiredaction. Anyway,withoverridingthismethodwenowhaveaScrollBarForNonModels whichsendsitsvaluetoitsownerwheneverchanged.Neat,eh? 2–SpecificationsforListBox VisualSpecifications • ListBoxshouldhighlightitsitemsuponmouseover • ListBoxshouldgiveadifferentcolortotheselecteditem • ListBox’sizemustbeadjustable Events • ListBoxmustbeabletobescrolledusingarrowkeys • Whenakeyispressed,ListBoxmustselectthenextitemstarting withthepressedkey’svalue,ifsuchanitemexists. • ListBoxmustrespondtoclickanddoubleclickevents Functionality • ListBoxmustbeabletocontainstringandnumericdata • ListBoxmustbeabletocontainanadditionaldataforeachitem • ListBoxmustbeabletoadditemsasawhole • ListBoxmustbeabletoremoveitemsifnecessary 3–DesignDecisions Alistboxissimplyacollectionofitemsplacedinacontainer.Wecanthink thatallrowsinthelistboxisaShapeButton.OurShapeButtonisversatile enoughtoactasarow.MoreOverShapeButtonalreadyhashovereffectandit handlesclickanddoubleclickevents. WecanchangethecolorofShapeButtonaswewish,therefore,re-coloringthe selecteditemisnoproblem,butwehavetostorethecolors. Wecaneasilymaketheboxresizable.

35 Wealsohavetokeepanothercollectionforitemdata,butitisjustacollection, ithasnovisualrepresentationwhatsoever. Addingandremovingitemstoacollectionisapieceofcake. Therearesometopicsaboutresizing,sorrysizeingeneral.Theitemsmaynot fitthebox.Henceweneedthreevariablestostore 1. Maximumnumberofvisiblerows 2. Toprowindexasinitemcollection 3. Andforourconveniencelastrowindexasinitemcollection Weareleftwithkeyboardeventsandweneedtofigureoutawaytoselect items.Naturallytheywillbeselectedwhentheyareclicked,but,howwillthe listboxknowwhichoneitis. Keyboardeventsarethesubjectofthischapter,sodon’tworryaboutthem.For theselection,Isayweusethethepositionoftherow.Yes,itisnotagoodidea, butIwanttodemonstratethecursorPointmethod. Andwhichclassshouldweextend?IsayweextendBorderedMorph,itwilllook good. 4–TheListBoxClass BorderedMorphsubclass:#ListBox instanceVariableNames:‘itemsitemDataselectedItemnormalColor normalForeColorhighlightColorselectedColorselectedForeColorlastListIndex listIndexclickActiondoubleClickActioncontainersmaxVisibleItemstopItem lastItemsBar‘ classVariableNames:‘’ poolDictionaries:‘’ category:‘’ items:anOrderedCollectionofitemstobelisted itemData:anOrderedCollectionofitemdata containers:mayberowswereabettername.AnOrderedCollectionof ShapeButtons. listIndex:currentselecteditem lastListIndex:thiswillletusrefreshfaster.Ratherthanremovingall submorphsandredrawingthem,wewilladdresstwoShapeButtonsupon selectionchanges.

36 5–ThemethodsofListBox Don’tworry;Iwon’tbotheryouwithallmethodsanymore.Wehavejustalittle lefttocover.Themethodsareprovidedattheendofchapterandyouprobably havetheminstalledinSqueaktoo. 5.1–Handlingkeyboardevents Wearegoingtooverrideagain.AsusualMorphclassprovidesthesemethods forus,buttheyarenotfunctional,waitingforustooverride. Thefirstmethodtooverrideis: hasFocus ^true. Iftheusercan’tfocusonanobject,thatobjectcan’thandlekeyboardevents. E.g.,youcanonlytypeintheactivewindow. Thesecondstepis: handlesKeyboard:evt ^true Justlikethemouseevent,isn’tit? Finally,thelastone:

eystroke:event |aChar| (selfscrollByKeyboard:event)ifTrue:[^self]. aChar_eventkeyCharacter. ^selfkeyPressed:aChar Wheneverthereisakeystrokewhilelistboxisfocusedthismethodwillbe invoked.Butwhatdoestheboldlinemean? TheboldlinetellsListBoxtogoandcheckifarrowkeyshasbeenpressed.How doesittellthat?Wearegoingtowritethatmethodtoo. IfscrollByKeyboardmethodreturnsfalse,mentioningsomeotherkeyhasbeen pressed,then“keypressed”methodwillbecalled. So,herearethetwomethodstofinalizekeyboardevent. scrollByKeyboard:event (listIndex=nil) ifTrue:[listIndex_0]. eventkeyValue=30“uparrow”

37 ifTrue:[ listIndex=1 ifTrue:[^true]. selflistIndex:listIndex–1. ^true]. EventkeyValue=31“downarrow” ifTrue:[ listIndex=itemssize ifTrue:[^true]. selflistIndex:listIndex+1. ^true]. ^false keyPressed:aChar |s| s_listIndex. s=0 ifTrue:[s_1]. (sto:itemssize) do:[:i| (aChar=(((itemsat:i)at:1)asCharacter)) ifTrue:[ selflistIndex:i. ^true. ]. ]. Asyoucansee,wechangethelistIndexvariableanddonothing.Sohowcome thelistgetsupdated?ThelistIndexmethoddoesthat. listIndex:aNumber lastListIndex_listIndex. listIndex_aNumber. selectedItem_itemsat:aNumber. listIndex<topItem ifTrue:[ sBarsetValue:(listIndex*(sBarscrollDelta))asFloat. ^true ]. listIndex>lastItem ifTrue:[ sBarsetValue:((listIndex–maxVisibleItems+1)*(sBarscrollDelta)) asFloat. ^true ]. selfupdateList. WheneverthelistIndexgetschangeditcallstheupdateListmethod,which changesthecolorsoftherows.

38 Theimportantpointhereiswhathappensiftheselecteditemisnotindisplay range.listIndexmethodconsidersthattoo.Itsetsthevalueofthescrollbarso thattheselecteditemcanbeseen. 5.2.Mappingmouseevents Justlookattheboldlines,thisisalongmethod. showList |bcurrentTopsDpDl| sBartop:selftop. sBarleft:selfleft+selfwidth–sBarwidth. sBarheight:selfheight. containers=nil ifTrue:[^false]. Items=nil ifTrue:[^false]. topItem=nil ifTrue:[^false]. currentTop_selftop+2. L_lastItem. ((itemssize)<maxVisibleItems) ifTrue:[l_itemssize]. (topItemto:l) do:[:i| ((itemsat:i)~=nil) ifTrue:[ b_ShapeButtonnew. binitialize. bshape:1. balignment:1. blabel:(itemsat:i). selfaddMorph:b. bnormalColor:normalColor. bnormalBorderColor:normalColor. bnormalBorderWidth:0. bnormalForeColor:normalForeColor. bhoverColor:highlightColor. bhoverBorderColor:highlightColor. bhoverBorderWidth:0. bhoverForeColor:normalForeColor. bheight:14. bwidth:selfwidth–2–sBarwidth. btop:currentTop. bleft:selfleft+2. bindex:i. bclickAction:[selfgotClicked:(selfcursorPointy–selftop)]. bdoubleClickAction:[selfgotDoubleClicked]. bdoubleClickAction:doubleClickAction. bturnOnHoverEffect. bturnOffMouseDownEffect. currentTop_currentTop+14. containersadd:b ].

39 ]. ((itemssize)>maxVisibleItems) ifTrue:[ sD_(1/(itemssize))asFloat. pD_((itemssize–maxVisibleItems)/(itemssize))asFloat. sBarscrollDelta:sDpageDelta:pD. sBarinterval:(1–pD)asFloat. sBarvalue:(topItem/(itemssize))asFloat. ] ifFalse:[ sBarscrollDelta:0.02pageDelta:0.2. sBarinterval:1.0 ]. selfupdateList AsyoucanseeintheboldlineswearesettingtheShapeButtonstocallListBox methodsuponevents. gotClicked:aNumber |n| n_(aNumber//14)+1. (n>(itemssize)) ifTrue:[n_itemssize]. selflistIndex:(n+topItem–1). clickAction~=nil ifTrue:[clickActionvalue]. gotDoubleClicked doubleClickAction~=nil ifTrue:[doubleClickActionvalue]. HerewehavethemethodIwasmentioning cursorPointy cursorPointreturnsapointvalueofthepositionofthecursor.Asarowhas14 pixelsheight,wedividetheyofthecursorPointminusListBoxposition,tofind theindexoftherowclicked. IactuallyaddedtheindexpropertytotheShapeButtonspecificallyforthese kindofsituations,butIrealizedIhaven’tcoveredcursorPoint,sotherewasa changeofplans. 6–Cool,nowwhat? Nothing.IamnotgoingtoexplainthewholeListBox.Youhavecompletedall essentialMorphproperties,submorphsandalmostallevents.Fromnowon, everythingdependsonyourdesignandimplementation.

40 7–Whatisnextformetodo? Youcanstillhavealookatmy“Farewell”andyoucanexaminetheMorph reference. Afterthat,well,theguideisoverandIamleavingyourlife. 8–MethodsofListBox methodsFor:‘accessing’ addItem:aString items=nil ifTrue:[items_OrderedCollectionnew]. itemData=nil ifTrue:[itemData_OrderedCollectionnew]. itemsadd:aStringasString. itemDataadd:nil. selfclearList. selfshowList.!! clear items_OrderedCollectionnew. itemData_OrderedCollectionnew. selfclearList itemData ^itemData itemData:anOrderedCollection itemData_anOrderedCollection itemData:anObjectat:anIndex anIndex<=itemssize ifTrue:[ itemDataat:anIndexput:anObject ] itemDataAt:anIndex anIndex<=itemssize ifTrue:[ ^itemDataat:anIndex ] items ^items items:anOrderedCollection items_anOrderedCollection. itemData_OrderedCollectionnew. (1to:anOrderedCollectionsize) do:[:i| itemDataadd:nil ].

41 selfclearList. selfshowList.!! listIndex ^listIndex listIndex:aNumber lastListIndex_listIndex. listIndex_aNumber. selectedItem_itemsat:aNumber. listIndex<topItem ifTrue:[ sBarsetValue:(listIndex*(sBarscrollDelta))asFloat. ^true ]. listIndex>lastItem ifTrue:[ sBarsetValue:((listIndex–maxVisibleItems+1)*(sBarscrollDelta))asFloat. ^true ]. selfupdateList removeItem:anIndex items=nil ifTrue:[^false]. anIndex<=itemssize ifTrue:[ itemsremoveAt:anIndex. selfremoveItemDataAt:anIndex. ]. selfclearList. selfshowList removeItemDataAt:anIndex itemData=nil ifTrue:[^false]. anIndex<=itemssize ifTrue:[ ^itemDataremoveAt:anIndex ] selectedItem ^selectedItem selectedItem:aNumber ^selflistIndex:aNumber methodsFor:‘eventhandling’ handlesKeyboard:evt ^true hasFocus ^true

42

eystroke:event |aChar| (selfscrollByKeyboard:event)ifTrue:[^self]. aChar_eventkeyCharacter. ^selfkeyPressed:aChar scrollByKeyboard:event (listIndex=nil) ifTrue:[listIndex_0]. eventkeyValue=30 ifTrue:[ listIndex=1 ifTrue:[^true]. selflistIndex:listIndex–1. ^true]. eventkeyValue=31 ifTrue:[ listIndex=itemssize ifTrue:[^true]. selflistIndex:listIndex+1. ^true]. ^false methodsFor:‘events-processing’ clickAction:aBloc clickAction_aBlock doubleClickAction:aBlock |b| doubleClickAction_aBlock. containers~=nil ifTrue:[ (1to:containerssize) do:[:i| b_containersat:i. bdoubleClickAction:aBlock. ]. ] gotClicked:aNumber |n| n_(aNumber//14)+1. (n>(itemssize)) ifTrue:[n_itemssize]. selflistIndex:(n+topItem–1). clickAction~=nil ifTrue:[clickActionvalue] gotDoubleClicked doubleClickAction~=nil ifTrue:[doubleClickActionvalue]

43 keyPressed:aChar |s| s_listIndex. s=0 ifTrue:[s_1]. (sto:itemssize) do:[:i| (aChar=(((itemsat:i)at:1)asCharacter)) ifTrue:[ selflistIndex:i. ^true. ]. ] methodsFor:‘initialization’ initialize superinitialize. sBar_ScrollBarForNonModelsnew. selfaddMorph:sBar. ListBoxdefaultProperties:self. maxVisibleItems_(selfheight//14). topItem_1. lastItem_maxVisibleItems. selfcolor:normalColor. containers_OrderedCollectionnew!! hideOrShowScrollBar ^true!! scrollBarValue:scrollValue topItem_(scrollValue*itemssize). topItem<1 ifTrue:[ topItem_1. sBarvalue:sBarscrollDelta. ]. lastItem_topItem+maxVisibleItems–1. (lastItem>(itemssize)) ifTrue:[ lastItem_itemssize. topItem_lastItem–maxVisibleItems+1. ]. selfclearList. selfshowList

methodsFor:‘visualproperties’ extent:aPoint superextent:aPoint. maxVisibleItems_(selfheight//2)+1. lastItem~=nil ifTrue:[lastItem_topItem+maxVisibleItems].

44 selfclearList. selfshowList height:aNumber superheight:aNumber. maxVisibleItems_(selfheight//2)+1. lastItem~=nil ifTrue:[lastItem_topItem+maxVisibleItems]. selfclearList. selfshowList highlightColor ^highlightColor highlightColor:aColor highlightColor_aColor normalColor ^normalColor normalColor:aColor normalColor_aColor normalForeColor ^normalForeColor normalForeColor:aColor normalForeColor_aColor selectedColor ^selectedColor selectedColor:aColor selectedColor_aColor selectedForeColor ^selectedForeColor selectedForeColor:aColor selectedForeColor_aColor width:aNumber superwidth:aNumber. selfclearList. selfshowList methodsFor:‘private’ clearList |b| containers=nil ifTrue:[^false]. ((containerssize)>0) ifTrue:[

45 (1to:containerssize) do:[:i| b_containersat:i. bdelete. ]. ]. containers_OrderedCollectionnew.!! showList |bcurrentTopsDpDl| sBartop:selftop. sBarleft:selfleft+selfwidth–sBarwidth. sBarheight:selfheight. containers=nil ifTrue:[^false]. items=nil ifTrue:[^false]. topItem=nil ifTrue:[^false]. currentTop_selftop+2. l_lastItem. ((itemssize)<maxVisibleItems) ifTrue:[l_itemssize]. (topItemto:l) do:[:i| ((itemsat:i)~=nil) ifTrue:[ b_ShapeButtonnew. binitialize. bshape:1. balignment:1. blabel:(itemsat:i). selfaddMorph:b. bnormalColor:normalColor. bnormalBorderColor:normalColor. bnormalBorderWidth:0. bnormalForeColor:normalForeColor. bhoverColor:highlightColor. bhoverBorderColor:highlightColor. bhoverBorderWidth:0. bhoverForeColor:normalForeColor. bheight:14. bwidth:selfwidth–2–sBarwidth. btop:currentTop. bleft:selfleft+2. bindex:i. bclickAction:[selfgotClicked:(selfcursorPointy–selftop)]. bdoubleClickAction:[selfgotDoubleClicked]. bdoubleClickAction:doubleClickAction. bturnOnHoverEffect. bturnOffMouseDownEffect. currentTop_currentTop+14. containersadd:b ]. ].

46 ((itemssize)>maxVisibleItems) ifTrue:[ sD_(1/(itemssize))asFloat. pD_((itemssize–maxVisibleItems)/(itemssize))asFloat. sBarscrollDelta:sDpageDelta:pD. sBarinterval:(1–pD)asFloat. sBarvalue:(topItem/(itemssize))asFloat. ] ifFalse:[ sBarscrollDelta:0.02pageDelta:0.2. sBarinterval:1.0 ]. selfupdateList updateList |b| listIndex=nil ifTrue:[^false]. listIndex>(maxVisibleItems+topItem–1) ifTrue:[^false]. listIndex<topItem ifTrue:[^false]. (lastListIndex~=nil and:[lastListIndex>=topItem and:[lastListIndex<=(lastItem)]]) ifTrue:[b_containersat:(lastListIndex–topItem+1). bnormalColor:normalColor. bnormalBorderColor:normalColor. bnormalForeColor:normalForeColor. bturnOnHoverEffect]. b_containersat:listIndex–topItem+1. bnormalColor:selectedColor. bnormalBorderColor:selectedColor. bnormalForeColor:selectedForeColor. bturnOffHoverEffect classmethodsFor:‘instancecreation’ defaultProperties:aListBox aListBoxborderColor:ColorlightGray. aListBoxnormalColor:Colorwhite. aListBoxhighlightColor:ColorpaleBlue. aListBoxselectedColor:Colorblue. aListBoxnormalForeColor:Colorblack. aListBoxselectedForeColor:Colorwhite. aListBoxextent:100@200.

47 Farewell Ihopeyouenjoyedthistutorial,asmuchasIenjoyedwritingit.IthinkhereI mustsaythatIenjoyedcreatingthisdocumentalot. WhatIreallywishisthatthisdocumenthasbeenusefultoyou. stemsfromtheideaofhavingeverythingasanobject.Asallapproaches,this hasadvantages,aswellasdisadvantages. Objectorientedprogrammingisasmartwaytofollow,butitbringsproblems aboutusabilityalong.Ifwehave1000objectsinthesystemandeachobject introduces10newmethods,itmakes11000wordsforausertohandle,which isalmostasdifficultaslearningaforeignlanguage.Somanyobjectsand methodstaketoomuchtimeeventoscan,noneedtomentiondecidingwhatto use. Thoughthisguideaimstodemonstratemorphicclassesandtheiruses,Itried toshowhowtodesignandcreateobjectsaswell.Evidentiallyeveryprogrammer hasanownstyle,butknowingotherstyleswouldn’thurt. Thankyouforreadingthetutorialand Farewell.

48 MORPHCLASSREFERENCE

49 ObjectsubclassMorph Commoninstancemethodsinalphabeticalorder addAllMorphs:aCollection addsallmorphsinthecollectionassubmorphs. addAllMorphs:aCollectionafter:anotherMorph addsallmorphsinthecollectionassubmorphsaftertheexistingsubmorph,keeping thez-order. addMorph:aMorph addsamorphasasubmorphtothez-order1. addMorph:newMorphafter:aMorph addsthenewmorphaftertheexistingsubmorphaMorphregardingthez-order. addMorph:newMorphbehind:aMorph addsthenewmorphaftertheexistingsubmorphaMorphregardingthez-order. addMorph:newMorphinFrontOf:aMorph addsthenewmorphbeforetheexistingsubmorphaMorphregardingthez-order. addMorphBack:aMorph addsamorphasasubmorphwithlowestz-order. addMorphCentered:aMorph addsamorphasasubmorphandcentersitinsideitself. addMorphFront:aMorph addsamorphasasubmorphwithhighestz-order. beTransparent makesthemorphtransparent. bottom:aNumber movesthemorphsothatitsbottomisataNumber. bottomLeft:aPoint movesthemorphsothatitsbottomleftcornerisonaPoint. bottomRight:aPoint movesthemorphsothatitsbottomrightcornerisonaPoint. center centersthemorphintheworldthatitbelongs. click:evt defaultmethoddoesnothing,mustbeoverriddentoprovideaction.Becomesinvoked uponmouseclick. collapse minimizesthemorph.

50 color:aColor changesthecolorofamorph comeToFront setsthez-orderofthemorphto1. copy returnsacopyofthemorphwithoutitssubmorphs. cursorPoint returnsapointindicatingwherethemousecursoris. delete deletesthemorphasasubmorph doubleClick:evt defaultmethoddoesnothing,mustbeoverriddentoprovideaction.Becomesinvoked uponmousedoubleclick. dragEnabled returnsabooleanvalueindicatingifsubmorphscanbeaddedbydrag&dropthethe morph. dragEnabled:aBool setsdragEnabledproperty. duplicate returnsacloneofthemorph. extent:aPoint resizestheMorph goBehind setsthemorph’sz-ordertothelowest. handlesKeyboard:evt defaultmethodreturnsfalse,mustbeoverriddentoprovideaction.Mustreturntrueif keyboardeventswillbehandledbythemorph.Relatedmethods:hasFocus,keyDown, keyStroke,keyUp. handlesMouseDown:evt defaultmethodreturnsfalse,mustbeoverriddentoprovideaction.Mustreturntrueif mousedowneventswillbehandledbythemorph.Relatedmethods:click,doubleClick, mouseDown,mouseUp. handlesMouseOver:evt defaultmethodreturnsfalse,mustbeoverriddentoprovideaction.Mustreturntrueif mouseovereventswillbehandledbythemorph.Relatedmethods:mouseEnter, mouseLeave. handlesMouseOverDragging:evt defaultmethodreturnsfalse,mustbeoverriddentoprovideaction.Mustreturntrueif drageventswillbehandledbythemorph. handlesMouseStillDown:evt

51 defaultmethodreturnsfalse,mustbeoverriddentoprovideaction.Mustreturntrueif mousepressedeventswillbehandledbythemorph. hasFocus defaultmethodreturnsfalse,mustbeoverriddentoprovideaction.Mustreturntrueif keyboardeventswillbehandledbythemorph.Relatedmethods:handlesKeyboard, keyDown,keyStroke,keyUp. height:aNumber resizesthemorphsothatithastheheightaNumber initialize initializesthemorph. isStepping returnswhetherthemorphtimerisonoroff. keyDown:anEvent defaultmethoddoesnothing,mustbeoverriddentoprovideaction.Becomesinvoked uponakeyispressed.Relatedmethods:handlesKeyboard,hasFocus. keyStroke:anEvent defaultmethoddoesnothing,mustbeoverriddentoprovideaction.Becomesinvoked uponakeystroke.Relatedmethods:handlesKeyboard,hasFocus. keyUp:anEvent defaultmethoddoesnothing,mustbeoverriddentoprovideaction.Becomesinvoked uponakeyisreleased.Relatedmethods:handlesKeyboard,hasFocus. left:aNumber setstheleftofthemorphtothegivennumber. mouseDown:evt defaultmethoddoesnothing,mustbeoverriddentoprovideaction.Becomesinvoked whenmouseispressed.Relatedmethods:handlesMouseDown. mouseEnter:evt defaultmethoddoesnothing,mustbeoverriddentoprovideaction.Becomesinvoked whenmouseentersmorph’sbounds.Relatedmethods:handlesMouseOver. mouseEnterDragging:evt defaultmethoddoesnothing,mustbeoverriddentoprovideaction.Becomesinvoked whenmouseentersmorph’sboundsdragginganobject.Relatedmethods: handlesMouseOverDragging. mouseLeave:evt defaultmethoddoesnothing,mustbeoverriddentoprovideaction.Becomesinvoked whenmouseleavesmorph’sbounds.Relatedmethods:handlesMouseOver. mouseLeaveDragging:evt defaultmethoddoesnothing,mustbeoverriddentoprovideaction.Becomesinvoked whenmouseleavesmorph’sboundsdragginganobject.Relatedmethods: handlesMouseOverDragging. mouseMove:evt

52 defaultmethoddoesnothing,mustbeoverriddentoprovideaction.Becomesinvoked uponmousemovement. mouseStillDown:evt defaultmethoddoesnothing,mustbeoverriddentoprovideaction.Becomesinvokedif mouseispressedandhold.Relatedmethods:handlesMouseStillDown. mouseUp:evt defaultmethoddoesnothing,mustbeoverriddentoprovideaction.Becomesinvoked whenmouseisreleased.Relatedmethods:handlesMouseDown. openInWindowLabeled:aString opensmorphinthewindowwiththegivenlabel. openInWorld opensmorphinthedefaultworld. openInWorld:aWorld opensthemorphinadesiredworld. owner returnstheownerofthemorph. position returnsapointindicatingthetopleftcornerofthemorph. position:aPoint setstopleftcornerofthemorphtoapoint. removeAllMorphs removesallsubmorphsofthemorph. right:aNumber movesthemorphsothatitsrightisatanumber. showBalloon:msgText showsballooncontainingmsgText. startStepping startsthetimer.Relatedmethods:step,stepAt,stepTime,stop. step defaultmethoddoesnothing,mustbeoverriddentoprovideaction.Thismethodis invokedperiodically.Relatedmethods:startStepping,stepAt,stepTime,stop. stepAt:amillisecondValue invokethestepmethodinamillisecondValue.Relatedmethods:startStepping,step, stepTime,stop. stepTime returnshowfrequentthestepmethodwillbeinvoked.Relatedmethods:startStepping, step,stepAt,stop. stop

53 stopstimer.Relatedmethods:startStepping,step,stepAt,stepTime. submorphs returnsacopyofthesubmorphscollection. top:aNumber movesthemorphsothatitstopisataNumber. topLeft:aPoint movesthemorphsothatitstopleftcornerisataPoint. topRight:aPoint movesthemorphsothatitstoprightcornerisataPoint. visible:aBoolean setswhetherthemorphisvisibleornot. width:aNumber resizesthemorphsothatithasthewidthaNumber.

54