WMComponents.Mod 125 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779
  1. MODULE WMComponents; (** AUTHOR "TF"; PURPOSE "Component Framework based on XML"; *)
  2. (**
  3. -- Events: --
  4. Each VisualComponent can produce keyboard and mouse events which can trigger A2 commands.
  5. The command string for a given event can by specified by the usage of XML attributes and component properties.
  6. The following attributes are defined:
  7. Keyboard: onReturn, onEscape, onKeyPressed, onKeyReleased
  8. Mouse: onLeftClick, onRightClick, onMiddleClick, onClick
  9. The command strings are processed (macro substitution) before the actual command is called.
  10. -- Macro substitution: --
  11. General form: "^" [namespace ":"] macrostring
  12. A macro always start with MacroCharacter ("^"). The next occurence of a whitespace character determines the end of the macro.
  13. Two consequent MacroCharacter's ("^^") will be replaced by the MacroCharacter ("^") not triggering macro substitution at all.
  14. The user can install MacroHandlerProcedures for a given namespace. At most one handler per namespace can be installed.
  15. If the namespace is omitted, the default macro handler is triggered.
  16. The DefaultMacroHandler currently supports the following macro substitutions:
  17. ^selection is replaced by the last selection of the user
  18. ^clipboard is replaced by the content of the clipboard
  19. ^attribute=[component "."] attribute
  20. ^property=[component "."] property
  21. is replaced by the value of <attribute> or <property>.
  22. If the component qualifier is omitted, <attribute> or <property> is supposed to be an attribute or property of the originator of the event.
  23. If no MacroHandlerProcedure is found for a given macro, no substitution takes place.
  24. Example:
  25. onLeftClick = System.Show ^attribute=generator
  26. onMiddleClick = System.Show ^property=FillColor
  27. *)
  28. (*PH 08/14:
  29. - avoid parallel call of FormWindow.SetContent, Component.AddContent, Form.InvalidateRect by different processes, through use of EXCLUSIVE sections.
  30. - send an "invalidate content" message to a window after it appears on the display, which is handled after "form" field is ready
  31. - restructure FormWindow.SetContent() to assure coherent displays and to assure FormWindow.content is consistent
  32. *)
  33. IMPORT
  34. KernelLog, Inputs, Streams, Events, Files, Texts, TextUtilities,
  35. XML, XMLScanner, XMLParser, XMLObjects, Codecs, Localization, Repositories,
  36. Messages := WMMessages, Rectangles := WMRectangles,
  37. WMEvents, WMProperties, WMGraphics, Strings, WM := WMWindowManager, Raster,
  38. Commands, Modules, Kernel, Locks, Objects, WMDropTarget;
  39. CONST
  40. Ok* = 0;
  41. DuplicateNamespace* = 1;
  42. AlignNone* = 0; AlignLeft* = 1; AlignTop* = 2; AlignRight* = 3; AlignBottom* = 4; AlignClient* = 5; AlignRelative*=6;
  43. None=0; Left=1; Right=2; Lower=3; Upper=4; LowerRight=5; UpperRight=6; LowerLeft=7; UpperLeft=8; Inside = 9;
  44. MaxRel = 16*1024;
  45. MaxComponentNameSize* = 64; (* including 0X *)
  46. TraceFocus = 0;
  47. TraceFinalize = 1;
  48. Trace = {};
  49. (* Enable event logging? *)
  50. Logging = TRUE;
  51. (* Macro handling *)
  52. (* General form of macro: MacroCharacter [Namespace + NamespaceCharacter] MacroName *)
  53. MacroCharacter = "^";
  54. NamespaceCharacter = ":";
  55. NoNamespace = "";
  56. (* Namespace used if no namespace is specified *)
  57. DefaultNamespace = "system";
  58. (* Macros names of default macro handler *)
  59. MacroSelection = "selection";
  60. MacroClipboard = "clipboard";
  61. MacroAttributePrefix = "attribute=";
  62. MacroPropertyPrefix = "property=";
  63. CanYield = TRUE;
  64. (*temporary - to be removed*)
  65. FlagDirty=13;
  66. TYPE
  67. (** Installable event preview handlers. Are called by the components sequencer thread *)
  68. PointerHandler* = PROCEDURE {DELEGATE} (x, y : LONGINT; keys : SET; VAR handled : BOOLEAN);
  69. PointerLeaveHandler* = PROCEDURE {DELEGATE} (VAR handled : BOOLEAN);
  70. DragDropHandler* = PROCEDURE {DELEGATE} (x, y : LONGINT; dragInfo : WM.DragInfo; VAR handled : BOOLEAN);
  71. DragResultHandler* = PROCEDURE {DELEGATE} (accepted : BOOLEAN; recipient : ANY; dragInfo : WM.DragInfo; VAR handled : BOOLEAN);
  72. DragAutoStartHandler* = PROCEDURE {DELEGATE} (VAR handled : BOOLEAN);
  73. FocusHandler* = PROCEDURE {DELEGATE} (hasFocus : BOOLEAN);
  74. ContextMenuHandler* = PROCEDURE {DELEGATE} (sender : ANY; x, y: LONGINT);
  75. KeyEventHandler* = PROCEDURE {DELEGATE} (ucs : LONGINT; flags : SET; VAR keySym : LONGINT; VAR handled : BOOLEAN);
  76. DrawHandler* = PROCEDURE {DELEGATE} (canvas : WMGraphics.Canvas);
  77. Recursion*= ENUM None*, FromComponent*, FromBottom* END;
  78. TYPE
  79. SetStringProcedure = PROCEDURE {DELEGATE} (CONST string : ARRAY OF CHAR; x,y : LONGINT; VAR res : WORD);
  80. DropTarget = OBJECT(WMDropTarget.DropTarget)
  81. VAR
  82. originator : ANY;
  83. setString : SetStringProcedure;
  84. x,y : LONGINT;
  85. PROCEDURE &Init(originator : ANY; setString : SetStringProcedure; x,y : LONGINT);
  86. BEGIN
  87. ASSERT(setString # NIL);
  88. SELF.originator := originator;
  89. SELF.setString := setString;
  90. SELF.x := x;
  91. SELF.y := y;
  92. END Init;
  93. PROCEDURE GetInterface*(type : LONGINT) : WMDropTarget.DropInterface;
  94. VAR sdi : DropString;
  95. BEGIN
  96. IF (type = WMDropTarget.TypeString) THEN
  97. NEW(sdi, originator, setString, x,y); RETURN sdi;
  98. ELSE
  99. RETURN NIL;
  100. END;
  101. END GetInterface;
  102. END DropTarget;
  103. DropString = OBJECT(WMDropTarget.DropString)
  104. VAR
  105. originator : ANY;
  106. setString : SetStringProcedure;
  107. x,y : LONGINT;
  108. PROCEDURE &Init(originator : ANY; setString : SetStringProcedure; x,y : LONGINT);
  109. BEGIN
  110. ASSERT(setString # NIL);
  111. SELF.originator := originator;
  112. SELF.setString := setString;
  113. SELF.x := x; SELF.y := y;
  114. END Init;
  115. PROCEDURE Set*(CONST string : ARRAY OF CHAR; VAR res : WORD);
  116. BEGIN
  117. setString(string, x,y, res);
  118. END Set;
  119. END DropString;
  120. LanguageExtension* = POINTER TO RECORD(Messages.MessageExtension)
  121. languages* : Localization.Languages;
  122. END;
  123. ToggleEditMode* = POINTER TO RECORD
  124. recursion*: Recursion;
  125. END;
  126. FindComponentMode* = POINTER TO RECORD END;
  127. Event* = RECORD
  128. END;
  129. KeyPressedEvent* = RECORD(Event)
  130. ucs- : LONGINT;
  131. flags- : SET;
  132. keysym- : LONGINT;
  133. END;
  134. PointerEvent* = RECORD(Event)
  135. x-, y-, z- : LONGINT;
  136. keys- : SET;
  137. END;
  138. EventContext* = OBJECT(Repositories.Context)
  139. VAR
  140. originator- : Component; (** {originator # NIL} *)
  141. command- : Strings.String; (** {command # NIL}, immutable *)
  142. timestamp- : LONGINT;
  143. PROCEDURE &New*(originator : Component; command : Strings.String; in, arg : Streams.Reader; out, error : Streams.Writer; caller : OBJECT);
  144. BEGIN
  145. ASSERT((originator # NIL) & (command # NIL));
  146. SELF.originator := originator;
  147. SELF.command := command;
  148. Init(in, arg, out, error, caller);
  149. END New;
  150. END EventContext;
  151. PointerContext* = OBJECT(EventContext)
  152. VAR
  153. pointer- : PointerEvent;
  154. END PointerContext;
  155. KeyContext* = OBJECT(EventContext)
  156. VAR
  157. key- : KeyPressedEvent;
  158. END KeyContext;
  159. TYPE
  160. (** Basic component *)
  161. ComponentStyleChanged = OBJECT
  162. END ComponentStyleChanged;
  163. Component* = OBJECT(Repositories.Component)
  164. VAR
  165. sequencer- : Messages.MsgSequencer;
  166. initialized- : BOOLEAN;
  167. properties- : WMProperties.PropertyList;
  168. events- : WMEvents.EventSourceList;
  169. eventListeners- : WMEvents.EventListenerList;
  170. id-, uid- : WMProperties.StringProperty;
  171. enabled- : WMProperties.BooleanProperty;
  172. (* discard property changes that come from a property change within the same component*)
  173. inPropertyUpdate, inLinkUpdate : BOOLEAN;
  174. (* If TRUE, this component is supposed to be created and managed by its parent. It is not externalized. *)
  175. internal- : BOOLEAN;
  176. (* after Init() , calling Reset() implicitely by insertion into FormWindow or explicitely, thereby triggering Initialize() is required to render component responsive to messages *)
  177. PROCEDURE &Init*;
  178. BEGIN
  179. Init^;
  180. SetNameAsString(StrComponent);
  181. sequencer := NIL;
  182. initialized := FALSE;
  183. NEW(properties); properties.onPropertyChanged.Add(SELF.InternalPropertyChanged); properties.onLinkChanged.Add(SELF.InternalLinkChanged);
  184. NEW(events);
  185. NEW(eventListeners);
  186. NEW(id, PrototypeID, NIL, NIL); properties.Add(id);
  187. NEW(uid, PrototypeUID, NIL, NIL); properties.Add(uid);
  188. NEW(enabled, PrototypeEnabled, NIL, NIL); properties.Add(enabled);
  189. inPropertyUpdate := FALSE;
  190. inLinkUpdate := FALSE;
  191. internal := FALSE;
  192. SetGenerator("WMComponents.NewComponent");
  193. END Init;
  194. PROCEDURE Write*(w : Streams.Writer;context: ANY; level : LONGINT);
  195. VAR enum: XMLObjects.Enumerator; c: ANY; name : Strings.String; nextLevel : LONGINT;
  196. BEGIN
  197. IF IsLocked() THEN (* D.String("Component.Write: islocked"); D.Ln; *) RETURN; END;
  198. IF ~internal THEN
  199. name := GetName();
  200. w.Char('<'); IF name = NIL THEN w.String("_NILNAME_") ELSE w.String(name^) END;
  201. WriteAttributes(w, context, level);
  202. w.Char('>');
  203. properties.WriteXML(w, context, level);
  204. nextLevel := level + 1;
  205. ELSE
  206. (* D.String("Component.Write: isInternal"); D.Ln; *)
  207. nextLevel := level;
  208. END;
  209. enum := GetContents();
  210. WHILE enum.HasMoreElements() DO
  211. c := enum.GetNext();
  212. IF ~(c IS WMProperties.Properties) THEN
  213. IF ~((c IS Component) & ((c(Component).internal) OR c(Component).IsLocked())) THEN NewLine(w, 0); NewLine(w, nextLevel); END;
  214. c(XML.Content).Write(w, context, nextLevel);
  215. (*c(Component).Write(w, context, nextLevel)*)
  216. END;
  217. END;
  218. IF ~internal THEN
  219. NewLine(w, level);
  220. w.String("</"); IF name = NIL THEN w.String("_NILNAME_") ELSE w.String(name^); END; w.Char('>')
  221. END;
  222. END Write;
  223. (*
  224. PROCEDURE ToRepository*(CONST repository: ARRAY OF CHAR; w: Streams.Writer; level: LONGINT);
  225. VAR enum: XMLObjects.Enumerator; c: ANY; name : Strings.String; nextLevel : LONGINT;
  226. BEGIN
  227. IF IsLocked() THEN RETURN; END;
  228. IF ~internal THEN
  229. name := GetName();
  230. w.Char('<'); IF name = NIL THEN w.String("_NILNAME_") ELSE w.String(name^) END;
  231. WriteAttributes(w, NIL, level);
  232. w.Char('>');
  233. properties.ToRepository(repository,w, level);
  234. nextLevel := level + 1;
  235. ELSE
  236. nextLevel := level;
  237. END;
  238. enum := GetContents();
  239. WHILE enum.HasMoreElements() DO
  240. c := enum.GetNext();
  241. IF ~(c IS WMProperties.Properties) THEN
  242. IF ~((c IS Component) & ((c(Component).internal) OR c(Component).IsLocked())) THEN NewLine(w, 0); NewLine(w, nextLevel); END;
  243. IF (c IS Repositories.Component) THEN
  244. c(Repositories.Component).ToRepository(repository, w, level);
  245. ELSE
  246. c(XML.Content).Write(w, NIL, nextLevel);
  247. END;
  248. END;
  249. END;
  250. IF ~internal THEN
  251. NewLine(w, level);
  252. w.String("</"); IF name = NIL THEN w.String("_NILNAME_") ELSE w.String(name^); END; w.Char('>')
  253. END;
  254. END ToRepository;
  255. *)
  256. PROCEDURE FromXML*(xml: XML.Element);
  257. VAR component: Component; enum: XMLObjects.Enumerator; c: ANY; element: XML.Element;
  258. BEGIN
  259. element := GetElementByName(xml,"Properties");
  260. IF (element = NIL) & (xml IS Component) THEN (* trick to get XML description of properties if not already there (new components) *)
  261. xml(Component).properties.ToXML(element)
  262. END;
  263. properties.FromXML(element);
  264. (* was: supercall to Repositories *)
  265. enum := xml.GetContents();
  266. WHILE enum.HasMoreElements() DO
  267. c := enum.GetNext();
  268. IF c IS XML.Element THEN
  269. IF ~(c IS Component) OR ~c(Component).internal THEN
  270. component := ComponentFromXML(c(XML.Element));
  271. IF component # NIL THEN
  272. AddContent(component)
  273. END;
  274. END;
  275. END;
  276. END;
  277. enum :=xml.GetAttributes();
  278. WHILE enum.HasMoreElements() DO
  279. c := enum.GetNext();
  280. IF c(XML.Attribute).GetName()^ # "generator" THEN
  281. SetAttributeValue(c(XML.Attribute).GetName()^, c(XML.Attribute).GetValue()^);
  282. END;
  283. END;
  284. (*Initialize;*) (* redundant *)
  285. END FromXML;
  286. PROCEDURE IsCallFromSequencer*():BOOLEAN;
  287. BEGIN
  288. ASSERT (sequencer # NIL);
  289. RETURN sequencer.IsCallFromSequencer()
  290. END IsCallFromSequencer;
  291. PROCEDURE AssertLock*;
  292. BEGIN
  293. ASSERT((sequencer = NIL) OR sequencer.IsCallFromSequencer() OR sequencer.lock.HasReadLock())
  294. END AssertLock;
  295. (** Atomically set the components sequencer *)
  296. PROCEDURE SetSequencer*(s : Messages.MsgSequencer);
  297. VAR old : Messages.MsgSequencer; c : XML.Content;
  298. BEGIN
  299. old := sequencer;
  300. IF old # NIL THEN old.lock.AcquireWrite() END;
  301. sequencer := s;
  302. c := GetFirst();
  303. WHILE (c # NIL) DO
  304. IF c IS Component THEN c(Component).SetSequencer(s); END; (*? what happens to old sequencers/active objects ?*)
  305. c := GetNext(c);
  306. END;
  307. IF old # NIL THEN old.lock.ReleaseWrite() END
  308. END SetSequencer;
  309. PROCEDURE Acquire*;
  310. BEGIN
  311. IF sequencer # NIL THEN sequencer.lock.AcquireWrite END
  312. END Acquire;
  313. PROCEDURE Release*;
  314. BEGIN
  315. IF sequencer # NIL THEN sequencer.lock.ReleaseWrite END
  316. END Release;
  317. PROCEDURE CheckReadLock*;
  318. BEGIN
  319. IF (sequencer # NIL) & (~sequencer.lock.HasReadLock()) THEN
  320. KernelLog.String("WMComponents.Component.CheckReadLock: FAILED!"); KernelLog.Ln;
  321. sequencer.lock.WriteLock
  322. END;
  323. IF sequencer # NIL THEN ASSERT(sequencer.lock.HasReadLock()) END
  324. END CheckReadLock;
  325. (** AddContent adds a content (element or subtree) to the element *)
  326. PROCEDURE AddContent*(c : XML.Content);
  327. VAR m:Messages.Message; rect:Rectangles.Rectangle;
  328. BEGIN
  329. ASSERT(c # NIL);
  330. Acquire;
  331. BEGIN (*{EXCLUSIVE}*)(* EXCLUSIVE leads to deadlock ?*)
  332. IF c IS WMProperties.Properties THEN
  333. properties.SetXML(c(WMProperties.Properties));
  334. ELSIF c IS Component THEN
  335. IF sequencer#NIL THEN
  336. c(Component).SetSequencer(sequencer);
  337. c(Component).Reset(SELF,NIL); (* will be scheduled by sequencer. implied RecacheProperties*)
  338. Initialize; (*? there is also a Initialize() within Reset() above, but that one seems sometimes not be effective because scheduled later; however ,this is partial redundancy *)
  339. ELSE (* no tree traversal - is less costly *)
  340. c(Component).initialized:=FALSE;
  341. c(Component).sequencer:=NIL;
  342. END;
  343. ELSIF ~(c IS XML.Comment) THEN
  344. Release; RETURN
  345. END;
  346. END;
  347. (*Acquire;*)
  348. AddContent^(c);
  349. Release;
  350. END AddContent;
  351. PROCEDURE RemoveContent*(c : XML.Content);
  352. BEGIN
  353. (*ASSERT(c # NIL);*)
  354. IF c = NIL THEN RETURN END;
  355. Acquire;
  356. RemoveContent^(c);
  357. Release;
  358. END RemoveContent;
  359. (** Add internal component. Internal components are supposed to be created and managed by its parent component.
  360. Internal components and their subcomponents are not externalized *)
  361. PROCEDURE AddInternalComponent*(component : Component);
  362. BEGIN
  363. IF (component # NIL) THEN
  364. component.internal := TRUE;
  365. AddContent(component);
  366. END;
  367. END AddInternalComponent;
  368. (** Return the root element of the component hierarchy. This is not necessarily the same as the
  369. root element of XML since it is possible to have multiple component hierarchies in an XML file *)
  370. PROCEDURE GetComponentRoot*(): Component;
  371. VAR p, c : XML.Element;
  372. BEGIN
  373. c := SELF;
  374. LOOP
  375. p := c.GetParent();
  376. IF (p # NIL) & (p IS Component) THEN c := p ELSE RETURN c(Component) END
  377. END
  378. END GetComponentRoot;
  379. PROCEDURE Find*(id : ARRAY OF CHAR) : Component;
  380. VAR
  381. root, component : Component;
  382. PROCEDURE IsUID(CONST id : ARRAY OF CHAR) : BOOLEAN;
  383. BEGIN
  384. RETURN id[0] = "&";
  385. END IsUID;
  386. PROCEDURE RemoveAmpersand(VAR id : ARRAY OF CHAR);
  387. VAR i : LONGINT;
  388. BEGIN
  389. ASSERT(id[0] = "&");
  390. FOR i := 0 TO LEN(id)-2 DO
  391. id[i] := id[i + 1];
  392. END;
  393. END RemoveAmpersand;
  394. BEGIN
  395. component := NIL;
  396. IF IsUID(id) THEN
  397. RemoveAmpersand(id);
  398. root := GetComponentRoot();
  399. component := root.FindByUID(id);
  400. ELSE
  401. component := FindByPath(id, 0);
  402. END;
  403. RETURN component;
  404. END Find;
  405. (** Find a sub component by its uid *)
  406. PROCEDURE FindByUID*(CONST uid : ARRAY OF CHAR) : Component;
  407. VAR c : XML.Content; result : Component; s : Strings.String;
  408. BEGIN
  409. IF (uid = "") THEN RETURN NIL END;
  410. s := SELF.uid.Get();
  411. IF (s # NIL) & (s^ = uid) THEN
  412. RETURN SELF
  413. ELSE
  414. result := NIL;
  415. Acquire;
  416. c := GetFirst();
  417. WHILE (result = NIL) & (c # NIL) DO
  418. IF (c IS Component) THEN result := c(Component).FindByUID(uid) END;
  419. c := GetNext(c);
  420. END;
  421. Release;
  422. RETURN result
  423. END
  424. END FindByUID;
  425. (** find a component by relative path *)
  426. PROCEDURE FindByPath*(CONST path : ARRAY OF CHAR; pos : LONGINT) : Component;
  427. VAR component : Component;
  428. BEGIN
  429. Acquire;
  430. component := FindRelativePath(SELF, path, pos);
  431. Release;
  432. RETURN component;
  433. END FindByPath;
  434. PROCEDURE StringToComponent*(str : Strings.String) : Component;
  435. VAR
  436. id : ARRAY 100 OF CHAR;
  437. isUID : BOOLEAN;
  438. ch : CHAR;
  439. sr : Streams.StringReader;
  440. r, target : Component;
  441. BEGIN
  442. NEW(sr, LEN(str)); sr.Set(str^);
  443. isUID := FALSE; IF sr.Peek() = "%" THEN isUID := TRUE; ch := sr.Get() END;
  444. sr.Token(id);
  445. IF isUID THEN r := GetComponentRoot(); target := r.FindByUID(id);
  446. IF target = NIL THEN KernelLog.String("StringToComponent : UID target not found: "); KernelLog.String(id); KernelLog.Ln; END
  447. ELSE target := FindByPath(id, 0);
  448. IF target = NIL THEN KernelLog.String("StringToComponent : Path target not found: "); KernelLog.String(id); KernelLog.Ln; END
  449. END;
  450. RETURN target
  451. END StringToComponent;
  452. (** Search a CompCommand by string *)
  453. PROCEDURE StringToCompCommand*(eventstr : Strings.String) : WMEvents.EventListener;
  454. VAR
  455. id, name : ARRAY 100 OF CHAR;
  456. isUID : BOOLEAN;
  457. ch : CHAR;
  458. sr : Streams.StringReader;
  459. r, target : Component;
  460. BEGIN
  461. NEW(sr, LEN(eventstr)); sr.Set(eventstr^);
  462. isUID := FALSE; IF sr.Peek() = "%" THEN isUID := TRUE; ch := sr.Get() END;
  463. sr.Token(id); sr.SkipWhitespace; sr.Token(name);
  464. IF isUID THEN r := GetComponentRoot(); target := r.FindByUID(id);
  465. IF target = NIL THEN KernelLog.String("StringToEvent : UID target not found: "); KernelLog.String(id); KernelLog.Ln; END
  466. ELSE target := FindByPath(id, 0);
  467. IF target = NIL THEN KernelLog.String("StringToEvent : Path target not found: "); KernelLog.String(id); KernelLog.Ln; END
  468. END;
  469. IF target # NIL THEN RETURN target.eventListeners.GetHandlerByName(NewString(name))
  470. ELSE RETURN NIL
  471. END
  472. END StringToCompCommand;
  473. (** The Finalize Method is asynchronous since queuing could result in modules being freed before finalize ispropagated..
  474. Active components should terminate, external resources should be released *)
  475. PROCEDURE Finalize*; (** PROTECTED *)
  476. VAR c : XML.Content;
  477. BEGIN
  478. IF TraceFinalize IN Trace THEN IF uid # NIL THEN (* KernelLog.String(uid.string) *) KernelLog.String(".Finalize") END END;
  479. Acquire;
  480. c := GetFirst();
  481. WHILE (c # NIL) DO
  482. IF (c IS Component) THEN c(Component).Finalize END;
  483. c := GetNext(c);
  484. END;
  485. properties.Finalize;
  486. Release;
  487. END Finalize;
  488. (* reset/initialize a hierarchy of components *)
  489. PROCEDURE Reset*(sender, data : ANY); (** PROTECTED *)
  490. VAR c : XML.Content;
  491. BEGIN
  492. IF ~IsCallFromSequencer() THEN
  493. sequencer.ScheduleEvent(SELF.Reset, sender, data);
  494. IF CanYield THEN Objects.Yield END;
  495. ELSE
  496. BEGIN (* how about exclusivity ?*)
  497. RecacheProperties;
  498. c := GetFirst();
  499. WHILE (c # NIL) DO
  500. IF c IS Component THEN
  501. c(Component).Reset(sender, data)
  502. END;
  503. c := GetNext(c);
  504. END;
  505. IF ~initialized THEN Initialize END;
  506. END;
  507. END
  508. END Reset;
  509. (* Initialize is called by Reset() and is required to render components responsive *)
  510. PROCEDURE Initialize*; (** PROTECTED *)
  511. BEGIN
  512. BEGIN{EXCLUSIVE}
  513. initialized := TRUE
  514. END;
  515. END Initialize;
  516. (** Internal interface of the message handler. This method may only be called via the Handle method.
  517. Components that need to handle messages should implement HandleInternal. *)
  518. PROCEDURE HandleInternal*(VAR msg : Messages.Message); (** PROTECTED *)
  519. VAR pa : WMProperties.PropertyArray; i : LONGINT;
  520. BEGIN
  521. ASSERT(IsCallFromSequencer());
  522. IF (msg.msgType = Messages.MsgSetLanguage) & (msg.ext # NIL) & (msg.ext IS LanguageExtension) THEN
  523. pa := properties.Enumerate();
  524. IF (pa # NIL) THEN
  525. FOR i := 0 TO LEN(pa) - 1 DO
  526. IF (pa[i] # NIL) & (pa[i] IS WMProperties.StringProperty) THEN
  527. pa[i](WMProperties.StringProperty).SetLanguage(msg.ext(LanguageExtension).languages);
  528. END;
  529. END;
  530. END;
  531. LanguageChanged(msg.ext(LanguageExtension).languages);
  532. BroadcastSubcomponents(msg);
  533. ELSE
  534. BroadcastSubcomponents(msg); (*added PH 0816 - unhandled messages may be meant for children !*)
  535. END;
  536. END HandleInternal;
  537. (** External interface to the message handler. Asynchronous messages are synchronized by
  538. the sequencer of the Container *)
  539. PROCEDURE Handle*(VAR msg : Messages.Message); (** FINAL *)
  540. VAR s : Strings.String;
  541. BEGIN
  542. (* if asynchronous call --> synchronize *)
  543. IF sequencer=NIL THEN RETURN
  544. ELSIF ~IsCallFromSequencer() THEN
  545. IF ~sequencer.Add(msg) THEN
  546. s := uid.Get();
  547. KernelLog.String("A message sent to ");
  548. IF s # NIL THEN KernelLog.String(s^) ELSE KernelLog.String(" <uid = NIL>") END;
  549. KernelLog.String(" was discarded")
  550. END;
  551. IF CanYield THEN Objects.Yield END (* give the sequencer an immediate chance to react -- important on single-processor machines *)
  552. ELSE HandleInternal(msg) END
  553. END Handle;
  554. (** Broadcast a message to all direct subcomponents. The subcomponent can then decide
  555. whether to further propagate the message to its children or not *)
  556. PROCEDURE BroadcastSubcomponents*(VAR msg : Messages.Message); (** FINAL *)
  557. VAR c : XML.Content;
  558. BEGIN
  559. Acquire;
  560. c := GetFirst();
  561. WHILE (c # NIL) DO
  562. IF c IS Component THEN c(Component).Handle(msg) END;
  563. c := GetNext(c);
  564. END;
  565. Release
  566. END BroadcastSubcomponents;
  567. (* not to be called from user *)
  568. PROCEDURE LanguageChanged*(languages : Localization.Languages);
  569. BEGIN
  570. ASSERT(languages # NIL);
  571. ASSERT(IsCallFromSequencer());
  572. END LanguageChanged;
  573. (* LinkChanged can be called to inform about changes of the state of links (i.e. objects in reference properties)
  574. Unlike PropertyChanged which informs about an actual replacement of the link *)
  575. PROCEDURE LinkChanged*(sender, link: ANY);
  576. BEGIN ASSERT(IsCallFromSequencer());
  577. END LinkChanged;
  578. (* will be called synchronously if a property of the component changes. May not be called directly.
  579. Call Invalidate in this procedure whenever a property changed that impacts the visualization.
  580. No such messages are sent until the component is initialized *)
  581. PROCEDURE PropertyChanged*(sender, property : ANY);(** PROTECTED *)
  582. BEGIN ASSERT(IsCallFromSequencer());
  583. END PropertyChanged;
  584. (** called by the internal property changed handler via the sequencer, either if multiple properties have
  585. changed or a Reset occured. The PropertyChanged method is called, too in case of multi-property changes
  586. The component should call the inherited RecacheProperties method.
  587. Do not call Invalidate in RecacheProperties, but rather in PropertyChanged(). *)
  588. PROCEDURE RecacheProperties*;
  589. BEGIN
  590. END RecacheProperties;
  591. PROCEDURE InternalPropertyChanged(sender, property : ANY);
  592. BEGIN
  593. IF ~initialized THEN RETURN END;
  594. IF ~IsCallFromSequencer() THEN
  595. sequencer.ScheduleEvent(SELF.InternalPropertyChanged, sender, property);
  596. IF CanYield THEN Objects.Yield END;
  597. ELSE
  598. IF ~inPropertyUpdate THEN
  599. inPropertyUpdate := TRUE;
  600. IF property = properties THEN RecacheProperties END;
  601. PropertyChanged(sender, property);
  602. inPropertyUpdate := FALSE
  603. END;
  604. END
  605. END InternalPropertyChanged;
  606. PROCEDURE InternalLinkChanged(sender, link : ANY);
  607. BEGIN
  608. IF ~initialized THEN RETURN END;
  609. IF ~IsCallFromSequencer() THEN
  610. sequencer.ScheduleEvent(SELF.InternalLinkChanged, sender, link);
  611. IF CanYield THEN Objects.Yield END;
  612. ELSE
  613. IF ~inLinkUpdate THEN
  614. inLinkUpdate := TRUE;
  615. LinkChanged(sender, link);
  616. inLinkUpdate := FALSE
  617. END;
  618. END
  619. END InternalLinkChanged;
  620. END Component;
  621. TYPE
  622. Macro* = ARRAY 128 OF CHAR;
  623. (** Installable macro handler procedure. {(originator # NIL) & (w # NIL)} *)
  624. MacroHandlerProcedure* = PROCEDURE {DELEGATE} (CONST macro : Macro; originator : Component; w : Streams.Writer; VAR handled : BOOLEAN);
  625. Namespace = ARRAY 16 OF CHAR;
  626. MacroHandler = POINTER TO RECORD
  627. handler : MacroHandlerProcedure;
  628. namespace : Namespace;
  629. next : MacroHandler;
  630. END;
  631. TYPE
  632. (** Basic visual component *)
  633. VisualComponent* = OBJECT(Component)
  634. VAR
  635. bounds-, bearing-, relativeBounds-: WMProperties.RectangleProperty;
  636. alignment- : WMProperties.Int32Property;
  637. fillColor- : WMProperties.ColorProperty;
  638. font- : WMProperties.FontProperty;
  639. scaleFont-: WMProperties.Int32Property;
  640. visible-, takesFocus-, needsTab-, editMode- : WMProperties.BooleanProperty;
  641. focusPrevious-, focusNext- : WMProperties.StringProperty;
  642. model- : WMProperties.ReferenceProperty;
  643. onStartDrag- : WMEvents.EventSource;
  644. canvasState- : WMGraphics.CanvasState; (** PROTECTED *)
  645. fPointerOwner : VisualComponent;
  646. hasFocus- : BOOLEAN;
  647. focusComponent : VisualComponent; (** Subcomponent that has the keyboard focus, if any *)
  648. extPointerDown, extPointerUp, extPointerMove : PointerHandler;
  649. extPointerLeave : PointerLeaveHandler;
  650. extDragOver, extDragDropped : DragDropHandler;
  651. extDragResult : DragResultHandler;
  652. extKeyEvent : KeyEventHandler;
  653. extDraw : DrawHandler;
  654. extFocus : FocusHandler;
  655. extContextMenu : ContextMenuHandler;
  656. extGetPositionOwner : GetPositionOwnerHandler;
  657. layoutManager : LayoutManager;
  658. aligning* : BOOLEAN;
  659. pointerInfo : WM.PointerInfo;
  660. editRegion: LONGINT;
  661. editX, editY: LONGINT;
  662. keyFlags: SET; (*! remove *)
  663. oldPointerInfo : WM.PointerInfo;
  664. PROCEDURE &Init*;
  665. BEGIN
  666. Init^;
  667. SetGenerator("WMComponents.NewVisualComponent");
  668. SetNameAsString(StrVisualComponent);
  669. NEW(bounds, PrototypeBounds, NIL, NIL); properties.Add(bounds);
  670. NEW(relativeBounds, PrototypeBoundsRelative, NIL, NIL); properties.Add(relativeBounds);
  671. NEW(bearing, PrototypeBearing, NIL, NIL); properties.Add(bearing);
  672. NEW(alignment, PrototypeAlignment, NIL, NIL); properties.Add(alignment);
  673. NEW(fillColor, PrototypeFillColor, NIL, NIL); properties.Add(fillColor);
  674. NEW(visible, PrototypeVisible, NIL, NIL); properties.Add(visible);
  675. NEW(takesFocus, PrototypeTakesFocus, NIL, NIL); properties.Add(takesFocus);
  676. NEW(needsTab, PrototypeNeedsTab, NIL, NIL); properties.Add(needsTab);
  677. NEW(focusPrevious, PrototypeFocusPrevious, NIL, NIL); properties.Add(focusPrevious);
  678. NEW(focusNext, PrototypeFocusNext, NIL, NIL); properties.Add(focusNext);
  679. NEW(editMode, PrototypeEditMode, NIL,NIL); properties.Add(editMode); editMode.Set(FALSE);
  680. NEW(model, ModelPrototype, NIL, NIL); properties.Add(model);
  681. NEW(font, PrototypeFont, NIL, NIL); properties.Add(font);
  682. NEW(scaleFont, PrototypeScaleFont, NIL,NIL); properties.Add(scaleFont);
  683. NEW(onStartDrag, SELF, GSonStartDrag,GSonStartDragInfo, SELF.StringToCompCommand);
  684. events.Add(onStartDrag);
  685. extGetPositionOwner := NIL;
  686. aligning := FALSE; fPointerOwner := SELF; focusComponent := SELF;
  687. END Init;
  688. (** Focus handling *)
  689. PROCEDURE TraceFocusChain*;
  690. BEGIN
  691. KernelLog.String(" -> ");
  692. ShowComponent(SELF);
  693. IF focusComponent = SELF THEN
  694. KernelLog.String(" <END>"); KernelLog.Ln;
  695. ELSIF focusComponent = NIL THEN
  696. KernelLog.String("ERROR focusComponent is NIL"); KernelLog.Ln;
  697. ELSE
  698. focusComponent.TraceFocusChain;
  699. END;
  700. END TraceFocusChain;
  701. (** Set the keyboard focus chain to this component its takesFocus field is set and unset the old chain *)
  702. PROCEDURE SetFocus*;
  703. VAR root, vc : VisualComponent; p : XML.Element;
  704. BEGIN
  705. Acquire;
  706. IF (takesFocus.Get() OR editMode.Get()) & visible.Get() THEN
  707. IF TraceFocus IN Trace THEN KernelLog.String("Set focus to: "); ShowComponent(SELF); KernelLog.Ln; END;
  708. root := GetVisualComponentRoot();
  709. IF (root IS Form) THEN root(Form).lastFocusComponent := SELF; END;
  710. (* unset the old focus chain *)
  711. (* find the leaf component that has the focus *)
  712. vc := root;
  713. WHILE (vc # NIL) & (vc.focusComponent # NIL) & (vc.focusComponent # vc) DO vc := vc.focusComponent; END;
  714. (* clear the focus chain until the root or this component *)
  715. p := vc;
  716. WHILE (p # SELF) & (p # NIL) & (p IS VisualComponent) DO
  717. vc := p(VisualComponent);
  718. vc.focusComponent := vc;
  719. vc.FocusLost;
  720. IF (vc.extFocus # NIL) THEN vc.extFocus(FALSE); END;
  721. p := p.GetParent();
  722. END;
  723. (* set the new chain *)
  724. vc := SELF; vc.focusComponent := SELF;
  725. WHILE (vc # NIL) DO
  726. IF ~vc.hasFocus THEN
  727. vc.FocusReceived;
  728. IF vc.extFocus # NIL THEN vc.extFocus(TRUE) END;
  729. END;
  730. p := vc.GetParent();
  731. IF (p # NIL) & (p IS VisualComponent) THEN
  732. p(VisualComponent).focusComponent := vc; vc := p(VisualComponent);
  733. ELSE
  734. vc := NIL;
  735. END;
  736. END;
  737. ELSE (* component does not take focus or is not visible *)
  738. IF TraceFocus IN Trace THEN ShowComponent(SELF); KernelLog.String("does not take focus."); KernelLog.Ln END;
  739. END;
  740. Release;
  741. END SetFocus;
  742. PROCEDURE FocusReceived*;
  743. BEGIN
  744. hasFocus := TRUE
  745. END FocusReceived;
  746. PROCEDURE FocusLost*;
  747. BEGIN
  748. hasFocus := FALSE
  749. END FocusLost;
  750. PROCEDURE SetFocusTo(CONST id : ARRAY OF CHAR);
  751. VAR vc : Component;
  752. BEGIN
  753. vc := Find(id);
  754. IF (vc # NIL) & (vc IS VisualComponent) THEN
  755. vc(VisualComponent).SetFocus;
  756. ELSE
  757. KernelLog.String("Warning: WMComponents.VisualComponent.SetFocusTo: Component ");
  758. KernelLog.String(id); KernelLog.String(" not found."); KernelLog.Ln;
  759. END;
  760. END SetFocusTo;
  761. PROCEDURE FocusNext*;
  762. VAR string : Strings.String;
  763. BEGIN
  764. string := focusNext.Get();
  765. IF (string # NIL) THEN
  766. SetFocusTo(string^);
  767. END;
  768. END FocusNext;
  769. PROCEDURE FocusPrev*;
  770. VAR string : Strings.String;
  771. BEGIN
  772. string := focusPrevious.Get();
  773. IF (string # NIL) THEN
  774. SetFocusTo(string^);
  775. END;
  776. END FocusPrev;
  777. (* LinkChanged can be called to inform about changes of the state of links (i.e. objects in reference properties)
  778. Unlike PropertyChanged which informs about an actual replacement of the link *)
  779. PROCEDURE LinkChanged*(sender, link: ANY);
  780. BEGIN
  781. IF sender = model THEN
  782. Invalidate
  783. END;
  784. END LinkChanged;
  785. PROCEDURE PropertyChanged*(sender, property : ANY);
  786. BEGIN
  787. IF property = bounds THEN
  788. (*ScaleFont(bounds.GetHeight(), scaleFont.Get());*)
  789. Resized (*implicit Invalidate*)
  790. ELSIF property = bearing THEN Resized;
  791. (* ELSIF bounds=relativeBounds THEN ? *)
  792. ELSIF property = alignment THEN AlignmentChanged; Invalidate (*moved here from implicit Invalidate*)
  793. ELSIF property = fillColor THEN Invalidate;
  794. ELSIF property = font THEN
  795. IF scaleFont.Get() # 0 THEN
  796. ScaleFont(bounds.GetHeight(), scaleFont.Get()); (* implicit Invalidate*)
  797. END;
  798. Invalidate;
  799. ELSIF (property = scaleFont) THEN ScaleFont(bounds.GetHeight(),scaleFont.Get()); (*implicit Invalidate*)
  800. ELSIF property = visible THEN Resized (*Implicit Invalidate*)
  801. (* ELSIF takesFocus, needsTab...*)
  802. ELSIF property = editMode THEN Invalidate;
  803. ELSIF property = model THEN LinkChanged(model, model.Get());
  804. ELSE PropertyChanged^(sender, property)
  805. END;
  806. END PropertyChanged;
  807. PROCEDURE RecacheProperties*;
  808. BEGIN
  809. RecacheProperties^;
  810. IF scaleFont.Get() # 0 THEN ScaleFont(bounds.GetHeight(), scaleFont.Get()) END;
  811. IF (model # NIL) & (model.Get() # NIL) THEN LinkChanged(model,model.Get()) END;
  812. END RecacheProperties;
  813. (** Get the root of visible components. Not neccessarily the same as GetComponentRoot() OR GetRoot() *)
  814. PROCEDURE GetVisualComponentRoot*(): VisualComponent;
  815. VAR p, c : XML.Element;
  816. BEGIN
  817. c := SELF;
  818. LOOP
  819. p := c.GetParent();
  820. IF (p # NIL) & (p IS VisualComponent) THEN c := p
  821. ELSE RETURN c(VisualComponent)
  822. END
  823. END
  824. END GetVisualComponentRoot;
  825. PROCEDURE AdaptRelativeBounds(inner: Rectangles.Rectangle; parent: XML.Element);
  826. VAR outer: Rectangles.Rectangle;
  827. BEGIN
  828. Acquire;
  829. IF (parent # NIL) & (parent IS VisualComponent) THEN
  830. (* inner := bounds.Get();*)
  831. outer := parent(VisualComponent).bounds.Get();
  832. IF (outer.b - outer.t > 0) & (outer.r - outer.l > 0) THEN
  833. relativeBounds.Set(Rectangles.MakeRect( (inner.l * MaxRel) DIV (outer.r-outer.l), (inner.t * MaxRel) DIV (outer.b-outer.t),
  834. (inner.r * MaxRel) DIV (outer.r - outer.l), (inner.b * MaxRel) DIV (outer.b - outer.t)));
  835. END;
  836. END;
  837. Release
  838. END AdaptRelativeBounds;
  839. (** Position handling *)
  840. PROCEDURE AlignmentChanged;
  841. VAR p : XML.Element; inner, outer: Rectangles.Rectangle;
  842. BEGIN
  843. Acquire;
  844. IF alignment.Get()= AlignRelative THEN
  845. AdaptRelativeBounds(bounds.Get(), GetParent());
  846. END;
  847. p := SELF.GetParent();
  848. IF (p # NIL) & (p IS VisualComponent) THEN
  849. p(VisualComponent).AlignSubComponents
  850. END;
  851. (*Invalidate;*)
  852. Release
  853. END AlignmentChanged;
  854. (** Get the bounds of the component *)
  855. PROCEDURE GetClientRect*() : Rectangles.Rectangle;
  856. VAR r, t : Rectangles.Rectangle;
  857. BEGIN
  858. r := bounds.Get();
  859. t := Rectangles.MakeRect(0, 0, r.r - r.l, r.b - r.t);
  860. RETURN t
  861. END GetClientRect;
  862. PROCEDURE SetLayoutManager*(layoutManager : LayoutManager);
  863. BEGIN
  864. Acquire;
  865. SELF.layoutManager := layoutManager;
  866. Release
  867. END SetLayoutManager;
  868. PROCEDURE AlignEvent(sender, data: ANY);
  869. BEGIN
  870. AlignSubComponents;
  871. END AlignEvent;
  872. PROCEDURE AlignSubComponents*;
  873. VAR c : XML.Content; vc : VisualComponent;
  874. r, b, rel : Rectangles.Rectangle;
  875. BEGIN
  876. Acquire;
  877. IF (sequencer # NIL) & ~IsCallFromSequencer() THEN sequencer.ScheduleEvent(SELF.AlignEvent, NIL,NIL); Release; RETURN
  878. ELSIF sequencer = NIL THEN Release; RETURN
  879. END;
  880. IF aligning THEN Release; RETURN END;
  881. DisableUpdate;
  882. aligning := TRUE;
  883. IF layoutManager # NIL THEN layoutManager(SELF)
  884. ELSE
  885. r := GetClientRect();
  886. c := GetFirst();
  887. WHILE (c # NIL) DO
  888. IF c IS VisualComponent THEN
  889. vc := c(VisualComponent);
  890. IF vc.visible.Get() THEN
  891. b := vc.bearing.Get();
  892. CASE vc.alignment.Get() OF
  893. | AlignTop : vc.bounds.Set(Rectangles.MakeRect(r.l + b.l , r.t + b.t, r.r - b.r, r.t + b.t + vc.bounds.GetHeight())); INC(r.t, vc.bounds.GetHeight() + b.t + b.b)
  894. | AlignLeft : vc.bounds.Set(Rectangles.MakeRect(r.l + b.l, r.t + b.t, r.l + b.l + vc.bounds.GetWidth(), r.b - b.b)); INC(r.l, vc.bounds.GetWidth() + b.l + b.r)
  895. | AlignBottom : vc.bounds.Set(Rectangles.MakeRect(r.l + b.l, r.b - vc.bounds.GetHeight() - b.b, r.r - b.r, r.b - b.b)); DEC(r.b, vc.bounds.GetHeight() + b.t + b.b)
  896. | AlignRight : vc.bounds.Set(Rectangles.MakeRect(r.r - vc.bounds.GetWidth() - b.r , r.t + b.t, r.r - b.r, r.b - b.b)); DEC(r.r, vc.bounds.GetWidth() + b.l + b.r);
  897. | AlignClient : IF ~Rectangles.RectEmpty(r) THEN vc.bounds.Set(Rectangles.MakeRect(r.l + b.l , r.t + b.t, r.r - b.r, r.b - b.b)) END
  898. | AlignRelative:
  899. IF ~editMode.Get() THEN
  900. rel := vc.relativeBounds.Get();
  901. vc.bounds.Set(Rectangles.MakeRect(r.l + ((r.r-r.l)*rel.l+MaxRel DIV 2) DIV MaxRel, r.t + ((r.b-r.t)*rel.t+MaxRel DIV 2) DIV MaxRel,
  902. r.l + ((r.r-r.l)*rel.r +MaxRel DIV 2) DIV MaxRel, r.t+((r.b-r.t)*rel.b + MaxRel DIV 2) DIV MaxRel));
  903. ELSE
  904. vc.AdaptRelativeBounds(vc.bounds.Get(),SELF);
  905. END;
  906. ELSE (* nothing *)
  907. END;
  908. END;
  909. END;
  910. c := GetNext(c);
  911. END;
  912. END;
  913. EnableUpdate;
  914. aligning := FALSE;
  915. Release;
  916. END AlignSubComponents;
  917. PROCEDURE Initialize*;
  918. BEGIN
  919. Initialize^;
  920. AlignSubComponents;
  921. IF sequencer#NIL THEN Invalidate END;
  922. END Initialize;
  923. (** Locating *)
  924. (** transform the local component coordinates into global window manager coordinates *)
  925. PROCEDURE ToWMCoordinates*(x, y : LONGINT; VAR gx, gy : LONGINT);
  926. VAR cr : Component; tc : XML.Element; r : Rectangles.Rectangle;
  927. BEGIN
  928. gx := x; gy := y; tc := SELF;
  929. REPEAT
  930. IF (tc # NIL) & (tc IS VisualComponent) THEN
  931. r := tc(VisualComponent).bounds.Get();
  932. INC(gx, r.l); INC(gy, r.t)
  933. END;
  934. tc := tc.GetParent()
  935. UNTIL (tc = NIL) OR ~(tc IS VisualComponent);
  936. cr := GetComponentRoot();
  937. IF (cr # NIL) & (cr IS Form) THEN
  938. INC(gx, cr(Form).window.bounds.l);
  939. INC(gy, cr(Form).window.bounds.t)
  940. END
  941. END ToWMCoordinates;
  942. (** Return if the component is hit at (x, y) in component coordinates *)
  943. PROCEDURE IsHit*(x, y: LONGINT): BOOLEAN;
  944. BEGIN
  945. RETURN visible.Get() & enabled.Get() & Rectangles.PointInRect(x, y, GetClientRect())
  946. END IsHit;
  947. (** Return the topmost first child component at (x, y) *)
  948. PROCEDURE GetPositionOwner*(x, y: LONGINT): VisualComponent;
  949. VAR c: XML.Content; result, vc : VisualComponent; r : Rectangles.Rectangle;
  950. BEGIN
  951. Acquire;
  952. result := SELF;
  953. c := GetFirst();
  954. WHILE (c # NIL) DO
  955. IF c IS VisualComponent THEN
  956. vc := c(VisualComponent);
  957. r := vc.bounds.Get();
  958. IF Rectangles.PointInRect(x, y, r) & vc.IsHit(x - r.l, y - r.t) THEN
  959. result := vc
  960. END;
  961. END;
  962. c := GetNext(c);
  963. END;
  964. Release;
  965. RETURN result
  966. END GetPositionOwner;
  967. (** DragOver is called via the message handler. The should call manager.SetDragAccept(SELF, .... *)
  968. PROCEDURE DragOver*(x, y: LONGINT; dragInfo : WM.DragInfo);
  969. END DragOver;
  970. (** Dropped is called via the message handler to indicate an item has been dropped. *)
  971. PROCEDURE DragDropped*(x, y: LONGINT; dragInfo : WM.DragInfo);
  972. BEGIN
  973. IF dragInfo.onReject # NIL THEN dragInfo.onReject(SELF,dragInfo) END;
  974. END DragDropped;
  975. (*
  976. PROCEDURE EditDragOver(x,y: LONGINT; dragInfo: WMWindowManager.DragInfo);
  977. BEGIN
  978. END EditDragOver;
  979. *)
  980. PROCEDURE FromXML*(xml: XML.Element);
  981. BEGIN
  982. FromXML^(xml);
  983. END FromXML;
  984. (*
  985. PROCEDURE AddContent*(c : XML.Content);
  986. VAR m:Messages.Message;
  987. BEGIN
  988. AddContent^(c);
  989. IF c IS VisualComponent THEN
  990. m.sender:=SELF (*c*); (*move to VisualComponent ?*)
  991. m.msgType := Messages.MsgInvalidate;
  992. m.msgSubType := Messages.MsgSubAll;
  993. (* SELF(VisualComponent).Invalidate ...*)
  994. IF sequencer.Add(m) THEN END;
  995. END;
  996. END AddContent;
  997. *)
  998. PROCEDURE AddVisualComponent(c :VisualComponent; x, y : LONGINT);
  999. VAR bounds : Rectangles.Rectangle;canvas: WMGraphics.BufferCanvas; relativeAlignment: BOOLEAN;
  1000. BEGIN
  1001. ASSERT(c # NIL);
  1002. IF (c.bounds.GetWidth() < 10) OR (c.bounds.GetHeight() < 10) THEN
  1003. c.bounds.SetExtents(40, 20);
  1004. END;
  1005. bounds := c.bounds.Get();
  1006. Rectangles.MoveRel(bounds, x, y);
  1007. c.bounds.Set(bounds);
  1008. c.AdaptRelativeBounds(c.bounds.Get(), SELF);
  1009. (*
  1010. IF c.sequencer # sequencer THEN c.SetSequencer(sequencer) END; (* redundant - implicit in AddContent *)
  1011. c.Reset(NIL, NIL); (*currently redundant - already in happens Component.AddContent() *)
  1012. c.RecacheProperties; (*currently redundant - already in happens Reset() *)
  1013. *)
  1014. Acquire;
  1015. AddContent(c);
  1016. Release;
  1017. END AddVisualComponent;
  1018. PROCEDURE EditDragDropped(x,y: LONGINT; dragInfo: WM.DragInfo): BOOLEAN;
  1019. VAR data: ANY; e: ComponentListEntry; parent: XML.Element; dt: DropTarget; pos: LONGINT;
  1020. BEGIN
  1021. data := dragInfo.data;
  1022. IF (data # NIL) & (data IS VisualComponent) THEN
  1023. IF dragInfo.sender # SELF THEN
  1024. IF dragInfo.onAccept # NIL THEN dragInfo.onAccept(SELF,dragInfo) END;
  1025. data(VisualComponent).bounds.Set(Rectangles.MakeRect(0, 0, data(VisualComponent).bounds.GetWidth(), data(VisualComponent).bounds.GetHeight()));
  1026. AddVisualComponent(data(VisualComponent),x+dragInfo.offsetX,y+dragInfo.offsetY);
  1027. Invalidate;
  1028. ELSE
  1029. parent := GetParent();
  1030. IF parent = NIL THEN RETURN FALSE END;
  1031. x := x + bounds.GetLeft();
  1032. y := y + bounds.GetTop();
  1033. RETURN parent(VisualComponent).EditDragDropped(x,y,dragInfo);
  1034. END;
  1035. RETURN TRUE
  1036. ELSIF (data # NIL) & (data IS Repositories.Component) THEN
  1037. IF dragInfo.onAccept # NIL THEN dragInfo.onAccept(SELF,dragInfo) END;
  1038. model.Set(data(Repositories.Component));
  1039. RETURN TRUE
  1040. ELSIF (data # NIL) & (data IS SelectionList) THEN
  1041. IF (dragInfo.sender # SELF) & ~data(SelectionList).Has(SELF) THEN
  1042. IF dragInfo.onAccept # NIL THEN dragInfo.onAccept(SELF,dragInfo) END;
  1043. e := data(SelectionList).first;
  1044. WHILE e # NIL DO
  1045. e.component.bounds.Set(Rectangles.MakeRect(0, 0, e.component.bounds.GetWidth(), e.component.bounds.GetHeight()));
  1046. ASSERT(e.component IS VisualComponent);
  1047. AddVisualComponent(e.component,x+e.dx+dragInfo.offsetX, y+e.dy + dragInfo.offsetY);
  1048. e := e.next;
  1049. END;
  1050. Invalidate;
  1051. ELSE
  1052. parent := GetParent();
  1053. IF parent = NIL THEN RETURN FALSE END;
  1054. x := x + bounds.GetLeft();
  1055. y := y + bounds.GetTop();
  1056. RETURN parent(VisualComponent).EditDragDropped(x,y,dragInfo);
  1057. END;
  1058. RETURN TRUE
  1059. ELSE
  1060. NEW(dt, SELF, SetDroppedString, x,y);
  1061. dragInfo.data := dt;
  1062. ConfirmDrag(TRUE, dragInfo);
  1063. RETURN FALSE
  1064. END;
  1065. END EditDragDropped;
  1066. PROCEDURE SetDroppedString( CONST string : ARRAY OF CHAR; x,y : LONGINT; VAR res : WORD);
  1067. VAR gen: XML.GeneratorProcedure; moduleName, procedureName ,msg: Modules.Name; element: XML.Element;
  1068. context: Repositories.Context; repositoryName, componentName: ARRAY 265 OF CHAR; componentID: LONGINT; object: Repositories.Component;
  1069. BEGIN
  1070. Commands.Split(string, moduleName, procedureName, res, msg);
  1071. IF (res = Commands.Ok) THEN
  1072. GETPROCEDURE(moduleName, procedureName, gen);
  1073. END;
  1074. IF gen # NIL THEN
  1075. element := gen();
  1076. ELSIF Repositories.IsCommandString(string) THEN
  1077. Repositories.CallCommand(string, context, res);
  1078. IF (res = Repositories.Ok) & (context.object # NIL) & (context.object IS Repositories.Component) THEN
  1079. element := context.object(Repositories.Component);
  1080. END;
  1081. ELSIF Repositories.SplitName(string, repositoryName, componentName, componentID) THEN
  1082. Repositories.GetComponent(repositoryName, componentName, componentID, object, res);
  1083. element := object;
  1084. END;
  1085. IF (element # NIL) & (element IS VisualComponent) THEN
  1086. AddVisualComponent(element(VisualComponent),x,y);
  1087. Invalidate;
  1088. ELSIF (element # NIL) & (element IS Repositories.Component) THEN
  1089. model.Set(element(Repositories.Component))
  1090. END;
  1091. res := 1; (* to avoid removal of source *)
  1092. END SetDroppedString;
  1093. (** Is called via the message handler to inform about the result of a recent drag operation *)
  1094. PROCEDURE DragResult*(accepted : BOOLEAN; recipient : ANY; dragInfo : WM.DragInfo);
  1095. END DragResult;
  1096. (** Start a drag operation. *)
  1097. PROCEDURE StartDrag*(data : ANY; img : WMGraphics.Image; offsetX, offsetY: LONGINT; onAccept, onReject : Messages.CompCommand) : BOOLEAN;
  1098. VAR rc : Component;
  1099. BEGIN
  1100. rc := GetVisualComponentRoot();
  1101. IF (rc # NIL) & (rc IS Form) THEN
  1102. RETURN rc(Form).window.StartDrag(SELF, data, img, offsetX, offsetY, onAccept, onReject)
  1103. ELSE
  1104. RETURN FALSE
  1105. END
  1106. END StartDrag;
  1107. (** confirm a drag operation. *)
  1108. PROCEDURE ConfirmDrag*(accept : BOOLEAN; dragInfo : WM.DragInfo);
  1109. VAR rc : Component;
  1110. BEGIN
  1111. rc := GetVisualComponentRoot();
  1112. IF (rc # NIL) & (rc IS Form) THEN rc(Form).window.ConfirmDrag(accept, dragInfo)
  1113. END
  1114. END ConfirmDrag;
  1115. (** Is called by the component if it detects a default drag action. The subclass should then call StartDrag with
  1116. the respective coordinates. If it wants to start the drag operation *)
  1117. PROCEDURE AutoStartDrag*;
  1118. BEGIN
  1119. onStartDrag.Call(NIL)
  1120. END AutoStartDrag;
  1121. (** Is called by the component if it detects a request for a context menu. The subclass should open the
  1122. context menu if applicable *)
  1123. PROCEDURE ShowContextMenu*(x, y : LONGINT);
  1124. BEGIN
  1125. IF extContextMenu # NIL THEN extContextMenu(SELF, x, y) END;
  1126. END ShowContextMenu;
  1127. (** Special methods *)
  1128. PROCEDURE Resized*;
  1129. VAR p : XML.Element;
  1130. BEGIN
  1131. (*
  1132. AdaptRelativeBounds(GetParent());
  1133. *)
  1134. IF sequencer # NIL THEN ASSERT(sequencer.lock.HasWriteLock()) END;
  1135. DisableUpdate;
  1136. p := SELF.GetParent();
  1137. IF (p # NIL) & (p IS VisualComponent) & (alignment.Get() # AlignNone) THEN p(VisualComponent).AlignSubComponents END;
  1138. IF visible.Get() THEN
  1139. AlignSubComponents;
  1140. IF scaleFont.Get() # 0 THEN ScaleFont(bounds.GetHeight(), scaleFont.Get()) END;
  1141. END;
  1142. EnableUpdate;
  1143. IF (p # NIL) & (p IS VisualComponent) THEN p(VisualComponent).Invalidate
  1144. ELSE Invalidate()
  1145. END
  1146. END Resized;
  1147. (** Is called before any sub-components are drawn *)
  1148. PROCEDURE DrawBackground*(canvas : WMGraphics.Canvas);
  1149. VAR color: WMGraphics.Color; i : LONGINT; name:Strings.String;
  1150. (* DebugUpdates can be used in order to visualize updates via some color cycling
  1151. Moreover, it slows down display extremely such that updates can be seen
  1152. *)
  1153. CONST DebugUpdates = FALSE;
  1154. BEGIN
  1155. (* message tracing
  1156. IF sequencer = Messages.debug THEN
  1157. D.Enter;
  1158. D.Ln;
  1159. D.String("##############"); D.Ln;
  1160. name := GetName();
  1161. IF name # NIL THEN D.String(name^); D.Ln; END;
  1162. name := id.Get();
  1163. IF name # NIL THEN D.String(name^); D.Ln; END;
  1164. D.Int(Kernel.GetTicks(),1); D.Ln;
  1165. (*D.TraceBack;*)
  1166. D.Exit;
  1167. END;
  1168. *)
  1169. CheckReadLock;
  1170. IF DebugUpdates THEN
  1171. canvas.Fill(GetClientRect(), Kernel.GetTicks()*100H +0FFH, WMGraphics.ModeSrcOverDst);
  1172. FOR i := 0 TO 10000000 DO END;
  1173. ELSE
  1174. color := fillColor.Get();
  1175. IF color # 0 THEN canvas.Fill(GetClientRect(), color, WMGraphics.ModeSrcOverDst) END;
  1176. END;
  1177. END DrawBackground;
  1178. (** Is called after all sub-components are drawn *)
  1179. PROCEDURE DrawForeground*(canvas : WMGraphics.Canvas);
  1180. END DrawForeground;
  1181. PROCEDURE DrawSelection(canvas : WMGraphics.Canvas);
  1182. VAR r,r0: Rectangles.Rectangle; x,y,x0,y0: LONGINT; color: WMGraphics.Color;
  1183. PROCEDURE MarkSelected(r: Rectangles.Rectangle; w: LONGINT; color: WMGraphics.Color);
  1184. VAR r0: Rectangles.Rectangle;
  1185. BEGIN
  1186. r0 :=r; r0.r := r.l+w; r0.b := r.t+w;
  1187. canvas.Fill(r0, color, WMGraphics.ModeSrcOverDst);
  1188. r0 :=r; r0.r := r.l+w; r0.t := r.b-w;
  1189. canvas.Fill(r0, color, WMGraphics.ModeSrcOverDst);
  1190. r0 :=r; r0.l := r.r-w; r0.b := r.t+w;
  1191. canvas.Fill(r0, color, WMGraphics.ModeSrcOverDst);
  1192. r0 :=r; r0.l := r.r-w; r0.t := r.b-w;
  1193. canvas.Fill(r0, color, WMGraphics.ModeSrcOverDst);
  1194. r0 := r; r0.l := r.r-1; canvas.Fill(r0,color, WMGraphics.ModeSrcOverDst);
  1195. r0 := r; r0.r := r.l+1; canvas.Fill(r0,color, WMGraphics.ModeSrcOverDst);
  1196. r0 := r; r0.b := r.t+1; canvas.Fill(r0,color, WMGraphics.ModeSrcOverDst);
  1197. r0 := r; r0.t := r.b-1; canvas.Fill(r0,color, WMGraphics.ModeSrcOverDst);
  1198. END MarkSelected;
  1199. BEGIN
  1200. CheckReadLock;
  1201. r := GetClientRect();
  1202. IF editMode.Get() THEN
  1203. y := r.t + (-r.t) MOD 8;
  1204. y0 := 0;
  1205. WHILE y < r.b DO
  1206. r0.t := y; r0.b := y+2;
  1207. x := r.l + (-r.l) MOD 8; x0 := 0;
  1208. WHILE x < r.r DO
  1209. r0.l := x; r0.r := x+2;
  1210. IF ODD(x DIV 8+y DIV 8) THEN color := 060H;
  1211. ELSE color := WMGraphics.Color(0FFFFFF60H);
  1212. END;
  1213. canvas.Fill(r0,color, WMGraphics.ModeSrcOverDst);
  1214. INC(x,8); INC(x0);
  1215. END;
  1216. INC(y,8);INC(y0);
  1217. END;
  1218. IF selection.rectOwner = SELF THEN
  1219. r0 := selection.rect;
  1220. color := WMGraphics.Color(0FF000080H);
  1221. canvas.Fill(r0, color, WMGraphics.ModeCopy);
  1222. END;
  1223. END;
  1224. IF selection.Has(SELF) THEN
  1225. IF selection.state = 0 THEN
  1226. MarkSelected(r,8,WMGraphics.Color(080H));
  1227. ELSE
  1228. MarkSelected(r,8,WMGraphics.Color(0FFFFFFFF80H));
  1229. END;
  1230. END;
  1231. END DrawSelection;
  1232. PROCEDURE DrawSubComponents*(canvas : WMGraphics.Canvas);
  1233. VAR c : XML.Content; vc : VisualComponent; cr, r : Rectangles.Rectangle;
  1234. BEGIN
  1235. CheckReadLock;
  1236. canvas.GetClipRect(cr);
  1237. canvas.SaveState(canvasState);
  1238. (* draw all sub-components *)
  1239. c := GetFirst();
  1240. WHILE (c # NIL) DO
  1241. IF c IS VisualComponent THEN
  1242. vc := c(VisualComponent); r := vc.bounds.Get();
  1243. IF Rectangles.Intersect(r, cr) THEN (* only draw if the component has a chance to be visible *)
  1244. canvas.SetClipRect(r); canvas.SetClipMode({WMGraphics.ClipRect});
  1245. canvas.ClipRectAsNewLimits(r.l, r.t);
  1246. vc.Draw(canvas);
  1247. canvas.RestoreState(canvasState);
  1248. END;
  1249. END;
  1250. c := GetNext(c);
  1251. END;
  1252. END DrawSubComponents;
  1253. PROCEDURE GetFont*() : WMGraphics.Font;
  1254. BEGIN
  1255. IF font.Get() = NIL THEN RETURN WMGraphics.GetDefaultFont()
  1256. ELSE RETURN font.Get()
  1257. END
  1258. END GetFont;
  1259. PROCEDURE SetFont*(font : WMGraphics.Font);
  1260. BEGIN
  1261. Acquire;
  1262. IF SELF.font.Get() # font THEN
  1263. SELF.font.Set(font);
  1264. (*?Invalidate()*) (* Invalidate already in PropertyChanged() *)
  1265. END;
  1266. Release
  1267. END SetFont;
  1268. PROCEDURE ScaleFont*(height: LONGINT; percent: LONGINT);
  1269. VAR fh,newSize: LONGINT; f: WMGraphics.Font;
  1270. BEGIN
  1271. IF height < 4 THEN height := 4 END;
  1272. IF percent <= 0 THEN RETURN END;
  1273. Acquire;
  1274. f := GetFont();
  1275. f := WMGraphics.GetFont(f.name, 100, f.style); (* expensive ? *)
  1276. fh := f.GetAscent() + f.GetDescent();
  1277. fh := height * percent DIV fh;
  1278. IF fh > 100 THEN fh := fh - fh MOD 8
  1279. ELSIF fh > 32 THEN fh := fh - fh MOD 4
  1280. ELSIF fh > 12 THEN fh := fh - fh MOD 2
  1281. END;
  1282. IF font.GetSize() # fh THEN
  1283. font.SetSize(fh);
  1284. Invalidate;
  1285. END;
  1286. Release;
  1287. END ScaleFont;
  1288. (** Called by the component owner whenever a redraw to a canvas is needed. Caller must hold hierarchy lock *)
  1289. PROCEDURE Draw*(canvas : WMGraphics.Canvas);
  1290. VAR command: Strings.String; event: Event;
  1291. BEGIN
  1292. (*
  1293. can lead to deadlock:
  1294. we hold the lock "lock"
  1295. onDraw tries to get the Objects lock, but this may be held by other component (should better not, but did, dead: WMPartitionsComponents.OperationEventHandler
  1296. command := GetAttributeValue("onDraw");
  1297. IF (command # NIL) THEN HandleEvent(event, SELF, command); END;
  1298. *)
  1299. CheckReadLock;
  1300. IF ~visible.Get() THEN RETURN END;
  1301. canvas.SaveState(canvasState);
  1302. IF font # NIL THEN canvas.SetFont(font.Get()) END;
  1303. DrawBackground(canvas);
  1304. IF extDraw # NIL THEN extDraw(canvas) END;
  1305. DrawSelection(canvas);
  1306. DrawSubComponents(canvas);
  1307. DrawForeground(canvas);
  1308. canvas.RestoreState(canvasState)
  1309. END Draw;
  1310. (** declare a rectangle area as dirty *)
  1311. PROCEDURE InvalidateRect*(r: Rectangles.Rectangle);
  1312. VAR parent : XML.Element;
  1313. m : Messages.Message; b : Rectangles.Rectangle;
  1314. BEGIN
  1315. IF ~initialized THEN RETURN END;
  1316. IF ~visible.Get() THEN RETURN END;
  1317. IF ~IsCallFromSequencer() THEN
  1318. m.msgType := Messages.MsgInvalidate;
  1319. m.msgSubType := Messages.MsgSubRectangle;
  1320. (*
  1321. m.msgType := Messages.MsgExt;
  1322. m.ext := invalidateRectMsg;
  1323. *)
  1324. m.x := r.l; m.y := r.t; m.dx := r.r; m.dy := r.b; m.sender := SELF;
  1325. IF sequencer.Add(m) THEN IF CanYield THEN Objects.Yield END END;
  1326. ELSE
  1327. parent := GetParent();
  1328. IF (parent # NIL) & (parent IS VisualComponent) THEN
  1329. b := bounds.Get();
  1330. Rectangles.MoveRel(r, b.l, b.t);
  1331. parent(VisualComponent).InvalidateRect(r)
  1332. END
  1333. END
  1334. END InvalidateRect;
  1335. PROCEDURE PostInvalidateCommand*(sender, par : ANY);
  1336. VAR m: Messages.Message; r, b: Rectangles.Rectangle; client: VisualComponent; parent: XML.Element;
  1337. BEGIN
  1338. IF ~initialized OR ~visible.Get() THEN RETURN END; (*? double call to visible.Get here and below. Which one is better ?*)
  1339. r := GetClientRect();
  1340. client := SELF;
  1341. parent := GetParent();
  1342. WHILE (parent # NIL) & (parent IS VisualComponent) DO
  1343. IF ~parent(VisualComponent).visible.Get() THEN RETURN END;
  1344. b := client.bounds.Get();
  1345. Rectangles.MoveRel(r, b.l, b.t);
  1346. client := parent(VisualComponent);
  1347. parent := client.GetParent();
  1348. END;
  1349. m.msgType := Messages.MsgInvalidate;
  1350. m.msgSubType := Messages.MsgSubRectangle;
  1351. m.x := r.l; m.y := r.t; m.dx := r.r; m.dy := r.b;
  1352. m.sender := client;
  1353. IF sequencer.Add(m) THEN IF CanYield THEN Objects.Yield END END;
  1354. END PostInvalidateCommand;
  1355. PROCEDURE InvalidateCommand*(sender, par : ANY);
  1356. VAR m: Messages.Message; r, b: Rectangles.Rectangle; client: VisualComponent; parent: XML.Element;
  1357. BEGIN
  1358. IF ~initialized OR ~visible.Get() THEN RETURN END; (*? double call to visible.Get here and below. Which one is better ?*)
  1359. IF ~IsCallFromSequencer() OR ~visible.Get() THEN
  1360. PostInvalidateCommand(sender, par);
  1361. ELSE
  1362. InvalidateRect(GetClientRect());
  1363. END;
  1364. END InvalidateCommand;
  1365. PROCEDURE Invalidate*; (* For convenience in component internal use *)
  1366. BEGIN
  1367. PostInvalidateCommand(SELF, NIL)
  1368. END Invalidate;
  1369. (** recursively disable the redrawing of any components in the hierarchy *)
  1370. (** dont forget to re-enable it ;-). Use with care to optimize sub-component operations *)
  1371. PROCEDURE DisableUpdate*;
  1372. VAR vc: VisualComponent;
  1373. BEGIN
  1374. ASSERT(IsCallFromSequencer());
  1375. vc := GetVisualComponentRoot();
  1376. IF (vc # NIL) & (vc IS Form) THEN vc(Form).DisableUpdate() END
  1377. END DisableUpdate;
  1378. (** recursively enable the redrawing of any components in the hierarchy *)
  1379. (** Only enable drawing if it was disabled before, but dont forget it, then ! *)
  1380. PROCEDURE EnableUpdate*;
  1381. VAR vc: VisualComponent;
  1382. BEGIN
  1383. ASSERT(IsCallFromSequencer());
  1384. vc := GetVisualComponentRoot();
  1385. IF (vc # NIL) & (vc IS Form) THEN vc(Form).EnableUpdate() END
  1386. END EnableUpdate;
  1387. PROCEDURE GetInternalPointerInfo*() : WM.PointerInfo;
  1388. VAR vc: VisualComponent;
  1389. BEGIN
  1390. ASSERT(IsCallFromSequencer());
  1391. vc := GetVisualComponentRoot();
  1392. IF (vc # NIL) & (vc IS Form) THEN
  1393. RETURN vc(Form).GetPointerInfo()
  1394. ELSE
  1395. RETURN NIL
  1396. END
  1397. END GetInternalPointerInfo;
  1398. PROCEDURE SetInternalPointerInfo*(pi : WM.PointerInfo);
  1399. VAR vc: VisualComponent;
  1400. BEGIN
  1401. AssertLock;
  1402. vc := GetVisualComponentRoot();
  1403. IF (vc # NIL) & (vc IS Form) THEN vc(Form).SetPointerInfo(pi) END
  1404. END SetInternalPointerInfo;
  1405. PROCEDURE SetPointerInfo*(pi : WM.PointerInfo);
  1406. BEGIN
  1407. Acquire;
  1408. SetInternalPointerInfo(pi);
  1409. pointerInfo := pi;
  1410. Release
  1411. END SetPointerInfo;
  1412. PROCEDURE GetPointerInfo*() : WM.PointerInfo;
  1413. BEGIN
  1414. RETURN pointerInfo
  1415. END GetPointerInfo;
  1416. (** User interaction messages *)
  1417. PROCEDURE SetExtPointerLeaveHandler*(handler : PointerLeaveHandler);
  1418. BEGIN
  1419. Acquire; extPointerLeave := handler; Release
  1420. END SetExtPointerLeaveHandler;
  1421. PROCEDURE SetExtPointerDownHandler*(handler : PointerHandler);
  1422. BEGIN
  1423. Acquire; extPointerDown := handler; Release
  1424. END SetExtPointerDownHandler;
  1425. PROCEDURE SetExtPointerMoveHandler*(handler : PointerHandler);
  1426. BEGIN
  1427. Acquire; extPointerMove := handler; Release
  1428. END SetExtPointerMoveHandler;
  1429. PROCEDURE SetExtPointerUpHandler*(handler : PointerHandler);
  1430. BEGIN
  1431. Acquire; extPointerUp := handler; Release
  1432. END SetExtPointerUpHandler;
  1433. PROCEDURE SetExtDragOverHandler*(handler : DragDropHandler);
  1434. BEGIN
  1435. Acquire; extDragOver := handler; Release
  1436. END SetExtDragOverHandler;
  1437. PROCEDURE SetExtDragDroppedHandler*(handler : DragDropHandler);
  1438. BEGIN
  1439. Acquire; extDragDropped := handler; Release
  1440. END SetExtDragDroppedHandler;
  1441. PROCEDURE SetExtDragResultHandler*(handler : DragResultHandler);
  1442. BEGIN
  1443. Acquire; extDragResult := handler; Release
  1444. END SetExtDragResultHandler;
  1445. PROCEDURE SetExtKeyEventHandler*(handler : KeyEventHandler);
  1446. BEGIN
  1447. Acquire; extKeyEvent := handler; Release
  1448. END SetExtKeyEventHandler;
  1449. PROCEDURE SetExtDrawHandler*(handler : DrawHandler);
  1450. BEGIN
  1451. Acquire; extDraw := handler; Release
  1452. END SetExtDrawHandler;
  1453. PROCEDURE SetExtFocusHandler*(handler : FocusHandler);
  1454. BEGIN
  1455. Acquire; extFocus := handler; Release
  1456. END SetExtFocusHandler;
  1457. PROCEDURE SetExtContextMenuHandler*(handler : ContextMenuHandler);
  1458. BEGIN
  1459. Acquire; extContextMenu := handler; Release
  1460. END SetExtContextMenuHandler;
  1461. PROCEDURE SetExtGetPositionOwnerHandler*(handler : GetPositionOwnerHandler);
  1462. BEGIN
  1463. Acquire; extGetPositionOwner := handler; Release;
  1464. END SetExtGetPositionOwnerHandler;
  1465. (** Indicates the pointing device has left the component without a key pressed down.
  1466. May only be called from the sequencer thread.
  1467. Components interested in this message can override this method instead of searching for the message in HandleInternal. *)
  1468. PROCEDURE PointerLeave*; (** PROTECTED *)
  1469. BEGIN ASSERT(IsCallFromSequencer());
  1470. END PointerLeave;
  1471. (** Indicates one of the pointer keys went down. keys is the set of buttons currently pressed. x, y is the position in component
  1472. coordinates.
  1473. May only be called from the sequencer thread.
  1474. Components interested in this message can override this method instead of searching for the message in HandleInternal. *)
  1475. PROCEDURE PointerDown*(x, y: LONGINT; keys: SET); (** PROTECTED *)
  1476. BEGIN ASSERT(IsCallFromSequencer());
  1477. IF keys = {2} THEN ShowContextMenu(x, y)
  1478. END;
  1479. END PointerDown;
  1480. (** Indicates the pointer was moved. keys is the set of buttons currently pressed. x, y is the position in component
  1481. coordinates.
  1482. May only be called from the sequencer thread.
  1483. Components interested in this message can override this method instead of searching for the message in HandleInternal.
  1484. When using PointerMove to move the component itself within a context (window or parent component),
  1485. remember that Component.PointerMove are given in component coordinates (thus, a moving coordinate origin ...), but you want to move the component in context coordinates !
  1486. *)
  1487. PROCEDURE PointerMove*(x, y: LONGINT; keys: SET); (** PROTECTED *)
  1488. BEGIN ASSERT(IsCallFromSequencer());
  1489. END PointerMove;
  1490. PROCEDURE WheelMove*(dz: LONGINT); (** PROTECTED *)
  1491. BEGIN ASSERT(IsCallFromSequencer());
  1492. END WheelMove;
  1493. (** Indicates one of the pointer keys went up. keys is the set of buttons currently pressed. x, y is the position in component
  1494. coordinates.
  1495. May only be called from the sequencer thread.
  1496. Components interested in this message can override this method instead of searching for the message in HandleInternal. *)
  1497. PROCEDURE PointerUp*(x, y: LONGINT; keys: SET); (** PROTECTED *)
  1498. BEGIN ASSERT(IsCallFromSequencer());
  1499. END PointerUp;
  1500. (** The component can determine wheter the key was pressed or released by examining the
  1501. Inputs.Release flag in flags. ucs contains the unicode equivalent of the key. Special input editors
  1502. send the generated unicode characters via KeyEvent.
  1503. May only be called from the sequencer thread.
  1504. Components interested in this message can override this method instead of searching for the message in HandleInternal. *)
  1505. PROCEDURE KeyEvent*(ucs : LONGINT; flags: SET; VAR keySym: LONGINT); (** PROTECTED *)
  1506. BEGIN ASSERT(IsCallFromSequencer());
  1507. END KeyEvent;
  1508. PROCEDURE EditKeyEvents(ucs : LONGINT; flags: SET; VAR keySym: LONGINT): BOOLEAN; (** FINAL *)
  1509. VAR event : KeyPressedEvent; command : Strings.String; scale: LONGINT;
  1510. clone: Repositories.Component; parent: XML.Content; parentEditMode: BOOLEAN;
  1511. enum: XMLObjects.Enumerator; obj: ANY;
  1512. po: VisualComponent;
  1513. entry: ComponentListEntry;
  1514. c: VisualComponent;
  1515. BEGIN
  1516. ASSERT(IsCallFromSequencer());
  1517. IF fPointerOwner # SELF THEN
  1518. RETURN fPointerOwner.EditKeyEvents(ucs,flags,keySym);
  1519. END;
  1520. event.ucs := ucs; event.flags := flags; event.keysym := keySym;
  1521. parent := GetParent();
  1522. IF (parent # NIL) & (parent IS VisualComponent) & parent(VisualComponent).editMode.Get() THEN
  1523. parentEditMode := TRUE
  1524. ELSE
  1525. parentEditMode := FALSE
  1526. END;
  1527. IF ({Inputs.Release} * flags = {}) THEN
  1528. IF (keySym = Inputs.KsF1) & (Inputs.Shift * flags # {}) THEN
  1529. SetEditMode(~editMode.Get(), FALSE);
  1530. RETURN TRUE
  1531. ELSIF (keySym = Inputs.KsEscape) THEN
  1532. selection.Reset(NIL);
  1533. RETURN FALSE
  1534. ELSIF parentEditMode OR editMode.Get() THEN
  1535. IF Inputs.Shift * flags # {} THEN scale := 1 ELSE scale := 4 END;
  1536. IF keySym = Inputs.KsLeft THEN selection.Shift(-scale,0); RETURN TRUE
  1537. ELSIF keySym = Inputs.KsRight THEN selection.Shift(scale,0); RETURN TRUE
  1538. ELSIF keySym = Inputs.KsDown THEN selection.Shift(0,scale); RETURN TRUE
  1539. ELSIF keySym = Inputs.KsUp THEN selection.Shift(0,-scale); RETURN TRUE
  1540. ELSIF keySym=4 (* CTRL-D *) THEN
  1541. entry := selection.first;
  1542. WHILE entry # NIL DO
  1543. clone := Clone(entry.component);
  1544. parent := selection.first.component.GetParent();
  1545. c := clone(VisualComponent);
  1546. IF c.sequencer # parent(Component).sequencer THEN c.SetSequencer(parent(Component).sequencer) END;
  1547. c.Reset(NIL, NIL);
  1548. c.RecacheProperties;
  1549. parent(Component).AddContent(c);
  1550. entry.component := clone(VisualComponent);
  1551. entry := entry.next;
  1552. END;
  1553. selection.Shift(20,20);
  1554. RETURN TRUE
  1555. ELSIF keySym=1 THEN (* CTRL-A *)
  1556. enum := GetContents();
  1557. WHILE enum.HasMoreElements() DO
  1558. obj := enum.GetNext();
  1559. IF obj IS VisualComponent THEN
  1560. selection.Add(obj(VisualComponent))
  1561. END;
  1562. END;
  1563. ELSIF keySym = Inputs.KsDelete THEN
  1564. RemoveSelection();
  1565. RETURN TRUE
  1566. END;
  1567. END
  1568. END;
  1569. RETURN FALSE;
  1570. END EditKeyEvents;
  1571. PROCEDURE CheckKeyEvents(ucs : LONGINT; flags: SET; VAR keySym: LONGINT); (** FINAL *)
  1572. VAR event : KeyPressedEvent; command : Strings.String; scale: LONGINT; clone: Repositories.Component; parent: XML.Content;
  1573. BEGIN
  1574. ASSERT(IsCallFromSequencer());
  1575. event.ucs := ucs; event.flags := flags; event.keysym := keySym;
  1576. IF ({Inputs.Release} * flags = {}) THEN
  1577. IF (keySym = Inputs.KsReturn) THEN
  1578. command := GetAttributeValue("onReturn");
  1579. ELSIF (keySym = Inputs.KsEscape) THEN
  1580. command := GetAttributeValue("onEscape");
  1581. selection.Reset(NIL);
  1582. END;
  1583. IF (command # NIL) THEN HandleEvent(event, SELF, command); END;
  1584. command := GetAttributeValue("onKeyPressed");
  1585. IF (command # NIL) THEN HandleEvent(event, SELF, command); END;
  1586. ELSE
  1587. command := GetAttributeValue("onKeyReleased");
  1588. IF (command # NIL) THEN HandleEvent(event, SELF, command); END;
  1589. END;
  1590. END CheckKeyEvents;
  1591. PROCEDURE CheckPointerEvent(x, y, z : LONGINT; keys : SET);
  1592. VAR event : PointerEvent; command : Strings.String;
  1593. BEGIN
  1594. ASSERT(IsCallFromSequencer());
  1595. event.x := x; event.y := y; event.z := z; event.keys := keys;
  1596. IF ({0} * keys = {0}) THEN
  1597. command := GetAttributeValue("onLeftClick");
  1598. ELSIF ({2} * keys = {2}) THEN
  1599. command := GetAttributeValue("onRightClick");
  1600. ELSIF ({1} * keys = {1}) THEN
  1601. command := GetAttributeValue("onMiddleClick");
  1602. END;
  1603. IF (command # NIL) THEN HandleEvent(event, SELF, command); END;
  1604. command := GetAttributeValue("onClick");
  1605. IF (command # NIL) THEN HandleEvent(event, SELF, command); END;
  1606. END CheckPointerEvent;
  1607. PROCEDURE CheckPointerUpEvent(x, y, z : LONGINT; keys : SET);
  1608. VAR event : PointerEvent; command : Strings.String;
  1609. BEGIN
  1610. ASSERT(IsCallFromSequencer());
  1611. event.x := x; event.y := y; event.z := z; event.keys := keys;
  1612. command := GetAttributeValue("onRelease");
  1613. IF (command # NIL) THEN HandleEvent(event, SELF, command); END;
  1614. END CheckPointerUpEvent;
  1615. PROCEDURE InEditBounds(x,y: LONGINT): LONGINT;
  1616. CONST Border = 8;
  1617. VAR left, right, top, bottom: LONGINT;
  1618. BEGIN
  1619. left := bounds.GetLeft();
  1620. right := bounds.GetRight();
  1621. top := bounds.GetTop();
  1622. bottom := bounds.GetBottom();
  1623. INC(x,left); INC(y,top); (* relative -> absolute *)
  1624. IF (ABS(left-x) <= Border) THEN
  1625. IF (ABS(top-y) <= Border) THEN
  1626. RETURN UpperLeft
  1627. ELSIF (ABS(bottom-y) <= Border) THEN
  1628. RETURN LowerLeft
  1629. ELSE
  1630. RETURN Left
  1631. END
  1632. ELSIF (ABS(right-x) <= Border) THEN
  1633. IF (ABS(top-y) <= Border) THEN
  1634. RETURN UpperRight
  1635. ELSIF (ABS(bottom-y) <= Border) THEN
  1636. RETURN LowerRight
  1637. ELSE
  1638. RETURN Right
  1639. END
  1640. ELSIF (ABS(y-top) <= Border) THEN
  1641. RETURN Upper
  1642. ELSIF (ABS(bottom-y) <= Border) THEN
  1643. RETURN Lower
  1644. ELSIF (x > left+Border) & (x < right-Border) & (y > top+Border) & (y< bottom-Border) THEN
  1645. RETURN Inside
  1646. ELSE
  1647. RETURN None
  1648. END;
  1649. END InEditBounds;
  1650. PROCEDURE Edit(VAR msg: Messages.Message);
  1651. VAR region: LONGINT; dx,dy: LONGINT; b: Rectangles.Rectangle; manager: WM.WindowManager;
  1652. w,h: LONGINT; img: WMGraphics.Image; canvas: WMGraphics.BufferCanvas; e: ComponentListEntry;
  1653. tr,or : Rectangles.Rectangle; enum: XMLObjects.Enumerator; obj: ANY;
  1654. alignRelative : BOOLEAN;
  1655. BEGIN
  1656. IF msg.msgSubType = Messages.MsgSubPointerUp THEN
  1657. editRegion := None;
  1658. SetPointerInfo(oldPointerInfo);
  1659. RETURN
  1660. END;
  1661. dx := msg.x-editX; dy := msg.y-editY;
  1662. b := bounds.Get();
  1663. IF editRegion = Right THEN
  1664. b.r := b.r + dx
  1665. ELSIF editRegion = Left THEN
  1666. b.l := b.l + dx; dx := 0;
  1667. ELSIF editRegion = Lower THEN
  1668. b.b := b.b + dy
  1669. ELSIF editRegion = Upper THEN
  1670. b.t := b.t + dy; dy := 0;
  1671. ELSIF editRegion = LowerLeft THEN
  1672. b.b := b.b + dy;
  1673. b.l := b.l + dx; dx := 0;
  1674. ELSIF editRegion = LowerRight THEN
  1675. b.b := b.b + dy;
  1676. b.r := b.r + dx
  1677. ELSIF editRegion = UpperLeft THEN
  1678. b.t := b.t + dy; dy := 0;
  1679. b.l := b.l + dx; dx := 0;
  1680. ELSIF editRegion = UpperRight THEN
  1681. b.t := b.t + dy; dy := 0;
  1682. b.r := b.r + dx
  1683. ELSIF (editRegion = Inside) & ((dx # 0) OR (dy # 0)) THEN
  1684. img := selection.ToImg(SELF,e);
  1685. IF e # NIL THEN
  1686. IF StartDrag(selection,img,-msg.x-e.dx,-msg.y-e.dy, EditMoved,NIL) THEN END;
  1687. END;
  1688. RETURN
  1689. ELSIF (editRegion = None) & (msg.flags * {0,1,2} # {}) THEN
  1690. tr.l :=MIN (editX,msg.x); ;
  1691. tr.t := MIN(editY, msg.y);
  1692. tr.r := MAX(editX, msg.x);
  1693. tr.b := MAX(editY, msg.y);
  1694. selection.rectOwner := SELF;
  1695. selection.rect := tr;
  1696. Invalidate;
  1697. enum := GetContents();
  1698. WHILE enum.HasMoreElements() DO
  1699. obj := enum.GetNext();
  1700. IF (obj IS VisualComponent) THEN
  1701. or := obj(VisualComponent).bounds.Get();
  1702. IF Rectangles.Intersect(or, tr) THEN
  1703. selection.Add(obj(VisualComponent))
  1704. END;
  1705. END;
  1706. END;
  1707. RETURN;
  1708. END;
  1709. AdaptRelativeBounds(b, GetParent());
  1710. bounds.Set(b);
  1711. editX := editX + dx; editY := editY + dy;
  1712. END Edit;
  1713. PROCEDURE SetEditMode*(mode: BOOLEAN; recurse: BOOLEAN);
  1714. VAR vc: VisualComponent; c: XML.Content;
  1715. BEGIN
  1716. Acquire;
  1717. editMode.Set(mode);
  1718. IF recurse THEN
  1719. c := GetFirst();
  1720. WHILE (c # NIL) DO
  1721. IF c IS VisualComponent THEN
  1722. vc := c(VisualComponent);
  1723. vc.SetEditMode(mode, TRUE);
  1724. END;
  1725. c := GetNext(c);
  1726. END;
  1727. END;
  1728. Release;
  1729. END SetEditMode;
  1730. PROCEDURE EditMoved(sender, data: ANY);
  1731. VAR parent: XML.Element; ldata: ANY; e: ComponentListEntry;
  1732. BEGIN
  1733. IF (sender # SELF) THEN
  1734. IF (data # NIL) & (data IS WM.DragInfo) THEN
  1735. ldata := data(WM.DragInfo).data;
  1736. IF (ldata # NIL) & (ldata IS XML.Element) THEN
  1737. parent := ldata(XML.Element).GetParent();
  1738. parent.RemoveContent(ldata(XML.Element));
  1739. parent(VisualComponent).Invalidate;
  1740. ELSIF (ldata # NIL) & (ldata IS SelectionList) THEN
  1741. e := ldata(SelectionList).first;
  1742. WHILE e # NIL DO
  1743. parent := e.component.GetParent();
  1744. ldata := e.component;
  1745. parent.RemoveContent(ldata(XML.Element));
  1746. parent(VisualComponent).Invalidate;
  1747. e := e.next;
  1748. END;
  1749. END;
  1750. END;
  1751. END;
  1752. END EditMoved;
  1753. PROCEDURE HandleInternal*(VAR msg : Messages.Message); (** PROTECTED *)
  1754. VAR
  1755. po : VisualComponent; nm : Messages.Message; handled : BOOLEAN; b : Rectangles.Rectangle;
  1756. r, v : VisualComponent;
  1757. p : XML.Element;
  1758. keyFlags: SET; manager : WM.WindowManager;
  1759. currentEditRegion: LONGINT;
  1760. parent: XML.Element;
  1761. parentEditMode: BOOLEAN;
  1762. BEGIN
  1763. ASSERT(IsCallFromSequencer());
  1764. handled := FALSE;
  1765. IF msg.msgType = Messages.MsgPointer THEN
  1766. parent := GetParent();
  1767. IF (parent # NIL) & (parent IS VisualComponent) & parent(VisualComponent).editMode.Get() THEN
  1768. parentEditMode := TRUE
  1769. ELSE
  1770. parentEditMode := FALSE
  1771. END;
  1772. IF msg.msgSubType = Messages.MsgSubPointerMove THEN
  1773. IF (msg.flags * {0, 1, 2} = {}) OR (fPointerOwner = NIL) THEN
  1774. IF parentEditMode & ~editMode.Get() THEN fPointerOwner := SELF; handled := TRUE
  1775. ELSIF ~parentEditMode & (extGetPositionOwner # NIL) THEN extGetPositionOwner(msg.x, msg.y, fPointerOwner, handled);
  1776. END;
  1777. IF ~handled THEN
  1778. po := GetPositionOwner(msg.x, msg.y);
  1779. IF po # fPointerOwner THEN
  1780. nm.msgType := Messages.MsgPointer;
  1781. nm.msgSubType := Messages.MsgSubPointerLeave;
  1782. HandleInternal(nm)
  1783. END;
  1784. fPointerOwner := po
  1785. ELSE
  1786. handled := FALSE;
  1787. END;
  1788. END
  1789. END;
  1790. IF (fPointerOwner = SELF) THEN
  1791. IF (msg.originator # NIL) & (msg.originator IS WM.ViewPort) THEN
  1792. manager := msg.originator(WM.ViewPort).manager;
  1793. msg.originator(WM.ViewPort).GetKeyState(keyFlags);
  1794. END;
  1795. IF parentEditMode & (editRegion # None) THEN
  1796. Edit(msg)
  1797. ELSE
  1798. IF msg.msgSubType = Messages.MsgSubPointerMove THEN
  1799. IF (parentEditMode) & (msg.originator # NIL) & (msg.originator IS WM.ViewPort) THEN
  1800. currentEditRegion := InEditBounds(msg.x, msg.y);
  1801. CASE currentEditRegion OF
  1802. | Lower, Upper: SetPointerInfo(manager.pointerUpDown)
  1803. | Left, Right:SetPointerInfo(manager.pointerLeftRight)
  1804. | LowerLeft, UpperRight:SetPointerInfo(manager.pointerURDL)
  1805. | UpperLeft, LowerRight: SetPointerInfo(manager.pointerULDR)
  1806. | Inside: SetPointerInfo(manager.pointerMove)
  1807. ELSE
  1808. IF oldPointerInfo # NIL THEN
  1809. SetPointerInfo(oldPointerInfo); oldPointerInfo := NIL;
  1810. ELSE oldPointerInfo := GetPointerInfo();
  1811. END;
  1812. END;
  1813. ELSIF editMode.Get() & (msg.flags * {0, 1, 2} # {}) & ~parentEditMode THEN
  1814. IF (keyFlags # {}) & (keyFlags <= Inputs.Shift) THEN
  1815. ELSE
  1816. selection.Reset(SELF);
  1817. END;
  1818. Edit(msg);
  1819. END;
  1820. IF extPointerMove # NIL THEN extPointerMove(msg.x, msg.y, msg.flags, handled) END;
  1821. SetInternalPointerInfo(pointerInfo);
  1822. IF ~handled THEN PointerMove(msg.x, msg.y, msg.flags) END;
  1823. IF msg.dz # 0 THEN WheelMove(msg.dz) END
  1824. ELSIF msg.msgSubType = Messages.MsgSubPointerDown THEN
  1825. IF parentEditMode THEN
  1826. editRegion := InEditBounds(msg.x, msg.y);
  1827. ELSIF editMode.Get() THEN
  1828. editRegion := None;
  1829. editX := msg.x; editY := msg.y;
  1830. END;
  1831. (*
  1832. IF (msg.originator # NIL) & (msg.originator IS WM.ViewPort) THEN
  1833. msg.originator(WM.ViewPort).GetKeyState(keyFlags);
  1834. IF (keyFlags # {}) & (keyFlags <= Inputs.Ctrl) THEN editRegion := InEditBounds(msg.x, msg.y) ELSE editRegion := None END;
  1835. ELSE
  1836. editRegion := None
  1837. END;
  1838. *)
  1839. IF (editRegion # None) & parentEditMode THEN
  1840. IF (keyFlags # {}) & (keyFlags <= Inputs.Shift) THEN
  1841. selection.Toggle(SELF)
  1842. ELSIF ~selection.Has(SELF) THEN
  1843. selection.Reset(SELF);
  1844. selection.Add(SELF);
  1845. END;
  1846. manager := msg.originator(WM.ViewPort).manager;
  1847. editX := msg.x; editY := msg.y;
  1848. ELSE
  1849. IF extPointerDown # NIL THEN extPointerDown(msg.x, msg.y, msg.flags, handled) END;
  1850. IF ~handled THEN PointerDown(msg.x, msg.y, msg.flags) END;
  1851. END;
  1852. SetFocus
  1853. ELSIF msg.msgSubType = Messages.MsgSubPointerUp THEN
  1854. IF selection.rectOwner = SELF THEN
  1855. Invalidate;
  1856. selection.rectOwner := NIL;
  1857. END;
  1858. IF extPointerUp # NIL THEN extPointerUp(msg.x, msg.y, msg.flags, handled) END;
  1859. IF ~handled THEN PointerUp(msg.x, msg.y, msg.flags) END
  1860. ELSIF msg.msgSubType = Messages.MsgSubPointerLeave THEN
  1861. IF extPointerLeave # NIL THEN extPointerLeave(handled) END;
  1862. IF ~handled THEN PointerLeave END
  1863. END;
  1864. IF ~parentEditMode & (msg.flags * {0, 1, 2} # {}) THEN
  1865. IF (msg.msgSubType = Messages.MsgSubPointerDown) THEN
  1866. CheckPointerEvent(msg.x, msg.y, msg.z, msg.flags);
  1867. ELSIF msg.msgSubType = Messages.MsgSubPointerUp THEN
  1868. CheckPointerUpEvent(msg.x, msg.y, msg.z, msg.flags);
  1869. END;
  1870. END;
  1871. END;
  1872. ELSE
  1873. b := fPointerOwner.bounds.Get();
  1874. msg.x := msg.x - b.l; msg.y := msg.y - b.t;
  1875. fPointerOwner.Handle(msg)
  1876. END
  1877. ELSIF msg.msgType = Messages.MsgKey THEN
  1878. IF fPointerOwner.EditKeyEvents(msg.x, msg.flags, msg.y) THEN
  1879. handled := TRUE
  1880. ELSIF focusComponent # SELF THEN focusComponent.Handle(msg)
  1881. ELSIF (visible.Get()) THEN
  1882. IF ~needsTab.Get() & (msg.y = 0FF09H) THEN
  1883. IF (Inputs.Shift * msg.flags # {}) THEN FocusPrev ELSE FocusNext END
  1884. ELSIF msg.y = 0FF67H THEN ShowContextMenu(0, 0)
  1885. ELSE
  1886. IF extKeyEvent # NIL THEN extKeyEvent(msg.x, msg.flags, msg.y, handled) END;
  1887. IF ~handled THEN KeyEvent(msg.x, msg.flags, msg.y) END;
  1888. CheckKeyEvents(msg.x, msg.flags, msg.y);
  1889. END
  1890. END;
  1891. ELSIF msg.msgType = Messages.MsgDrag THEN
  1892. IF extGetPositionOwner # NIL THEN extGetPositionOwner(msg.x, msg.y, po, handled); END;
  1893. IF ~handled THEN
  1894. po := GetPositionOwner(msg.x, msg.y);
  1895. ELSE
  1896. handled := FALSE;
  1897. END;
  1898. IF (po # SELF) & editMode.Get() & (~po.editMode.Get() OR (msg.ext # NIL) & (msg.ext(WM.DragInfo).data=po)) THEN
  1899. po := SELF
  1900. ELSIF (msg.ext # NIL) & (msg.ext(WM.DragInfo).data # NIL) & (msg.ext(WM.DragInfo).data IS ToggleEditMode) & (msg.ext(WM.DragInfo).data(ToggleEditMode).recursion = Recursion.FromBottom) THEN
  1901. po := SELF
  1902. END;
  1903. IF (po # SELF) THEN (* Let child handle the drag and drop message *)
  1904. b := po.bounds.Get();
  1905. msg.x := msg.x - b.l; msg.y := msg.y - b.t;
  1906. po.Handle(msg)
  1907. ELSE (* handle the drag and drop message *)
  1908. IF msg.msgSubType = Messages.MsgDragOver THEN
  1909. IF (msg.ext # NIL) THEN
  1910. IF extDragOver # NIL THEN extDragOver(msg.x, msg.y, msg.ext(WM.DragInfo), handled) END;
  1911. IF ~handled THEN po.DragOver(msg.x, msg.y, msg.ext(WM.DragInfo)) END
  1912. END
  1913. ELSIF msg.msgSubType = Messages.MsgDragDropped THEN
  1914. IF (msg.ext # NIL) THEN
  1915. IF (msg.ext(WM.DragInfo).data # NIL) & (msg.ext(WM.DragInfo).data IS FindComponentMode) THEN
  1916. IF msg.ext(WM.DragInfo).onAccept # NIL THEN
  1917. msg.ext(WM.DragInfo).onAccept(po, msg.ext(WM.DragInfo));
  1918. END;
  1919. ELSIF (msg.ext(WM.DragInfo).data # NIL) & (msg.ext(WM.DragInfo).data IS ToggleEditMode) THEN
  1920. SetEditMode(~editMode.Get(), msg.ext(WM.DragInfo).data(ToggleEditMode).recursion # Recursion.None);
  1921. Invalidate;
  1922. ELSIF editMode.Get() THEN
  1923. handled := EditDragDropped(msg.x,msg.y,msg.ext(WM.DragInfo));
  1924. ELSIF extDragDropped # NIL THEN
  1925. extDragDropped(msg.x, msg.y, msg.ext(WM.DragInfo), handled)
  1926. END;
  1927. IF ~handled THEN
  1928. po.DragDropped(msg.x, msg.y, msg.ext(WM.DragInfo))
  1929. END
  1930. END
  1931. END
  1932. END
  1933. ELSIF (msg.msgType = Messages.MsgFocus) & (msg.msgSubType = Messages.MsgSubFocusLost) THEN
  1934. (* unset the old focus chain *)
  1935. r := GetVisualComponentRoot(); (* find the leaf component that has the focus *)
  1936. WHILE (r # NIL) & (r.focusComponent # NIL) & (r.focusComponent # r) DO r := r.focusComponent END;
  1937. p := r; (* clear the focus chain until the root or this component *)
  1938. WHILE (p # SELF) & (p # NIL) & (p IS VisualComponent) DO
  1939. v := p(VisualComponent);
  1940. v.focusComponent := v;
  1941. v.FocusLost; IF v.extFocus # NIL THEN v.extFocus(FALSE) END; p := p.GetParent()
  1942. END;
  1943. ELSIF msg.msgType = Messages.MsgInvalidate THEN
  1944. IF msg.msgSubType = Messages.MsgSubAll THEN
  1945. msg.sender(VisualComponent).InvalidateRect(GetClientRect());
  1946. ELSIF msg.msgSubType = Messages.MsgSubRectangle THEN
  1947. msg.sender(VisualComponent).InvalidateRect(Rectangles.MakeRect(msg.x, msg.y, msg.dx, msg.dy));
  1948. ELSE (* nothing to do *)
  1949. END;
  1950. ELSIF msg.msgType = Messages.MsgExt THEN
  1951. IF msg.ext = invalidateRectMsg THEN
  1952. TRACE("WARNING: OLD MESSAGE FORM");
  1953. msg.sender(VisualComponent).InvalidateRect(Rectangles.MakeRect(msg.x, msg.y, msg.dx, msg.dy))
  1954. ELSE
  1955. BroadcastSubcomponents(msg);
  1956. END
  1957. ELSE HandleInternal^(msg)
  1958. END;
  1959. END HandleInternal;
  1960. END VisualComponent;
  1961. GetPositionOwnerHandler* = PROCEDURE {DELEGATE} (x, y : LONGINT; VAR positionOwner : VisualComponent; VAR handled : BOOLEAN);
  1962. TYPE
  1963. (* Layout Manager *)
  1964. LayoutManager* = PROCEDURE {DELEGATE} (vc : VisualComponent);
  1965. FormWindow* = OBJECT(WM.DoubleBufferWindow)
  1966. VAR
  1967. form- : Form;
  1968. cs : WMGraphics.CanvasState;
  1969. disableUpdate : LONGINT;
  1970. content : VisualComponent;
  1971. scaling* : BOOLEAN;
  1972. PROCEDURE ToXML*():XML.Content;
  1973. VAR winx: XML.Element; a: XML.Attribute; string: ARRAY 128 OF CHAR; title:Strings.String;
  1974. BEGIN {EXCLUSIVE}
  1975. NEW(winx); winx.SetName("FormWindow");
  1976. NEW(a); a.SetName("name");
  1977. title:=GetTitle(); IF title=NIL THEN a.SetValue("componentWindow") ELSE a.SetValue(title^) END;
  1978. winx.AddAttribute(a);
  1979. NEW(a); a.SetName("loader"); a.SetValue("WMComponents.FormWindowGen"); winx.AddAttribute(a);
  1980. NEW(a); a.SetName("l"); Strings.IntToStr(bounds.l, string); a.SetValue(string); winx.AddAttribute(a);
  1981. NEW(a); a.SetName("t"); Strings.IntToStr(bounds.t, string); a.SetValue(string); winx.AddAttribute(a);
  1982. NEW(a); a.SetName("r"); Strings.IntToStr(bounds.r, string); a.SetValue(string); winx.AddAttribute(a);
  1983. NEW(a); a.SetName("b"); Strings.IntToStr(bounds.b, string); a.SetValue(string); winx.AddAttribute(a);
  1984. NEW(a); a.SetName("flags"); Strings.SetToStr(flags, string); a.SetValue(string); winx.AddAttribute(a);
  1985. NEW(a); a.SetName("canvasGenerator"); a.SetValue(canvas.generator^); winx.AddAttribute(a);
  1986. winx.AddContent(form);
  1987. RETURN winx
  1988. END ToXML;
  1989. PROCEDURE LoadComponents*(xml: XML.Element);
  1990. VAR component: Repositories.Component;
  1991. BEGIN
  1992. IF xml # NIL THEN
  1993. component := Repositories.ComponentFromXML(xml);
  1994. IF (component # NIL) & (component IS VisualComponent) THEN
  1995. SetContent(component);
  1996. ELSE
  1997. KernelLog.String("formwindow could not load content"); KernelLog.Ln;
  1998. END;
  1999. END;
  2000. END LoadComponents;
  2001. PROCEDURE StoreComponents*(): XML.Element;
  2002. BEGIN RETURN content (* do not store form separately *)
  2003. END StoreComponents;
  2004. PROCEDURE SetContent*(x : XML.Content);
  2005. VAR c: XML.Content;
  2006. m:Messages.Message;
  2007. BEGIN
  2008. IF sequencer # NIL THEN sequencer.WaitFree() END;
  2009. BEGIN{EXCLUSIVE}
  2010. INC(disableUpdate);
  2011. INCL(flags, 13); (* render windows background non-displayed*)
  2012. IF form # NIL THEN form.Finalize; form.sequencer.Stop; content:=NIL END;
  2013. IF x IS Form THEN
  2014. form := x(Form);
  2015. form.initialized:=FALSE;
  2016. form.SetWindow(SELF); (* includes new sequencer *)
  2017. c:=form.GetFirst(); (* get first VisualComponent content of form*)
  2018. WHILE (c#NIL) & (c IS XML.Container) & ~(c IS VisualComponent) DO
  2019. c:=c(XML.Container).GetNext(c);
  2020. END;
  2021. IF c#NIL THEN form.RemoveContent(c) END; (* avoid duplicates. will be added in a systematic way below in AddContent *)
  2022. ELSE
  2023. NEW(form, SELF); (* includes new sequencer; initialized=FALSE *)
  2024. form.uid.Set(NewString("form"));
  2025. c:=x;
  2026. END;
  2027. IF (c#NIL) & (c IS VisualComponent) THEN
  2028. content := c(VisualComponent);
  2029. form.initialized:=TRUE;
  2030. form.AddContent(content);
  2031. form.focusComponent := content;
  2032. form.fPointerOwner := content;
  2033. END;
  2034. DEC(disableUpdate);
  2035. END;
  2036. (*form.Initialize;*)(*implied above*)
  2037. (*form.Invalidate;*)(*implied above*)
  2038. END SetContent;
  2039. PROCEDURE DisableUpdate*;
  2040. BEGIN {EXCLUSIVE}
  2041. INC(disableUpdate);
  2042. ASSERT(disableUpdate # -1); (* overflow *)
  2043. END DisableUpdate;
  2044. PROCEDURE EnableUpdate*;
  2045. BEGIN {EXCLUSIVE}
  2046. DEC(disableUpdate);
  2047. ASSERT(disableUpdate # -1); (* underflow *)
  2048. END EnableUpdate;
  2049. PROCEDURE Resized*( width, height: LONGINT);
  2050. BEGIN
  2051. IF ~scaling THEN
  2052. DisableUpdate;
  2053. form.Acquire;
  2054. ReInit(width, height);
  2055. form.Release;
  2056. form.bounds.Set(Rectangles.MakeRect(0, 0, GetWidth(), GetHeight()));
  2057. content.bounds.Set(Rectangles.MakeRect(0, 0, GetWidth(), GetHeight()));
  2058. EnableUpdate;
  2059. form.Invalidate()
  2060. END
  2061. END Resized;
  2062. PROCEDURE Trap():BOOLEAN;
  2063. BEGIN
  2064. KernelLog.String("WMComponents.FormWindow.Trap !!! --> Resetting Locks "); KernelLog.Ln;
  2065. form.sequencer.lock.Reset;
  2066. RETURN TRUE
  2067. END Trap;
  2068. PROCEDURE Update(rect : Rectangles.Rectangle);
  2069. BEGIN
  2070. (*KernelLog.String("Update "); KernelLog.Int(disableUpdate,0); KernelLog.Ln;*)
  2071. IF disableUpdate > 0 THEN RETURN END;
  2072. form.Acquire;
  2073. canvas.SaveState(cs);
  2074. canvas.SetClipRect(rect);
  2075. canvas.ClipRectAsNewLimits(0, 0);
  2076. IF Raster.alpha IN img.fmt.components THEN
  2077. canvas.Fill(rect, 0H, WMGraphics.ModeCopy)
  2078. ELSE
  2079. canvas.Fill(rect, 0H (*0FFH*), Raster.clear(*WMGraphics.ModeCopy*))
  2080. END;
  2081. form.Draw(canvas);
  2082. canvas.RestoreState(cs);
  2083. form.Release;
  2084. CopyRect(rect);
  2085. Invalidate(rect)
  2086. END Update;
  2087. PROCEDURE Handle*(VAR m : Messages.Message);
  2088. VAR pendingM: Messages.Message;
  2089. BEGIN
  2090. Handle^(m);
  2091. IF (m.msgType = Messages.MsgExt) & (m.ext # NIL) THEN
  2092. IF (m.ext = componentStyleMsg) THEN CSChanged
  2093. END;
  2094. ELSIF (m.msgType = Messages.MsgFocus) & (m.msgSubType = Messages.MsgSubFocusGot) THEN
  2095. IF (form # NIL) & (form.lastFocusComponent # NIL) THEN
  2096. form.lastFocusComponent.SetFocus;
  2097. END;
  2098. ELSIF (m.msgType = Messages.MsgSetLanguage) & (m.ext # NIL) & (m.ext IS LanguageExtension) THEN
  2099. LanguageChanged(m.ext(LanguageExtension).languages);
  2100. ELSIF (m.msgType=Messages.MsgInvalidate) THEN (* sent by WindowManager when a window is added to display space to assure it is up-to-date*)
  2101. IF form=NIL THEN RETURN
  2102. ELSE m.sender:=form; (* will be passed to form below, which will call sender.InvalidateRect *)
  2103. END;
  2104. END;
  2105. IF (TraceFocus IN Trace) THEN
  2106. IF (m.msgType = Messages.MsgFocus) THEN
  2107. IF (m.msgSubType = Messages.MsgSubFocusGot) THEN
  2108. KernelLog.String("Got Focus: "); form.TraceFocusChain;
  2109. ELSIF (m.msgSubType = Messages.MsgSubMasterFocusGot) THEN
  2110. KernelLog.String("Got Master Focus: "); form.TraceFocusChain;
  2111. END;
  2112. ELSIF (m.msgType = Messages.MsgKey) & (m.x = ORD("f")) THEN
  2113. KernelLog.String("Focus chain: "); form.TraceFocusChain;
  2114. END;
  2115. END;
  2116. IF (form # NIL) THEN form.Handle(m); END;
  2117. END Handle;
  2118. PROCEDURE LanguageChanged*(languages : Localization.Languages);
  2119. BEGIN
  2120. ASSERT(languages # NIL);
  2121. END LanguageChanged;
  2122. PROCEDURE CSChanged*;
  2123. BEGIN
  2124. DisableUpdate; (* the components are going to redraw like crazy *)
  2125. form.Acquire;
  2126. form.Reset(SELF, NIL);
  2127. form.Release;
  2128. EnableUpdate;
  2129. END CSChanged;
  2130. PROCEDURE Close*;
  2131. BEGIN
  2132. Close^; (* remove the form to avoid further messages *)
  2133. IF form # NIL THEN
  2134. form.Acquire;
  2135. form.Finalize; form.sequencer.Stop;
  2136. form.Release
  2137. END;
  2138. END Close;
  2139. END FormWindow;
  2140. Form* = OBJECT(VisualComponent)
  2141. VAR
  2142. window- : FormWindow;
  2143. lastFocusComponent : VisualComponent;
  2144. PROCEDURE &New*(window : FormWindow);
  2145. BEGIN
  2146. Init;
  2147. SetGenerator("WMComponents.NewForm");
  2148. lastFocusComponent := NIL;
  2149. SetNameAsString(StrForm);
  2150. SetWindow(window);
  2151. END New;
  2152. PROCEDURE SetWindow*(window: FormWindow);
  2153. VAR seq: Messages.MsgSequencer;
  2154. BEGIN {EXCLUSIVE}
  2155. IF window # NIL THEN
  2156. SELF.window := window;
  2157. window.form := SELF;
  2158. bounds.Set(Rectangles.MakeRect(0, 0, window.GetWidth(), window.GetHeight()));
  2159. NEW(seq, Handle); seq.SetTrapHandler(window.Trap); SetSequencer(seq);
  2160. END;
  2161. END SetWindow;
  2162. PROCEDURE GetPointerInfo*() : WM.PointerInfo;
  2163. BEGIN
  2164. ASSERT(IsCallFromSequencer());
  2165. IF window # NIL THEN RETURN window.pointerInfo ELSE RETURN NIL END
  2166. END GetPointerInfo;
  2167. PROCEDURE SetPointerInfo*(pi : WM.PointerInfo);
  2168. BEGIN
  2169. ASSERT(IsCallFromSequencer());
  2170. IF window # NIL THEN window.SetPointerInfo(pi) END;
  2171. END SetPointerInfo;
  2172. PROCEDURE DisableUpdate*;
  2173. BEGIN
  2174. ASSERT(IsCallFromSequencer());
  2175. IF window # NIL THEN window.DisableUpdate END
  2176. END DisableUpdate;
  2177. PROCEDURE EnableUpdate*;
  2178. BEGIN
  2179. ASSERT(IsCallFromSequencer());
  2180. IF window # NIL THEN window.EnableUpdate END
  2181. END EnableUpdate;
  2182. PROCEDURE InvalidateRect*(rect : Rectangles.Rectangle);
  2183. BEGIN
  2184. IF window # NIL THEN
  2185. BEGIN{EXCLUSIVE} AWAIT(initialized) END;
  2186. window.Update(rect)
  2187. END;
  2188. END InvalidateRect;
  2189. PROCEDURE PropertyChanged*(sender, property : ANY);
  2190. VAR w,h: LONGINT;
  2191. BEGIN
  2192. IF property = bounds THEN
  2193. IF ~ Rectangles.IsEqual(window.bounds, bounds.Get()) THEN
  2194. bounds.GetExtents(w,h);
  2195. IF window # NIL THEN
  2196. window.manager.SetWindowSize(window,w,h);
  2197. END;
  2198. ELSE
  2199. (*ScaleFont(bounds.GetHeight(), scaleFont.Get());*)
  2200. Resized
  2201. END;
  2202. END
  2203. END PropertyChanged;
  2204. END Form;
  2205. TYPE
  2206. (** PropertyLists for style support *)
  2207. PropertyListEntry = POINTER TO RECORD
  2208. next : PropertyListEntry;
  2209. name : Strings.String;
  2210. list : WMProperties.PropertyList;
  2211. END;
  2212. ListArray* = POINTER TO ARRAY OF WMProperties.PropertyList;
  2213. PropertyListList* = OBJECT
  2214. VAR
  2215. first : PropertyListEntry;
  2216. PROCEDURE Find*(CONST name : ARRAY OF CHAR) : WMProperties.PropertyList;
  2217. VAR cur : PropertyListEntry;
  2218. BEGIN {EXCLUSIVE}
  2219. cur := first;
  2220. WHILE (cur # NIL) & (cur.name^ # name) DO cur := cur.next END;
  2221. IF cur # NIL THEN RETURN cur.list
  2222. ELSE RETURN NIL
  2223. END
  2224. END Find;
  2225. PROCEDURE RemoveInternal(CONST name : ARRAY OF CHAR);
  2226. VAR cur : PropertyListEntry;
  2227. BEGIN
  2228. IF first = NIL THEN RETURN END;
  2229. IF (first # NIL) & (first.name^ = name) THEN first := first.next
  2230. ELSE
  2231. cur := first;
  2232. WHILE (cur.next # NIL) DO
  2233. IF (cur.next.name^ = name) THEN cur.next := cur.next.next END;
  2234. cur := cur.next
  2235. END
  2236. END
  2237. END RemoveInternal;
  2238. PROCEDURE Remove*(CONST name : ARRAY OF CHAR);
  2239. BEGIN {EXCLUSIVE}
  2240. RemoveInternal(name)
  2241. END Remove;
  2242. PROCEDURE Add*(CONST name : ARRAY OF CHAR; pl : WMProperties.PropertyList);
  2243. VAR new : PropertyListEntry;
  2244. BEGIN {EXCLUSIVE}
  2245. RemoveInternal(name);
  2246. NEW(new); new.name := NewString(name); new.list := pl; new.next := first; first := new
  2247. END Add;
  2248. PROCEDURE Enumerate*() : ListArray;
  2249. VAR array : ListArray; current : PropertyListEntry; i : LONGINT;
  2250. BEGIN {EXCLUSIVE}
  2251. i := 0;
  2252. current := first;
  2253. WHILE current # NIL DO INC(i); current := current.next END;
  2254. NEW(array, i );
  2255. current := first;
  2256. i := 0;
  2257. WHILE current # NIL DO
  2258. array[i] := current.list;
  2259. INC(i);
  2260. current := current.next
  2261. END;
  2262. RETURN array
  2263. END Enumerate;
  2264. PROCEDURE UpdateStyle*;
  2265. VAR
  2266. en : XMLObjects.Enumerator;
  2267. p : ANY; s : Strings.String;
  2268. pl : WMProperties.PropertyList;
  2269. BEGIN
  2270. IF currentStyle = NIL THEN RETURN END;
  2271. en := currentStyle.GetContents();
  2272. WHILE en.HasMoreElements() DO
  2273. p := en.GetNext();
  2274. IF p IS XML.Element THEN
  2275. s := p(XML.Element).GetName();
  2276. pl := propertyListList.Find(s^);
  2277. IF pl # NIL THEN pl.SetXML(p(XML.Element)) END
  2278. END
  2279. END
  2280. END UpdateStyle;
  2281. END PropertyListList;
  2282. ComponentListEntry= POINTER TO RECORD
  2283. component: VisualComponent;
  2284. dx,dy: LONGINT;
  2285. next: ComponentListEntry
  2286. END;
  2287. SelectionArray* = POINTER TO ARRAY OF VisualComponent;
  2288. SelectionList*= OBJECT
  2289. VAR first, last: ComponentListEntry; number: LONGINT; state: LONGINT; timer: Kernel.Timer;
  2290. onChanged-: WMEvents.EventSource;
  2291. lock: Locks.RecursiveLock;
  2292. rectOwner: ANY;
  2293. rect : Rectangles.Rectangle;
  2294. PROCEDURE &Init;
  2295. BEGIN
  2296. NEW(lock);
  2297. first := NIL; last := NIL; number := 0; state := 0; NEW(onChanged, NIL, NIL, NIL, NIL);
  2298. END Init;
  2299. PROCEDURE Reset(this: VisualComponent);
  2300. VAR entry: ComponentListEntry;
  2301. BEGIN
  2302. lock.Acquire;
  2303. entry := first;
  2304. first := NIL; last := NIL; number := 0;
  2305. WHILE entry # NIL DO entry.component.Invalidate; entry := entry.next END;
  2306. lock.Release;
  2307. (*Add(this);*)
  2308. onChanged.Call(SELF);
  2309. END Reset;
  2310. PROCEDURE Has*(this: ANY): BOOLEAN;
  2311. VAR entry: ComponentListEntry;
  2312. BEGIN
  2313. IF first = NIL THEN RETURN FALSE END; (* no lock for usual case *)
  2314. lock.Acquire;
  2315. entry := first;
  2316. WHILE (entry # NIL) & (entry.component # this) DO entry := entry.next END;
  2317. lock.Release;
  2318. RETURN entry # NIL
  2319. END Has;
  2320. PROCEDURE Add*(this: VisualComponent);
  2321. VAR entry: ComponentListEntry;
  2322. BEGIN
  2323. IF (this = NIL) OR Has(this) THEN RETURN END;
  2324. lock.Acquire;
  2325. NEW(entry); entry.component := this; entry.next := NIL;
  2326. IF last = NIL THEN
  2327. ASSERT(first = NIL);
  2328. first := entry; last := entry;
  2329. ELSE
  2330. last.next := entry; last := entry
  2331. END;
  2332. INC(number);
  2333. lock.Release;
  2334. this.Invalidate;
  2335. onChanged.Call(SELF);
  2336. END Add;
  2337. PROCEDURE Remove*(this: VisualComponent);
  2338. VAR entry, prev: ComponentListEntry;
  2339. BEGIN
  2340. lock.Acquire;
  2341. entry := first; prev := NIL;
  2342. WHILE (entry # NIL) & (entry.component # this) DO
  2343. prev := entry;
  2344. entry := entry.next;
  2345. END;
  2346. IF entry = NIL THEN lock.Release; RETURN END;
  2347. IF prev # NIL THEN prev.next := entry.next END;
  2348. IF entry = first THEN first := first.next END;
  2349. IF entry = last THEN last := prev END;
  2350. DEC(number);
  2351. lock.Release;
  2352. this.Invalidate;
  2353. onChanged.Call(SELF);
  2354. END Remove;
  2355. PROCEDURE GetSelection*(): SelectionArray;
  2356. VAR array: SelectionArray; i: LONGINT; e: ComponentListEntry;
  2357. BEGIN
  2358. lock.Acquire;
  2359. NEW(array, number);
  2360. e := first; i := 0;
  2361. WHILE e # NIL DO
  2362. array[i] := e.component;
  2363. INC(i);
  2364. e := e.next;
  2365. END;
  2366. lock.Release;
  2367. RETURN array;
  2368. END GetSelection;
  2369. PROCEDURE Toggle*(this: VisualComponent);
  2370. BEGIN
  2371. IF Has(this) THEN Remove(this) ELSE Add(this) END;
  2372. END Toggle;
  2373. PROCEDURE Update;
  2374. VAR e: ComponentListEntry;
  2375. BEGIN
  2376. e := first;
  2377. WHILE e # NIL DO
  2378. e.component.Invalidate;
  2379. e := e.next;
  2380. END;
  2381. END Update;
  2382. PROCEDURE Shift(dx, dy: LONGINT);
  2383. VAR e: ComponentListEntry; rect: Rectangles.Rectangle;
  2384. BEGIN
  2385. e := first;
  2386. WHILE e # NIL DO
  2387. rect := e.component.bounds.Get();
  2388. INC(rect.l,dx); INC(rect.r,dx);
  2389. INC(rect.t,dy); INC(rect.b,dy);
  2390. e.component.AdaptRelativeBounds(rect,e.component.GetParent());
  2391. e.component.bounds.Set(rect);
  2392. e := e.next
  2393. END;
  2394. END Shift;
  2395. PROCEDURE ToImg(start: VisualComponent; VAR this: ComponentListEntry): WMGraphics.Image;
  2396. VAR l,t,r,b: LONGINT; e: ComponentListEntry; rect: Rectangles.Rectangle; img, image: WMGraphics.Image; w,h: LONGINT;
  2397. canvas: WMGraphics.BufferCanvas; srcCopy: Raster.Mode;
  2398. BEGIN
  2399. l := MAX(LONGINT); r := MIN(LONGINT);
  2400. t := MAX(LONGINT); b := MIN(LONGINT);
  2401. e := first;
  2402. WHILE e # NIL DO
  2403. rect := e.component(VisualComponent).bounds.Get();
  2404. IF rect.l < l THEN l := rect.l END;
  2405. IF rect.r > r THEN r := rect.r END;
  2406. IF rect.t < t THEN t := rect.t END;
  2407. IF rect.b > b THEN b := rect.b END;
  2408. e := e.next;
  2409. END;
  2410. Raster.InitMode(srcCopy, Raster.srcCopy);
  2411. NEW(image);
  2412. w := r-l+1; h := b-t+1;
  2413. Raster.Create(image, w,h, Raster.BGRA8888);
  2414. e := first;
  2415. WHILE e # NIL DO
  2416. rect := e.component.bounds.Get();
  2417. NEW(img);
  2418. Raster.Create(img,rect.r-rect.l+1, rect.b-rect.t+1, Raster.BGRA8888);
  2419. NEW(canvas,img);
  2420. e.component.Draw(canvas);
  2421. Raster.Copy(img,image,0,0,img.width-1, img.height-1,rect.l-l, rect.t-t, srcCopy);
  2422. e.dx := rect.l-l; e.dy := rect.t-t;
  2423. IF e.component = start THEN this := e END;
  2424. e := e.next
  2425. END;
  2426. RETURN image
  2427. END ToImg;
  2428. BEGIN {ACTIVE}
  2429. NEW(timer);
  2430. LOOP
  2431. timer.Sleep(400);
  2432. state := (state + 1) MOD 2;
  2433. Update;
  2434. END
  2435. END SelectionList;
  2436. WindowGenerator*= PROCEDURE(xml: XML.Content): WM.Window;
  2437. VAR
  2438. hasErrors : BOOLEAN; (* accessed only from (EXCLUSIVE) *)
  2439. invalidateRectMsg- : Messages.MessageExtension; (* used as unique ID *)
  2440. PrototypeID, PrototypeUID : WMProperties.StringProperty;
  2441. PrototypeBounds-, PrototypeBoundsRelative-, PrototypeBearing : WMProperties.RectangleProperty;
  2442. PrototypeEnabled : WMProperties.BooleanProperty;
  2443. PrototypeFillColor : WMProperties.ColorProperty;
  2444. PrototypeAlignment : WMProperties.Int32Property;
  2445. PrototypeVisible, PrototypeTakesFocus, PrototypeNeedsTab, PrototypeEditMode: WMProperties.BooleanProperty;
  2446. PrototypeScaleFont: WMProperties.Int32Property;
  2447. PrototypeFocusPrevious, PrototypeFocusNext : WMProperties.StringProperty;
  2448. PrototypeFont- : WMProperties.FontProperty;
  2449. StrComponent, StrVisualComponent, StrForm, StrFormWindow, StrModel, StrModelInfo : Strings.String;
  2450. GSonStartDrag, GSonStartDragInfo : Strings.String;
  2451. ModelPrototype-: WMProperties.ReferenceProperty;
  2452. propertyListList- : PropertyListList;
  2453. currentStyle- : XML.Element;
  2454. componentStyleMsg- : ComponentStyleChanged;
  2455. timestamp : LONGINT;
  2456. macroHandlers : MacroHandler; (* the head of the list is always the DefaultMacroHandler *)
  2457. selection-: SelectionList;
  2458. PROCEDURE IsWhiteSpace(ch : CHAR) : BOOLEAN;
  2459. BEGIN
  2460. RETURN ch <= " ";
  2461. END IsWhiteSpace;
  2462. PROCEDURE SkipWhiteSpace(CONST string : ARRAY OF CHAR; VAR index : LONGINT);
  2463. VAR length : LONGINT;
  2464. BEGIN
  2465. length := LEN(string);
  2466. WHILE (index < length) & (string[index] # 0X) & IsWhiteSpace(string[index]) DO INC(index); END;
  2467. ASSERT(index < LEN(string));
  2468. END SkipWhiteSpace;
  2469. PROCEDURE ReadWord*(CONST string : ARRAY OF CHAR; VAR word : ARRAY OF CHAR; VAR index : LONGINT) : BOOLEAN;
  2470. VAR length, wordLength, i : LONGINT;
  2471. BEGIN
  2472. SkipWhiteSpace(string, index);
  2473. length := LEN(string);
  2474. wordLength := LEN(word);
  2475. i := 0;
  2476. WHILE (index < length) & (string[index] # 0X) & ~IsWhiteSpace(string[index]) & (i < wordLength) DO
  2477. word[i] := string[index];
  2478. INC(i);
  2479. INC(index);
  2480. END;
  2481. IF (i < wordLength) THEN word[i] := 0X; END;
  2482. ASSERT(index < LEN(string));
  2483. RETURN (i > 0) & (index < length) & (i < wordLength);
  2484. END ReadWord;
  2485. (* Split <string> into two strings separated by <separator> *)
  2486. PROCEDURE SplitMacroString(CONST string : ARRAY OF CHAR; VAR namespace, name : ARRAY OF CHAR; separator : CHAR);
  2487. VAR i, j : LONGINT;
  2488. BEGIN
  2489. ASSERT((LEN(namespace) >= LEN(string)) & (LEN(name) >= LEN(string)));
  2490. i := 0;
  2491. WHILE (i < LEN(string)) & (string[i] # 0X) & (string[i] # separator) DO
  2492. namespace[i] := string[i];
  2493. INC(i);
  2494. END;
  2495. namespace[i] := 0X;
  2496. INC(i); (* skip separator *)
  2497. j := 0;
  2498. WHILE (i < LEN(string)) & (string[i] # 0X) DO
  2499. name[j] := string[i];
  2500. INC(i); INC(j);
  2501. END;
  2502. name[j] := 0X;
  2503. IF (name = "") THEN COPY(namespace, name); COPY(NoNamespace, namespace); END; (* no namespace *)
  2504. END SplitMacroString;
  2505. PROCEDURE ReportError(CONST text, argument1, argument2 : ARRAY OF CHAR);
  2506. VAR
  2507. message : Events.Message;
  2508. textIdx, messageIdx : LONGINT;
  2509. secondArgument : BOOLEAN;
  2510. PROCEDURE Append(VAR message : ARRAY OF CHAR; CONST argument : ARRAY OF CHAR; VAR index : LONGINT);
  2511. VAR i : LONGINT;
  2512. BEGIN
  2513. i := 0;
  2514. WHILE (i < LEN(argument)) & (argument[i] # 0X) & (index < LEN(message) - 1) DO
  2515. message[index] := argument[i];
  2516. INC(i);
  2517. INC(index);
  2518. END;
  2519. END Append;
  2520. BEGIN
  2521. secondArgument := FALSE;
  2522. textIdx := 0;
  2523. messageIdx := 0;
  2524. WHILE (textIdx < LEN(text)) & (text[textIdx] # 0X) & (messageIdx < LEN(message) - 1) DO
  2525. IF (text[textIdx] # "%") THEN
  2526. message[messageIdx] := text[textIdx];
  2527. INC(messageIdx);
  2528. ELSE
  2529. IF ~secondArgument THEN
  2530. secondArgument := TRUE;
  2531. Append(message, argument1, messageIdx);
  2532. ELSE
  2533. Append(message, argument2, messageIdx);
  2534. END;
  2535. END;
  2536. INC(textIdx);
  2537. END;
  2538. message[messageIdx] := 0X;
  2539. Events.AddEvent("Components", Events.Error, 0, 0, 0, message, FALSE);
  2540. END ReportError;
  2541. PROCEDURE GetArgumentStream*(command: Strings.String; offset: LONGINT; VAR arguments: Streams.StringReader);
  2542. VAR i: LONGINT;
  2543. BEGIN
  2544. IF command = NIL THEN arguments := NIL; RETURN END;
  2545. i := offset;
  2546. WHILE (i < LEN(command)) & (command[i] # 0X) DO INC(i); END;
  2547. IF (i # offset) THEN
  2548. NEW(arguments, i - offset + 1);
  2549. arguments.SetRaw(command^, offset, i - offset + 1);
  2550. ELSE
  2551. arguments := NIL;
  2552. END;
  2553. END GetArgumentStream;
  2554. PROCEDURE GenerateContext*(oldCommand, command : Strings.String; index : LONGINT; originator : Component; CONST event : Event) : EventContext;
  2555. VAR
  2556. context : EventContext; pointerContext : PointerContext; keyContext : KeyContext;
  2557. arguments : Streams.StringReader;
  2558. i : LONGINT;
  2559. BEGIN
  2560. ASSERT((command # NIL) & (0 <= index) & (index < LEN(command)));
  2561. ASSERT(originator # NIL);
  2562. GetArgumentStream(command,index,arguments);
  2563. IF (event IS PointerEvent) THEN
  2564. NEW(pointerContext, originator, oldCommand, NIL, arguments, NIL, NIL, NIL); pointerContext.pointer := event(PointerEvent);
  2565. context := pointerContext;
  2566. ELSIF (event IS KeyPressedEvent) THEN
  2567. NEW(keyContext, originator, oldCommand, NIL, arguments, NIL, NIL, NIL); keyContext.key := event(KeyPressedEvent);
  2568. context := keyContext;
  2569. ELSE
  2570. NEW(context, originator, oldCommand, NIL, arguments, NIL, NIL, NIL);
  2571. END;
  2572. BEGIN {EXCLUSIVE}
  2573. context.timestamp := timestamp;
  2574. INC(timestamp);
  2575. END;
  2576. ASSERT(context # NIL);
  2577. RETURN context;
  2578. END GenerateContext;
  2579. PROCEDURE HandleEvent*(CONST event : Event; originator : Component; command : Strings.String);
  2580. VAR
  2581. commandString : ARRAY 128 OF CHAR;
  2582. newCommand : Strings.String;
  2583. context : EventContext;
  2584. msg : Events.Message;
  2585. index : LONGINT;
  2586. BEGIN
  2587. ASSERT((originator # NIL) & (command # NIL));
  2588. index := 0;
  2589. IF Logging THEN
  2590. COPY(command^, msg);
  2591. Events.AddEvent("Components", Events.Information, 0, 0, 0, msg, FALSE);
  2592. END;
  2593. SubstituteMacros(command, newCommand, originator);
  2594. IF ReadWord(newCommand^, commandString, index) THEN
  2595. context := GenerateContext(command, newCommand, index, originator, event);
  2596. Commands.Activate(commandString, context, {}, context.result, msg); (* asynchronous call since holding the originators lock! *)
  2597. IF (context.result # Commands.Ok) THEN
  2598. Events.AddEvent("Components", Events.Error, 0, 0, 0, msg, FALSE);
  2599. END;
  2600. ELSE
  2601. Events.AddEvent("Components", Events.Error, 0, 0, 0, "Expected command", FALSE);
  2602. END;
  2603. END HandleEvent;
  2604. PROCEDURE ContainsMacros(CONST string : ARRAY OF CHAR) : BOOLEAN;
  2605. VAR result : BOOLEAN; length, i : LONGINT;
  2606. BEGIN
  2607. result := FALSE;
  2608. i := 0; length := LEN(string);
  2609. WHILE (i < length) & (string[i] # 0X) & ~result DO
  2610. IF (string[i] = MacroCharacter) THEN
  2611. result := (i + 1 < length) & (string[i+1] # MacroCharacter);
  2612. IF ~result THEN (* two consequent MacroCharacter's are used to escape *)
  2613. INC(i); (*skip string[i+1] *)
  2614. END;
  2615. END;
  2616. INC(i);
  2617. END;
  2618. RETURN result;
  2619. END ContainsMacros;
  2620. PROCEDURE WriteSelectionToStream(w : Streams.Writer);
  2621. VAR text : Texts.Text; from, to : Texts.TextPosition; a, b : LONGINT;
  2622. BEGIN
  2623. ASSERT(w # NIL);
  2624. IF Texts.GetLastSelection(text, from, to) THEN
  2625. text.AcquireRead;
  2626. a := MIN(from.GetPosition(), to.GetPosition());
  2627. b := MAX(from.GetPosition(), to.GetPosition());
  2628. IF (text.GetLength() > 0) THEN
  2629. TextUtilities.SubTextToStream(text, a, b - a + 1, w);
  2630. END;
  2631. text.ReleaseRead;
  2632. END;
  2633. END WriteSelectionToStream;
  2634. PROCEDURE SubstituteMacro(CONST command : Strings.String; VAR index : LONGINT; originator : Component; w : Streams.Writer);
  2635. VAR oldIndex : LONGINT; macro, namespace, name : Macro; handler : MacroHandlerProcedure; handled : BOOLEAN;
  2636. BEGIN
  2637. ASSERT((command # NIL) & (0 <= index) & (index < LEN(command)) & (command[index] = MacroCharacter));
  2638. ASSERT(originator # NIL);
  2639. ASSERT(w # NIL);
  2640. oldIndex := index;
  2641. INC(index); (* skip MacroCharacter *)
  2642. IF ReadWord(command^, macro, index) THEN (*? TBD error handling *)
  2643. SplitMacroString(macro, namespace, name, NamespaceCharacter);
  2644. IF (namespace = NoNamespace) OR (namespace = DefaultNamespace) THEN
  2645. handler := DefaultMacroHandler;
  2646. ELSE
  2647. BEGIN {EXCLUSIVE}
  2648. handler := FindMacroHandler(namespace);
  2649. END;
  2650. END;
  2651. handled := FALSE;
  2652. IF (handler # NIL) THEN handler(name, originator, w, handled); END;
  2653. IF ~handled THEN
  2654. w.Char(MacroCharacter); w.String(macro); (* don't substitute *)
  2655. END;
  2656. END;
  2657. ASSERT(index > oldIndex);
  2658. END SubstituteMacro;
  2659. PROCEDURE SubstituteMacros*(CONST command : Strings.String; VAR newCommand : Strings.String; originator : Component);
  2660. VAR index, oldIndex, length : LONGINT; w : Streams.Writer; buffer : Strings.Buffer;
  2661. BEGIN
  2662. ASSERT((command # NIL) & (originator # NIL));
  2663. IF ContainsMacros(command^) THEN
  2664. NEW(buffer, 256);
  2665. w := buffer.GetWriter();
  2666. index := 0; length := LEN(command^);
  2667. WHILE (index < length) & (command[index] # 0X) DO
  2668. oldIndex := index;
  2669. IF (command[index] = MacroCharacter) THEN
  2670. IF (index + 1 < length) & (command[index + 1] = MacroCharacter) THEN (* escape *)
  2671. w.Char(MacroCharacter);
  2672. index := index + 2; (* skip both MacroCharacter's *)
  2673. ELSE
  2674. (* substitute macro *)
  2675. SubstituteMacro(command, index, originator, w);
  2676. END;
  2677. ELSE
  2678. w.Char(command[index]);
  2679. INC(index);
  2680. END;
  2681. ASSERT(index > oldIndex);
  2682. END;
  2683. newCommand := buffer.GetString();
  2684. ELSE
  2685. newCommand := command;
  2686. END;
  2687. ASSERT(newCommand # NIL);
  2688. END SubstituteMacros;
  2689. PROCEDURE GetAttributeValue(originator : Component; CONST fullname : ARRAY OF CHAR) : Strings.String;
  2690. VAR value : Strings.String; c : Component; component, attribute : ARRAY 64 OF CHAR;
  2691. BEGIN
  2692. ASSERT(originator # NIL);
  2693. value := NIL;
  2694. Strings.GetExtension(fullname, component, attribute);
  2695. IF (attribute = "") THEN
  2696. COPY(component, attribute);
  2697. COPY("", component);
  2698. END;
  2699. IF (component[0] = "@") THEN component[0] := "&"; END; (*? TBD: Hack to avoid ampersand in XML *)
  2700. IF (component = "") THEN
  2701. c := originator;
  2702. ELSE
  2703. c := originator.Find(component);
  2704. END;
  2705. IF (c # NIL) THEN
  2706. IF c.HasAttribute(attribute) THEN
  2707. RETURN c.GetAttributeValue(attribute);
  2708. ELSE
  2709. ReportError("Attribute % of component % not found", attribute, component);
  2710. END;
  2711. ELSE
  2712. ReportError("Component % not found", component, "");
  2713. END;
  2714. RETURN value;
  2715. END GetAttributeValue;
  2716. PROCEDURE GetPropertyValue(originator : Component; CONST fullname : ARRAY OF CHAR) : Strings.String;
  2717. VAR value : ARRAY 256 OF CHAR; string:Strings.String; c : Component; component, property : ARRAY 64 OF CHAR;
  2718. BEGIN
  2719. ASSERT(originator # NIL);
  2720. Strings.GetExtension(fullname, component, property);
  2721. IF (property = "") THEN COPY(component, property); COPY("", component);
  2722. END;
  2723. IF (component[0] = "@") THEN component[0] := "&"; END; (*? TBD: Hack to avoid ampersand in XML *)
  2724. IF (component = "") THEN c := originator;
  2725. ELSE c := originator.Find(component);
  2726. END;
  2727. IF (c # NIL) THEN
  2728. IF c.properties.GetPropertyValue(property,value) THEN RETURN Strings.NewString(value)
  2729. ELSE ReportError("Property % of component % not found", property, component);
  2730. END;
  2731. ELSE ReportError("Component % not found", component, "");
  2732. END;
  2733. RETURN NIL;
  2734. END GetPropertyValue;
  2735. PROCEDURE DefaultMacroHandler(CONST macro : Macro; originator : Component; w : Streams.Writer; VAR handled : BOOLEAN);
  2736. VAR string, value : Strings.String;
  2737. BEGIN
  2738. ASSERT((originator # NIL) & (w # NIL));
  2739. handled := TRUE;
  2740. IF (macro = MacroSelection) THEN
  2741. WriteSelectionToStream(w);
  2742. ELSIF (macro = MacroClipboard) THEN
  2743. TextUtilities.TextToStream(Texts.clipboard, w);
  2744. ELSIF Strings.StartsWith(MacroAttributePrefix, 0, macro) THEN
  2745. string := Strings.Substring(Strings.Length(MacroAttributePrefix), Strings.Length(macro), macro);
  2746. value := GetAttributeValue(originator, string^);
  2747. IF (value # NIL) THEN
  2748. w.String(value^);
  2749. ELSE
  2750. handled := FALSE;
  2751. END;
  2752. ELSIF Strings.StartsWith(MacroPropertyPrefix, 0, macro) THEN
  2753. string := Strings.Substring(Strings.Length(MacroPropertyPrefix), Strings.Length(macro), macro);
  2754. value := GetPropertyValue(originator,string^);
  2755. IF (value # NIL) THEN
  2756. w.String(value^);
  2757. ELSE
  2758. handled := FALSE;
  2759. END;
  2760. ELSE
  2761. handled := FALSE;
  2762. END;
  2763. END DefaultMacroHandler;
  2764. PROCEDURE FindMacroHandler(CONST namespace : ARRAY OF CHAR) : MacroHandlerProcedure;
  2765. VAR node : MacroHandler; handler : MacroHandlerProcedure;
  2766. BEGIN (* caller must hold module lock! *)
  2767. node := macroHandlers;
  2768. WHILE (node # NIL) & (node.namespace # namespace) DO node := node.next; END;
  2769. IF (node # NIL) THEN
  2770. handler := node.handler;
  2771. ELSE
  2772. handler := NIL;
  2773. END;
  2774. RETURN handler;
  2775. END FindMacroHandler;
  2776. PROCEDURE AddMacroHandler*(CONST namespace : Namespace; handler : MacroHandlerProcedure; VAR res : WORD);
  2777. VAR new, node : MacroHandler; h : MacroHandlerProcedure;
  2778. BEGIN {EXCLUSIVE}
  2779. ASSERT((namespace # NoNamespace) & (handler # NIL));
  2780. ASSERT(macroHandlers # NIL);
  2781. h := FindMacroHandler(namespace);
  2782. IF (h = NIL) THEN (* append new handler to list *)
  2783. NEW(new);
  2784. new.handler := handler;
  2785. new.namespace := namespace;
  2786. new.next := NIL;
  2787. node := macroHandlers;
  2788. WHILE (node.next # NIL) DO node := node.next; END;
  2789. node.next := new;
  2790. res := Ok;
  2791. ELSE
  2792. res := DuplicateNamespace;
  2793. END;
  2794. END AddMacroHandler;
  2795. PROCEDURE RemoveMacroHandler*(handler : MacroHandlerProcedure);
  2796. VAR node : MacroHandler;
  2797. BEGIN {EXCLUSIVE}
  2798. ASSERT((handler # NIL) & (handler # DefaultMacroHandler));
  2799. ASSERT(macroHandlers # NIL);
  2800. node := macroHandlers;
  2801. WHILE (node.next # NIL) & (node.next.handler # handler) DO node := node.next; END;
  2802. ASSERT((node.next # NIL) & (node.next.handler = handler));
  2803. node.next := node.next.next;
  2804. END RemoveMacroHandler;
  2805. PROCEDURE SetAttribute*(context : Commands.Context); (** component attribute value ~ *)
  2806. VAR originator, target : Component; name, attribute, value : ARRAY 128 OF CHAR; (*? TBD array size *)
  2807. BEGIN
  2808. IF (context IS EventContext) THEN
  2809. originator := context(EventContext).originator;
  2810. IF context.arg.GetString(name) & context.arg.GetString(attribute) & context.arg.GetString(value) THEN
  2811. target := originator.Find(name);
  2812. IF (target # NIL) THEN
  2813. IF target.HasAttribute(attribute) THEN
  2814. target.SetAttributeValue(attribute, value);
  2815. ELSE
  2816. context.result := Commands.CommandError;
  2817. END;
  2818. ELSE
  2819. context.result := Commands.CommandError;
  2820. END;
  2821. ELSE
  2822. context.error.String("Expected component name, attribute and value parameters"); context.error.Ln;
  2823. context.result := Commands.CommandParseError;
  2824. END;
  2825. ELSE
  2826. context.error.String("Command requires EventContext."); context.error.Ln;
  2827. context.result := Commands.CommandParseError;
  2828. END;
  2829. END SetAttribute;
  2830. (** Activate a string of commands, including their parameters.
  2831. The string is parsed from left to right and Activate is called for every command.
  2832. Parsing stops at the end of the string, or when Activate returns an error.
  2833. The flags are applied to every command, i.e., for sequential execution,
  2834. use the Wait flag (the caller waits until all commands return).
  2835. Syntax:
  2836. cmds = [mode " " ] cmd {";" cmd} .
  2837. mode = "PAR" | "SEQ" .
  2838. cmd = mod ["." proc] [" " params] .
  2839. params = {<any character except ";">} .
  2840. REMARK: For now, this is almost the same as Commands.Call. This procedure will either be enhanced to
  2841. support some component-related macro substitution or be replaced by Commands.Call
  2842. *)
  2843. PROCEDURE Call*(cmds : ARRAY OF CHAR; caller : Component; flags : SET; VAR res : WORD; VAR msg : ARRAY OF CHAR);
  2844. VAR
  2845. context : Commands.Context; arg : Streams.StringReader;
  2846. buffer : Strings.Buffer; w : Streams.Writer; par : Strings.String;
  2847. length, i, k : LONGINT;
  2848. PROCEDURE Expand(CONST string : ARRAY OF CHAR; w : Streams.Writer; start : LONGINT; VAR end : LONGINT);
  2849. VAR
  2850. component : Component;
  2851. componentStr, attributeStr : ARRAY 256 OF CHAR;
  2852. property : WMProperties.Property; attribute : XML.Attribute;
  2853. value : Strings.String;
  2854. lastDotIdx, i, j : LONGINT; error : BOOLEAN;
  2855. BEGIN
  2856. ASSERT((string[start] = "&") & (start + 1 < LEN(string)) & (w # NIL));
  2857. end := start; WHILE (end < LEN(string)) & (string[end] # 0X) & (string[end] # ";") & (string[end] > " ") DO INC(end); END;
  2858. DEC(end);
  2859. lastDotIdx := end;
  2860. WHILE (lastDotIdx > start) & (string[lastDotIdx] # ".") DO DEC(lastDotIdx); END;
  2861. error := (lastDotIdx <= start); (* missing dot *)
  2862. IF ~error THEN
  2863. i := start + 1; (* skip ampersand *)
  2864. IF (string[i] = "&") OR (string[i] = "/") THEN
  2865. j := 0;
  2866. WHILE (i < lastDotIdx) & (j < LEN(componentStr) - 1) DO
  2867. componentStr[j] := string[i];
  2868. INC(i); INC(j);
  2869. END;
  2870. componentStr[j] := 0X;
  2871. component := caller.Find(componentStr);
  2872. ELSE
  2873. componentStr := "";
  2874. component := caller;
  2875. END;
  2876. ASSERT(string[i] = ".");
  2877. INC(i); (* skip dot *)
  2878. attributeStr := "";
  2879. j := 0;
  2880. WHILE (j < LEN(attributeStr)) & (i <= end) DO
  2881. attributeStr[j] := string[i];
  2882. INC(i); INC(j);
  2883. END;
  2884. error := (attributeStr = "");
  2885. IF ~error THEN
  2886. IF (component # NIL) THEN
  2887. property := component.properties.Get(attributeStr);
  2888. IF (property # NIL) THEN
  2889. property.ToStream(w);
  2890. ELSE
  2891. attribute := component.GetAttribute(attributeStr);
  2892. IF (attribute # NIL) THEN
  2893. value := attribute.GetValue();
  2894. IF (value # NIL) THEN w.String(value^); ELSE w.String("NIL"); END;
  2895. ELSE
  2896. error := TRUE;
  2897. END;
  2898. END;
  2899. ELSE
  2900. error := TRUE;
  2901. END;
  2902. END;
  2903. END;
  2904. IF error THEN (* don't expand macro *)
  2905. FOR i := start TO end DO w.Char(string[i]); END;
  2906. END;
  2907. ASSERT(end >= start);
  2908. END Expand;
  2909. BEGIN
  2910. ASSERT(caller # NIL);
  2911. NEW(buffer, LEN(cmds)); w := buffer.GetWriter();
  2912. IF Strings.StartsWith2(Repositories.CommandPrefix, cmds) THEN i := Strings.Length(Repositories.CommandPrefix); ELSE i := 0; END;
  2913. LOOP
  2914. buffer.Clear;
  2915. w.Reset;
  2916. k := 0;
  2917. WHILE (i < LEN(cmds)) & (cmds[i] # " ") & (cmds[i] # 09X) & (cmds[i] # 0DX) & (cmds[i] # 0AX) & (cmds[i] # 0X) & (cmds[i] # ";") DO cmds[k] := cmds[i]; INC(k); INC(i); END;
  2918. IF k = 0 THEN EXIT; END; (* end of string *)
  2919. IF (i < LEN(cmds)) & (cmds[i] # ";") & (cmds[i] # 0X) THEN (* parameters *)
  2920. INC(i); (* skip delimiter *)
  2921. WHILE (i < LEN(cmds)) & (cmds[i] # 0X) & (cmds[i] # ";") DO
  2922. IF (cmds[i] = "&") & (i + 1 < LEN(cmds)) & ((cmds[i+1] = "&") OR (cmds[i+1] = ".") OR (cmds[i+1] = "/")) THEN
  2923. Expand(cmds, w, i, i);
  2924. ELSE
  2925. w.Char(cmds[i]);
  2926. END;
  2927. INC(i);
  2928. END;
  2929. END;
  2930. IF (i < LEN(cmds)) & (cmds[i] = ";") THEN (* skip command delimiter *) INC(i); END;
  2931. cmds[k] := 0X;
  2932. length := buffer.GetLength();
  2933. IF (length > 0) THEN
  2934. par := buffer.GetString();
  2935. NEW(arg, length + 1); arg.SetRaw(par^, 0, length + 1);
  2936. ELSE
  2937. arg := NIL;
  2938. END;
  2939. NEW(context, NIL, arg, NIL, NIL, caller);
  2940. Commands.Activate(cmds, context, flags, res, msg);
  2941. IF (res # Commands.Ok) THEN KernelLog.String("WMComponents.Call error, res = "); KernelLog.Int(res, 0); KernelLog.Ln; EXIT; END;
  2942. END;
  2943. END Call;
  2944. PROCEDURE GetComponent*(CONST name : ARRAY OF CHAR) : Component;
  2945. VAR component : Component; c : Repositories.Component; res : WORD;
  2946. BEGIN
  2947. component := NIL;
  2948. Repositories.GetComponentByString(name, c, res);
  2949. IF (res = Repositories.Ok) THEN
  2950. IF (c # NIL) & (c IS Component) THEN
  2951. component := c (Component);
  2952. ELSE
  2953. KernelLog.String("WMComponents.GetComponent: Could not generate component ");
  2954. KernelLog.String(name); KernelLog.String(": Wrong type"); KernelLog.Ln;
  2955. END;
  2956. ELSE
  2957. KernelLog.String("WMComponents.GetComponent: Could not generate component ");
  2958. KernelLog.String(name); KernelLog.String(", res: "); KernelLog.Int(res, 0); KernelLog.Ln;
  2959. END;
  2960. RETURN component;
  2961. END GetComponent;
  2962. PROCEDURE GetVisualComponent*(CONST name : ARRAY OF CHAR) : VisualComponent;
  2963. VAR component : VisualComponent; c : Repositories.Component; res : WORD;
  2964. BEGIN
  2965. component := NIL;
  2966. Repositories.GetComponentByString(name, c, res);
  2967. IF (res = Repositories.Ok) THEN
  2968. IF (c # NIL) & (c IS VisualComponent) THEN
  2969. component := c (VisualComponent);
  2970. ELSE
  2971. KernelLog.String("WMComponents.GetVisualComponent: Could not generate component ");
  2972. KernelLog.String(name); KernelLog.String(": Wrong type"); KernelLog.Ln;
  2973. END;
  2974. ELSE
  2975. KernelLog.String("WMComponents.GetVisualComponent: Could not generate component ");
  2976. KernelLog.String(name); KernelLog.String(", res: "); KernelLog.Int(res, 0); KernelLog.Ln;
  2977. END;
  2978. RETURN component;
  2979. END GetVisualComponent;
  2980. PROCEDURE SetStyle*(style : XML.Element);
  2981. BEGIN
  2982. SetStyleInternal(style)
  2983. END SetStyle;
  2984. PROCEDURE SetStyleInternal(style : XML.Element);
  2985. VAR msg : Messages.Message; m : WM.WindowManager;
  2986. BEGIN
  2987. currentStyle := style;
  2988. IF propertyListList # NIL THEN propertyListList.UpdateStyle END;
  2989. msg.msgType := Messages.MsgExt; msg.ext := componentStyleMsg;
  2990. m := WM.GetDefaultManager();
  2991. m.Broadcast(msg)
  2992. END SetStyleInternal;
  2993. PROCEDURE FindRelativePath(x : Component; CONST path : ARRAY OF CHAR; pos : LONGINT) : Component;
  2994. VAR c : XML.Content;
  2995. sn : ARRAY MaxComponentNameSize OF CHAR;
  2996. i : LONGINT; id : Strings.String;
  2997. BEGIN
  2998. IF x = NIL THEN RETURN NIL
  2999. ELSIF path[pos] = 0X THEN RETURN x
  3000. ELSIF (pos = 0) & (path[0] = "/") THEN RETURN FindRelativePath(x.GetComponentRoot(), path, pos + 1)
  3001. ELSIF (path[pos] = ".") & (path[pos + 1] = ".") THEN
  3002. INC(pos, 2); IF path[pos]="/" THEN INC(pos) END;
  3003. c := x.GetParent();
  3004. IF (c # NIL) & (c IS Component) THEN
  3005. RETURN FindRelativePath(c(Component), path, pos)
  3006. ELSE
  3007. RETURN NIL
  3008. END
  3009. ELSE
  3010. i := 0; WHILE (i < MaxComponentNameSize - 1) & (path[pos] # 0X) & (path[pos] # "/") DO
  3011. sn[i] := path[pos]; INC(i); INC(pos)
  3012. END;
  3013. IF (path[pos] = "/") THEN INC(pos) END;
  3014. sn[i] := 0X;
  3015. c := x.GetFirst();
  3016. WHILE (c # NIL) DO
  3017. IF (c IS Component) THEN
  3018. id := c(Component).id.Get();
  3019. IF (id # NIL) & (id^ = sn) THEN
  3020. RETURN FindRelativePath(c(Component), path, pos);
  3021. END;
  3022. END;
  3023. c := x.GetNext(c);
  3024. END;
  3025. RETURN NIL
  3026. END
  3027. END FindRelativePath;
  3028. (* Report errors while parsing *)
  3029. PROCEDURE Error(pos, line, row: LONGINT; CONST msg: ARRAY OF CHAR);
  3030. BEGIN
  3031. KernelLog.String("Parse error at pos "); KernelLog.Int(pos, 5); KernelLog.String(" in line "); KernelLog.Int(line, 5);
  3032. KernelLog.String(" row "); KernelLog.Int(row, 5); KernelLog.String(" - "); KernelLog.String(msg); KernelLog.Ln;
  3033. hasErrors := TRUE
  3034. END Error;
  3035. (** Load an XML file. Return NIL if errors occured *)
  3036. PROCEDURE Load*(CONST filename : ARRAY OF CHAR) : XML.Content;
  3037. VAR scanner : XMLScanner.Scanner;
  3038. parser : XMLParser.Parser;
  3039. doc : XML.Document;
  3040. in : Streams.Reader;
  3041. BEGIN {EXCLUSIVE}
  3042. hasErrors := FALSE;
  3043. in := Codecs.OpenInputStream(filename);
  3044. IF in # NIL THEN
  3045. NEW(scanner, in); scanner.reportError := Error;
  3046. NEW(parser, scanner); parser.reportError := Error;
  3047. parser.elemReg := Repositories.registry; doc := parser.Parse();
  3048. IF hasErrors THEN RETURN NIL END;
  3049. RETURN doc.GetRoot()
  3050. END;
  3051. RETURN NIL
  3052. END Load;
  3053. PROCEDURE FormWindowGen*(xml:XML.Content): WM.Window;
  3054. VAR winx: XML.Element; formx: XML.Content; window: FormWindow; name, string:Strings.String; canvas:WMGraphics.BufferCanvas;
  3055. canvasGenerator: WMGraphics.CanvasGenerator;
  3056. moduleName, procedureName : Modules.Name;
  3057. msg : ARRAY 128 OF CHAR;
  3058. res: WORD;
  3059. l,t,r,b: LONGINT;
  3060. BEGIN
  3061. IF xml IS XML.Element THEN
  3062. winx:=xml(XML.Element);
  3063. string:=winx.GetName();
  3064. IF string^="FormWindow" THEN
  3065. string:=winx.GetAttributeValue("l"); Strings.StrToInt(string^,l);
  3066. string:=winx.GetAttributeValue("t"); Strings.StrToInt(string^,t);
  3067. string:=winx.GetAttributeValue("r"); Strings.StrToInt(string^,r);
  3068. string:=winx.GetAttributeValue("b"); Strings.StrToInt(string^,b);
  3069. NEW(window, r-l, b-t, TRUE);
  3070. name:=winx.GetAttributeValue("name"); window.SetTitle(name);
  3071. window.bounds.r:=r; window.bounds.l:=l; window.bounds.t:=t; window.bounds.b:=b;
  3072. string:=winx.GetAttributeValue("flags"); Strings.StrToSet(string^,window.flags);
  3073. string:=winx.GetAttributeValue("canvasGenerator"); (* allow to plug in alternative canvas versions,e.g. WMGraphicsGfx.Canvas *)
  3074. IF (string#NIL) THEN
  3075. Commands.Split(string^, moduleName, procedureName, res, msg);
  3076. IF (res = Commands.Ok) THEN
  3077. GETPROCEDURE(moduleName, procedureName, canvasGenerator);
  3078. IF (canvasGenerator # NIL) THEN
  3079. window.SetCanvasGenerator(canvasGenerator);
  3080. END;
  3081. END;
  3082. END;
  3083. formx:=winx.GetFirst(); (* this typically has name="Form" *)
  3084. IF (formx#NIL)&(formx IS XML.Element) THEN
  3085. window.LoadComponents(formx(XML.Element)); (* at the price of duplication of component tree construction ...*)
  3086. window.form.Reset(NIL,NIL);
  3087. ELSE window:=NIL;
  3088. END;
  3089. END;
  3090. END;
  3091. RETURN window
  3092. END FormWindowGen;
  3093. (* generic loading of any form window using the generator procedure supplied in the XML as 'loader' attribute *)
  3094. PROCEDURE LoadFormWindow*(xml:XML.Content): WM.Window;
  3095. VAR winx: XML.Element; window: WM.Window; formWindow:FormWindow;
  3096. formx, c:Component;
  3097. name, string, load:Strings.String;
  3098. moduleName, procedureName : Modules.Name;
  3099. msg : ARRAY 128 OF CHAR;
  3100. res: WORD;
  3101. gen:WindowGenerator;
  3102. bounds:Rectangles.Rectangle;
  3103. BEGIN
  3104. IF xml IS XML.Element THEN
  3105. winx:=xml(XML.Element);
  3106. name:=winx.GetName();
  3107. IF name^="FormWindow" THEN
  3108. string:=winx.GetAttributeValue("loader");
  3109. Commands.Split(string^, moduleName, procedureName, res, msg);
  3110. IF (res = Commands.Ok) THEN
  3111. GETPROCEDURE(moduleName, procedureName, gen);
  3112. IF (gen # NIL) THEN
  3113. window:=gen(xml);
  3114. END;
  3115. END;
  3116. ELSE (*generate FormWindow from generic Visual Component*)
  3117. c:=ComponentFromXML(xml(XML.Element));
  3118. IF (c#NIL) & (c IS VisualComponent) THEN
  3119. bounds:=c(VisualComponent).bounds.Get();
  3120. NEW(formWindow, bounds.r-bounds.l, bounds.b-bounds.t, TRUE);
  3121. formWindow.SetContent(c);
  3122. (*formWindow.SetTitle(c.GetName());*)
  3123. window:=formWindow;
  3124. END;
  3125. END;
  3126. END;
  3127. RETURN window
  3128. END LoadFormWindow;
  3129. (** Open form window and build its component tree *)
  3130. PROCEDURE Open*(context : Commands.Context);
  3131. VAR filename: Files.FileName; window: WM.Window; xml:XML.Content;
  3132. BEGIN
  3133. IF context.arg.GetString(filename) & (Strings.Length(filename)>0) THEN
  3134. xml:=Load(filename); (* here, the xml tree is already constructed, however not in the right sequence for component contruction ( [Init()..loadProperties()..Initialize()] )*)
  3135. window:=LoadFormWindow(xml);
  3136. IF window#NIL THEN
  3137. WM.AddWindow(window,window.bounds.l,window.bounds.t);
  3138. END;
  3139. END;
  3140. END Open;
  3141. PROCEDURE LoadStyleInternal(CONST filename : ARRAY OF CHAR);
  3142. VAR f : Files.File;
  3143. scanner : XMLScanner.Scanner;
  3144. parser : XMLParser.Parser;
  3145. reader : Files.Reader;
  3146. doc : XML.Document;
  3147. BEGIN
  3148. hasErrors := FALSE;
  3149. f := Files.Old(filename);
  3150. IF f # NIL THEN
  3151. NEW(reader, f, 0);
  3152. NEW(scanner, reader); scanner.reportError := Error;
  3153. NEW(parser, scanner); parser.reportError := Error;
  3154. parser.elemReg := Repositories.registry; doc := parser.Parse();
  3155. IF hasErrors THEN KernelLog.String("Stylefile not ok"); KernelLog.Ln
  3156. ELSE
  3157. SetStyleInternal(doc.GetRoot())
  3158. END
  3159. END
  3160. END LoadStyleInternal;
  3161. (** Load Component registry file. Return NIL if errors occured *)
  3162. PROCEDURE LoadStyle*(context : Commands.Context);
  3163. VAR filename : ARRAY 64 OF CHAR;
  3164. BEGIN {EXCLUSIVE}
  3165. IF context.arg.GetString(filename) THEN
  3166. LoadStyleInternal(filename);
  3167. ELSE
  3168. context.result := Commands.CommandParseError;
  3169. END;
  3170. END LoadStyle;
  3171. PROCEDURE NewString*(CONST x : ARRAY OF CHAR) : Strings.String;
  3172. VAR t : Strings.String;
  3173. BEGIN
  3174. NEW(t, LEN(x)); COPY(x, t^); RETURN t
  3175. END NewString;
  3176. PROCEDURE InitStrings;
  3177. BEGIN
  3178. StrComponent := NewString("Component");
  3179. StrVisualComponent := NewString("VisualComponent");
  3180. StrForm := NewString("Form");
  3181. StrFormWindow := NewString("FormWindow");
  3182. GSonStartDrag := NewString("onStartDrag");
  3183. GSonStartDragInfo := NewString("Event generated whenever a drag is started");
  3184. StrModel := NewString("Model");
  3185. StrModelInfo := NewString("Model used by component");
  3186. END InitStrings;
  3187. PROCEDURE InitPrototypes;
  3188. BEGIN
  3189. (* General component properties *)
  3190. NEW(PrototypeID, NIL, NewString("ID"),
  3191. NewString("identifier of the component"));
  3192. NEW(PrototypeUID, NIL, NewString("UID"),
  3193. NewString("unique identifier of the component"));
  3194. NEW(PrototypeEnabled, NIL, NewString("Enabled"),
  3195. NewString("defines if the component is enabled"));
  3196. PrototypeEnabled.Set(TRUE);
  3197. (* Visual component properties *)
  3198. NEW(PrototypeBounds, NIL, NewString("Bounds"),
  3199. NewString("the bounding box of the component in parent coordinates"));
  3200. NEW(PrototypeBoundsRelative, NIL, NewString("RelBounds"),
  3201. NewString("the bounding box of the component in relative parent coordinates"));
  3202. NEW(PrototypeBearing, NIL, NewString("Bearing"),
  3203. NewString("the bearing (empty space) aroung the component if auto aligned"));
  3204. NEW(PrototypeFillColor, NIL, NewString("FillColor"),
  3205. NewString("the main fill color of the component. i.e. background"));
  3206. NEW(PrototypeAlignment, NIL, NewString("Alignment"),
  3207. NewString("defines the alignment none, left, right, top, bottom or client"));
  3208. PrototypeAlignment.Set(0);
  3209. NEW(PrototypeVisible, NIL, NewString("Visible"),
  3210. NewString("defines if the component is visible"));
  3211. PrototypeVisible.Set(TRUE);
  3212. NEW(PrototypeTakesFocus, NIL, NewString("TakesFocus"),
  3213. NewString("defines if the component takes the keyboard focus"));
  3214. NEW(PrototypeNeedsTab, NIL, NewString("NeedsTab"),
  3215. NewString("defines if the component handles the tabulator key"));
  3216. NEW(PrototypeFocusPrevious, NIL, NewString("FocusPrevious"), NewString("Previous focus component ID"));
  3217. PrototypeFocusPrevious.Set(NIL);
  3218. NEW(PrototypeFocusNext, NIL, NewString("FocusNext"), NewString("Next focus component ID"));
  3219. PrototypeFocusNext.Set(NIL);
  3220. NEW(PrototypeEditMode, NIL, NewString("EditMode"), NewString("defines if the contents of the component can be edited"));
  3221. PrototypeEditMode.Set(FALSE);
  3222. NEW(PrototypeFont, NIL, NewString("Font"), NewString("Font"));
  3223. PrototypeFont.Set(WMGraphics.GetDefaultFont());
  3224. NEW(PrototypeScaleFont, NIL, Strings.NewString("ScaleFont"), Strings.NewString("percentage that fonts scales with height (0=none)"));
  3225. NEW(ModelPrototype, NIL, StrModel, StrModelInfo);
  3226. END InitPrototypes;
  3227. PROCEDURE ShowComponent(component : Component);
  3228. VAR string : Strings.String;
  3229. BEGIN
  3230. IF (component # NIL) THEN
  3231. string := component.GetName();
  3232. IF (string # NIL) THEN KernelLog.String(string^); ELSE KernelLog.String("NoName"); END;
  3233. KernelLog.String(" [");
  3234. string := component.uid.Get();
  3235. IF (string # NIL) THEN KernelLog.String(string^); ELSE KernelLog.String("NIL"); END;
  3236. IF (component IS VisualComponent) THEN
  3237. KernelLog.String(", "); KernelLog.Boolean(component(VisualComponent).takesFocus.Get());
  3238. END;
  3239. KernelLog.String("]");
  3240. ELSE
  3241. KernelLog.String("NIL?");
  3242. END;
  3243. END ShowComponent;
  3244. PROCEDURE NewLine(w : Streams.Writer; level : LONGINT);
  3245. BEGIN
  3246. w.Ln; WHILE level > 0 DO w.Char(09X); DEC(level) END
  3247. END NewLine;
  3248. PROCEDURE InstallDefaultMacroHandler;
  3249. BEGIN
  3250. NEW(macroHandlers);
  3251. macroHandlers.handler := DefaultMacroHandler;
  3252. macroHandlers.namespace := DefaultNamespace;
  3253. macroHandlers.next := NIL;
  3254. END InstallDefaultMacroHandler;
  3255. (*! ---- xml tool --- move to where appropriate *)
  3256. PROCEDURE GetElementByName(parent : XML.Element; CONST name : ARRAY OF CHAR) : XML.Element;
  3257. VAR elem : XML.Element; enum : XMLObjects.Enumerator; ptr : ANY; string : Strings.String;
  3258. BEGIN
  3259. IF parent # NIL THEN
  3260. enum := parent.GetContents(); enum.Reset();
  3261. WHILE enum.HasMoreElements() DO
  3262. ptr := enum.GetNext();
  3263. IF ptr IS XML.Element THEN
  3264. elem := ptr (XML.Element);
  3265. string := elem.GetName();
  3266. IF (string # NIL) & (string^ = name) THEN
  3267. RETURN elem;
  3268. END;
  3269. END;
  3270. END;
  3271. END;
  3272. RETURN NIL;
  3273. END GetElementByName;
  3274. PROCEDURE NewComponent*(): XML.Element;
  3275. VAR component: Component;
  3276. BEGIN NEW(component); RETURN component;
  3277. END NewComponent;
  3278. PROCEDURE NewVisualComponent*(): XML.Element;
  3279. VAR component: VisualComponent;
  3280. BEGIN NEW(component); RETURN component;
  3281. END NewVisualComponent;
  3282. (* does not work like this its own because a form is statically bound to a window, but for completeness.. *)
  3283. PROCEDURE NewForm*(): XML.Element;
  3284. VAR component: Form;
  3285. BEGIN NEW(component, NIL); RETURN component
  3286. END NewForm;
  3287. PROCEDURE Align*(context: Commands.Context);
  3288. VAR width,height,bwidth,bheight: LONGINT; entry: ComponentListEntry; b,rect: Rectangles.Rectangle; string: ARRAY 32 OF CHAR; l,t: LONGINT; done: BOOLEAN;
  3289. BEGIN
  3290. entry := selection.first;
  3291. rect.l := MAX(LONGINT); rect.r := MIN(LONGINT);
  3292. rect.t := MAX(LONGINT); rect.b := MIN(LONGINT);
  3293. width := 0; height := 0;
  3294. WHILE entry # NIL DO
  3295. b := entry.component.bounds.Get();
  3296. bwidth := b.r-b.l; bheight := b.b-b.t;
  3297. IF b.l < rect.l THEN rect.l := b.l END;
  3298. IF b.r > rect.r THEN rect.r := b.r END;
  3299. IF b.t < rect.t THEN rect.t := b.t END;
  3300. IF b.b > rect.b THEN rect.b := b.b END;
  3301. IF width < bwidth THEN width := bwidth END;
  3302. IF height < bheight THEN height := bheight END;
  3303. entry := entry.next
  3304. END;
  3305. done := FALSE;
  3306. WHILE ~done & context.arg.GetString(string) DO
  3307. l := rect.l; t := rect.t;
  3308. entry := selection.first;
  3309. WHILE ~done & (entry # NIL) DO
  3310. b := entry.component.bounds.Get(); bwidth := b.r-b.l; bheight := b.b-b.t;
  3311. entry.component.AdaptRelativeBounds(b,entry.component.GetParent());
  3312. IF string = "left" THEN b.l := rect.l; b.r := rect.l + bwidth;
  3313. ELSIF string = "right" THEN b.r := rect.r; b.l := rect.r-bwidth
  3314. ELSIF string = "top" THEN b.t := rect.t; b.b := rect.t + bheight;
  3315. ELSIF string = "bottom" THEN b.b := rect.b; b.t := rect.b-bheight
  3316. ELSIF string = "width" THEN b.r := b.l + width;
  3317. ELSIF string = "height" THEN b.b := b.t + height;
  3318. ELSIF string = "size" THEN b.r := b.l + width; b.b := b.t + height;
  3319. ELSIF string = "hcenter" THEN b.l := (rect.l+rect.r) DIV 2 - bwidth DIV 2; b.r := b.l + bwidth;
  3320. ELSIF string = "vcenter" THEN b.t := (rect.t + rect.b) DIV 2 - bheight DIV 2; b.b := b.t + bheight;
  3321. ELSIF string = "horizontal" THEN b.l := l; b.r := b.l + bwidth; l := b.r+1
  3322. ELSIF string = "vertical" THEN b.t := t; b.b := b.t + bheight; t := b.b + 1;
  3323. ELSIF string = "none" THEN entry.component.alignment.Set(AlignNone)
  3324. ELSIF string = "relative" THEN entry.component.alignment.Set(AlignRelative)
  3325. ELSE done := TRUE
  3326. END;
  3327. entry.component.AdaptRelativeBounds(b,entry.component.GetParent());
  3328. entry.component.bounds.Set(b);
  3329. entry := entry.next
  3330. END;
  3331. END;
  3332. END Align;
  3333. PROCEDURE SetProperty*(context: Commands.Context);
  3334. VAR name, value: ARRAY 256 OF CHAR; entry: ComponentListEntry;
  3335. BEGIN
  3336. IF context.arg.GetString(name) & context.arg.GetString(value) THEN
  3337. entry := selection.first;
  3338. WHILE entry # NIL DO
  3339. IF entry.component.properties.SetPropertyValue(name, value) THEN END;
  3340. entry := entry.next;
  3341. END;
  3342. END;
  3343. END SetProperty;
  3344. PROCEDURE RemoveSelection*;
  3345. VAR entry: ComponentListEntry; parent: XML.Element;
  3346. BEGIN
  3347. entry := selection.first;
  3348. WHILE entry # NIL DO
  3349. parent := entry.component.GetParent();
  3350. IF parent # NIL THEN parent(VisualComponent).RemoveContent(entry.component); parent(VisualComponent).Invalidate END;
  3351. entry := entry.next
  3352. END;
  3353. END RemoveSelection;
  3354. PROCEDURE ComponentFromXML*(xml: XML.Element): Component;
  3355. VAR generator: PROCEDURE(): XML.Element;
  3356. VAR
  3357. l,name: Strings.String;
  3358. moduleName, procedureName: Modules.Name;
  3359. res: WORD; msg: ARRAY 32 OF CHAR;
  3360. component: Component;
  3361. element: XML.Element;
  3362. BEGIN
  3363. component := NIL;
  3364. IF xml # NIL THEN
  3365. name := xml.GetName();
  3366. l := xml.GetAttributeValue("generator");
  3367. IF l # NIL THEN
  3368. Commands.Split(l^, moduleName, procedureName, res, msg);
  3369. IF (res = Commands.Ok) THEN
  3370. GETPROCEDURE(moduleName, procedureName, generator);
  3371. IF (generator # NIL) THEN
  3372. element := generator();
  3373. IF (element # NIL) & (element IS Component) THEN
  3374. component := element(Component);
  3375. component.SetName(name^);
  3376. component.FromXML(xml);
  3377. END;
  3378. ELSE KernelLog.String("WMComponents error: invalid generator "); KernelLog.String(l^); KernelLog.Ln;
  3379. END;
  3380. ELSE KernelLog.String("WMComponents error: could not generate component "); KernelLog.String(l^); KernelLog.Ln;
  3381. END;
  3382. END;
  3383. END;
  3384. RETURN component
  3385. END ComponentFromXML;
  3386. PROCEDURE Clone*(x: Component): Repositories.Component;
  3387. BEGIN
  3388. RETURN ComponentFromXML(x)
  3389. END Clone;
  3390. BEGIN
  3391. timestamp := 0;
  3392. NEW(componentStyleMsg);
  3393. NEW(propertyListList);
  3394. InitStrings;
  3395. InitPrototypes;
  3396. NEW(invalidateRectMsg);
  3397. InstallDefaultMacroHandler;
  3398. NEW(selection);
  3399. END WMComponents.
  3400. WMComponents.Open FigureExample.Cwd ~
  3401. WMComponents.Open DictEntry.wm ~
  3402. The message sequencer contains a reader writer lock that can be used to block the hierarchy.
  3403. Each message-call from the sequencer posesses the writer lock.
  3404. WMComponents.LoadStyle ComponentStyle.XML ~
  3405. If a focusComponent is set in an non-focus container-component, the focus can not escape the "isolated" component group