guindilla_gui 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +1 -0
- data/LICENSE.md +675 -0
- data/README.md +89 -0
- data/lib/guindilla_gui/guindilla_classes.rb +605 -0
- data/lib/guindilla_gui/guindilla_methods.rb +614 -0
- data/lib/guindilla_gui/resources/guindilla.html +35 -0
- data/lib/guindilla_gui/resources/guindilla.js +46 -0
- data/lib/guindilla_gui/resources/guindilla_gui.png +0 -0
- data/lib/guindilla_gui/resources/jquery/jquery-3.6.0.min.js +2 -0
- data/lib/guindilla_gui/resources/plotly/plotly-2.9.0.min.js +65 -0
- data/lib/guindilla_gui/version.rb +5 -0
- data/lib/guindilla_gui.rb +20 -0
- metadata +98 -0
@@ -0,0 +1,614 @@
|
|
1
|
+
#------------------------------------------------------------------------------#
|
2
|
+
# Copyleft 2022
|
3
|
+
# This file is part of GuindillaGUI.
|
4
|
+
# GuindillaGUI is free software: you can redistribute it and/or modify it under
|
5
|
+
# the terms of the GNU General Public License as published by the Free Software
|
6
|
+
# Foundation, either version 3 of the License, or (at your option) any later
|
7
|
+
# version.
|
8
|
+
# GuindillaGUI is distributed in the hope that it will be useful, but WITHOUT
|
9
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
10
|
+
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
11
|
+
# You should have received a copy of the GNU General Public License along with
|
12
|
+
# GuindillaGUI. If not, see <https://www.gnu.org/licenses/>.
|
13
|
+
#------------------------------------------------------------------------------#
|
14
|
+
|
15
|
+
module GuindillaGUI
|
16
|
+
class Guindilla
|
17
|
+
##
|
18
|
+
# JavaScript `setTimeout` Timer
|
19
|
+
def after(seconds, &block)
|
20
|
+
Timer.new("timeout", seconds, &block)
|
21
|
+
end
|
22
|
+
|
23
|
+
def alert(message)
|
24
|
+
send_js(%Q~ alert("#{message}") ~)
|
25
|
+
end
|
26
|
+
|
27
|
+
def append(element)
|
28
|
+
id = caller_id(self)
|
29
|
+
send_js(%Q~ $("##{self.id}").append($("##{element.id}")); ~)
|
30
|
+
end
|
31
|
+
|
32
|
+
##
|
33
|
+
# attributes may include `controls: true`
|
34
|
+
def audio_out(attributes={})
|
35
|
+
AudioVideo.new("audio", attributes)
|
36
|
+
end
|
37
|
+
|
38
|
+
def bullet_list(list_array, attributes={})
|
39
|
+
ul = Element.new("ul")
|
40
|
+
list_array.each do |li|
|
41
|
+
send_js(%Q~ $("##{ul.id}").append($("<li>").html("#{li}")); ~)
|
42
|
+
end
|
43
|
+
return ul
|
44
|
+
end
|
45
|
+
|
46
|
+
##
|
47
|
+
# `button(text="", attributes={}, &block)`
|
48
|
+
def button(*args, &block)
|
49
|
+
args.unshift("") unless args[0].is_a?(String)
|
50
|
+
txt = args[0]
|
51
|
+
args[1] ? attributes = args[1] : attributes = {}
|
52
|
+
btn = Element.new("button", attributes)
|
53
|
+
send_js(%Q~ #{btn.id}.innerHTML = "#{txt}"; ~)
|
54
|
+
send_js(%Q~
|
55
|
+
#{btn.id}.onclick = function(event){
|
56
|
+
socket.send("#{btn.id}:!!:");
|
57
|
+
event.stopPropagation();
|
58
|
+
};
|
59
|
+
~)
|
60
|
+
@@gui.blocks[:"#{btn.id}"] = block if block_given?
|
61
|
+
return btn
|
62
|
+
end
|
63
|
+
|
64
|
+
def canvas(attributes={}, &block)
|
65
|
+
attributes[:width] = "50%" unless attributes[:width]
|
66
|
+
attributes[:height] = "33%" unless attributes[:height]
|
67
|
+
Canvas.new(attributes, &block)
|
68
|
+
end
|
69
|
+
|
70
|
+
##
|
71
|
+
# `chart(type: 'scatter', title: "", attributes={}, &block)`
|
72
|
+
def chart(attributes={}, &block)
|
73
|
+
# OPTIMIZE: use Hash#merge!
|
74
|
+
Chart.new(attributes, &block)
|
75
|
+
end
|
76
|
+
|
77
|
+
##
|
78
|
+
# `checkbox(label="", attributes={}, &block |boolean|)`
|
79
|
+
def checkbox(*args, &block)
|
80
|
+
args.unshift("") unless args[0].is_a?(String)
|
81
|
+
label = args[0]
|
82
|
+
args[1] ? attributes = args[1] : attributes = {}
|
83
|
+
Input.new("checkbox", label, attributes, &block)
|
84
|
+
end
|
85
|
+
|
86
|
+
def circle(radius, attributes={})
|
87
|
+
attributes[:cx] = radius
|
88
|
+
attributes[:cy] = radius
|
89
|
+
attributes[:r] = radius
|
90
|
+
Svg.new("circle", attributes)
|
91
|
+
end
|
92
|
+
|
93
|
+
##
|
94
|
+
# `color_input(label="", attributes={}, &block |color|)`
|
95
|
+
def color_input(*args, &block)
|
96
|
+
args.unshift("") unless args[0].is_a?(String)
|
97
|
+
label = args[0]
|
98
|
+
args[1] ? attributes = args[1] : attributes = {}
|
99
|
+
Input.new("color", label, attributes, &block)
|
100
|
+
end
|
101
|
+
|
102
|
+
def container(attributes={}, &block)
|
103
|
+
Box.new(nil, attributes, &block)
|
104
|
+
end
|
105
|
+
|
106
|
+
##
|
107
|
+
# JavaScript `setInterval` Timer
|
108
|
+
def every(seconds, &block)
|
109
|
+
Timer.new("interval", seconds, &block)
|
110
|
+
end
|
111
|
+
|
112
|
+
##
|
113
|
+
# `file_input(label="", attributes={}, &block |file|)`
|
114
|
+
def file_input(*args, &block)
|
115
|
+
args.unshift("") unless args[0].is_a?(String)
|
116
|
+
label = args[0]
|
117
|
+
args[1] ? attributes = args[1] : attributes = {}
|
118
|
+
Input.new("file", label, attributes, &block)
|
119
|
+
end
|
120
|
+
|
121
|
+
def h_box(attributes={}, &block)
|
122
|
+
Box.new("row", attributes, &block)
|
123
|
+
end
|
124
|
+
|
125
|
+
def h_rule(attributes={})
|
126
|
+
attributes[:width] = "100%" unless attributes[:width]
|
127
|
+
Element.new("hr", attributes)
|
128
|
+
end
|
129
|
+
|
130
|
+
##
|
131
|
+
# `heading(level=1, string, attributes={})`
|
132
|
+
def heading(*args)
|
133
|
+
args.unshift(1) unless args[0].is_a?(Integer)
|
134
|
+
level = args[0]
|
135
|
+
string = args[1]
|
136
|
+
args[2] ? attributes = args[2] : attributes = {}
|
137
|
+
h = Element.new("#{'h' + level.to_s}", attributes)
|
138
|
+
send_js(%Q~ #{h.id}.innerHTML = "#{string}"; ~)
|
139
|
+
return h
|
140
|
+
end
|
141
|
+
|
142
|
+
def hide
|
143
|
+
id = caller_id(self)
|
144
|
+
send_js(%Q~ $("##{id}").hide(); ~)
|
145
|
+
end
|
146
|
+
|
147
|
+
def image(source, attributes={})
|
148
|
+
img = Element.new("img", attributes)
|
149
|
+
send_js(%Q~ #{img.id}.src = "#{source}"; ~)
|
150
|
+
send_js(%Q~ #{img.id}.onerror = function(){
|
151
|
+
#{img.id}.src = "resources/guindilla_gui.png"
|
152
|
+
};
|
153
|
+
~)
|
154
|
+
return img
|
155
|
+
end
|
156
|
+
|
157
|
+
def line_break
|
158
|
+
para("")
|
159
|
+
end
|
160
|
+
|
161
|
+
def link(url, attributes={})
|
162
|
+
lnk = Element.new("a", attributes)
|
163
|
+
if self.is_a?(GuindillaGUI::Element)
|
164
|
+
lnk.append(self)
|
165
|
+
else
|
166
|
+
attributes[:text] ? txt = attributes[:text] : txt = url
|
167
|
+
send_js(%Q~ #{lnk.id}.textContent = "#{txt}"; ~)
|
168
|
+
end
|
169
|
+
send_js(%Q~ #{lnk.id}.href = "#{url}"; ~)
|
170
|
+
send_js(%Q~ #{lnk.id}.target = "_blank"; ~)
|
171
|
+
return lnk
|
172
|
+
end
|
173
|
+
|
174
|
+
##
|
175
|
+
# `number_input(label="", attributes={}, &block |input|)`
|
176
|
+
def number_input(*args, &block)
|
177
|
+
args.unshift("") unless args[0].is_a?(String)
|
178
|
+
label = args[0]
|
179
|
+
args[1] ? attributes = args[1] : attributes = {}
|
180
|
+
Input.new("number", label, attributes, &block)
|
181
|
+
end
|
182
|
+
|
183
|
+
def on_click(&block)
|
184
|
+
id = caller_id(self)
|
185
|
+
send_js(%Q~
|
186
|
+
#{id}.onclick = function(event){
|
187
|
+
socket.send("#{id}_click:!!:");
|
188
|
+
event.stopPropagation();
|
189
|
+
};
|
190
|
+
~)
|
191
|
+
@@gui.blocks[:"#{id}_click"] = block if block_given?
|
192
|
+
return @@gui.elements[:"#{id}"]
|
193
|
+
end
|
194
|
+
|
195
|
+
def on_hover(&block)
|
196
|
+
id = caller_id(self)
|
197
|
+
send_js(%Q~
|
198
|
+
#{id}.onmouseover = function(event){
|
199
|
+
socket.send("#{id}_hover:!!:");
|
200
|
+
event.stopPropagation();
|
201
|
+
};
|
202
|
+
~)
|
203
|
+
@@gui.blocks[:"#{id}_hover"] = block if block_given?
|
204
|
+
return @@gui.elements[:"#{id}"]
|
205
|
+
end
|
206
|
+
|
207
|
+
def on_leave(&block)
|
208
|
+
id = caller_id(self)
|
209
|
+
send_js(%Q~
|
210
|
+
#{id}.onmouseout = function(event){
|
211
|
+
socket.send("#{id}_leave:!!:");
|
212
|
+
event.stopPropagation();
|
213
|
+
};
|
214
|
+
~)
|
215
|
+
@@gui.blocks[:"#{id}_leave"] = block if block_given?
|
216
|
+
return @@gui.elements[:"#{id}"]
|
217
|
+
end
|
218
|
+
|
219
|
+
def on_mouse_move(&block)
|
220
|
+
id = caller_id(self)
|
221
|
+
send_js(%Q~
|
222
|
+
#{id}.onmousemove = function(event){
|
223
|
+
socket.send("#{id}:!!:mousemove:!!:" + event.pageX + ',' + event.pageY);
|
224
|
+
event.stopPropagation();
|
225
|
+
};
|
226
|
+
~)
|
227
|
+
@@gui.blocks[:"#{id}_move"] = block if block_given?
|
228
|
+
return @@gui.elements[:"#{id}"]
|
229
|
+
end
|
230
|
+
|
231
|
+
def ordered_list(list_array, attributes={})
|
232
|
+
ol = Element.new("ol")
|
233
|
+
list_array.each do |li|
|
234
|
+
send_js(%Q~ $("##{ol.id}").append($("<li>").html("#{li}")); ~)
|
235
|
+
end
|
236
|
+
return ol
|
237
|
+
end
|
238
|
+
|
239
|
+
def para(string, attributes={})
|
240
|
+
p = Element.new("p", attributes)
|
241
|
+
send_js(%Q~ #{p.id}.innerHTML = "#{string}"; ~)
|
242
|
+
return p
|
243
|
+
end
|
244
|
+
|
245
|
+
##
|
246
|
+
# `polygon` takes a nested array of x, y coordinates, e.g.:
|
247
|
+
# `polygon([[2, 0], [0, 3], [3, 3], [2, 0]])`
|
248
|
+
def polygon(points_array, attributes={})
|
249
|
+
points = ""
|
250
|
+
points_array.each do |arr|
|
251
|
+
points += arr.join(",")
|
252
|
+
points += " "
|
253
|
+
end
|
254
|
+
attributes[:points] = points
|
255
|
+
width = 0
|
256
|
+
height = 0
|
257
|
+
points.split(" ").each do |xy|
|
258
|
+
pair = xy.split(",")
|
259
|
+
width = pair[0].to_i if pair[0].to_i > width
|
260
|
+
height = pair[1].to_i if pair[1].to_i > height
|
261
|
+
end
|
262
|
+
attributes[:width] = width unless attributes[:width]
|
263
|
+
attributes[:height] = height unless attributes[:height]
|
264
|
+
Svg.new("polygon", attributes)
|
265
|
+
end
|
266
|
+
|
267
|
+
##
|
268
|
+
# `radio_button(label="", attributes={}, &block |boolean|)`
|
269
|
+
# attributes may include a +group:+ key to group buttons
|
270
|
+
def radio_button(*args, &block)
|
271
|
+
args.unshift("") unless args[0].is_a?(String)
|
272
|
+
label = args[0]
|
273
|
+
args[1] ? attributes = args[1] : attributes = {}
|
274
|
+
attributes[:group] = "no_group" unless attributes[:group]
|
275
|
+
Input.new("radio", label, attributes, &block)
|
276
|
+
end
|
277
|
+
|
278
|
+
##
|
279
|
+
# `range_slider(label="", {min: 0, max: 1.0, step: 0.05, value: 0.5}, &block |value|)`
|
280
|
+
def range_slider(*args, &block)
|
281
|
+
args.unshift("") unless args[0].is_a?(String)
|
282
|
+
label = args[0]
|
283
|
+
args[1] ? attributes = args[1] : attributes = {}
|
284
|
+
attributes[:min] = 0 unless attributes[:min]
|
285
|
+
attributes[:max] = 1.0 unless attributes[:max]
|
286
|
+
attributes[:step] = 0.05 unless attributes[:step]
|
287
|
+
attributes[:value] = (attributes[:max] - attributes[:min]) / 2 unless attributes[:value]
|
288
|
+
Input.new("range", label, attributes, &block)
|
289
|
+
end
|
290
|
+
|
291
|
+
def rectangle(width_integer, height_integer, attributes={})
|
292
|
+
attributes[:width] = width_integer
|
293
|
+
attributes[:height] = height_integer
|
294
|
+
Svg.new("rect", attributes)
|
295
|
+
end
|
296
|
+
|
297
|
+
def show
|
298
|
+
id = caller_id(self)
|
299
|
+
send_js(%Q~ $("##{id}").show(); ~)
|
300
|
+
end
|
301
|
+
|
302
|
+
def source(path_string)
|
303
|
+
id = caller_id(self)
|
304
|
+
send_js(%Q~ #{id}.src = "#{path_string}"; ~)
|
305
|
+
end
|
306
|
+
alias_method :source=, :source
|
307
|
+
|
308
|
+
def square(size_integer, attributes={})
|
309
|
+
rectangle(size_integer, size_integer, attributes)
|
310
|
+
end
|
311
|
+
|
312
|
+
def sub_script(string, attributes={})
|
313
|
+
## FIXME: displays superscript, huh???
|
314
|
+
sub = Element.new("p", attributes)
|
315
|
+
send_js(%Q~ #{sub.id}.innerHTML = "#{string}"; ~)
|
316
|
+
sub.style(vertical_align: "sub", font_size: "small")
|
317
|
+
return sub
|
318
|
+
end
|
319
|
+
|
320
|
+
def sup_script(string, attributes={})
|
321
|
+
sup = Element.new("p", attributes)
|
322
|
+
send_js(%Q~ #{sup.id}.innerHTML = "#{string}"; ~)
|
323
|
+
sup.style(vertical_align: "super", font_size: "small")
|
324
|
+
return sup
|
325
|
+
end
|
326
|
+
|
327
|
+
##
|
328
|
+
# set element text
|
329
|
+
def text(string)
|
330
|
+
id = caller_id(self)
|
331
|
+
send_js(%Q~ #{id}.innerHTML = "#{string}"; ~)
|
332
|
+
end
|
333
|
+
alias_method :text=, :text
|
334
|
+
|
335
|
+
##
|
336
|
+
# `text_input(label="", attributes={}, &block |input|)`
|
337
|
+
def text_input(*args, &block)
|
338
|
+
args.unshift("") unless args[0].is_a?(String)
|
339
|
+
label = args[0]
|
340
|
+
args[1] ? attributes = args[1] : attributes = {}
|
341
|
+
Input.new("text", label, attributes, &block)
|
342
|
+
end
|
343
|
+
|
344
|
+
##
|
345
|
+
# show/hide element
|
346
|
+
def toggle
|
347
|
+
id = caller_id(self)
|
348
|
+
send_js(%Q~ $("##{id}").toggle(); ~)
|
349
|
+
end
|
350
|
+
|
351
|
+
def triangle(size_integer, attributes={})
|
352
|
+
polygon(
|
353
|
+
[
|
354
|
+
[0, size_integer * 0.866],
|
355
|
+
[size_integer / 2, 0],
|
356
|
+
[size_integer, size_integer * 0.866]
|
357
|
+
],
|
358
|
+
attributes
|
359
|
+
)
|
360
|
+
end
|
361
|
+
|
362
|
+
##
|
363
|
+
# `url_input(label="", attributes={}, &block |input|)`
|
364
|
+
def url_input(*args, &block)
|
365
|
+
args.unshift("") unless args[0].is_a?(String)
|
366
|
+
label = args[0]
|
367
|
+
args[1] ? attributes = args[1] : attributes = {}
|
368
|
+
Input.new("url", label, attributes, &block)
|
369
|
+
end
|
370
|
+
|
371
|
+
def v_box(attributes={}, &block)
|
372
|
+
Box.new("column", attributes, &block)
|
373
|
+
end
|
374
|
+
|
375
|
+
##
|
376
|
+
# attributes may include `controls: true`
|
377
|
+
def video_out(attributes={})
|
378
|
+
attributes[:width] = 500 unless attributes[:width]
|
379
|
+
attributes[:height] = 300 unless attributes[:height]
|
380
|
+
AudioVideo.new("video", attributes)
|
381
|
+
end
|
382
|
+
|
383
|
+
def web_frame(attributes={})
|
384
|
+
attributes[:height] = "500px" unless attributes[:height]
|
385
|
+
Element.new("iframe", attributes)
|
386
|
+
end
|
387
|
+
|
388
|
+
|
389
|
+
##############################################################################
|
390
|
+
#----------------------------------------------------------------------------#
|
391
|
+
# style methods #
|
392
|
+
#----------------------------------------------------------------------------#
|
393
|
+
##############################################################################
|
394
|
+
##
|
395
|
+
# CSS properties key/value pairs with underscores `_` rather than dashes `-`
|
396
|
+
# e.g. `style(color: 'blue', text_align: 'center')`
|
397
|
+
##
|
398
|
+
|
399
|
+
def style(hash)
|
400
|
+
id = caller_id(self)
|
401
|
+
hash.each do |key, value|
|
402
|
+
send_js(%Q~
|
403
|
+
$("##{id}").css("#{key.to_s.gsub("_","-")}", "#{value}");
|
404
|
+
~)
|
405
|
+
@@gui.elements[:"#{id}"].attributes[:"#{key}"] = "#{value}"
|
406
|
+
end
|
407
|
+
return self
|
408
|
+
end
|
409
|
+
alias_method :style=, :style
|
410
|
+
|
411
|
+
##
|
412
|
+
# Vertical alignment within a box.
|
413
|
+
# Position may be `'stretch'`(default), `'center'`, `'start'`, `'end'`, or `'baseline'`.
|
414
|
+
# See 'align-items': https://css-tricks.com/snippets/css/a-guide-to-flexbox/
|
415
|
+
def align(position) # vertical
|
416
|
+
position = "flex-start" if position == "start"
|
417
|
+
position = "flex-end" if position == "end"
|
418
|
+
self.style(align_items: "#{position}")
|
419
|
+
return self
|
420
|
+
end
|
421
|
+
alias_method :align=, :align
|
422
|
+
|
423
|
+
##
|
424
|
+
# `color_string` may be rgb, rgba, hex, or CSS color
|
425
|
+
def background(color_string)
|
426
|
+
self.style(background: "#{color_string}")
|
427
|
+
return self
|
428
|
+
end
|
429
|
+
alias_method :background=, :background
|
430
|
+
|
431
|
+
##
|
432
|
+
# https://www.w3schools.com/css/css_border.asp
|
433
|
+
# e.g. `border('2px solid blue')`
|
434
|
+
def border(border_string)
|
435
|
+
self.style(border: "#{border_string}")
|
436
|
+
return self
|
437
|
+
end
|
438
|
+
alias_method :border=, :border
|
439
|
+
|
440
|
+
##
|
441
|
+
# `color_string` may be rgb, rgba, hex, or CSS color
|
442
|
+
def border_color(color_string)
|
443
|
+
if self.class.to_s == "GuindillaGUI::Svg"
|
444
|
+
self.style(stroke: "#{color_string}")
|
445
|
+
else
|
446
|
+
self.style(border_color: "#{color_string}")
|
447
|
+
end
|
448
|
+
return self
|
449
|
+
end
|
450
|
+
alias_method :border_color=, :border_color
|
451
|
+
|
452
|
+
##
|
453
|
+
# https://www.w3schools.com/cssref/css3_pr_border-radius.asp
|
454
|
+
def border_radius(pixels)
|
455
|
+
self.style(border_radius: "#{pixels}")
|
456
|
+
return self
|
457
|
+
end
|
458
|
+
alias_method :border_radius=, :border_radius
|
459
|
+
|
460
|
+
def border_width(width)
|
461
|
+
self.style(border_width: "#{width_integer}")
|
462
|
+
return self
|
463
|
+
|
464
|
+
end
|
465
|
+
alias_method :border_width=, :border_width
|
466
|
+
|
467
|
+
##
|
468
|
+
# `color_string` may be rgb, rgba, hex, or CSS color
|
469
|
+
def color(color_string)
|
470
|
+
if self.class.to_s == "GuindillaGUI::Svg"
|
471
|
+
self.style(fill: "#{color_string}")
|
472
|
+
else
|
473
|
+
self.style(color: "#{color_string}")
|
474
|
+
end
|
475
|
+
return self
|
476
|
+
end
|
477
|
+
alias_method :color=, :color
|
478
|
+
|
479
|
+
##
|
480
|
+
# CSS display property.
|
481
|
+
# https://www.w3schools.com/CSSref/pr_class_display.asp
|
482
|
+
def display(property)
|
483
|
+
self.style(display: "#{property}")
|
484
|
+
return self
|
485
|
+
end
|
486
|
+
alias_method :display=, :display
|
487
|
+
|
488
|
+
##
|
489
|
+
# https://www.w3schools.com/css/css_font.asp
|
490
|
+
def font(family_string, size_integer)
|
491
|
+
id = caller_id(self)
|
492
|
+
self.style(font_family: "#{family_string}", font_size: "#{size_integer}")
|
493
|
+
return self
|
494
|
+
end
|
495
|
+
alias_method :font=, :font
|
496
|
+
|
497
|
+
##
|
498
|
+
# https://www.w3schools.com/Css/css_font.asp
|
499
|
+
def font_family(family_string)
|
500
|
+
self.style(font_family: "#{family_string}")
|
501
|
+
return self
|
502
|
+
end
|
503
|
+
alias_method :font_family=, :font_family
|
504
|
+
|
505
|
+
##
|
506
|
+
# https://www.w3schools.com/cssref/pr_font_font-size.asp
|
507
|
+
def font_size(size)
|
508
|
+
self.style(font_size: "#{size}")
|
509
|
+
return self
|
510
|
+
end
|
511
|
+
alias_method :font_size=, :font_size
|
512
|
+
|
513
|
+
##
|
514
|
+
# https://www.w3schools.com/cssref/pr_dim_height.asp
|
515
|
+
def height(h)
|
516
|
+
self.style(height: "#{h}")
|
517
|
+
return self
|
518
|
+
end
|
519
|
+
alias_method :height=, :height
|
520
|
+
|
521
|
+
##
|
522
|
+
# Horizontal justification within a box.
|
523
|
+
# https://www.w3schools.com/csSref/css3_pr_justify-content.asp
|
524
|
+
def justify(position)
|
525
|
+
position = "flex-start" if position == "start"
|
526
|
+
position = "flex-end" if position == "end"
|
527
|
+
self.style(justify_content: "#{position}")
|
528
|
+
return self
|
529
|
+
end
|
530
|
+
alias_method :justify=, :justify
|
531
|
+
|
532
|
+
##
|
533
|
+
# margin in pixels, or `'auto'` to center
|
534
|
+
def margin(size)
|
535
|
+
self.style(margin: "#{size}")
|
536
|
+
return self
|
537
|
+
end
|
538
|
+
alias_method :margin=, :margin
|
539
|
+
|
540
|
+
##
|
541
|
+
# 0.0 to 1.0
|
542
|
+
def opacity(value)
|
543
|
+
if self.class.to_s == "GuindillaGUI::Svg"
|
544
|
+
self.style(fill_opacity: "#{value}")
|
545
|
+
else
|
546
|
+
self.style(opacity: "#{value}")
|
547
|
+
end
|
548
|
+
return self
|
549
|
+
end
|
550
|
+
alias_method :opacity=, :opacity
|
551
|
+
|
552
|
+
##
|
553
|
+
# padding in pixels
|
554
|
+
def padding(size)
|
555
|
+
self.style(padding: "#{size}")
|
556
|
+
return self
|
557
|
+
end
|
558
|
+
alias_method :padding=, :padding
|
559
|
+
|
560
|
+
##
|
561
|
+
# position by x and y pixel coordinates
|
562
|
+
def position(x, y)
|
563
|
+
self.style(position: 'absolute')
|
564
|
+
self.style(left: "#{x}px", top: "#{y}px")
|
565
|
+
end
|
566
|
+
alias_method :position=, :position
|
567
|
+
|
568
|
+
def rotate(degrees)
|
569
|
+
rotation = self.attributes[:rotate].to_i + degrees
|
570
|
+
self.style(rotate: "#{rotation}deg")
|
571
|
+
return self
|
572
|
+
end
|
573
|
+
|
574
|
+
def size(width, height)
|
575
|
+
self.style(width: "#{width}", height: "#{height}")
|
576
|
+
return self
|
577
|
+
end
|
578
|
+
alias_method :size=, :size
|
579
|
+
|
580
|
+
##
|
581
|
+
# position may be `'left'`, `'right'`, `'center'`, or `'justify'`
|
582
|
+
def text_align(position)
|
583
|
+
self.style(text_align: "#{position}")
|
584
|
+
return self
|
585
|
+
end
|
586
|
+
alias_method :text_align=, :text_align
|
587
|
+
|
588
|
+
##
|
589
|
+
# `transition(property, duration, delay=0, type="ease")`
|
590
|
+
# https://www.w3schools.com/css/css3_transitions.asp
|
591
|
+
def transition(property, duration, *args)
|
592
|
+
self.style(transition: "#{property} #{duration}s")
|
593
|
+
unless args.empty?
|
594
|
+
args.each do |arg|
|
595
|
+
if arg.is_a?(String)
|
596
|
+
self.style(transition_timing_function: "#{arg}")
|
597
|
+
elsif arg.is_a?(Integer)
|
598
|
+
self.style(transition_delay: "#{arg}s")
|
599
|
+
end
|
600
|
+
end
|
601
|
+
end
|
602
|
+
end
|
603
|
+
alias_method :transition=, :transition
|
604
|
+
|
605
|
+
##
|
606
|
+
# https://www.w3schools.com/cssref/pr_dim_width.asp
|
607
|
+
def width(w)
|
608
|
+
self.style(width: "#{w}")
|
609
|
+
return self
|
610
|
+
end
|
611
|
+
alias_method :width=, :width
|
612
|
+
|
613
|
+
end #class Guindilla
|
614
|
+
end #module
|
@@ -0,0 +1,35 @@
|
|
1
|
+
<!--
|
2
|
+
#------------------------------------------------------------------------------#
|
3
|
+
# Copyleft 2022
|
4
|
+
# This file is part of GuindillaGUI.
|
5
|
+
# GuindillaGUI is free software: you can redistribute it and/or modify it under
|
6
|
+
# the terms of the GNU General Public License as published by the Free Software
|
7
|
+
# Foundation, either version 3 of the License, or (at your option) any later
|
8
|
+
# version.
|
9
|
+
# GuindillaGUI is distributed in the hope that it will be useful, but WITHOUT
|
10
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
11
|
+
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
12
|
+
# You should have received a copy of the GNU General Public License along with
|
13
|
+
# GuindillaGUI. If not, see <https://www.gnu.org/licenses/>.
|
14
|
+
#------------------------------------------------------------------------------#
|
15
|
+
-->
|
16
|
+
|
17
|
+
<!doctype html>
|
18
|
+
|
19
|
+
<html lang="en">
|
20
|
+
<head>
|
21
|
+
<meta charset="utf-8">
|
22
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
23
|
+
<title>GuindillaGUI</title>
|
24
|
+
<meta name="description" content="GuindillaGUI generated html">
|
25
|
+
<meta name="author" content="lljk">
|
26
|
+
<link rel="icon" href="guindilla_gui.png">
|
27
|
+
|
28
|
+
<script src="jquery/jquery-3.6.0.min.js"></script>
|
29
|
+
<script src="plotly/plotly-2.9.0.min.js"></script>
|
30
|
+
<script src="guindilla.js"></script>
|
31
|
+
</head>
|
32
|
+
|
33
|
+
<body id="body">
|
34
|
+
</body>
|
35
|
+
</html>
|
@@ -0,0 +1,46 @@
|
|
1
|
+
/*
|
2
|
+
#------------------------------------------------------------------------------#
|
3
|
+
# Copyleft 2022
|
4
|
+
# This file is part of GuindillaGUI.
|
5
|
+
# GuindillaGUI is free software: you can redistribute it and/or modify it under
|
6
|
+
# the terms of the GNU General Public License as published by the Free Software
|
7
|
+
# Foundation, either version 3 of the License, or (at your option) any later
|
8
|
+
# version.
|
9
|
+
# GuindillaGUI is distributed in the hope that it will be useful, but WITHOUT
|
10
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
11
|
+
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
12
|
+
# You should have received a copy of the GNU General Public License along with
|
13
|
+
# GuindillaGUI. If not, see <https://www.gnu.org/licenses/>.
|
14
|
+
#------------------------------------------------------------------------------#
|
15
|
+
*/
|
16
|
+
|
17
|
+
let socket = null
|
18
|
+
|
19
|
+
$(document).ready(function(){
|
20
|
+
|
21
|
+
socket = new WebSocket('ws://localhost:8181/');
|
22
|
+
|
23
|
+
socket.onopen = function(event) {
|
24
|
+
console.log("[open] Connection with GuindillaGUI established");
|
25
|
+
};
|
26
|
+
socket.onmessage = function(event) {
|
27
|
+
console.log(`[message] Data received from server: ${event.data}`);
|
28
|
+
$(document.body).append(event.data);
|
29
|
+
};
|
30
|
+
socket.onclose = function(event) {
|
31
|
+
if (event.wasClean) {
|
32
|
+
console.log(`[close] Connection with GuindillaGUI closed, code=${event.code} reason=${event.reason}`);
|
33
|
+
} else {
|
34
|
+
alert('[close] Connection with GuindillaGUI died');
|
35
|
+
}
|
36
|
+
};
|
37
|
+
socket.onerror = function(error) {
|
38
|
+
alert(`[error] ${error.message}`);
|
39
|
+
};
|
40
|
+
|
41
|
+
window.addEventListener('beforeunload', function (e) {
|
42
|
+
socket.send("UI closed.")
|
43
|
+
socket.close();
|
44
|
+
});
|
45
|
+
|
46
|
+
});
|
Binary file
|