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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 14aff80a445145535994cd93357eae0a5ed6b3b5ae31c722ab043e92857dc645
4
- data.tar.gz: 5cbcc5dea862306c0d9e572f8781b78f1da32e77947f130ef49670ff3f9ef8fd
3
+ metadata.gz: a1cf7ab7c4229f57f2bb4691819c5a4282a3fd0f7703e5caa6c93e49aeb35053
4
+ data.tar.gz: a1f0e971db1ea5064e44fef39c31767125f844b8ab3ef87eeaf09e3e92f27ad1
5
5
  SHA512:
6
- metadata.gz: 1e43b86028c31695ecee423d4cda06a59e09386f55cd08507058443373541f2dd2914dae44d0f6c5d2937688546b37986f0c7cc66f7ae4f24d749d4457e390f3
7
- data.tar.gz: 954a9e628886be15e7e91cdf3a7522c845480e48b49cd0c01666d91fb695f6885c06775933d1f36ff64ce3db75e508a2f2d37e20b8067fa8dce442dead4aa32d
6
+ metadata.gz: 315790b3c8fe99525c3ad78eaa90eecd17fadd09a2a3e16a13ba82cb61ea5279472c57ada6e88021e9c6649236bb598aad0a46a1954928a1c37dc8dbf8b45b5e
7
+ data.tar.gz: 89de4f997dcef2e1b9e25062af443d6994d7ee4070d89dab21f06cb492ed3d106f837a9c3bdf85d7ba7e6522d30a039694982d939d49dd41b7da30c2637299ea
data/CHANGELOG.md CHANGED
@@ -10,3 +10,10 @@
10
10
 
11
11
  - Fixed bugs with data structures. Added convenience methods to manage child widgets
12
12
 
13
+ ## [0.1.3] - 2021-09-30
14
+
15
+ - Improvements to graph display including user ability to change focus node
16
+
17
+ ## [0.2.0] - 2021-10-05
18
+
19
+ - Breaking change in order to refactor, including standardizing order of widget constructor args
data/README.md CHANGED
@@ -2,6 +2,17 @@
2
2
 
3
3
  A number of Ruby Gosu-based (W)idgets (a)nd (D)ata (S)tructures for your applications.
4
4
 
