wads 0.1.0 → 0.2.0

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.
data/lib/wads.rb CHANGED
@@ -4,4 +4,4 @@ require_relative "wads/version"
4
4
  require_relative "wads/data_structures"
5
5
  require_relative "wads/widgets"
6
6
  require_relative "wads/textinput"
7
-
7
+ require_relative "wads/app"
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
data/run-graph ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env bash
2
+
3
+ ruby samples/graph.rb
data/run-star-wars ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env bash
2
+
3
+ ruby samples/star_wars.rb
data/run-stocks ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env bash
2
+
3
+ ruby samples/stocks.rb
data/run-theme-test ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env bash
2
+
3
+ ruby samples/theme_test.rb $1 $2 $3
@@ -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