XMLComponents.Mod 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138
  1. MODULE XMLComponents; (** Stefan Walthert *)
  2. (** AUTHOR "swalthert"; PURPOSE ""; *)
  3. IMPORT
  4. Files, DynamicStrings, XMLObjects, XML, CSS2, CSS2Properties, CSS2Scanner, CSS2Parser,
  5. WMWindowManager, Gfx;
  6. TYPE
  7. String* = XML.String;
  8. (* Message* = OBJECT END Message;*)
  9. StateMessage* = OBJECT (*Message*)
  10. VAR state-: BOOLEAN;
  11. PROCEDURE & InitStateMessage*(state: BOOLEAN);
  12. BEGIN
  13. SELF.state := state
  14. END InitStateMessage;
  15. END StateMessage;
  16. ValueMessage* = OBJECT (*Message*)
  17. VAR value*: LONGINT;
  18. END ValueMessage;
  19. MouseMessage* = OBJECT (*Message*)
  20. VAR
  21. x*, y*: LONGINT;
  22. keys*: SET
  23. END MouseMessage;
  24. KeyMessage* = OBJECT (*Message*)
  25. VAR
  26. ch*: CHAR;
  27. keySym*: LONGINT;
  28. flags*: SET
  29. END KeyMessage;
  30. Listener* = PROCEDURE {DELEGATE} (sender, data: ANY);
  31. VAR
  32. Unassigned: Listener;
  33. TYPE
  34. ListenerEntry = OBJECT
  35. VAR
  36. listener: Listener
  37. END ListenerEntry;
  38. EventDispatcher* = OBJECT
  39. VAR
  40. listeners: XMLObjects.Collection;
  41. sender: ANY;
  42. PROCEDURE & Init*(sender: ANY);
  43. VAR arrColl: XMLObjects.ArrayCollection;
  44. BEGIN
  45. NEW(arrColl); listeners := arrColl;
  46. SELF.sender := sender
  47. END Init;
  48. PROCEDURE AddListener*(listener: Listener);
  49. VAR entry: ListenerEntry;
  50. BEGIN
  51. NEW(entry);
  52. entry.listener := listener;
  53. listeners.Add(entry)
  54. END AddListener;
  55. PROCEDURE Dispatch*(data: ANY);
  56. VAR entries: XMLObjects.Enumerator; entry: ANY;
  57. BEGIN
  58. IF listeners.GetNumberOfElements() > 0 THEN
  59. entries := listeners.GetEnumerator();
  60. WHILE entries.HasMoreElements() DO
  61. entry := entries.GetNext();
  62. entry(ListenerEntry).listener(sender, data)
  63. END
  64. END
  65. END Dispatch;
  66. END EventDispatcher;
  67. PropChangerEntry = OBJECT
  68. VAR
  69. listenedComponent: CSS2Component;
  70. event: String;
  71. state: BOOLEAN
  72. END PropChangerEntry;
  73. PropertyChanger* = OBJECT
  74. VAR
  75. entries: XMLObjects.Collection;
  76. changingComponent: CSS2Component;
  77. changingProperties: CSS2.RuleSet;
  78. oldState: BOOLEAN;
  79. PROCEDURE & Init*;
  80. VAR arrColl: XMLObjects.ArrayCollection;
  81. BEGIN
  82. NEW(arrColl); entries := arrColl; NEW(arrColl);
  83. oldState := FALSE
  84. END Init;
  85. PROCEDURE Copy*(): PropertyChanger;
  86. VAR newPropChanger: PropertyChanger; enum: XMLObjects.Enumerator;
  87. BEGIN
  88. NEW(newPropChanger);
  89. enum := entries.GetEnumerator();
  90. WHILE enum.HasMoreElements() DO
  91. newPropChanger.entries.Add(enum.GetNext());
  92. END;
  93. newPropChanger.changingComponent := changingComponent;
  94. newPropChanger.changingProperties := changingProperties;
  95. newPropChanger.oldState := oldState;
  96. RETURN newPropChanger
  97. END Copy;
  98. PROCEDURE AddListenedComponent*(comp: CSS2Component; VAR event: ARRAY OF CHAR);
  99. VAR newPropChangerEntry: PropChangerEntry;
  100. BEGIN
  101. NEW(newPropChangerEntry);
  102. newPropChangerEntry.listenedComponent := comp;
  103. newPropChangerEntry.event := NewString(event);
  104. newPropChangerEntry.state := FALSE;
  105. entries.Add(newPropChangerEntry)
  106. END AddListenedComponent;
  107. PROCEDURE SetChangingComponent*(comp: CSS2Component; ruleSet: CSS2.RuleSet);
  108. VAR enum: XMLObjects.Enumerator; entry: ANY;
  109. BEGIN
  110. changingComponent := comp;
  111. changingProperties := ruleSet;
  112. enum := entries.GetEnumerator();
  113. WHILE enum.HasMoreElements() DO
  114. entry := enum.GetNext();
  115. entry(PropChangerEntry).listenedComponent.AddEventListener(StatusChanged, entry(PropChangerEntry).event^)
  116. END
  117. END SetChangingComponent;
  118. PROCEDURE StatusChanged(sender, data: ANY);
  119. VAR enum: XMLObjects.Enumerator; entry: ANY; found: BOOLEAN;
  120. BEGIN
  121. IF (sender # NIL) & (sender IS CSS2Component) & (data # NIL) & (data IS StateMessage) THEN
  122. enum := entries.GetEnumerator(); found := FALSE;
  123. WHILE enum.HasMoreElements() & ~found DO
  124. entry := enum.GetNext();
  125. found := entry(PropChangerEntry).listenedComponent = sender
  126. END;
  127. IF found & (entry(PropChangerEntry).state # data(StateMessage).state) THEN
  128. entry(PropChangerEntry).state := data(StateMessage).state;
  129. IF AllStatesSet() # oldState THEN ChangeProperties() END
  130. END
  131. END
  132. END StatusChanged;
  133. PROCEDURE AllStatesSet(): BOOLEAN;
  134. VAR enum: XMLObjects.Enumerator; propChangerEntry: ANY; state: BOOLEAN;
  135. BEGIN
  136. enum := entries.GetEnumerator(); state := TRUE;
  137. WHILE enum.HasMoreElements() & state DO
  138. propChangerEntry := enum.GetNext();
  139. state := propChangerEntry(PropChangerEntry).state
  140. END;
  141. RETURN state
  142. END AllStatesSet;
  143. PROCEDURE ChangeProperties;
  144. VAR declarations: XMLObjects.Enumerator; declaration: ANY; s: String; oldRuleSet: CSS2.RuleSet;
  145. BEGIN
  146. NEW(oldRuleSet);
  147. declarations := changingProperties.GetDeclarations();
  148. WHILE declarations.HasMoreElements() DO
  149. declaration := declarations.GetNext();
  150. s := declaration(CSS2.Declaration).GetProperty();
  151. oldRuleSet.AddDeclaration(changingComponent.properties.GetValue(s^));
  152. changingComponent.properties.SetValue(declaration(CSS2.Declaration))
  153. END;
  154. changingProperties := oldRuleSet;
  155. oldState := ~oldState;
  156. changingComponent.PropertiesChanged();
  157. changingComponent.Invalidate()
  158. END ChangeProperties;
  159. END PropertyChanger;
  160. Component* = OBJECT (XML.Element)
  161. VAR
  162. locks: LONGINT;
  163. PROCEDURE AddAttribute*(attribute: XML.Attribute);
  164. BEGIN
  165. ConnectAttribute(attribute);
  166. AddAttribute^(attribute)
  167. END AddAttribute;
  168. PROCEDURE LockUpdate*;
  169. BEGIN
  170. INC(locks)
  171. END LockUpdate;
  172. PROCEDURE UnlockUpdate*;
  173. BEGIN
  174. IF locks > 0 THEN DEC(locks) END
  175. END UnlockUpdate;
  176. PROCEDURE IsLocked*(): BOOLEAN;
  177. BEGIN
  178. RETURN locks > 0
  179. END IsLocked;
  180. PROCEDURE GetNumberOfEvents*(): LONGINT;
  181. BEGIN
  182. RETURN 0
  183. END GetNumberOfEvents;
  184. PROCEDURE GetEventName*(i: LONGINT): String;
  185. BEGIN
  186. RETURN NIL
  187. END GetEventName;
  188. PROCEDURE AddEventListener*(listener: Listener; event: ARRAY OF CHAR);
  189. END AddEventListener;
  190. PROCEDURE GetNumberOfListeners*(): LONGINT;
  191. BEGIN
  192. RETURN 0
  193. END GetNumberOfListeners;
  194. PROCEDURE GetListenerName*(i: LONGINT): String;
  195. BEGIN
  196. RETURN NIL
  197. END GetListenerName;
  198. PROCEDURE GetListener*(name: ARRAY OF CHAR): Listener;
  199. BEGIN
  200. RETURN Unassigned
  201. END GetListener;
  202. PROCEDURE Connect*;
  203. VAR enum: XMLObjects.Enumerator; p: ANY;
  204. BEGIN
  205. enum := GetAttributes();
  206. WHILE enum.HasMoreElements() DO
  207. p := enum.GetNext();
  208. ConnectAttribute(p(XML.Attribute))
  209. END;
  210. IF GetNumberOfContents() > 0 THEN
  211. enum := GetContents();
  212. WHILE enum.HasMoreElements() DO
  213. p := enum.GetNext();
  214. IF p IS Component THEN p(Component).Connect() END
  215. END
  216. END
  217. END Connect;
  218. PROCEDURE Finalize*;
  219. VAR contents: XMLObjects.Enumerator; c: ANY;
  220. BEGIN
  221. contents := GetContents();
  222. WHILE contents.HasMoreElements() DO
  223. c := contents.GetNext();
  224. IF c IS Component THEN c(Component).Finalize() END
  225. END
  226. END Finalize;
  227. PROCEDURE ConnectAttribute(attribute: XML.Attribute);
  228. VAR listener: Listener; s1, event: String;
  229. BEGIN
  230. s1 := attribute.GetName();
  231. IF s1 # NIL THEN
  232. listener := GetListener(s1^);
  233. IF listener # Unassigned THEN
  234. s1 := attribute.GetValue();
  235. event := ExtractEvent(s1^);
  236. RegisterListener(listener, event^, s1^, 0, DynamicStrings.StringLength(s1^))
  237. END
  238. END;
  239. END ConnectAttribute;
  240. PROCEDURE RegisterListener(listener: Listener; VAR event, path: ARRAY OF CHAR; offset, len: LONGINT);
  241. VAR elem: XML.Element; retComp: Component; s1, s2: String; i: LONGINT;
  242. contents: XMLObjects.Enumerator; content: ANY; quoteChar: CHAR; attr: XML.Attribute;
  243. PROCEDURE SkipWhiteSpace;
  244. BEGIN
  245. WHILE (offset < len) & ((path[offset] = 20X) OR (path[offset] = 9X)) DO INC(offset) END
  246. END SkipWhiteSpace;
  247. BEGIN
  248. SkipWhiteSpace();
  249. IF offset < len THEN
  250. CASE path[offset] OF
  251. | ':': AddEventListener(listener, event)
  252. | '/':
  253. IF offset = 0 THEN
  254. elem := GetRoot();
  255. IF elem IS Component THEN elem(Component).RegisterListener(listener, event, path, offset + 1, len) END
  256. ELSE
  257. contents := GetContents();
  258. WHILE (contents.HasMoreElements()) & (retComp = NIL) DO
  259. content := contents.GetNext();
  260. IF content IS Component THEN content(Component).RegisterListener(listener, event, path, offset + 1, len) END
  261. END
  262. END
  263. | '.':
  264. IF (offset + 1 < len) & (path[offset + 1] = '/') THEN
  265. RegisterListener(listener, event, path, offset + 1, len)
  266. ELSIF (offset + 2 < len) & (path[offset + 1] = '.') & (path[offset + 2] = '/') THEN
  267. elem := GetParent();
  268. IF (elem # NIL) & (elem IS Component) THEN
  269. elem(Component).RegisterListener(listener, event, path, offset + 2, len)
  270. END
  271. END
  272. | '[':
  273. INC(offset); SkipWhiteSpace(); NEW(s1, len - offset + 2); i := 0;
  274. WHILE (i < len - offset) & (path[offset + i] # '=') DO
  275. s1[i] := path[offset + i]; INC(i)
  276. END;
  277. s1[i + 1] := 0X; INC(offset, i + 1); SkipWhiteSpace();
  278. attr := GetAttribute(s1^);
  279. IF attr # NIL THEN
  280. quoteChar := path[offset]; INC(offset);
  281. IF (quoteChar = "'") OR (quoteChar = '"') THEN
  282. NEW(s1, len - offset + 2); i := 0;
  283. WHILE (i < len - offset) & (path[offset + i] # quoteChar) DO
  284. s1[i] := path[offset + i]; INC(i)
  285. END;
  286. s1[i + 1] := 0X; INC(offset, i);
  287. s2 := attr.GetValue();
  288. IF (s1^ = s2^) & (offset + 1 < len) & (path[offset + 1] = ']') THEN
  289. RegisterListener(listener, event, path, offset + 2, len)
  290. END
  291. END
  292. END
  293. | '#':
  294. INC(offset); NEW(s1, len - offset + 2); i := 0;
  295. WHILE (i < len - offset) & (path[offset + i] # '/') & (path[offset + 1] # '.') & (path[offset + 1] # '[')
  296. & (path[offset + 1] # '#') DO
  297. s1[i] := path[offset + i]; INC(i)
  298. END;
  299. s1[i + 1] := 0X; INC(offset, i);
  300. s2 := GetId();
  301. IF (s2 # NIL) & (s1^ = s2^) THEN RegisterListener(listener, event, path, offset, len) END
  302. | '*':
  303. IF offset + 1 < len THEN RegisterListener(listener, event, path, offset + 1, len) END
  304. ELSE
  305. NEW(s1, len - offset + 2); i := 0;
  306. WHILE (i < len - offset) & (path[offset + i] # '/') & (path[offset + i] # '.') & (path[offset + i] # '[')
  307. & (path[offset + i] # '#') & (path[offset + i] # ':')DO
  308. s1[i] := path[offset + i]; INC(i)
  309. END;
  310. s1[i + 1] := 0X; INC(offset, i);
  311. s2 := GetName();
  312. IF s1^ = s2^ THEN RegisterListener(listener, event, path, offset, len) END
  313. END
  314. ELSE
  315. AddEventListener(listener, event)
  316. END
  317. END RegisterListener;
  318. END Component;
  319. CSS2Component* = OBJECT (Component)
  320. VAR
  321. properties-: CSS2Properties.AllMediaProperties;
  322. PROCEDURE &Init*;
  323. BEGIN
  324. Init^();
  325. NEW(properties);
  326. END Init;
  327. PROCEDURE AddContent*(c: XML.Content);
  328. BEGIN
  329. IF c IS CSS2Component THEN c(CSS2Component).properties.SetParent(properties) END;
  330. AddContent^(c)
  331. END AddContent;
  332. PROCEDURE GetProperties*(): CSS2Properties.AllMediaProperties;
  333. BEGIN
  334. RETURN properties
  335. END GetProperties;
  336. PROCEDURE SetProperties*(p: CSS2Properties.AllMediaProperties);
  337. BEGIN
  338. properties := p
  339. END SetProperties;
  340. PROCEDURE SetProperty*(name, value: ARRAY OF CHAR);
  341. VAR ruleSet: CSS2.RuleSet; declarations: XMLObjects.Enumerator; declaration: ANY;
  342. BEGIN
  343. ruleSet := GenerateRuleSet(name, value);
  344. IF ruleSet # NIL THEN
  345. declarations := ruleSet.GetDeclarations();
  346. IF declarations.HasMoreElements() THEN
  347. declaration := declarations.GetNext();
  348. properties.SetValue(declaration(CSS2.Declaration))
  349. END
  350. END
  351. END SetProperty;
  352. PROCEDURE SetPropertyOnEvent*(name, value, event: ARRAY OF CHAR);
  353. VAR ruleSet: CSS2.RuleSet; propertyChanger: PropertyChanger;
  354. BEGIN
  355. ruleSet := GenerateRuleSet(name, value);
  356. IF ruleSet # NIL THEN
  357. NEW(propertyChanger);
  358. propertyChanger.AddListenedComponent(SELF, event);
  359. propertyChanger.SetChangingComponent(SELF, ruleSet)
  360. END
  361. END SetPropertyOnEvent;
  362. PROCEDURE GenerateRuleSet(name, value: ARRAY OF CHAR): CSS2.RuleSet;
  363. VAR scanner: CSS2Scanner.Scanner; parser: CSS2Parser.Parser; file: Files.File; w: Files.Writer;
  364. styleSheet: CSS2.StyleSheet; ruleSets: XMLObjects.Enumerator; ruleSet: ANY;
  365. BEGIN
  366. file := Files.New("");
  367. Files.OpenWriter(w, file, 0);
  368. w.Char('{');
  369. w.Bytes(name, 0, DynamicStrings.StringLength(name));
  370. w.Char(':');
  371. w.Bytes(value, 0, DynamicStrings.StringLength(value));
  372. w.Char('}');
  373. w.Update;
  374. NEW(scanner, file); NEW(parser, scanner); parser.reportError := NoReportError;
  375. styleSheet := parser.Parse();
  376. ruleSets := styleSheet.GetRuleSets();
  377. IF ruleSets.HasMoreElements() THEN ruleSet := ruleSets.GetNext(); RETURN ruleSet(CSS2.RuleSet)
  378. ELSE RETURN NIL
  379. END
  380. END GenerateRuleSet;
  381. PROCEDURE PropertiesChanged*;
  382. VAR contents: XMLObjects.Enumerator; c: ANY;
  383. BEGIN
  384. properties.ComputeValues();
  385. IF GetNumberOfContents() > 0 THEN
  386. contents := GetContents();
  387. WHILE contents.HasMoreElements() DO
  388. c := contents.GetNext();
  389. IF c IS CSS2Component THEN c(CSS2Component).PropertiesChanged() END
  390. END
  391. END
  392. END PropertiesChanged;
  393. PROCEDURE Invalidate*;
  394. END Invalidate;
  395. END CSS2Component;
  396. Box* = OBJECT
  397. VAR
  398. x*, y*, w*, h*: LONGINT;
  399. PROCEDURE InBox*(x, y: LONGINT): BOOLEAN;
  400. BEGIN
  401. RETURN (SELF.x <= x) & (x < SELF.x + w) & (SELF.y <= y) & (y < SELF.y + h)
  402. END InBox;
  403. PROCEDURE IsEmpty*(): BOOLEAN;
  404. BEGIN
  405. RETURN (w = 0) OR (h = 0)
  406. END IsEmpty;
  407. PROCEDURE SetBox*(box: Box);
  408. BEGIN
  409. x := box.x; y := box.y; w := box.w; h := box.h
  410. END SetBox;
  411. PROCEDURE SetRect*(x, y, w, h: LONGINT);
  412. BEGIN
  413. SELF.x := x; SELF.y := y; SELF.w := w; SELF.h := h
  414. END SetRect;
  415. PROCEDURE Intersect*(box: Box): BOOLEAN;
  416. BEGIN
  417. RETURN (x < box.x + box.w) & (box.x < x + w) & (y < box.y + box.h) & (box.y < y + h)
  418. END Intersect;
  419. PROCEDURE IntersectRect*(x, y, w, h: LONGINT): BOOLEAN;
  420. BEGIN
  421. RETURN (SELF.x < x + w) & (x < SELF.x + SELF.w) & (SELF.y < y + h) & (y < SELF.y + SELF.h)
  422. END IntersectRect;
  423. PROCEDURE Clip*(box: Box);
  424. BEGIN
  425. ClipRect(box.x, box.y, box.w, box.h)
  426. END Clip;
  427. PROCEDURE ClipRect*(x, y, w, h: LONGINT);
  428. VAR ur: LONGINT;
  429. BEGIN
  430. ur := MIN(SELF.x + SELF.w, x + w); SELF.x := MAX(SELF.x, x); SELF.w := MAX(0, ur - SELF.x);
  431. ur := MIN(SELF.y + SELF.h, y + h); SELF.y := MAX(SELF.y, y); SELF.h := MAX(0, ur - SELF.y)
  432. END ClipRect;
  433. PROCEDURE Extend*(box: Box);
  434. BEGIN
  435. ExtendRect(box.x, box.y, box.w, box.h)
  436. END Extend;
  437. PROCEDURE ExtendRect*(x, y, w, h: LONGINT);
  438. VAR ur: LONGINT;
  439. BEGIN
  440. ur := MAX(SELF.x + SELF.w, x + w); SELF.x := MIN(SELF.x, x); SELF.w := ur - SELF.x;
  441. ur := MAX(SELF.y + SELF.h, y + h); SELF.y := MIN(SELF.y, y); SELF.h := ur - SELF.y
  442. END ExtendRect;
  443. END Box;
  444. VisualComponent* = OBJECT (CSS2Component)
  445. VAR
  446. pointerMoveListeners, hoverListeners, activeListeners, focusListeners: EventDispatcher;
  447. bounds, borderBox, paddingBox, contentBox, invalidBox: Box;
  448. inlineBoxes, textBoxes: XMLObjects.Collection;
  449. pointerOwner, focusOwner: VisualComponent;
  450. isHovered*, hasFocus*, isActive*, isLink*, isVisited*, dragable*: BOOLEAN;
  451. lastMouseKeys-: SET;
  452. lastX-, lastY-: LONGINT;
  453. trueStateMsg, falseStateMsg: StateMessage;
  454. PROCEDURE &Init*;
  455. VAR vprop: CSS2Properties.VisualProperties; arrColl: XMLObjects.ArrayCollection;
  456. BEGIN
  457. Init^();
  458. NEW(vprop);
  459. properties := vprop;
  460. NEW(bounds); bounds.x := 0; bounds.y := 0; bounds.w := 0; bounds.h := 0;
  461. NEW(borderBox); NEW(paddingBox); NEW(contentBox); NEW(invalidBox);
  462. NEW(arrColl); textBoxes := arrColl;
  463. NEW(arrColl); inlineBoxes := arrColl;
  464. pointerOwner := SELF;
  465. NEW(trueStateMsg, TRUE); NEW(falseStateMsg, FALSE);
  466. NEW(pointerMoveListeners, SELF); NEW(hoverListeners, SELF); NEW(activeListeners, SELF); NEW(focusListeners, SELF)
  467. END Init;
  468. PROCEDURE AddContent*(c: XML.Content);
  469. BEGIN
  470. IF c IS CSS2Component THEN
  471. c(VisualComponent).properties.SetParent(properties);
  472. END;
  473. AddContent^(c)
  474. END AddContent;
  475. PROCEDURE SetProperties*(p: CSS2Properties.AllMediaProperties);
  476. BEGIN
  477. IF (p # NIL) & (p IS CSS2Properties.VisualProperties) THEN
  478. SetProperties^(p)
  479. END
  480. END SetProperties;
  481. PROCEDURE GetBounds*(): Box;
  482. VAR box: Box;
  483. BEGIN
  484. NEW(box); box.x := GetX(); box.y := GetY(); box.w := GetWidth(); box.h := GetHeight(); RETURN box
  485. END GetBounds;
  486. PROCEDURE SetBounds*(bounds: Box);
  487. BEGIN
  488. IF bounds # NIL THEN SELF.bounds.SetBox(bounds) END
  489. END SetBounds;
  490. (* PROCEDURE GetSize*(VAR w, h: LONGINT);
  491. BEGIN
  492. w := GetWidth(); h := GetHeight()
  493. END GetSize;
  494. PROCEDURE SetSize*(w, h: LONGINT);
  495. VAR vp: CSS2Properties.VisualProperties;
  496. BEGIN
  497. SetWidth(w); SetHeight(h);
  498. END SetSize;*)
  499. PROCEDURE GetWidth*(): LONGINT;
  500. BEGIN
  501. RETURN bounds.w
  502. END GetWidth;
  503. PROCEDURE SetWidth*(w: LONGINT);
  504. VAR vp: CSS2Properties.VisualProperties;
  505. BEGIN
  506. vp := properties(CSS2Properties.VisualProperties);
  507. vp.width.computed := w - (vp.margin.left.computed + vp.borderWidth.left.computed + vp.padding.left.computed
  508. + vp.padding.right.computed + vp.borderWidth.right.computed + vp.margin.right.computed);
  509. ComputeWidths()
  510. END SetWidth;
  511. PROCEDURE GetHeight*(): LONGINT;
  512. BEGIN
  513. RETURN bounds.h
  514. END GetHeight;
  515. PROCEDURE SetHeight*(h: LONGINT);
  516. VAR vp: CSS2Properties.VisualProperties;
  517. BEGIN
  518. vp := properties(CSS2Properties.VisualProperties);
  519. vp.height.computed := h - (vp.margin.top.computed + vp.borderWidth.top.computed + vp.padding.top.computed
  520. + vp.padding.bottom.computed + vp.borderWidth.bottom.computed + vp.margin.bottom.computed);
  521. ComputeHeights()
  522. END SetHeight;
  523. PROCEDURE GetX*(): LONGINT;
  524. BEGIN
  525. RETURN bounds.x
  526. END GetX;
  527. PROCEDURE SetX*(x: LONGINT);
  528. BEGIN
  529. lastX := lastX - (x - bounds.x); bounds.x := x;
  530. IF ~IsHit(lastX, lastY) THEN PointerUp(lastX, lastY, lastMouseKeys) END
  531. END SetX;
  532. PROCEDURE GetY*(): LONGINT;
  533. BEGIN
  534. RETURN bounds.y
  535. END GetY;
  536. PROCEDURE SetY*(y: LONGINT);
  537. BEGIN
  538. lastY := lastY - (y - bounds.y); bounds.y := y;
  539. IF ~IsHit(lastX, lastY) THEN PointerUp(lastX, lastY, lastMouseKeys) END
  540. END SetY;
  541. PROCEDURE GetContentBox*(): Box;
  542. VAR box: Box;
  543. BEGIN
  544. NEW(box); box.SetBox(contentBox); RETURN box
  545. END GetContentBox;
  546. PROCEDURE SetContentBox*(contentBox: Box);
  547. BEGIN
  548. SELF.contentBox.SetBox(contentBox)
  549. END SetContentBox;
  550. PROCEDURE GetContentWidth*(): LONGINT;
  551. BEGIN
  552. RETURN contentBox.w
  553. END GetContentWidth;
  554. PROCEDURE SetContentWidth*(w: LONGINT);
  555. BEGIN
  556. properties(CSS2Properties.VisualProperties).width.computed := w;
  557. ComputeWidths()
  558. END SetContentWidth;
  559. PROCEDURE GetContentHeight*(): LONGINT;
  560. BEGIN
  561. RETURN contentBox.h
  562. END GetContentHeight;
  563. PROCEDURE SetContentHeight*(h: LONGINT);
  564. BEGIN
  565. properties(CSS2Properties.VisualProperties).height.computed := h;
  566. ComputeHeights()
  567. END SetContentHeight;
  568. PROCEDURE GetContentX*(): LONGINT;
  569. BEGIN
  570. RETURN contentBox.x
  571. END GetContentX;
  572. PROCEDURE GetContentY*(): LONGINT;
  573. BEGIN
  574. RETURN contentBox.y
  575. END GetContentY;
  576. PROCEDURE GetBorderBox*(): Box;
  577. VAR box: Box;
  578. BEGIN
  579. NEW(box); box.SetBox(borderBox); RETURN box
  580. END GetBorderBox;
  581. PROCEDURE GetBorderWidth*(): LONGINT;
  582. BEGIN
  583. RETURN borderBox.w
  584. END GetBorderWidth;
  585. PROCEDURE GetBorderHeight*(): LONGINT;
  586. BEGIN
  587. RETURN borderBox.h
  588. END GetBorderHeight;
  589. PROCEDURE GetBorderX*(): LONGINT;
  590. BEGIN
  591. RETURN borderBox.x
  592. END GetBorderX;
  593. PROCEDURE GetBorderY*(): LONGINT;
  594. BEGIN
  595. RETURN borderBox.y
  596. END GetBorderY;
  597. PROCEDURE GetPaddingBox*(): Box;
  598. VAR box: Box;
  599. BEGIN
  600. NEW(box); box.SetBox(paddingBox); RETURN box
  601. END GetPaddingBox;
  602. PROCEDURE GetPaddingWidth*(): LONGINT;
  603. BEGIN
  604. RETURN paddingBox.w
  605. END GetPaddingWidth;
  606. PROCEDURE GetPaddingHeight*(): LONGINT;
  607. BEGIN
  608. RETURN paddingBox.h
  609. END GetPaddingHeight;
  610. PROCEDURE GetPaddingX*(): LONGINT;
  611. BEGIN
  612. RETURN paddingBox.x
  613. END GetPaddingX;
  614. PROCEDURE GetPaddingY*(): LONGINT;
  615. BEGIN
  616. RETURN paddingBox.y
  617. END GetPaddingY;
  618. PROCEDURE ComputeWidths*;
  619. VAR vp: CSS2Properties.VisualProperties;
  620. BEGIN
  621. vp := properties(CSS2Properties.VisualProperties);
  622. bounds.w := ENTIER(0.5 + vp.margin.left.computed + vp.borderWidth.left.computed + vp.padding.left.computed
  623. + vp.width.computed + vp.padding.right.computed + vp.borderWidth.right.computed + vp.margin.right.computed);
  624. borderBox.x := ENTIER(0.5 + vp.margin.left.computed);
  625. borderBox.w := ENTIER(0.5 + vp.borderWidth.left.computed + vp.padding.left.computed + vp.width.computed
  626. + vp.padding.right.computed + vp.borderWidth.right.computed);
  627. paddingBox.x := ENTIER(0.5 + vp.margin.left.computed + vp.borderWidth.left.computed);
  628. paddingBox.w := ENTIER(0.5 + vp.padding.left.computed + vp.width.computed + vp.padding.right.computed);
  629. contentBox.x := ENTIER(0.5 + vp.margin.left.computed + vp.borderWidth.left.computed + vp.padding.left.computed);
  630. contentBox.w := ENTIER(0.5 + vp.width.computed);
  631. IF ~IsHit(lastX, lastY) THEN PointerUp(lastX, lastY, lastMouseKeys) END
  632. END ComputeWidths;
  633. PROCEDURE ComputeHeights*;
  634. VAR vp: CSS2Properties.VisualProperties;
  635. BEGIN
  636. vp := properties(CSS2Properties.VisualProperties);
  637. bounds.h := ENTIER(0.5 + vp.margin.top.computed + vp.borderWidth.top.computed + vp.padding.top.computed
  638. + vp.height.computed + vp.padding.bottom.computed + vp.borderWidth.bottom.computed
  639. + vp.margin.bottom.computed);
  640. borderBox.y := ENTIER(0.5 + vp.margin.top.computed);
  641. borderBox.h := ENTIER(0.5 + vp.borderWidth.top.computed + vp.padding.top.computed + vp.height.computed
  642. + vp.padding.bottom.computed + vp.borderWidth.bottom.computed);
  643. paddingBox.y := ENTIER(0.5 + vp.margin.top.computed + vp.borderWidth.top.computed);
  644. paddingBox.h := ENTIER(0.5 + vp.padding.top.computed + vp.height.computed + vp.padding.bottom.computed);
  645. contentBox.y := ENTIER(0.5 + vp.margin.top.computed + vp.borderWidth.top.computed + vp.padding.top.computed);
  646. contentBox.h := ENTIER(0.5 + vp.height.computed);
  647. IF ~IsHit(lastX, lastY) THEN PointerUp(lastX, lastY, lastMouseKeys) END
  648. END ComputeHeights;
  649. PROCEDURE GetNumberOfEvents*(): LONGINT;
  650. BEGIN
  651. RETURN GetNumberOfEvents^() + 4
  652. END GetNumberOfEvents;
  653. PROCEDURE GetEventName*(i: LONGINT): String;
  654. VAR s: String;
  655. BEGIN
  656. CASE i - GetNumberOfEvents^() OF
  657. | 0: s := NewString("hover")
  658. | 1: s := NewString("active")
  659. | 2: s := NewString("focus")
  660. | 3: RETURN NewString("pointer-move")
  661. ELSE
  662. END;
  663. RETURN s
  664. END GetEventName;
  665. PROCEDURE AddEventListener*(listener: Listener; event: ARRAY OF CHAR);
  666. BEGIN
  667. IF event = "hover" THEN hoverListeners.AddListener(listener)
  668. ELSIF event = "active" THEN activeListeners.AddListener(listener)
  669. ELSIF event = "focus" THEN focusListeners.AddListener(listener)
  670. ELSIF event = "pointer-move" THEN pointerMoveListeners.AddListener(listener)
  671. ELSE AddEventListener^(listener, event)
  672. END
  673. END AddEventListener;
  674. PROCEDURE UnlockUpdate*;
  675. BEGIN
  676. UnlockUpdate^();
  677. IF ~IsLocked() & ~invalidBox.IsEmpty() THEN
  678. InvalidateRange(invalidBox.x, invalidBox.y, invalidBox.w, invalidBox.h);
  679. invalidBox.w := 0; invalidBox.h := 0
  680. END
  681. END UnlockUpdate;
  682. PROCEDURE SetActive*(isActive: BOOLEAN);
  683. BEGIN
  684. IF isActive # SELF.isActive THEN
  685. LockUpdate();
  686. IF isActive THEN activeListeners.Dispatch(trueStateMsg) ELSE activeListeners.Dispatch(falseStateMsg) END;
  687. UnlockUpdate();
  688. SELF.isActive := isActive
  689. END
  690. END SetActive;
  691. PROCEDURE IsActive(): BOOLEAN;
  692. BEGIN
  693. RETURN isActive
  694. END IsActive;
  695. PROCEDURE SetPointer*(pointerInfo: WMWindowManager.PointerInfo);
  696. VAR parent: XML.Element;
  697. BEGIN
  698. parent := GetParent();
  699. IF (parent # NIL) & (parent IS VisualComponent) THEN
  700. parent(VisualComponent).SetPointer(pointerInfo)
  701. END
  702. END SetPointer;
  703. PROCEDURE GetPointerOwner*(): VisualComponent;
  704. BEGIN
  705. RETURN pointerOwner
  706. END GetPointerOwner;
  707. PROCEDURE IsHit*(x, y: LONGINT): BOOLEAN;
  708. VAR contents: XMLObjects.Enumerator; content: ANY;
  709. BEGIN
  710. IF ((properties(CSS2Properties.VisualProperties).overflow.computed = CSS2Properties.Visible) OR contentBox.InBox(x, y))
  711. & (properties(CSS2Properties.VisualProperties).visibility.computed = CSS2Properties.Visible) THEN
  712. IF GetNumberOfContents() > 0 THEN
  713. contents := GetContents();
  714. WHILE contents.HasMoreElements() DO
  715. content := contents.GetNext();
  716. IF (content IS VisualComponent)
  717. & content(VisualComponent).IsHit(x - content(VisualComponent).GetX(), y - content(VisualComponent).GetY())
  718. THEN
  719. RETURN TRUE
  720. END
  721. END
  722. END
  723. END;
  724. RETURN FALSE
  725. END IsHit;
  726. PROCEDURE PositionOwner*(x, y: LONGINT): VisualComponent;
  727. VAR contents: XMLObjects.Enumerator; content: ANY; po: VisualComponent;
  728. BEGIN
  729. IF (properties(CSS2Properties.VisualProperties).overflow.computed = CSS2Properties.Visible) OR contentBox.InBox(x, y) THEN
  730. IF GetNumberOfContents() > 0 THEN
  731. contents := GetContents();
  732. WHILE contents.HasMoreElements() DO
  733. content := contents.GetNext();
  734. IF content IS VisualComponent THEN
  735. WITH content: VisualComponent DO
  736. IF content.IsHit(x - content.GetX(), y - content.GetY()) THEN
  737. po := content
  738. END
  739. END
  740. END
  741. END
  742. END
  743. END;
  744. IF po # NIL THEN RETURN po ELSE
  745. RETURN SELF
  746. END
  747. END PositionOwner;
  748. PROCEDURE PointerLeave*;
  749. BEGIN
  750. IF (pointerOwner = SELF) THEN
  751. IF isActive THEN PointerUp(lastX, lastY, lastMouseKeys) END;
  752. IF isHovered THEN hoverListeners.Dispatch(falseStateMsg); isHovered := FALSE END
  753. ELSIF pointerOwner # SELF THEN
  754. pointerOwner.PointerLeave()
  755. END
  756. END PointerLeave;
  757. PROCEDURE PointerDown*(x, y: LONGINT; keys: SET);
  758. BEGIN
  759. IF dragable & (keys = {0}) THEN lastX := x; lastY := y END;
  760. SetActive(IsHit(x, y))
  761. END PointerDown;
  762. PROCEDURE PointerMove*(x, y: LONGINT; keys: SET);
  763. BEGIN
  764. lastX := x; lastY := y;
  765. LockUpdate();
  766. IF IsHit(x, y) THEN
  767. IF ~isHovered THEN
  768. hoverListeners.Dispatch(trueStateMsg);
  769. isHovered := TRUE;
  770. IF keys # {} THEN SetActive(TRUE) END;
  771. SetPointer(properties(CSS2Properties.VisualProperties).cursor.computed)
  772. END
  773. ELSE
  774. IF isHovered THEN
  775. IF keys # {} THEN
  776. SetActive(FALSE)
  777. END;
  778. hoverListeners.Dispatch(falseStateMsg);
  779. isHovered := FALSE
  780. END
  781. END;
  782. IF dragable & (keys = {0}) THEN
  783. (* to do: Move Component; Invalidate Parent *)
  784. END;
  785. pointerMoveListeners.Dispatch(NIL);
  786. UnlockUpdate()
  787. END PointerMove;
  788. PROCEDURE PointerUp*(x, y: LONGINT; keys: SET);
  789. BEGIN
  790. SetActive(FALSE)
  791. END PointerUp;
  792. PROCEDURE KeyPressed*(ch: CHAR; flags: SET; VAR keySym: LONGINT);
  793. END KeyPressed;
  794. PROCEDURE FocusReceived*;
  795. BEGIN
  796. focusListeners.Dispatch(trueStateMsg)
  797. END FocusReceived;
  798. PROCEDURE FocusLost*;
  799. BEGIN
  800. focusListeners.Dispatch(falseStateMsg);
  801. IF focusOwner # NIL THEN
  802. IF focusOwner # SELF THEN focusOwner.FocusLost() END;
  803. focusOwner := NIL
  804. END
  805. END FocusLost;
  806. PROCEDURE ProcessMessage*(m: ANY);
  807. VAR newPointerOwner: VisualComponent; kd, kdp: SHORTINT;
  808. BEGIN
  809. IF m IS MouseMessage THEN
  810. WITH m: MouseMessage DO
  811. IF m.keys = {} THEN
  812. (* up in case the pointer is not on the component but goes up *)
  813. IF lastMouseKeys # {} THEN
  814. IF pointerOwner = SELF THEN
  815. PointerUp(m.x, m.y, {})
  816. ELSE
  817. DEC(m.x, pointerOwner.GetX()); DEC(m.y, pointerOwner.GetY());
  818. pointerOwner.ProcessMessage(m);
  819. END;
  820. lastMouseKeys := {} (*; RETURN*)
  821. ELSE
  822. newPointerOwner := PositionOwner(m.x, m.y);
  823. IF newPointerOwner # pointerOwner THEN
  824. pointerOwner.lastMouseKeys := m.keys;
  825. pointerOwner.PointerLeave(); pointerOwner := newPointerOwner END
  826. END
  827. ELSE
  828. (* click --> focus *)
  829. IF lastMouseKeys = {} THEN
  830. IF pointerOwner # focusOwner THEN
  831. IF focusOwner # NIL THEN focusOwner.FocusLost() END;
  832. focusOwner := pointerOwner;
  833. focusOwner.FocusReceived()
  834. END
  835. END
  836. END;
  837. IF pointerOwner = SELF THEN
  838. IF lastMouseKeys # m.keys THEN
  839. kd := 0;
  840. IF 0 IN m.keys THEN INC(kd) END;
  841. IF 1 IN m.keys THEN INC(kd) END;
  842. IF 2 IN m.keys THEN INC(kd) END;
  843. kdp := 0;
  844. IF 0 IN lastMouseKeys THEN INC(kdp) END;
  845. IF 1 IN lastMouseKeys THEN INC(kdp) END;
  846. IF 2 IN lastMouseKeys THEN INC(kdp) END;
  847. IF kd < kdp THEN PointerUp(m.x, m.y, m.keys)
  848. ELSE PointerDown(m.x, m.y, m.keys)
  849. END;
  850. lastMouseKeys := m.keys
  851. ELSE
  852. PointerMove(m.x, m.y, m.keys)
  853. END
  854. ELSE
  855. DEC(m.x, pointerOwner.GetX()); DEC(m.y, pointerOwner.GetY());
  856. pointerOwner.ProcessMessage(m)
  857. END
  858. END
  859. ELSIF m IS KeyMessage THEN
  860. WITH m: KeyMessage DO
  861. IF (focusOwner = SELF) OR (focusOwner = NIL) THEN
  862. KeyPressed(m.ch, m.flags, m.keySym)
  863. ELSIF (focusOwner # SELF) & (focusOwner # NIL) THEN
  864. IF m.keySym >= 0 THEN focusOwner.ProcessMessage(m) END
  865. END
  866. END
  867. END
  868. END ProcessMessage;
  869. PROCEDURE ComputeDimensions*;
  870. VAR contents: XMLObjects.Enumerator; content: ANY;
  871. BEGIN
  872. properties(CSS2Properties.VisualProperties).ComputeDimensions();
  873. contents := GetContents();
  874. WHILE contents.HasMoreElements() DO
  875. content := contents.GetNext();
  876. IF content IS VisualComponent THEN content(VisualComponent).ComputeDimensions() END
  877. END;
  878. ComputeWidths();
  879. ComputeHeights()
  880. END ComputeDimensions;
  881. PROCEDURE Format*;
  882. VAR contents: XMLObjects.Enumerator; content: ANY;
  883. BEGIN
  884. ComputeWidths();
  885. ComputeHeights();
  886. IF GetNumberOfContents() > 0 THEN
  887. contents := GetContents();
  888. WHILE contents.HasMoreElements() DO
  889. content := contents.GetNext();
  890. IF (content IS VisualComponent)
  891. & (content(VisualComponent).properties(CSS2Properties.VisualProperties).
  892. visibility.computed = CSS2Properties.Visible) THEN
  893. content(VisualComponent).Format() END
  894. END
  895. END
  896. END Format;
  897. PROCEDURE Resized*;
  898. VAR parent: XML.Element;
  899. BEGIN
  900. parent := GetParent();
  901. IF (parent # NIL) & (parent IS VisualComponent) THEN parent(VisualComponent).Resized() END;
  902. END Resized;
  903. PROCEDURE PropertiesChanged*;
  904. BEGIN
  905. PropertiesChanged^();
  906. IF properties(CSS2Properties.VisualProperties).dimensionChanged THEN Resized() END
  907. END PropertiesChanged;
  908. PROCEDURE InvalidateRange*(x, y, w, h: LONGINT);
  909. VAR parent: XML.Element;
  910. BEGIN
  911. IF IsLocked() THEN
  912. IF invalidBox.IsEmpty() THEN invalidBox.SetRect(x, y, w, h)
  913. ELSE invalidBox.ExtendRect(x, y, w, h)
  914. END
  915. ELSE
  916. parent := GetParent();
  917. IF (parent # NIL) THEN
  918. parent(VisualComponent).InvalidateRange(bounds.x + x, bounds.y + y, w, h)
  919. END
  920. END
  921. END InvalidateRange;
  922. PROCEDURE Invalidate*;
  923. BEGIN
  924. Invalidate^();
  925. InvalidateRange(0, 0, bounds.w, bounds.h)
  926. END Invalidate;
  927. PROCEDURE Draw*(ctxt: Gfx.Context);
  928. VAR enum: XMLObjects.Enumerator; p: ANY; state1, state2: Gfx.State; llx, lly, urx, ury: REAL;
  929. BEGIN
  930. IF properties(CSS2Properties.VisualProperties).overflow.computed = CSS2Properties.Hidden THEN
  931. Gfx.Save(ctxt, {Gfx.clip}, state1);
  932. Gfx.DrawRect(ctxt, contentBox.x, contentBox.y, contentBox.x + contentBox.w, contentBox.y + contentBox.h,
  933. {Gfx.Clip})
  934. END;
  935. Gfx.GetClipRect(ctxt, llx, lly, urx, ury);
  936. IF (0 < urx) & (llx < bounds.w) & (0 < ury) & (lly < bounds.h) & (GetNumberOfContents() > 0) THEN
  937. enum := GetContents();
  938. WHILE enum.HasMoreElements() DO
  939. p := enum.GetNext();
  940. IF p IS VisualComponent THEN
  941. WITH p: VisualComponent DO
  942. IF (p.GetX() < urx) & (llx < p.GetX() + p.GetWidth()) & (p.GetY() < ury) & (lly < p.GetY() + p.GetHeight())
  943. & (p.properties(CSS2Properties.VisualProperties).visibility.computed = CSS2Properties.Visible) THEN
  944. Gfx.Save(ctxt, {Gfx.ctm, Gfx.clip}, state2);
  945. Gfx.Translate(ctxt, p.GetX(), p.GetY());
  946. (* Gfx.DrawRect(ctxt, 0, 0, childBounds.w, childBounds.h, {Gfx.Clip}); *)
  947. p.Draw(ctxt);
  948. Gfx.Restore(ctxt, state2)
  949. END
  950. END
  951. END
  952. END
  953. END;
  954. IF properties(CSS2Properties.VisualProperties).overflow.computed = CSS2Properties.Hidden THEN
  955. Gfx.Restore(ctxt, state1)
  956. END
  957. END Draw;
  958. END VisualComponent;
  959. PROCEDURE NoReportError(pos, line, row: LONGINT; msg: ARRAY OF CHAR);
  960. END NoReportError;
  961. PROCEDURE NewString*(value: ARRAY OF CHAR): String;
  962. VAR s: String;
  963. BEGIN
  964. NEW(s, DynamicStrings.StringLength(value) + 1);
  965. COPY(value, s^);
  966. RETURN s
  967. END NewString;
  968. (* PROCEDURE DrawClipRect*(ctxt: Gfx.Context; x, y, w, h: LONGINT);
  969. VAR llx, lly, urx, ury: INTEGER;
  970. BEGIN
  971. IF ctxt IS GfxRaster.Context THEN
  972. WITH ctxt: GfxRaster.Context DO
  973. llx := SHORT(x + ENTIER(0.5 + ctxt.ctm[2, 0])); urx := SHORT(llx + w);
  974. lly := SHORT(y + ENTIER(0.5 + ctxt.ctm[2, 1])); ury := SHORT(lly + h);
  975. GfxRegions.ClipRect(llx, lly, urx, ury, SHORT(ENTIER(0.5 + ctxt.clipReg.llx)), SHORT(ENTIER(0.5 + ctxt.clipReg.lly)),
  976. SHORT(ENTIER(0.5 + ctxt.clipReg.urx)), SHORT(ENTIER(0.5 + ctxt.clipReg.ury)));
  977. Gfx.ResetClip(ctxt);
  978. GfxRegions.SetToRect(ctxt.clipReg, llx, lly, urx, ury);
  979. ctxt.clipState := GfxRaster.In;
  980. END
  981. ELSE
  982. Gfx.DrawRect(ctxt, x, y, x + w, y + h, {Gfx.Clip})
  983. END
  984. END DrawClipRect;*)
  985. PROCEDURE ExtractEvent(VAR string: ARRAY OF CHAR): String;
  986. VAR i, j, len: LONGINT; event: String;
  987. BEGIN
  988. len := DynamicStrings.StringLength(string);
  989. i := len - 1;
  990. WHILE (i >= 0) & (string[i] # ':') DO DEC(i) END; j := 0;
  991. IF i >= 0 THEN
  992. (*string[i] := 0X;*)
  993. NEW(event, len - i);
  994. FOR i := i + 1 TO len - 1 DO event[j] := string[i]; (*string[i] := 0X;*) INC(j) END
  995. ELSE
  996. NEW(event, 1)
  997. END;
  998. event[j] := 0X;
  999. RETURN event
  1000. END ExtractEvent;
  1001. END XMLComponents.