Mercurial > repos > tabletprog
comparison modules/ui.tp @ 337:b8f721bde066
Add support for text elements in ui module
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Fri, 03 Apr 2015 23:08:19 -0700 |
parents | 79a14e41b79a |
children | d61b1f0e1936 |
comparison
equal
deleted
inserted
replaced
336:2a0463c46913 | 337:b8f721bde066 |
---|---|
16 object setProperty: name on: base to: (object sendMessage: name to: properties) | 16 object setProperty: name on: base to: (object sendMessage: name to: properties) |
17 } | 17 } |
18 } | 18 } |
19 base | 19 base |
20 } | 20 } |
21 _ft <- option none | |
22 _getFT <- { | |
23 _ft value: :ft { ft } none: { | |
24 ft <- freetype init | |
25 _ft <- option value: ft | |
26 ft | |
27 } | |
28 } | |
29 | |
30 //TODO: Fix this for multi window | |
31 _atlasDict <- dict hash | |
32 _currentTex <- option none | |
33 _texX <- 0 | |
34 _texY <- 0 | |
35 _texRowHeight <- 0 | |
36 _getFontAtlas <- :path _size renderer { | |
37 sizes <- _atlasDict get: path else: { | |
38 new <- dict hash | |
39 _atlasDict set: path new | |
40 new | |
41 } | |
42 _getTexture <- :width height { | |
43 _currentTex value: { | |
44 if: _texX + width > 2048 { | |
45 _texY <- _texY + _texRowHeight | |
46 _texRowHeight <- 0 | |
47 _texX <- 0 | |
48 } | |
49 if: _texY + height > 2048 { | |
50 _currentTex <- renderer createTexture: ((sdl pixelFormats) bgra8888) access: ((sdl textureAccess) streaming) width: 2048 height: 2048 | |
51 _currentTex value: :tex { | |
52 tex blendMode!: ((sdl blendModes) blend) | |
53 } none: {} | |
54 _texX <- 0 | |
55 _texY <- 0 | |
56 _texRowHeight <- 0 | |
57 } | |
58 if: _texRowHeight < height { | |
59 _texRowHeight <- height | |
60 } | |
61 } none: { | |
62 _currentTex <- renderer createTexture: ((sdl pixelFormats) bgra8888) access: ((sdl textureAccess) streaming) width: 2048 height: 2048 | |
63 _currentTex value: :tex { | |
64 tex blendMode!: ((sdl blendModes) blend) | |
65 } none: {} | |
66 } | |
67 _currentTex | |
68 } | |
69 atlas <- sizes get: _size else: { | |
70 //TODO: Only load face once for all sizes | |
71 a <- ((_getFT: ) faceFromPath: path index: 0) value: :_face { | |
72 _textures <- #[] | |
73 | |
74 _charmap <- _face charmap | |
75 //TODO: Feed in window system DPI or at least make this configurable | |
76 dpi <- 96 | |
77 _face setCharSize: _size res: dpi | |
78 _pixelFactor <- ((_face unitsPerEm) f64) * 72.0 / (_size * (dpi f64)) | |
79 _emUnits <- _face unitsPerEm | |
80 _glyphs <- dict hash | |
81 _getGlyph <- :codePoint face { | |
82 _glyphs get: codePoint else: { | |
83 flags <- freetype loadFlags | |
84 _charmap ifget: codePoint :_glyphIndex { | |
85 slot <- face glyphSlot | |
86 face loadGlyph: _glyphIndex flags: ((flags render) or (flags linearDesign) or (flags noHinting)) | |
87 w <- slot bitmapWidth | |
88 h <- slot bitmapRows | |
89 _advX <- slot linearHoriAdvance | |
90 _advY <- slot linearVertAdvance | |
91 _texture <- _getTexture: w h | |
92 _rect <- sdl rect: _texX _texY size: w h | |
93 _texture value: :tex { | |
94 srcPitch <- slot bitmapPitch | |
95 srcBuffer <- slot bitmapData | |
96 tex lockRect: (sdl rect: _texX _texY size: w h ) with: :dstBuffer dstPitch { | |
97 srcY <- 0 | |
98 dstY <- 0 | |
99 while: { srcY < h } do: { | |
100 srcX <- 0 | |
101 srcIdx <- srcY * srcPitch | |
102 dstIdx <- dstY * dstPitch | |
103 while: { srcX < w } do: { | |
104 //Set destination pixel to white with the source pixel as alpha | |
105 //This allows text color to be set using colorMod! on the texture | |
106 dstBuffer set: dstIdx (srcBuffer get: srcIdx) | |
107 dstBuffer set: (dstIdx + 1) 255u8 | |
108 dstBuffer set: (dstIdx + 2) 255u8 | |
109 dstBuffer set: (dstIdx + 3) 255u8 | |
110 | |
111 srcX <- srcX + 1 | |
112 srcIdx <- srcIdx + 1 | |
113 dstIdx <- dstIdx + 4 | |
114 } | |
115 | |
116 srcY <- srcY + 1 | |
117 dstY <- dstY + 1 | |
118 } | |
119 } | |
120 } none: {} | |
121 _texX <- _texX + w | |
122 _leftOff <- slot bitmapLeft | |
123 _topOff <- slot bitmapTop | |
124 g <- #{ | |
125 advanceX <- { _advX } | |
126 advanceY <- { _advY } | |
127 atlasRect <- { _rect } | |
128 | |
129 glyphIndex <- { _glyphIndex } | |
130 drawAt:color <- :x y :color { | |
131 _texture value: :tex { | |
132 tex colorMod!: color | |
133 tex copyRect: _rect To: (sdl rect: x+_leftOff y-_topOff size: (_rect w) (_rect h)) | |
134 } none: {} | |
135 } | |
136 } | |
137 _glyphs set: codePoint g | |
138 g | |
139 } else: { | |
140 //get fallback | |
141 _getGlyph: 0u32 face | |
142 } | |
143 } | |
144 } | |
145 | |
146 _getGlyphs <- :str face { | |
147 i <- 0 | |
148 lines <- #[] | |
149 curline <- #[] | |
150 nl <- ("\n" byte: 0) uint32 | |
151 while: { i < (str byte_length) } do: { | |
152 //TODO: Unicode | |
153 codePoint <- (str byte: i) uint32 | |
154 if: codePoint = nl { | |
155 lines append: curline | |
156 curline <- #[] | |
157 } else: { | |
158 glyph <- _getGlyph: codePoint face | |
159 curline append: glyph | |
160 } | |
161 i <- i + 1 | |
162 } | |
163 lines append: curline | |
164 lines | |
165 } | |
166 _iterateGlyphs:leading:using <- :str :leading :fun { | |
167 lines <- _getGlyphs: str _face | |
168 y <- 0.0 | |
169 maxX <- 0.0 | |
170 print: "Leading: " . leading . ", EM units: " . _emUnits . "\n" | |
171 leading <- leading * (_emUnits f64) / _size | |
172 foreach: lines :_ glyphs { | |
173 x <- 0.0 | |
174 baseline <- y + (_emUnits f64) | |
175 foreach: glyphs :_ glyph { | |
176 fun: glyph x baseline | |
177 x <- x + ((glyph advanceX) f64) | |
178 //baseline <- baseline + ((glyph advanceY) f64) | |
179 //TODO: kerning | |
180 } | |
181 y <- y + leading | |
182 if: x > maxX { | |
183 maxX <- x | |
184 } | |
185 } | |
186 //convert font units into pixels | |
187 x <- (maxX / _pixelFactor + 0.5) truncInt32 | |
188 y <- (y / _pixelFactor + 0.5) truncInt32 | |
189 vec x: x y: y | |
190 } | |
191 option value: #{ | |
192 stringSize:leading <- :str :leading { | |
193 _iterateGlyphs: str leading: leading using: :glyph x y {} | |
194 } | |
195 | |
196 drawString:at:color:leading <- :str :xpos ypos :color :lead { | |
197 _iterateGlyphs: str leading: lead using: :glyph x y { | |
198 x <- ((x / _pixelFactor + 0.5) truncInt32) + xpos | |
199 y <- ((y / _pixelFactor + 0.5) truncInt32) + ypos | |
200 glyph drawAt: x y color: color | |
201 } | |
202 } | |
203 } | |
204 } none: { | |
205 option none | |
206 } | |
207 sizes set: _size a | |
208 a | |
209 } | |
210 } | |
21 #{ | 211 #{ |
22 import: [ | 212 import: [ |
23 r:g:b | 213 r:g:b |
24 r:g:b:a | 214 r:g:b:a |
25 ] from: sdl | 215 ] from: sdl |
26 _styles <- [] | 216 _styles <- [] |
27 window <- :properties { | 217 window <- :properties { |
28 _wind <- option none | 218 _wind <- option none |
29 _renderer <- option none | 219 _renderer <- option none |
220 | |
221 | |
30 base <- #{ | 222 base <- #{ |
31 title <- "Window" | 223 title <- "Window" |
32 width <- 640 | 224 width <- 640 |
33 height <- 480 | 225 height <- 480 |
34 x <- 0 | 226 x <- 0 |
48 } | 240 } |
49 } | 241 } |
50 } | 242 } |
51 | 243 |
52 layout <- { | 244 layout <- { |
53 yPos <- 0 | 245 _renderer value: :renderer { |
54 xPos <- 0 | 246 yPos <- 0 |
55 rowMaxHeight <- 0 | 247 xPos <- 0 |
56 foreach: children :_ child { | 248 rowMaxHeight <- 0 |
57 softMax <- (width - xPos) | 249 foreach: children :_ child { |
58 child softMaxWidth: softMax maxWidth: width maxHeight: (height - yPos) renderer: _renderer | 250 softMax <- (width - xPos) |
59 if: (child width) > softMax { | 251 child softMaxWidth: softMax maxWidth: width maxHeight: (height - yPos) renderer: renderer |
60 yPos <- yPos + rowMaxHeight | 252 if: (child width) > softMax { |
61 xPos <- 0 | 253 yPos <- yPos + rowMaxHeight |
62 rowMaxHeight <- 0 | 254 xPos <- 0 |
63 } | 255 rowMaxHeight <- 0 |
64 child x!: xPos | 256 } |
65 child y!: yPos | 257 child x!: xPos |
66 xPos <- xPos + (child width) | 258 child y!: yPos |
67 if: (child height) > rowMaxHeight { | 259 xPos <- xPos + (child width) |
68 rowMaxHeight <- (child height) | 260 if: (child height) > rowMaxHeight { |
69 } | 261 rowMaxHeight <- (child height) |
70 if: xPos >= width { | 262 } |
71 yPos <- yPos + rowMaxHeight | 263 if: xPos >= width { |
72 xPos <- 0 | 264 yPos <- yPos + rowMaxHeight |
73 rowMaxHeight <- 0 | 265 xPos <- 0 |
74 } | 266 rowMaxHeight <- 0 |
75 } | 267 } |
268 } | |
269 } none: {} | |
76 } | 270 } |
77 | 271 |
78 draw <- { | 272 draw <- { |
79 print: "Draw!\n" | 273 print: "Draw!\n" |
80 _renderer value: :renderer { | 274 _renderer value: :renderer { |
99 } | 293 } |
100 _applyProps: base properties | 294 _applyProps: base properties |
101 } | 295 } |
102 | 296 |
103 text <- :properties { | 297 text <- :properties { |
104 #{ | 298 _fontSize <- 12.0 |
299 _leading <- 15.0 | |
300 _explicitLeading <- false | |
301 _applyProps: #{ | |
105 text <- "" | 302 text <- "" |
106 //TODO: replace this with font family and style once fontconfig is hooked up | 303 //TODO: replace this with font family and style once fontconfig is hooked up |
107 font <- "/usr/share/fonts/truetype/droid/DroidSans.ttf" | 304 font <- "/usr/share/fonts/truetype/droid/DroidSans.ttf" |
108 fontSize <- 12.0 | 305 fontSize <- { _fontSize } |
306 fontSize! <- :newSize { | |
307 _fontSize <- newSize | |
308 if: (not: _explicitLeading) { | |
309 _leading <- newSize * 1.25 | |
310 } | |
311 } | |
312 leading <- { _leading } | |
313 leading! <- :newLeading { | |
314 _explicitLeading <- true | |
315 _leading <- newLeading | |
316 } | |
317 color <- (ui r: 0u8 g: 0u8 b: 0u8) | |
109 width <- -1 | 318 width <- -1 |
110 height <- -1 | 319 height <- -1 |
111 x <- 0 | 320 x <- 0 |
112 y <- 0 | 321 y <- 0 |
113 | 322 |
114 softMaxWidth:maxWidth:maxHeight <- :softMax :maxWidth :maxHeight { | 323 softMaxWidth:maxWidth:maxHeight:renderer <- :softMax :maxWidth :maxHeight :renderer { |
115 | 324 (_getFontAtlas: font fontSize renderer) value: :atlas { |
116 } | 325 //TODO: word wrap |
117 } | 326 bbox <- atlas stringSize: text leading: _leading |
327 width <- bbox x | |
328 height <- bbox y | |
329 print: "Text: " . text . " has size: " . width . ", " . height . "\n" | |
330 } none: { | |
331 } | |
332 } | |
333 | |
334 draw <- :renderer { | |
335 (_getFontAtlas: font fontSize renderer) value: :atlas { | |
336 print: "Drawing: " . text . " at " . x . ", " . y . "\n" | |
337 atlas drawString: text at: x y color: color leading: _leading | |
338 } none: { | |
339 } | |
340 } | |
341 } properties | |
118 } | 342 } |
119 | 343 |
120 image <- :properties { | 344 image <- :properties { |
121 _texture <- option none | 345 _texture <- option none |
122 _applyProps: #{ | 346 _applyProps: #{ |
124 width <- -1 | 348 width <- -1 |
125 height <- -1 | 349 height <- -1 |
126 x <- 0 | 350 x <- 0 |
127 y <- 0 | 351 y <- 0 |
128 | 352 |
129 softMaxWidth:maxWidth:maxHeight:renderer <- :softMax :maxWidth :maxHeight :_renderer { | 353 softMaxWidth:maxWidth:maxHeight:renderer <- :softMax :maxWidth :maxHeight :renderer { |
130 _renderer value: :renderer { | 354 _texture value: :_ { |
355 } none: { | |
131 (sdl loadBMP: source) value: :surface { | 356 (sdl loadBMP: source) value: :surface { |
132 (surface asTexture: renderer) value: :texture { | 357 (surface asTexture: renderer) value: :texture { |
133 _texture <- option value: texture | 358 _texture <- option value: texture |
134 width <- texture width | 359 width <- texture width |
135 height <- texture height | 360 height <- texture height |
147 print: "Failed to load " . source . "\n" | 372 print: "Failed to load " . source . "\n" |
148 //Should this have some kind of placeholder as a fallback? | 373 //Should this have some kind of placeholder as a fallback? |
149 width <- 0 | 374 width <- 0 |
150 height <- 0 | 375 height <- 0 |
151 } | 376 } |
152 } none: { | |
153 } | 377 } |
154 } | 378 } |
155 | 379 |
156 draw <- :_ { | 380 draw <- :_ { |
157 _texture value: :texture { | 381 _texture value: :texture { |