wads 0.1.3 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/README.md +11 -0
- data/data/sample_graph.csv +11 -0
- data/lib/wads/app.rb +40 -332
- data/lib/wads/data_structures.rb +236 -19
- data/lib/wads/textinput.rb +20 -14
- data/lib/wads/version.rb +1 -1
- data/lib/wads/widgets.rb +2142 -212
- data/lib/wads.rb +1 -1
- data/media/CircleAlpha.png +0 -0
- data/media/CircleAqua.png +0 -0
- data/media/CircleBlue.png +0 -0
- data/media/CircleGray.png +0 -0
- data/media/CircleGreen.png +0 -0
- data/media/CirclePurple.png +0 -0
- data/media/CircleRed.png +0 -0
- data/media/CircleWhite.png +0 -0
- data/media/CircleYellow.png +0 -0
- data/media/SampleGraph.png +0 -0
- data/media/WadsScreenshot.png +0 -0
- data/run-graph +3 -0
- data/run-star-wars +3 -0
- data/run-stocks +3 -0
- data/run-theme-test +3 -0
- data/samples/basic_gosu_with_graph_widget.rb +66 -0
- data/samples/graph.rb +72 -0
- data/samples/star_wars.rb +112 -0
- data/samples/stocks.rb +126 -0
- data/samples/theme_test.rb +256 -0
- metadata +22 -5
- data/run-sample-app +0 -3
- data/sample_app.rb +0 -64
data/lib/wads.rb
CHANGED
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
data/media/CircleRed.png
ADDED
Binary file
|
Binary file
|
Binary file
|
data/media/SampleGraph.png
CHANGED
Binary file
|
data/media/WadsScreenshot.png
CHANGED
Binary file
|
data/run-graph
ADDED
data/run-star-wars
ADDED
data/run-stocks
ADDED
data/run-theme-test
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'gosu'
|
2
|
+
require_relative '../lib/wads'
|
3
|
+
|
4
|
+
include Wads
|
5
|
+
#
|
6
|
+
# The WadsApp class provides a simple starting point to quickly build a native
|
7
|
+
# Ruby application using Gosu as an underlying library. It provides all the necessary
|
8
|
+
# hooks to get started. All you need to do is supply the parent Wads widget using
|
9
|
+
# the set_display(widget) method. See one of the Wads samples for example usage.
|
10
|
+
#
|
11
|
+
class BasicGosuAppWithGraph < Gosu::Window
|
12
|
+
def initialize
|
13
|
+
super(800, 600)
|
14
|
+
self.caption = 'Basic Gosu App with Graph Widget'
|
15
|
+
@font = Gosu::Font.new(22)
|
16
|
+
@graph_widget = GraphWidget.new(10, 110, # x, y coordinate of top left corder
|
17
|
+
780, 480, # width x height
|
18
|
+
create_graph,
|
19
|
+
GRAPH_DISPLAY_EXPLORER)
|
20
|
+
@update_count = 0
|
21
|
+
end
|
22
|
+
|
23
|
+
def create_graph
|
24
|
+
g = Graph.new
|
25
|
+
g.add("A")
|
26
|
+
g.add("B")
|
27
|
+
g.add("C")
|
28
|
+
g.add("D")
|
29
|
+
g.add("E")
|
30
|
+
g.add("F")
|
31
|
+
g.connect("A", "B")
|
32
|
+
g.connect("A", "C")
|
33
|
+
g.connect("B", "D")
|
34
|
+
g.connect("B", "E")
|
35
|
+
g.connect("E", "F")
|
36
|
+
g
|
37
|
+
end
|
38
|
+
|
39
|
+
def update
|
40
|
+
# Calling handle_update on the grpah widget is required if you want interactivity
|
41
|
+
# specifically, for drag and drop of the nodes
|
42
|
+
@update_count = @update_count + 1
|
43
|
+
@graph_widget.handle_update @update_count, mouse_x, mouse_y
|
44
|
+
end
|
45
|
+
|
46
|
+
def draw
|
47
|
+
@font.draw_text("Sample App with Wads Graph Widget", 240, 49, 1, 1, 1, COLOR_WHITE)
|
48
|
+
@graph_widget.draw
|
49
|
+
end
|
50
|
+
|
51
|
+
def button_down id
|
52
|
+
close if id == Gosu::KbEscape
|
53
|
+
# Delegate button events to the graph widget if you want the
|
54
|
+
# user to be able to interact with it
|
55
|
+
@graph_widget.button_down id, mouse_x, mouse_y
|
56
|
+
end
|
57
|
+
|
58
|
+
def button_up id
|
59
|
+
# Delegate button events to the graph widget if you want the
|
60
|
+
# user to be able to interact with it
|
61
|
+
@graph_widget.button_up id, mouse_x, mouse_y
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
BasicGosuAppWithGraph.new.show
|
data/samples/graph.rb
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'gosu'
|
2
|
+
require_relative '../lib/wads'
|
3
|
+
|
4
|
+
include Wads
|
5
|
+
|
6
|
+
class SampleGraphApp < WadsApp
|
7
|
+
|
8
|
+
SAMPLE_GRAPH_DEFINITION_FILE = "./data/sample_graph.csv"
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
super(800, 600, "Wads Sample Graph App", GraphDisplay.new(create_sample_graph))
|
12
|
+
end
|
13
|
+
|
14
|
+
#
|
15
|
+
# Below are three different ways you can construct a graph
|
16
|
+
#
|
17
|
+
def create_sample_graph
|
18
|
+
g = Graph.new
|
19
|
+
g.add("A")
|
20
|
+
g.add("B")
|
21
|
+
g.add("C")
|
22
|
+
g.add("D")
|
23
|
+
g.add("E")
|
24
|
+
g.add("F")
|
25
|
+
g.connect("A", "B")
|
26
|
+
g.connect("A", "C")
|
27
|
+
g.connect("B", "D")
|
28
|
+
g.connect("B", "E")
|
29
|
+
g.connect("E", "F")
|
30
|
+
g
|
31
|
+
end
|
32
|
+
|
33
|
+
def create_sample_graph_using_nodes
|
34
|
+
root = Node.new("A")
|
35
|
+
b = root.add("B")
|
36
|
+
b.add("D")
|
37
|
+
b.add("E").add("F")
|
38
|
+
root.add("C")
|
39
|
+
Graph.new(root)
|
40
|
+
end
|
41
|
+
|
42
|
+
def create_sample_graph_from_file
|
43
|
+
Graph.new(SAMPLE_GRAPH_DEFINITION_FILE)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class GraphDisplay < Widget
|
48
|
+
|
49
|
+
def initialize(graph)
|
50
|
+
super(0, 0, 800, 600)
|
51
|
+
set_layout(LAYOUT_TOP_MIDDLE_BOTTOM)
|
52
|
+
@graph = graph
|
53
|
+
|
54
|
+
image = get_layout.add_image("./media/Banner.png", { ARG_SECTION => SECTION_TOP})
|
55
|
+
image.add_text("Wads Sample App", 10, 20, nil, true)
|
56
|
+
image.add_text("Version #{Wads::VERSION}", 13, 54)
|
57
|
+
|
58
|
+
panel = get_layout.add_horizontal_panel({ ARG_SECTION => SECTION_BOTTOM})
|
59
|
+
panel.add_button("Exit", 0, panel.height - 30) do
|
60
|
+
WidgetResult.new(true)
|
61
|
+
end
|
62
|
+
panel.center_children
|
63
|
+
panel.disable_border
|
64
|
+
|
65
|
+
@graph_display = get_layout.add_graph_display(@graph, GRAPH_DISPLAY_EXPLORER,
|
66
|
+
{ ARG_SECTION => SECTION_CENTER})
|
67
|
+
disable_border
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
#WadsConfig.instance.set_current_theme(WadsNoIconTheme.new)
|
72
|
+
SampleGraphApp.new.show
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require 'gosu'
|
2
|
+
require 'json'
|
3
|
+
require_relative '../lib/wads'
|
4
|
+
|
5
|
+
include Wads
|
6
|
+
|
7
|
+
class SampleStarWarsApp < WadsApp
|
8
|
+
|
9
|
+
STAR_WARS_DATA_FILE = "./data/starwars-episode-4-interactions.json"
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
super(800, 800, "Wads Sample Star Wars App", StarWarsDisplay.new(process_star_wars_data))
|
13
|
+
end
|
14
|
+
|
15
|
+
def process_star_wars_data
|
16
|
+
star_wars_json = File.read(STAR_WARS_DATA_FILE)
|
17
|
+
data_hash = JSON.parse(star_wars_json)
|
18
|
+
characters = data_hash['nodes']
|
19
|
+
interactions = data_hash['links']
|
20
|
+
|
21
|
+
# The interactions in the data set reference the characters by their
|
22
|
+
# zero based index, so we keep a reference in our graph by index.
|
23
|
+
# The character's value is the number of scenes in which they appear.
|
24
|
+
graph = Graph.new
|
25
|
+
characters.each do |character|
|
26
|
+
node_tags = {}
|
27
|
+
node_color_str = character['colour']
|
28
|
+
# This is a bit of a hack, but our background is black so black text
|
29
|
+
# will not show up. Change this to white
|
30
|
+
if node_color_str == "#000000"
|
31
|
+
node_color_str = "#FFFFFF"
|
32
|
+
end
|
33
|
+
# Convert hex string (ex. "#EE00AA") into int hex representation
|
34
|
+
# understood by Gosu color (ex. 0xFFEE00AA)
|
35
|
+
node_color = "0xFF#{node_color_str[1..-1]}".to_i(16)
|
36
|
+
node_tags['color'] = node_color
|
37
|
+
graph.add_node(Node.new(character['name'], character['value'], node_tags))
|
38
|
+
end
|
39
|
+
interactions.each do |interaction|
|
40
|
+
character_one = graph.node_by_index(interaction['source'])
|
41
|
+
character_two = graph.node_by_index(interaction['target'])
|
42
|
+
number_of_scenes_together = interaction['value']
|
43
|
+
edge_tags = {}
|
44
|
+
edge_tags["scenes"] = number_of_scenes_together
|
45
|
+
graph.add_edge(character_one, character_two, edge_tags)
|
46
|
+
end
|
47
|
+
graph
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
class StarWarsDisplay < Widget
|
52
|
+
attr_accessor :graph
|
53
|
+
|
54
|
+
def initialize(graph)
|
55
|
+
super(0, 0, 800, 800)
|
56
|
+
set_layout(LAYOUT_TOP_MIDDLE_BOTTOM)
|
57
|
+
@graph = graph
|
58
|
+
|
59
|
+
image = get_layout.add_image("./media/Banner.png", { ARG_SECTION => SECTION_TOP})
|
60
|
+
image.add_text("Wads Sample App", 10, 20, nil, true)
|
61
|
+
image.add_text("Version #{Wads::VERSION}", 13, 54)
|
62
|
+
|
63
|
+
get_layout.add_document(sample_content, { ARG_SECTION => SECTION_CENTER})
|
64
|
+
|
65
|
+
panel = get_layout.add_horizontal_panel({ ARG_SECTION => SECTION_BOTTOM})
|
66
|
+
panel.add_button("Exit", 0, panel.height - 30) do
|
67
|
+
WidgetResult.new(true)
|
68
|
+
end
|
69
|
+
panel.center_children
|
70
|
+
panel.disable_border
|
71
|
+
|
72
|
+
@data_table = get_layout.add_single_select_table(
|
73
|
+
["Character", "Number of Scenes"], 4, { ARG_SECTION => SECTION_CENTER})
|
74
|
+
|
75
|
+
@graph.node_list.each do |character|
|
76
|
+
@data_table.add_row([character.name, character.value], character.get_tag(ARG_COLOR))
|
77
|
+
end
|
78
|
+
@graph_display = get_layout.add_graph_display(@graph, GRAPH_DISPLAY_EXPLORER,
|
79
|
+
{ ARG_SECTION => SECTION_CENTER})
|
80
|
+
|
81
|
+
disable_border
|
82
|
+
end
|
83
|
+
|
84
|
+
def sample_content
|
85
|
+
<<~HEREDOC
|
86
|
+
This sample analysis shows the interactions between characters in the Star Wars
|
87
|
+
Episode 4: A New Hope. Click on a character to see more detail.
|
88
|
+
HEREDOC
|
89
|
+
end
|
90
|
+
|
91
|
+
def handle_key_press id, mouse_x, mouse_y
|
92
|
+
if id == Gosu::KbUp
|
93
|
+
@data_table.scroll_up
|
94
|
+
elsif id == Gosu::KbDown
|
95
|
+
@data_table.scroll_down
|
96
|
+
end
|
97
|
+
WidgetResult.new(false)
|
98
|
+
end
|
99
|
+
|
100
|
+
def handle_mouse_down mouse_x, mouse_y
|
101
|
+
if @data_table.contains_click(mouse_x, mouse_y)
|
102
|
+
val = @data_table.set_selected_row(mouse_y, 0)
|
103
|
+
if not val.nil?
|
104
|
+
node = @graph.find_node(val)
|
105
|
+
#@graph_display.set_center_node(node, 2)
|
106
|
+
@graph_display.set_explorer_display(node)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
SampleStarWarsApp.new.show
|
data/samples/stocks.rb
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
require 'gosu'
|
2
|
+
require_relative '../lib/wads'
|
3
|
+
|
4
|
+
include Wads
|
5
|
+
|
6
|
+
class SampleStocksApp < WadsApp
|
7
|
+
|
8
|
+
STOCKS_DATA_FILE = "./data/NASDAQ.csv"
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
super(800, 600, "Wads Sample Stocks App", StocksDisplay.new(process_stock_data))
|
12
|
+
end
|
13
|
+
|
14
|
+
def process_stock_data
|
15
|
+
# The data file comes from https://finance.yahoo.com
|
16
|
+
# The format of this file is as follows:
|
17
|
+
#
|
18
|
+
# Date,Open,High,Low,Close,Adj Close,Volume
|
19
|
+
# 2000-01-03,4186.189941,4192.189941,3989.709961,4131.149902,4131.149902,1510070000
|
20
|
+
# 2000-01-04,4020.000000,4073.250000,3898.229980,3901.689941,3901.689941,1511840000
|
21
|
+
# ...
|
22
|
+
# 2020-12-30,12906.509766,12924.929688,12857.759766,12870.000000,12870.000000,5292210000
|
23
|
+
# 2020-12-31,12877.089844,12902.070313,12821.230469,12888.280273,12888.280273,4771390000
|
24
|
+
|
25
|
+
stats = Stats.new("NASDAQ")
|
26
|
+
previous_close = nil
|
27
|
+
|
28
|
+
puts "Read the data file #{STOCKS_DATA_FILE}"
|
29
|
+
File.readlines(STOCKS_DATA_FILE).each do |line|
|
30
|
+
line = line.chomp # remove the carriage return
|
31
|
+
|
32
|
+
# Ignore header and any empty lines, process numeric data lines
|
33
|
+
if line.length > 0 and line[0].match(/[0-9]/)
|
34
|
+
values = line.split(",")
|
35
|
+
date = Date.strptime(values[0], "%Y-%m-%d")
|
36
|
+
weekday = Date::DAYNAMES[date.wday]
|
37
|
+
|
38
|
+
open_value = values[1].to_f
|
39
|
+
close_value = values[4].to_f
|
40
|
+
|
41
|
+
if previous_close.nil?
|
42
|
+
# Just use the first day to set the baseline
|
43
|
+
previous_close = close_value
|
44
|
+
else
|
45
|
+
change_from_previous_close = close_value - previous_close
|
46
|
+
change_intraday = close_value - open_value
|
47
|
+
change_overnight = open_value - previous_close
|
48
|
+
|
49
|
+
change_percent = change_from_previous_close / previous_close
|
50
|
+
|
51
|
+
stats.add(weekday, change_percent)
|
52
|
+
stats.add("#{weekday} prev close", change_from_previous_close)
|
53
|
+
stats.add("#{weekday} intraday", change_intraday)
|
54
|
+
stats.add("#{weekday} overnight", change_overnight)
|
55
|
+
|
56
|
+
previous_close = close_value
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
stats
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
class StocksDisplay < Widget
|
66
|
+
|
67
|
+
def initialize(stats)
|
68
|
+
super(0, 0, 800, 600)
|
69
|
+
set_layout(LAYOUT_TOP_MIDDLE_BOTTOM)
|
70
|
+
|
71
|
+
image = get_layout.add_image("./media/Banner.png", { ARG_SECTION => SECTION_TOP})
|
72
|
+
image.add_text("Wads Sample App", 10, 20, nil, true)
|
73
|
+
image.add_text("Version #{Wads::VERSION}", 13, 54)
|
74
|
+
|
75
|
+
get_layout.add_document(sample_content, { ARG_SECTION => SECTION_CENTER})
|
76
|
+
|
77
|
+
panel = get_layout.add_horizontal_panel({ ARG_SECTION => SECTION_BOTTOM})
|
78
|
+
panel.add_button("Exit", 0, panel.height - 30) do
|
79
|
+
WidgetResult.new(true)
|
80
|
+
end
|
81
|
+
panel.center_children
|
82
|
+
|
83
|
+
@data_table = get_layout.add_single_select_table(
|
84
|
+
["Day", "Min", "Avg", "StdDev", "Max", "p10", "p90"], 5,
|
85
|
+
{ ARG_SECTION => SECTION_CENTER})
|
86
|
+
Date::DAYNAMES[1..5].each do |day|
|
87
|
+
min = format_percent(stats.min(day))
|
88
|
+
avg = format_percent(stats.average(day))
|
89
|
+
std = format_percent(stats.std_dev(day))
|
90
|
+
max = format_percent(stats.max(day))
|
91
|
+
p10 = format_percent(stats.percentile(day, 0.1))
|
92
|
+
p90 = format_percent(stats.percentile(day, 0.90))
|
93
|
+
@data_table.add_row([day, min, avg, std, max, p10, p90])
|
94
|
+
end
|
95
|
+
|
96
|
+
@selection_text = nil
|
97
|
+
end
|
98
|
+
|
99
|
+
def format_percent(val)
|
100
|
+
"#{(val * 100).round(3)}%"
|
101
|
+
end
|
102
|
+
|
103
|
+
def sample_content
|
104
|
+
<<~HEREDOC
|
105
|
+
This sample stock analysis uses NASDAQ data from https://finance.yahoo.com looking
|
106
|
+
at closing data through the years 2000 to 2020. The percent gain or loss is broken
|
107
|
+
down per day, as shown in the table below.
|
108
|
+
HEREDOC
|
109
|
+
end
|
110
|
+
|
111
|
+
def render
|
112
|
+
@selection_text.draw unless @selection_text.nil?
|
113
|
+
end
|
114
|
+
|
115
|
+
def handle_mouse_down mouse_x, mouse_y
|
116
|
+
if @data_table.contains_click(mouse_x, mouse_y)
|
117
|
+
val = @data_table.set_selected_row(mouse_y, 0)
|
118
|
+
if not val.nil?
|
119
|
+
@selection_text = Text.new(relative_x(5), relative_y(500), "You selected #{val}, a great day!")
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
WadsConfig.instance.set_current_theme(WadsBrightTheme.new)
|
126
|
+
SampleStocksApp.new.show
|
@@ -0,0 +1,256 @@
|
|
1
|
+
require 'gosu'
|
2
|
+
require_relative '../lib/wads'
|
3
|
+
|
4
|
+
include Wads
|
5
|
+
|
6
|
+
class ThemeTestApp < WadsApp
|
7
|
+
def initialize
|
8
|
+
super(800, 600, "Wads Theme Test App", ThemeTestDisplay.new)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class ThemeTestDisplay < Widget
|
13
|
+
def initialize
|
14
|
+
super(0, 0, 800, 600)
|
15
|
+
disable_border
|
16
|
+
|
17
|
+
if ARGV.length == 0
|
18
|
+
render_basic_widgets
|
19
|
+
elsif ARGV[0] == "-h" or ARGV[0] == "h" or ARGV[0] == "help"
|
20
|
+
puts "Wads Theme Tester"
|
21
|
+
puts " "
|
22
|
+
display_help
|
23
|
+
elsif ARGV[0] == "border"
|
24
|
+
render_border_layout
|
25
|
+
elsif ARGV[0] == "three"
|
26
|
+
render_top_middle_bottom_layout
|
27
|
+
elsif ARGV[0] == "header"
|
28
|
+
render_header_layout
|
29
|
+
elsif ARGV[0] == "footer"
|
30
|
+
render_footer_layout
|
31
|
+
elsif ARGV[0] == "vertical"
|
32
|
+
render_vertical_layout
|
33
|
+
elsif ARGV[0] == "horizontal"
|
34
|
+
render_horizontal_layout
|
35
|
+
elsif ARGV[0] == "eastwest"
|
36
|
+
render_east_west_layout
|
37
|
+
elsif ARGV[0] == "plot"
|
38
|
+
render_plot
|
39
|
+
elsif ARGV[0] == "form"
|
40
|
+
render_form
|
41
|
+
elsif ARGV[0] == "overlay"
|
42
|
+
render_overlay
|
43
|
+
else
|
44
|
+
puts "Argument #{ARGV[0]} is invalid."
|
45
|
+
display_help
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def display_help
|
50
|
+
puts "Valid arguments are:"
|
51
|
+
puts " border show BorderLayout"
|
52
|
+
puts " three show TopMiddleBottomLayout"
|
53
|
+
puts " header show HeaderContentLayout"
|
54
|
+
puts " footer show ContentFooterLayout"
|
55
|
+
puts " vertical show VerticalColumnLayout"
|
56
|
+
puts " eastwest show EastWestLayout"
|
57
|
+
puts " plot show a simple plot using HeaderContentLayout"
|
58
|
+
puts " form test a form"
|
59
|
+
puts " overlay show an overlay widget"
|
60
|
+
exit
|
61
|
+
end
|
62
|
+
|
63
|
+
def render_basic_widgets
|
64
|
+
set_layout(LAYOUT_TOP_MIDDLE_BOTTOM)
|
65
|
+
|
66
|
+
# Example of using the layout for absolute positioning
|
67
|
+
# and then relative positioning of a child widget
|
68
|
+
# within that
|
69
|
+
image = get_layout.add_image("./media/Banner.png", { ARG_SECTION => SECTION_TOP})
|
70
|
+
image.add_text("Banner", 10, 10)
|
71
|
+
|
72
|
+
get_layout.add_text("Hello", { ARG_SECTION => SECTION_CENTER})
|
73
|
+
get_layout.add_text("There", { ARG_SECTION => SECTION_CENTER})
|
74
|
+
get_layout.add_button("Test Button", { ARG_SECTION => SECTION_CENTER}) do
|
75
|
+
puts "User hit the test button"
|
76
|
+
end
|
77
|
+
|
78
|
+
table = get_layout.add_multi_select_table(["A", "B", "C"], 4, { ARG_SECTION => SECTION_CENTER})
|
79
|
+
table.add_row(["These", "are", "values in row 1"])
|
80
|
+
table.add_row(["These", "are", "values in row 2"])
|
81
|
+
table.add_row(["These", "are", "values in row 3"])
|
82
|
+
table.add_row(["These", "are", "values in row 4"])
|
83
|
+
|
84
|
+
panel = get_layout.add_horizontal_panel({ ARG_SECTION => SECTION_BOTTOM})
|
85
|
+
panel.add_button("Exit", 380, panel.height - 30) do
|
86
|
+
WidgetResult.new(true)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def render_header_layout
|
91
|
+
set_layout(LAYOUT_HEADER_CONTENT)
|
92
|
+
|
93
|
+
header = get_layout.add_max_panel({ ARG_SECTION => SECTION_HEADER,
|
94
|
+
ARG_THEME => WadsNatureTheme.new })
|
95
|
+
header.get_layout.add_text("I am the header section",
|
96
|
+
{ ARG_TEXT_ALIGN => TEXT_ALIGN_CENTER,
|
97
|
+
ARG_USE_LARGE_FONT => true})
|
98
|
+
|
99
|
+
main = get_layout.add_max_panel({ ARG_SECTION => SECTION_CONTENT,
|
100
|
+
ARG_THEME => WadsNatureTheme.new })
|
101
|
+
main.get_layout.add_document(sample_content)
|
102
|
+
table = main.get_layout.add_multi_select_table(["A", "B", "C"], 4, { ARG_SECTION => SECTION_WEST})
|
103
|
+
table.add_row(["Key1", "Value1", "ValueD"])
|
104
|
+
table.add_row(["Key2", "Value2", "ValueE"])
|
105
|
+
table.add_row(["Key3", "Value3", "ValueF"])
|
106
|
+
end
|
107
|
+
|
108
|
+
def render_border_layout
|
109
|
+
set_layout(LAYOUT_BORDER)
|
110
|
+
header = get_layout.add_max_panel({ ARG_SECTION => SECTION_NORTH})
|
111
|
+
header.get_layout.add_text("I am the header section", { ARG_TEXT_ALIGN => TEXT_ALIGN_CENTER})
|
112
|
+
|
113
|
+
west = get_layout.add_vertical_panel({ ARG_SECTION => SECTION_WEST})
|
114
|
+
west.get_layout.add_button("Do stuff") do
|
115
|
+
puts "Hit the do stuff button"
|
116
|
+
end
|
117
|
+
west.get_layout.add_button("More stuff") do
|
118
|
+
puts "Hit the more stuff button"
|
119
|
+
end
|
120
|
+
|
121
|
+
get_layout.add_document(sample_content, { ARG_SECTION => SECTION_CENTER})
|
122
|
+
|
123
|
+
east = get_layout.add_vertical_panel({ ARG_SECTION => SECTION_EAST})
|
124
|
+
east.get_layout.add_text("item1")
|
125
|
+
east.get_layout.add_text("item2")
|
126
|
+
|
127
|
+
footer = get_layout.add_max_panel({ ARG_SECTION => SECTION_SOUTH})
|
128
|
+
footer.get_layout.add_text("I am the footer section", { ARG_TEXT_ALIGN => TEXT_ALIGN_CENTER})
|
129
|
+
end
|
130
|
+
|
131
|
+
def render_top_middle_bottom_layout
|
132
|
+
set_layout(LAYOUT_TOP_MIDDLE_BOTTOM)
|
133
|
+
header = get_layout.add_max_panel({ ARG_SECTION => SECTION_TOP})
|
134
|
+
header.get_layout.add_text("I am the header section", { ARG_TEXT_ALIGN => TEXT_ALIGN_CENTER})
|
135
|
+
|
136
|
+
get_layout.add_document(sample_content, { ARG_SECTION => SECTION_MIDDLE})
|
137
|
+
|
138
|
+
footer = get_layout.add_max_panel({ ARG_SECTION => SECTION_BOTTOM})
|
139
|
+
footer.get_layout.add_text("I am the footer section", { ARG_TEXT_ALIGN => TEXT_ALIGN_CENTER})
|
140
|
+
end
|
141
|
+
|
142
|
+
def sample_content
|
143
|
+
<<~HEREDOC
|
144
|
+
This is the content section.
|
145
|
+
A document can contain multi-line text.
|
146
|
+
Typically you provide the content
|
147
|
+
using a squiggly heredoc.
|
148
|
+
HEREDOC
|
149
|
+
end
|
150
|
+
|
151
|
+
def render_footer_layout
|
152
|
+
set_layout(LAYOUT_CONTENT_FOOTER)
|
153
|
+
|
154
|
+
get_layout.add_document(sample_content, { ARG_SECTION => SECTION_CONTENT})
|
155
|
+
|
156
|
+
footer = get_layout.add_max_panel({ ARG_SECTION => SECTION_FOOTER,
|
157
|
+
ARG_THEME => WadsBrightTheme.new })
|
158
|
+
footer.get_layout.add_text("I am the footer section", { ARG_TEXT_ALIGN => TEXT_ALIGN_CENTER})
|
159
|
+
end
|
160
|
+
|
161
|
+
def render_vertical_layout
|
162
|
+
set_layout(LAYOUT_VERTICAL_COLUMN)
|
163
|
+
get_layout.add_image("./media/Banner.png")
|
164
|
+
get_layout.add_text("This is text below the image")
|
165
|
+
get_layout.add_text("Each widget will get placed below the previous in a vertical column.")
|
166
|
+
end
|
167
|
+
|
168
|
+
def render_east_west_layout
|
169
|
+
set_layout(LAYOUT_EAST_WEST)
|
170
|
+
table = get_layout.add_multi_select_table(["A", "B", ""], 4, { ARG_SECTION => SECTION_WEST})
|
171
|
+
table.add_row(["Key1", "Value1"])
|
172
|
+
table.add_row(["Key2", "Value2"])
|
173
|
+
table.add_row(["Key3", "Value3"])
|
174
|
+
|
175
|
+
get_layout.add_document(sample_content, { ARG_SECTION => SECTION_EAST})
|
176
|
+
end
|
177
|
+
|
178
|
+
def render_plot
|
179
|
+
set_layout(LAYOUT_HEADER_CONTENT)
|
180
|
+
|
181
|
+
header = get_layout.add_max_panel({ ARG_SECTION => SECTION_HEADER,
|
182
|
+
ARG_THEME => WadsBrightTheme.new })
|
183
|
+
# The zero x coord doesn't matter here because we center it below
|
184
|
+
# Centering only adjusts the x coordinate
|
185
|
+
header.add_text("This is a plot of sine (yellow) and cosine (pink) waves", 0, 35)
|
186
|
+
header.center_children
|
187
|
+
header.disable_border
|
188
|
+
|
189
|
+
plot = get_layout.add_plot({ ARG_SECTION => SECTION_CONTENT})
|
190
|
+
plot.define_range(VisibleRange.new(-5, 5, -5, 5))
|
191
|
+
plot.enable_border
|
192
|
+
x = -5
|
193
|
+
while x < 5
|
194
|
+
plot.add_data_point("Sine", x, Math.sin(x), COLOR_LIME)
|
195
|
+
plot.add_data_point("Cosine", x, Math.cos(x), COLOR_PINK)
|
196
|
+
x = x + 0.05
|
197
|
+
end
|
198
|
+
|
199
|
+
# Draw the 0 horizontal and vertical axes
|
200
|
+
plot.add_child(Line.new(plot.draw_x(0), plot.draw_y(-5), plot.draw_x(0), plot.draw_y(5), COLOR_GRAY))
|
201
|
+
plot.add_child(Line.new(plot.draw_x(-5), plot.draw_y(0), plot.draw_x(5), plot.draw_y(0), COLOR_GRAY))
|
202
|
+
end
|
203
|
+
|
204
|
+
def render_form
|
205
|
+
set_layout(LAYOUT_CONTENT_FOOTER)
|
206
|
+
|
207
|
+
content_panel = get_layout.add_max_panel({ ARG_SECTION => SECTION_CONTENT,
|
208
|
+
ARG_LAYOUT => LAYOUT_EAST_WEST,
|
209
|
+
ARG_PANEL_WIDTH => 200 })
|
210
|
+
|
211
|
+
label_panel = content_panel.add_panel(SECTION_WEST)
|
212
|
+
label_panel.get_layout.add_text("First Name", { ARG_TEXT_ALIGN => TEXT_ALIGN_RIGHT})
|
213
|
+
label_panel.get_layout.add_text("Middle Name", { ARG_TEXT_ALIGN => TEXT_ALIGN_RIGHT})
|
214
|
+
label_panel.get_layout.add_text("Last Name", { ARG_TEXT_ALIGN => TEXT_ALIGN_RIGHT})
|
215
|
+
|
216
|
+
field_panel = content_panel.add_panel(SECTION_EAST)
|
217
|
+
@first_name = field_panel.get_layout.add_text_input(200)
|
218
|
+
@middle_name = field_panel.get_layout.add_text_input(200)
|
219
|
+
@last_name = field_panel.get_layout.add_text_input(200)
|
220
|
+
|
221
|
+
footer_panel = get_layout.add_max_panel({ ARG_SECTION => SECTION_FOOTER})
|
222
|
+
footer_panel.get_layout.add_button("Display Full Name", {ARG_TEXT_ALIGN => TEXT_ALIGN_CENTER}) do
|
223
|
+
footer_panel.get_layout.add_text("The full name is #{@first_name.text} #{@middle_name.text} #{@last_name.text}.")
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
def render_overlay
|
228
|
+
set_layout(LAYOUT_HEADER_CONTENT)
|
229
|
+
|
230
|
+
header = get_layout.add_max_panel({ ARG_SECTION => SECTION_HEADER})
|
231
|
+
header.get_layout.add_text("I am the header section", { ARG_TEXT_ALIGN => TEXT_ALIGN_CENTER})
|
232
|
+
|
233
|
+
main = get_layout.add_max_panel({ ARG_SECTION => SECTION_CONTENT})
|
234
|
+
main.get_layout.add_document(sample_content)
|
235
|
+
|
236
|
+
main.get_layout.add_button("Display InfoBox", {ARG_TEXT_ALIGN => TEXT_ALIGN_CENTER}) do
|
237
|
+
add_overlay(create_overlay_widget)
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
def create_overlay_widget
|
242
|
+
InfoBox.new(100, 60, 600, 400, "Sample Overlay", overlay_content, { ARG_THEME => WadsBrightTheme.new})
|
243
|
+
end
|
244
|
+
|
245
|
+
def overlay_content
|
246
|
+
<<~HEREDOC
|
247
|
+
This is a sample overlay widget which typically
|
248
|
+
you would use to display important information
|
249
|
+
upon request. The InfoBox widget is used for
|
250
|
+
this purpose.
|
251
|
+
HEREDOC
|
252
|
+
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
ThemeTestApp.new.show
|