-
Notifications
You must be signed in to change notification settings - Fork 30
/
widgets.fs
174 lines (157 loc) · 6 KB
/
widgets.fs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
module FVim.widgets
open common
open def
open theme
open svg
open Avalonia
open Avalonia.Layout
open Avalonia.Media
open Avalonia.Media.Imaging
open System.IO
open System.Text
let mutable guiwidgetNamespace = -1
type SignPlacement =
{
line: int
kind: SignKind
}
type CursorHide =
| NoHide
| CursorOverlap
| CursorLineOverlap
type WidgetPlacement =
{
mark: int
widget: int
w: int
h: int
opt: hashmap<obj,obj>
}
member this.HorizontalAlignment with get() =
match this.opt.TryGetValue "halign" with
| true, x -> parseHorizontalAlignment x
| _ -> None
|> Option.defaultValue HorizontalAlignment.Stretch
member this.VerticalAlignment with get() =
match this.opt.TryGetValue "valign" with
| true, x -> parseVerticalAlignment x
| _ -> None
|> Option.defaultValue VerticalAlignment.Stretch
member this.Stretch with get() =
match this.opt.TryGetValue "stretch" with
| true, x -> parseStretch x
| _ -> None
|> Option.defaultValue Stretch.None
member this.GetDrawingBounds (src_size: Size) (dst_bounds: Rect) =
let halign, valign, stretch = this.HorizontalAlignment, this.VerticalAlignment, this.Stretch
let sx, sy = dst_bounds.Width / src_size.Width , dst_bounds.Height / src_size.Height
let scale = match stretch with
| Stretch.Uniform -> min sx sy
| Stretch.UniformToFill -> max sx sy
| (*Stretch.None*) _ -> 1.0
let scaled_size = src_size * scale
let center = dst_bounds.Center
let dst_l, dst_w = match halign with
| HorizontalAlignment.Center -> center.X - scaled_size.Width / 2.0, scaled_size.Width
| HorizontalAlignment.Left -> dst_bounds.Left, scaled_size.Width
| HorizontalAlignment.Right -> dst_bounds.Right - scaled_size.Width, scaled_size.Width
| (* HorizontalAlignment.Stretch *) _ -> dst_bounds.Left, dst_bounds.Width
let dst_t, dst_h = match valign with
| VerticalAlignment.Center -> center.Y - scaled_size.Height / 2.0, scaled_size.Height
| VerticalAlignment.Top -> dst_bounds.Top, scaled_size.Height
| VerticalAlignment.Bottom -> dst_bounds.Bottom - scaled_size.Height, scaled_size.Height
| (* VerticalAlignment.Stretch *) _ -> dst_bounds.Top, dst_bounds.Height
Rect(0.0, 0.0, src_size.Width, src_size.Height), Rect(dst_l, dst_t, dst_w, dst_h)
member this.GetTextAttr() =
let drawAttrs = match this.opt.TryGetValue("text-hlid") with
| true, (Integer32 id) -> GetDrawAttrs id
| true, (String semid) ->
match SemanticHighlightGroup.TryParse semid with
| true, semid -> getSemanticHighlightGroup semid
| _ -> GetDrawAttrs 1
| _ -> GetDrawAttrs 1
let font = match this.opt.TryGetValue("text-font") with
| true, String(fnt) -> fnt
| _ -> theme.guifont
let size = match this.opt.TryGetValue("text-scale") with
| true, Float(x) -> theme.fontsize * x
| _ -> theme.fontsize
let fg,bg,_,attrs = drawAttrs
let bg = removeAlpha bg
let typeface = ui.GetTypeface(Rune.empty, attrs.italic, attrs.bold, font, theme.guifontwide)
fg, bg, typeface, size
member this.GetHideAttr() =
match this.opt.TryGetValue("hide") with
| true, String("cursor") -> CursorOverlap
| true, String("cursorline") -> CursorLineOverlap
| _ -> NoHide
member this.GetSvgAttr(hideAttr: CursorHide, lineOverlap: bool, colOverlap: bool, singleLine: bool) =
let themed =
match this.opt.TryGetValue("svg-themed") with
| true, ForceBool true -> true
| _ -> false
let black, white, _, _ =
if lineOverlap && singleLine && hideAttr = CursorOverlap then
getSemanticHighlightGroup SemanticHighlightGroup.CursorLine
else
GetDrawAttrs 1
let white = removeAlpha white
themed, black, white
member this.Mouse =
match this.opt.TryGetValue("mouse") with
| true, Bool x -> x
| _ -> false
let private s_no_opt = hashmap[]
let parse_placement =
function
| ObjArray [| Integer32 a; Integer32 b; Integer32 c; Integer32 d; |]
-> Some({mark = a; widget = b; w = c; h = d; opt = s_no_opt})
| ObjArray [| Integer32 a; Integer32 b; Integer32 c; Integer32 d; :?hashmap<obj,obj> as e |]
-> Some({mark = a; widget = b; w = c; h = d; opt = e})
| _ -> None
type GuiWidgetType =
| BitmapWidget of Bitmap
| VectorImageWidget of SvgPicture
| PlainTextWidget of string
| UnknownWidget of mime: string * data: byte[]
| NotFound
let private widget_resources = hashmap[]
let private widget_placements = hashmap[]
let private sign_placements = hashmap[]
let loadGuiResource (id:int) (mime: string) (data: byte[]) =
widget_resources.[id] <-
match mime with
| "image/svg" ->
let data = Encoding.UTF8.GetString(data)
VectorImageWidget(SvgPicture data)
| x when x.StartsWith("image/") ->
use stream = new MemoryStream(data)
BitmapWidget(new Bitmap(stream))
| "text/plain" ->
let data = Encoding.UTF8.GetString(data)
PlainTextWidget data
| _ ->
UnknownWidget(mime, data)
let loadGuiWidgetPlacements (buf:int) (M: WidgetPlacement[]) =
let index = hashmap[]
for {mark = mark} as p in M do
index.[mark] <- p
widget_placements.[buf] <- index
let loadSignPlacements (buf:int) (M: SignPlacement[]) =
sign_placements.[buf] <- M
let private _no_widget_placements = hashmap[]
let getGuiWidgetPlacements (buf:int) =
match widget_placements.TryGetValue buf with
| true, p -> p
| _ -> _no_widget_placements
let getGuiWidget (id: int) =
match widget_resources.TryGetValue id with
| true, x -> x
| _ ->
// TODO make another request here
NotFound
let private _no_sign_placements = [||]
let getSignPlacements (buf:int) =
match sign_placements.TryGetValue buf with
| true, p -> p
| _ -> _no_sign_placements