wads 0.1.2 → 0.2.2
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 +42 -0
- data/data/sample_graph.csv +11 -0
- data/lib/wads/app.rb +53 -320
- data/lib/wads/data_structures.rb +248 -18
- data/lib/wads/textinput.rb +20 -14
- data/lib/wads/version.rb +1 -1
- data/lib/wads/widgets.rb +2165 -216
- 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/GreenLight.png +0 -0
- data/media/RedLight.png +0 -0
- data/media/SampleGraph.png +0 -0
- data/media/StocksSample.png +0 -0
- data/media/WadsScreenshot.png +0 -0
- data/media/YellowLight.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/gosu_bouncing_ball.rb +34 -0
- data/samples/gosu_hello_world.rb +16 -0
- data/samples/gosu_reaction_time.rb +121 -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
- data/samples/wads_reaction_time.rb +117 -0
- metadata +31 -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
|
Binary file
|
data/media/RedLight.png
ADDED
Binary file
|
Binary file
|
Binary file
|
data/media/WadsScreenshot.png
CHANGED
Binary file
|
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
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'gosu'
|
2
|
+
|
3
|
+
class AppWindow < Gosu::Window
|
4
|
+
def initialize
|
5
|
+
super(800, 600)
|
6
|
+
self.caption = 'Bouncing Ball'
|
7
|
+
@img = Gosu::Image.new("media/CircleYellow.png")
|
8
|
+
@x = 400
|
9
|
+
@y = 300
|
10
|
+
@delta_x = 2
|
11
|
+
@delta_y = 2
|
12
|
+
end
|
13
|
+
|
14
|
+
def update
|
15
|
+
@x = @x + @delta_x
|
16
|
+
@y = @y + @delta_y
|
17
|
+
if @x < 0
|
18
|
+
@delta_x = 2
|
19
|
+
elsif @x > 800 - @img.width
|
20
|
+
@delta_x = -2
|
21
|
+
end
|
22
|
+
if @y < 0
|
23
|
+
@delta_y = 2
|
24
|
+
elsif @y > 600 - @img.height
|
25
|
+
@delta_y = -2
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def draw
|
30
|
+
@img.draw @x, @y, 1
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
AppWindow.new.show
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'gosu'
|
2
|
+
|
3
|
+
class GameWindow < Gosu::Window
|
4
|
+
def initialize
|
5
|
+
super(400, 300)
|
6
|
+
self.caption = 'Hello World App'
|
7
|
+
@font = Gosu::Font.new(24)
|
8
|
+
end
|
9
|
+
|
10
|
+
def draw
|
11
|
+
@font.draw_text("Hello World", 144, 120, 1)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
window = GameWindow.new
|
16
|
+
window.show
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require 'gosu'
|
2
|
+
|
3
|
+
AVERAGE_RESPONSE_TIME = 284.to_f # Per humanbenchmark.com, in milliseconds
|
4
|
+
GAME_STATE_PROMPT_TO_START = 0
|
5
|
+
GAME_STATE_RED = 1
|
6
|
+
GAME_STATE_YELLOW = 2
|
7
|
+
GAME_STATE_GREEN = 3
|
8
|
+
GAME_STATE_OVER = 4
|
9
|
+
|
10
|
+
class AppWindow < Gosu::Window
|
11
|
+
def initialize
|
12
|
+
super(600, 300)
|
13
|
+
self.caption = 'Reaction Time Game'
|
14
|
+
@update_count = 0
|
15
|
+
@next_light_count = 0
|
16
|
+
@messages = []
|
17
|
+
@font = Gosu::Font.new(32)
|
18
|
+
@red_light = Gosu::Image.new("media/CircleRed.png")
|
19
|
+
@yellow_light = Gosu::Image.new("media/CircleYellow.png")
|
20
|
+
@green_light = Gosu::Image.new("media/CircleGreen.png")
|
21
|
+
# game state 0 1 2 3 4
|
22
|
+
# state Prompt Red Yellow Green Game over
|
23
|
+
@traffic_light_images = [@red_light, @red_light, @yellow_light, @green_light, @green_light]
|
24
|
+
@traffic_light_color = GAME_STATE_PROMPT_TO_START
|
25
|
+
end
|
26
|
+
|
27
|
+
def update
|
28
|
+
@update_count = @update_count + 1
|
29
|
+
@traffic_light_image = @traffic_light_images[@traffic_light_color]
|
30
|
+
|
31
|
+
# Once the game is started, the lights progress automatically until green
|
32
|
+
if @traffic_light_color > GAME_STATE_PROMPT_TO_START
|
33
|
+
next_traffic_light unless @update_count < @next_light_count
|
34
|
+
@button_text = "Click when the light turns green" unless @traffic_light_color > GAME_STATE_GREEN
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def draw
|
39
|
+
@font.draw_text("Reaction Time Game", 180, 10, 1)
|
40
|
+
@traffic_light_image.draw(248, 60, 1)
|
41
|
+
|
42
|
+
if @traffic_light_color == GAME_STATE_PROMPT_TO_START
|
43
|
+
@font.draw_text("Press 'p' to play", 200, 200, 1)
|
44
|
+
elsif @traffic_light_color == GAME_STATE_OVER
|
45
|
+
@font.draw_text("Press 'p' to play again", 50, 200, 1)
|
46
|
+
else
|
47
|
+
draw_button(@button_text) unless @button_text.nil?
|
48
|
+
end
|
49
|
+
|
50
|
+
y = 232
|
51
|
+
@messages.each do |msg|
|
52
|
+
@font.draw_text(msg, 50, y, 1)
|
53
|
+
y = y + 32
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def button_down id
|
58
|
+
close if id == Gosu::KbEscape
|
59
|
+
|
60
|
+
if @traffic_light_color == GAME_STATE_PROMPT_TO_START or @traffic_light_color == GAME_STATE_OVER
|
61
|
+
if id == Gosu::KbP
|
62
|
+
next_traffic_light
|
63
|
+
end
|
64
|
+
return
|
65
|
+
end
|
66
|
+
|
67
|
+
if id == Gosu::MsLeft and button_contains_click
|
68
|
+
if @traffic_light_color < GAME_STATE_YELLOW
|
69
|
+
next_traffic_light
|
70
|
+
elsif @traffic_light_color == GAME_STATE_YELLOW
|
71
|
+
@traffic_light_color = GAME_STATE_OVER
|
72
|
+
@messages = ["Sorry, you were too early"]
|
73
|
+
@button_text = "Click to play again"
|
74
|
+
elsif @traffic_light_color == GAME_STATE_GREEN
|
75
|
+
@button_text = nil
|
76
|
+
time_since_green = ((Time.now - @mark_time) * 1000.to_f).round(3)
|
77
|
+
@messages = ["Response time: #{time_since_green} ms"]
|
78
|
+
diff_from_average = (((time_since_green - AVERAGE_RESPONSE_TIME) / AVERAGE_RESPONSE_TIME) * 100).round
|
79
|
+
if diff_from_average > 0
|
80
|
+
@messages << "#{diff_from_average}% slower than the average human"
|
81
|
+
elsif diff_from_average < 0
|
82
|
+
@messages << "#{-diff_from_average}% faster than the average human"
|
83
|
+
else
|
84
|
+
@messages << "Wow, that is exactly the human average."
|
85
|
+
end
|
86
|
+
@button_text = "Click to play again"
|
87
|
+
@traffic_light_color = GAME_STATE_OVER
|
88
|
+
else
|
89
|
+
@traffic_light_color = GAME_STATE_PROMPT_TO_START
|
90
|
+
@messages = []
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def next_traffic_light
|
96
|
+
return unless @traffic_light_color < GAME_STATE_GREEN
|
97
|
+
@traffic_light_color = @traffic_light_color + 1
|
98
|
+
@mark_time = Time.now
|
99
|
+
@next_light_count = @update_count + 60 + rand(100)
|
100
|
+
end
|
101
|
+
|
102
|
+
def button_contains_click
|
103
|
+
mouse_x > 100 and mouse_x < 500 and mouse_y > 198 and mouse_y < 232
|
104
|
+
end
|
105
|
+
|
106
|
+
def draw_button(text)
|
107
|
+
text_width = @font.text_width(text)
|
108
|
+
draw_box(100, 198, 500, 232)
|
109
|
+
text_x = (600 - text_width) / 2
|
110
|
+
@font.draw_text(@button_text, text_x, 200, 1)
|
111
|
+
end
|
112
|
+
|
113
|
+
def draw_box(x1, y1, x2, y2, color = Gosu::Color::WHITE)
|
114
|
+
Gosu::draw_line x1, y1, color, x2, y1, color, 1
|
115
|
+
Gosu::draw_line x1, y1, color, x1, y2, color, 1
|
116
|
+
Gosu::draw_line x1, y2, color, x2, y2, color, 1
|
117
|
+
Gosu::draw_line x2, y1, color, x2, y2, color, 1
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
AppWindow.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(WadsAquaTheme.new)
|
126
|
+
SampleStocksApp.new.show
|