Grafoscopio/repository/Grafoscopio/GrafoscopioComposer.class.st

195 lines
5.7 KiB
Smalltalk

Class {
#name : #GrafoscopioComposer,
#superclass : #Object,
#instVars : [
'text',
'styler',
'container',
'lines'
],
#category : 'Grafoscopio-Rub'
}
{ #category : #'as yet unclassified' }
GrafoscopioComposer >> actualWidth [
^ (lines collect: [ :l | l approximateWidth ]) max
]
{ #category : #'as yet unclassified' }
GrafoscopioComposer >> calculateMaximumAmountOfCharactersToComposeStartingAt: startingY contemplating: delta [
| deltaX deltaY |
" This method is mean to restrict the amount of text to be processed. For knowing how much of the text is going to be processed, we calculate the size of a minimal character with the default font.
This strategy is not really the best, since we should check with the smallest font used in the text instead of using the default.
But by the time being this code should beenough, knowning that for a text drawn in a scrolled area we have almost infinite space. We should mind this bug first then come back .
"
deltaX := delta + (((styler fontAt: styler defaultFontIndex) linearWidthOf: $.) roundDownTo: 1).
deltaY := (styler fontAt: styler defaultFontIndex) height.
^ (container width / deltaX) * ((container height - startingY ) / deltaY ).
]
{ #category : #'as yet unclassified' }
GrafoscopioComposer >> charWidthForCharIndex: idx [
| font |
text ifNil: [ ^ 1 ].
font := styler
fontAt:
((text runs at: idx) detect: [ :a | a isKindOf: TextFontChange ])
fontNumber.
^ font widthOf: (text at: idx)
]
{ #category : #'as yet unclassified' }
GrafoscopioComposer >> composeLinesFrom: from to: to [
| genLines width charWidth lastAdded maxWidth |
genLines := OrderedCollection new.
width := 0.
lastAdded := from.
maxWidth := container width.
from to: to do: [ :i |
charWidth := self charWidthForCharIndex: i.
width + charWidth > maxWidth
ifTrue: [ genLines
add:
(GrafoscopioLine new
from: lastAdded
to: i - 1
text: text
styler: styler;
yourself).
lastAdded := i.
width := 0
].
width := width + charWidth
].
^ genLines
]
{ #category : #'as yet unclassified' }
GrafoscopioComposer >> composeLinesFrom: start to: stop delta: delta into: lineColl priorLines: priorLines atY: startingY [
| maxChars stackedY bounding |
" we set the lines collection "
lines := lineColl.
" we do calculate the size of an average "
maxChars := self
calculateMaximumAmountOfCharactersToComposeStartingAt: startingY
contemplating: delta.
" we should care about really fragmenting the composittion once we have this assert failling
should be enough to stop the inspection of the tree nodes once the from > maxChars.
something like:
text allSegmentsOfLinesUpTo: [: from : to | from > maxChars] collect: [ :from :to | GrafoscopioLine new from: from to: to].
for this we should implement #allSegmentsOfLinesUpTo:collect:
"
stackedY := startingY.
self assert: stop - start < maxChars.
bounding := container.
text
allSegmentsOfLinesDo: [ :from :to |
| h |
(self composeLinesFrom: from to: to)
do: [ :line |
lines add: line.
h := line height.
line
bounds:
(bounding origin x @ stackedY
corner: bounding corner x @ (stackedY + h)).
stackedY := stackedY + h ] ].
lines
ifEmpty: [ lines
add:
(GrafoscopioLine new
from: 1 to: 1;
bounds: (0 @ 0 corner: 0 @ 0);
yourself) ]
]
{ #category : #'as yet unclassified' }
GrafoscopioComposer >> container: aRectangle [
container := aRectangle
]
{ #category : #'as yet unclassified' }
GrafoscopioComposer >> cursorWidth: anInteger [
]
{ #category : #'as yet unclassified' }
GrafoscopioComposer >> emphasisHere: anObject [
self assert: (anObject isNil or: [ anObject isArray ])
]
{ #category : #'as yet unclassified' }
GrafoscopioComposer >> fastFindFirstLineIndexSuchThat: lineBlock [
"Perform a binary search of the lines array and return the index
of the first element for which lineBlock evaluates as true.
This assumes the condition is one that goes from false to true for
increasing line numbers (as, eg, yval > somey or start char > somex).
If lineBlock is not true for any element, return size+1."
| index low high |
low := 1.
high := lines size.
[index := high + low // 2.
low > high]
whileFalse:
[(lineBlock value: (lines at: index))
ifTrue: [high := index - 1]
ifFalse: [low := index + 1]].
^ low
]
{ #category : #'as yet unclassified' }
GrafoscopioComposer >> lineIndexForPoint: aPoint [
"Answer the index of the line in which to select the character nearest to aPoint."
| i py |
py := aPoint y truncated.
"Find the first line at this y-value"
i := (self fastFindFirstLineIndexSuchThat: [:line | line bottom > py]) min: self lines size.
"Now find the first line at this x-value"
[i < self lines size and: [(self lines at: i+1) top = (self lines at: i) top
and: [aPoint x >= (self lines at: i+1) left]]]
whileTrue: [i := i + 1].
^ i
]
{ #category : #'as yet unclassified' }
GrafoscopioComposer >> lineIndexOfCharacterIndex: characterIndex [
^ (self
fastFindFirstLineIndexSuchThat:
[ :line | line first >= characterIndex and: [ line last <= characterIndex ] ])
- 1 max: 1
]
{ #category : #'as yet unclassified' }
GrafoscopioComposer >> lines [
^ lines ifNil: [ lines := { GrafoscopioLine new }]
]
{ #category : #'as yet unclassified' }
GrafoscopioComposer >> replaceFrom: anInteger to: anInteger2 with: aCollection [
]
{ #category : #'as yet unclassified' }
GrafoscopioComposer >> text [
^ text
]
{ #category : #'as yet unclassified' }
GrafoscopioComposer >> text: aCollection [
text := aCollection
]
{ #category : #'as yet unclassified' }
GrafoscopioComposer >> textStyle: aTextStyle [
styler := aTextStyle
]