Skip to content

Commit 774b54c

Browse files
committed
Add RTF support
1 parent 8d64f15 commit 774b54c

10 files changed

Lines changed: 598 additions & 102 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ bin/
2828
.ropeproject
2929
*.iml
3030
*.json.gz
31+
gemini_cli_config.json
3132

3233
# ENV
3334
.env

examples/rtf.v

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import gui
2+
3+
// Rich Text Format
4+
// =============================
5+
// RTF allows mixing different colors and fonts in the same text block.
6+
// Hyperlinks are also supported.
7+
8+
@[heap]
9+
fn main() {
10+
mut window := gui.window(
11+
width: 300
12+
height: 300
13+
on_init: fn (mut w gui.Window) {
14+
w.update_view(main_view)
15+
}
16+
)
17+
window.set_theme(gui.theme_dark_bordered)
18+
window.run()
19+
}
20+
21+
fn main_view(window &gui.Window) gui.View {
22+
w, h := window.window_size()
23+
24+
return gui.column(
25+
width: w
26+
height: h
27+
sizing: gui.fixed_fixed
28+
h_align: .center
29+
v_align: .middle
30+
content: [
31+
gui.rtf(
32+
mode: .wrap
33+
spans: [
34+
gui.span('Hello', gui.theme().n3),
35+
gui.span(' RTF ', gui.theme().b3),
36+
gui.span('World', gui.theme().n3),
37+
gui.br(),
38+
gui.br(),
39+
gui.strike_span('Now is the', gui.theme().n3),
40+
gui.span(' ', gui.theme().n3),
41+
gui.span('time', gui.theme().i3),
42+
gui.span(' for all good men to come to the aid of their ', gui.theme().n3),
43+
gui.uspan('country', gui.theme().b3),
44+
gui.br(),
45+
gui.br(),
46+
gui.span('This is a ', gui.theme().n3),
47+
gui.hyperlink('hyperlink', 'https://vlang.io', gui.theme().n3),
48+
]
49+
),
50+
]
51+
)
52+
}

examples/showcase.v

Lines changed: 157 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ enum TabItem {
1414
tab_menus
1515
tab_dialogs
1616
tab_tree_view
17+
tab_text_view
1718
}
1819

1920
@[heap]
@@ -90,6 +91,7 @@ fn side_bar(mut w gui.Window) gui.View {
9091
tab_select('Menus', .tab_menus, app),
9192
tab_select('Dialogs', .tab_dialogs, app),
9293
tab_select('Tree View', .tab_tree_view, app),
94+
tab_select('Text', .tab_text_view, app),
9395
gui.column(sizing: gui.fit_fill),
9496
toggle_theme(app),
9597
]
@@ -106,7 +108,7 @@ fn gallery(mut w gui.Window) gui.View {
106108
.tab_stock {
107109
[buttons(w), inputs(w), toggles(w), select_drop_down(w),
108110
list_box(w), expand_panel(w), progress_bars(w),
109-
range_sliders(w), throbbers(w), text_sizes_weights(w)]
111+
range_sliders(w), throbbers(w)]
110112
}
111113
.tab_icons {
112114
[icons(mut w)]
@@ -123,6 +125,9 @@ fn gallery(mut w gui.Window) gui.View {
123125
.tab_tree_view {
124126
[tree_view(mut w)]
125127
}
128+
.tab_text_view {
129+
[text_sizes_weights(w), rich_text_format(w)]
130+
}
126131
}
127132
)
128133
}
@@ -368,105 +373,6 @@ fn text_changed(_ &gui.InputCfg, s string, mut w gui.Window) {
368373
app.input_text = s
369374
}
370375

