Skip to content

Commit bde2215

Browse files
authored
Improvements v12.10 tweaks (#93)
* tweaks on apis * calculating min/max font content * adding test for text widget * alternate text setup * bump version - lots of changes recently - new baseline build * updates * tweak updates * rename attrs to flags * remove transparency field * various fixes
1 parent ef86d86 commit bde2215

28 files changed

+513
-391
lines changed

examples/hnbrowser.css

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,22 @@ Button:hover {
1313
box-shadow: 5px 2px 4px rgba(47, 0, 75, 0.119);
1414
}
1515

16+
#items {
17+
background: #5b5b5b;
18+
}
19+
20+
#scrollbar-vertical {
21+
background-color: rgb(57, 51, 1);
22+
}
23+
1624
#story {
1725
background: black;
1826
border-width: 3;
1927
border-color: rgba(57, 50, 1, 0.45);
2028
border-radius: 6;
2129
color: #ddd;
2230
background: rgb(50, 50, 47);
23-
height: 40;
31+
/* height: 40; */
2432
}
2533

2634
#story:hover {

examples/hnbrowser.nim

Lines changed: 57 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -44,34 +44,46 @@ proc hover*(self: Main, kind: EventKind) {.slot.} =
4444
proc draw*(self: Main) {.slot.} =
4545
withRootWidget(self):
4646

47-
rectangle "outer":
47+
Rectangle.new "outer":
4848
with this:
49-
offset 10'ux, 10'ux
49+
size 100'pp, 100'pp
5050
setGridCols 1'fr
5151
setGridRows ["top"] 70'ux \
5252
["items"] 1'fr \
53-
["bottom"] 20'ux
53+
["bottom"] 40'ux \
54+
["end"] 0'ux
5455
setGridCols ["left"] 1'fr \
5556
["right"] 0'ux
56-
gridColumn 1 // 1
5757
gridAutoFlow grRow
58-
justifyItems CxCenter
59-
alignItems CxStart
60-
61-
Button.new "Load":
62-
with this:
63-
size 0.5'fr, 50'ux
64-
gridRow "top" // "items"
65-
gridColumn "left" // "right"
66-
onSignal(doMouseClick) do(self: Main, kind: EventKind, buttons: UiButtonView):
67-
echo "Load clicked: ", kind
68-
if kind == Done and not self.loading:
69-
emit self.htmlLoad()
70-
self.loading = true
71-
refresh(self)
58+
justifyItems CxStretch
59+
alignItems CxStretch
60+
61+
# setPrettyPrintMode(cmTerminal)
62+
# printLayout(this, cmTerminal)
63+
onSignal(doMouseClick) do(this: Figuro,
64+
kind: EventKind,
65+
buttons: UiButtonView):
66+
if kind == Done:
67+
printLayout(this.frame[].root, cmTerminal)
68+
69+
Rectangle.new "top":
70+
gridRow "top" // "items"
71+
gridColumn "left" // "right"
72+
73+
Button.new "Load":
74+
with this:
75+
size 50'pp, 50'ux
76+
offset 25'pp, 10'ux
77+
onSignal(doMouseClick) do(self: Main, kind: EventKind, buttons: UiButtonView):
78+
echo "Load clicked: ", kind
79+
if kind == Done and not self.loading:
80+
emit self.htmlLoad()
81+
self.loading = true
82+
refresh(self)
7283

7384
Text.new "text":
7485
with this:
86+
size 100'pp, 100'pp
7587
foreground blackColor
7688
case self.loading:
7789
of false:
@@ -92,38 +104,47 @@ proc draw*(self: Main) {.slot.} =
92104
with this:
93105
gridRow "items" // "bottom"
94106
gridColumn 1 // 2
95-
offset 2'pp, 2'pp
96107
cornerRadius 7.0'ux
97-
size 96'pp, 90'pp
108+
size cx"auto", cx"none"
98109

99110
ScrollPane.new "scroll":
100-
offset 2'pp, 2'pp
111+
offset 0'pp, 0'pp
101112
cornerRadius 7.0'ux
102-
size 96'pp, 90'pp
103-
echo "\n"
104-
printLayout(this, cmTerminal)
113+
size 100'pp, 100'pp
105114

106115
Vertical.new "items":
107116
with this:
108-
contentHeight cx"max-content", 3'ui
117+
offset 0'ux, 0'ux
118+
size 100'pp-10'ux, cx"max-content"
119+
contentHeight cx"auto", 3'ui
109120

