From eba462b9c085ec74dac831b5bc57e7acc35478af Mon Sep 17 00:00:00 2001 From: Dany LE Date: Mon, 21 Mar 2022 01:45:21 +0100 Subject: [PATCH] Add bootstrap font icons support --- Diya/DiyaBaseObject.class.st | 5 +++ Diya/DiyaBoot.class.st | 17 ++++---- Diya/DiyaEllipse.class.st | 5 +++ Diya/DiyaFontIcon.class.st | 58 ++++++++++++++++++++++++++ Diya/DiyaFontManager.class.st | 14 ++++++- Diya/DiyaIcon.class.st | 5 --- Diya/DiyaLine.class.st | 5 +++ Diya/DiyaNode.class.st | 15 +++++-- Diya/DiyaText.class.st | 57 ++++++++++++++++--------- Diya/OpenGLFontTex.class.st | 15 ++++++- Diya/SDL_MouseMotionEvent.extension.st | 5 +-- Diya/SDL_TouchFingerEvent.extension.st | 4 +- 12 files changed, 162 insertions(+), 43 deletions(-) create mode 100644 Diya/DiyaFontIcon.class.st delete mode 100644 Diya/DiyaIcon.class.st diff --git a/Diya/DiyaBaseObject.class.st b/Diya/DiyaBaseObject.class.st index 6fe0305..1f095e1 100644 --- a/Diya/DiyaBaseObject.class.st +++ b/Diya/DiyaBaseObject.class.st @@ -18,6 +18,11 @@ DiyaBaseObject >> logError: string [ self stderr nextPutAll: string; cr ] +{ #category : #asserting } +DiyaBaseObject >> shouldNotBeCalled [ + ^DiyaCoreAPIError signal: 'Should not be called' +] + { #category : #accessing } DiyaBaseObject >> stderr [ ^VTermOutputDriver stderr diff --git a/Diya/DiyaBoot.class.st b/Diya/DiyaBoot.class.st index 9106980..86348f3 100644 --- a/Diya/DiyaBoot.class.st +++ b/Diya/DiyaBoot.class.st @@ -47,9 +47,7 @@ DiyaBoot >> bindGlobalEventTo: aNode [ pointer borderWidth: 3." aNode on: #keydown do:[:e| Transcript show: 'keydown...';cr. running := false.]. aNode on: #quit do: [:e| running := false]. - aNode on: #fingerdown do:[:e| self setCursorPosition: e mapped ]. - aNode on: #fingermotion do:[:e| self setCursorPosition: e mapped ]. - aNode on: #mousemotion do:[:e| + aNode on: #(fingerdown fingermotion mousemotion) do:[:e| pointer position: e mapped worldPosition. DiyaRendererContext uniqueInstance mouse: (e mapped x) @ (e mapped y). ]. @@ -91,10 +89,10 @@ DiyaBoot >> createWindow [ { #category : #events } DiyaBoot >> exampleNodes: tree [ - |root node node1 ell tex txtNode| + |root node node1 ell tex txtNode icon| root := tree addNode: (Diya2DNode new) at: 0@10. tex := (DiyaImageTex fromFile:Smalltalk imageDirectory / 'assets'/'mrsang.png'). - txtNode := root addNode: (DiyaText data: 'Event') at: 10@50. + txtNode := root addNode: (DiyaText data: 'Event') at: 10@55. txtNode color: Color orange. txtNode extent: 200@40. @@ -102,7 +100,7 @@ DiyaBoot >> exampleNodes: tree [ node1 rotation: (Float pi / 8.0). node1 scale: 1.2@1.2. node1 on: #mousebuttondown do:[:e| txtNode data: 'Mouse ', (node1 local: e mapped worldPosition) asIntegerPoint asString]. - node1 on: #fingerdown do:[:e| Transcript show:'finger down on image'; cr]. + node1 on: #fingerdown do:[:e| txtNode data: 'Mouse ', (node1 local: e mapped worldPosition) asIntegerPoint asString]. node := root addNode: (DiyaRectangle size: 200@200) at: 250 @ 430. node texture: tex. @@ -121,7 +119,7 @@ DiyaBoot >> exampleNodes: tree [ node := root addNode: (DiyaText data: String loremIpsum) at: 10@400. - node extent: 250@320. + node extent: 240@320. node wordWrap: true. node := root addNode: (DiyaLine from: 10@620 to: 200@635). @@ -137,7 +135,7 @@ DiyaBoot >> exampleNodes: tree [ "node rotation: Float pi / 2.0." ell texture: tex. ell on: #mousebuttondown do:[:e| txtNode data: 'Ellipse clicked', (ell local:e mapped worldPosition) asIntegerPoint asString]. - ell on: #fingerdown do:[:e| Transcript show:'finger down on ellipse'; cr]. + ell on: #fingerdown do:[:e| txtNode data: 'Ellipse clicked', (ell local:e mapped worldPosition) asIntegerPoint asString]. node := root addNode: (DiyaConvexPolygon points:{250@100. 400@250. 450@80. 350@60}). @@ -146,6 +144,9 @@ DiyaBoot >> exampleNodes: tree [ node texture: tex. node borderWidth: 3.0. + icon := root addNode: (DiyaFontIcon data: #(16rF101 16rF155 16rF185 16rF21B 16rF298 16rF254)) at: 10@10. + icon fontSize: 24. + icon color: (Color r: 209/255 g: 66/255 b:245/255 ). ^ root ] diff --git a/Diya/DiyaEllipse.class.st b/Diya/DiyaEllipse.class.st index 0607191..0deeea8 100644 --- a/Diya/DiyaEllipse.class.st +++ b/Diya/DiyaEllipse.class.st @@ -38,6 +38,11 @@ DiyaEllipse >> drawBorder [ "do nothing" ] +{ #category : #initialization } +DiyaEllipse >> drawLines [ + self shouldNotBeCalled +] + { #category : #initialization } DiyaEllipse >> initialize [ super initialize. diff --git a/Diya/DiyaFontIcon.class.st b/Diya/DiyaFontIcon.class.st new file mode 100644 index 0000000..8ddb53d --- /dev/null +++ b/Diya/DiyaFontIcon.class.st @@ -0,0 +1,58 @@ +Class { + #name : #DiyaFontIcon, + #superclass : #DiyaText, + #pools : [ + 'FT2Types' + ], + #category : #'Diya-Graphics' +} + +{ #category : #initialization } +DiyaFontIcon >> data: code [ + super data:(code isArray ifTrue: [ code ] ifFalse:[{code}]). + bbox := Rectangle origin: 0@0 corner: ((data size) * (self fontSize) ) @ self fontSize. +] + +{ #category : #initialization } +DiyaFontIcon >> drawText [ + |index offset tex| + index := 1. + tex := self texture. + offset := 0@(self fontSize). + 1 to: data size do: [ :i| + (self getCharsVerticesAt:i offset: offset on: tex) do: [ + :e| vbuffer at: index put:e. + index := index + 1 + ]. + "offset setX: offset x + tex spacing setY: offset y" + ]. + + +] + +{ #category : #initialization } +DiyaFontIcon >> fontName: name style: face size: size [ + super fontName: name style:face size: size. + data ifNil: [ ^ self ]. + bbox := Rectangle origin: 0@0 corner: ((data size) * (self fontSize) ) @ self fontSize. +] + +{ #category : #initialization } +DiyaFontIcon >> getLinebreakIndices: delta [ + self shouldNotBeCalled +] + +{ #category : #initialization } +DiyaFontIcon >> initialize [ + super initialize. + data := { }. + self fontName: 'bootstrap-icons' style: 'Regular' size: 16. + vbuffer := FFIExternalArray externalNewType: GLfloat size:24. + vbuffer autoRelease. + style := DiyaFontManager uniqueInstance defaultIconSet. +] + +{ #category : #initialization } +DiyaFontIcon >> lastSeparatorFrom: i [ + self shouldNotBeCalled +] diff --git a/Diya/DiyaFontManager.class.st b/Diya/DiyaFontManager.class.st index 36ee81a..331db08 100644 --- a/Diya/DiyaFontManager.class.st +++ b/Diya/DiyaFontManager.class.st @@ -25,6 +25,18 @@ DiyaFontManager >> defaultFamily [ ^'Ubuntu' +] + +{ #category : #initialization } +DiyaFontManager >> defaultIconSet [ + ^ self style: 'Regular' from: 'bootstrap-icons' +] + +{ #category : #initialization } +DiyaFontManager >> defaultStyle [ + ^'Regular' + + ] { #category : #accessing } @@ -97,7 +109,7 @@ DiyaFontManager >> reset [ { #category : #initialization } DiyaFontManager >> style: styleName from: familyName [ |family| - family := families at: familyName ifAbsent: [ self defaultFamily ]. + family := families at: familyName ifAbsent: [ families at: self defaultFamily ]. ^family style: styleName ] diff --git a/Diya/DiyaIcon.class.st b/Diya/DiyaIcon.class.st deleted file mode 100644 index f739e87..0000000 --- a/Diya/DiyaIcon.class.st +++ /dev/null @@ -1,5 +0,0 @@ -Class { - #name : #DiyaIcon, - #superclass : #DiyaImageView, - #category : #'Diya-Widgets' -} diff --git a/Diya/DiyaLine.class.st b/Diya/DiyaLine.class.st index 2591fc8..71dc0f7 100644 --- a/Diya/DiyaLine.class.st +++ b/Diya/DiyaLine.class.st @@ -53,6 +53,11 @@ DiyaLine >> drawBorder [ "do nothing" ] +{ #category : #initialization } +DiyaLine >> drawLines [ + self shouldNotBeCalled +] + { #category : #accessing } DiyaLine >> from [ ^ from diff --git a/Diya/DiyaNode.class.st b/Diya/DiyaNode.class.st index b83b0a7..90886a4 100644 --- a/Diya/DiyaNode.class.st +++ b/Diya/DiyaNode.class.st @@ -86,10 +86,8 @@ DiyaNode >> isRoot [ { #category : #convenience } DiyaNode >> on: eventName do: aBlock [ - |evtCode| - evtCode := SDL2Constants bindingOf: ('SDL_', eventName asUppercase). - evtCode ifNil: [ ^DiyaCoreAPIError signal: 'Unknow event ', eventName ]. - ehandlers at: evtCode value put: aBlock. + eventName isArray ifFalse:[ ^ self register: aBlock to: eventName ]. + eventName do:[:e| self register: aBlock to:e ]. ] @@ -114,6 +112,15 @@ DiyaNode >> position: anObject [ self updateTF. ] +{ #category : #convenience } +DiyaNode >> register: aBlock to: eventName [ + |evtCode| + evtCode := SDL2Constants bindingOf: ('SDL_', eventName asUppercase). + evtCode ifNil: [ ^DiyaCoreAPIError signal: 'Unknow event ', eventName ]. + ehandlers at: evtCode value put: aBlock. + +] + { #category : #accessing } DiyaNode >> render [ dirty ifTrue:[dirty := self update not]. diff --git a/Diya/DiyaText.class.st b/Diya/DiyaText.class.st index ad1921c..9e7fb3f 100644 --- a/Diya/DiyaText.class.st +++ b/Diya/DiyaText.class.st @@ -39,14 +39,21 @@ DiyaText >> data: anObject [ { #category : #initialization } DiyaText >> drawBorder [ + self shouldNotBeCalled +] + +{ #category : #initialization } +DiyaText >> drawLines [ + ^ self shouldNotBeCalled ] { #category : #accessing } DiyaText >> drawText [ - |vertices index tex2D offset| + |vertices index tex2D offset lbdelta| index := 1. offset := 0@0. tex2D := self texture. + lbdelta := self getLinebreakIndices: (self extent x / tex2D meanww) asInteger. 1 to: data size do: [ :i| vertices := self getCharsVerticesAt:i offset: offset on: tex2D. vertices do: [ @@ -54,7 +61,10 @@ DiyaText >> drawText [ index := index + 1. ]. (offset x > self extent x and: wrap not) ifTrue: [ ^self ]. - (offset y negated > self extent y) ifTrue: [ ^self ]. + ((lbdelta includes: i + 1) and: wrap) ifTrue: [ + offset setX: 0.0 setY: (offset y )- (tex2D linespace). + (offset y negated > self extent y) ifTrue: [ ^self ]. + ]. ]. ] @@ -71,8 +81,12 @@ DiyaText >> fontName [ { #category : #initialization } DiyaText >> fontName: name style: face size: size [ - name ifNotNil: [ fontName := name ]. - face ifNotNil: [ fontStyle := face ]. + name ifNotNil: [fontName := name]. + face ifNotNil: [fontStyle := face]. + + fontName := fontName ifNil: [DiyaFontManager uniqueInstance defaultFamily]. + fontStyle := fontStyle ifNil: [DiyaFontManager uniqueInstance defaultStyle]. + fontSize := size. style := DiyaFontManager uniqueInstance style: self fontStyle from: self fontName. dirty := true. @@ -96,21 +110,11 @@ DiyaText >> fontStyle [ { #category : #accessing } DiyaText >> getCharsVerticesAt:i offset: offset on: tex2D [ |x y w h glyph gsize c texcoord| - c := (data at:i) asciiValue. - c = (Character space asciiValue) ifTrue:[ - offset setX: (offset x + (tex2D spacing ) ) setY: offset y. - wrap ifTrue: [ - (offset x + ((self nextSpaceFrom: i + 1) * (tex2D fontSize))) > (self extent x) ifTrue: [ - offset setX: 0.0 setY: (offset y )- (tex2D linespace)]. - ]. - ^ {}. - ]. + c := (data at:i) asInteger. glyph := tex2D getGlyph: c. gsize := glyph extent. ((offset x > self extent x) and: (gsize x > 0)) ifTrue:[ wrap ifFalse: [ ^ { } ]. - offset setX: 0.0 setY: (offset y )- (tex2D linespace). - offset y negated > self extent y ifTrue:[^{}]. ]. x := offset x + (glyph bearing x). y := offset y - (tex2D cellh). @@ -126,20 +130,35 @@ DiyaText >> getCharsVerticesAt:i offset: offset on: tex2D [ x + w. y + h. texcoord corner x. texcoord origin y. }. ] +{ #category : #accessing } +DiyaText >> getLinebreakIndices: delta [ + |indices idx| + indices := Set new. + idx := delta + 1. + [ + idx < data size + ] whileTrue: [ + indices add: (self lastSeparatorFrom: idx) + 1. + idx := idx + delta. + ]. + ^indices +] + { #category : #initialization } DiyaText >> initialize [ super initialize. - self fontName: 'Ubuntu' style:'Regular' size: 16. + "self fontName: 'Ubuntu' style:'Regular' size: 16." data := nil. wrap := false. bbox := nil. texheight := 0. + self fontSize: 16 ] { #category : #'as yet unclassified' } -DiyaText >> nextSpaceFrom: index [ - index to: (data size) do: [:i| - (data at: i) = (Character space) ifTrue:[^i - index]. +DiyaText >> lastSeparatorFrom: index [ + index to: 1 by: -1 do: [:i| + (data at: i) isSeparator ifTrue:[^i]. ]. ^ 0 ] diff --git a/Diya/OpenGLFontTex.class.st b/Diya/OpenGLFontTex.class.st index 19a534f..abaee96 100644 --- a/Diya/OpenGLFontTex.class.st +++ b/Diya/OpenGLFontTex.class.st @@ -11,7 +11,8 @@ Class { 'rowp', 'face', 'maxbearing', - 'maxrows' + 'maxrows', + 'meanww' ], #pools : [ 'OpenGLConstants', @@ -63,7 +64,7 @@ OpenGLFontTex >> fontSize [ { #category : #'instance creation' } OpenGLFontTex >> fromFace: aFace ofSize: size [ - |minhang rec iptr charcode w| + |minhang rec iptr charcode w numw| fontSize := size. face := aFace. charmap := Dictionary new. @@ -73,6 +74,8 @@ OpenGLFontTex >> fromFace: aFace ofSize: size [ iptr at:1 put: 0. rec := (FTFaceRec fromHandle: face getHandle). charcode := face getFirstChar: iptr getHandle. + meanww := 0. + numw := 0. [ (iptr at: 1) = 0 ] whileFalse: [ face loadCharacter: charcode flags: (1 << 2). w := ((rec glyph metrics width) >> 6). @@ -80,11 +83,14 @@ OpenGLFontTex >> fromFace: aFace ofSize: size [ maxbearing := maxbearing max: ((rec glyph metrics horiBearingY) >> 6). cellw := cellw max: w. minhang := minhang min: ((( rec glyph metrics horiBearingY) - (rec glyph metrics height)) >> 6). + meanww := meanww + w. + numw := numw + 1. ]. charcode := face getNextChar: charcode iptr: iptr getHandle. ]. cellh := maxbearing - minhang. spacing := (cellw >> 2) asInteger. + meanww := meanww / numw. maxrows := 8. data := FFIExternalArray externalNewType: GLubyte size:cellw * cellh * (maxrows << 5). LibC memset: data getHandle value: 0 size: data size. @@ -145,6 +151,11 @@ OpenGLFontTex >> linespace [ ^ cellh ] +{ #category : #accessing } +OpenGLFontTex >> meanww [ + ^ meanww +] + { #category : #accessing } OpenGLFontTex >> reallocateBuffer [ |newbuffer| diff --git a/Diya/SDL_MouseMotionEvent.extension.st b/Diya/SDL_MouseMotionEvent.extension.st index 8fdc08f..e1ca138 100644 --- a/Diya/SDL_MouseMotionEvent.extension.st +++ b/Diya/SDL_MouseMotionEvent.extension.st @@ -1,9 +1,8 @@ Extension { #name : #'SDL_MouseMotionEvent' } { #category : #'*Diya' } -SDL_MouseMotionEvent >> triggableOn: aNode [ - ^false - "^ aNode inner: self worldPosition " +SDL_MouseMotionEvent >> triggableOn: arg1 [ + ^ arg1 inner: self worldPosition ] { #category : #'*Diya' } diff --git a/Diya/SDL_TouchFingerEvent.extension.st b/Diya/SDL_TouchFingerEvent.extension.st index 3bd35b8..7fc1d99 100644 --- a/Diya/SDL_TouchFingerEvent.extension.st +++ b/Diya/SDL_TouchFingerEvent.extension.st @@ -7,5 +7,7 @@ SDL_TouchFingerEvent >> triggableOn: aNode [ { #category : #'*Diya' } SDL_TouchFingerEvent >> worldPosition [ - ^ (self x) @ (DiyaRendererContext uniqueInstance resolution y - self y ) + |resolution| + resolution := DiyaRendererContext uniqueInstance resolution. + ^((self x)* (resolution x) ) @ ((1.0 - self y)* (resolution y)). ]