5
+ The user guide and examples can be found at https://www.rubydoesitagain.com
6
+
7
+ Wads (Widgets and Data Structures) is intended to help you quickly build native Ruby applications using the Gosu gem.
8
+ GUI widgets, such as tables and buttons, are provided to simplify building graphical applications.
9
+ Widgets in wads can be used independently within your Gosu app, or you can use wads as a holistic GUI framework.
10
+ Wads includes basic features found in many GUI toolkits including The use of themes and a layout manager.
11
+
12
+ One of the motivations for creating wads is to making data analysis, games, and productivity applications using Ruby easier to do.
13
+ Data structures are included that can be used for statistical analysis or graph-based applications.
14
+ The samples provided illustrate both use cases (Stocks - stats) and Star Wars character interactions (graphs).
15
+
5
16
  ![alt Screenshot](https://github.com/dbroemme/ruby-wads/blob/main/media/WadsScreenshot.png?raw=true)
6
17
  ## Installation
7
18
 
@@ -0,0 +1,11 @@
1
+ N,A,color=COLOR_YELLOW
2
+ N,B,color=COLOR_GREEN
3
+ N,C,color=COLOR_BLUE
4
+ N,D,color=COLOR_RED
5
+ N,E,color=COLOR_PURPLE
6
+ N,F,color=COLOR_GRAY
7
+ C,A,B
8
+ C,A,C
9
+ C,B,D
10
+ C,B,E
11
+ C,E,F
data/lib/wads/app.rb CHANGED
@@ -1,349 +1,57 @@
1
1
  require 'gosu'
2
- require 'json'
3
- require_relative 'data_structures'
4
2
  require_relative 'widgets'
5
- require_relative 'version'
6
3
 
7
- include Wads
8
-
9
- class WadsSampleApp < Gosu::Window
10
-
11
- STOCKS_DATA_FILE = "./data/NASDAQ.csv"
12
- LOTTERY_DATA_FILE = "./data/Pick4_12_21_2020.txt"
13
- STAR_WARS_DATA_FILE = "./data/starwars-episode-4-interactions.json"
14
-
15
- def initialize
16
- super(800, 600)
17
- self.caption = "Wads Sample App"
18
- @font = Gosu::Font.new(32)
19
- @title_font = Gosu::Font.new(38)
20
- @version_font = Gosu::Font.new(22)
21
- @small_font = Gosu::Font.new(22)
22
- @banner_image = Gosu::Image.new("./media/Banner.png")
23
- @display_widget = nil
24
- @update_count = 0
25
- end
4
+ module 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 WadsApp < Gosu::Window
12
+ def initialize(width, height, caption, widget)
13
+ super(width, height)
14
+ self.caption = caption
15
+ @update_count = 0
16
+ WadsConfig.instance.set_window(self)
17
+ set_display(widget)
18
+ WadsConfig.instance.set_log_level("info")
19
+ end
26
20
 
27
- def parse_opts_and_run
28
- # Make help the default output if no args are specified
29
- if ARGV.length == 0
30
- ARGV[0] = "-h"
21
+ #
22
+ # This method must be invoked with any Wads::Widget instance. It then handles
23
+ # delegating all events and drawing all child widgets.
24
+ #
25
+ def set_display(widget)
26
+ @main_widget = widget
31
27
  end
32
28
 
33
- opts = SampleAppCommand.new.parse.run
34
- if opts[:stocks]
35
- stats = process_stock_data
36
- if opts[:text]
37
- stats.report(Date::DAYNAMES[1..5])
38
- else
39
- @display_widget = SampleStocksDisplay.new(@small_font, stats)
40
- show
41
- end
42
-
43
- elsif opts[:jedi]
44
- graph = process_star_wars_data
45
- @display_widget = SampleStarWarsDisplay.new(@small_font, graph)
46
- show
47
-
48
- elsif opts[:lottery]
49
- process_lottery_data
50
-
51
- elsif opts[:graph]
52
- graph = create_test_graph #_using_nodes
53
- if not opts[:text]
54
- @display_widget = SampleGraphDisplay.new(@small_font, graph)
55
- show
56
- end
57
- else
58
- puts " "
59
- puts "Select one of the following sample analysis options"
60
- puts "-s Run sample stocks analysis"
61
- puts "-j Run sample Star Wars character analysis"
62
- puts "-g Run sample graph display"
63
- puts " "
64
- exit
29
+ def get_display
30
+ @main_widget
65
31
  end
66
32
 
67
- end
68
-
69
- def update
70
- @display_widget.update(@update_count, mouse_x, mouse_y)
71
- @update_count = @update_count + 1
72
- end
33
+ def update
34
+ @main_widget.update(@update_count, mouse_x, mouse_y)
35
+ @update_count = @update_count + 1
36
+ end
73
37
 
74
- def draw
75
- draw_banner
76
- @display_widget.draw
77
- end
78
-
79
- def draw_banner
80
- @banner_image.draw(1,1,1,0.9,0.9)
81
- @title_font.draw_text("Wads Sample App", 10, 20, 2, 1, 1, Gosu::Color::WHITE)
82
- @version_font.draw_text("Version #{Wads::VERSION}", 13, 54, 2, 1, 1, Gosu::Color::WHITE)
83
- end
84
-
85
- def button_down id
86
- close if id == Gosu::KbEscape
87
- # Delegate button events to the primary display widget
88
- result = @display_widget.button_down id, mouse_x, mouse_y
89
- if not result.nil? and result.is_a? WidgetResult
90
- if result.close_widget
91
- close
92
- end
38
+ def draw
39
+ @main_widget.draw
93
40
  end
94
- end
95
-
96
- def button_up id
97
- @display_widget.button_up id, mouse_x, mouse_y
98
- end
99
-
100
- def process_stock_data
101
- # The data file comes from https://finance.yahoo.com
102
- # The format of this file is as follows:
103
- #
104
- # Date,Open,High,Low,Close,Adj Close,Volume
105
- # 2000-01-03,4186.189941,4192.189941,3989.709961,4131.149902,4131.149902,1510070000
106
- # 2000-01-04,4020.000000,4073.250000,3898.229980,3901.689941,3901.689941,1511840000
107
- # ...
108
- # 2020-12-30,12906.509766,12924.929688,12857.759766,12870.000000,12870.000000,5292210000
109
- # 2020-12-31,12877.089844,12902.070313,12821.230469,12888.280273,12888.280273,4771390000
110
-
111
- stats = Stats.new("NASDAQ")
112
- previous_close = nil
113
-
114
- puts "Read the data file #{STOCKS_DATA_FILE}"
115
- File.readlines(STOCKS_DATA_FILE).each do |line|
116
- line = line.chomp # remove the carriage return
117
-
118
- # Ignore header and any empty lines, process numeric data lines
119
- if line.length > 0 and line[0].match(/[0-9]/)
120
- values = line.split(",")
121
- date = Date.strptime(values[0], "%Y-%m-%d")
122
- weekday = Date::DAYNAMES[date.wday]
123
-
124
- open_value = values[1].to_f
125
- close_value = values[4].to_f
126
-
127
- if previous_close.nil?
128
- # Just use the first day to set the baseline
129
- previous_close = close_value
130
- else
131
- change_from_previous_close = close_value - previous_close
132
- change_intraday = close_value - open_value
133
- change_overnight = open_value - previous_close
134
-
135
- change_percent = change_from_previous_close / previous_close
136
-
137
- stats.add(weekday, change_percent)
138
- stats.add("#{weekday} prev close", change_from_previous_close)
139
- stats.add("#{weekday} intraday", change_intraday)
140
- stats.add("#{weekday} overnight", change_overnight)
141
41
 
142
- previous_close = close_value
42
+ def button_down id
43
+ close if id == Gosu::KbEscape
44
+ # Delegate button events to the primary display widget
45
+ result = @main_widget.button_down id, mouse_x, mouse_y
46
+ if not result.nil? and result.is_a? WidgetResult
47
+ if result.close_widget
48
+ close
143
49
  end
144
50
  end
145
51
  end
146
-
147
- stats
148
- end
149
-
150
- def process_lottery_data
151
- puts "The lottery example has not been implemented yet"
152
- puts "however the data is available in the data directory,"
153
- puts "and the same pattern used in the stocks example can"
154
- puts "be applied here."
155
- end
156
-
157
- def process_star_wars_data
158
- star_wars_json = File.read(STAR_WARS_DATA_FILE)
159
- data_hash = JSON.parse(star_wars_json)
160
- characters = data_hash['nodes']
161
- interactions = data_hash['links']
162
-
163
- # The interactions in the data set reference the characters by their
164
- # zero based index, so we keep a reference in our graph by index.
165
- # The character's value is the number of scenes in which they appear.
166
- graph = Graph.new
167
- characters.each do |character|
168
- node_tags = {}
169
- node_color_str = character['colour']
170
- # This is a bit of a hack, but our background is black so black text
171
- # will not show up. Change this to white
172
- if node_color_str == "#000000"
173
- node_color_str = "#FFFFFF"
174
- end
175
- # Convert hex string (ex. "#EE00AA") into int hex representation
176
- # understood by Gosu color (ex. 0xFFEE00AA)
177
- node_color = "0xFF#{node_color_str[1..-1]}".to_i(16)
178
- node_tags['color'] = node_color
179
- graph.add_node(Node.new(character['name'], character['value'], node_tags))
180
- end
181
- interactions.each do |interaction|
182
- character_one = graph.node_by_index(interaction['source'])
183
- character_two = graph.node_by_index(interaction['target'])
184
- number_of_scenes_together = interaction['value']
185
- edge_tags = {}
186
- edge_tags["scenes"] = number_of_scenes_together
187
- graph.add_edge(character_one, character_two, edge_tags)
188
- end
189
- graph
190
- end
191
-
192
- def create_test_graph
193
- g = Graph.new
194
- g.add("a")
195
- g.add("b")
196
- g.add("c")
197
- g.add("d")
198
- g.add("e")
199
- g.add("f")
200
- g.connect("a", "b")
201
- g.connect("a", "c")
202
- g.connect("b", "d")
203
- g.connect("b", "e")
204
- g.connect("e", "f")
205
- g
206
- end
207
-
208
- def create_test_graph_using_nodes
209
- root = Node.new("a")
210
- b = root.add("b")
211
- b.add("d")
212
- b.add("e").add("f")
213
- root.add("c")
214
- Graph.new(root)
215
- end
216
- end
217
-
218
- class SampleStocksDisplay < Widget
219
- attr_accessor :stats
220
-
221
- def initialize(font, stats)
222
- super(10, 100, COLOR_HEADER_BRIGHT_BLUE)
223
- set_dimensions(780, 500)
224
- set_font(font)
225
- add_document(sample_content, 5, 5, @width, @height)
226
- add_button("Exit", 380, @height - 30) do
227
- WidgetResult.new(true)
228
- end
229
-
230
- @stats = stats
231
- @data_table = add_single_select_table(5, 100, # top left corner
232
- 770, 200, # width, height
233
- ["Day", "Min", "Avg", "StdDev", "Max", "p10", "p90"], # column headers
234
- COLOR_WHITE) # font and text color
235
- @data_table.selected_color = COLOR_LIGHT_GRAY
236
- Date::DAYNAMES[1..5].each do |day|
237
- min = format_percent(@stats.min(day))
238
- avg = format_percent(@stats.average(day))
239
- std = format_percent(@stats.std_dev(day))
240
- max = format_percent(@stats.max(day))
241
- p10 = format_percent(@stats.percentile(day, 0.1))
242
- p90 = format_percent(@stats.percentile(day, 0.90))
243
- @data_table.add_row([day, min, avg, std, max, p10, p90], COLOR_HEADER_BRIGHT_BLUE)
244
- end
245
-
246
- @selection_text = nil
247
- end
248
-
249
- def format_percent(val)
250
- "#{(val * 100).round(3)}%"
251
- end
252
-
253
- def sample_content
254
- <<~HEREDOC
255
- This sample stock analysis uses NASDAQ data from https://finance.yahoo.com looking
256
- at closing data through the years 2000 to 2020. The percent gain or loss is broken
257
- down per day, as shown in the table below.
258
- HEREDOC
259
- end
260
-
261
- def render
262
- if @selection_text
263
- @selection_text.draw
264
- end
265
- end
266
-
267
- def handle_mouse_down mouse_x, mouse_y
268
- if @data_table.contains_click(mouse_x, mouse_y)
269
- val = @data_table.set_selected_row(mouse_y, 0)
270
- if not val.nil?
271
- @selection_text = Text.new("You selected #{val}, a great day!",
272
- x + 5, y + 400, @font)
273
- end
274
- end
275
- nil
276
- end
277
- end
278
-
279
- class SampleStarWarsDisplay < Widget
280
- attr_accessor :graph
281
-
282
- def initialize(font, graph)
283
- super(10, 100, COLOR_HEADER_BRIGHT_BLUE)
284
- set_dimensions(780, 500)
285
- set_font(font)
286
- @graph = graph
287
-
288
- add_document(sample_content, 5, 5, @width, @height)
289
- add_button("Exit", 370, @height - 30) do
290
- WidgetResult.new(true)
291
- end
292
-
293
- @data_table = add_single_select_table(5, 70, # top left corner
294
- 770, 180, # width, height
295
- ["Character", "Number of Scenes"], # column headers
296
- COLOR_WHITE, # font and text color
297
- 5) # max visible rows
298
- @data_table.selected_color = COLOR_LIGHT_GRAY
299
-
300
- @graph.node_list.each do |character|
301
- @data_table.add_row([character.name, character.value], character.get_tag("color"))
52
+
53
+ def button_up id
54
+ @main_widget.button_up id, mouse_x, mouse_y
302
55
  end
303
- @graph_display = add_graph_display(5, 260, 770, 200, @graph)
304
56
  end
305
-
306
- def sample_content
307
- <<~HEREDOC
308
- This sample analysis shows the interactions between characters in the Star Wars
309
- Episode 4: A New Hope. Click on a character to see more detail.
310
- HEREDOC
311
- end
312
-
313
- def handle_key_press id, mouse_x, mouse_y
314
- if id == Gosu::KbUp
315
- @data_table.scroll_up
316
- elsif id == Gosu::KbDown
317
- @data_table.scroll_down
318
- end
319
- WidgetResult.new(false)
320
- end
321
-
322
- def handle_mouse_down mouse_x, mouse_y
323
- if @data_table.contains_click(mouse_x, mouse_y)
324
- val = @data_table.set_selected_row(mouse_y, 0)
325
- if not val.nil?
326
- node = @graph.find_node(val)
327
- @graph_display.set_center_node(node, 2)
328
- end
329
- end
330
- nil
331
- end
332
57
  end
333
-
334
- class SampleGraphDisplay < Widget
335
- attr_accessor :graph
336
-
337
- def initialize(font, graph)
338
- super(10, 100, COLOR_CYAN)
339
- set_dimensions(780, 500)
340
- set_font(font)
341
- @graph = graph
342
- exit_button = add_button("Exit", 370, @height - 30) do
343
- WidgetResult.new(true)
344
- end
345
- exit_button.text_color = COLOR_CYAN
346
- @graph_display = add_graph_display(5, 60, 770, 400, @graph)
347
- @graph_display.set_tree_display
348
- end
349
- end