Windows.txt 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855
  1. MODULE Windows;
  2. (* THIS IS TEXT COPY OF BlackBox 1.6-rc6 System/Mod/Windows.odc *)
  3. (* DO NOT EDIT *)
  4. IMPORT
  5. Kernel, Ports, Files, Services,
  6. Stores, Sequencers, Models, Views, Controllers, Properties,
  7. Dialog, Converters, Containers, Documents;
  8. CONST
  9. (** Window.flags **)
  10. isTool* = 0; isAux* = 1;
  11. noHScroll* = 2; noVScroll* = 3; noResize* = 4;
  12. allowDuplicates* = 5; neverDirty* = 6;
  13. (** Directory.Select lazy **)
  14. eager* = FALSE; lazy* = TRUE;
  15. notRecorded = 3;
  16. TYPE
  17. Window* = POINTER TO ABSTRACT RECORD
  18. port-: Ports.Port;
  19. frame-: Views.RootFrame;
  20. doc-: Documents.Document;
  21. seq-: Sequencers.Sequencer;
  22. link-: Window; (* ring of windows with same sequencer *)
  23. sub-: BOOLEAN;
  24. flags-: SET;
  25. loc-: Files.Locator;
  26. name-: Files.Name;
  27. conv-: Converters.Converter
  28. END;
  29. Directory* = POINTER TO ABSTRACT RECORD
  30. l*, t*, r*, b*: INTEGER;
  31. minimized*, maximized*: BOOLEAN
  32. END;
  33. OpElem = POINTER TO RECORD
  34. next: OpElem;
  35. st: Stores.Store;
  36. op: Stores.Operation;
  37. name: Stores.OpName;
  38. invisible, transparent: BOOLEAN
  39. END;
  40. Script = POINTER TO RECORD (Stores.Operation)
  41. up: Script;
  42. list: OpElem;
  43. level: INTEGER; (* nestLevel at creation time *)
  44. name: Stores.OpName
  45. END;
  46. StdSequencer = POINTER TO RECORD (Sequencers.Sequencer)
  47. home: Window;
  48. trapEra: INTEGER; (* last observed TrapCount value *)
  49. modLevel: INTEGER; (* dirty if modLevel > 0 *)
  50. entryLevel: INTEGER; (* active = (entryLevel > 0) *)
  51. nestLevel: INTEGER; (* nesting level of BeginScript/Modification *)
  52. modStack: ARRAY 64 OF RECORD store: Stores.Store; type: INTEGER END;
  53. lastSt: Stores.Store;
  54. lastOp: Stores.Operation;
  55. script: Script;
  56. undo, redo: OpElem; (* undo/redo stacks *)
  57. noUndo: BOOLEAN; (* script # NIL and BeginModification called *)
  58. invisibleLevel, transparentLevel, notRecordedLevel: INTEGER
  59. END;
  60. SequencerDirectory = POINTER TO RECORD (Sequencers.Directory) END;
  61. Forwarder = POINTER TO RECORD (Controllers.Forwarder) END;
  62. RootContext = POINTER TO RECORD (Models.Context)
  63. win: Window
  64. END;
  65. Reducer = POINTER TO RECORD (Kernel.Reducer) END;
  66. Hook = POINTER TO RECORD (Views.MsgHook) END;
  67. CheckAction = POINTER TO RECORD (Services.Action)
  68. wait: WaitAction
  69. END;
  70. WaitAction = POINTER TO RECORD (Services.Action)
  71. check: CheckAction
  72. END;
  73. LangNotifier = POINTER TO RECORD (Dialog.LangNotifier) END;
  74. VAR dir-, stdDir-: Directory;
  75. PROCEDURE ^ Reset (s: StdSequencer);
  76. PROCEDURE CharError;
  77. BEGIN
  78. Dialog.Beep
  79. END CharError;
  80. (** Window **)
  81. PROCEDURE (w: Window) Init* (port: Ports.Port), NEW;
  82. BEGIN
  83. ASSERT(w.port = NIL, 20); ASSERT(port # NIL, 21);
  84. w.port := port
  85. END Init;
  86. PROCEDURE (w: Window) SetTitle* (title: Views.Title), NEW, ABSTRACT;
  87. PROCEDURE (w: Window) GetTitle* (OUT title: Views.Title), NEW, ABSTRACT;
  88. PROCEDURE (w: Window) RefreshTitle* (), NEW, ABSTRACT;
  89. PROCEDURE (w: Window) SetSpec* (loc: Files.Locator; name: Files.Name; conv: Converters.Converter), NEW, EXTENSIBLE;
  90. VAR u: Window;
  91. BEGIN
  92. u := w;
  93. REPEAT
  94. u := u.link;
  95. u.loc := loc; u.name := name$; u.conv := conv
  96. UNTIL u = w
  97. END SetSpec;
  98. PROCEDURE (w: Window) Restore* (l, t, r, b: INTEGER), NEW;
  99. VAR f: Views.Frame; u, pw, ph: INTEGER;
  100. BEGIN
  101. f := w.frame;
  102. IF f # NIL THEN
  103. w.port.GetSize(pw, ph); u := w.port.unit;
  104. IF r > pw THEN r := pw END;
  105. IF b > ph THEN b := ph END;
  106. l := l * u - f.gx; t := t * u - f.gy; r := r * u - f.gx; b := b * u - f.gy;
  107. (* only adds to the BlackBox region, but doesn't draw: *)
  108. Views.UpdateRoot(w.frame, l, t, r, b, Views.keepFrames)
  109. END
  110. END Restore;
  111. PROCEDURE (w: Window) Update*, NEW;
  112. BEGIN
  113. ASSERT(w.frame # NIL, 20);
  114. (* redraws the whole accumulated BlackBox region: *)
  115. Views.ValidateRoot(w.frame)
  116. END Update;
  117. PROCEDURE (w: Window) GetSize*(OUT width, height: INTEGER), NEW, EXTENSIBLE;
  118. BEGIN
  119. w.port.GetSize(width, height)
  120. END GetSize;
  121. PROCEDURE (w: Window) SetSize* (width, height: INTEGER), NEW, EXTENSIBLE;
  122. VAR c: Containers.Controller; w0, h0: INTEGER;
  123. BEGIN
  124. w.port.GetSize(w0, h0);
  125. w.port.SetSize(width, height);
  126. IF w.frame # NIL THEN Views.AdaptRoot(w.frame) END;
  127. c := w.doc.ThisController();
  128. IF c.opts * {Documents.winWidth, Documents.winHeight} # {} THEN
  129. w.Restore(0, 0, width, height)
  130. END
  131. END SetSize;
  132. PROCEDURE (w: Window) BroadcastModelMsg* (VAR msg: Models.Message), NEW, EXTENSIBLE;
  133. BEGIN
  134. IF w.frame # NIL THEN
  135. Views.BroadcastModelMsg(w.frame, msg)
  136. END
  137. END BroadcastModelMsg;
  138. PROCEDURE (w: Window) BroadcastViewMsg* (VAR msg: Views.Message), NEW, EXTENSIBLE;
  139. BEGIN
  140. IF w.frame # NIL THEN
  141. Views.BroadcastViewMsg(w.frame, msg)
  142. END
  143. END BroadcastViewMsg;
  144. PROCEDURE (w: Window) ForwardCtrlMsg* (VAR msg: Controllers.Message), NEW, EXTENSIBLE;
  145. BEGIN
  146. IF w.frame # NIL THEN
  147. WITH msg: Controllers.CursorMessage DO
  148. DEC(msg.x, w.frame.gx); DEC(msg.y, w.frame.gy)
  149. ELSE
  150. END;
  151. Views.ForwardCtrlMsg(w.frame, msg)
  152. END
  153. END ForwardCtrlMsg;
  154. PROCEDURE (w: Window) MouseDown* (x, y, time: INTEGER; modifiers: SET), NEW, ABSTRACT;
  155. PROCEDURE (w: Window) KeyDown* (ch: CHAR; modifiers: SET), NEW, EXTENSIBLE;
  156. VAR key: Controllers.EditMsg;
  157. BEGIN
  158. IF ch = 0X THEN
  159. CharError
  160. ELSE
  161. key.op := Controllers.pasteChar; key.char := ch;
  162. key.modifiers:= modifiers;
  163. w.ForwardCtrlMsg(key)
  164. END
  165. END KeyDown;
  166. PROCEDURE (w: Window) Close*, NEW, EXTENSIBLE;
  167. VAR u: Window; f: Views.Frame; s: Sequencers.Sequencer; msg: Sequencers.RemoveMsg;
  168. BEGIN
  169. u := w.link; WHILE u.link # w DO u := u.link END;
  170. u.link := w.link;
  171. f := w.frame; s := w.seq;
  172. IF ~w.sub THEN s.Notify(msg) END;
  173. WITH s: StdSequencer DO
  174. IF s.home = w THEN s.home := NIL END
  175. ELSE
  176. END;
  177. w.port.SetSize(0, 0); Views.AdaptRoot(w.frame);
  178. w.port := NIL; w.frame := NIL; w.doc := NIL; w.seq := NIL; w.link := NIL; w.loc := NIL;
  179. f.Close
  180. END Close;
  181. (** Directory **)
  182. PROCEDURE (d: Directory) NewSequencer* (): Sequencers.Sequencer, NEW;
  183. VAR s: StdSequencer;
  184. BEGIN
  185. NEW(s); Reset(s); RETURN s
  186. END NewSequencer;
  187. PROCEDURE (d: Directory) First* (): Window, NEW, ABSTRACT;
  188. PROCEDURE (d: Directory) Next* (w: Window): Window, NEW, ABSTRACT;
  189. PROCEDURE (d: Directory) New* (): Window, NEW, ABSTRACT;
  190. PROCEDURE (d: Directory) Open* (w: Window; doc: Documents.Document;
  191. flags: SET; name: Views.Title;
  192. loc: Files.Locator; fname: Files.Name;
  193. conv: Converters.Converter),
  194. NEW, EXTENSIBLE;
  195. VAR v: Views.View; c: RootContext; s: Sequencers.Sequencer; f: Views.Frame; any: ANYPTR;
  196. BEGIN
  197. ASSERT(w # NIL, 20); ASSERT(doc # NIL, 21); ASSERT(doc.context = NIL, 22);
  198. v := doc.ThisView(); ASSERT(v # NIL, 23);
  199. ASSERT(w.doc = NIL, 24); ASSERT(w.port # NIL, 25);
  200. IF w.link = NIL THEN w.link := w END; (* create new window ring *)
  201. w.doc := doc; w.flags := flags;
  202. IF w.seq = NIL THEN
  203. ASSERT(doc.Domain() # NIL, 27);
  204. any := doc.Domain().GetSequencer();
  205. IF any # NIL THEN
  206. ASSERT(any IS Sequencers.Sequencer, 26);
  207. w.seq := any(Sequencers.Sequencer)
  208. ELSE
  209. w.seq := d.NewSequencer();
  210. doc.Domain().SetSequencer(w.seq)
  211. END
  212. END;
  213. s := w.seq;
  214. WITH s: StdSequencer DO
  215. IF s.home = NIL THEN s.home := w END
  216. ELSE
  217. END;
  218. NEW(c); c.win := w; doc.InitContext(c);
  219. doc.GetNewFrame(f); w.frame := f(Views.RootFrame);
  220. w.frame.ConnectTo(w.port);
  221. Views.SetRoot(w.frame, w.doc, FALSE, w.flags);
  222. w.SetSpec(loc, fname, conv)
  223. END Open;
  224. PROCEDURE (d: Directory) OpenSubWindow* (w: Window; doc: Documents.Document; flags: SET; name: Views.Title), NEW, EXTENSIBLE;
  225. VAR u: Window; title: Views.Title;
  226. BEGIN
  227. ASSERT(w # NIL, 20); ASSERT(doc # NIL, 21);
  228. u := d.First(); WHILE (u # NIL) & (u.seq # doc.Domain().GetSequencer()) DO u := d.Next(u) END;
  229. IF u # NIL THEN
  230. w.sub := TRUE;
  231. w.link := u.link; u.link := w;
  232. w.seq := u.seq; w.loc := u.loc; w.name := u.name; w.conv := u.conv;
  233. u.GetTitle(title);
  234. d.Open(w, doc, flags, title, u.loc, u.name, u.conv)
  235. ELSE
  236. d.Open(w, doc, flags, name, NIL, "", NIL)
  237. END
  238. END OpenSubWindow;
  239. PROCEDURE ^ RestoreSequencer(seq: Sequencers.Sequencer);
  240. PROCEDURE (d: Directory) Focus* (target: BOOLEAN): Window, NEW, ABSTRACT;
  241. PROCEDURE (d: Directory) GetThisWindow* (p: Ports.Port; px, py: INTEGER; OUT x, y: INTEGER; OUT w: Window), NEW, ABSTRACT;
  242. PROCEDURE (d: Directory) Select* (w: Window; lazy: BOOLEAN), NEW, ABSTRACT;
  243. PROCEDURE (d: Directory) Close* (w: Window), NEW, ABSTRACT;
  244. PROCEDURE (d: Directory) Update* (w: Window), NEW;
  245. VAR u: Window;
  246. BEGIN
  247. (* redraws the BlackBox region of a given window, or of all windows *)
  248. u := d.First();
  249. WHILE u # NIL DO
  250. ASSERT(u.frame # NIL, 101);
  251. IF (u = w) OR (w = NIL) THEN RestoreSequencer(u.seq) END;
  252. u := d.Next(u)
  253. END
  254. END Update;
  255. PROCEDURE (d: Directory) GetBounds* (OUT w, h: INTEGER), NEW, ABSTRACT;
  256. (* RootContext *)
  257. PROCEDURE (c: RootContext) GetSize (OUT w, h: INTEGER);
  258. BEGIN
  259. c.win.port.GetSize(w, h);
  260. w := w * c.win.port.unit; h := h * c.win.port.unit
  261. END GetSize;
  262. PROCEDURE (c: RootContext) SetSize (w, h: INTEGER);
  263. END SetSize;
  264. PROCEDURE (c: RootContext) Normalize (): BOOLEAN;
  265. BEGIN
  266. RETURN TRUE
  267. END Normalize;
  268. PROCEDURE (c: RootContext) ThisModel (): Models.Model;
  269. BEGIN
  270. RETURN NIL
  271. END ThisModel;
  272. (* sequencing utilities *)
  273. PROCEDURE Prepend (s: Script; st: Stores.Store; IN name: Stores.OpName; op: Stores.Operation);
  274. VAR e: OpElem;
  275. BEGIN
  276. ASSERT(op # NIL, 20);
  277. NEW(e); e.st := st; e.op := op; e.name := name;
  278. e.next := s.list; s.list := e
  279. END Prepend;
  280. PROCEDURE Push (VAR list, e: OpElem);
  281. BEGIN
  282. e.next := list; list := e
  283. END Push;
  284. PROCEDURE Pop (VAR list, e: OpElem);
  285. BEGIN
  286. e := list; list := list.next
  287. END Pop;
  288. PROCEDURE Reduce (VAR list: OpElem; max: INTEGER);
  289. VAR e: OpElem;
  290. BEGIN
  291. e := list; WHILE (max > 1) & (e # NIL) DO DEC(max); e := e.next END;
  292. IF e # NIL THEN e.next := NIL END
  293. END Reduce;
  294. PROCEDURE (r: Reducer) Reduce (full: BOOLEAN);
  295. VAR e: OpElem; n: INTEGER; w: Window;
  296. BEGIN
  297. IF dir # NIL THEN
  298. w := dir.First();
  299. WHILE w # NIL DO
  300. IF w.seq IS StdSequencer THEN
  301. IF full THEN
  302. n := 1
  303. ELSE
  304. n := 0; e := w.seq(StdSequencer).undo;
  305. WHILE e # NIL DO INC(n); e := e.next END;
  306. IF n > 20 THEN n := n DIV 2 ELSE n := 10 END
  307. END;
  308. Reduce(w.seq(StdSequencer).undo, n)
  309. END;
  310. w := dir.Next(w)
  311. END
  312. END;
  313. Kernel.InstallReducer(r)
  314. END Reduce;
  315. PROCEDURE Reset (s: StdSequencer);
  316. BEGIN
  317. s.trapEra := Kernel.trapCount;
  318. IF (s.entryLevel # 0) OR (s.nestLevel # 0) THEN
  319. s.modLevel := 0;
  320. s.entryLevel := 0;
  321. s.nestLevel := 0;
  322. s.lastSt := NIL;
  323. s.lastOp := NIL;
  324. s.script := NIL;
  325. s.noUndo := FALSE;
  326. s.undo := NIL; s.redo := NIL;
  327. s.invisibleLevel := 0;
  328. s.transparentLevel := 0;
  329. s.notRecordedLevel := 0
  330. END
  331. END Reset;
  332. PROCEDURE Neutralize (st: Stores.Store);
  333. VAR neutralize: Models.NeutralizeMsg;
  334. BEGIN
  335. IF st # NIL THEN (* st = NIL for scripts *)
  336. WITH st: Models.Model DO
  337. Models.Broadcast(st, neutralize)
  338. | st: Views.View DO
  339. st.Neutralize
  340. ELSE
  341. END
  342. END
  343. END Neutralize;
  344. PROCEDURE Do (s: StdSequencer; st: Stores.Store; op: Stores.Operation);
  345. BEGIN
  346. INC(s.entryLevel); s.lastSt := NIL; s.lastOp := NIL;
  347. Neutralize(st); op.Do;
  348. DEC(s.entryLevel)
  349. END Do;
  350. PROCEDURE AffectsDoc (s: StdSequencer; st: Stores.Store): BOOLEAN;
  351. VAR v, w: Window;
  352. BEGIN
  353. w := s.home;
  354. IF (w = NIL) OR (st = w.doc) OR (st = w.doc.ThisView()) THEN
  355. RETURN TRUE
  356. ELSE
  357. v := w.link;
  358. WHILE (v # w) & (st # v.doc) & (st # v.doc.ThisView()) DO v := v.link END;
  359. RETURN v = w
  360. END
  361. END AffectsDoc;
  362. (* Script *)
  363. PROCEDURE (s: Script) Do;
  364. VAR e, f, g: OpElem;
  365. BEGIN
  366. e := s.list; f := NIL;
  367. REPEAT
  368. Neutralize(e.st); e.op.Do;
  369. g := e.next; e.next := f; f := e; e := g
  370. UNTIL e = NIL;
  371. s.list := f
  372. END Do;
  373. (* StdSequencer *)
  374. PROCEDURE (s: StdSequencer) Handle (VAR msg: ANYREC);
  375. (* send message to all windows attached to s *)
  376. VAR w: Window;
  377. BEGIN
  378. IF s.trapEra # Kernel.trapCount THEN Reset(s) END;
  379. WITH msg: Models.Message DO
  380. IF msg IS Models.UpdateMsg THEN
  381. Properties.IncEra;
  382. IF s.entryLevel = 0 THEN
  383. (* updates in dominated model bypassed the sequencer *)
  384. Reset(s); (* panic reset: clear sequencer *)
  385. INC(s.modLevel) (* but leave dirty *)
  386. END
  387. END;
  388. w := dir.First();
  389. WHILE w # NIL DO
  390. IF w.seq = s THEN w.BroadcastModelMsg(msg) END;
  391. w := dir.Next(w)
  392. END
  393. | msg: Views.Message DO
  394. w := dir.First();
  395. WHILE w # NIL DO
  396. IF w.seq = s THEN w.BroadcastViewMsg(msg) END;
  397. w := dir.Next(w)
  398. END
  399. ELSE
  400. END
  401. END Handle;
  402. PROCEDURE (s: StdSequencer) Dirty (): BOOLEAN;
  403. BEGIN
  404. RETURN s.modLevel > 0
  405. END Dirty;
  406. PROCEDURE (s: StdSequencer) SetDirty (dirty: BOOLEAN);
  407. BEGIN
  408. IF dirty THEN INC(s.modLevel) ELSE s.modLevel := 0 END
  409. END SetDirty;
  410. PROCEDURE (s: StdSequencer) LastOp (st: Stores.Store): Stores.Operation;
  411. BEGIN
  412. ASSERT(st # NIL, 20);
  413. IF s.lastSt = st THEN RETURN s.lastOp ELSE RETURN NIL END
  414. END LastOp;
  415. PROCEDURE (s: StdSequencer) BeginScript (IN name: Stores.OpName; VAR script: Stores.Operation);
  416. VAR sop: Script;
  417. BEGIN
  418. IF s.trapEra # Kernel.trapCount THEN Reset(s) END;
  419. INC(s.nestLevel);
  420. IF (s.nestLevel = 1) & (s.invisibleLevel = 0) & (s.transparentLevel = 0) & (s.notRecordedLevel = 0) THEN
  421. INC(s.modLevel)
  422. END;
  423. s.lastSt := NIL; s.lastOp := NIL;
  424. NEW(sop); sop.up := s.script; sop.list := NIL; sop.level := s.nestLevel; sop.name := name;
  425. s.script := sop;
  426. script := sop
  427. END BeginScript;
  428. PROCEDURE (s: StdSequencer) Do (st: Stores.Store; IN name: Stores.OpName; op: Stores.Operation);
  429. VAR e: OpElem;
  430. BEGIN
  431. ASSERT(st # NIL, 20); ASSERT(op # NIL, 21);
  432. IF s.trapEra # Kernel.trapCount THEN Reset(s) END;
  433. Do(s, st, op);
  434. IF s.noUndo THEN (* cannot undo: unbalanced BeginModification pending *)
  435. s.lastSt := NIL; s.lastOp := NIL
  436. ELSIF (s.entryLevel = 0) (* don't record when called from within op.Do *)
  437. & AffectsDoc(s, st) THEN (* don't record when Do affected child window only *)
  438. s.lastSt := st; s.lastOp := op;
  439. s.redo := NIL; (* clear redo stack *)
  440. IF s.script # NIL THEN
  441. Prepend(s.script, st, name, op)
  442. ELSE
  443. IF (s.invisibleLevel = 0) & (s.transparentLevel = 0) & (s.notRecordedLevel = 0) THEN INC(s.modLevel) END;
  444. NEW(e); e.st := st; e.op := op; e.name := name;
  445. e.invisible := s.invisibleLevel > 0; e.transparent := s.transparentLevel > 0;
  446. IF (s.notRecordedLevel=0) THEN Push(s.undo, e) END
  447. END
  448. END
  449. END Do;
  450. PROCEDURE (s: StdSequencer) Bunch (st: Stores.Store);
  451. VAR lastOp: Stores.Operation;
  452. BEGIN
  453. IF s.trapEra # Kernel.trapCount THEN Reset(s) END;
  454. ASSERT(st # NIL, 20); ASSERT(st = s.lastSt, 21);
  455. lastOp := s.lastOp;
  456. Do(s, st, lastOp);
  457. IF s.noUndo THEN
  458. s.lastSt := NIL; s.lastOp := NIL
  459. ELSIF (s.entryLevel = 0) (* don't record when called from within op.Do *)
  460. & AffectsDoc(s, st) THEN (* don't record when Do affected child window only *)
  461. s.lastSt := st; s.lastOp := lastOp
  462. END
  463. END Bunch;
  464. PROCEDURE (s: StdSequencer) EndScript (script: Stores.Operation);
  465. VAR e: OpElem;
  466. BEGIN
  467. IF s.trapEra # Kernel.trapCount THEN Reset(s) END;
  468. ASSERT(script # NIL, 20); ASSERT(s.script = script, 21);
  469. WITH script: Script DO
  470. ASSERT(s.nestLevel = script.level, 22);
  471. s.script := script.up;
  472. IF s.entryLevel = 0 THEN (* don't record when called from within op.Do *)
  473. IF script.list # NIL THEN
  474. IF s.script # NIL THEN
  475. Prepend(s.script, NIL, script.name, script)
  476. ELSE (* outermost scripting level *)
  477. s.redo := NIL; (* clear redo stack *)
  478. IF ~s.noUndo THEN
  479. NEW(e); e.st := NIL; e.op := script; e.name := script.name;
  480. e.invisible := s.invisibleLevel > 0; e.transparent := s.transparentLevel > 0;
  481. IF s.notRecordedLevel=0 THEN Push(s.undo, e) END
  482. END;
  483. s.lastSt := NIL; s.lastOp := NIL
  484. END
  485. ELSE
  486. IF (s.script = NIL) & (s.modLevel > 0) & (s.invisibleLevel = 0) & (s.transparentLevel = 0) THEN
  487. DEC(s.modLevel)
  488. END
  489. END
  490. END
  491. END;
  492. DEC(s.nestLevel);
  493. IF s.nestLevel = 0 THEN ASSERT(s.script = NIL, 22); s.noUndo := FALSE END
  494. END EndScript;
  495. PROCEDURE (s: StdSequencer) StopBunching;
  496. BEGIN
  497. s.lastSt := NIL; s.lastOp := NIL
  498. END StopBunching;
  499. PROCEDURE (s: StdSequencer) BeginModification (type: INTEGER; st: Stores.Store);
  500. BEGIN
  501. IF s.trapEra # Kernel.trapCount THEN Reset(s) END;
  502. IF s.nestLevel < LEN(s.modStack) THEN s.modStack[s.nestLevel].store := st; s.modStack[s.nestLevel].type := type END;
  503. INC(s.nestLevel);
  504. IF type = Sequencers.notUndoable THEN
  505. INC(s.modLevel); (* unbalanced! *)
  506. s.noUndo := TRUE; s.undo := NIL; s.redo := NIL;
  507. s.lastSt := NIL; s.lastOp := NIL;
  508. INC(s.entryLevel) (* virtual entry of modification "operation" *)
  509. ELSIF type = Sequencers.invisible THEN
  510. INC(s.invisibleLevel)
  511. ELSIF type = Sequencers.clean THEN
  512. INC(s.transparentLevel)
  513. ELSIF type = notRecorded THEN
  514. INC(s.notRecordedLevel)
  515. END
  516. END BeginModification;
  517. PROCEDURE (s: StdSequencer) EndModification (type: INTEGER; st: Stores.Store);
  518. BEGIN
  519. IF s.trapEra # Kernel.trapCount THEN Reset(s) END;
  520. ASSERT(s.nestLevel > 0, 20);
  521. IF s.nestLevel <= LEN(s.modStack) THEN
  522. ASSERT((s.modStack[s.nestLevel - 1].store = st) & (s.modStack[s.nestLevel - 1].type = type), 21)
  523. END;
  524. DEC(s.nestLevel);
  525. IF type = Sequencers.notUndoable THEN
  526. DEC(s.entryLevel)
  527. ELSIF type = Sequencers.invisible THEN
  528. DEC(s.invisibleLevel)
  529. ELSIF type = Sequencers.clean THEN
  530. DEC(s.transparentLevel)
  531. ELSIF type = notRecorded THEN
  532. DEC(s.notRecordedLevel)
  533. END;
  534. IF s.nestLevel = 0 THEN ASSERT(s.script = NIL, 22); s.noUndo := FALSE END
  535. END EndModification;
  536. PROCEDURE (s: StdSequencer) CanUndo (): BOOLEAN;
  537. VAR op: OpElem;
  538. BEGIN
  539. IF s.trapEra # Kernel.trapCount THEN Reset(s) END;
  540. op := s.undo;
  541. WHILE (op # NIL) & op.invisible DO op := op.next END;
  542. RETURN op # NIL
  543. END CanUndo;
  544. PROCEDURE (s: StdSequencer) CanRedo (): BOOLEAN;
  545. VAR op: OpElem;
  546. BEGIN
  547. IF s.trapEra # Kernel.trapCount THEN Reset(s) END;
  548. op := s.redo;
  549. WHILE (op # NIL) & op.invisible DO op := op.next END;
  550. RETURN op # NIL
  551. END CanRedo;
  552. PROCEDURE (s: StdSequencer) GetUndoName (VAR name: Stores.OpName);
  553. VAR op: OpElem;
  554. BEGIN
  555. IF s.trapEra # Kernel.trapCount THEN Reset(s) END;
  556. op := s.undo;
  557. WHILE (op # NIL) & op.invisible DO op := op.next END;
  558. IF op # NIL THEN name := op.name$ ELSE name[0] := 0X END
  559. END GetUndoName;
  560. PROCEDURE (s: StdSequencer) GetRedoName (VAR name: Stores.OpName);
  561. VAR op: OpElem;
  562. BEGIN
  563. IF s.trapEra # Kernel.trapCount THEN Reset(s) END;
  564. op := s.redo;
  565. WHILE (op # NIL) & op.invisible DO op := op.next END;
  566. IF op # NIL THEN name := op.name$ ELSE name[0] := 0X END
  567. END GetRedoName;
  568. PROCEDURE (s: StdSequencer) Undo;
  569. VAR e: OpElem;
  570. BEGIN
  571. IF s.trapEra # Kernel.trapCount THEN Reset(s) END;
  572. IF s.undo # NIL THEN
  573. REPEAT
  574. Pop(s.undo, e); Do(s, e.st, e.op); Push(s.redo, e)
  575. UNTIL ~e.invisible OR (s.undo = NIL);
  576. IF ~e.transparent THEN
  577. IF s.modLevel > 0 THEN DEC(s.modLevel) END
  578. END
  579. END
  580. END Undo;
  581. PROCEDURE (s: StdSequencer) Redo;
  582. VAR e: OpElem;
  583. BEGIN
  584. IF s.trapEra # Kernel.trapCount THEN Reset(s) END;
  585. IF s.redo # NIL THEN
  586. Pop(s.redo, e); Do(s, e.st, e.op); Push(s.undo, e);
  587. WHILE (s.redo # NIL) & s.redo.invisible DO
  588. Pop(s.redo, e); Do(s, e.st, e.op); Push(s.undo, e)
  589. END;
  590. IF ~e.transparent THEN
  591. INC(s.modLevel)
  592. END
  593. END
  594. END Redo;
  595. (* Forwarder *)
  596. PROCEDURE (f: Forwarder) Forward (target: BOOLEAN; VAR msg: Controllers.Message);
  597. VAR w: Window;
  598. BEGIN
  599. w := dir.Focus(target);
  600. IF w # NIL THEN w.ForwardCtrlMsg(msg) END
  601. END Forward;
  602. PROCEDURE (f: Forwarder) Transfer (VAR msg: Controllers.TransferMessage);
  603. VAR w: Window; h: Views.Frame; p: Ports.Port; sx, sy, tx, ty, pw, ph: INTEGER;
  604. BEGIN
  605. h := msg.source; p := h.rider.Base();
  606. (* (msg.x, msg.y) is point in local coordinates of source frame *)
  607. sx := (msg.x + h.gx) DIV h.unit;
  608. sy := (msg.y + h.gy) DIV h.unit;
  609. (* (sx, sy) is point in global coordinates of source port *)
  610. dir.GetThisWindow(p, sx, sy, tx, ty, w);
  611. IF w # NIL THEN
  612. (* (tx, ty) is point in global coordinates of target port *)
  613. w.port.GetSize(pw, ph);
  614. msg.x := tx * w.port.unit;
  615. msg.y := ty * w.port.unit;
  616. (* (msg.x, msg.y) is point in coordinates of target window *)
  617. w.ForwardCtrlMsg(msg)
  618. END
  619. END Transfer;
  620. (** miscellaneous **)
  621. PROCEDURE SetDir* (d: Directory);
  622. BEGIN
  623. ASSERT(d # NIL, 20);
  624. IF stdDir = NIL THEN stdDir := d END;
  625. dir := d
  626. END SetDir;
  627. PROCEDURE SelectBySpec* (loc: Files.Locator; name: Files.Name; conv: Converters.Converter; VAR done: BOOLEAN);
  628. VAR w: Window;
  629. BEGIN
  630. Kernel.MakeFileName(name, "");
  631. w := dir.First();
  632. WHILE (w # NIL) & ((loc = NIL) OR (w.loc = NIL) OR (loc.res = 77) OR (w.loc.res = 77) OR
  633. (name = "") OR (w.name = "") OR
  634. ~Files.dir.SameFile(loc, name, w.loc, w.name) OR (w.conv # conv)) DO
  635. w := dir.Next(w)
  636. END;
  637. IF w # NIL THEN dir.Select(w, lazy); done := TRUE ELSE done := FALSE END
  638. END SelectBySpec;
  639. PROCEDURE SelectByTitle* (v: Views.View; flags: SET; title: Views.Title; VAR done: BOOLEAN);
  640. VAR w: Window; t: Views.Title; n1, n2: ARRAY 64 OF CHAR;
  641. BEGIN
  642. done := FALSE;
  643. IF v # NIL THEN
  644. IF v IS Documents.Document THEN v := v(Documents.Document).ThisView() END;
  645. Services.GetTypeName(v, n1)
  646. ELSE n1 := ""
  647. END;
  648. w := dir.First();
  649. WHILE w # NIL DO
  650. IF ((w.flags / flags) * {isAux, isTool} = {}) & ~(allowDuplicates IN w.flags) THEN
  651. w.GetTitle(t);
  652. IF t = title THEN
  653. Services.GetTypeName(w.doc.ThisView(), n2);
  654. IF (n1 = "") OR (n1 = n2) THEN dir.Select(w, lazy); done := TRUE; RETURN END
  655. END
  656. END;
  657. w := dir.Next(w)
  658. END
  659. END SelectByTitle;
  660. PROCEDURE (h: Hook) Omnicast (VAR msg: ANYREC);
  661. VAR w: Window;
  662. BEGIN
  663. w := dir.First();
  664. WHILE w # NIL DO
  665. IF ~w.sub THEN w.seq.Handle(msg) END;
  666. w := dir.Next(w)
  667. END
  668. END Omnicast;
  669. PROCEDURE RestoreSequencer (seq: Sequencers.Sequencer);
  670. VAR w: Window;
  671. BEGIN
  672. w := dir.First();
  673. WHILE w # NIL DO
  674. ASSERT(w.frame # NIL, 100);
  675. IF (seq = NIL) OR (w.seq = seq) THEN
  676. w.Update (* causes redrawing of BlackBox region *)
  677. END;
  678. w := dir.Next(w)
  679. END
  680. END RestoreSequencer;
  681. PROCEDURE (h: Hook) RestoreDomain (d: Stores.Domain);
  682. VAR seq: ANYPTR;
  683. BEGIN
  684. IF d = NIL THEN
  685. RestoreSequencer(NIL)
  686. ELSE
  687. seq := d.GetSequencer();
  688. IF seq # NIL THEN
  689. RestoreSequencer (seq(Sequencers.Sequencer))
  690. END
  691. END
  692. END RestoreDomain;
  693. (* SequencerDirectory *)
  694. PROCEDURE (d: SequencerDirectory) New (): Sequencers.Sequencer;
  695. BEGIN
  696. RETURN dir.NewSequencer()
  697. END New;
  698. (** CheckAction **)
  699. PROCEDURE (a: CheckAction) Do;
  700. VAR w: Window; s: StdSequencer;
  701. BEGIN
  702. Services.DoLater(a.wait, Services.resolution);
  703. w := dir.First();
  704. WHILE w # NIL DO
  705. s := w.seq(StdSequencer);
  706. IF s.trapEra # Kernel.trapCount THEN Reset(s) END;
  707. ASSERT(s.nestLevel = 0, 100);
  708. (* unbalanced calls of Views.BeginModification/EndModification or Views.BeginScript/EndScript *)
  709. w := dir.Next(w)
  710. END
  711. END Do;
  712. PROCEDURE (a: WaitAction) Do;
  713. BEGIN
  714. Services.DoLater(a.check, Services.immediately)
  715. END Do;
  716. PROCEDURE (n: LangNotifier) Notify;
  717. VAR w: Window; pw, ph: INTEGER;
  718. BEGIN
  719. w := dir.First();
  720. WHILE w # NIL DO
  721. w.port.GetSize(pw, ph);
  722. w.Restore(0, 0, pw, ph);
  723. w.RefreshTitle;
  724. w := dir.Next(w)
  725. END
  726. END Notify;
  727. PROCEDURE Init;
  728. VAR f: Forwarder; r: Reducer; sdir: SequencerDirectory;
  729. a: CheckAction; w: WaitAction; h: Hook; ln: LangNotifier;
  730. BEGIN
  731. NEW(sdir); Sequencers.SetDir(sdir);
  732. NEW(h); Views.SetMsgHook(h);
  733. NEW(f); Controllers.Register(f);
  734. NEW(r); Kernel.InstallReducer(r);
  735. NEW(a); NEW(w); a.wait := w; w.check := a; Services.DoLater(a, Services.immediately);
  736. NEW(ln); Dialog.RegisterLangNotifier(ln)
  737. END Init;
  738. BEGIN
  739. Init
  740. END Windows.