teek 0.1.3 → 0.1.4
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 +4 -4
- data/README.md +21 -0
- data/Rakefile +120 -22
- data/ext/teek/extconf.rb +19 -1
- data/ext/teek/tcltkbridge.c +38 -2
- data/ext/teek/tcltkbridge.h +3 -0
- data/ext/teek/tkdrop.c +66 -0
- data/ext/teek/tkdrop.h +26 -0
- data/ext/teek/tkdrop_macos.m +141 -0
- data/ext/teek/tkdrop_win.c +232 -0
- data/ext/teek/tkdrop_x11.c +337 -0
- data/ext/teek/tkwin.c +42 -0
- data/lib/teek/platform.rb +29 -0
- data/lib/teek/version.rb +1 -1
- data/lib/teek.rb +49 -3
- data/teek.gemspec +3 -2
- metadata +7 -53
- data/sample/calculator.rb +0 -255
- data/sample/debug_demo.rb +0 -43
- data/sample/gamepad_viewer/assets/controller.png +0 -0
- data/sample/gamepad_viewer/gamepad_viewer.rb +0 -554
- data/sample/goldberg.rb +0 -1803
- data/sample/goldberg_helpers.rb +0 -170
- data/sample/optcarrot/thwaite.nes +0 -0
- data/sample/optcarrot/vendor/optcarrot/apu.rb +0 -856
- data/sample/optcarrot/vendor/optcarrot/config.rb +0 -257
- data/sample/optcarrot/vendor/optcarrot/cpu.rb +0 -1162
- data/sample/optcarrot/vendor/optcarrot/driver.rb +0 -144
- data/sample/optcarrot/vendor/optcarrot/mapper/cnrom.rb +0 -14
- data/sample/optcarrot/vendor/optcarrot/mapper/mmc1.rb +0 -105
- data/sample/optcarrot/vendor/optcarrot/mapper/mmc3.rb +0 -153
- data/sample/optcarrot/vendor/optcarrot/mapper/uxrom.rb +0 -14
- data/sample/optcarrot/vendor/optcarrot/nes.rb +0 -105
- data/sample/optcarrot/vendor/optcarrot/opt.rb +0 -168
- data/sample/optcarrot/vendor/optcarrot/pad.rb +0 -92
- data/sample/optcarrot/vendor/optcarrot/palette.rb +0 -65
- data/sample/optcarrot/vendor/optcarrot/ppu.rb +0 -1468
- data/sample/optcarrot/vendor/optcarrot/rom.rb +0 -143
- data/sample/optcarrot/vendor/optcarrot.rb +0 -14
- data/sample/optcarrot.rb +0 -354
- data/sample/paint/assets/bucket.png +0 -0
- data/sample/paint/assets/cursor.png +0 -0
- data/sample/paint/assets/eraser.png +0 -0
- data/sample/paint/assets/pencil.png +0 -0
- data/sample/paint/assets/spray.png +0 -0
- data/sample/paint/layer.rb +0 -255
- data/sample/paint/layer_manager.rb +0 -179
- data/sample/paint/paint_demo.rb +0 -837
- data/sample/paint/sparse_pixel_buffer.rb +0 -202
- data/sample/sdl2_demo.rb +0 -318
- data/sample/threading_demo.rb +0 -494
- data/sample/yam/assets/MINESWEEPER_0.png +0 -0
- data/sample/yam/assets/MINESWEEPER_1.png +0 -0
- data/sample/yam/assets/MINESWEEPER_2.png +0 -0
- data/sample/yam/assets/MINESWEEPER_3.png +0 -0
- data/sample/yam/assets/MINESWEEPER_4.png +0 -0
- data/sample/yam/assets/MINESWEEPER_5.png +0 -0
- data/sample/yam/assets/MINESWEEPER_6.png +0 -0
- data/sample/yam/assets/MINESWEEPER_7.png +0 -0
- data/sample/yam/assets/MINESWEEPER_8.png +0 -0
- data/sample/yam/assets/MINESWEEPER_F.png +0 -0
- data/sample/yam/assets/MINESWEEPER_M.png +0 -0
- data/sample/yam/assets/MINESWEEPER_X.png +0 -0
- data/sample/yam/assets/click.wav +0 -0
- data/sample/yam/assets/explosion.wav +0 -0
- data/sample/yam/assets/flag.wav +0 -0
- data/sample/yam/assets/music.mp3 +0 -0
- data/sample/yam/assets/sweep.wav +0 -0
- data/sample/yam/yam.rb +0 -587
data/lib/teek.rb
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require 'tcltklib'
|
|
4
4
|
require_relative 'teek/version'
|
|
5
|
+
require_relative 'teek/platform'
|
|
5
6
|
require_relative 'teek/ractor_support'
|
|
6
7
|
require_relative 'teek/widget'
|
|
7
8
|
require_relative 'teek/photo'
|
|
@@ -242,8 +243,25 @@ module Teek
|
|
|
242
243
|
# @return [String] the Tcl result
|
|
243
244
|
def command(cmd, *args, **kwargs)
|
|
244
245
|
parts = [cmd.to_s]
|
|
245
|
-
|
|
246
|
-
|
|
246
|
+
i = 0
|
|
247
|
+
while i < args.length
|
|
248
|
+
arg = args[i]
|
|
249
|
+
if arg.is_a?(Proc)
|
|
250
|
+
id = @interp.register_callback(arg)
|
|
251
|
+
subs = []
|
|
252
|
+
while i + 1 < args.length && args[i + 1].is_a?(String) && args[i + 1].start_with?('%')
|
|
253
|
+
subs << args[i + 1]
|
|
254
|
+
i += 1
|
|
255
|
+
end
|
|
256
|
+
parts << if subs.empty?
|
|
257
|
+
"{ruby_callback #{id}}"
|
|
258
|
+
else
|
|
259
|
+
"{ruby_callback #{id} #{subs.join(' ')}}"
|
|
260
|
+
end
|
|
261
|
+
else
|
|
262
|
+
parts << tcl_value(arg)
|
|
263
|
+
end
|
|
264
|
+
i += 1
|
|
247
265
|
end
|
|
248
266
|
kwargs.each do |key, value|
|
|
249
267
|
parts << "-#{key}"
|
|
@@ -592,6 +610,7 @@ module Teek
|
|
|
592
610
|
button: '%b', # mouse button number
|
|
593
611
|
mouse_wheel: '%D', # mousewheel delta
|
|
594
612
|
type: '%T', # event type
|
|
613
|
+
data: '%d', # virtual event data (Tk 8.6+)
|
|
595
614
|
}.freeze
|
|
596
615
|
|
|
597
616
|
def bind(widget, event, *subs, &block)
|
|
@@ -613,6 +632,22 @@ module Teek
|
|
|
613
632
|
@interp.tcl_eval("bind #{widget} #{event_str} {}")
|
|
614
633
|
end
|
|
615
634
|
|
|
635
|
+
# Register a widget as a file drop target.
|
|
636
|
+
# After registration, dropping files onto the widget generates a single
|
|
637
|
+
# +<<DropFile>>+ virtual event with all file paths as a Tcl list in the
|
|
638
|
+
# event data. Use {#split_list} to convert to a Ruby array.
|
|
639
|
+
# @param widget [String] Tk widget path (e.g., ".", ".frame")
|
|
640
|
+
# @return [void]
|
|
641
|
+
# @example
|
|
642
|
+
# app.register_drop_target('.')
|
|
643
|
+
# app.bind('.', '<<DropFile>>', :data) do |data|
|
|
644
|
+
# paths = app.split_list(data)
|
|
645
|
+
# puts "Dropped #{paths.length} file(s): #{paths.inspect}"
|
|
646
|
+
# end
|
|
647
|
+
def register_drop_target(widget)
|
|
648
|
+
@interp.register_drop_target(widget.to_s)
|
|
649
|
+
end
|
|
650
|
+
|
|
616
651
|
# Get the macOS window appearance. No-op (returns +nil+) on non-macOS.
|
|
617
652
|
# @example
|
|
618
653
|
# app.appearance # => "aqua", "darkaqua", or "auto"
|
|
@@ -760,7 +795,18 @@ module Teek
|
|
|
760
795
|
when Array
|
|
761
796
|
"{#{value.map { |v| tcl_value(v) }.join(' ')}}"
|
|
762
797
|
else
|
|
763
|
-
|
|
798
|
+
tcl_quote_string(value.to_s)
|
|
799
|
+
end
|
|
800
|
+
end
|
|
801
|
+
|
|
802
|
+
# Brace-quote a string for Tcl, falling back to double-quote quoting
|
|
803
|
+
# when the string ends with a backslash (Tcl treats \} as an escaped
|
|
804
|
+
# brace, preventing the closing brace from terminating the group).
|
|
805
|
+
def tcl_quote_string(s)
|
|
806
|
+
if s.end_with?('\\')
|
|
807
|
+
'"' + s.gsub(/[\\\[\]$"]/) { |c| "\\#{c}" } + '"'
|
|
808
|
+
else
|
|
809
|
+
"{#{s}}"
|
|
764
810
|
end
|
|
765
811
|
end
|
|
766
812
|
end
|
data/teek.gemspec
CHANGED
|
@@ -11,8 +11,9 @@ Gem::Specification.new do |spec|
|
|
|
11
11
|
spec.homepage = "https://github.com/jamescook/teek"
|
|
12
12
|
spec.licenses = ["MIT"]
|
|
13
13
|
|
|
14
|
-
spec.files = Dir.glob("{lib,ext,exe
|
|
15
|
-
File.file?(f) && f !~ /\.(bundle|so|o|log)$/
|
|
14
|
+
spec.files = Dir.glob("{lib,ext,exe}/**/*").select { |f|
|
|
15
|
+
File.file?(f) && f !~ /\.(bundle|so|o|log)$/ &&
|
|
16
|
+
!f.include?('.dSYM/') && File.basename(f) != 'Makefile'
|
|
16
17
|
} + %w[Rakefile LICENSE README.md teek.gemspec Gemfile]
|
|
17
18
|
spec.bindir = "exe"
|
|
18
19
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: teek
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- James Cook
|
|
@@ -124,6 +124,11 @@ files:
|
|
|
124
124
|
- ext/teek/tcl9compat.h
|
|
125
125
|
- ext/teek/tcltkbridge.c
|
|
126
126
|
- ext/teek/tcltkbridge.h
|
|
127
|
+
- ext/teek/tkdrop.c
|
|
128
|
+
- ext/teek/tkdrop.h
|
|
129
|
+
- ext/teek/tkdrop_macos.m
|
|
130
|
+
- ext/teek/tkdrop_win.c
|
|
131
|
+
- ext/teek/tkdrop_x11.c
|
|
127
132
|
- ext/teek/tkeventsource.c
|
|
128
133
|
- ext/teek/tkfont.c
|
|
129
134
|
- ext/teek/tkphoto.c
|
|
@@ -136,61 +141,10 @@ files:
|
|
|
136
141
|
- lib/teek/demo_support.rb
|
|
137
142
|
- lib/teek/method_coverage_service.rb
|
|
138
143
|
- lib/teek/photo.rb
|
|
144
|
+
- lib/teek/platform.rb
|
|
139
145
|
- lib/teek/ractor_support.rb
|
|
140
146
|
- lib/teek/version.rb
|
|
141
147
|
- lib/teek/widget.rb
|
|
142
|
-
- sample/calculator.rb
|
|
143
|
-
- sample/debug_demo.rb
|
|
144
|
-
- sample/gamepad_viewer/assets/controller.png
|
|
145
|
-
- sample/gamepad_viewer/gamepad_viewer.rb
|
|
146
|
-
- sample/goldberg.rb
|
|
147
|
-
- sample/goldberg_helpers.rb
|
|
148
|
-
- sample/optcarrot.rb
|
|
149
|
-
- sample/optcarrot/thwaite.nes
|
|
150
|
-
- sample/optcarrot/vendor/optcarrot.rb
|
|
151
|
-
- sample/optcarrot/vendor/optcarrot/apu.rb
|
|
152
|
-
- sample/optcarrot/vendor/optcarrot/config.rb
|
|
153
|
-
- sample/optcarrot/vendor/optcarrot/cpu.rb
|
|
154
|
-
- sample/optcarrot/vendor/optcarrot/driver.rb
|
|
155
|
-
- sample/optcarrot/vendor/optcarrot/mapper/cnrom.rb
|
|
156
|
-
- sample/optcarrot/vendor/optcarrot/mapper/mmc1.rb
|
|
157
|
-
- sample/optcarrot/vendor/optcarrot/mapper/mmc3.rb
|
|
158
|
-
- sample/optcarrot/vendor/optcarrot/mapper/uxrom.rb
|
|
159
|
-
- sample/optcarrot/vendor/optcarrot/nes.rb
|
|
160
|
-
- sample/optcarrot/vendor/optcarrot/opt.rb
|
|
161
|
-
- sample/optcarrot/vendor/optcarrot/pad.rb
|
|
162
|
-
- sample/optcarrot/vendor/optcarrot/palette.rb
|
|
163
|
-
- sample/optcarrot/vendor/optcarrot/ppu.rb
|
|
164
|
-
- sample/optcarrot/vendor/optcarrot/rom.rb
|
|
165
|
-
- sample/paint/assets/bucket.png
|
|
166
|
-
- sample/paint/assets/cursor.png
|
|
167
|
-
- sample/paint/assets/eraser.png
|
|
168
|
-
- sample/paint/assets/pencil.png
|
|
169
|
-
- sample/paint/assets/spray.png
|
|
170
|
-
- sample/paint/layer.rb
|
|
171
|
-
- sample/paint/layer_manager.rb
|
|
172
|
-
- sample/paint/paint_demo.rb
|
|
173
|
-
- sample/paint/sparse_pixel_buffer.rb
|
|
174
|
-
- sample/sdl2_demo.rb
|
|
175
|
-
- sample/threading_demo.rb
|
|
176
|
-
- sample/yam/assets/MINESWEEPER_0.png
|
|
177
|
-
- sample/yam/assets/MINESWEEPER_1.png
|
|
178
|
-
- sample/yam/assets/MINESWEEPER_2.png
|
|
179
|
-
- sample/yam/assets/MINESWEEPER_3.png
|
|
180
|
-
- sample/yam/assets/MINESWEEPER_4.png
|
|
181
|
-
- sample/yam/assets/MINESWEEPER_5.png
|
|
182
|
-
- sample/yam/assets/MINESWEEPER_6.png
|
|
183
|
-
- sample/yam/assets/MINESWEEPER_7.png
|
|
184
|
-
- sample/yam/assets/MINESWEEPER_8.png
|
|
185
|
-
- sample/yam/assets/MINESWEEPER_F.png
|
|
186
|
-
- sample/yam/assets/MINESWEEPER_M.png
|
|
187
|
-
- sample/yam/assets/MINESWEEPER_X.png
|
|
188
|
-
- sample/yam/assets/click.wav
|
|
189
|
-
- sample/yam/assets/explosion.wav
|
|
190
|
-
- sample/yam/assets/flag.wav
|
|
191
|
-
- sample/yam/assets/music.mp3
|
|
192
|
-
- sample/yam/assets/sweep.wav
|
|
193
|
-
- sample/yam/yam.rb
|
|
194
148
|
- teek.gemspec
|
|
195
149
|
homepage: https://github.com/jamescook/teek
|
|
196
150
|
licenses:
|
data/sample/calculator.rb
DELETED
|
@@ -1,255 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
# teek-record: title=Calculator
|
|
4
|
-
|
|
5
|
-
# Calculator - A simple desktop calculator
|
|
6
|
-
#
|
|
7
|
-
# Run: ruby -Ilib sample/calculator.rb
|
|
8
|
-
|
|
9
|
-
require 'teek'
|
|
10
|
-
|
|
11
|
-
class Calculator
|
|
12
|
-
attr_reader :app
|
|
13
|
-
|
|
14
|
-
def initialize
|
|
15
|
-
@app = Teek::App.new
|
|
16
|
-
@display_value = '0'
|
|
17
|
-
@pending_op = nil
|
|
18
|
-
@accumulator = nil
|
|
19
|
-
@reset_on_next = false
|
|
20
|
-
|
|
21
|
-
build_ui
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def build_ui
|
|
25
|
-
@app.show
|
|
26
|
-
@app.set_window_title('Calculator')
|
|
27
|
-
@app.set_window_resizable(false, false)
|
|
28
|
-
|
|
29
|
-
# Button style — use a larger font since macOS aqua theme
|
|
30
|
-
# ignores vertical stretch; font size drives button height
|
|
31
|
-
@app.tcl_eval('ttk::style configure Calc.TButton -font {{TkDefaultFont} 18}')
|
|
32
|
-
|
|
33
|
-
# Display
|
|
34
|
-
@app.set_variable('::display', '0')
|
|
35
|
-
@display = @app.create_widget('ttk::entry', textvariable: '::display',
|
|
36
|
-
justify: :right, state: :readonly, font: '{TkDefaultFont} 24')
|
|
37
|
-
@display.grid(row: 0, column: 0, columnspan: 4,
|
|
38
|
-
sticky: :ew, padx: 4, pady: 4, ipady: 8)
|
|
39
|
-
|
|
40
|
-
build_buttons
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
def build_buttons
|
|
44
|
-
# Row 1: C, +/-, %, /
|
|
45
|
-
button('C', 1, 0, style: :accent) { clear }
|
|
46
|
-
button('+/-', 1, 1, style: :accent) { negate }
|
|
47
|
-
button('%', 1, 2, style: :accent) { percent }
|
|
48
|
-
button('/', 1, 3, style: :op) { set_op(:/) }
|
|
49
|
-
|
|
50
|
-
# Row 2: 7, 8, 9, *
|
|
51
|
-
button('7', 2, 0) { digit('7') }
|
|
52
|
-
button('8', 2, 1) { digit('8') }
|
|
53
|
-
button('9', 2, 2) { digit('9') }
|
|
54
|
-
button('*', 2, 3, style: :op) { set_op(:*) }
|
|
55
|
-
|
|
56
|
-
# Row 3: 4, 5, 6, -
|
|
57
|
-
button('4', 3, 0) { digit('4') }
|
|
58
|
-
button('5', 3, 1) { digit('5') }
|
|
59
|
-
button('6', 3, 2) { digit('6') }
|
|
60
|
-
button('-', 3, 3, style: :op) { set_op(:-) }
|
|
61
|
-
|
|
62
|
-
# Row 4: 1, 2, 3, +
|
|
63
|
-
button('1', 4, 0) { digit('1') }
|
|
64
|
-
button('2', 4, 1) { digit('2') }
|
|
65
|
-
button('3', 4, 2) { digit('3') }
|
|
66
|
-
button('+', 4, 3, style: :op) { set_op(:+) }
|
|
67
|
-
|
|
68
|
-
# Row 5: 0 (wide), ., =
|
|
69
|
-
button('0', 5, 0, colspan: 2) { digit('0') }
|
|
70
|
-
button('.', 5, 2) { decimal }
|
|
71
|
-
button('=', 5, 3, style: :op) { equals }
|
|
72
|
-
|
|
73
|
-
# Make columns equal width
|
|
74
|
-
4.times { |c| @app.command(:grid, 'columnconfigure', '.', c, weight: 1, minsize: 60) }
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
# --- UI helpers ---
|
|
78
|
-
|
|
79
|
-
# Click a button by its label (for demo/testing).
|
|
80
|
-
# In recording mode, shows the pressed visual state briefly before invoking.
|
|
81
|
-
def click(label, recording: false)
|
|
82
|
-
widget = @buttons[label]
|
|
83
|
-
return unless widget
|
|
84
|
-
if recording
|
|
85
|
-
widget.command('state', 'pressed')
|
|
86
|
-
@app.after(80) {
|
|
87
|
-
widget.command('state', '!pressed')
|
|
88
|
-
widget.command(:invoke)
|
|
89
|
-
}
|
|
90
|
-
else
|
|
91
|
-
widget.command(:invoke)
|
|
92
|
-
end
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
def button(text, row, col, style: :num, colspan: 1, &action)
|
|
96
|
-
@buttons ||= {}
|
|
97
|
-
widget = @app.create_widget('ttk::button', text: text, style: 'Calc.TButton',
|
|
98
|
-
command: proc { |*| action.call })
|
|
99
|
-
@buttons[text] = widget
|
|
100
|
-
widget.grid(row: row, column: col, columnspan: colspan,
|
|
101
|
-
sticky: :nsew, padx: 2, pady: 2)
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
def update_display
|
|
105
|
-
@app.set_variable('::display', @display_value)
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
# --- Calculator logic ---
|
|
109
|
-
|
|
110
|
-
def digit(d)
|
|
111
|
-
if @reset_on_next
|
|
112
|
-
@display_value = '0'
|
|
113
|
-
@reset_on_next = false
|
|
114
|
-
end
|
|
115
|
-
if @display_value == '0' && d != '0'
|
|
116
|
-
@display_value = d
|
|
117
|
-
elsif @display_value != '0'
|
|
118
|
-
@display_value += d
|
|
119
|
-
end
|
|
120
|
-
update_display
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
def decimal
|
|
124
|
-
@display_value = '0' if @reset_on_next
|
|
125
|
-
@reset_on_next = false
|
|
126
|
-
unless @display_value.include?('.')
|
|
127
|
-
@display_value += '.'
|
|
128
|
-
end
|
|
129
|
-
update_display
|
|
130
|
-
end
|
|
131
|
-
|
|
132
|
-
def clear
|
|
133
|
-
@display_value = '0'
|
|
134
|
-
@pending_op = nil
|
|
135
|
-
@accumulator = nil
|
|
136
|
-
@reset_on_next = false
|
|
137
|
-
update_display
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
def negate
|
|
141
|
-
if @display_value.start_with?('-')
|
|
142
|
-
@display_value = @display_value[1..]
|
|
143
|
-
elsif @display_value != '0'
|
|
144
|
-
@display_value = "-#{@display_value}"
|
|
145
|
-
end
|
|
146
|
-
update_display
|
|
147
|
-
end
|
|
148
|
-
|
|
149
|
-
def percent
|
|
150
|
-
@display_value = (current_value / 100.0).to_s
|
|
151
|
-
@reset_on_next = true
|
|
152
|
-
update_display
|
|
153
|
-
end
|
|
154
|
-
|
|
155
|
-
def set_op(op)
|
|
156
|
-
evaluate if @pending_op && !@reset_on_next
|
|
157
|
-
@accumulator = current_value
|
|
158
|
-
@pending_op = op
|
|
159
|
-
@reset_on_next = true
|
|
160
|
-
end
|
|
161
|
-
|
|
162
|
-
def equals
|
|
163
|
-
evaluate
|
|
164
|
-
@pending_op = nil
|
|
165
|
-
end
|
|
166
|
-
|
|
167
|
-
def run
|
|
168
|
-
@app.mainloop
|
|
169
|
-
end
|
|
170
|
-
|
|
171
|
-
private
|
|
172
|
-
|
|
173
|
-
def current_value
|
|
174
|
-
@display_value.to_f
|
|
175
|
-
end
|
|
176
|
-
|
|
177
|
-
def evaluate
|
|
178
|
-
return unless @pending_op && @accumulator
|
|
179
|
-
|
|
180
|
-
b = current_value
|
|
181
|
-
result = case @pending_op
|
|
182
|
-
when :+ then @accumulator + b
|
|
183
|
-
when :- then @accumulator - b
|
|
184
|
-
when :* then @accumulator * b
|
|
185
|
-
when :/ then b.zero? ? Float::NAN : @accumulator / b
|
|
186
|
-
end
|
|
187
|
-
|
|
188
|
-
@accumulator = result
|
|
189
|
-
@display_value = format_result(result)
|
|
190
|
-
@reset_on_next = true
|
|
191
|
-
update_display
|
|
192
|
-
end
|
|
193
|
-
|
|
194
|
-
def format_result(val)
|
|
195
|
-
return 'Error' if val.nil? || val.nan? || val.infinite?
|
|
196
|
-
val == val.to_i ? val.to_i.to_s : val.to_s
|
|
197
|
-
end
|
|
198
|
-
end
|
|
199
|
-
|
|
200
|
-
calc = Calculator.new
|
|
201
|
-
|
|
202
|
-
# Automated demo support (testing and recording)
|
|
203
|
-
require_relative '../lib/teek/demo_support'
|
|
204
|
-
TeekDemo.app = calc.app
|
|
205
|
-
|
|
206
|
-
if TeekDemo.recording?
|
|
207
|
-
calc.app.set_window_geometry('+0+0')
|
|
208
|
-
calc.app.tcl_eval('. configure -cursor none')
|
|
209
|
-
TeekDemo.signal_recording_ready
|
|
210
|
-
end
|
|
211
|
-
|
|
212
|
-
if TeekDemo.active?
|
|
213
|
-
TeekDemo.after_idle {
|
|
214
|
-
d = TeekDemo.method(:delay)
|
|
215
|
-
app = calc.app
|
|
216
|
-
rec = TeekDemo.recording?
|
|
217
|
-
|
|
218
|
-
# Exercises all four operations, landing on 42.
|
|
219
|
-
# 8 * 9 = 72, / 3 = 24, + 25 = 49, - 7 = 42
|
|
220
|
-
steps = [
|
|
221
|
-
-> { calc.click('8', recording: rec) },
|
|
222
|
-
-> { calc.click('*', recording: rec) },
|
|
223
|
-
-> { calc.click('9', recording: rec) },
|
|
224
|
-
-> { calc.click('=', recording: rec) }, # 72
|
|
225
|
-
nil,
|
|
226
|
-
-> { calc.click('/', recording: rec) },
|
|
227
|
-
-> { calc.click('3', recording: rec) },
|
|
228
|
-
-> { calc.click('=', recording: rec) }, # 24
|
|
229
|
-
nil,
|
|
230
|
-
-> { calc.click('+', recording: rec) },
|
|
231
|
-
-> { calc.click('2', recording: rec) },
|
|
232
|
-
-> { calc.click('5', recording: rec) },
|
|
233
|
-
-> { calc.click('=', recording: rec) }, # 49
|
|
234
|
-
nil,
|
|
235
|
-
-> { calc.click('-', recording: rec) },
|
|
236
|
-
-> { calc.click('7', recording: rec) },
|
|
237
|
-
-> { calc.click('=', recording: rec) }, # 42
|
|
238
|
-
nil, nil,
|
|
239
|
-
-> { TeekDemo.finish },
|
|
240
|
-
]
|
|
241
|
-
|
|
242
|
-
run_step = nil
|
|
243
|
-
i = 0
|
|
244
|
-
run_step = proc {
|
|
245
|
-
steps[i]&.call
|
|
246
|
-
i += 1
|
|
247
|
-
if i < steps.length
|
|
248
|
-
app.after(d.call(test: 1, record: 250)) { run_step.call }
|
|
249
|
-
end
|
|
250
|
-
}
|
|
251
|
-
run_step.call
|
|
252
|
-
}
|
|
253
|
-
end
|
|
254
|
-
|
|
255
|
-
calc.run
|
data/sample/debug_demo.rb
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# Demo of the Teek debugger window.
|
|
4
|
-
# Run: ruby -Ilib sample/debug_demo.rb
|
|
5
|
-
|
|
6
|
-
require 'teek'
|
|
7
|
-
|
|
8
|
-
app = Teek::App.new(debug: true)
|
|
9
|
-
|
|
10
|
-
# Show the main app window
|
|
11
|
-
app.show
|
|
12
|
-
app.set_window_title('Debug Demo App')
|
|
13
|
-
app.set_window_geometry('300x200')
|
|
14
|
-
|
|
15
|
-
# Create some widgets
|
|
16
|
-
frame = app.create_widget('ttk::frame')
|
|
17
|
-
app.command(:pack, frame, fill: :both, expand: 1, padx: 10, pady: 10)
|
|
18
|
-
|
|
19
|
-
lbl = app.create_widget('ttk::label', parent: frame, text: 'Hello from the app')
|
|
20
|
-
app.command(:pack, lbl, pady: 5)
|
|
21
|
-
|
|
22
|
-
ent = app.create_widget('ttk::entry', parent: frame)
|
|
23
|
-
app.command(:pack, ent, pady: 5)
|
|
24
|
-
|
|
25
|
-
# Button that creates more widgets dynamically
|
|
26
|
-
dynamic_widgets = []
|
|
27
|
-
add_btn = app.create_widget('ttk::button', parent: frame, text: 'Add Widget',
|
|
28
|
-
command: proc { |*|
|
|
29
|
-
btn = app.create_widget('ttk::button', parent: frame, text: "Button #{dynamic_widgets.size + 1}")
|
|
30
|
-
app.command(:pack, btn, pady: 2)
|
|
31
|
-
dynamic_widgets << btn
|
|
32
|
-
})
|
|
33
|
-
app.command(:pack, add_btn, pady: 5)
|
|
34
|
-
|
|
35
|
-
# Button to destroy last widget
|
|
36
|
-
rm_btn = app.create_widget('ttk::button', parent: frame, text: 'Remove Widget',
|
|
37
|
-
command: proc { |*|
|
|
38
|
-
widget = dynamic_widgets.pop
|
|
39
|
-
widget&.destroy
|
|
40
|
-
})
|
|
41
|
-
app.command(:pack, rm_btn, pady: 5)
|
|
42
|
-
|
|
43
|
-
app.mainloop
|
|
Binary file
|