371-
// ==============================================================
372-
// Text Sizes & Weights
373-
// ==============================================================
374-
375-
fn text_sizes_weights(w &gui.Window) gui.View {
376-
text_style_file := gui.TextStyle{
377-
...gui.theme().text_style
378-
color: gui.theme().color_border
379-
}
380-
variants := gui.font_variants(gui.theme().text_style)
381-
return gui.column(
382-
sizing: gui.fill_fit
383-
padding: gui.padding_none
384-
content: [
385-
view_title('Text Sizes & Weights'),
386-
gui.column(
387-
spacing: 0
388-
padding: gui.padding_none
389-
content: [
390-
gui.text(text: variants.normal, text_style: text_style_file),
391-
gui.row(
392-
padding: gui.padding_none
393-
sizing: gui.fill_fit
394-
v_align: .bottom
395-
content: [
396-
gui.text(text: 'Theme().n1', text_style: gui.theme().n1),
397-
gui.text(text: 'Theme().n2', text_style: gui.theme().n2),
398-
gui.text(text: 'Theme().n3', text_style: gui.theme().n3),
399-
gui.text(text: 'Theme().n4', text_style: gui.theme().n4),
400-
gui.text(text: 'Theme().n5', text_style: gui.theme().n5),
401-
gui.text(text: 'Theme().n6', text_style: gui.theme().n6),
402-
]
403-
),
404-
]
405-
),
406-
gui.column(
407-
spacing: 0
408-
padding: gui.padding_none
409-
content: [
410-
gui.text(text: variants.bold, text_style: text_style_file),
411-
gui.row(
412-
padding: gui.padding_none
413-
sizing: gui.fill_fit
414-
v_align: .bottom
415-
content: [
416-
gui.text(text: 'Theme().b1', text_style: gui.theme().b1),
417-
gui.text(text: 'Theme().b2', text_style: gui.theme().b2),
418-
gui.text(text: 'Theme().b3', text_style: gui.theme().b3),
419-
gui.text(text: 'Theme().b4', text_style: gui.theme().b4),
420-
gui.text(text: 'Theme().b5', text_style: gui.theme().b5),
421-
gui.text(text: 'Theme().b6', text_style: gui.theme().b6),
422-
]
423-
),
424-
]
425-
),
426-
gui.column(
427-
spacing: 0
428-
padding: gui.padding_none
429-
content: [
430-
gui.text(text: variants.italic, text_style: text_style_file),
431-
gui.row(
432-
padding: gui.padding_none
433-
sizing: gui.fill_fit
434-
v_align: .bottom
435-
content: [
436-
gui.text(text: 'Theme().i1', text_style: gui.theme().i1),
437-
gui.text(text: 'Theme().i2', text_style: gui.theme().i2),
438-
gui.text(text: 'Theme().i3', text_style: gui.theme().i3),
439-
gui.text(text: 'Theme().i4', text_style: gui.theme().i4),
440-
gui.text(text: 'Theme().i5', text_style: gui.theme().i5),
441-
gui.text(text: 'Theme().i6', text_style: gui.theme().i6),
442-
]
443-
),
444-
]
445-
),
446-
gui.column(
447-
spacing: 0
448-
padding: gui.padding_none
449-
content: [
450-
gui.text(text: variants.mono, text_style: text_style_file),
451-
gui.row(
452-
padding: gui.padding_none
453-
sizing: gui.fill_fit
454-
v_align: .bottom
455-
content: [
456-
gui.text(text: 'Theme().m1', text_style: gui.theme().m1),
457-
gui.text(text: 'Theme().m2', text_style: gui.theme().m2),
458-
gui.text(text: 'Theme().m3', text_style: gui.theme().m3),
459-
gui.text(text: 'Theme().m4', text_style: gui.theme().m4),
460-
gui.text(text: 'Theme().m5', text_style: gui.theme().m5),
461-
gui.text(text: 'Theme().m6', text_style: gui.theme().m6),
462-
]
463-
),
464-
]
465-
),
466-
]
467-
)
468-
}
469-
470376
// ==============================================================
471377
// Toggles
472378
// ==============================================================
@@ -1652,3 +1558,154 @@ fn throbber_sample(w &gui.Window) gui.View {
16521558
]
16531559
)
16541560
}
1561+
1562+
// ==============================================================
1563+
// Text Sizes & Weights
1564+
// ==============================================================
1565+
1566+
fn text_sizes_weights(w &gui.Window) gui.View {
1567+
text_style_file := gui.TextStyle{
1568+
...gui.theme().text_style
1569+
color: gui.theme().color_border
1570+
}
1571+
variants := gui.font_variants(gui.theme().text_style)
1572+
return gui.column(
1573+
sizing: gui.fill_fit
1574+
padding: gui.padding_none
1575+
content: [
1576+
view_title('Text Sizes & Weights'),
1577+
gui.column(
1578+
spacing: 0
1579+
padding: gui.padding_none
1580+
content: [
1581+
gui.text(text: variants.normal, text_style: text_style_file),
1582+
gui.row(
1583+
padding: gui.padding_none
1584+
sizing: gui.fill_fit
1585+
v_align: .bottom
1586+
content: [
1587+
gui.text(text: 'Theme().n1', text_style: gui.theme().n1),
1588+
gui.text(text: 'Theme().n2', text_style: gui.theme().n2),
1589+
gui.text(text: 'Theme().n3', text_style: gui.theme().n3),
1590+
gui.text(text: 'Theme().n4', text_style: gui.theme().n4),
1591+
gui.text(text: 'Theme().n5', text_style: gui.theme().n5),
1592+
gui.text(text: 'Theme().n6', text_style: gui.theme().n6),
1593+
]
1594+
),
1595+
]
1596+
),
1597+
gui.column(
1598+
spacing: 0
1599+
padding: gui.padding_none
1600+
content: [
1601+
gui.text(text: variants.bold, text_style: text_style_file),
1602+
gui.row(
1603+
padding: gui.padding_none
1604+
sizing: gui.fill_fit
1605+
v_align: .bottom
1606+
content: [
1607+
gui.text(text: 'Theme().b1', text_style: gui.theme().b1),
1608+
gui.text(text: 'Theme().b2', text_style: gui.theme().b2),
1609+
gui.text(text: 'Theme().b3', text_style: gui.theme().b3),
1610+
gui.text(text: 'Theme().b4', text_style: gui.theme().b4),
1611+
gui.text(text: 'Theme().b5', text_style: gui.theme().b5),
1612+
gui.text(text: 'Theme().b6', text_style: gui.theme().b6),
1613+
]
1614+
),
1615+
]
1616+
),
1617+
gui.column(
1618+
spacing: 0
1619+
padding: gui.padding_none
1620+
content: [
1621+
gui.text(text: variants.italic, text_style: text_style_file),
1622+
gui.row(
1623+
padding: gui.padding_none
1624+
sizing: gui.fill_fit
1625+
v_align: .bottom
1626+
content: [
1627+
gui.text(text: 'Theme().i1', text_style: gui.theme().i1),
1628+
gui.text(text: 'Theme().i2', text_style: gui.theme().i2),
1629+
gui.text(text: 'Theme().i3', text_style: gui.theme().i3),
1630+
gui.text(text: 'Theme().i4', text_style: gui.theme().i4),
1631+
gui.text(text: 'Theme().i5', text_style: gui.theme().i5),
1632+
gui.text(text: 'Theme().i6', text_style: gui.theme().i6),
1633+
]
1634+
),
1635+
]
1636+
),
1637+
gui.column(
1638+
spacing: 0
1639+
padding: gui.padding_none
1640+
content: [
1641+
gui.text(text: variants.mono, text_style: text_style_file),
1642+
gui.row(
1643+
padding: gui.padding_none
1644+
sizing: gui.fill_fit
1645+
v_align: .bottom
1646+
content: [
1647+
gui.text(text: 'Theme().m1', text_style: gui.theme().m1),
1648+
gui.text(text: 'Theme().m2', text_style: gui.theme().m2),
1649+
gui.text(text: 'Theme().m3', text_style: gui.theme().m3),
1650+
gui.text(text: 'Theme().m4', text_style: gui.theme().m4),
1651+
gui.text(text: 'Theme().m5', text_style: gui.theme().m5),
1652+
gui.text(text: 'Theme().m6', text_style: gui.theme().m6),
1653+
]
1654+
),
1655+
]
1656+
),
1657+
]
1658+
)
1659+
}
1660+
1661+
// ==============================================================
1662+
// Rich Text Format
1663+
// ==============================================================
1664+
fn rich_text_format(w &gui.Window) gui.View {
1665+
return gui.column(
1666+
padding: gui.padding_none
1667+
sizing: gui.fill_fill
1668+
content: [
1669+
view_title('Rich Text Format (RTF)'),
1670+
gui.row(
1671+
padding: gui.padding_none
1672+
sizing: gui.fill_fit
1673+
spacing: 0
1674+
content: [rtf_sample(w)]
1675+
),
1676+
]
1677+
)
1678+
}
1679+
1680+
fn rtf_sample(w &gui.Window) gui.View {
1681+
return gui.column(
1682+
padding: gui.padding_none
1683+
sizing: gui.fill_fill
1684+
content: [
1685+
gui.rtf(
1686+
mode: .wrap
1687+
spans: [
1688+
gui.span('Hello', gui.theme().n3),
1689+
gui.span(' RTF ', gui.theme().b3),
1690+
gui.span('World', gui.theme().n3),
1691+
gui.br(),
1692+
gui.br(),
1693+
gui.strike_span('Now is the', gui.theme().n3),
1694+
gui.span(' ', gui.theme().n3),
1695+
gui.span('time', gui.theme().i3),
1696+
gui.span(' for all', gui.theme().n3),
1697+
gui.span(' good men ', gui.TextStyle{
1698+
...gui.theme().n3
1699+
color: gui.green
1700+
}),
1701+
gui.span('to come to the aid of their ', gui.theme().n3),
1702+
gui.uspan('country', gui.theme().b3),
1703+
gui.br(),
1704+
gui.br(),
1705+
gui.span('This is a ', gui.theme().n3),
1706+
gui.hyperlink('hyperlink', 'https://www.example.com', gui.theme().n3),
1707+
]
1708+
),
1709+
]
1710+
)
1711+
}

0 commit comments

Comments
 (0)