Views.txt 50 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579
  1. MODULE TextViews;
  2. (* THIS IS TEXT COPY OF BlackBox 1.6-rc6 Text/Mod/Views.odc *)
  3. (* DO NOT EDIT *)
  4. (* could use +, $ in DrawLine cache implementation *)
  5. IMPORT
  6. Services, Fonts, Ports, Stores,
  7. Models, Views, Controllers, Properties, Dialog, Printing, Containers,
  8. TextModels, TextRulers, TextSetters;
  9. CONST
  10. (** v.DisplayMarks hide *)
  11. show* = FALSE; hide* = TRUE;
  12. (** v.ShowRange focusOnly **)
  13. any* = FALSE; focusOnly* = TRUE;
  14. parasign = 0B6X; (* paragraph sign, to mark non-ruler paragraph breaks *)
  15. mm = Ports.mm; inch16 = Ports.inch DIV 16; point = Ports.point;
  16. maxScrollHeight = 16 * point; maxScrollSteps = 100; fuseScrollHeight = maxScrollHeight DIV 2;
  17. maxHeight = maxScrollHeight * maxScrollSteps;
  18. adjustMask = {TextRulers.leftAdjust, TextRulers.rightAdjust};
  19. (* SetOp.mode *)
  20. setMarks = 0; setSetter = 1; setDefs = 2;
  21. scrollingKey = "#System:Scrolling";
  22. viewSettingKey = "#System:ViewSetting";
  23. minVersion = 0; maxVersion = 0; maxStdVersion = 0;
  24. TYPE
  25. View* = POINTER TO ABSTRACT RECORD (Containers.View) END;
  26. Directory* = POINTER TO ABSTRACT RECORD
  27. defAttr-: TextModels.Attributes
  28. END;
  29. Location* = RECORD
  30. (** start of line and position of location **)
  31. start*, pos*: INTEGER;
  32. (** coordinates of location **)
  33. x*, y*: INTEGER;
  34. (** line dimensions at location **)
  35. asc*, dsc*: INTEGER;
  36. (** if view at location: **)
  37. view*: Views.View;
  38. l*, t*, r*, b*: INTEGER
  39. END;
  40. PositionMsg* = RECORD (Models.Message)
  41. focusOnly*: BOOLEAN;
  42. beg*, end*: INTEGER
  43. END;
  44. PageMsg* = RECORD (Properties.Message)
  45. current*: INTEGER
  46. END;
  47. Line = POINTER TO RECORD
  48. next: Line;
  49. start, asc, h: INTEGER;
  50. attr: TextRulers.Attributes; (* attr = box.ruler.style.attr *)
  51. box: TextSetters.LineBox (* caching of box.rpos not consistent *)
  52. END;
  53. StdView = POINTER TO RECORD (View)
  54. (* model *)
  55. text: TextModels.Model;
  56. org: INTEGER;
  57. dy: INTEGER; (* 0 <= dy < Height(first line) *)
  58. defRuler: TextRulers.Ruler;
  59. defAttr: TextModels.Attributes;
  60. hideMarks: BOOLEAN;
  61. (* general state *)
  62. cachedRd: TextSetters.Reader;
  63. (* line grid cache *)
  64. trailer: Line; (* trailer # NIL => trailer.eot, trailer.next # trailer *)
  65. bot: INTEGER; (* max(f : f seen by Restore : f.b) *)
  66. (* setter *)
  67. setter, setter0: TextSetters.Setter (* setter # setter0 lazily detects setter change *)
  68. END;
  69. StdDirectory = POINTER TO RECORD (Directory) END;
  70. ScrollOp = POINTER TO RECORD (Stores.Operation)
  71. v: StdView;
  72. org, dy: INTEGER;
  73. bunchOrg, bunchDy: INTEGER;
  74. bunch: BOOLEAN; (* bunch => bunchOrg, bunchDy valid *)
  75. silent: BOOLEAN (* original caller of Do(op) already handled situation *)
  76. END;
  77. SetOp = POINTER TO RECORD (Stores.Operation)
  78. mode: INTEGER;
  79. view: StdView;
  80. hideMarks: BOOLEAN;
  81. setter: TextSetters.Setter;
  82. defRuler: TextRulers.Ruler;
  83. defAttr: TextModels.Attributes
  84. END;
  85. FindAnyFrameMsg = RECORD (Views.Message)
  86. (* find frame with smallest height (frame.b - frame.t) that displays view; NIL if none found *)
  87. frame: Views.Frame (* OUT, initially NIL *)
  88. END;
  89. FindFocusFrameMsg = RECORD (Controllers.Message)
  90. (* find outermost focus frame displaying view; NIL if none found *)
  91. view: Views.View; (* IN *)
  92. frame: Views.Frame (* OUT, initially NIL *)
  93. END;
  94. VAR
  95. ctrlDir-: Containers.Directory;
  96. dir-, stdDir-: Directory;
  97. (* forward used in GetStart, UpdateView, ShowRangeIn *)
  98. PROCEDURE ^ DoSetOrigin (v: StdView; org, dy: INTEGER; silent: BOOLEAN);
  99. (** View **)
  100. PROCEDURE (v: View) Internalize2- (VAR rd: Stores.Reader), EXTENSIBLE;
  101. (** pre: ~v.init **)
  102. (** post: v.init **)
  103. VAR thisVersion: INTEGER;
  104. BEGIN
  105. (*v.Internalize^(rd);*)
  106. IF rd.cancelled THEN RETURN END;
  107. rd.ReadVersion(minVersion, maxVersion, thisVersion)
  108. END Internalize2;
  109. PROCEDURE (v: View) Externalize2- (VAR wr: Stores.Writer), EXTENSIBLE;
  110. (** pre: v.init **)
  111. BEGIN
  112. (*v.Externalize^(wr);*)
  113. wr.WriteVersion(maxVersion)
  114. END Externalize2;
  115. PROCEDURE (v: View) ThisModel* (): TextModels.Model, EXTENSIBLE;
  116. VAR m: Containers.Model;
  117. BEGIN
  118. m := v.ThisModel^();
  119. IF m # NIL THEN
  120. RETURN m(TextModels.Model)
  121. ELSE
  122. RETURN NIL
  123. END
  124. END ThisModel;
  125. PROCEDURE (v: View) DisplayMarks* (hide: BOOLEAN), NEW, ABSTRACT;
  126. PROCEDURE (v: View) HidesMarks* (): BOOLEAN, NEW, ABSTRACT;
  127. PROCEDURE (v: View) SetSetter* (setter: TextSetters.Setter), NEW, ABSTRACT;
  128. PROCEDURE (v: View) ThisSetter* (): TextSetters.Setter, NEW, ABSTRACT;
  129. PROCEDURE (v: View) SetOrigin* (org, dy: INTEGER), NEW, ABSTRACT;
  130. (** post: org = ThisLine(org) => v.org = org, v.dy = dy; else v.org = ThisLine(org), v.dy = 0 **)
  131. PROCEDURE (v: View) PollOrigin* (OUT org, dy: INTEGER), NEW, ABSTRACT;
  132. PROCEDURE (v: View) SetDefaults* (r: TextRulers.Ruler; a: TextModels.Attributes),
  133. NEW, ABSTRACT;
  134. (** pre: r.init, a.init **)
  135. PROCEDURE (v: View) PollDefaults* (OUT r: TextRulers.Ruler; OUT a: TextModels.Attributes),
  136. NEW, ABSTRACT;
  137. PROCEDURE (v: View) GetThisLocation* (f: Views.Frame; pos: INTEGER; OUT loc: Location),
  138. NEW, ABSTRACT;
  139. PROCEDURE (v: View) GetRect* (f: Views.Frame; view: Views.View; OUT l, t, r, b: INTEGER);
  140. VAR con: Models.Context; loc: Location; pos: INTEGER;
  141. BEGIN
  142. con := view.context;
  143. ASSERT(con # NIL, 20); ASSERT(con.ThisModel() = v.ThisModel(), 21);
  144. pos := con(TextModels.Context).Pos();
  145. v.GetThisLocation(f, pos, loc);
  146. IF loc.view = view THEN
  147. l := loc.l; t := loc.t; r := loc.r; b := loc.b
  148. ELSE
  149. l := MAX(INTEGER); t := MAX(INTEGER); r := l; b := t
  150. END
  151. END GetRect;
  152. PROCEDURE (v: View) GetRange* (f: Views.Frame; OUT beg, end: INTEGER), NEW, ABSTRACT;
  153. (** post: beg = beg of first visible line, end = end of last visible line **)
  154. PROCEDURE (v: View) ThisPos* (f: Views.Frame; x, y: INTEGER): INTEGER, NEW, ABSTRACT;
  155. PROCEDURE (v: View) ShowRangeIn* (f: Views.Frame; beg, end: INTEGER), NEW, ABSTRACT;
  156. PROCEDURE (v: View) ShowRange* (beg, end: INTEGER; focusOnly: BOOLEAN), NEW, ABSTRACT;
  157. (** post: in all frames (resp. in front or otherwise target frame if focusOnly):
  158. if possible, first visible pos <= k <= last visible pos,
  159. with k = beg if beg = end and beg <= k < end otherwise **)
  160. (** Directory **)
  161. PROCEDURE (d: Directory) Set* (defAttr: TextModels.Attributes), NEW, EXTENSIBLE;
  162. BEGIN
  163. ASSERT(defAttr # NIL, 20); ASSERT(defAttr.init, 21);
  164. d.defAttr := defAttr
  165. END Set;
  166. PROCEDURE (d: Directory) New* (text: TextModels.Model): View, NEW, ABSTRACT;
  167. (** miscellaneous **)
  168. PROCEDURE SetCtrlDir* (d: Containers.Directory);
  169. BEGIN
  170. ASSERT(d # NIL, 20); ctrlDir := d
  171. END SetCtrlDir;
  172. PROCEDURE SetDir* (d: Directory);
  173. BEGIN
  174. ASSERT(d # NIL, 20); dir := d
  175. END SetDir;
  176. PROCEDURE Focus* (): View;
  177. VAR v: Views.View;
  178. BEGIN
  179. v := Controllers.FocusView();
  180. IF (v # NIL) & (v IS View) THEN RETURN v(View) ELSE RETURN NIL END
  181. END Focus;
  182. PROCEDURE FocusText* (): TextModels.Model;
  183. VAR v: View;
  184. BEGIN
  185. v := Focus();
  186. IF v # NIL THEN RETURN v.ThisModel() ELSE RETURN NIL END
  187. END FocusText;
  188. PROCEDURE Deposit*;
  189. BEGIN
  190. Views.Deposit(dir.New(NIL))
  191. END Deposit;
  192. PROCEDURE ShowRange* (text: TextModels.Model; beg, end: INTEGER; focusOnly: BOOLEAN);
  193. (** post: in all front or target frames displaying a view displaying t:
  194. if possible, first visible pos <= k <= last visible pos,
  195. with k = beg if beg = end and beg <= k < end otherwise **)
  196. VAR pm: PositionMsg;
  197. BEGIN
  198. ASSERT(text # NIL, 20);
  199. pm.beg := beg; pm.end := end; pm.focusOnly := focusOnly;
  200. Models.Broadcast(text, pm)
  201. END ShowRange;
  202. PROCEDURE ThisRuler* (v: View; pos: INTEGER): TextRulers.Ruler;
  203. VAR r: TextRulers.Ruler; a: TextModels.Attributes; rpos: INTEGER;
  204. BEGIN
  205. v.PollDefaults(r, a); rpos := -1; TextRulers.GetValidRuler(v.ThisModel(), pos, -1, r, rpos);
  206. RETURN r
  207. END ThisRuler;
  208. (* auxiliary procedures *)
  209. PROCEDURE GetReader (v: StdView; start: INTEGER; IN box: TextSetters.LineBox
  210. ): TextSetters.Reader;
  211. VAR st: TextSetters.Setter; rd: TextSetters.Reader;
  212. BEGIN
  213. ASSERT(box.ruler # NIL, 100);
  214. st := v.ThisSetter();
  215. rd := v.cachedRd; v.cachedRd := NIL; (* reader recycling *)
  216. rd := st.NewReader(rd);
  217. rd.Set(rd.r, v.text, box.left, start, box.ruler, box.rpos, st.vw, st.hideMarks);
  218. RETURN rd
  219. END GetReader;
  220. PROCEDURE CacheReader (v: StdView; rd: TextSetters.Reader);
  221. BEGIN
  222. ASSERT(v.cachedRd = NIL, 20);
  223. v.cachedRd := rd
  224. END CacheReader;
  225. (* line descriptors *)
  226. PROCEDURE SetLineAsc (st: TextSetters.Setter; t: Line; dsc: INTEGER);
  227. (* pre: dsc: descender of previous line (-1 if first line) *)
  228. BEGIN
  229. t.asc := t.box.asc + st.GridOffset(dsc, t.box);
  230. t.h := t.asc + t.box.dsc
  231. END SetLineAsc;
  232. PROCEDURE NewLine (st: TextSetters.Setter; start, dsc: INTEGER): Line;
  233. (* pre: start: start of line to measure; dsc: descender of previous line (-1 if first line) *)
  234. VAR t: Line;
  235. BEGIN
  236. NEW(t); st.GetLine(start, t.box);
  237. t.start := start; SetLineAsc(st, t, dsc);
  238. t.attr := t.box.ruler.style.attr;
  239. RETURN t
  240. END NewLine;
  241. PROCEDURE AddLine (st: TextSetters.Setter; VAR t: Line; VAR start, y: INTEGER);
  242. BEGIN
  243. t.next := NewLine(st, start, t.box.dsc); t := t.next;
  244. INC(start, t.box.len); INC(y, t.h)
  245. END AddLine;
  246. PROCEDURE InitLines (v: StdView);
  247. VAR asc, dsc, w: INTEGER; t0, t: Line; start, y: INTEGER;
  248. BEGIN
  249. v.defAttr.font.GetBounds(asc, dsc, w);
  250. NEW(t0); start := v.org; y := v.dy;
  251. t0.box.dsc := -1; (* dsc = -1: trailer.next is first line *)
  252. t := t0; AddLine(v.ThisSetter(), t, start, y); t.next := t0; (* at least one valid line desc *)
  253. t0.start := start; t0.asc := asc; t0.h := asc + dsc; (* trailer.(asc, h) for caret display following last line *)
  254. t0.attr := NIL;
  255. t0.box.eot := TRUE; t0.box.len := 0;
  256. t0.box.ruler := NIL;
  257. t0.box.left := -1; (* make trailer async to every other line *)
  258. v.trailer := t0; v.bot := 0
  259. END InitLines;
  260. PROCEDURE ExtendLines (v: StdView; bot: INTEGER);
  261. VAR st: TextSetters.Setter; t0, t: Line; start, y: INTEGER;
  262. BEGIN
  263. IF bot >= v.bot THEN
  264. t0 := v.trailer; start := t0.start;
  265. y := v.dy; t := t0; WHILE t.next # t0 DO t := t.next; INC(y, t.h) END;
  266. IF (y < bot) & ~t.box.eot THEN
  267. st := v.ThisSetter();
  268. REPEAT AddLine(st, t, start, y) UNTIL (y >= bot) OR t.box.eot;
  269. t.next := t0; t0.start := start
  270. END;
  271. v.bot := bot
  272. END
  273. END ExtendLines;
  274. PROCEDURE ReduceLines (v: StdView; bot: INTEGER);
  275. VAR t0, t: Line; y: INTEGER;
  276. BEGIN
  277. IF bot <= v.bot THEN
  278. t0 := v.trailer; y := v.dy;
  279. t := t0; WHILE (t.next # t0) & (y < bot) DO t := t.next; INC(y, t.h) END;
  280. t0.start := t.next.start; t.next := t0;
  281. v.bot := bot
  282. END
  283. END ReduceLines;
  284. PROCEDURE ValidateLines (v: StdView; bot: INTEGER);
  285. VAR st: TextSetters.Setter; w, h, len: INTEGER;
  286. BEGIN
  287. IF v.setter # NIL THEN
  288. v.context.GetSize(w, h); (* possibly adapt to changed width *)
  289. IF v.setter.vw # w THEN v.setter0 := NIL; v.trailer := NIL END
  290. END;
  291. len := v.text.Length();
  292. IF (v.org > len) OR (v.trailer # NIL) & (v.trailer.start > len) THEN v.trailer := NIL END;
  293. IF v.trailer = NIL THEN
  294. IF v.org > len THEN v.org := len END;
  295. st := v.ThisSetter(); v.org := st.ThisLine(v.org);
  296. InitLines(v)
  297. END;
  298. ExtendLines(v, bot)
  299. END ValidateLines;
  300. PROCEDURE PrependLines (v: StdView);
  301. VAR st: TextSetters.Setter; t0, t1, t: Line; start, y: INTEGER;
  302. BEGIN
  303. t0 := v.trailer; start := v.org; y := v.dy;
  304. IF t0.start # start THEN
  305. st := v.ThisSetter();
  306. t := t0; t1 := t0.next;
  307. WHILE (t1.start # start) & (y < v.bot) DO AddLine(st, t, start, y) END;
  308. IF y >= v.bot THEN
  309. t.next := t0; t0.start := start
  310. ELSE
  311. t.next := t1;
  312. IF t1 # v.trailer THEN SetLineAsc(st, t1, t.box.dsc) END
  313. END
  314. END
  315. END PrependLines;
  316. (* update frame after insert/delete/replace *)
  317. PROCEDURE ThisViewLine (v: StdView; y: INTEGER): Line;
  318. (* pre: 0 <= y < v.bot *)
  319. VAR t: Line; py: INTEGER;
  320. BEGIN
  321. t := v.trailer.next; py := v.dy;
  322. WHILE ~t.box.eot & (py + t.h < y) DO INC(py, t.h); t := t.next END;
  323. RETURN t
  324. END ThisViewLine;
  325. PROCEDURE LocateThisLine (v: StdView; start: INTEGER; OUT t: Line; OUT y: INTEGER);
  326. VAR t1: Line;
  327. BEGIN
  328. t := v.trailer.next; y := v.dy;
  329. t1 := v.trailer.next;
  330. WHILE t.start # start DO INC(y, t.h); t := t.next; ASSERT(t # t1, 100) END
  331. END LocateThisLine;
  332. PROCEDURE GetStart (st: TextSetters.Setter; v: StdView; beg: INTEGER; OUT start: INTEGER);
  333. (* find start of line containing beg after text change; tuned using valid line descs *)
  334. VAR s, t: Line;
  335. BEGIN
  336. s := v.trailer; t := s.next;
  337. WHILE (t # v.trailer) & (t.start + t.box.len < beg) DO s := t; t := s.next END;
  338. IF s # v.trailer THEN (* at least first line desc possibly still valid *)
  339. start := st.NextLine(s.start); (* NextLine can be much cheaper than ThisLine *)
  340. IF start # t.start THEN
  341. GetStart(st, v, s.start, start)
  342. ELSIF ~t.box.eot & (start + t.box.len = beg) & (st.NextLine(start) = beg) THEN
  343. start := beg
  344. END
  345. ELSE
  346. IF v.org <= v.text.Length() THEN
  347. start := st.ThisLine(v.org)
  348. ELSE
  349. start := st.ThisLine(v.text.Length())
  350. END;
  351. IF start < v.org THEN
  352. DoSetOrigin(v, start, 0, TRUE)
  353. ELSIF start > v.org THEN
  354. start := v.org
  355. END
  356. END
  357. END GetStart;
  358. PROCEDURE GetStringStart (v: StdView; t: Line; pos: INTEGER; OUT p1, x: INTEGER);
  359. VAR rd: TextSetters.Reader;
  360. BEGIN
  361. p1 := t.start; x := t.box.left;
  362. IF t.box.views THEN
  363. rd := GetReader(v, p1, t.box); rd.Read;
  364. WHILE ~rd.eot & (rd.pos <= pos) DO
  365. rd.AdjustWidth(t.start, p1, t.box, rd.w); INC(rd.x, rd.w);
  366. IF rd.view # NIL THEN p1 := rd.pos; x := rd.x END;
  367. rd.Read
  368. END;
  369. CacheReader(v, rd)
  370. END
  371. END GetStringStart;
  372. PROCEDURE InSynch (t0, t1: Line): BOOLEAN;
  373. BEGIN
  374. RETURN (t0.start = t1.start) & (t0.asc = t1.asc) & (t0.attr = t1.attr)
  375. & (t0.box.left = t1.box.left) & (t0.box.asc = t1.box.asc) & (t0.box.dsc = t1.box.dsc)
  376. & (t0.box.rbox = t1.box.rbox) & (t0.box.bop = t1.box.bop)
  377. END InSynch;
  378. PROCEDURE RebuildView (v: StdView);
  379. BEGIN
  380. v.setter0 := NIL;
  381. IF v.trailer # NIL THEN v.trailer := NIL; v.bot := 0; Views.Update(v, Views.rebuildFrames) END
  382. END RebuildView;
  383. PROCEDURE UpdateIn (v: StdView; l, t, b: INTEGER);
  384. BEGIN
  385. Views.UpdateIn(v, l, t, MAX(INTEGER), b, Views.rebuildFrames)
  386. END UpdateIn;
  387. PROCEDURE UpdateFrames (v: StdView; t0, t1, u: Line; beg, y0, yu: INTEGER);
  388. VAR t, te: Line; b, x, b0, b1, top, bot: INTEGER;
  389. BEGIN
  390. IF ((beg < t0.next.start) OR t0.box.eot) & ~t0.box.adj
  391. & ((beg < t1.next.start) OR t1.box.eot) & ~t1.box.adj
  392. & InSynch(t0, t1) THEN
  393. GetStringStart(v, t1, beg, beg, x)
  394. ELSE
  395. beg := t1.start
  396. END;
  397. b := y0; t := t0; WHILE t # u DO INC(b, t.h); t := t.next END;
  398. IF b = yu THEN
  399. te := u
  400. ELSE (* t = u *)
  401. te := v.trailer;
  402. b0 := b; WHILE t # v.trailer DO INC(b0, t.h); t := t.next END;
  403. IF yu < b THEN ExtendLines(v, v.bot) ELSE ReduceLines(v, v.bot) END;
  404. b1 := y0; t := t1; WHILE t # v.trailer DO INC(b1, t.h); t := t.next END;
  405. IF b1 < b0 THEN UpdateIn(v, 0, b1, b0) END (* erase trailer *)
  406. END;
  407. IF t1.start < beg THEN (* conserve head of t1 *)
  408. UpdateIn(v, x, y0, y0 + t1.h); (* redraw tail of t1 *)
  409. top := y0 + t1.h
  410. ELSE
  411. top := y0
  412. END;
  413. bot := y0; REPEAT INC(bot, t1.h); t1 := t1.next UNTIL t1 = te;
  414. IF top < bot THEN UpdateIn(v, 0, top, bot) END (* redraw affected lines *)
  415. END UpdateFrames;
  416. PROCEDURE UpdateView (v: StdView; beg, end, delta: INTEGER);
  417. VAR st: TextSetters.Setter; r: TextRulers.Ruler; rpos: INTEGER;
  418. s0, t0, t, tn, u: Line; start, y, y0: INTEGER;
  419. BEGIN
  420. IF v.trailer # NIL THEN
  421. v.setter0 := NIL; st := v.ThisSetter();
  422. IF (beg <= v.trailer.start) & ((end >= v.org) OR (end - delta >= v.org)) THEN
  423. GetStart(st, v, beg, start);
  424. y0 := v.dy; s0 := v.trailer;
  425. WHILE s0.next.start < start DO s0 := s0.next; INC(y0, s0.h) END;
  426. t := s0.next; WHILE (t # v.trailer) & (t.start < end) DO t := t.next END;
  427. IF (t = v.trailer.next) & (t.start >= end) THEN
  428. REPEAT
  429. INC(t.start, delta);
  430. IF t.box.rpos >= end THEN INC(t.box.rpos, delta) END;
  431. t := t.next
  432. UNTIL t = v.trailer.next
  433. ELSE
  434. WHILE (t # v.trailer.next) & (t.start >= end) DO
  435. INC(t.start, delta);
  436. IF t.box.rpos >= end THEN INC(t.box.rpos, delta) END;
  437. t := t.next
  438. END
  439. END;
  440. tn := s0; y := y0; t0 := s0.next; u := t0;
  441. REPEAT
  442. t := tn; AddLine(st, tn, start, y); (* start = end(tn), y = bot(tn) *)
  443. WHILE (u # v.trailer) & (u.start < tn.start) DO u := u.next END
  444. UNTIL tn.box.eot OR (y > v.bot)
  445. OR (tn.start >= end) & (u.start = tn.start) & (u.box.len = tn.box.len)
  446. & (u.asc = tn.asc) & (u.attr = tn.attr) & (u.box.dsc = tn.box.dsc)
  447. & (u.box.rpos = tn.box.rpos); (* can be expensive ... *)
  448. IF tn.box.eot OR (y > v.bot) THEN
  449. t := tn; u := v.trailer; v.trailer.start := start
  450. ELSE
  451. DEC(y, tn.h)
  452. END;
  453. t.next := u;
  454. IF (s0 # v.trailer) & (s0.next # v.trailer) THEN s0.box.eot := FALSE END;
  455. ASSERT(v.trailer.start <= v.text.Length(), 100);
  456. UpdateFrames(v, t0, s0.next, u, beg, y0, y)
  457. ELSIF end <= v.org THEN
  458. INC(v.org, delta);
  459. (*
  460. IF end < v.org - delta - 500 THEN start := v.org ELSE start := st.ThisLine(v.org) END;
  461. (* this is not safe; even a change 500 characters away could force the view's origin to a
  462. new position in order to maintain the invariant that the origin always falls on a line start;
  463. however, ThisLine can be quite expensive -- can we rely on TextSetters cache ? *)
  464. *)
  465. start := st.ThisLine(v.org);
  466. r := v.defRuler; rpos := -1; TextRulers.GetValidRuler(v.text, start, -1, r, rpos);
  467. IF (v.org = start) & (v.trailer.next.attr = r.style.attr) THEN
  468. t := v.trailer;
  469. REPEAT
  470. t := t.next; INC(t.start, delta);
  471. IF t.box.rpos < start THEN t.box.rpos := rpos ELSE INC(t.box.rpos, delta) END
  472. UNTIL t = v.trailer
  473. ELSE
  474. DoSetOrigin(v, start, 0, TRUE); RebuildView(v)
  475. END
  476. END
  477. END
  478. END UpdateView;
  479. PROCEDURE StyleUpdate (v: StdView; oldAttr: TextRulers.Attributes);
  480. VAR t: Line; beg: INTEGER; first: BOOLEAN;
  481. BEGIN
  482. IF v.trailer # NIL THEN
  483. t := v.trailer.next; first := TRUE;
  484. WHILE t # v.trailer DO
  485. WHILE (t # v.trailer) & (t.attr # oldAttr) DO t := t.next END;
  486. IF t # v.trailer THEN
  487. IF first THEN v.Neutralize; first := FALSE END;
  488. beg := t.start; t := t.next;
  489. WHILE (t # v.trailer) & (t.attr = oldAttr) DO t := t.next END;
  490. UpdateView(v, beg, t.start, 0)
  491. END
  492. END
  493. END
  494. END StyleUpdate;
  495. (* line drawing *)
  496. PROCEDURE DrawLine (v: StdView;
  497. start: INTEGER; IN box: TextSetters.LineBox;
  498. f: Views.Frame; l, r, y, t: INTEGER; pageF: BOOLEAN
  499. );
  500. (* pre: area cleared *)
  501. (* [l,r) for high-level clipping to tune update after small change *)
  502. CONST cacheLen = 128;
  503. VAR rd: TextSetters.Reader; ra: TextRulers.Attributes;
  504. v1: Views.View; c: Containers.Controller;
  505. py, end, skip: INTEGER;
  506. cache: RECORD (* initially: long = TRUE, len = 0 *)
  507. x, y: INTEGER; color: Ports.Color; font: Fonts.Font;
  508. len: INTEGER;
  509. buf: ARRAY cacheLen OF CHAR
  510. END;
  511. PROCEDURE FlushCaches;
  512. BEGIN
  513. IF cache.len > 0 THEN
  514. cache.buf[cache.len] := 0X;
  515. f.DrawString(cache.x, cache.y, cache.color, cache.buf, cache.font)
  516. END;
  517. cache.len := 0
  518. END FlushCaches;
  519. PROCEDURE CacheString (x, y: INTEGER; c: INTEGER; IN s: ARRAY OF CHAR;
  520. f: Fonts.Font
  521. );
  522. VAR i, j, len: INTEGER;
  523. BEGIN
  524. len := 0; WHILE s[len] # 0X DO INC(len) END;
  525. IF (cache.len + len >= cacheLen) OR (cache.y # y) OR (cache.color # c) OR (cache.font # f) THEN
  526. FlushCaches
  527. END;
  528. ASSERT(cache.len + len < cacheLen, 100);
  529. IF cache.len = 0 THEN cache.x := x; cache.y := y; cache.color := c; cache.font := f END;
  530. i := 0; j := cache.len;
  531. WHILE i < len DO cache.buf[j] := s[i]; INC(i); INC(j) END;
  532. cache.len := j
  533. END CacheString;
  534. (*
  535. PROCEDURE CacheString (x, y: INTEGER; c: INTEGER; IN s: ARRAY OF CHAR;
  536. f: Fonts.Font
  537. );
  538. VAR i, j, len: INTEGER;
  539. BEGIN
  540. (* flush first, then promote *)
  541. len := 0; WHILE s[len] # 0X DO INC(len) END;
  542. IF (cache.len + len >= cacheLen) OR (cache.y # y) OR (cache.color # c) OR (cache.font # f) THEN
  543. FlushCaches
  544. END;
  545. IF (cache.len > 0) & cache.short THEN (* promote short chars to chars *)
  546. i := 0; WHILE i < cache.len DO cache.buf[i] := cache.sbuf[i]; INC(i) END
  547. END;
  548. cache.short := FALSE;
  549. ASSERT(cache.len + len < cacheLen, 100);
  550. IF cache.len = 0 THEN cache.x := x; cache.y := y; cache.color := c; cache.font := f END;
  551. i := 0; j := cache.len;
  552. WHILE i < len DO cache.buf[j] := s[i]; INC(i); INC(j) END;
  553. cache.len := j
  554. END CacheString;
  555. *)
  556. BEGIN
  557. IF box.len > 0 THEN
  558. cache.len := 0;
  559. end := start + box.len; skip := start + box.skipOff;
  560. rd := GetReader(v, start, box); rd.Read;
  561. WHILE ~rd.eot & (rd.pos <= end) & (rd.x < r) DO
  562. IF rd.pos > skip THEN rd.w := rd.endW END;
  563. rd.AdjustWidth(start, rd.pos, box, rd.w);
  564. IF rd.x + rd.w > l THEN
  565. v1 := rd.view;
  566. IF v1 # NIL THEN
  567. FlushCaches;
  568. IF ~((TextModels.hideable IN rd.textOpts) & v.hideMarks) THEN
  569. c := v.ThisController();
  570. Views.InstallFrame(f, v1,
  571. rd.x, y - rd.attr.offset + rd.dsc - rd.h, 0,
  572. (c # NIL) & (v1 = c.ThisFocus()) )
  573. END
  574. ELSIF (rd.h > 0) & (rd.w > 0) THEN
  575. IF box.rbox & ~v.hideMarks THEN rd.string[0] := parasign END; (* ¶ sign *)
  576. py := y - rd.attr.offset;
  577. IF rd.string[0] > " " THEN
  578. CacheString(rd.x, py, rd.attr.color, rd.string, rd.attr.font);
  579. IF ~v.hideMarks & (TextModels.hideable IN rd.textOpts) THEN
  580. f.DrawRect(rd.x, py - box.asc + f.dot,
  581. MIN(rd.x + rd.w, f.r), py + box.dsc - f.dot, 0, Ports.grey25)
  582. END
  583. ELSIF rd.string[0] # 0X THEN
  584. FlushCaches;
  585. IF ~v.hideMarks & (TextModels.hideable IN rd.textOpts) THEN
  586. f.DrawRect(rd.x, py - box.asc + f.dot, rd.x + rd.w, py + box.dsc - f.dot, 0, Ports.grey25)
  587. END
  588. ELSE FlushCaches
  589. END
  590. END
  591. END;
  592. INC(rd.x, rd.w); rd.Read
  593. END;
  594. FlushCaches;
  595. CacheReader(v, rd)
  596. END;
  597. IF v.hideMarks & ~pageF THEN
  598. ra := box.ruler.style.attr;
  599. IF TextRulers.pageBreak IN ra.opts THEN
  600. IF (box.rpos = start) & (ra.lead >= f.dot) THEN
  601. f.DrawLine(l, t, r - f.dot, t, 0, Ports.grey50)
  602. ELSIF (box.rpos = start - 1) & (ra.lead < f.dot) THEN
  603. f.DrawLine(l, t, r - f.dot, t, 0, Ports.grey50)
  604. END
  605. END
  606. END
  607. END DrawLine;
  608. PROCEDURE DrawDecorations (v: StdView; u: Line; f: Views.Frame; l, t, r, b: INTEGER);
  609. VAR a: TextRulers.Attributes; i, x: INTEGER; col: Ports.Color;
  610. st: TextSetters.Setter; srd: TextSetters.Reader; rd: TextModels.Reader;
  611. BEGIN
  612. IF t < b THEN
  613. i := 0; a := u.attr; srd := NIL;
  614. WHILE i < a.tabs.len DO
  615. IF TextRulers.barTab IN a.tabs.tab[i].type THEN
  616. x := a.tabs.tab[i].stop;
  617. IF (l <= x) & (x < r) THEN
  618. IF u.box.rpos = -1 THEN col := v.defAttr.color
  619. ELSIF srd = NIL THEN
  620. st := v.ThisSetter();
  621. srd := v.cachedRd; v.cachedRd := NIL;
  622. srd := st.NewReader(srd);
  623. srd.Set(srd.r, v.text, 0, 0, v.defRuler, 0, st.vw, st.hideMarks); rd := srd.r;
  624. rd.SetPos(u.box.rpos); rd.Read; col := rd.attr.color
  625. END;
  626. f.DrawLine(x, t, x, b - f.dot, 0, col)
  627. END
  628. END;
  629. INC(i)
  630. END;
  631. IF srd # NIL THEN CacheReader(v, srd) END
  632. END
  633. END DrawDecorations;
  634. (* focus-message handling *)
  635. PROCEDURE PollSection (v: StdView; f: Views.Frame; VAR msg: Controllers.PollSectionMsg);
  636. CONST ms = maxScrollSteps; mh = maxScrollHeight;
  637. VAR t: Line; steps, step: INTEGER;
  638. BEGIN
  639. IF msg.vertical THEN
  640. ValidateLines(v, f.b); t := v.trailer.next;
  641. IF t.h > 0 THEN
  642. steps := -((-t.h) DIV mh); step := -(v.dy DIV mh)
  643. ELSE steps := 1; step := 0
  644. END;
  645. msg.wholeSize := v.text.Length() * ms;
  646. msg.partPos := v.org * ms + t.box.len * ms * step DIV steps;
  647. msg.partSize := 0;
  648. msg.valid := (v.org > 0) OR (t.h > mh) OR (t.next # v.trailer);
  649. msg.done := TRUE
  650. END
  651. END PollSection;
  652. PROCEDURE Scroll (v: StdView; f: Views.Frame; VAR msg: Controllers.ScrollMsg);
  653. VAR st: TextSetters.Setter; box, box0: TextSetters.LineBox;
  654. t, t1, trailer: Line; org, len, dy, h, h1, sh, steps, step: INTEGER;
  655. poll: Controllers.PollSectionMsg;
  656. BEGIN
  657. IF msg.vertical THEN
  658. poll.vertical := TRUE;
  659. PollSection(v, f, poll)
  660. END;
  661. IF msg.vertical & poll.valid THEN
  662. org := v.org; dy := v.dy; st := v.ThisSetter(); trailer := v.trailer;
  663. CASE msg.op OF
  664. Controllers.decLine:
  665. IF dy <= -(maxScrollHeight + fuseScrollHeight) THEN
  666. INC(dy, maxScrollHeight)
  667. ELSIF dy < 0 THEN
  668. dy := 0
  669. ELSIF org > 0 THEN
  670. org := st.PreviousLine(org); st.GetLine(org, box);
  671. h1 := box.asc + box.dsc + st.GridOffset(-1, box);
  672. IF h1 > maxScrollHeight + fuseScrollHeight THEN
  673. sh := h1 - h1 MOD maxScrollHeight;
  674. IF h1 - sh < fuseScrollHeight THEN DEC(sh, maxScrollHeight) END;
  675. dy := -sh
  676. ELSE dy := 0
  677. END
  678. END
  679. | Controllers.incLine:
  680. t := trailer.next;
  681. IF t.h + dy > maxScrollHeight + fuseScrollHeight THEN
  682. DEC(dy, maxScrollHeight)
  683. ELSIF ~t.box.eot THEN
  684. org := t.next.start; dy := 0
  685. END
  686. | Controllers.decPage:
  687. sh := f.b; DEC(sh, maxScrollHeight + sh MOD maxScrollHeight);
  688. IF dy <= -(sh + fuseScrollHeight) THEN
  689. INC(dy, sh)
  690. ELSE
  691. t := trailer.next;
  692. h := maxScrollHeight - dy;
  693. IF t.h < h THEN h := t.h END;
  694. box0 := t.box; h1:= h - st.GridOffset(-1, box0);
  695. WHILE (org > 0) & (h + fuseScrollHeight < f.b) DO
  696. org := st.PreviousLine(org); st.GetLine(org, box);
  697. h1 := box.asc + box.dsc;
  698. INC(h, h1 + st.GridOffset(box.dsc, box0));
  699. box0 := box
  700. END;
  701. h1 := h1 + st.GridOffset(-1, box0);
  702. sh := h1 - (h - f.b); DEC(sh, sh MOD maxScrollHeight);
  703. IF h1 - sh >= fuseScrollHeight THEN dy := -sh ELSE dy := 0 END
  704. END;
  705. IF (org > v.org) OR (org = v.org) & (dy <= v.dy) THEN (* guarantee progress *)
  706. org := st.PreviousLine(org); st.GetLine(org, box);
  707. h1 := box.asc + box.dsc + st.GridOffset(-1, box);
  708. IF h1 > maxScrollHeight + fuseScrollHeight THEN
  709. dy := - (h1 DIV maxScrollHeight * maxScrollHeight)
  710. ELSE
  711. dy := 0
  712. END
  713. END
  714. | Controllers.incPage:
  715. t := trailer.next;
  716. sh := f.b; DEC(sh, maxScrollHeight + sh MOD maxScrollHeight);
  717. IF t.h + dy > sh + fuseScrollHeight THEN
  718. DEC(dy, sh)
  719. ELSE
  720. t := ThisViewLine(v, f.b); LocateThisLine(v, t.start, t1, h);
  721. IF (h + t.h >= f.b) & (t.h <= maxScrollHeight) THEN
  722. org := st.PreviousLine(t.start)
  723. ELSE org := t.start
  724. END;
  725. IF h + t.h - f.b > maxScrollHeight THEN
  726. sh := f.b - h; DEC(sh, maxScrollHeight + sh MOD maxScrollHeight);
  727. IF sh >= fuseScrollHeight THEN dy := -sh ELSE dy := 0 END
  728. ELSE
  729. dy := 0
  730. END
  731. END;
  732. IF (org < v.org) OR (org = v.org) & (dy >= v.dy) THEN (* guarantee progress *)
  733. IF t.h + dy > maxScrollHeight + fuseScrollHeight THEN
  734. DEC(dy, maxScrollHeight)
  735. ELSE
  736. org := t.next.start; dy := 0
  737. END
  738. END
  739. | Controllers.gotoPos:
  740. org := st.ThisLine(msg.pos DIV maxScrollSteps); st.GetLine(org, box);
  741. sh := box.asc + box.dsc + st.GridOffset(-1, box);
  742. steps := -((-sh) DIV maxScrollHeight);
  743. IF (steps > 0) & (box.len > 0) THEN
  744. step := steps * (msg.pos - org * maxScrollSteps) DIV (maxScrollSteps * box.len);
  745. (*
  746. step := steps * (msg.pos MOD maxScrollSteps) DIV maxScrollSteps;
  747. *)
  748. dy := -(step * maxScrollHeight)
  749. ELSE
  750. dy := 0
  751. END
  752. ELSE
  753. END;
  754. len := v.text.Length();
  755. IF org > len THEN org := len; dy := 0 END;
  756. v.SetOrigin(org, dy);
  757. msg.done := TRUE
  758. END
  759. END Scroll;
  760. PROCEDURE NotifyViewsOnPage (v: StdView; beg, end, pageNo: INTEGER);
  761. VAR st: TextSetters.Setter; rd: TextSetters.Reader; r: TextModels.Reader;
  762. view: Views.View; current: INTEGER;
  763. page: PageMsg;
  764. BEGIN
  765. IF pageNo >= 0 THEN current := pageNo
  766. ELSIF Printing.par # NIL THEN current := Printing.Current() (* Printing.par.page.current *) + 1
  767. ELSE current := -1
  768. END;
  769. IF current >= 0 THEN
  770. st := v.ThisSetter();
  771. rd := v.cachedRd; v.cachedRd := NIL; (* reader recycling *)
  772. rd := st.NewReader(rd);
  773. rd.Set(rd.r, v.text, 0, 0, v.defRuler, 0, st.vw, st.hideMarks);
  774. r := rd.r; r.SetPos(beg); r.ReadView(view);
  775. WHILE (r.Pos() <= end) & ~r.eot DO
  776. page.current := current; Views.HandlePropMsg(view, page); r.ReadView(view)
  777. END;
  778. CacheReader(v, rd)
  779. END
  780. END NotifyViewsOnPage;
  781. PROCEDURE Page (v: StdView; pageH: INTEGER; op, pageY: INTEGER; OUT done, eoy: BOOLEAN);
  782. VAR st: TextSetters.Setter; org, prev, page: INTEGER;
  783. BEGIN
  784. IF ~v.hideMarks & ((v.context = NIL) OR v.context.Normalize()) THEN
  785. v.DisplayMarks(hide)
  786. END;
  787. st := v.ThisSetter();
  788. IF op = Controllers.nextPageY THEN
  789. done := TRUE; org := st.NextPage(pageH, v.org); eoy := (org = v.text.Length());
  790. IF ~eoy THEN NotifyViewsOnPage(v, org, st.NextPage(pageH, org), -1) END
  791. ELSIF op = Controllers.gotoPageY THEN
  792. ASSERT(pageY >= 0, 20);
  793. done := TRUE; org := 0; eoy := FALSE; page := 0;
  794. WHILE (page < pageY) & ~eoy DO
  795. prev := org; org := st.NextPage(pageH, org); eoy := org = prev;
  796. IF ~eoy THEN NotifyViewsOnPage(v, prev, org, page) END;
  797. INC(page)
  798. END;
  799. IF ~eoy THEN NotifyViewsOnPage(v, org, st.NextPage(pageH, org), page) END
  800. ELSE
  801. done := FALSE
  802. END;
  803. IF done & ~eoy THEN v.org := org; v.dy := 0; v.trailer := NIL; v.bot := 0 END
  804. END Page;
  805. PROCEDURE ShowAdjusted (v: StdView; shift: INTEGER; rebuild: BOOLEAN);
  806. BEGIN
  807. IF shift # 0 THEN Views.Scroll(v, 0, shift)
  808. ELSIF rebuild THEN UpdateIn(v, 0, 0, MAX(INTEGER))
  809. END;
  810. Views.RestoreDomain(v.Domain())
  811. END ShowAdjusted;
  812. PROCEDURE AdjustLines (v: StdView; org, dy: INTEGER;
  813. OUT shift: INTEGER; OUT rebuild: BOOLEAN
  814. );
  815. (* post: shift = 0 OR ~rebuild *)
  816. VAR d: Stores.Domain; c: Containers.Controller; t, t0, t1: Line; org0, dy0, y: INTEGER;
  817. BEGIN
  818. d := v.Domain(); t0 := v.trailer; org0 := v.org; rebuild := FALSE; shift := 0;
  819. IF (d # NIL) & ((org # org0) OR (dy # v.dy)) THEN
  820. Views.RestoreDomain(d); (* make sure that pixels are up-to-date before scrolling *)
  821. c := v.ThisController();
  822. IF c # NIL THEN
  823. Containers.FadeMarks(c, Containers.hide) (* fade marks with overhang *)
  824. END
  825. END;
  826. IF (t0 # NIL) & (org = org0) & (dy # v.dy) THEN (* sub-line shift *)
  827. shift := dy - v.dy;
  828. ELSIF (t0 # NIL) & (org > org0) & (org < t0.start) THEN (* shift up *)
  829. LocateThisLine(v, org, t, y); t0.next := t;
  830. shift := dy - y
  831. ELSIF (t0 # NIL) & (org < org0) THEN (* shift down *)
  832. t1 := t0.next; dy0 := v.dy + t1.asc; v.org := org; v.dy := dy;
  833. IF t1.start = org0 THEN (* new lines need to be prepended *)
  834. PrependLines(v) (* may change t1.asc *)
  835. END;
  836. ASSERT(t0.next.start = org, 100);
  837. IF org0 < t0.start THEN (* former top still visible -> shift down *)
  838. LocateThisLine(v, org0, t, y); shift := y - (dy0 - t1.asc)
  839. ELSE (* rebuild all *)
  840. rebuild := TRUE
  841. END
  842. ELSIF (t0 = NIL) OR (org # org0) OR (dy # v.dy) THEN (* rebuild all *)
  843. rebuild := TRUE
  844. END;
  845. v.org := org; v.dy := dy;
  846. IF rebuild THEN (* rebuild all *)
  847. v.trailer := NIL; ValidateLines(v, v.bot)
  848. ELSIF shift < 0 THEN (* shift up *)
  849. INC(v.bot, shift); ExtendLines(v, v.bot - shift)
  850. ELSIF shift > 0 THEN (* shift down *)
  851. INC(v.bot, shift); ReduceLines(v, v.bot - shift)
  852. END
  853. END AdjustLines;
  854. PROCEDURE Limit (v: StdView; bot: INTEGER; allLines: BOOLEAN): INTEGER;
  855. CONST minH = 12 * point;
  856. VAR s, t: Line; pos, y: INTEGER;
  857. BEGIN
  858. s := v.trailer.next; t := s; y := v.dy;
  859. WHILE ~t.box.eot & (y + t.h <= bot) DO INC(y, t.h); s := t; t := t.next END;
  860. IF ~allLines & (bot - y < t.h) & (bot - y < minH) THEN t := s END;
  861. pos := t.start + t.box.len;
  862. (*
  863. IF t.box.eot THEN INC(pos) END;
  864. *)
  865. RETURN pos
  866. END Limit;
  867. (* ScrollOp *)
  868. PROCEDURE (op: ScrollOp) Do;
  869. VAR org0, dy0, org, dy, shift: INTEGER; rebuild: BOOLEAN;
  870. BEGIN
  871. IF op.bunch THEN org := op.bunchOrg; dy := op.bunchDy
  872. ELSE org := op.org; dy := op.dy
  873. END;
  874. org0 := op.v.org; dy0 := op.v.dy;
  875. IF op.silent THEN
  876. op.v.org := org; op.v.dy := dy; op.silent := FALSE
  877. ELSE
  878. AdjustLines(op.v, org, dy, shift, rebuild); ShowAdjusted(op.v, shift, rebuild)
  879. END;
  880. IF op.bunch THEN op.bunch := FALSE ELSE op.org := org0; op.dy := dy0 END
  881. END Do;
  882. PROCEDURE DoSetOrigin (v: StdView; org, dy: INTEGER; silent: BOOLEAN);
  883. (* pre: org = v.ThisSetter().ThisLine(org) *)
  884. VAR con: Models.Context; last: Stores.Operation; op: ScrollOp;
  885. shift: INTEGER; rebuild: BOOLEAN;
  886. BEGIN
  887. IF (org # v.org) OR (dy # v.dy) THEN
  888. con := v.context;
  889. IF con # NIL THEN
  890. IF (v.Domain() = NIL) OR con.Normalize() THEN
  891. IF silent THEN
  892. v.org := org; v.dy := dy
  893. ELSE
  894. AdjustLines(v, org, dy, shift, rebuild); ShowAdjusted(v, shift, rebuild)
  895. END
  896. ELSE
  897. last := Views.LastOp(v);
  898. IF (last # NIL) & (last IS ScrollOp) THEN
  899. op := last(ScrollOp);
  900. op.bunch := TRUE; op.bunchOrg := org; op.bunchDy := dy;
  901. op.silent := silent;
  902. Views.Bunch(v)
  903. ELSE
  904. NEW(op); op.v := v; op.org := org; op.dy := dy;
  905. op.bunch := FALSE;
  906. op.silent := silent;
  907. Views.Do(v, scrollingKey, op)
  908. END
  909. END
  910. ELSE
  911. v.org := org; v.dy := dy
  912. END
  913. END
  914. END DoSetOrigin;
  915. (* SetOp *)
  916. PROCEDURE (op: SetOp) Do;
  917. VAR v: StdView; m: BOOLEAN;
  918. a: TextModels.Attributes; r: TextRulers.Ruler; s: TextSetters.Setter;
  919. BEGIN
  920. v := op.view;
  921. CASE op.mode OF
  922. setMarks:
  923. m := v.hideMarks; v.hideMarks := op.hideMarks; op.hideMarks := m
  924. | setSetter:
  925. s := v.setter;
  926. IF s # NIL THEN s.ConnectTo(NIL, NIL, 0, FALSE) END;
  927. v.setter := op.setter; op.setter := s
  928. | setDefs:
  929. r := v.defRuler; a := v.defAttr;
  930. v.defRuler := op.defRuler; v.defAttr := op.defAttr;
  931. op.defRuler := r; op.defAttr := a;
  932. (*
  933. IF (v.defAttr.Domain() # NIL) & (v.defAttr.Domain() # v.Domain()) THEN
  934. v.defAttr := Stores.CopyOf(v.defAttr)(TextModels.Attributes)
  935. END;
  936. Stores.Join(v, v.defAttr);
  937. *)
  938. IF v.defAttr # NIL THEN (* could be for undo operations *)
  939. IF ~Stores.Joined(v, v.defAttr) THEN
  940. IF ~Stores.Unattached(v.defAttr) THEN
  941. v.defAttr := Stores.CopyOf(v.defAttr)(TextModels.Attributes)
  942. END;
  943. Stores.Join(v, v.defAttr)
  944. END;
  945. END;
  946. IF v.defRuler # NIL THEN Stores.Join(v, v.defRuler) END;
  947. END;
  948. RebuildView(v)
  949. END Do;
  950. PROCEDURE DoSet (op: SetOp; mode: INTEGER; v: StdView);
  951. BEGIN
  952. op.mode := mode; op.view := v; Views.Do(v, viewSettingKey, op)
  953. END DoSet;
  954. (* StdView *)
  955. PROCEDURE (v: StdView) Internalize2 (VAR rd: Stores.Reader);
  956. VAR st: Stores.Store; r: TextRulers.Ruler; a: TextModels.Attributes;
  957. org, dy: INTEGER; thisVersion: INTEGER; hideMarks: BOOLEAN;
  958. BEGIN
  959. v.Internalize2^(rd);
  960. IF rd.cancelled THEN RETURN END;
  961. rd.ReadVersion(minVersion, maxStdVersion, thisVersion);
  962. IF rd.cancelled THEN RETURN END;
  963. rd.ReadBool(hideMarks);
  964. rd.ReadStore(st); ASSERT(st # NIL, 100);
  965. IF ~(st IS TextRulers.Ruler) THEN
  966. rd.TurnIntoAlien(Stores.alienComponent);
  967. Stores.Report("#Text:AlienDefaultRuler", "", "", "");
  968. RETURN
  969. END;
  970. r := st(TextRulers.Ruler);
  971. TextModels.ReadAttr(rd, a);
  972. rd.ReadInt(org); rd.ReadInt(dy);
  973. v.DisplayMarks(hideMarks);
  974. v.setter := TextSetters.dir.New(); v.setter0 := NIL;
  975. v.SetDefaults(r, a); v.SetOrigin(org, dy);
  976. v.trailer := NIL; v.bot := 0
  977. END Internalize2;
  978. PROCEDURE (v: StdView) Externalize2 (VAR wr: Stores.Writer);
  979. VAR org, dy: INTEGER; hideMarks: BOOLEAN;
  980. a: Stores.Store;
  981. BEGIN
  982. v.Externalize2^(wr);
  983. IF (v.context = NIL) OR v.context.Normalize() THEN
  984. org := 0; dy := 0; hideMarks := TRUE
  985. ELSE
  986. org := v.org; dy := v.dy; hideMarks := v.hideMarks
  987. END;
  988. wr.WriteVersion(maxStdVersion);
  989. wr.WriteBool(hideMarks);
  990. a := Stores.CopyOf(v.defAttr); (*Stores.InitDomain(a, v.Domain());*) Stores.Join(v, a);
  991. (* bkwd-comp hack: avoid link => so that pre release 1.3 Internalize can still read texts *)
  992. wr.WriteStore(v.defRuler);
  993. wr.WriteStore(a);
  994. wr.WriteInt(org); wr.WriteInt(dy)
  995. END Externalize2;
  996. PROCEDURE (v: StdView) CopyFromModelView2 (source: Views.View; model: Models.Model);
  997. VAR s: TextSetters.Setter; r: TextRulers.Ruler;
  998. BEGIN
  999. (* v.CopyFromModelView^(source, model); *)
  1000. WITH source: StdView DO
  1001. s := Stores.CopyOf(source.setter)(TextSetters.Setter);
  1002. v.setter := s; v.setter0 := NIL;
  1003. r := TextRulers.CopyOf(source.defRuler, Views.deep);
  1004. v.DisplayMarks(source.HidesMarks());
  1005. v.SetDefaults(r, source.defAttr);
  1006. v.trailer := NIL; v.bot := 0;
  1007. IF v.text = source.text THEN
  1008. v.org := source.org; v.dy := source.dy
  1009. END
  1010. END
  1011. END CopyFromModelView2;
  1012. PROCEDURE (v: StdView) Restore (f: Views.Frame; l, t, r, b: INTEGER);
  1013. VAR st: TextSetters.Setter; u0, u: Line;
  1014. y0, y, w, h: INTEGER; end: INTEGER; pageF: BOOLEAN;
  1015. BEGIN
  1016. ASSERT(v.context # NIL, 20);
  1017. IF v.setter # NIL THEN v.context.GetSize(w, h) END;
  1018. IF (v.setter = NIL) OR (v.setter.vw # w) THEN
  1019. Views.RemoveFrames(f, l, t, r, b)
  1020. END;
  1021. ValidateLines(v, b);
  1022. u := v.trailer.next; y := v.dy;
  1023. pageF := Views.IsPrinterFrame(f) & v.context.Normalize();
  1024. IF pageF THEN (* on page-formatted frames do not display truncated lines at bottom *)
  1025. st := v.ThisSetter(); end := st.NextPage(f.b - f.t, v.org)
  1026. END;
  1027. WHILE (u # v.trailer) & (y + u.h <= t) DO INC(y, u.h); u := u.next END;
  1028. y0 := y; u0 := u;
  1029. IF (u = v.trailer.next) & (y < b) THEN (* at least one line per page *)
  1030. ASSERT((u.box.len > 0) OR u.box.eot OR (u.next = v.trailer), 100);
  1031. DrawLine(v, u.start, u.box, f, l, r, y + u.asc, y + u.h - u.box.dsc - u.box.asc, pageF);
  1032. INC(y, u.h); u := u.next
  1033. END;
  1034. WHILE (u # v.trailer) & (y < b) & (~pageF OR (u.start < end)) DO
  1035. ASSERT((u.box.len > 0) OR u.box.eot OR (u.next = v.trailer), 101);
  1036. IF u.box.ruler # u0.box.ruler THEN
  1037. DrawDecorations(v, u0, f, l, y0, r, y); u0 := u; y0 := y
  1038. END;
  1039. DrawLine(v, u.start, u.box, f, l, r, y + u.asc, y + u.h - u.box.dsc - u.box.asc, pageF);
  1040. INC(y, u.h); u := u.next
  1041. END;
  1042. IF y0 # y THEN DrawDecorations(v, u0, f, l, y0, r, y) END
  1043. END Restore;
  1044. PROCEDURE (v: StdView) DisplayMarks (hide: BOOLEAN);
  1045. VAR op: SetOp; c: Containers.Controller;
  1046. BEGIN
  1047. IF v.hideMarks # hide THEN
  1048. c := v.ThisController();
  1049. IF c # NIL THEN Containers.FadeMarks(c, Containers.hide) END;
  1050. IF (v.context # NIL) & ~v.context.Normalize() THEN
  1051. NEW(op); op.hideMarks := hide; DoSet(op, setMarks, v)
  1052. ELSE
  1053. v.hideMarks := hide; RebuildView(v)
  1054. END
  1055. END
  1056. END DisplayMarks;
  1057. PROCEDURE (v: StdView) HidesMarks (): BOOLEAN;
  1058. BEGIN
  1059. RETURN v.hideMarks
  1060. END HidesMarks;
  1061. PROCEDURE (v: StdView) SetSetter (setter: TextSetters.Setter);
  1062. VAR op: SetOp;
  1063. BEGIN
  1064. ASSERT(setter # NIL, 20);
  1065. IF v.setter # setter THEN
  1066. IF v.setter # NIL THEN
  1067. NEW(op); op.setter := setter; DoSet(op, setSetter, v)
  1068. ELSE v.setter := setter
  1069. END
  1070. END
  1071. END SetSetter;
  1072. PROCEDURE (v: StdView) ThisSetter (): TextSetters.Setter;
  1073. VAR st: TextSetters.Setter; w, h: INTEGER;
  1074. BEGIN
  1075. st := v.setter; ASSERT(st # NIL, 20);
  1076. IF st # v.setter0 THEN
  1077. IF v.context # NIL THEN
  1078. v.context.GetSize(w, h)
  1079. ELSE
  1080. IF Dialog.metricSystem THEN
  1081. w := 165*mm
  1082. ELSE
  1083. w := 104*inch16
  1084. END
  1085. END;
  1086. st.ConnectTo(v.text, v.defRuler, w, v.hideMarks);
  1087. v.setter0 := st
  1088. END;
  1089. RETURN st
  1090. END ThisSetter;
  1091. PROCEDURE (d: StdView) AcceptableModel (m: Containers.Model): BOOLEAN;
  1092. BEGIN
  1093. RETURN m IS TextModels.Model
  1094. END AcceptableModel;
  1095. PROCEDURE (v: StdView) InitModel2 (m: Containers.Model);
  1096. BEGIN
  1097. ASSERT(m IS TextModels.Model, 23);
  1098. v.text := m(TextModels.Model)
  1099. END InitModel2;
  1100. PROCEDURE (v: StdView) SetOrigin (org, dy: INTEGER);
  1101. VAR st: TextSetters.Setter; start: INTEGER;
  1102. BEGIN
  1103. ASSERT(v.text # NIL, 20);
  1104. st := v.ThisSetter(); start := st.ThisLine(org);
  1105. IF start # org THEN org := start; dy := 0 END;
  1106. DoSetOrigin(v, org, dy, FALSE)
  1107. END SetOrigin;
  1108. PROCEDURE (v: StdView) PollOrigin (OUT org, dy: INTEGER);
  1109. BEGIN
  1110. org := v.org; dy := v.dy
  1111. END PollOrigin;
  1112. PROCEDURE (v: StdView) SetDefaults (r: TextRulers.Ruler; a: TextModels.Attributes);
  1113. VAR op: SetOp;
  1114. BEGIN
  1115. ASSERT(r # NIL, 20); ASSERT(r.style.attr.init, 21);
  1116. ASSERT(a # NIL, 22); ASSERT(a.init, 23);
  1117. IF (v.defRuler # r) OR (v.defAttr # a) THEN
  1118. (*
  1119. (*IF (v.context # NIL) & (r # v.defRuler) THEN*)
  1120. IF (v.Domain() # NIL) & (r # v.defRuler) THEN
  1121. Stores.InitDomain(r, v.Domain())
  1122. END;
  1123. *)
  1124. IF r # v.defRuler THEN Stores.Join(v, r) END;
  1125. NEW(op); op.defRuler := r; op.defAttr := a; DoSet(op, setDefs, v)
  1126. END
  1127. END SetDefaults;
  1128. PROCEDURE (v: StdView) PollDefaults (OUT r: TextRulers.Ruler; OUT a: TextModels.Attributes);
  1129. BEGIN
  1130. r := v.defRuler; a := v.defAttr
  1131. END PollDefaults;
  1132. (*
  1133. PROCEDURE (v: StdView) PropagateDomain;
  1134. VAR m: Models.Model;
  1135. BEGIN
  1136. ASSERT(v.setter # NIL, 20); ASSERT(v.text # NIL, 21);
  1137. ASSERT(v.defRuler # NIL, 22); ASSERT(v.defAttr # NIL, 23);
  1138. v.PropagateDomain^;
  1139. m := v.ThisModel();
  1140. IF m # NIL THEN Stores.InitDomain(m, v.Domain()) END;
  1141. Stores.InitDomain(v.defRuler, v.Domain())
  1142. END PropagateDomain;
  1143. *)
  1144. (*
  1145. PROCEDURE (v: StdView) Flush, NEW;
  1146. BEGIN
  1147. v.trailer := NIL; v.bot := 0; v.setter0 := NIL
  1148. END Flush;
  1149. *)
  1150. PROCEDURE (v: StdView) HandleModelMsg2 (VAR msg: Models.Message);
  1151. BEGIN
  1152. IF msg.model = v.text THEN
  1153. WITH msg: Models.UpdateMsg DO
  1154. WITH msg: TextModels.UpdateMsg DO
  1155. IF msg.op IN {TextModels.insert, TextModels.delete, TextModels.replace} THEN
  1156. UpdateView(v, msg.beg, msg.end, msg.delta)
  1157. ELSE (* unknown text op happened *)
  1158. RebuildView(v)
  1159. END
  1160. ELSE (* unknown text update happened *)
  1161. RebuildView(v)
  1162. END
  1163. | msg: PositionMsg DO
  1164. v.ShowRange(msg.beg, msg.end, msg.focusOnly)
  1165. ELSE
  1166. END
  1167. ELSE (* domaincast received *)
  1168. WITH msg: TextRulers.UpdateMsg DO
  1169. StyleUpdate(v, msg.oldAttr)
  1170. | msg: Models.UpdateMsg DO (* forced rebuild *)
  1171. RebuildView(v)
  1172. ELSE
  1173. END
  1174. END
  1175. END HandleModelMsg2;
  1176. PROCEDURE (v: StdView) HandleViewMsg2 (f: Views.Frame; VAR msg: Views.Message);
  1177. BEGIN
  1178. IF msg.view = v THEN
  1179. WITH msg: FindAnyFrameMsg DO
  1180. IF (msg.frame = NIL) OR (msg.frame.b - msg.frame.t > f.b - f.t) THEN msg.frame := f END
  1181. ELSE
  1182. END
  1183. ELSE
  1184. WITH msg: Views.UpdateCachesMsg DO (* display view in new frame *)
  1185. IF Views.Era(v) # Models.Era(v.text) THEN
  1186. (* view/setter caches outdated - possible if v previous to this notification had no frame open *)
  1187. v.setter0 := NIL; v.trailer := NIL; v.bot := 0
  1188. END
  1189. ELSE
  1190. END
  1191. END
  1192. END HandleViewMsg2;
  1193. PROCEDURE (v: StdView) HandleCtrlMsg2 (f: Views.Frame;
  1194. VAR msg: Controllers.Message; VAR focus: Views.View
  1195. );
  1196. BEGIN
  1197. WITH msg: Controllers.PollSectionMsg DO
  1198. IF (focus = NIL) OR ~msg.focus THEN
  1199. PollSection(v, f, msg);
  1200. focus := NIL
  1201. END
  1202. | msg: FindFocusFrameMsg DO
  1203. IF (msg.view = v) & (msg.frame = NIL) THEN msg.frame := f END
  1204. | msg: Controllers.ScrollMsg DO
  1205. IF (focus = NIL) OR ~msg.focus THEN
  1206. Scroll(v, f, msg);
  1207. focus := NIL
  1208. END
  1209. | msg: Controllers.PageMsg DO
  1210. Page(v, f.b - f.t, msg.op, msg.pageY, msg.done, msg.eoy);
  1211. focus := NIL
  1212. ELSE
  1213. END
  1214. END HandleCtrlMsg2;
  1215. PROCEDURE (v: StdView) HandlePropMsg2 (VAR p: Properties.Message);
  1216. CONST minW = 5 * point; maxW = maxHeight; minH = 5 * point; maxH = maxHeight;
  1217. VAR st: TextSetters.Setter;
  1218. BEGIN
  1219. WITH p: Properties.SizePref DO
  1220. IF p.w = Views.undefined THEN p.w := v.defRuler.style.attr.right END;
  1221. IF p.h = Views.undefined THEN p.h := MAX(INTEGER) END
  1222. | p: Properties.BoundsPref DO
  1223. st := v.ThisSetter();
  1224. st.GetBox(0, v.text.Length(), maxW, maxH, p.w, p.h);
  1225. IF p.w < minW THEN p.w := minW END;
  1226. IF p.h < minH THEN p.h := minH END
  1227. | p: Properties.ResizePref DO
  1228. p.fixed := FALSE;
  1229. p.horFitToPage := ~(TextRulers.rightFixed IN v.defRuler.style.attr.opts);
  1230. p.verFitToWin := TRUE
  1231. | p: Properties.TypePref DO
  1232. IF Services.Is(v, p.type) THEN p.view := v END
  1233. | p: Containers.DropPref DO
  1234. p.okToDrop := TRUE
  1235. ELSE
  1236. END
  1237. END HandlePropMsg2;
  1238. PROCEDURE (v: StdView) GetThisLocation (f: Views.Frame; pos: INTEGER; OUT loc: Location);
  1239. (* pre: f must be displayed *)
  1240. (* if position lies outside view, the next best location inside will be taken *)
  1241. VAR rd: TextSetters.Reader; t: Line; p1, y, w, h: INTEGER;
  1242. BEGIN
  1243. ValidateLines(v, f.b);
  1244. y := v.dy;
  1245. IF pos < v.org THEN
  1246. t := v.trailer.next;
  1247. loc.start := t.start; loc.pos := t.start;
  1248. loc.x := 0; loc.y := y; loc.asc := t.asc; loc.dsc := t.h - t.asc; loc.view := NIL;
  1249. RETURN
  1250. ELSIF pos < v.trailer.start THEN
  1251. t := v.trailer.next;
  1252. WHILE ~t.box.eot & ~((t.start <= pos) & (pos < t.next.start)) DO
  1253. INC(y, t.h); t := t.next
  1254. END
  1255. ELSE (* pos >= v.trailer.start *)
  1256. t := v.trailer.next; WHILE ~t.box.eot DO INC(y, t.h); t := t.next END;
  1257. IF t = v.trailer THEN
  1258. loc.start := t.start; loc.pos := t.start;
  1259. loc.x := 0; loc.y := y; loc.asc := t.asc; loc.dsc := t.h - t.asc; loc.view := NIL;
  1260. RETURN
  1261. END
  1262. END;
  1263. p1 := t.start;
  1264. rd := GetReader(v, p1, t.box); rd.Read;
  1265. WHILE rd.pos < pos DO
  1266. p1 := rd.pos; rd.AdjustWidth(t.start, p1, t.box, rd.w); INC(rd.x, rd.w); rd.Read
  1267. END;
  1268. IF LEN(rd.string$) > 1 THEN (* collated subsequence *)
  1269. rd.x := f.CharPos(rd.x, pos - p1, rd.string, rd.attr.font);
  1270. IF rd.pos = pos THEN rd.Read END
  1271. ELSIF rd.pos = pos THEN
  1272. rd.AdjustWidth(t.start, pos, t.box, rd.w); INC(rd.x, rd.w); rd.Read
  1273. ELSE
  1274. ASSERT(p1 = pos, 100)
  1275. END;
  1276. loc.view := rd.view;
  1277. loc.start := t.start; loc.pos := pos;
  1278. loc.x := rd.x; loc.y := y; loc.asc := t.asc; loc.dsc := t.h - t.asc;
  1279. IF loc.view # NIL THEN
  1280. v.context.GetSize(w, h);
  1281. IF rd.x + rd.w > w THEN rd.w := w - rd.x END;
  1282. loc.l := rd.x; loc.t := y - rd.attr.offset + t.asc + rd.dsc - rd.h;
  1283. loc.r := loc.l + rd.w; loc.b := loc.t + rd.h
  1284. END;
  1285. CacheReader(v, rd)
  1286. END GetThisLocation;
  1287. PROCEDURE (v: StdView) GetRange (f: Views.Frame; OUT beg, end: INTEGER);
  1288. VAR t: Line;
  1289. BEGIN
  1290. ValidateLines(v, f.b);
  1291. t := ThisViewLine(v, f.t); beg := t.start; end := Limit(v, f.b, TRUE)
  1292. END GetRange;
  1293. PROCEDURE (v: StdView) ThisPos (f: Views.Frame; x, y: INTEGER): INTEGER;
  1294. (* pre: f must be displayed *)
  1295. (* post: f.org <= result <= v.text.Length() *)
  1296. VAR rd: TextSetters.Reader; t: Line; p1, end, py: INTEGER;
  1297. BEGIN
  1298. ValidateLines(v, f.b);
  1299. t := v.trailer.next; py := v.dy;
  1300. WHILE ~t.box.eot & (py + t.h <= y) DO INC(py, t.h); t := t.next END;
  1301. p1 := t.start; end := p1 + t.box.len;
  1302. IF py + t.h > y THEN
  1303. IF (end > p1) & (y >= v.dy) THEN
  1304. IF t.box.eot THEN INC(end) END;
  1305. rd := GetReader(v, p1, t.box);
  1306. rd.Read; rd.AdjustWidth(t.start, rd.pos, t.box, rd.w);
  1307. WHILE (rd.x + rd.SplitWidth(rd.w) < x) & (rd.pos < end) DO
  1308. p1 := rd.pos; INC(rd.x, rd.w);
  1309. rd.Read; rd.AdjustWidth(t.start, rd.pos, t.box, rd.w)
  1310. END;
  1311. IF LEN(rd.string$) > 1 THEN (* collated subsequence *)
  1312. INC(p1, f.CharIndex(rd.x, x, rd.string, rd.attr.font))
  1313. END;
  1314. CacheReader(v, rd)
  1315. END
  1316. ELSE p1 := end
  1317. END;
  1318. RETURN p1
  1319. END ThisPos;
  1320. PROCEDURE (v: StdView) ShowRangeIn (f: Views.Frame; beg, end: INTEGER);
  1321. CONST minH = 12 * point;
  1322. VAR c: Models.Context; st: TextSetters.Setter; t, t1: Line;
  1323. org0, last, len, org, dy, p, q: INTEGER; y, h, mh: INTEGER;
  1324. box, box0: TextSetters.LineBox; loc, loc1: Location;
  1325. focus: BOOLEAN;
  1326. BEGIN
  1327. focus := f = Controllers.FocusFrame();
  1328. c := v.context;
  1329. st := v.ThisSetter(); ValidateLines(v, f.b); org0 := v.org;
  1330. last := Limit(v, f.b, FALSE); len := v.text.Length();
  1331. IF last = len THEN p := st.ThisLine(last); LocateThisLine(v, p, t1, y); h := f.b - y END;
  1332. IF (beg > last)
  1333. OR (beg = last) & ((last < len) OR (len > 0) & (h < t1.h) & (h < minH))
  1334. OR (end < org0)
  1335. OR (beg < end) & (end = org0) THEN
  1336. org := -1; dy := 0;
  1337. IF beg <= org0 THEN (* try to adjust by scrolling up *)
  1338. p := st.PreviousLine(v.org);
  1339. IF p <= beg THEN (* reveal one line at top *)
  1340. org := p; st.GetLine(org, box);
  1341. h := box.asc + box.dsc + st.GridOffset(-1, box);
  1342. IF h > maxScrollHeight + fuseScrollHeight THEN
  1343. dy := -(h - h MOD maxScrollHeight);
  1344. IF h + dy < fuseScrollHeight THEN INC(dy, maxScrollHeight) END
  1345. END
  1346. END
  1347. END;
  1348. IF (org = -1) & (beg >= last) THEN (* try to adjust by scrolling down *)
  1349. p := st.ThisLine(last); q := st.NextLine(p); st.GetLine(q, box);
  1350. IF (beg < q + box.len) OR (p = q) THEN (* reveal one line at bottom *)
  1351. LocateThisLine(v, p, t1, y);
  1352. h := box.asc + box.dsc + st.GridOffset(t1.box.dsc, box);
  1353. IF h > maxScrollHeight + fuseScrollHeight THEN h := maxScrollHeight END;
  1354. mh := y + t1.h - f.b + h;
  1355. t := v.trailer.next; h := v.dy;
  1356. WHILE (t # v.trailer) & (h < mh) DO INC(h, t.h); t := t.next END;
  1357. IF t.start > v.org THEN org := t.start END
  1358. END
  1359. END;
  1360. IF org = -1 THEN (* adjust by moving into "nice" position *)
  1361. mh := f.b DIV 3;
  1362. org := st.ThisLine(beg); st.GetLine(org, box0);
  1363. h := box0.asc + box0.dsc + st.GridOffset(-1, box0); p := org;
  1364. WHILE (p > 0) & (h < mh) DO
  1365. DEC(h, st.GridOffset(-1, box0)); org := p;
  1366. p := st.PreviousLine(org); st.GetLine(p, box);
  1367. INC(h, box.asc + box.dsc + st.GridOffset(box.dsc, box0));
  1368. box0 := box
  1369. END;
  1370. IF (org = len) & (len > 0) THEN org := st.PreviousLine(org) END
  1371. END;
  1372. DoSetOrigin(v, org, dy, FALSE)
  1373. END;
  1374. IF focus THEN
  1375. f := Controllers.FocusFrame();
  1376. IF (f # NIL) & (f.view = v) THEN
  1377. v.GetThisLocation(f, beg, loc);
  1378. v.GetThisLocation(f, end, loc1);
  1379. IF (loc.y = loc1.y) & (loc.x <= loc1.x) THEN
  1380. c.MakeVisible(loc.x, loc.y, loc1.x, loc1.y)
  1381. END
  1382. ELSE
  1383. HALT(100); (* this should not happen *)
  1384. END
  1385. END;
  1386. (*
  1387. IF c IS Documents.Context THEN
  1388. v.GetThisLocation(f, beg, loc);
  1389. v.GetThisLocation(f, end, loc1);
  1390. IF (loc.y = loc1.y) & (loc.x <= loc1.x) THEN
  1391. Documents.MakeVisible(c(Documents.Context).ThisDoc(), f, loc.x, loc.y, loc1.x, loc1.y)
  1392. END
  1393. END
  1394. *)
  1395. END ShowRangeIn;
  1396. PROCEDURE (v: StdView) ShowRange (beg, end: INTEGER; focusOnly: BOOLEAN);
  1397. VAR fmsg: FindFocusFrameMsg; amsg: FindAnyFrameMsg; f: Views.Frame;
  1398. BEGIN
  1399. IF focusOnly THEN
  1400. fmsg.view := v; fmsg.frame := NIL; Controllers.Forward(fmsg); f := fmsg.frame
  1401. ELSE
  1402. amsg.frame := NIL; Views.Broadcast(v, amsg); f := amsg.frame
  1403. END;
  1404. IF f # NIL THEN v.ShowRangeIn(f, beg, end) END
  1405. END ShowRange;
  1406. (* StdDirectory *)
  1407. PROCEDURE (d: StdDirectory) New (text: TextModels.Model): View;
  1408. VAR v: StdView; c: Controllers.Controller; r: TextRulers.Ruler;
  1409. BEGIN
  1410. r := TextRulers.dir.New(NIL);
  1411. IF text = NIL THEN text := TextModels.dir.New() END;
  1412. (* IF text.Domain() # NIL THEN Stores.InitDomain(r, text.Domain()) END; *)
  1413. Stores.Join(text, r);
  1414. NEW(v); v.hideMarks := FALSE; v.bot := 0; v.org := 0; v.dy := 0;
  1415. v.InitModel(text);
  1416. v.SetDefaults(r, d.defAttr);
  1417. v.SetSetter(TextSetters.dir.New());
  1418. v.DisplayMarks(hide);
  1419. IF ctrlDir # NIL THEN v.SetController(ctrlDir.New()) END;
  1420. (* Stores.InitDomain(v, text.Domain()); *)
  1421. Stores.Join(v, text);
  1422. RETURN v
  1423. END New;
  1424. PROCEDURE Init;
  1425. VAR d: StdDirectory; a: TextModels.Attributes; res: INTEGER;
  1426. BEGIN
  1427. Dialog.Call("TextControllers.Install", "#Text:CntrlInstallFailed", res);
  1428. NEW(a); a.InitFromProp(NIL); (* use defaults *)
  1429. NEW(d); d.defAttr := a;
  1430. stdDir := d; dir := d
  1431. END Init;
  1432. BEGIN
  1433. Init
  1434. END TextViews.