110121
for idx, story in self.stories:
111-
# if idx > 5: break
122+
# if idx > 6: break
112123
capture story, idx:
113-
Button.new "story" & $idx:
114-
onSignal(doRightClick) do(this: Button[tuple[]]):
124+
Button[Submission].new "story":
125+
this.state = story
126+
# if idx == 0:
127+
# printLayout(this, cmTerminal)
128+
onSignal(doRightClick) do(this: Button[Submission]):
115129
printLayout(this, cmTerminal)
116-
with this:
117-
# size 1'fr, ux(2*lh)
118-
size 1'fr, max(ux(2.0*lh.float), cx"min-content")
119-
# this.cxPadOffset[drow] = 20'ux
120-
# this.cxPadSize[drow] = 20'ux
130+
onSignal(doSingleClick) do(this: Button[Submission]):
131+
echo "HN Story: "
132+
echo this.state
133+
size 1'fr, cx"auto"
134+
this.cxPadOffset[drow] = 10'ux
135+
this.cxPadSize[drow] = 10'ux
136+
137+
Text.new "text":
138+
with this:
139+
offset 5'ux, 0'ux
140+
foreground blackColor
141+
justify Left
142+
align Middle
143+
text({font: $story.rank})
121144

122145
Text.new "text":
123146
with this:
124-
size 1'fr, ux(2*lh)
125-
# size 1'fr, max(ux(1.5*lh.float), cx"min-content")
126-
offset 10'ux, 0'ux
147+
offset 40'ux, 0'ux
127148
foreground blackColor
128149
justify Left
129150
align Middle

figuro.nimble

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
version = "0.12.9"
1+
version = "0.12.10"
22
author = "Jaremy Creechley"
33
description = "UI Engine for Nim"
44
license = "MIT"
@@ -9,7 +9,7 @@ srcDir = "src"
99
requires "nim >= 2.0.10"
1010
requires "sigils >= 0.11.8"
1111
requires "pixie >= 5.0.1"
12-
requires "cssgrid >= 0.9.8"
12+
requires "cssgrid >= 0.10.0"
1313
requires "chroma >= 0.2.7"
1414
requires "bumpy"
1515
requires "pretty"

src/figuro/common/fonttypes.nim

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,9 @@ type
5151
runes*: seq[Rune] ## The runes of the text.
5252
positions*: seq[Vec2] ## The positions of the glyphs for each rune.
5353
selectionRects*: seq[Rect] ## The selection rects for each glyph.
54-
maxPosition*: UiSize
54+
maxSize*: UiSize
55+
minSize*: UiSize
56+
bounding*: UiBox
5557

5658
TextSpan* = object
5759
text*: string

src/figuro/common/fontutils.nim

Lines changed: 68 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@ import pretty
1313

1414
type GlyphPosition* = ref object ## Represents a glyph position after typesetting.
1515
fontId*: FontId
16-
fontSize*: float32
1716
rune*: Rune
1817
pos*: Vec2 # Where to draw the image character.
1918
rect*: Rect
2019
descent*: float32
20+
lineHeight*: float32
2121

2222
var
2323
glyphImageChan* = newChan[(Hash, Image)](1000)
@@ -46,9 +46,9 @@ proc getId*(typeface: Typeface): TypefaceId =
4646
iterator glyphs*(arrangement: GlyphArrangement): GlyphPosition =
4747
var idx = 0
4848

49-
var mlh = 0.0 # maximum line height per row (though this does in total?)
50-
for f in arrangement.fonts:
51-
mlh = max(f.lineHeight, mlh)
49+
# var mlh = 0.0 # maximum line height per row (though this does in total?)
50+
# for f in arrangement.fonts:
51+
# mlh = max(f.lineHeight, mlh)
5252

5353
block:
5454
for i, (span, gfont) in zip(arrangement.spans, arrangement.fonts):
@@ -62,11 +62,12 @@ iterator glyphs*(arrangement: GlyphArrangement): GlyphPosition =
6262

6363
yield GlyphPosition(
6464
fontId: gfont.fontId,
65-
fontSize: gfont.size,
65+
# fontSize: gfont.size,
6666
rune: rune,
6767
pos: pos,
6868
rect: selection,
6969
descent: descent,
70+
lineHeight: gfont.lineHeight,
7071
)
7172

