102 Due to historic reasons (ListView implemented scrolling before the general |
104 Due to historic reasons (ListView implemented scrolling before the general |
103 scrolling code in View was added), this one does scrolling different from all other |
105 scrolling code in View was added), this one does scrolling different from all other |
104 views. The general scrolling code (in View) uses the transformation for transparent scrolling |
106 views. The general scrolling code (in View) uses the transformation for transparent scrolling |
105 using the viewOrigin (transparent means, that the code does not need to know - it simply draws |
107 using the viewOrigin (transparent means, that the code does not need to know - it simply draws |
106 as if all of the text was visible). |
108 as if all of the text was visible). |
107 Here in ListView, the transformation is not used, instead it is done again, and different, |
109 Here in ListView, the transformation is not used, instead it is done again, and different, |
108 by keeping the firstLineShown (i.e. vertical offset) and leftOffset (horizontal offset). |
110 by keeping the firstLineShown (i.e. vertical offset) and leftOffset (horizontal offset). |
109 Even worse: the firstLineShown is a line-index, the most annoying consequence of this is that |
111 Even worse: the firstLineShown is a line-index, the most annoying consequence of this is that |
110 scrolling is done by lines here, whereas it is done in pixels in the View class. |
112 scrolling is done by lines here, whereas it is done in pixels in the View class. |
111 Thus, be very careful, when changing things (better: don't touch it ;-). |
113 Thus, be very careful, when changing things (better: don't touch it ;-). |
112 Also, the viewOrigin variable is only valid for the x coordinate. The viewOrigin's y is always 0 !! |
114 Also, the viewOrigin variable is only valid for the x coordinate. The viewOrigin's y is always 0 !! |
113 |
115 |
114 Also, all controller functionality is completely performed by the listView |
116 Also, all controller functionality is completely performed by the listView |
115 (and subclasses) itself. It is still possible, to define and set a specialized |
117 (and subclasses) itself. It is still possible, to define and set a specialized |
116 controller, though. I.e. if you like to change the input behavior, define |
118 controller, though. I.e. if you like to change the input behavior, define |
169 fontAscent <Number> font ascent in pixels (internal) |
171 fontAscent <Number> font ascent in pixels (internal) |
170 fontIsFixed <Boolean> true if its a fixed font (internal) |
172 fontIsFixed <Boolean> true if its a fixed font (internal) |
171 fontWidth <Number> width of space (internal) |
173 fontWidth <Number> width of space (internal) |
172 lineSpacing <Number> pixels between lines |
174 lineSpacing <Number> pixels between lines |
173 lastSearchPattern <String> last pattern for searching |
175 lastSearchPattern <String> last pattern for searching |
174 (kept to provide a default for next search) |
176 (kept to provide a default for next search) |
175 lastSearchIgnoredCase <Boolean> last search ignored case |
177 lastSearchIgnoredCase <Boolean> last search ignored case |
176 (kept to provide a default for next search) |
178 (kept to provide a default for next search) |
177 wordCheck <Block> rule used for check for word boundaries in word select |
179 wordCheck <Block> rule used for check for word boundaries in word select |
178 The default rule is to return true for alphaNumeric characters. |
180 The default rule is to return true for alphaNumeric characters. |
179 (can be changed to allow for underscore and other |
181 (can be changed to allow for underscore and other |
180 characters to be treated as alphaCharacters) |
182 characters to be treated as alphaCharacters) |
181 |
183 |
182 autoScrollBlock <Block> block installed as timeoutBlock when doing an |
184 autoScrollBlock <Block> block installed as timeoutBlock when doing an |
183 autoScroll (internal) |
185 autoScroll (internal) |
184 autoScrollDeltaT computed scroll time delta in seconds (internal) |
186 autoScrollDeltaT computed scroll time delta in seconds (internal) |
185 |
187 |
186 includesNonStrings cached flag if any non-strings are in list |
188 includesNonStrings cached flag if any non-strings are in list |
187 widthOfWidestLine cached width of widest line |
189 widthOfWidestLine cached width of widest line |
188 listMsg if view has a model and listMsg is non-nil, |
190 listMsg if view has a model and listMsg is non-nil, |
189 this is sent to the model to acquired a new contents |
191 this is sent to the model to acquired a new contents |
190 whenever a change of the aspect (aspectMsg) occurs. |
192 whenever a change of the aspect (aspectMsg) occurs. |
191 |
193 |
192 viewOrigin the current origin |
194 viewOrigin the current origin |
193 |
195 |
194 backgroundAlreadyClearedColor internal; speedup by avoiding |
196 backgroundAlreadyClearedColor internal; speedup by avoiding |
195 multiple fills when drawing |
197 multiple fills when drawing |
196 internal lines |
198 internal lines |
197 |
199 |
198 scrollWhenUpdating |
200 scrollWhenUpdating |
199 <Symbol> defines how the view is scrolled if the |
201 <Symbol> defines how the view is scrolled if the |
200 model changes its value by some outside activity |
202 model changes its value by some outside activity |
201 (i.e. not by user input). |
203 (i.e. not by user input). |
202 Can be one of: |
204 Can be one of: |
203 #keep / nil -> stay unchanged |
205 #keep / nil -> stay unchanged |
204 #endOfText -> scroll to the end |
206 #endOfText -> scroll to the end |
205 #beginOfText -> scroll to the top |
207 #beginOfText -> scroll to the top |
206 The default is #beginOfText (i.e. scroll to top). |
208 The default is #beginOfText (i.e. scroll to top). |
207 |
209 |
208 [StyleSheet parameters:] |
210 [StyleSheet parameters:] |
209 |
211 |
210 textForegroundColor defaults to Black |
212 textForegroundColor defaults to Black |
211 textBackgroundColor defaults to White |
213 textBackgroundColor defaults to White |
212 textFont defaults to defaultFont |
214 textFont defaults to defaultFont |
213 textTabPositions defaults to #(1 9 17 25 ...) |
215 textTabPositions defaults to #(1 9 17 25 ...) |
214 |
216 |
215 [author:] |
217 [author:] |
216 Claus Gittinger |
218 Claus Gittinger |
217 |
219 |
218 [see also:] |
220 [see also:] |
219 TextView EditTextView |
221 TextView EditTextView |
220 |
222 |
221 " |
223 " |
222 ! |
224 ! |
223 |
225 |
224 examples |
226 examples |
227 for TextView, EditTextView and SelectionInListView. |
229 for TextView, EditTextView and SelectionInListView. |
228 |
230 |
229 anyway, here are a few examples: |
231 anyway, here are a few examples: |
230 |
232 |
231 basic simple setup: |
233 basic simple setup: |
232 [exBegin] |
234 [exBegin] |
233 |top l| |
235 |top l| |
234 |
236 |
235 top := StandardSystemView new. |
237 top := StandardSystemView new. |
236 top extent:100@200. |
238 top extent:100@200. |
237 |
239 |
238 l := ListView origin:0.0 @ 0.0 corner:1.0 @ 1.0 in:top. |
240 l := ListView origin:0.0 @ 0.0 corner:1.0 @ 1.0 in:top. |
239 l list:#('one' 'two' 'three'). |
241 l list:#('one' 'two' 'three'). |
240 |
242 |
241 top open |
243 top open |
242 [exEnd] |
244 [exEnd] |
243 |
245 |
244 |
246 |
245 |
247 |
246 specifying textMargins (these have NOTHING to do with the viewInset): |
248 specifying textMargins (these have NOTHING to do with the viewInset): |
247 [exBegin] |
249 [exBegin] |
248 |top l| |
250 |top l| |
249 |
251 |
250 top := StandardSystemView new. |
252 top := StandardSystemView new. |
251 top extent:100@200. |
253 top extent:100@200. |
252 |
254 |
253 l := ListView origin:0.0 @ 0.0 corner:1.0 @ 1.0 in:top. |
255 l := ListView origin:0.0 @ 0.0 corner:1.0 @ 1.0 in:top. |
254 l list:#('one' 'two' 'three'). |
256 l list:#('one' 'two' 'three'). |
255 l topMargin:10. |
257 l topMargin:10. |
256 l leftMargin:20. |
258 l leftMargin:20. |
257 |
259 |
258 top open |
260 top open |
259 [exEnd] |
261 [exEnd] |
260 |
262 |
261 |
263 |
262 |
264 |
263 globally set the fg/bg colors: |
265 globally set the fg/bg colors: |
264 [exBegin] |
266 [exBegin] |
265 |top l| |
267 |top l| |
266 |
268 |
267 top := StandardSystemView new. |
269 top := StandardSystemView new. |
268 top extent:100@200. |
270 top extent:100@200. |
269 |
271 |
270 l := ListView origin:0.0 @ 0.0 corner:1.0 @ 1.0 in:top. |
272 l := ListView origin:0.0 @ 0.0 corner:1.0 @ 1.0 in:top. |
271 l list:#('one' 'two' 'three'). |
273 l list:#('one' 'two' 'three'). |
272 l foregroundColor:(Color white). |
274 l foregroundColor:(Color white). |
273 l backgroundColor:(Color blue). |
275 l backgroundColor:(Color blue). |
274 |
276 |
275 top open |
277 top open |
276 [exEnd] |
278 [exEnd] |
277 |
279 |
278 |
280 |
279 |
281 |
280 non-string (text) entries: |
282 non-string (text) entries: |
281 [exBegin] |
283 [exBegin] |
282 |top list l| |
284 |top list l| |
283 |
285 |
284 top := StandardSystemView new. |
286 top := StandardSystemView new. |
285 top extent:100@200. |
287 top extent:100@200. |
286 |
288 |
287 l := ListView origin:0.0 @ 0.0 corner:1.0 @ 1.0 in:top. |
289 l := ListView origin:0.0 @ 0.0 corner:1.0 @ 1.0 in:top. |
288 list := #('all' 'of' 'your' 'preferred' 'colors') |
290 list := #('all' 'of' 'your' 'preferred' 'colors') |
289 with:#(red green blue 'orange' cyan) |
291 with:#(red green blue 'orange' cyan) |
290 collect:[:s :clr | |
292 collect:[:s :clr | |
291 Text string:s |
293 Text string:s |
292 emphasis:(Array with:#bold |
294 emphasis:(Array with:#bold |
293 with:(#color->(Color name:clr))) ]. |
295 with:(#color->(Color name:clr))) ]. |
294 l list:list. |
296 l list:list. |
295 |
297 |
296 top open |
298 top open |
297 [exEnd] |
299 [exEnd] |
298 |
300 |
299 |
301 |
300 |
302 |
301 generic non-string entries: |
303 generic non-string entries: |
302 (notice: ColoredListEntry is obsoleted by Text) |
304 (notice: ColoredListEntry is obsoleted by Text) |
303 [exBegin] |
305 [exBegin] |
304 |top list l| |
306 |top list l| |
305 |
307 |
306 top := StandardSystemView new. |
308 top := StandardSystemView new. |
307 top extent:100@200. |
309 top extent:100@200. |
308 |
310 |
309 l := ListView origin:0.0 @ 0.0 corner:1.0 @ 1.0 in:top. |
311 l := ListView origin:0.0 @ 0.0 corner:1.0 @ 1.0 in:top. |
310 list := #('all' 'of' 'your' 'preferred' 'colors') |
312 list := #('all' 'of' 'your' 'preferred' 'colors') |
311 with:#(red green blue 'orange' cyan) |
313 with:#(red green blue 'orange' cyan) |
312 collect:[:s :clr | ColoredListEntry string:s color:(Color name:clr) ]. |
314 collect:[:s :clr | ColoredListEntry string:s color:(Color name:clr) ]. |
313 l list:list. |
315 l list:list. |
314 |
316 |
315 top open |
317 top open |
316 [exEnd] |
318 [exEnd] |
317 |
319 |
318 |
320 |
319 |
321 |
320 using a model (default listMessage is aspectMessage): |
322 using a model (default listMessage is aspectMessage): |
321 [exBegin] |
323 [exBegin] |
322 |top model l theModelsText| |
324 |top model l theModelsText| |
323 |
325 |
324 model := Plug new. |
326 model := Plug new. |
325 model respondTo:#modelsAspect |
327 model respondTo:#modelsAspect |
326 with:[ theModelsText ]. |
328 with:[ theModelsText ]. |
327 |
329 |
328 top := StandardSystemView new. |
330 top := StandardSystemView new. |
329 top extent:100@200. |
331 top extent:100@200. |
330 |
332 |
331 l := ListView origin:0.0 @ 0.0 corner:1.0 @ 1.0 in:top. |
333 l := ListView origin:0.0 @ 0.0 corner:1.0 @ 1.0 in:top. |
332 l model:model. |
334 l model:model. |
333 l aspect:#modelsAspect. |
335 l aspect:#modelsAspect. |
334 |
336 |
335 top open. |
337 top open. |
336 |
338 |
337 Delay waitForSeconds:3. |
339 Delay waitForSeconds:3. |
338 theModelsText := #('foo' 'bar' 'baz'). |
340 theModelsText := #('foo' 'bar' 'baz'). |
339 model changed:#modelsAspect. |
341 model changed:#modelsAspect. |
340 [exEnd] |
342 [exEnd] |
341 |
343 |
342 |
344 |
343 |
345 |
344 using a model with different aspects |
346 using a model with different aspects |
345 for two listViews: |
347 for two listViews: |
346 [exBegin] |
348 [exBegin] |
347 |top model l1 l2 plainText| |
349 |top model l1 l2 plainText| |
348 |
350 |
349 plainText := #(''). |
351 plainText := #(''). |
350 |
352 |
351 model := Plug new. |
353 model := Plug new. |
352 model respondTo:#modelsUppercaseText |
354 model respondTo:#modelsUppercaseText |
353 with:[ plainText asStringCollection |
355 with:[ plainText asStringCollection |
354 collect:[:l | l asUppercase]]. |
356 collect:[:l | l asUppercase]]. |
355 model respondTo:#modelsLowercaseText |
357 model respondTo:#modelsLowercaseText |
356 with:[ plainText asStringCollection |
358 with:[ plainText asStringCollection |
357 collect:[:l | l asLowercase]]. |
359 collect:[:l | l asLowercase]]. |
358 |
360 |
359 top := StandardSystemView extent:200@200. |
361 top := StandardSystemView extent:200@200. |
360 |
362 |
361 l1 := ListView origin:0.0 @ 0.0 corner:1.0 @ 0.5 in:top. |
363 l1 := ListView origin:0.0 @ 0.0 corner:1.0 @ 0.5 in:top. |
362 l1 model:model. |
364 l1 model:model. |
363 l1 aspect:#modelsAspect. |
365 l1 aspect:#modelsAspect. |
364 l1 listMessage:#modelsUppercaseText. |
366 l1 listMessage:#modelsUppercaseText. |
365 |
367 |
366 l2 := ListView origin:0.0 @ 0.5 corner:1.0 @ 1.0 in:top. |
368 l2 := ListView origin:0.0 @ 0.5 corner:1.0 @ 1.0 in:top. |
367 l2 model:model. |
369 l2 model:model. |
368 l2 aspect:#modelsAspect. |
370 l2 aspect:#modelsAspect. |
369 l2 listMessage:#modelsLowercaseText. |
371 l2 listMessage:#modelsLowercaseText. |
370 |
372 |
371 top open. |
373 top open. |
372 |
374 |
373 Delay waitForSeconds:3. |
375 Delay waitForSeconds:3. |
374 plainText := #('foo' 'bar' 'baz'). |
376 plainText := #('foo' 'bar' 'baz'). |
375 model changed:#modelsAspect. |
377 model changed:#modelsAspect. |
376 [exEnd] |
378 [exEnd] |
377 |
379 |
378 using a big list (100000 lines), |
380 using a big list (100000 lines), |
379 wrapping in a ScrollableView: |
381 wrapping in a ScrollableView: |
380 [exBegin] |
382 [exBegin] |
381 |bigList top lv| |
383 |bigList top lv| |
382 |
384 |
383 bigList := (1 to:100000) collect:[:lineNr | 'List line Nr. ' , lineNr printString]. |
385 bigList := (1 to:100000) collect:[:lineNr | 'List line Nr. ' , lineNr printString]. |
384 bigList at:10 put:('Some Text ' asText , 'with Bold part' allBold). |
386 bigList at:10 put:('Some Text ' asText , 'with Bold part' allBold). |
385 bigList at:20 put:('Some Text ' asText , 'with Italic part' allItalic). |
387 bigList at:20 put:('Some Text ' asText , 'with Italic part' allItalic). |
386 |
388 |
387 top := StandardSystemView extent:200@200. |
389 top := StandardSystemView extent:200@200. |
388 |
390 |
389 lv := HVScrollableView for:ListView in:top. |
391 lv := HVScrollableView for:ListView in:top. |
390 lv origin:0.0 @ 0.0 corner:1.0 @ 1.0. |
392 lv origin:0.0 @ 0.0 corner:1.0 @ 1.0. |
391 lv list:bigList expandTabs:false scanForNonStrings:false includesNonStrings:false. |
393 lv list:bigList expandTabs:false scanForNonStrings:false includesNonStrings:false. |
392 |
394 |
393 top open. |
395 top open. |
394 [exEnd] |
396 [exEnd] |
395 |
397 |
396 using a huge virtual list (1 mio simulated lines), |
398 using a huge virtual list (1 mio simulated lines), |
397 wrapping in a ScrollableView: |
399 wrapping in a ScrollableView: |
398 [exBegin] |
400 [exBegin] |
399 |virtualList top lv| |
401 |virtualList top lv| |
400 |
402 |
401 virtualList := Plug new. |
403 virtualList := Plug new. |
402 virtualList inheritFrom:SequenceableCollection. |
404 virtualList inheritFrom:SequenceableCollection. |
403 virtualList respondTo:#size with:[ 1000000 ]. |
405 virtualList respondTo:#size with:[ 1000000 ]. |
404 virtualList respondTo:#at: with:[:lineNr | 'List line Nr. ' , lineNr printString ]. |
406 virtualList respondTo:#at: with:[:lineNr | 'List line Nr. ' , lineNr printString ]. |
405 |
407 |
406 top := StandardSystemView extent:200@200. |
408 top := StandardSystemView extent:200@200. |
407 |
409 |
408 lv := ScrollableView for:ListView in:top. |
410 lv := ScrollableView for:ListView in:top. |
409 lv origin:0.0 @ 0.0 corner:1.0 @ 1.0. |
411 lv origin:0.0 @ 0.0 corner:1.0 @ 1.0. |
410 lv list:virtualList expandTabs:false scanForNonStrings:false includesNonStrings:false. |
412 lv list:virtualList expandTabs:false scanForNonStrings:false includesNonStrings:false. |
411 |
413 |
412 top open. |
414 top open. |
413 [exEnd] |
415 [exEnd] |
414 |
416 |
415 |
417 |
416 using a huge virtual array (1 mio simulated lines), |
418 using a huge virtual array (1 mio simulated lines), |
417 wrapping in a ScrollableView. |
419 wrapping in a ScrollableView. |
418 To simulate an expensive computation, a delay is planted into the line generator; |
420 To simulate an expensive computation, a delay is planted into the line generator; |
419 Startup and display of page full of lines should not take longer than the number of lines shown: |
421 Startup and display of page full of lines should not take longer than the number of lines shown: |
420 [exBegin] |
422 [exBegin] |
421 |virtualList top lv| |
423 |virtualList top lv| |
422 |
424 |
423 virtualList := VirtualArray new. |
425 virtualList := VirtualArray new. |
424 virtualList |
426 virtualList |
425 setSize:1000000; |
427 setSize:1000000; |
426 generator:[:index | Transcript showCR:index. |
428 generator:[:index | Transcript showCR:index. |
427 Delay waitForSeconds:0.5. |
429 Delay waitForSeconds:0.5. |
428 '%1 -> %2' bindWith:index with:index squared]. |
430 '%1 -> %2' bindWith:index with:index squared]. |
429 |
431 |
430 top := StandardSystemView extent:200@200. |
432 top := StandardSystemView extent:200@200. |
431 |
433 |
432 lv := ScrollableView for:ListView in:top. |
434 lv := ScrollableView for:ListView in:top. |
433 lv origin:0.0 @ 0.0 corner:1.0 @ 1.0. |
435 lv origin:0.0 @ 0.0 corner:1.0 @ 1.0. |
434 lv expandTabsWhenUpdating:false. |
436 lv expandTabsWhenUpdating:false. |
435 lv checkLineEndConventionWhenUpdating:false. |
437 lv checkLineEndConventionWhenUpdating:false. |
436 lv checkedLinesForWidthOfContentsComputation:-1. |
438 lv checkedLinesForWidthOfContentsComputation:-1. |
437 lv list:virtualList. |
439 lv list:virtualList. |
438 |
440 |
439 top open. |
441 top open. |
440 [exEnd] |
442 [exEnd] |
441 " |
443 " |
442 ! ! |
444 ! ! |
443 |
445 |
444 !ListView class methodsFor:'accessing private classes'! |
446 !ListView class methodsFor:'accessing private classes'! |
445 |
447 |
577 checkedLinesForWidthOfContentsComputation := aNumberOrNil |
579 checkedLinesForWidthOfContentsComputation := aNumberOrNil |
578 ! |
580 ! |
579 |
581 |
580 compareModelWhenUpdating |
582 compareModelWhenUpdating |
581 "return the compare when updating behavior. |
583 "return the compare when updating behavior. |
582 If true (the default), the list of lines as given due to a model update |
584 If true (the default), the list of lines as given due to a model update |
583 is processed and compared against the currently shown text. |
585 is processed and compared against the currently shown text. |
584 If they are the same, no action is taken. |
586 If they are the same, no action is taken. |
585 This behavior is ok in 99.99% of all applications. |
587 This behavior is ok in 99.99% of all applications. |
586 However, you may turn this off iff: |
588 However, you may turn this off iff: |
587 - it is very expensive to process the list (for example, because the list |
589 - it is very expensive to process the list (for example, because the list |
588 is defined by a virtual array, which computes the lines dynamically, on |
590 is defined by a virtual array, which computes the lines dynamically, on |
589 the fly). |
591 the fly). |
590 One use where this flag should be turned off is in the hex-memory display, |
592 One use where this flag should be turned off is in the hex-memory display, |
591 which is able to simulate texts with millions of lines, but they are actually |
593 which is able to simulate texts with millions of lines, but they are actually |
592 simulated by generating the presented lines dynamically, as they are displayed." |
594 simulated by generating the presented lines dynamically, as they are displayed." |
593 |
595 |
594 ^ compareModelOnUpdate |
596 ^ compareModelOnUpdate |
595 ! |
597 ! |
596 |
598 |
597 compareModelWhenUpdating:aBoolean |
599 compareModelWhenUpdating:aBoolean |
598 "define the compare when updating behavior. |
600 "define the compare when updating behavior. |
599 If true (the default), the list of lines as given due to a model update |
601 If true (the default), the list of lines as given due to a model update |
600 is processed and compared against the currently shown text. |
602 is processed and compared against the currently shown text. |
601 If they are the same, no action is taken. |
603 If they are the same, no action is taken. |
602 This behavior is ok in 99.99% of all applications. |
604 This behavior is ok in 99.99% of all applications. |
603 However, you may turn this off iff: |
605 However, you may turn this off iff: |
604 - it is very expensive to process the list (for example, because the list |
606 - it is very expensive to process the list (for example, because the list |
605 is defined by a virtual array, which computes the lines dynamically, on |
607 is defined by a virtual array, which computes the lines dynamically, on |
606 the fly). |
608 the fly). |
607 One use where this flag should be turned off is in the hex-memory display, |
609 One use where this flag should be turned off is in the hex-memory display, |
608 which is able to simulate texts with millions of lines, but they are actually |
610 which is able to simulate texts with millions of lines, but they are actually |
609 simulated by generating the presented lines dynamically, as they are displayed." |
611 simulated by generating the presented lines dynamically, as they are displayed." |
610 |
612 |
611 compareModelOnUpdate := aBoolean |
613 compareModelOnUpdate := aBoolean |
612 ! |
614 ! |
613 |
615 |
614 expandTabsWhenUpdating |
616 expandTabsWhenUpdating |
615 "return the tab expansion behavior. |
617 "return the tab expansion behavior. |
616 If true (the default), the list of lines as given via #list: or |
618 If true (the default), the list of lines as given via #list: or |
617 due to a model update is processed and lines are replaced by lines with |
619 due to a model update is processed and lines are replaced by lines with |
618 tabs expanded. |
620 tabs expanded. |
619 This behavior is ok in 99.99% of all applications. |
621 This behavior is ok in 99.99% of all applications. |
620 However, you may turn this off iff: |
622 However, you may turn this off iff: |
621 - you are certain, that no tabs are in the passed in list |
623 - you are certain, that no tabs are in the passed in list |
622 - it is very expensive to process the list (for example, because the list |
624 - it is very expensive to process the list (for example, because the list |
623 is defined by a virtual array, which computes the lines dynamically, on |
625 is defined by a virtual array, which computes the lines dynamically, on |
624 the fly). |
626 the fly). |
625 One use where this flag should be turned off is in the hex-memory display, |
627 One use where this flag should be turned off is in the hex-memory display, |
626 which is able to simulate texts with millions of lines, but they are actually |
628 which is able to simulate texts with millions of lines, but they are actually |
627 simulated by generating the presented lines dynamically, as they are displayed." |
629 simulated by generating the presented lines dynamically, as they are displayed." |
628 |
630 |
629 ^ expandTabsWhenUpdating |
631 ^ expandTabsWhenUpdating |
630 ! |
632 ! |
631 |
633 |
632 expandTabsWhenUpdating:aBoolean |
634 expandTabsWhenUpdating:aBoolean |
633 "define the tab expansion behavior. |
635 "define the tab expansion behavior. |
634 If true (the default), the list of lines as given via #list: or |
636 If true (the default), the list of lines as given via #list: or |
635 due to a model update is processed and lines are replaced by lines with |
637 due to a model update is processed and lines are replaced by lines with |
636 tabs expanded. |
638 tabs expanded. |
637 This behavior is ok in 99.99% of all applications. |
639 This behavior is ok in 99.99% of all applications. |
638 However, you may turn this off iff: |
640 However, you may turn this off iff: |
639 - you are certain, that no tabs are in the passed in list |
641 - you are certain, that no tabs are in the passed in list |
640 - it is very expensive to process the list (for example, because the list |
642 - it is very expensive to process the list (for example, because the list |
641 is defined by a virtual array, which computes the lines dynamically, on |
643 is defined by a virtual array, which computes the lines dynamically, on |
642 the fly). |
644 the fly). |
643 One use where this flag should be turned off is in the hex-memory display, |
645 One use where this flag should be turned off is in the hex-memory display, |
644 which is able to simulate texts with millions of lines, but they are actually |
646 which is able to simulate texts with millions of lines, but they are actually |
645 simulated by generating the presented lines dynamically, as they are displayed." |
647 simulated by generating the presented lines dynamically, as they are displayed." |
646 |
648 |
647 expandTabsWhenUpdating := aBoolean |
649 expandTabsWhenUpdating := aBoolean |
774 |
776 |
775 |lastShown| |
777 |lastShown| |
776 |
778 |
777 list isNil ifTrue:[list := OrderedCollection new]. |
779 list isNil ifTrue:[list := OrderedCollection new]. |
778 aCollectionOfLines do:[:eachLine | |
780 aCollectionOfLines do:[:eachLine | |
779 list addAll:aCollectionOfLines beforeIndex:index. |
781 list addAll:aCollectionOfLines beforeIndex:index. |
780 ]. |
782 ]. |
781 includesNonStrings ifFalse:[ |
783 includesNonStrings ifFalse:[ |
782 includesNonStrings := |
784 includesNonStrings := |
783 aCollectionOfLines |
785 aCollectionOfLines |
784 contains:[:someLine | |
786 contains:[:someLine | |
785 someLine notNil and:[(someLine isSingleByteString) not]. |
787 someLine notNil and:[(someLine isSingleByteString) not]. |
786 ] |
788 ] |
787 ]. |
789 ]. |
788 |
790 |
789 widthOfWidestLine notNil ifTrue:[ |
791 widthOfWidestLine notNil ifTrue:[ |
790 aCollectionOfLines do:[:eachLine | |
792 aCollectionOfLines do:[:eachLine | |
791 self recomputeWidthOfWidestLineFor:eachLine old:nil. |
793 self recomputeWidthOfWidestLineFor:eachLine old:nil. |
792 ]. |
794 ]. |
793 ]. |
795 ]. |
794 "/ widthOfWidestLine := nil. "/ i.e. unknown |
796 "/ widthOfWidestLine := nil. "/ i.e. unknown |
795 self textChanged. |
797 self textChanged. |
796 |
798 |
797 shown ifTrue:[ |
799 shown ifTrue:[ |
798 lastShown := self lastLineShown. |
800 lastShown := self lastLineShown. |
799 ((index-1) <= lastShown) ifTrue:[ |
801 ((index-1) <= lastShown) ifTrue:[ |
800 index <= 2 ifTrue:[ |
802 index <= 2 ifTrue:[ |
801 self invalidate |
803 self invalidate |
802 ] ifFalse:[ |
804 ] ifFalse:[ |
803 index-1 to:lastShown do:[:eachLine | |
805 index-1 to:lastShown do:[:eachLine | |
804 self invalidateLine:eachLine |
806 self invalidateLine:eachLine |
805 ]. |
807 ]. |
806 "/ self redrawFromLine:index-1. |
808 "/ self redrawFromLine:index-1. |
807 ]. |
809 ]. |
808 ]. |
810 ]. |
809 ]. |
811 ]. |
810 self enqueueDelayedContentsChangedNotification. "recompute scrollbars" |
812 self enqueueDelayedContentsChangedNotification. "recompute scrollbars" |
811 |
813 |
812 (scrollWhenUpdating == #end or:[scrollWhenUpdating == #endOfText]) ifTrue:[ |
814 (scrollWhenUpdating == #end or:[scrollWhenUpdating == #endOfText]) ifTrue:[ |
813 "/ self selection isNil ifTrue:[ |
815 "/ self selection isNil ifTrue:[ |
814 self scrollToBottom. |
816 self scrollToBottom. |
815 "/ ] |
817 "/ ] |
816 ]. |
818 ]. |
817 |
819 |
818 "Modified: / 25-07-2012 / 12:00:54 / cg" |
820 "Modified: / 25-07-2012 / 12:00:54 / cg" |
819 ! |
821 ! |
820 |
822 |
1054 "/ I think, if there is something to optimize, |
1056 "/ I think, if there is something to optimize, |
1055 "/ the caller should do so (moved to getListFromModel). |
1057 "/ the caller should do so (moved to getListFromModel). |
1056 "/ notice, that it may be very expensive to ask aCollection for each line |
1058 "/ notice, that it may be very expensive to ask aCollection for each line |
1057 "/ for example, iff the lines are generated on the fly by an algorithm |
1059 "/ for example, iff the lines are generated on the fly by an algorithm |
1058 false ifTrue:[ |
1060 false ifTrue:[ |
1059 "/ see if there is a change at all. |
1061 "/ see if there is a change at all. |
1060 "/ use to compare using =, but that's not enough in case of emphasis change. |
1062 "/ use to compare using =, but that's not enough in case of emphasis change. |
1061 aCollection size == list size ifTrue:[ |
1063 aCollection size == list size ifTrue:[ |
1062 same := true. |
1064 same := true. |
1063 aCollection size > 0 ifTrue:[ |
1065 aCollection size > 0 ifTrue:[ |
1064 aCollection with:list do:[:eachNewLine :eachOldLine | |
1066 aCollection with:list do:[:eachNewLine :eachOldLine | |
1065 (eachNewLine == eachOldLine) |
1067 (eachNewLine == eachOldLine) |
1066 ifFalse:[ |
1068 ifFalse:[ |
1067 same := false. |
1069 same := false. |
1068 ] |
1070 ] |
1069 ] |
1071 ] |
1070 ]. |
1072 ]. |
1071 same ifTrue:[^ self]. |
1073 same ifTrue:[^ self]. |
1072 ]. |
1074 ]. |
1073 ]. |
1075 ]. |
1074 |
1076 |
1075 scrollToTop := scrollWhenUpdating == #begin or:[scrollWhenUpdating == #beginOfText]. |
1077 scrollToTop := scrollWhenUpdating == #begin or:[scrollWhenUpdating == #beginOfText]. |
1076 scrollToEnd := scrollWhenUpdating == #end or:[scrollWhenUpdating == #endOfText]. |
1078 scrollToEnd := scrollWhenUpdating == #end or:[scrollWhenUpdating == #endOfText]. |
1077 |
1079 |
1078 (aCollection isEmptyOrNil and:[list isEmptyOrNil]) ifTrue:[ |
1080 (aCollection isEmptyOrNil and:[list isEmptyOrNil]) ifTrue:[ |
1079 "no contents change" |
1081 "no contents change" |
1080 list := aCollection. |
1082 list := aCollection. |
1081 scrollLocked ifFalse:[ |
1083 scrollLocked ifFalse:[ |
1082 scrollToTop ifTrue:[ |
1084 scrollToTop ifTrue:[ |
1083 self scrollToTop. |
1085 self scrollToTop. |
1084 ] ifFalse:[ |
1086 ] ifFalse:[ |
1085 scrollToEnd ifTrue:[ |
1087 scrollToEnd ifTrue:[ |
1086 self scrollToBottom. |
1088 self scrollToBottom. |
1087 ] |
1089 ] |
1088 ]. |
1090 ]. |
1089 self scrollToLeft. |
1091 self scrollToLeft. |
1090 ]. |
1092 ]. |
1091 ^ self |
1093 ^ self |
1092 ]. |
1094 ]. |
1093 |
1095 |
1094 checkLineEndConventionWhenUpdating ifTrue:[ |
1096 checkLineEndConventionWhenUpdating ifTrue:[ |
1095 "Check if the we use DOS/Windows line end convention with CR LF. |
1097 "Check if the we use DOS/Windows line end convention with CR LF. |
1096 The LF has already been consumed by the conversion to a StringCollection, |
1098 The LF has already been consumed by the conversion to a StringCollection, |
1097 now check for and remove the trailing left over CRs" |
1099 now check for and remove the trailing left over CRs" |
1098 |
1100 |
1099 lineEndCRLF := (aCollection size > 0 |
1101 lineEndCRLF := (aCollection size > 0 |
1100 and:[(firstLine := aCollection at:1) isString |
1102 and:[(firstLine := aCollection at:1) isString |
1101 and:[firstLine notEmpty |
1103 and:[firstLine notEmpty |
1102 and:[firstLine string endsWith:Character return]]]). |
1104 and:[firstLine string endsWith:Character return]]]). |
1103 ]. |
1105 ]. |
1104 lineEndCRLF ifTrue:[ |
1106 lineEndCRLF ifTrue:[ |
1105 list := aCollection |
1107 list := aCollection |
1106 collect:[:eachLineWithCROrNil | |
1108 collect:[:eachLineWithCROrNil | |
1107 eachLineWithCROrNil isNil |
1109 eachLineWithCROrNil isNil |
1108 ifTrue:nil |
1110 ifTrue:nil |
1109 ifFalse:[(eachLineWithCROrNil endsWith:Character return) |
1111 ifFalse:[(eachLineWithCROrNil endsWith:Character return) |
1110 ifTrue:[eachLineWithCROrNil copyButLast:1] |
1112 ifTrue:[eachLineWithCROrNil copyButLast:1] |
1111 ifFalse:[eachLineWithCROrNil]]]. |
1113 ifFalse:[eachLineWithCROrNil]]]. |
1112 ] ifFalse:[ |
1114 ] ifFalse:[ |
1113 list := aCollection. |
1115 list := aCollection. |
1114 ]. |
1116 ]. |
1115 |
1117 |
1116 nonStringsBefore := includesNonStrings. |
1118 nonStringsBefore := includesNonStrings. |
1117 fontHeightBefore := fontHeight. |
1119 fontHeightBefore := fontHeight. |
1118 includesNonStrings := false. |
1120 includesNonStrings := false. |
1119 |
1121 |
1120 list notNil ifTrue:[ |
1122 list notNil ifTrue:[ |
1121 expand ifTrue:[ |
1123 expand ifTrue:[ |
1122 self expandTabs |
1124 self expandTabs |
1123 ] ifFalse:[ |
1125 ] ifFalse:[ |
1124 scan ifTrue:[ |
1126 scan ifTrue:[ |
1125 includesNonStrings := list contains:[:e | e isString not]. |
1127 includesNonStrings := list contains:[:e | e isString not]. |
1126 ] ifFalse:[ |
1128 ] ifFalse:[ |
1127 includesNonStrings := nonStringsIfNoScan ? nonStringsBefore |
1129 includesNonStrings := nonStringsIfNoScan ? nonStringsBefore |
1128 ] |
1130 ] |
1129 ]. |
1131 ]. |
1130 ]. |
1132 ]. |
1131 (includesNonStrings ~~ nonStringsBefore) ifTrue:[ |
1133 (includesNonStrings ~~ nonStringsBefore) ifTrue:[ |
1132 self getFontParameters. |
1134 self getFontParameters. |
1133 ]. |
1135 ]. |
1134 |
1136 |
1135 widthOfWidestLine := nil. "/ i.e. unknown |
1137 widthOfWidestLine := nil. "/ i.e. unknown |
1136 oldFirst := firstLineShown. |
1138 oldFirst := firstLineShown. |
1137 oldLeft := viewOrigin x. |
1139 oldLeft := viewOrigin x. |
1138 |
1140 |
1139 (includesNonStrings ~~ nonStringsBefore) ifTrue:[ |
1141 (includesNonStrings ~~ nonStringsBefore) ifTrue:[ |
1140 self computeNumberOfLinesShown. |
1142 self computeNumberOfLinesShown. |
1141 ]. |
1143 ]. |
1142 |
1144 |
1143 scrollLocked ifFalse:[ |
1145 scrollLocked ifFalse:[ |
1144 newLeftOffset := viewOrigin x. |
1146 newLeftOffset := viewOrigin x. |
1145 scrollToTop ifTrue:[ |
1147 scrollToTop ifTrue:[ |
1146 firstLineShown := 1. |
1148 firstLineShown := 1. |
1147 newLeftOffset := 0. |
1149 newLeftOffset := 0. |
1148 ] ifFalse:[ |
1150 ] ifFalse:[ |
1149 scrollToEnd ifTrue:[ |
1151 scrollToEnd ifTrue:[ |
1150 firstLineShown := (list size - nFullLinesShown + 1) max:1. |
1152 firstLineShown := (list size - nFullLinesShown + 1) max:1. |
1151 newLeftOffset := 0. |
1153 newLeftOffset := 0. |
1152 ] |
1154 ] |
1153 ]. |
1155 ]. |
1154 newLeftOffset > 0 ifTrue:[ |
1156 newLeftOffset > 0 ifTrue:[ |
1155 wText := self widthOfContents. |
1157 wText := self widthOfContents. |
1156 (viewOrigin x + self innerWidth) > wText ifTrue:[ |
1158 (viewOrigin x + self innerWidth) > wText ifTrue:[ |
1157 newLeftOffset := (wText - self innerWidth) max:0. |
1159 newLeftOffset := (wText - self innerWidth) max:0. |
1158 ]. |
1160 ]. |
1159 ]. |
1161 ]. |
1160 newLeftOffset ~= oldLeft ifTrue:[ |
1162 newLeftOffset ~= oldLeft ifTrue:[ |
1161 viewOrigin := newLeftOffset @ viewOrigin y. |
1163 viewOrigin := newLeftOffset @ viewOrigin y. |
1162 ]. |
1164 ]. |
1163 ]. |
1165 ]. |
1164 |
1166 |
1165 realized ifTrue:[ |
1167 realized ifTrue:[ |
1166 self contentsChanged. |
1168 self contentsChanged. |
1167 scrollLocked ifFalse:[ |
1169 scrollLocked ifFalse:[ |
1168 " |
1170 " |
1169 don't use scroll here to avoid double redraw |
1171 don't use scroll here to avoid double redraw |
1170 " |
1172 " |
1171 viewOrigin := viewOrigin isNil ifTrue:[0@0] ifFalse:[(viewOrigin x) @ 0]. |
1173 viewOrigin := viewOrigin isNil ifTrue:[0@0] ifFalse:[(viewOrigin x) @ 0]. |
1172 transformation := nil. |
1174 gc transformation:nil. |
1173 |
1175 |
1174 oldFirst ~~ firstLineShown ifTrue:[ |
1176 oldFirst ~~ firstLineShown ifTrue:[ |
1175 self originChanged:0 @ ((oldFirst - 1) * fontHeight negated). |
1177 self originChanged:0 @ ((oldFirst - 1) * fontHeight negated). |
1176 ]. |
1178 ]. |
1177 ]. |
1179 ]. |
1178 doRedraw ifTrue:[ |
1180 doRedraw ifTrue:[ |
1179 shown ifTrue:[ |
1181 shown ifTrue:[ |
1180 self invalidate. |
1182 self invalidate. |
1181 ] |
1183 ] |
1182 ] |
1184 ] |
1183 ] |
1185 ] |
1184 |
1186 |
1185 "Modified: / 30-08-1995 / 19:07:13 / claus" |
1187 "Modified: / 30-08-1995 / 19:07:13 / claus" |
1186 "Created: / 05-06-1997 / 12:40:06 / cg" |
1188 "Created: / 05-06-1997 / 12:40:06 / cg" |
1187 "Modified: / 04-07-2006 / 19:12:39 / fm" |
1189 "Modified: / 04-07-2006 / 19:12:39 / fm" |
1364 "set the contents (a collection of strings); |
1366 "set the contents (a collection of strings); |
1365 do not change position (i.e. do not scroll). |
1367 do not change position (i.e. do not scroll). |
1366 This can be used to update a self-changing list |
1368 This can be used to update a self-changing list |
1367 (for example: a file list being shown, without disturbing the user too much)" |
1369 (for example: a file list being shown, without disturbing the user too much)" |
1368 |
1370 |
1369 self |
1371 self |
1370 setList:aCollection expandTabs:expandTabs scanForNonStrings:true includesNonStrings:nil |
1372 setList:aCollection expandTabs:expandTabs scanForNonStrings:true includesNonStrings:nil |
1371 redraw:doRedraw |
1373 redraw:doRedraw |
1372 ! |
1374 ! |
1373 |
1375 |
1374 setList:aCollection expandTabs:expandTabs scanForNonStrings:scan includesNonStrings:nonStringsIfNoScan redraw:doRedraw |
1376 setList:aCollection expandTabs:expandTabs scanForNonStrings:scan includesNonStrings:nonStringsIfNoScan redraw:doRedraw |
1375 "set the contents (a collection of strings); |
1377 "set the contents (a collection of strings); |
1376 do not change position (i.e. do not scroll). |
1378 do not change position (i.e. do not scroll). |
1377 This can be used to update a self-changing list |
1379 This can be used to update a self-changing list |
1378 (for example: a file list being shown, without disturbing the user too much). |
1380 (for example: a file list being shown, without disturbing the user too much). |
1379 TODO: this stinks: most of the code is the same as in #list:expandTabs:... |
1381 TODO: this stinks: most of the code is the same as in #list:expandTabs:... |
1380 needs a refactoring" |
1382 needs a refactoring" |
1381 |
1383 |
1382 |prev| |
1384 |prev| |
1383 |
1385 |
1384 prev := scrollLocked. |
1386 prev := scrollLocked. |
1385 [ |
1387 [ |
1386 scrollLocked := false. |
1388 scrollLocked := false. |
1387 self |
1389 self |
1388 list:aCollection |
1390 list:aCollection |
1389 expandTabs:expandTabs |
1391 expandTabs:expandTabs |
1390 scanForNonStrings:scan |
1392 scanForNonStrings:scan |
1391 includesNonStrings:nonStringsIfNoScan |
1393 includesNonStrings:nonStringsIfNoScan |
1392 redraw:doRedraw |
1394 redraw:doRedraw |
1393 ] ensure:[ |
1395 ] ensure:[ |
1394 scrollLocked := prev |
1396 scrollLocked := prev |
1395 ]. |
1397 ]. |
1396 "/ |
1398 "/ |
1397 "/ |
1399 "/ |
1398 "/"/ scrollLocked ifTrue:[ |
1400 "/"/ scrollLocked ifTrue:[ |
1399 "/"/ self setList:newText expandTabs:expandTabsWhenUpdating |
1401 "/"/ self setList:newText expandTabs:expandTabsWhenUpdating |
1400 "/"/ ] ifFalse:[ |
1402 "/"/ ] ifFalse:[ |
1401 "/ self list:newText expandTabs:expandTabsWhenUpdating scanForNonStrings:expandTabsWhenUpdating |
1403 "/ self list:newText expandTabs:expandTabsWhenUpdating scanForNonStrings:expandTabsWhenUpdating |
1402 "/"/ ] |
1404 "/"/ ] |
1914 |
1916 |
1915 y := self yOfVisibleLine:startVisLineNr. |
1917 y := self yOfVisibleLine:startVisLineNr. |
1916 sH := lineSpacing // 2. |
1918 sH := lineSpacing // 2. |
1917 |
1919 |
1918 backgroundAlreadyClearedColor == bg ifFalse:[ |
1920 backgroundAlreadyClearedColor == bg ifFalse:[ |
1919 self paint:bg. |
1921 self paint:bg. |
1920 self fillRectangleX:margin |
1922 self fillRectangleX:margin |
1921 y:y-sH |
1923 y:y-sH |
1922 width:(width - (margin * 2)) |
1924 width:(width - (margin * 2)) |
1923 height:(endVisLineNr - startVisLineNr + 1) * fontHeight + (lineSpacing - sH). |
1925 height:(endVisLineNr - startVisLineNr + 1) * fontHeight + (lineSpacing - sH). |
1924 ]. |
1926 ]. |
1925 list isNil ifTrue:[^ self]. |
1927 list isNil ifTrue:[^ self]. |
1926 |
1928 |
1927 y := y + fontAscent. |
1929 y := y + fontAscent. |
1928 listSize := self size. |
1930 listSize := self size. |
1929 |
1931 |
1930 startLine := startVisLineNr + firstLineShown - 1. |
1932 startLine := startVisLineNr + firstLineShown - 1. |
1931 endLine := endVisLineNr + firstLineShown - 1. |
1933 endLine := endVisLineNr + firstLineShown - 1. |
1932 (startLine == 0) ifTrue:[ |
1934 (startLine == 0) ifTrue:[ |
1933 y := y + fontHeight. |
1935 y := y + fontHeight. |
1934 startLine := startLine + 1 |
1936 startLine := startLine + 1 |
1935 ]. |
1937 ]. |
1936 |
1938 |
1937 (endLine > listSize) ifTrue:[ |
1939 (endLine > listSize) ifTrue:[ |
1938 e := listSize |
1940 e := listSize |
1939 ] ifFalse:[ |
1941 ] ifFalse:[ |
1940 e := endLine |
1942 e := endLine |
1941 ]. |
1943 ]. |
1942 |
1944 |
1943 (startLine <= e) ifTrue:[ |
1945 (startLine <= e) ifTrue:[ |
1944 x := textStartLeft - viewOrigin x. |
1946 x := textStartLeft - viewOrigin x. |
1945 self paint:fg on:bg. |
1947 self paint:fg on:bg. |
1946 "/ don't use list from:to:do:, to allow for subclasses to redefine the enumeration (TableView) |
1948 "/ don't use list from:to:do:, to allow for subclasses to redefine the enumeration (TableView) |
1947 self from:startLine to:e do:[:line | |
1949 self from:startLine to:e do:[:line | |
1948 line notNil ifTrue:[ |
1950 line notNil ifTrue:[ |
1949 "/ remove line's color emphasis, to enforce color. |
1951 "/ remove line's color emphasis, to enforce color. |
1950 "/ otherwise blue text is not visible if selection-bg is blue |
1952 "/ otherwise blue text is not visible if selection-bg is blue |
1951 l := self withoutColorEmphasis:line ifFg:fg andBg:bg. |
1953 l := self withoutColorEmphasis:line ifFg:fg andBg:bg. |
1952 self displayOpaqueString:l x:x y:y |
1954 self displayOpaqueString:l x:x y:y |
1953 ]. |
1955 ]. |
1954 y := y + fontHeight |
1956 y := y + fontHeight |
1955 ] |
1957 ] |
1956 ] |
1958 ] |
1957 |
1959 |
1958 "Modified: / 15.12.1999 / 23:19:39 / cg" |
1960 "Modified: / 15.12.1999 / 23:19:39 / cg" |
1959 ! |
1961 ! |
1960 |
1962 |
2159 "draw right part of a visible line from startCol to end of line in fg/bg" |
2161 "draw right part of a visible line from startCol to end of line in fg/bg" |
2160 |
2162 |
2161 |y x index1 index2 lineWithoutColor| |
2163 |y x index1 index2 lineWithoutColor| |
2162 |
2164 |
2163 (startCol < 1) ifTrue:[ |
2165 (startCol < 1) ifTrue:[ |
2164 index1 := 1 |
2166 index1 := 1 |
2165 ] ifFalse:[ |
2167 ] ifFalse:[ |
2166 index1 := startCol |
2168 index1 := startCol |
2167 ]. |
2169 ]. |
2168 y := self yOfVisibleLine:visLineNr. |
2170 y := self yOfVisibleLine:visLineNr. |
2169 x := (self xOfCol:index1 inVisibleLine:visLineNr) - viewOrigin x. |
2171 x := (self xOfCol:index1 inVisibleLine:visLineNr) - viewOrigin x. |
2170 backgroundAlreadyClearedColor == bg ifFalse:[ |
2172 backgroundAlreadyClearedColor == bg ifFalse:[ |
2171 self paint:bg. |
2173 self paint:bg. |
2172 self fillRectangleX:x y:y - (lineSpacing // 2) |
2174 self fillRectangleX:x y:y - (lineSpacing // 2) |
2173 width:(width + viewOrigin x - x) |
2175 width:(width + viewOrigin x - x) |
2174 height:fontHeight. |
2176 height:fontHeight. |
2175 ]. |
2177 ]. |
2176 lineString notNil ifTrue:[ |
2178 lineString notNil ifTrue:[ |
2177 lineString isString ifFalse:[ |
2179 lineString isString ifFalse:[ |
2178 self drawLine:lineString inVisible:visLineNr from:startCol to:nil with:fg and:bg. |
2180 self drawLine:lineString inVisible:visLineNr from:startCol to:nil with:fg and:bg. |
2179 ] ifTrue:[ |
2181 ] ifTrue:[ |
2180 lineWithoutColor := self withoutColorEmphasis:lineString ifFg:fg andBg:bg. |
2182 lineWithoutColor := self withoutColorEmphasis:lineString ifFg:fg andBg:bg. |
2181 index2 := lineWithoutColor size. |
2183 index2 := lineWithoutColor size. |
2182 (index2 < index1) ifTrue:[^ self]. |
2184 (index2 < index1) ifTrue:[^ self]. |
2183 (index1 <= index2) ifTrue:[ |
2185 (index1 <= index2) ifTrue:[ |
2184 self paint:fg on:bg. |
2186 self paint:fg on:bg. |
2185 "/ self displayOpaqueString:lineWithoutColor from:index1 to:index2 x:x y:(y + fontAscent) |
2187 "/ self displayOpaqueString:lineWithoutColor from:index1 to:index2 x:x y:(y + fontAscent) |
2186 self displayString:lineWithoutColor from:index1 to:index2 x:x y:(y + fontAscent) |
2188 self displayString:lineWithoutColor from:index1 to:index2 x:x y:(y + fontAscent) |
2187 ] |
2189 ] |
2188 ] |
2190 ] |
2189 ] |
2191 ] |
2190 |
2192 |
2191 "Modified: / 15.12.1999 / 23:24:40 / cg" |
2193 "Modified: / 15.12.1999 / 23:24:40 / cg" |
2192 ! |
2194 ! |
2193 |
2195 |
2377 shown ifFalse:[^ self]. |
2378 shown ifFalse:[^ self]. |
2378 |
2379 |
2379 startLine := self visibleLineOfY:y. |
2380 startLine := self visibleLineOfY:y. |
2380 stopLine := self visibleLineOfY:(y + h). |
2381 stopLine := self visibleLineOfY:(y + h). |
2381 |
2382 |
2382 saveClip := clipRect. |
2383 saveClip := gc clippingBoundsOrNil. |
2383 self clippingRectangle:(Rectangle left:x top:y width:w height:h). |
2384 self clippingRectangle:(Rectangle left:x top:y width:w height:h). |
2384 self paint:bgColor. |
2385 self paint:bgColor. |
2385 self fillRectangleX:x y:y width:w height:h. |
2386 self fillRectangleX:x y:y width:w height:h. |
2386 backgroundAlreadyClearedColor := bgColor. |
2387 backgroundAlreadyClearedColor := bgColor. |
2387 |
2388 |
2388 (includesNonStrings or:[w > (width // 4 * 3)]) ifTrue:[ |
2389 (includesNonStrings or:[w > (width // 4 * 3)]) ifTrue:[ |
2389 "includes non strings or area is big enough: redraw whole lines" |
2390 "includes non strings or area is big enough: redraw whole lines" |
2390 self redrawFromVisibleLine:startLine to:stopLine |
2391 self redrawFromVisibleLine:startLine to:stopLine |
2391 ] ifFalse:[ |
2392 ] ifFalse:[ |
2392 line := self visibleAt:startLine. |
2393 line := self visibleAt:startLine. |
2393 |
2394 |
2394 (fontIsFixedWidth and:[line isSingleByteString]) ifFalse:[ |
2395 (fontIsFixedWidth and:[line isSingleByteString]) ifFalse:[ |
2395 "start/end col has to be computed for each line" |
2396 "start/end col has to be computed for each line" |
2396 |
2397 |
2397 startLine to:stopLine do:[:i | |
2398 startLine to:stopLine do:[:i | |
2398 startCol := self colOfX:x inVisibleLine:i. |
2399 startCol := self colOfX:x inVisibleLine:i. |
2399 endCol := self colOfX:(x + w) inVisibleLine:i. |
2400 endCol := self colOfX:(x + w) inVisibleLine:i. |
2400 startCol > 0 ifTrue:[ |
2401 startCol > 0 ifTrue:[ |
2401 endCol > 0 ifTrue:[ |
2402 endCol > 0 ifTrue:[ |
2402 self redrawVisibleLine:i from:startCol to:endCol |
2403 self redrawVisibleLine:i from:startCol to:endCol |
2403 ] |
2404 ] |
2404 ] |
2405 ] |
2405 ] |
2406 ] |
2406 ] ifTrue:[ |
2407 ] ifTrue:[ |
2407 "start/end col is the same for all lines" |
2408 "start/end col is the same for all lines" |
2408 startCol := self colOfX:x inVisibleLine:startLine. |
2409 startCol := self colOfX:x inVisibleLine:startLine. |
2409 endCol := self colOfX:(x + w) inVisibleLine:startLine. |
2410 endCol := self colOfX:(x + w) inVisibleLine:startLine. |
2410 startCol > 0 ifTrue:[ |
2411 startCol > 0 ifTrue:[ |
2411 endCol > 0 ifTrue:[ |
2412 endCol > 0 ifTrue:[ |
2412 startLine to:stopLine do:[:i | |
2413 startLine to:stopLine do:[:i | |
2413 line := self visibleAt:i. |
2414 line := self visibleAt:i. |
2414 (line isSingleByteString) ifTrue:[ |
2415 (line isSingleByteString) ifTrue:[ |
2415 self redrawVisibleLine:i from:startCol to:endCol |
2416 self redrawVisibleLine:i from:startCol to:endCol |
2416 ] ifFalse:[ |
2417 ] ifFalse:[ |
2417 self redrawVisibleLine:i |
2418 self redrawVisibleLine:i |
2418 ] |
2419 ] |
2419 ] |
2420 ] |
2420 ] |
2421 ] |
2421 ] |
2422 ] |
2422 ] |
2423 ] |
2423 ]. |
2424 ]. |
2424 backgroundAlreadyClearedColor := nil. |
2425 backgroundAlreadyClearedColor := nil. |
2425 self clippingRectangle:saveClip. |
2426 self clippingRectangle:saveClip. |
2426 ! |
2427 ! |
2427 |
2428 |
2659 " |
2660 " |
2660 for fix fonts, this is easy ... |
2661 for fix fonts, this is easy ... |
2661 " |
2662 " |
2662 (fontIsFixedWidth |
2663 (fontIsFixedWidth |
2663 and:[lineString isNil |
2664 and:[lineString isNil |
2664 or:[lineString hasChangeOfEmphasis not]]) ifTrue:[ |
2665 or:[lineString hasChangeOfEmphasis not]]) ifTrue:[ |
2665 ^ (xRel // fontWidth) + 1 |
2666 ^ (xRel // fontWidth) + 1 |
2666 ]. |
2667 ]. |
2667 |
2668 |
2668 " |
2669 " |
2669 for variable fonts, more work is required ... |
2670 for variable fonts, more work is required ... |
2670 " |
2671 " |
2671 lineString notNil ifTrue:[ |
2672 lineString notNil ifTrue:[ |
2672 lineString := self visibleStringFrom:lineString. |
2673 lineString := self visibleStringFrom:lineString. |
2673 (hasEmphasis := lineString hasChangeOfEmphasis) ifTrue:[ |
2674 (hasEmphasis := lineString hasChangeOfEmphasis) ifTrue:[ |
2674 linePixelWidth := lineString widthOn:self |
2675 linePixelWidth := lineString widthOn:self |
2675 ] ifFalse:[ |
2676 ] ifFalse:[ |
2676 lineString := lineString string. |
2677 lineString := lineString string. |
2677 linePixelWidth := font widthOf:lineString. |
2678 linePixelWidth := gc font widthOf:lineString. |
2678 ] |
2679 ] |
2679 ] ifFalse:[ |
2680 ] ifFalse:[ |
2680 linePixelWidth := 0 |
2681 linePixelWidth := 0 |
2681 ]. |
2682 ]. |
2682 |
2683 |
2683 (linePixelWidth <= xRel) ifTrue:[ |
2684 (linePixelWidth <= xRel) ifTrue:[ |
2684 fontWidth == 0 ifTrue:[ |
2685 fontWidth == 0 ifTrue:[ |
2685 " |
2686 " |
2686 although this 'cannot happen', |
2687 although this 'cannot happen', |
2687 it seems that X reports this width for some strange fonts ... |
2688 it seems that X reports this width for some strange fonts ... |
2688 " |
2689 " |
2689 ^ lineString size |
2690 ^ lineString size |
2690 ]. |
2691 ]. |
2691 ^ lineString size + ((xRel - linePixelWidth) // fontWidth) + 1 |
2692 ^ lineString size + ((xRel - linePixelWidth) // fontWidth) + 1 |
2692 ]. |
2693 ]. |
2693 |
2694 |
2694 "/ cannot simply count individual characters, |
2695 "/ cannot simply count individual characters, |
2695 "/ since kerning or other non-linear effects may be involved ... |
2696 "/ since kerning or other non-linear effects may be involved ... |
2696 "/ use a binary search, initialized with some guess. |
2697 "/ use a binary search, initialized with some guess. |
2697 |
2698 |
2698 "/ a guess: take some 'average' character's width and compute an initial guess |
2699 "/ a guess: take some 'average' character's width and compute an initial guess |
2699 runCol := x // (font widthOf:'e'). |
2700 runCol := x // (gc font widthOf:'e'). |
2700 runCol := runCol min:lineString size. |
2701 runCol := runCol min:lineString size. |
2701 |
2702 |
2702 "/ runCol := lineString size // 2. |
2703 "/ runCol := lineString size // 2. |
2703 "/ (runCol == 0) ifTrue:[runCol := 1]. |
2704 "/ (runCol == 0) ifTrue:[runCol := 1]. |
2704 |
2705 |
2705 hasEmphasis ifTrue:[ |
2706 hasEmphasis ifTrue:[ |
2706 posLeft := (lineString copyFrom:1 to:(runCol - 1)) widthOn:self. |
2707 posLeft := (lineString copyFrom:1 to:(runCol - 1)) widthOn:self. |
2707 posRight := (lineString copyFrom:1 to:runCol) widthOn:self. |
2708 posRight := (lineString copyFrom:1 to:runCol) widthOn:self. |
2708 ] ifFalse:[ |
2709 ] ifFalse:[ |
2709 posLeft := font widthOf:lineString from:1 to:(runCol - 1). |
2710 posLeft := gc font widthOf:lineString from:1 to:(runCol - 1). |
2710 posRight := font widthOf:lineString from:1 to:runCol. |
2711 posRight := gc font widthOf:lineString from:1 to:runCol. |
2711 ]. |
2712 ]. |
2712 |
2713 |
2713 done := (posLeft <= xRel) and:[posRight > xRel]. |
2714 done := (posLeft <= xRel) and:[posRight > xRel]. |
2714 |
2715 |
2715 [done] whileFalse:[ |
2716 [done] whileFalse:[ |
2716 oPosRight := posRight. |
2717 oPosRight := posRight. |
2717 oPosLeft := posLeft. |
2718 oPosLeft := posLeft. |
2718 |
2719 |
2719 (posRight <= xRel) ifTrue:[ |
2720 (posRight <= xRel) ifTrue:[ |
2720 runCol := runCol + 1. |
2721 runCol := runCol + 1. |
2721 posLeft := posRight. |
2722 posLeft := posRight. |
2722 hasEmphasis ifTrue:[ |
2723 hasEmphasis ifTrue:[ |
2723 posRight := (lineString copyFrom:1 to:runCol) widthOn:self. |
2724 posRight := (lineString copyFrom:1 to:runCol) widthOn:self. |
2724 ] ifFalse:[ |
2725 ] ifFalse:[ |
2725 posRight := font widthOf:lineString from:1 to:runCol |
2726 posRight := gc font widthOf:lineString from:1 to:runCol |
2726 ] |
2727 ] |
2727 ] ifFalse:[ |
2728 ] ifFalse:[ |
2728 (posLeft > xRel) ifTrue:[ |
2729 (posLeft > xRel) ifTrue:[ |
2729 runCol := runCol - 1. |
2730 runCol := runCol - 1. |
2730 (runCol == 0) ifTrue:[^ 0]. |
2731 (runCol == 0) ifTrue:[^ 0]. |
2731 posRight := posLeft. |
2732 posRight := posLeft. |
2732 hasEmphasis ifTrue:[ |
2733 hasEmphasis ifTrue:[ |
2733 posLeft := (lineString copyFrom:1 to:(runCol - 1)) widthOn:self. |
2734 posLeft := (lineString copyFrom:1 to:(runCol - 1)) widthOn:self. |
2734 ] ifFalse:[ |
2735 ] ifFalse:[ |
2735 posLeft := font widthOf:lineString from:1 to:(runCol - 1) |
2736 posLeft := gc font widthOf:lineString from:1 to:(runCol - 1) |
2736 ] |
2737 ] |
2737 ] |
2738 ] |
2738 ]. |
2739 ]. |
2739 done := (posLeft <= xRel) and:[posRight > xRel]. |
2740 done := (posLeft <= xRel) and:[posRight > xRel]. |
2740 "234567890123456789012345678901234567890" |
2741 "234567890123456789012345678901234567890" |
2741 ((oPosRight == posRight) and:[oPosLeft == posLeft]) ifTrue:[ |
2742 ((oPosRight == posRight) and:[oPosLeft == posLeft]) ifTrue:[ |
2742 "/ paranoia: just in case there are unprintable characters |
2743 "/ paranoia: just in case there are unprintable characters |
2743 "/ (avoid endless loop if the binary search does not make progress) |
2744 "/ (avoid endless loop if the binary search does not make progress) |
2744 done := true. |
2745 done := true. |
2745 ] |
2746 ] |
2746 ]. |
2747 ]. |
2747 "/self paint:Color red. |
2748 "/self paint:Color red. |
2748 "/self displayRectangleX:posLeft+textStartLeft-viewOrigin x y:(self yOfVisibleLine:visLineNr) |
2749 "/self displayRectangleX:posLeft+textStartLeft-viewOrigin x y:(self yOfVisibleLine:visLineNr) |
2749 "/ width:(posRight-posLeft) height:fontHeight. |
2750 "/ width:(posRight-posLeft) height:fontHeight. |
2750 "/self paint:Color black. |
2751 "/self paint:Color black. |
2847 The code below uses the font's average height parameters - these |
2848 The code below uses the font's average height parameters - these |
2848 are not OK for some oversized national characters (such as A-dieresis). |
2849 are not OK for some oversized national characters (such as A-dieresis). |
2849 Therefore, this method should be redefined in views which will be used |
2850 Therefore, this method should be redefined in views which will be used |
2850 with national characters (i.e. editTextViews)." |
2851 with national characters (i.e. editTextViews)." |
2851 |
2852 |
2852 |hMax| |
2853 |hMax newDeviceFont| |
2853 |
2854 |
2854 font := font onDevice:device. |
2855 newDeviceFont := gc createFontOnDevice. |
2855 hMax := font height. |
2856 hMax := newDeviceFont height. |
2856 |
2857 |
2857 includesNonStrings == true ifTrue:[ |
2858 includesNonStrings == true ifTrue:[ |
2858 "/ |
2859 "/ |
2859 "/ find maximum height of lines |
2860 "/ find maximum height of lines |
2860 "/ |
2861 "/ |
2861 hMax := list inject:hMax into:[:maxSoFar :thisLine | |
2862 hMax := list inject:hMax into:[:maxSoFar :thisLine | |
2862 thisLine isNil ifTrue:[ |
2863 thisLine isNil ifTrue:[ |
2863 maxSoFar |
2864 maxSoFar |
2864 ] ifFalse:[ |
2865 ] ifFalse:[ |
2865 (thisLine isSingleByteString) ifTrue:[ |
2866 (thisLine isSingleByteString) ifTrue:[ |
2866 maxSoFar |
2867 maxSoFar |
2867 ] ifFalse:[ |
2868 ] ifFalse:[ |
2868 maxSoFar max:(thisLine heightOn:self) |
2869 maxSoFar max:(thisLine heightOn:self) |
2869 ] |
2870 ] |
2870 ] |
2871 ] |
2871 ]. |
2872 ]. |
2872 |
2873 |
2873 ]. |
2874 ]. |
2874 fontHeight := font maxHeight. |
2875 fontHeight := newDeviceFont maxHeight. |
2875 "/ fontHeight := font height. |
2876 "/ fontHeight := font height. |
2876 fontHeight := fontHeight max:(hMax + lineSpacing). |
2877 fontHeight := fontHeight max:(hMax + lineSpacing). |
2877 fontAscent := font ascent. "/ maxAscent. -- see SelectionInListViews selection in motif style |
2878 fontAscent := newDeviceFont ascent. "/ maxAscent. -- see SelectionInListViews selection in motif style |
2878 "/ fontAscent := font maxAscent "ascent". "/ maxAscent. -- see SelectionInListViews selection in motif style |
2879 "/ fontAscent := font maxAscent "ascent". "/ maxAscent. -- see SelectionInListViews selection in motif style |
2879 "/ fontAscent := (font maxAscent + font ascent) // 2. "/ maxAscent. -- see SelectionInListViews selection in motif style |
2880 "/ fontAscent := (font maxAscent + font ascent) // 2. "/ maxAscent. -- see SelectionInListViews selection in motif style |
2880 fontWidth := font width. |
2881 fontWidth := newDeviceFont width. |
2881 fontIsFixedWidth := font isFixedWidth. |
2882 fontIsFixedWidth := newDeviceFont isFixedWidth. |
2882 |
2883 |
2883 "Modified: 3.7.1997 / 12:24:25 / cg" |
2884 "Modified: 3.7.1997 / 12:24:25 / cg" |
2884 ! |
2885 ! |
2885 |
2886 |
2886 getListFromModel |
2887 getListFromModel |
2888 If there is no listMessage, try aspect for backward compatibility." |
2889 If there is no listMessage, try aspect for backward compatibility." |
2889 |
2890 |
2890 |newText msg doCompareIfUnchanged| |
2891 |newText msg doCompareIfUnchanged| |
2891 |
2892 |
2892 model notNil ifTrue:[ |
2893 model notNil ifTrue:[ |
2893 msg := listMsg ? aspectMsg. |
2894 msg := listMsg ? aspectMsg. |
2894 |
2895 |
2895 msg notNil ifTrue:[ |
2896 msg notNil ifTrue:[ |
2896 doCompareIfUnchanged := compareModelOnUpdate. |
2897 doCompareIfUnchanged := compareModelOnUpdate. |
2897 |
2898 |
2898 newText := model perform:msg. |
2899 newText := model perform:msg. |
2899 "/ cg: this makes many optimizations (virtualArray) useless; |
2900 "/ cg: this makes many optimizations (virtualArray) useless; |
2900 "/ I do not think that this is a good idea: |
2901 "/ I do not think that this is a good idea: |
2901 "/ text notNil ifTrue:[ |
2902 "/ text notNil ifTrue:[ |
2902 "/ so I changed it to: |
2903 "/ so I changed it to: |
2903 (newText notNil and:[newText isString]) ifTrue:[ |
2904 (newText notNil and:[newText isString]) ifTrue:[ |
2904 newText := newText asStringCollection. |
2905 newText := newText asStringCollection. |
2905 ] ifFalse:[ |
2906 ] ifFalse:[ |
2906 newText == model ifTrue:[ |
2907 newText == model ifTrue:[ |
2907 "/ I must operate on a copy |
2908 "/ I must operate on a copy |
2908 newText := model asNewOrderedCollection. |
2909 newText := model asNewOrderedCollection. |
2909 "/ doCompareIfUnchanged := false. |
2910 "/ doCompareIfUnchanged := false. |
2910 ]. |
2911 ]. |
2911 ]. |
2912 ]. |
2912 |
2913 |
2913 doCompareIfUnchanged ifTrue:[ |
2914 doCompareIfUnchanged ifTrue:[ |
2914 "/ see if there is a change at all. |
2915 "/ see if there is a change at all. |
2915 "/ use to compare using =, but that's not enough in case of emphasis change. |
2916 "/ use to compare using =, but that's not enough in case of emphasis change. |
2916 newText size == list size ifTrue:[ |
2917 newText size == list size ifTrue:[ |
2917 |same| |
2918 |same| |
2918 |
2919 |
2919 same := true. |
2920 same := true. |
2920 newText size > 0 ifTrue:[ |
2921 newText size > 0 ifTrue:[ |
2921 newText with:list do:[:eachNewLine :eachOldLine | |
2922 newText with:list do:[:eachNewLine :eachOldLine | |
2922 (eachNewLine == eachOldLine) ifFalse:[ |
2923 (eachNewLine == eachOldLine) ifFalse:[ |
2923 same := false. |
2924 same := false. |
2924 ] |
2925 ] |
2925 ] |
2926 ] |
2926 ]. |
2927 ]. |
2927 same ifTrue:[^ self]. |
2928 same ifTrue:[^ self]. |
2928 ]. |
2929 ]. |
2929 ]. |
2930 ]. |
2930 |
2931 |
2931 "/ SV: this compare does not work, if model uses (i.e. updates) |
2932 "/ SV: this compare does not work, if model uses (i.e. updates) |
2932 "/ the same stringCollection as the view!! |
2933 "/ the same stringCollection as the view!! |
2933 true "text ~= list" ifTrue:[ |
2934 true "text ~= list" ifTrue:[ |
2934 "/ changed #list to care for scrollLocked |
2935 "/ changed #list to care for scrollLocked |
2935 "/ scrollLocked ifTrue:[ |
2936 "/ scrollLocked ifTrue:[ |
2936 "/ self setList:newText expandTabs:expandTabsWhenUpdating |
2937 "/ self setList:newText expandTabs:expandTabsWhenUpdating |
2937 "/ ] ifFalse:[ |
2938 "/ ] ifFalse:[ |
2938 self list:newText expandTabs:expandTabsWhenUpdating scanForNonStrings:expandTabsWhenUpdating |
2939 self list:newText expandTabs:expandTabsWhenUpdating scanForNonStrings:expandTabsWhenUpdating |
2939 "/ ] |
2940 "/ ] |
2940 ]. |
2941 ]. |
2941 ]. |
2942 ]. |
2942 ]. |
2943 ]. |
2943 |
2944 |
2944 "Modified: 26.4.1996 / 14:09:42 / cg" |
2945 "Modified: 26.4.1996 / 14:09:42 / cg" |
2945 "Modified: 19.2.1997 / 12:08:50 / stefan" |
2946 "Modified: 19.2.1997 / 12:08:50 / stefan" |
2946 ! |
2947 ! |
3062 self recomputeWidthOfWidestLineFor:aString old:nil |
3063 self recomputeWidthOfWidestLineFor:aString old:nil |
3063 ! |
3064 ! |
3064 |
3065 |
3065 recomputeWidthOfWidestLineFor:newEntry old:oldEntry |
3066 recomputeWidthOfWidestLineFor:newEntry old:oldEntry |
3066 "a new line was added (oldEntry == nil) or replaced oldEntry. |
3067 "a new line was added (oldEntry == nil) or replaced oldEntry. |
3067 Update the widthOfWidestLine cache or flush it, if we cannot easily |
3068 Update the widthOfWidestLine cache or flush it, if we cannot easily |
3068 figure out the overall text width" |
3069 figure out the overall text width" |
3069 |
3070 |
3070 |newW oldW| |
3071 |newW oldW| |
3071 |
3072 |
3072 widthOfWidestLine notNil ifTrue:[ |
3073 widthOfWidestLine notNil ifTrue:[ |
3073 newEntry isNil ifTrue:[ |
3074 newEntry isNil ifTrue:[ |
3074 newW := 0 |
3075 newW := 0 |
3075 ] ifFalse:[ |
3076 ] ifFalse:[ |
3076 (newEntry isSingleByteString) ifTrue:[ |
3077 (newEntry isSingleByteString) ifTrue:[ |
3077 newW := font widthOf:newEntry |
3078 newW := gc font widthOf:newEntry |
3078 ] ifFalse:[ |
3079 ] ifFalse:[ |
3079 newW := newEntry widthOn:self |
3080 newW := newEntry widthOn:self |
3080 ]. |
3081 ]. |
3081 ]. |
3082 ]. |
3082 |
3083 |
3083 newW >= widthOfWidestLine ifTrue:[ |
3084 newW >= widthOfWidestLine ifTrue:[ |
3084 widthOfWidestLine := newW. |
3085 widthOfWidestLine := newW. |
3085 ] ifFalse:[ |
3086 ] ifFalse:[ |
3086 oldEntry isNil ifTrue:[ |
3087 oldEntry isNil ifTrue:[ |
3087 oldW := 0 |
3088 oldW := 0 |
3088 ] ifFalse:[ |
3089 ] ifFalse:[ |
3089 (oldEntry isSingleByteString) ifTrue:[ |
3090 (oldEntry isSingleByteString) ifTrue:[ |
3090 oldW := font widthOf:oldEntry |
3091 oldW := gc font widthOf:oldEntry |
3091 ] ifFalse:[ |
3092 ] ifFalse:[ |
3092 oldW := oldEntry widthOn:self |
3093 oldW := oldEntry widthOn:self |
3093 ]. |
3094 ]. |
3094 ]. |
3095 ]. |
3095 newW > oldW ifTrue:[ |
3096 newW > oldW ifTrue:[ |
3096 "/ no change; new entries width is between this width and amx width |
3097 "/ no change; new entries width is between this width and amx width |
3097 ] ifFalse:[ |
3098 ] ifFalse:[ |
3098 "/ new entry is smaller than oldEntry; if the oldEntry was the previos max, |
3099 "/ new entry is smaller than oldEntry; if the oldEntry was the previos max, |
3099 "/ we don't know the new max |
3100 "/ we don't know the new max |
3100 oldW = widthOfWidestLine ifTrue:[ |
3101 oldW = widthOfWidestLine ifTrue:[ |
3101 widthOfWidestLine := nil "/ means: unknown |
3102 widthOfWidestLine := nil "/ means: unknown |
3102 ] ifFalse:[ |
3103 ] ifFalse:[ |
3103 "/ old line was not the widest, and new line is shorter; |
3104 "/ old line was not the widest, and new line is shorter; |
3104 "/ no change |
3105 "/ no change |
3105 ] |
3106 ] |
3106 ] |
3107 ] |
3107 ]. |
3108 ]. |
3108 ]. |
3109 ]. |
3109 ^ widthOfWidestLine |
3110 ^ widthOfWidestLine |
3110 ! |
3111 ! |
3111 |
3112 |
3112 suppressEmphasisInSelection |
3113 suppressEmphasisInSelection |
4442 dltOrg := anOrigin - viewOrigin. |
4433 dltOrg := anOrigin - viewOrigin. |
4443 |
4434 |
4444 "/ compute valid horizontal offset x |
4435 "/ compute valid horizontal offset x |
4445 |
4436 |
4446 (x := dltOrg x) ~~ 0 ifTrue:[ |
4437 (x := dltOrg x) ~~ 0 ifTrue:[ |
4447 tmp := viewOrigin x + x. |
4438 tmp := viewOrigin x + x. |
4448 |
4439 |
4449 x < 0 ifTrue:[ "/ scrolling left |
4440 x < 0 ifTrue:[ "/ scrolling left |
4450 tmp < 0 ifTrue:[x := 0 - viewOrigin x] |
4441 tmp < 0 ifTrue:[x := 0 - viewOrigin x] |
4451 ] ifFalse:[ "/ scrolling right |
4442 ] ifFalse:[ "/ scrolling right |
4452 "/ allows scrolling to the right of widest line |
4443 "/ allows scrolling to the right of widest line |
4453 max := self widthOfContents + (self additionalMarginForHorizontalScroll). |
4444 max := self widthOfContents + (self additionalMarginForHorizontalScroll). |
4454 |
4445 |
4455 tmp + width > max ifTrue:[ |
4446 tmp + width > max ifTrue:[ |
4456 x := (max - viewOrigin x - width) max:0 |
4447 x := (max - viewOrigin x - width) max:0 |
4457 ] |
4448 ] |
4458 ] |
4449 ] |
4459 ]. |
4450 ]. |
4460 |
4451 |
4461 "/ compute valid vertical offset measured in lines |
4452 "/ compute valid vertical offset measured in lines |
4462 |
4453 |
4463 (y := dltOrg y // fontHeight) ~~ 0 ifTrue:[ |
4454 (y := dltOrg y // fontHeight) ~~ 0 ifTrue:[ |
4464 tmp := firstLineShown + y. |
4455 tmp := firstLineShown + y. |
4465 |
4456 |
4466 y < 0 ifTrue:[ "/ scrolling up |
4457 y < 0 ifTrue:[ "/ scrolling up |
4467 tmp < 1 ifTrue:[y := 1 - firstLineShown] |
4458 tmp < 1 ifTrue:[y := 1 - firstLineShown] |
4468 ] ifFalse:[ "/ scrolling down |
4459 ] ifFalse:[ "/ scrolling down |
4469 max := self size. |
4460 max := self size. |
4470 |
4461 |
4471 tmp + nFullLinesShown > max ifTrue:[ |
4462 tmp + nFullLinesShown > max ifTrue:[ |
4472 y := (max - firstLineShown - nFullLinesShown + 1) max:0 |
4463 y := (max - firstLineShown - nFullLinesShown + 1) max:0 |
4473 ] |
4464 ] |
4474 ] |
4465 ] |
4475 ]. |
4466 ]. |
4476 |
4467 |
4477 (x == 0 and:[y == 0]) ifTrue:[ "/ has viewOrigin changed ? |
4468 (x == 0 and:[y == 0]) ifTrue:[ "/ has viewOrigin changed ? |
4478 ^ self |
4469 ^ self |
4479 ]. |
4470 ]. |
4480 |
4471 |
4481 (noLn := y) ~~ 0 ifTrue:[ |
4472 (noLn := y) ~~ 0 ifTrue:[ |
4482 y := y * fontHeight |
4473 y := y * fontHeight |
4483 ]. |
4474 ]. |
4484 delta := (x @ y). |
4475 delta := (x @ y). |
4485 |
4476 |
4486 newFirstLine := firstLineShown + noLn. |
4477 newFirstLine := firstLineShown + noLn. |
4487 newViewOrigin := viewOrigin + delta. |
4478 newViewOrigin := viewOrigin + delta. |
4488 |
4479 |
4489 (shown and:[doRedraw]) ifFalse:[ |
4480 (shown and:[doRedraw]) ifFalse:[ |
4490 self originWillChange. |
4481 self originWillChange. |
4491 firstLineShown := newFirstLine. |
4482 firstLineShown := newFirstLine. |
4492 viewOrigin := newViewOrigin. |
4483 viewOrigin := newViewOrigin. |
4493 self assert:(viewOrigin x >= 0). |
4484 self assert:(viewOrigin x >= 0). |
4494 ^ self originChanged:delta |
4485 ^ self originChanged:delta |
4495 ]. |
4486 ]. |
4496 |
4487 |
4497 "/ (self sensor notNil and: [self sensor hasExposeEventFor:self]) ifTrue:[ "/ outstanding expose events |
4488 "/ (self sensor notNil and: [self sensor hasExposeEventFor:self]) ifTrue:[ "/ outstanding expose events |
4498 "/ self invalidate. "/ redraw all |
4489 "/ self invalidate. "/ redraw all |
4499 "/ self originWillChange. |
4490 "/ self originWillChange. |
4502 |
4493 |
4503 ( (y ~~ 0 and:[x ~~ 0]) "/ both x and y changed |
4494 ( (y ~~ 0 and:[x ~~ 0]) "/ both x and y changed |
4504 or:[(noLn abs) >= nLinesShown "/ at least one area is |
4495 or:[(noLn abs) >= nLinesShown "/ at least one area is |
4505 or:[(x abs) > (width // 4 * 3)]] "/ big enough to redraw all |
4496 or:[(x abs) > (width // 4 * 3)]] "/ big enough to redraw all |
4506 ) ifTrue:[ |
4497 ) ifTrue:[ |
4507 self originWillChange. |
4498 self originWillChange. |
4508 firstLineShown := newFirstLine. |
4499 firstLineShown := newFirstLine. |
4509 viewOrigin := newViewOrigin. |
4500 viewOrigin := newViewOrigin. |
4510 self invalidate. |
4501 self invalidate. |
4511 ^ self originChanged:delta |
4502 ^ self originChanged:delta |
4512 ]. |
4503 ]. |
4513 |
4504 |
4514 "/ OLD: |
4505 "/ OLD: |
4515 "/ self repairDamage. |
4506 "/ self repairDamage. |
4516 |
4507 |
4517 (wg := self windowGroup) notNil ifTrue:[ |
4508 (wg := self windowGroup) notNil ifTrue:[ |
4518 wg processRealExposeEventsFor:self. |
4509 wg processRealExposeEventsFor:self. |
4519 ]. |
4510 ]. |
4520 |
4511 |
4521 self originWillChange. |
4512 self originWillChange. |
4522 |
4513 |
4523 "/ make certain, that all drawing is complete |
4514 "/ make certain, that all drawing is complete |
4524 "/ device sync. |
4515 "/ device sync. |
4525 |
4516 |
4526 self catchExpose. |
4517 self catchExpose. |
4527 |
4518 |
4528 x == 0 ifTrue:[ |
4519 x == 0 ifTrue:[ |
4529 "/ scrolling vertical |
4520 "/ scrolling vertical |
4530 |
4521 |
4531 y0 := textStartTop + (y abs). |
4522 y0 := textStartTop + (y abs). |
4532 h := hBefore - margin - y0. |
4523 h := hBefore - margin - y0. |
4533 w := wBefore - margin. |
4524 w := wBefore - margin. |
4534 y > 0 ifTrue:[ "/ copy down |
4525 y > 0 ifTrue:[ "/ copy down |
4535 "/ kludge: if the selection highlighting draws into the textStartTop area, |
4526 "/ kludge: if the selection highlighting draws into the textStartTop area, |
4536 "/ the copy below leaves some selection depris in the top area. |
4527 "/ the copy below leaves some selection depris in the top area. |
4537 "/ Therefore, clear the top area. |
4528 "/ Therefore, clear the top area. |
4538 "/ (should avoid this, in case we know there cannot be anything |
4529 "/ (should avoid this, in case we know there cannot be anything |
4539 "/ there - selection is nil or >= firstLineShown). |
4530 "/ there - selection is nil or >= firstLineShown). |
4540 self clearDeviceRectangleX:margin y:margin width:width-margin-margin height:(textStartTop-margin). |
4531 self clearDeviceRectangleX:margin y:margin width:width-margin-margin height:(textStartTop-margin). |
4541 "/ self invalidateDeviceRectangle:((margin@margin) corner:(width-margin@textStartTop)) repairNow:false. |
4532 "/ self invalidateDeviceRectangle:((margin@margin) corner:(width-margin@textStartTop)) repairNow:false. |
4542 |
4533 |
4543 self copyFrom:self |
4534 self copyFrom:self |
4544 x:0 y:y0 toX:0 y:textStartTop |
4535 x:0 y:y0 toX:0 y:textStartTop |
4545 width:w height:h async:true. |
4536 width:w height:h async:true. |
4546 y1 := h - 1. |
4537 y1 := h - 1. |
4547 y0 := y0 + 1. |
4538 y0 := y0 + 1. |
4548 ] ifFalse:[ "/ copy up |
4539 ] ifFalse:[ "/ copy up |
4549 self copyFrom:self |
4540 self copyFrom:self |
4550 x:margin y:textStartTop toX:margin y:y0 |
4541 x:margin y:textStartTop toX:margin y:y0 |
4551 width:w height:h async:true. |
4542 width:w height:h async:true. |
4552 y1 := 0. |
4543 y1 := 0. |
4553 ]. |
4544 ]. |
4554 |
4545 |
4555 inv := (margin@y1) extent:(w@y0+margin). |
4546 inv := (margin@y1) extent:(w@y0+margin). |
4556 ] ifFalse:[ |
4547 ] ifFalse:[ |
4557 "/ scrolling horizontal |
4548 "/ scrolling horizontal |
4558 |
4549 |
4559 x > 0 ifTrue:[ "/ scrolling right |
4550 x > 0 ifTrue:[ "/ scrolling right |
4560 y0 := margin + x. |
4551 y0 := margin + x. |
4561 y1 := wBefore - y0. |
4552 y1 := wBefore - y0. |
4562 ] ifFalse:[ "/ scrolling left |
4553 ] ifFalse:[ "/ scrolling left |
4563 y0 := margin - x. |
4554 y0 := margin - x. |
4564 y1 := 0. |
4555 y1 := 0. |
4565 ]. |
4556 ]. |
4566 h := hBefore - margin - margin. |
4557 h := hBefore - margin - margin. |
4567 w := wBefore - margin - y0. |
4558 w := wBefore - margin - y0. |
4568 |
4559 |
4569 x > 0 ifTrue:[ "/ copy right |
4560 x > 0 ifTrue:[ "/ copy right |
4570 self copyFrom:self x:y0 y:margin toX:margin y:margin |
4561 self copyFrom:self x:y0 y:margin toX:margin y:margin |
4571 width:w height:h async:true. |
4562 width:w height:h async:true. |
4572 ] ifFalse:[ "/ copy left |
4563 ] ifFalse:[ "/ copy left |
4573 "/ self copyFrom:self x:textStartLeft y:margin toX:y0 y:margin |
4564 "/ self copyFrom:self x:textStartLeft y:margin toX:y0 y:margin |
4574 "/ viewOrigin x > margin ifTrue:[ |
4565 "/ viewOrigin x > margin ifTrue:[ |
4575 "/ self copyFrom:self x:0 y:margin toX:y0-margin y:margin |
4566 "/ self copyFrom:self x:0 y:margin toX:y0-margin y:margin |
4576 "/ width:w height:h async:true. |
4567 "/ width:w height:h async:true. |
4577 "/ ] ifFalse:[ |
4568 "/ ] ifFalse:[ |
4578 self copyFrom:self x:margin y:margin toX:y0 y:margin |
4569 self copyFrom:self x:margin y:margin toX:y0 y:margin |
4579 width:w height:h async:true. |
4570 width:w height:h async:true. |
4580 "/ ]. |
4571 "/ ]. |
4581 ]. |
4572 ]. |
4582 |
4573 |
4583 inv := (y1@margin) extent:(y0@h). |
4574 inv := (y1@margin) extent:(y0@h). |
4584 ]. |
4575 ]. |
4585 |
4576 |
4586 firstLineShown := newFirstLine. |
4577 firstLineShown := newFirstLine. |
4587 viewOrigin := newViewOrigin. |
4578 viewOrigin := newViewOrigin. |
4588 |
4579 |
4589 self invalidateDeviceRectangle:inv repairNow:false. |
4580 self invalidateDeviceRectangle:inv repairNow:false. |
4590 viewOrigin x <= margin ifTrue:[ |
4581 viewOrigin x <= margin ifTrue:[ |
4591 self invalidateDeviceRectangle:((0@margin) extent:(margin@h)) repairNow:false. |
4582 self invalidateDeviceRectangle:((0@margin) extent:(margin@h)) repairNow:false. |
4592 ]. |
4583 ]. |
4593 |
4584 |
4594 self originChanged:delta. |
4585 self originChanged:delta. |
4595 self waitForExpose. |
4586 self waitForExpose. |
4596 |
4587 |
4597 (wg := self windowGroup) notNil ifTrue:[ |
4588 (wg := self windowGroup) notNil ifTrue:[ |
4598 wg processRealExposeEventsFor:self. |
4589 wg processRealExposeEventsFor:self. |
4599 ]. |
4590 ]. |
4600 |
4591 |
4601 "/ (hBefore ~= height or:[wBefore ~= width]) ifTrue:[ |
4592 "/ (hBefore ~= height or:[wBefore ~= width]) ifTrue:[ |
4602 "/ self halt. |
4593 "/ self halt. |
4603 "/ ]. |
4594 "/ ]. |
4743 patternSize := pattern size. |
4734 patternSize := pattern size. |
4744 (list notNil |
4735 (list notNil |
4745 and:[startLine > 0 |
4736 and:[startLine > 0 |
4746 and:[patternSize ~~ 0]]) |
4737 and:[patternSize ~~ 0]]) |
4747 ifTrue:[ |
4738 ifTrue:[ |
4748 self withCursor:Cursor questionMark do:[ |
4739 self withCursor:Cursor questionMark do:[ |
4749 col := startCol - 1. |
4740 col := startCol - 1. |
4750 firstChar1 := pattern at:1. |
4741 firstChar1 := pattern at:1. |
4751 ignCase ifTrue:[ |
4742 ignCase ifTrue:[ |
4752 firstChar1 := firstChar1 asLowercase. |
4743 firstChar1 := firstChar1 asLowercase. |
4753 firstChar2 := firstChar1 asUppercase. |
4744 firstChar2 := firstChar1 asUppercase. |
4754 ] ifFalse:[ |
4745 ] ifFalse:[ |
4755 firstChar2 := firstChar1 |
4746 firstChar2 := firstChar1 |
4756 ]. |
4747 ]. |
4757 |
4748 |
4758 line1 := startLine. |
4749 line1 := startLine. |
4759 line1 > list size ifTrue:[ |
4750 line1 > list size ifTrue:[ |
4760 line1 := list size. |
4751 line1 := list size. |
4761 col := -999 |
4752 col := -999 |
4762 ] ifFalse:[ |
4753 ] ifFalse:[ |
4763 col > (list at:line1) size ifTrue:[ |
4754 col > (list at:line1) size ifTrue:[ |
4764 col := -999 |
4755 col := -999 |
4765 ] |
4756 ] |
4766 ]. |
4757 ]. |
4767 line1 to:1 by:-1 do:[:lnr | |
4758 line1 to:1 by:-1 do:[:lnr | |
4768 lineString := list at:lnr. |
4759 lineString := list at:lnr. |
4769 lineString notNil ifTrue:[ |
4760 lineString notNil ifTrue:[ |
4770 lineString := lineString asString. |
4761 lineString := lineString asString. |
4771 lineString isString ifTrue:[ |
4762 lineString isString ifTrue:[ |
4772 "/ quick check if pattern is present |
4763 "/ quick check if pattern is present |
4773 col1 := lineString |
4764 col1 := lineString |
4774 findString:pattern startingAt:1 |
4765 findString:pattern startingAt:1 |
4775 ifAbsent:0 caseSensitive: ignCase not. |
4766 ifAbsent:0 caseSensitive: ignCase not. |
4776 col1 ~~ 0 ifTrue:[ |
4767 col1 ~~ 0 ifTrue:[ |
4777 lineSize := lineString size. |
4768 lineSize := lineString size. |
4778 col == -999 ifTrue:[col := lineSize - patternSize + 1]. |
4769 col == -999 ifTrue:[col := lineSize - patternSize + 1]. |
4779 [(col > 0) |
4770 [(col > 0) |
4780 and:[(c := lineString at:col) ~= firstChar1 |
4771 and:[(c := lineString at:col) ~= firstChar1 |
4781 and:[c ~= firstChar2]]] whileTrue:[ |
4772 and:[c ~= firstChar2]]] whileTrue:[ |
4782 col := col - 1 |
4773 col := col - 1 |
4783 ]. |
4774 ]. |
4784 [col > 0] whileTrue:[ |
4775 [col > 0] whileTrue:[ |
4785 cc := col. |
4776 cc := col. |
4786 found := true. |
4777 found := true. |
4787 1 to:patternSize do:[:cnr | |
4778 1 to:patternSize do:[:cnr | |
4788 cc > lineSize ifTrue:[ |
4779 cc > lineSize ifTrue:[ |
4789 found := false |
4780 found := false |
4790 ] ifFalse:[ |
4781 ] ifFalse:[ |
4791 pc := pattern at:cnr. |
4782 pc := pattern at:cnr. |
4792 c := lineString at:cc. |
4783 c := lineString at:cc. |
4793 pc ~= c ifTrue:[ |
4784 pc ~= c ifTrue:[ |
4794 (ignCase not or:[pc asLowercase ~= c asLowercase]) ifTrue:[ |
4785 (ignCase not or:[pc asLowercase ~= c asLowercase]) ifTrue:[ |
4795 found := false |
4786 found := false |
4796 ] |
4787 ] |
4797 ] |
4788 ] |
4798 ]. |
4789 ]. |
4799 cc := cc + 1 |
4790 cc := cc + 1 |
4800 ]. |
4791 ]. |
4801 found ifTrue:[ |
4792 found ifTrue:[ |
4802 (fullWord not |
4793 (fullWord not |
4803 or:[ (self findBeginOfWordAtLine:lnr col:col) == col |
4794 or:[ (self findBeginOfWordAtLine:lnr col:col) == col |
4804 and:[ (self findEndOfWordAtLine:lnr col:col) == (col + patternSize - 1) ]] |
4795 and:[ (self findEndOfWordAtLine:lnr col:col) == (col + patternSize - 1) ]] |
4805 ) ifTrue:[ |
4796 ) ifTrue:[ |
4806 (atBeginOfLineOnly not or:[col == 1]) ifTrue:[ |
4797 (atBeginOfLineOnly not or:[col == 1]) ifTrue:[ |
4807 ^ block1 value:lnr value:col optionalArgument:nil. |
4798 ^ block1 value:lnr value:col optionalArgument:nil. |
4808 ] |
4799 ] |
4809 ] |
4800 ] |
4810 ]. |
4801 ]. |
4811 col := col - 1. |
4802 col := col - 1. |
4812 [(col > 0) |
4803 [(col > 0) |
4813 and:[(c := lineString at:col) ~= firstChar1 |
4804 and:[(c := lineString at:col) ~= firstChar1 |
4814 and:[c ~= firstChar2]]] whileTrue:[ |
4805 and:[c ~= firstChar2]]] whileTrue:[ |
4815 col := col - 1 |
4806 col := col - 1 |
4816 ] |
4807 ] |
4817 ] |
4808 ] |
4818 ] |
4809 ] |
4819 ]. |
4810 ]. |
4820 ]. |
4811 ]. |
4821 col := -999. |
4812 col := -999. |
4822 ] |
4813 ] |
4823 ] |
4814 ] |
4824 ]. |
4815 ]. |
4825 "not found" |
4816 "not found" |
4826 |
4817 |
4827 ^ block2 value |
4818 ^ block2 value |
4828 |
4819 |
4863 |
4854 |
4864 "Modified: 13.9.1997 / 01:07:11 / cg" |
4855 "Modified: 13.9.1997 / 01:07:11 / cg" |
4865 ! |
4856 ! |
4866 |
4857 |
4867 searchForwardUsingSpec:searchSpec startingAtLine:startLine col:startCol ifFound:block1 ifAbsent:block2 |
4858 searchForwardUsingSpec:searchSpec startingAtLine:startLine col:startCol ifFound:block1 ifAbsent:block2 |
4868 "search for a pattern, if found evaluate block1 with row/col as arguments, |
4859 "search for a pattern, if found evaluate block1 with row/col as arguments, |
4869 if not found evaluate block2. |
4860 if not found evaluate block2. |
4870 If the block is a three-arg block, it gets the end-col (or nil, if not known)" |
4861 If the block is a three-arg block, it gets the end-col (or nil, if not known)" |
4871 |
4862 |
4872 |lineString col pattern match regexMatch ignCase fullWord atBeginOfLineOnly |
4863 |lineString col pattern match regexMatch ignCase fullWord atBeginOfLineOnly |
4873 wrapAtEndOfText patternSize matcher lnr "{Class: SmallInteger}" |
4864 wrapAtEndOfText patternSize matcher lnr "{Class: SmallInteger}" |
4874 line1 "{Class: SmallInteger}" |
4865 line1 "{Class: SmallInteger}" |
4875 line2 "{Class: SmallInteger}" |
4866 line2 "{Class: SmallInteger}" |
4876 p realPattern runner foundCol endCol| |
4867 p realPattern runner foundCol endCol| |
4877 |
4868 |
4878 pattern := searchSpec pattern. |
4869 pattern := searchSpec pattern. |
4879 match := searchSpec match. |
4870 match := searchSpec match. |
4880 regexMatch := searchSpec regexMatch. |
4871 regexMatch := searchSpec regexMatch. |
4881 (match and:[regexMatch not]) ifTrue:[ |
4872 (match and:[regexMatch not]) ifTrue:[ |
4882 pattern := pattern globPatternAsRegexPattern. |
4873 pattern := pattern globPatternAsRegexPattern. |
4883 regexMatch := true. |
4874 regexMatch := true. |
4884 ]. |
4875 ]. |
4885 ignCase := searchSpec ignoreCase. |
4876 ignCase := searchSpec ignoreCase. |
4886 fullWord := searchSpec fullWord. |
4877 fullWord := searchSpec fullWord. |
4887 atBeginOfLineOnly := searchSpec atBeginOfLineOnly. |
4878 atBeginOfLineOnly := searchSpec atBeginOfLineOnly. |
4888 wrapAtEndOfText := searchSpec wrapAtEndOfText. |
4879 wrapAtEndOfText := searchSpec wrapAtEndOfText. |
4889 |
4880 |
4890 patternSize := pattern size. |
4881 patternSize := pattern size. |
4891 (list notNil and:[patternSize ~~ 0]) ifTrue:[ |
4882 (list notNil and:[patternSize ~~ 0]) ifTrue:[ |
4892 self withCursor:Cursor questionMark do:[ |
4883 self withCursor:Cursor questionMark do:[ |
4893 |
4884 |
4894 col := startCol + 1. |
4885 col := startCol + 1. |
4895 line1 := startLine. |
4886 line1 := startLine. |
4896 line2 := list size. |
4887 line2 := list size. |
4897 |
4888 |
4898 "/ call searchBlock with lnr, col, and line. Cares for wrap |
4889 "/ call searchBlock with lnr, col, and line. Cares for wrap |
4899 runner := |
4890 runner := |
4900 [:searchBlock | |
4891 [:searchBlock | |
4901 |didWrap| |
4892 |didWrap| |
4902 |
4893 |
4903 lnr := line1. |
4894 lnr := line1. |
4904 didWrap := false. |
4895 didWrap := false. |
4905 [lnr <= line2] whileTrue:[ |
4896 [lnr <= line2] whileTrue:[ |
4906 lineString := list at:lnr. |
4897 lineString := list at:lnr. |
4907 lineString notNil ifTrue:[ |
4898 lineString notNil ifTrue:[ |
4908 lineString := lineString asString string. |
4899 lineString := lineString asString string. |
4909 lineString isString ifTrue:[ |
4900 lineString isString ifTrue:[ |
4910 searchBlock value:lnr value:col value:lineString |
4901 searchBlock value:lnr value:col value:lineString |
4911 ] |
4902 ] |
4912 ]. |
4903 ]. |
4913 col := 1. |
4904 col := 1. |
4914 lnr := lnr + 1. |
4905 lnr := lnr + 1. |
4915 lnr > line2 ifTrue:[ |
4906 lnr > line2 ifTrue:[ |
4916 (wrapAtEndOfText and:[didWrap not]) ifTrue:[ |
4907 (wrapAtEndOfText and:[didWrap not]) ifTrue:[ |
4917 didWrap := true. |
4908 didWrap := true. |
4918 lnr := 1. |
4909 lnr := 1. |
4919 line2 := line1-1. |
4910 line2 := line1-1. |
4920 ]. |
4911 ]. |
4921 ]. |
4912 ]. |
4922 ]. |
4913 ]. |
4923 |
4914 |
4924 ]. |
4915 ]. |
4925 |
4916 |
4926 (match and:[regexMatch]) ifTrue:[ |
4917 (match and:[regexMatch]) ifTrue:[ |
4927 "perform a findMatchString (regex matching)" |
4918 "perform a findMatchString (regex matching)" |
4928 Regex::RxParser isNil ifTrue:[ |
4919 Regex::RxParser isNil ifTrue:[ |
4929 Smalltalk loadPackage:'stx:goodies/regex' |
4920 Smalltalk loadPackage:'stx:goodies/regex' |
4930 ]. |
4921 ]. |
4931 matcher := ignCase ifTrue:[pattern asRegexIgnoringCase] ifFalse:[pattern asRegex]. |
4922 matcher := ignCase ifTrue:[pattern asRegexIgnoringCase] ifFalse:[pattern asRegex]. |
4932 runner |
4923 runner |
4933 value:[:lnr :col :lineString | |
4924 value:[:lnr :col :lineString | |
4934 "/ first a crude check ... |
4925 "/ first a crude check ... |
4935 (matcher hasMatchesIn:lineString) ifTrue:[ |
4926 (matcher hasMatchesIn:lineString) ifTrue:[ |
4936 "/ find which match to show |
4927 "/ find which match to show |
4937 1 to:matcher subexpressionCount do:[:i | |
4928 1 to:matcher subexpressionCount do:[:i | |
4938 foundCol := matcher subBeginning:i. |
4929 foundCol := matcher subBeginning:i. |
4939 endCol := matcher subEnd:i. |
4930 endCol := matcher subEnd:i. |
4940 (foundCol notNil and: [endCol notNil]) ifTrue: [ |
4931 (foundCol notNil and: [endCol notNil]) ifTrue: [ |
4941 foundCol := foundCol + 1. "/ regex uses 0-based indexes (sigh) |
4932 foundCol := foundCol + 1. "/ regex uses 0-based indexes (sigh) |
4942 foundCol >= col ifTrue:[ |
4933 foundCol >= col ifTrue:[ |
4943 (atBeginOfLineOnly not or:[foundCol == 1]) ifTrue:[ |
4934 (atBeginOfLineOnly not or:[foundCol == 1]) ifTrue:[ |
4944 ^ block1 value:lnr value:foundCol optionalArgument:endCol. |
4935 ^ block1 value:lnr value:foundCol optionalArgument:endCol. |
4945 ]]]]]]. |
4936 ]]]]]]. |
4946 ] ifFalse:[ |
4937 ] ifFalse:[ |
4947 (match and:[pattern includesUnescapedMatchCharacters]) ifTrue:[ |
4938 (match and:[pattern includesUnescapedMatchCharacters]) ifTrue:[ |
4948 "perform a findMatchString (glob matching)" |
4939 "perform a findMatchString (glob matching)" |
4949 p := pattern species new:0. |
4940 p := pattern species new:0. |
4950 (pattern startsWith:$*) ifFalse:[p := p , '*']. |
4941 (pattern startsWith:$*) ifFalse:[p := p , '*']. |
4951 p := p , pattern. |
4942 p := p , pattern. |
4952 (pattern endsWith:$*) ifFalse:[p := p , '*']. |
4943 (pattern endsWith:$*) ifFalse:[p := p , '*']. |
4953 realPattern := pattern. |
4944 realPattern := pattern. |
4954 (realPattern startsWith:$*) ifTrue:[ |
4945 (realPattern startsWith:$*) ifTrue:[ |
4955 realPattern := realPattern copyFrom:2 |
4946 realPattern := realPattern copyFrom:2 |
4956 ]. |
4947 ]. |
4957 runner |
4948 runner |
4958 value:[:lnr :col :lineString | |
4949 value:[:lnr :col :lineString | |
4959 (p match:lineString caseSensitive:ignCase not) ifTrue:[ |
4950 (p match:lineString caseSensitive:ignCase not) ifTrue:[ |
4960 "/ ok, there it is; look at which position |
4951 "/ ok, there it is; look at which position |
4961 foundCol := lineString |
4952 foundCol := lineString |
4962 findMatchString:realPattern startingAt:col |
4953 findMatchString:realPattern startingAt:col |
4963 caseSensitive:ignCase not ifAbsent:0. |
4954 caseSensitive:ignCase not ifAbsent:0. |
4964 foundCol ~~ 0 ifTrue:[ |
4955 foundCol ~~ 0 ifTrue:[ |
4965 (atBeginOfLineOnly not or:[foundCol == 1]) ifTrue:[ |
4956 (atBeginOfLineOnly not or:[foundCol == 1]) ifTrue:[ |
4966 ^ block1 value:lnr value:foundCol optionalArgument:nil. |
4957 ^ block1 value:lnr value:foundCol optionalArgument:nil. |
4967 ]]]]. |
4958 ]]]]. |
4968 ] ifFalse:[ |
4959 ] ifFalse:[ |
4969 "perform a findString (no matching)" |
4960 "perform a findString (no matching)" |
4970 p := pattern. |
4961 p := pattern. |
4971 (match and:[pattern includesMatchCharacters]) ifTrue:[ |
4962 (match and:[pattern includesMatchCharacters]) ifTrue:[ |
4972 p := pattern withoutMatchEscapes |
4963 p := pattern withoutMatchEscapes |
4973 ]. |
4964 ]. |
4974 runner |
4965 runner |
4975 value:[:lnr :col :lineString | |
4966 value:[:lnr :col :lineString | |
4976 foundCol := lineString |
4967 foundCol := lineString |
4977 findString:p startingAt:col ifAbsent:0 caseSensitive: ignCase not. |
4968 findString:p startingAt:col ifAbsent:0 caseSensitive: ignCase not. |
4978 foundCol ~~ 0 ifTrue:[ |
4969 foundCol ~~ 0 ifTrue:[ |
4979 (fullWord not |
4970 (fullWord not |
4980 or:[ (self findBeginOfWordAtLine:lnr col:foundCol) == foundCol |
4971 or:[ (self findBeginOfWordAtLine:lnr col:foundCol) == foundCol |
4981 and:[ (self findEndOfWordAtLine:lnr col:foundCol) == (foundCol + patternSize - 1) ]] |
4972 and:[ (self findEndOfWordAtLine:lnr col:foundCol) == (foundCol + patternSize - 1) ]] |
4982 ) ifTrue:[ |
4973 ) ifTrue:[ |
4983 (atBeginOfLineOnly not or:[foundCol == 1]) ifTrue:[ |
4974 (atBeginOfLineOnly not or:[foundCol == 1]) ifTrue:[ |
4984 ^ block1 value:lnr value:foundCol optionalArgument:nil. |
4975 ^ block1 value:lnr value:foundCol optionalArgument:nil. |
4985 ] |
4976 ] |
4986 ] |
4977 ] |
4987 ] |
4978 ] |
4988 ]. |
4979 ]. |
4989 ]. |
4980 ]. |
4990 ]. |
4981 ]. |
4991 ] |
4982 ] |
4992 ]. |
4983 ]. |
4993 "not found" |
4984 "not found" |
4994 |
4985 |
4995 ^ block2 value |
4986 ^ block2 value |
4996 |
4987 |
5331 ignoreCase := ignoredCaseBoolean. |
5322 ignoreCase := ignoredCaseBoolean. |
5332 match := matchBoolean. |
5323 match := matchBoolean. |
5333 forward := forwardBoolean |
5324 forward := forwardBoolean |
5334 ! |
5325 ! |
5335 |
5326 |
5336 pattern:patternString ignoreCase:ignoredCaseBoolean |
5327 pattern:patternString ignoreCase:ignoredCaseBoolean |
5337 match:matchBoolean regexMatch:regexMatchBoolean |
5328 match:matchBoolean regexMatch:regexMatchBoolean |
5338 variable:variableBoolen |
5329 variable:variableBoolen |
5339 fullWord:fullWordBoolen forward:forwardBoolean |
5330 fullWord:fullWordBoolen forward:forwardBoolean |
5340 atBeginOfLineOnly:atBeginOfLineOnlyArg |
5331 atBeginOfLineOnly:atBeginOfLineOnlyArg |
5341 pattern := patternString. |
5332 pattern := patternString. |
5342 ignoreCase := ignoredCaseBoolean. |
5333 ignoreCase := ignoredCaseBoolean. |
5343 match := matchBoolean. |
5334 match := matchBoolean. |
5344 regexMatch := regexMatchBoolean. |
5335 regexMatch := regexMatchBoolean. |
5345 variable := variableBoolen. |
5336 variable := variableBoolen. |
5346 fullWord := fullWordBoolen. |
5337 fullWord := fullWordBoolen. |
5347 forward := forwardBoolean. |
5338 forward := forwardBoolean. |
5348 atBeginOfLineOnly := atBeginOfLineOnlyArg |
5339 atBeginOfLineOnly := atBeginOfLineOnlyArg |
5349 ! |
5340 ! |
5350 |
5341 |
5351 pattern:patternString ignoreCase:ignoredCaseBoolean |
5342 pattern:patternString ignoreCase:ignoredCaseBoolean |
5352 match:matchBoolean regexMatch:regexMatchBoolean |
5343 match:matchBoolean regexMatch:regexMatchBoolean |
5353 variable:variableBoolen |
5344 variable:variableBoolen |
5354 fullWord:fullWordBoolen forward:forwardBoolean |
5345 fullWord:fullWordBoolen forward:forwardBoolean |
5355 atBeginOfLineOnly:atBeginOfLineOnlyArg |
5346 atBeginOfLineOnly:atBeginOfLineOnlyArg |
5356 wrapAtEnd:wrapAtEndOfTextArg |
5347 wrapAtEnd:wrapAtEndOfTextArg |
5357 pattern := patternString. |
5348 pattern := patternString. |
5358 ignoreCase := ignoredCaseBoolean. |
5349 ignoreCase := ignoredCaseBoolean. |
5359 match := matchBoolean. |
5350 match := matchBoolean. |
5360 regexMatch := regexMatchBoolean. |
5351 regexMatch := regexMatchBoolean. |
5361 variable := variableBoolen. |
5352 variable := variableBoolen. |