7273
# echo "GLYPH: ", rune, " pos: ", pos, " sel: ", selection, " lh: ", gfont.lineHeight, " mlh: ", flh, " : ", flh - gfont.lineHeight
@@ -213,6 +214,64 @@ proc getLineHeightImpl*(font: UiFont): UiScalar =
213214
let (_, pf) = font.convertFont()
214215
result = pf.lineHeight.descaled()
215216
217+
proc calcMinMaxContent(textLayout: GlyphArrangement): tuple[maxSize, minSize: UiSize, bounding: UiBox] =
218+
## estimate the maximum and minimum size of a given typesetting
219+
220+
var longestWord: Slice[int]
221+
var longestWordLen: float
222+
223+
var words = 0
224+
var wordsHeight = 0.0
225+
var curr: Slice[int]
226+
var currLen: float
227+
var maxWidth: float
228+
var box: Rect = rect(float32.high, float32.high, 0, 0)
229+
230+
# find longest word and count the number of words
231+
# herein min content width is longest word
232+
# herein max content height is a word on each line
233+
var idx = 0
234+
for glyph in textLayout.glyphs():
235+
236+
maxWidth += glyph.rect.w
237+
box.x = min(box.x, glyph.rect.x)
238+
box.y = min(box.y, glyph.rect.y)
239+
box.w = max(box.w, glyph.rect.x+glyph.rect.w)
240+
box.h = max(box.h, glyph.rect.y+glyph.rect.h)
241+
242+
if glyph.rune.isWhiteSpace:
243+
curr = idx+1..idx
244+
currLen = 0.0
245+
else:
246+
if curr.len() == 1:
247+
words.inc
248+
wordsHeight += glyph.lineHeight
249+
curr.b = idx
250+
currLen += glyph.rect.w
251+
252+
if currLen > longestWordLen:
253+
longestWord = curr
254+
longestWordLen = currLen
255+
256+
# echo "RUNE: ", glyph.rune, " alpha: ", isWhiteSpace(glyph.rune), " idx: ", idx, " lw: ", longestWord, " curr: ", curr, "#", curr.len, " currLen: ", currLen, " x:", glyph.rect
257+
idx.inc()
258+
# echo "LONGEST WORD: ", longestWord, " len: ", longestWordLen, " word cnt: ", words, " height: ", wordsHeight
259+
260+
# find tallest font
261+
var maxLine = 0.0
262+
for font in textLayout.fonts:
263+
maxLine = max(maxLine, font.lineHeight)
264+
265+
# set results
266+
result.minSize.w = longestWordLen.descaled()
267+
result.minSize.h = maxLine.descaled()
268+
269+
result.maxSize.w = maxWidth.descaled()
270+
result.maxSize.h = wordsHeight.descaled()
271+
272+
result.bounding = box.descaled()
273+
274+
216275
proc getTypesetImpl*(
217276
box: Box,
218277
uiSpans: openArray[(UiFont, string)],
@@ -291,15 +350,10 @@ proc getTypesetImpl*(
291350
selectionRects: selectionRects,
292351
)
293352

294-
# echo "arrangement:\n", result.repr
295-
# print result
296-
var maxPosition = vec2(float32.low, float32.low)
297-
for selRect in result.selectionRects:
298-
maxPosition.x = max(selRect.x + selRect.w, maxPosition.x)
299-
maxPosition.y = max(selRect.y + selRect.h, maxPosition.y)
300-
301-
result.maxPosition.w = maxPosition.x.descaled()
302-
result.maxPosition.h = maxPosition.y.descaled()
353+
let content = result.calcMinMaxContent()
354+
result.minSize = content.minSize
355+
result.maxSize = content.maxSize
356+
result.bounding = content.bounding
303357

304358
result.generateGlyphImage()
305359
# echo "font: "

src/figuro/common/nodes/basics.nim

Lines changed: 16 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -24,30 +24,24 @@ type
2424
nkScrollBar
2525
nkImage
2626

27+
NodeFlags* = enum
28+
NfClipContent
29+
NfDisableRender
30+
NfScrollPanel
31+
NfDead
32+
NfPreDrawReady
33+
NfPostDrawReady
34+
NfContentsDrawReady
35+
NfRootWindow
36+
NfInitialized
37+
# user facing attributes
38+
2739
Attributes* = enum
28-
clipContent
29-
disableRender
30-
scrollPanel
31-
inactive
32-
preDrawReady
33-
postDrawReady
34-
contentsDrawReady
35-
rxWindowResize
36-
rootWindow
37-
initialized
38-
# style attributes
39-
zLevelSet
40-
rotationSet
41-
fillSet
42-
fillHoverSet
43-
highlightSet
44-
transparencySet
45-
strokeSet
46-
imageSet
47-
shadowSet
48-
skipCss
40+
SkipCss
41+
Disabled
42+
Active
43+
Highlighted
4944

50-
FieldSet* = enum
5145
## For tracking which fields have been set by the widget user code.
5246
##
5347
## An example is setting `fill` in a button's code. We want this
@@ -61,7 +55,6 @@ type
6155
fsFill
6256
fsFillHover
6357
fsHighlight
64-
fsTransparency
6558
fsStroke
6659
fsImage
6760
fsShadow

src/figuro/common/nodes/render.nim

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,12 @@ type
2929
offset*: Vec2
3030
totalOffset*: Vec2
3131
scroll*: Vec2
32-
attrs*: set[Attributes]
32+
flags*: set[NodeFlags]
3333

3434
zlevel*: ZLevel
3535
rotation*: float32
3636
fill*: Color
3737
highlight*: Color
38-
transparency*: float32
3938
stroke*: Stroke
4039

4140
case kind*: NodeKind

src/figuro/common/nodes/transfer.nim

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,13 +92,12 @@ proc convert*(current: Figuro): render.Node =
9292
result.offset = current.offset.scaled
9393
result.totalOffset = current.totalOffset.scaled
9494
result.scroll = current.scroll.scaled
95-
result.attrs = current.attrs
95+
result.flags = current.flags
9696

9797
result.zlevel = current.zlevel
9898
result.rotation = current.rotation
9999
result.fill = current.fill
100100
result.highlight = current.highlight
101-
result.transparency = current.transparency
102101
result.stroke = current.stroke
103102

104103
case current.kind

0 commit comments

Comments
 (0)