cryptopunks-gui 0.0.10 → 0.0.14
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/CHANGELOG.md +24 -0
- data/LICENSE.txt +1 -1
- data/README.md +16 -52
- data/VERSION +1 -1
- data/app/cryptopunks_gui.rb +17 -319
- data/app/model/image.rb +187 -0
- data/app/view/help_dialog.rb +31 -0
- data/app/view/image_frame.rb +145 -0
- data/app/view/menu_bar.rb +88 -0
- data/app/view/preferences_dialog.rb +174 -0
- data/app/view/style_options_frame.rb +60 -0
- data/bin/cryptopunks-gui +0 -0
- data/cryptopunks-gui.gemspec +68 -67
- metadata +15 -13
- data/bin/cryptopunks-mac-gui +0 -8
- data/bin/cryptopunks-mac-gui.rb +0 -8
- data/bin/package-mac +0 -8
- data/bin/package-mac-app +0 -5
- data/bin/package-mac-dmg +0 -6
data/app/model/image.rb
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
class CryptopunksGui
|
|
2
|
+
module Model
|
|
3
|
+
class Image
|
|
4
|
+
PALETTES = ['Standard'] + (Palette8bit.constants).map(&:to_s).map {|palette| palette.split('_').map(&:capitalize).join(' ')}.reject { |palette| palette.include?(' ') }.sort
|
|
5
|
+
STYLES = ['Normal', 'Led', 'Sketch']
|
|
6
|
+
OUTPUT_LOCATION_DEFAULT = File.join(Dir.home, 'cryptopunks')
|
|
7
|
+
CONFIG_FILE = File.join(OUTPUT_LOCATION_DEFAULT, 'cryptopunks.yml')
|
|
8
|
+
COLLECTIONS_YAML_PATH = File.join(OUTPUT_LOCATION_DEFAULT, 'cryptopunks-collections.yml')
|
|
9
|
+
COLLECTIONS_YAML_URL = 'https://raw.githubusercontent.com/cryptopunksnotdead/cryptopunks-gui/master/cryptopunks-collections.yml'
|
|
10
|
+
COLLECTIONS_YAML_REPO_PATH = File.expand_path('../../cryptopunks-collections.yml', __dir__)
|
|
11
|
+
|
|
12
|
+
attr_accessor :collection, :image_index, :zoom, :palette, :style, :led_spacing, :led_round_corner, :sketch_line, :flip, :mirror,
|
|
13
|
+
:collection_size, :collections_map, :images, :image_location, :output_location, :config
|
|
14
|
+
|
|
15
|
+
def initialize
|
|
16
|
+
initialize_output_location
|
|
17
|
+
initialize_collections_map
|
|
18
|
+
initialize_collection
|
|
19
|
+
load_config
|
|
20
|
+
initialize_defaults
|
|
21
|
+
observe_image_attribute_changes
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def collection_options
|
|
25
|
+
@collections_map.keys.select {|collection_name| @collections_map[collection_name][:enabled]}
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def palette_options
|
|
29
|
+
PALETTES
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def style_options
|
|
33
|
+
STYLES
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def initialize_output_location
|
|
37
|
+
@output_location = OUTPUT_LOCATION_DEFAULT
|
|
38
|
+
FileUtils.mkdir_p(@output_location)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def initialize_collections_map(reset: false)
|
|
42
|
+
FileUtils.touch(COLLECTIONS_YAML_PATH)
|
|
43
|
+
@collections_map = reset ? {} : (YAML.load(File.read(COLLECTIONS_YAML_PATH)) || {})
|
|
44
|
+
new_collections_map = {}
|
|
45
|
+
begin
|
|
46
|
+
http_response = Net::HTTP.get_response(URI(COLLECTIONS_YAML_URL))
|
|
47
|
+
if http_response.is_a?(Net::HTTPSuccess)
|
|
48
|
+
new_collections_map = YAML.load(http_response.body)
|
|
49
|
+
else
|
|
50
|
+
raise "code: #{http_response.code} message: #{http_response.message}"
|
|
51
|
+
end
|
|
52
|
+
rescue StandardError, SocketError => e
|
|
53
|
+
puts "Failed to utilize collection YAML from: #{COLLECTIONS_YAML_URL}"
|
|
54
|
+
puts e.full_message
|
|
55
|
+
puts "Utilizing local collection YAML instead: #{COLLECTIONS_YAML_REPO_PATH}"
|
|
56
|
+
new_collections_map = YAML.load(File.read(COLLECTIONS_YAML_REPO_PATH)) rescue {}
|
|
57
|
+
end
|
|
58
|
+
@collections_map_observers ||= {}
|
|
59
|
+
new_collections_map.each do |collection_name, collection_options|
|
|
60
|
+
@collections_map[collection_name] ||= {}
|
|
61
|
+
original_collections_map_for_collection = @collections_map[collection_name]
|
|
62
|
+
@collections_map[collection_name] = @collections_map[collection_name]
|
|
63
|
+
@collections_map[collection_name].reverse_merge!(collection_options)
|
|
64
|
+
@collections_map[collection_name][:enabled] = true unless @collections_map[collection_name].has_key?(:enabled)
|
|
65
|
+
@collections_map_observers[collection_name] ||= Glimmer::DataBinding::Observer.proc { |value, key|
|
|
66
|
+
if key == :enabled
|
|
67
|
+
self.collection = @collections_map.find { |name, options| options[:enabled] }.first if key == :enabled && value == false && @collection == collection_name
|
|
68
|
+
notify_observers(:collection_options)
|
|
69
|
+
end
|
|
70
|
+
save_collections_map
|
|
71
|
+
}.tap {|o| o.observe(original_collections_map_for_collection)}
|
|
72
|
+
end
|
|
73
|
+
@collections_map_observer ||= Glimmer::DataBinding::Observer.proc { |collection_options, collection_name|
|
|
74
|
+
if collection_options.nil?
|
|
75
|
+
self.collection = @collections_map.find { |name, options| options[:enabled] }.first if @collection == collection_name
|
|
76
|
+
self.collection = collection_name if @collections_map.select { |name, options| options[:enabled] }.count == 0
|
|
77
|
+
end
|
|
78
|
+
notify_observers(:collection_options)
|
|
79
|
+
save_collections_map
|
|
80
|
+
}.tap {|o| o.observe(@collections_map)}
|
|
81
|
+
save_collections_map
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def save_collections_map
|
|
85
|
+
normalized_collections_map = Hash[@collections_map.map {|k,v| [k, v.to_h]}]
|
|
86
|
+
File.write(COLLECTIONS_YAML_PATH, YAML.dump(normalized_collections_map))
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def initialize_collection
|
|
90
|
+
return if @collection && @collection == @last_collection
|
|
91
|
+
@collection ||= @collections_map.keys.first
|
|
92
|
+
url = @collections_map[@collection][:url]
|
|
93
|
+
width = @collections_map[@collection][:width]
|
|
94
|
+
height = @collections_map[@collection][:height]
|
|
95
|
+
@image_file = File.join(OUTPUT_LOCATION_DEFAULT, File.basename(url))
|
|
96
|
+
File.binwrite(@image_file, Net::HTTP.get(URI(url))) unless File.exist?(@image_file)
|
|
97
|
+
@images ||= {}
|
|
98
|
+
@images[@collection] ||= Punks::Image::Composite.read(@image_file, width: width, height: height)
|
|
99
|
+
@last_collection = @collection
|
|
100
|
+
self.image_index = 0
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def load_config
|
|
104
|
+
FileUtils.touch(CONFIG_FILE)
|
|
105
|
+
@config = YAML.load(File.read(CONFIG_FILE)) || {}
|
|
106
|
+
@output_location = @config[:output_location]
|
|
107
|
+
@config[:output_location] = @output_location = OUTPUT_LOCATION_DEFAULT if @output_location.nil?
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def save_config
|
|
111
|
+
File.write(CONFIG_FILE, YAML.dump(@config))
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def initialize_defaults
|
|
115
|
+
@collection = @collections_map.keys.first
|
|
116
|
+
@zoom = 12
|
|
117
|
+
@palette = PALETTES.first
|
|
118
|
+
@style = STYLES.first
|
|
119
|
+
@led_spacing = 2
|
|
120
|
+
@led_round_corner = false
|
|
121
|
+
@sketch_line = 1
|
|
122
|
+
@mirror = false
|
|
123
|
+
@flip = false
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def observe_image_attribute_changes
|
|
127
|
+
observer = Glimmer::DataBinding::Observer.proc { generate_image }
|
|
128
|
+
observer.observe(self, :collection)
|
|
129
|
+
observer.observe(self, :image_index)
|
|
130
|
+
observer.observe(self, :zoom)
|
|
131
|
+
observer.observe(self, :palette)
|
|
132
|
+
observer.observe(self, :style)
|
|
133
|
+
observer.observe(self, :led_spacing)
|
|
134
|
+
observer.observe(self, :led_round_corner)
|
|
135
|
+
observer.observe(self, :sketch_line)
|
|
136
|
+
observer.observe(self, :mirror)
|
|
137
|
+
observer.observe(self, :flip)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def generate_image
|
|
141
|
+
initialize_collection
|
|
142
|
+
return if @image_index.to_i >= @images[@collection].size
|
|
143
|
+
new_image_location = File.join(@output_location, "#{@collection.gsub(' ', '').downcase}-#{@image_index}#{"x#{@zoom}" if @zoom.to_i > 1}#{"-#{@palette.underscore}" if @palette != PALETTES.first}#{"-#{@style.underscore}" if @style != STYLES.first}#{"-spacing#{@led_spacing.to_i}" if @style == 'Led'}#{'-round-corner' if @style == 'Led' && @led_round_corner}#{"-line#{@sketch_line.to_i}" if @style == 'Sketch'}#{'-mirror' if @mirror}#{'-flip' if @flip}.png")
|
|
144
|
+
puts "Writing punk image to #{new_image_location}"
|
|
145
|
+
selected_punk = @images[@collection][@image_index.to_i]
|
|
146
|
+
selected_punk = selected_punk.change_palette8bit(Palette8bit.const_get(@palette.gsub(' ', '_').upcase.to_sym)) if @palette != PALETTES.first
|
|
147
|
+
@original_zoom = @zoom
|
|
148
|
+
if @previous_collection && @collection != @previous_collection && @collections_map[@collection][:width] != @collections_map[@previous_collection][:width]
|
|
149
|
+
@zoom = @collections_map[@collection][:default_zoom]
|
|
150
|
+
end
|
|
151
|
+
if @style != STYLES.first
|
|
152
|
+
style_options = {}
|
|
153
|
+
if @style == 'Led'
|
|
154
|
+
style_options[:spacing] = @led_spacing.to_i
|
|
155
|
+
style_options[:round_corner] = @led_round_corner
|
|
156
|
+
end
|
|
157
|
+
if @style == 'Sketch'
|
|
158
|
+
style_options[:line] = @sketch_line.to_i
|
|
159
|
+
end
|
|
160
|
+
selected_punk = selected_punk.send(@style.underscore, @zoom.to_i, **style_options)
|
|
161
|
+
end
|
|
162
|
+
selected_punk = selected_punk.mirror if @mirror
|
|
163
|
+
selected_punk = selected_punk.flip if @flip
|
|
164
|
+
selected_punk = selected_punk.zoom(@zoom.to_i) if @style == STYLES.first
|
|
165
|
+
selected_punk.save(new_image_location)
|
|
166
|
+
self.image_location = new_image_location
|
|
167
|
+
notify_observers(:zoom) if @zoom != @original_zoom
|
|
168
|
+
@previous_style = @style
|
|
169
|
+
@previous_collection = @collection
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def change_output_location(new_output_location)
|
|
173
|
+
@output_location = new_output_location
|
|
174
|
+
@config[:output_location] = @output_location
|
|
175
|
+
save_config
|
|
176
|
+
generate_image
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def reset_output_location
|
|
180
|
+
@output_location = OUTPUT_LOCATION_DEFAULT
|
|
181
|
+
@config[:output_location] = @output_location
|
|
182
|
+
save_config
|
|
183
|
+
generate_image
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
class CryptopunksGui
|
|
2
|
+
module View
|
|
3
|
+
module HelpDialog
|
|
4
|
+
def help_dialog(root: )
|
|
5
|
+
toplevel(root) {
|
|
6
|
+
title 'CryptoPunks GUI - README.md'
|
|
7
|
+
width 800
|
|
8
|
+
height 600
|
|
9
|
+
escapable true
|
|
10
|
+
|
|
11
|
+
help_dialog = text {
|
|
12
|
+
grid row: 0, column: 0, row_weight: 1, column_weight: 1
|
|
13
|
+
value help
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
help_dialog_yscrollbar = scrollbar {
|
|
17
|
+
grid row: 0, column: 1
|
|
18
|
+
orient 'vertical'
|
|
19
|
+
}
|
|
20
|
+
help_dialog.yscrollbar help_dialog_yscrollbar.tk
|
|
21
|
+
|
|
22
|
+
help_dialog_xscrollbar = scrollbar {
|
|
23
|
+
grid row: 1, column: 0, column_span: 2
|
|
24
|
+
orient 'horizontal'
|
|
25
|
+
}
|
|
26
|
+
help_dialog.xscrollbar help_dialog_xscrollbar.tk
|
|
27
|
+
}
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
class CryptopunksGui
|
|
2
|
+
module View
|
|
3
|
+
module ImageFrame
|
|
4
|
+
def image_frame(root: , image: )
|
|
5
|
+
image_label = output_location_entry = image_index_spinbox = style_options_container_frame = nil
|
|
6
|
+
|
|
7
|
+
frame {
|
|
8
|
+
label {
|
|
9
|
+
text 'Collection:'
|
|
10
|
+
}
|
|
11
|
+
combobox {
|
|
12
|
+
readonly true
|
|
13
|
+
values <= [image, :collection_options]
|
|
14
|
+
text <=> [image, :collection]
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
label {
|
|
18
|
+
text 'Image Index:'
|
|
19
|
+
}
|
|
20
|
+
image_index_spinbox = spinbox {
|
|
21
|
+
from 0
|
|
22
|
+
to image.images[image.collection].size - 1
|
|
23
|
+
text <=> [image, :image_index]
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
label {
|
|
27
|
+
text 'Zoom:'
|
|
28
|
+
}
|
|
29
|
+
spinbox {
|
|
30
|
+
from 1
|
|
31
|
+
to 72
|
|
32
|
+
text <=> [image, :zoom]
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
label {
|
|
36
|
+
text 'Palette:'
|
|
37
|
+
}
|
|
38
|
+
combobox {
|
|
39
|
+
readonly true
|
|
40
|
+
text <=> [image, :palette]
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
label {
|
|
44
|
+
text 'Style:'
|
|
45
|
+
}
|
|
46
|
+
combobox {
|
|
47
|
+
readonly true
|
|
48
|
+
text <=> [image, :style, after_write: ->(val) {add_style_options(style_options_container_frame: style_options_container_frame, image: image)}]
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
style_options_container_frame = frame {
|
|
52
|
+
padding 0
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
frame {
|
|
56
|
+
padding 0
|
|
57
|
+
|
|
58
|
+
checkbutton {
|
|
59
|
+
grid row: 0, column: 0, column_weight: 0
|
|
60
|
+
variable <=> [image, :mirror]
|
|
61
|
+
}
|
|
62
|
+
label {
|
|
63
|
+
grid row: 0, column: 1
|
|
64
|
+
text 'Mirror'
|
|
65
|
+
|
|
66
|
+
on('Button-1') do
|
|
67
|
+
image.mirror = !image.mirror
|
|
68
|
+
end
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
checkbutton {
|
|
72
|
+
grid row: 0, column: 2
|
|
73
|
+
variable <=> [image, :flip]
|
|
74
|
+
}
|
|
75
|
+
label {
|
|
76
|
+
grid row: 0, column: 3
|
|
77
|
+
text 'Flip'
|
|
78
|
+
|
|
79
|
+
on('Button-1') do
|
|
80
|
+
image.flip = !image.flip
|
|
81
|
+
end
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
label {
|
|
86
|
+
text 'Output Location:'
|
|
87
|
+
}
|
|
88
|
+
frame {
|
|
89
|
+
padding 0
|
|
90
|
+
|
|
91
|
+
output_location_entry = entry {
|
|
92
|
+
grid row: 0, column: 0
|
|
93
|
+
readonly true
|
|
94
|
+
width 47
|
|
95
|
+
}
|
|
96
|
+
button {
|
|
97
|
+
grid row: 0, column: 1
|
|
98
|
+
text '...'
|
|
99
|
+
width 1.1
|
|
100
|
+
|
|
101
|
+
on('command') do
|
|
102
|
+
change_output_location(root: root, image: image)
|
|
103
|
+
end
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
image_label = label {
|
|
108
|
+
grid row_weight: 1
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
register_image_frame_observers(image_label: image_label, output_location_entry: output_location_entry, image_index_spinbox: image_index_spinbox, image: image)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def register_image_frame_observers(image_label: , output_location_entry: , image_index_spinbox: , image: )
|
|
116
|
+
Glimmer::DataBinding::Observer.proc do
|
|
117
|
+
image_label.image = output_location_entry.text = image.image_location
|
|
118
|
+
end.observe(image, :image_location)
|
|
119
|
+
|
|
120
|
+
Glimmer::DataBinding::Observer.proc do
|
|
121
|
+
image_index_spinbox.to = image.images[image.collection].size - 1
|
|
122
|
+
end.observe(image, :collection)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def add_style_options(style_options_container_frame: , image: )
|
|
126
|
+
style_options_container_frame.children.each(&:destroy)
|
|
127
|
+
style_options_container_frame.content {
|
|
128
|
+
case image.style
|
|
129
|
+
when 'Led'
|
|
130
|
+
led_style_options_frame(image: image)
|
|
131
|
+
when 'Sketch'
|
|
132
|
+
sketch_style_options_frame(image: image)
|
|
133
|
+
else
|
|
134
|
+
no_style_options_frame
|
|
135
|
+
end
|
|
136
|
+
}
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def change_output_location(root: , image: )
|
|
140
|
+
new_output_location = choose_directory(parent: root)
|
|
141
|
+
image.change_output_location(new_output_location) unless new_output_location.to_s.empty?
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# require_relative 'preferences_dialog'
|
|
2
|
+
require_relative 'help_dialog'
|
|
3
|
+
|
|
4
|
+
class CryptopunksGui
|
|
5
|
+
module View
|
|
6
|
+
module MenuBar
|
|
7
|
+
# include View::PreferencesDialog
|
|
8
|
+
include View::HelpDialog
|
|
9
|
+
|
|
10
|
+
LICENSE = File.expand_path('../../LICENSE.txt', __dir__)
|
|
11
|
+
HELP = File.expand_path('../../README.md', __dir__)
|
|
12
|
+
|
|
13
|
+
def cryptopunks_gui_menu_bar(root: , image: )
|
|
14
|
+
menu {
|
|
15
|
+
if OS.mac?
|
|
16
|
+
menu(:application) {
|
|
17
|
+
menu_item(:about, label: 'About') {
|
|
18
|
+
accelerator OS.mac? ? 'Command+Shift+A' : 'Control+Alt+A'
|
|
19
|
+
|
|
20
|
+
on('command') do
|
|
21
|
+
show_about_dialog(root: root)
|
|
22
|
+
end
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
# menu_item(:preferences) {
|
|
26
|
+
# on('command') do
|
|
27
|
+
# preferences_dialog(root: root, image: image)
|
|
28
|
+
# end
|
|
29
|
+
# }
|
|
30
|
+
}
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
menu(label: 'File', underline: 0) {
|
|
34
|
+
menu_item(label: 'Change Output Location...', underline: 7) {
|
|
35
|
+
accelerator OS.mac? ? 'Command+O' : 'Control+O'
|
|
36
|
+
|
|
37
|
+
on('command') do
|
|
38
|
+
change_output_location(root: root, image: image) # assumes View::ImageFrame is mixed in
|
|
39
|
+
end
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
menu_item(label: 'Reset Output Location', underline: 0) {
|
|
43
|
+
on('command') do
|
|
44
|
+
image.reset_output_location
|
|
45
|
+
end
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
menu_item(:separator)
|
|
49
|
+
|
|
50
|
+
# menu_item(label: 'Preferences...', underline: 0) {
|
|
51
|
+
# on('command') do
|
|
52
|
+
# preferences_dialog(root: root, image: image)
|
|
53
|
+
# end
|
|
54
|
+
# }
|
|
55
|
+
|
|
56
|
+
menu_item(:separator)
|
|
57
|
+
|
|
58
|
+
menu_item(label: 'Exit', underline: 1) {
|
|
59
|
+
on('command') do
|
|
60
|
+
exit(0)
|
|
61
|
+
end
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
menu(label: 'Help') {
|
|
66
|
+
menu_item(:help) {
|
|
67
|
+
on('command') do
|
|
68
|
+
help_dialog(root: root)
|
|
69
|
+
end
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def show_about_dialog(root: )
|
|
76
|
+
message_box(parent: root, title: 'CryptoPunks GUI', message: "CryptoPunks GUI\n\n#{license}")
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def license
|
|
80
|
+
@license ||= File.read(LICENSE)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def help
|
|
84
|
+
@help ||= File.read(HELP)
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
class CryptopunksGui
|
|
2
|
+
module View
|
|
3
|
+
module PreferencesDialog
|
|
4
|
+
def preferences_dialog(root: , image: )
|
|
5
|
+
toplevel(root) {
|
|
6
|
+
title 'Preferences'
|
|
7
|
+
width 1280
|
|
8
|
+
height 700
|
|
9
|
+
escapable true
|
|
10
|
+
|
|
11
|
+
scrollbar_frame {
|
|
12
|
+
label {
|
|
13
|
+
grid row: 0, column: 0
|
|
14
|
+
text ''
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
label {
|
|
18
|
+
grid row: 0, column: 1
|
|
19
|
+
text 'Collection Name'
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
label {
|
|
23
|
+
grid row: 0, column: 2
|
|
24
|
+
text 'URL'
|
|
25
|
+
width 82
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
label {
|
|
29
|
+
grid row: 0, column: 3
|
|
30
|
+
text 'Width'
|
|
31
|
+
width 3
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
label {
|
|
35
|
+
grid row: 0, column: 4
|
|
36
|
+
text 'Height'
|
|
37
|
+
width 3
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
label {
|
|
41
|
+
grid row: 0, column: 5
|
|
42
|
+
text "Default\nZoom"
|
|
43
|
+
width 3
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
label {
|
|
47
|
+
grid row: 0, column: 6, column_span: 3
|
|
48
|
+
text 'Actions'
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
image.collections_map.each_with_index do |pair, index|
|
|
52
|
+
collection_name, collection_options = pair
|
|
53
|
+
row = index + 1
|
|
54
|
+
|
|
55
|
+
checkbutton { |cb|
|
|
56
|
+
grid row: row, column: 0
|
|
57
|
+
# TODO consider using hash_proxy object to bind more effectively
|
|
58
|
+
variable <= [image.collections_map[collection_name], :enabled]
|
|
59
|
+
|
|
60
|
+
on('command') do
|
|
61
|
+
collection_options[:enabled] = cb.variable
|
|
62
|
+
end
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
entry {
|
|
66
|
+
grid row: row, column: 1
|
|
67
|
+
text collection_name
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
entry {
|
|
71
|
+
grid row: row, column: 2
|
|
72
|
+
text collection_options[:url]
|
|
73
|
+
width 82
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
spinbox {
|
|
77
|
+
grid row: row, column: 3
|
|
78
|
+
from 1
|
|
79
|
+
to 512
|
|
80
|
+
text collection_options[:width]
|
|
81
|
+
width 3
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
spinbox {
|
|
85
|
+
grid row: row, column: 4
|
|
86
|
+
from 1
|
|
87
|
+
to 512
|
|
88
|
+
text collection_options[:height]
|
|
89
|
+
width 3
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
spinbox {
|
|
93
|
+
grid row: row, column: 5
|
|
94
|
+
from 1
|
|
95
|
+
to 72
|
|
96
|
+
text collection_options[:default_zoom]
|
|
97
|
+
width 3
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
button {
|
|
101
|
+
grid row: row, column: 6
|
|
102
|
+
text 'X'
|
|
103
|
+
width 1
|
|
104
|
+
}
|
|
105
|
+
button {
|
|
106
|
+
grid row: row, column: 7
|
|
107
|
+
text '^'
|
|
108
|
+
width 1
|
|
109
|
+
}
|
|
110
|
+
button {
|
|
111
|
+
grid row: row, column: 8
|
|
112
|
+
text 'v'
|
|
113
|
+
width 1
|
|
114
|
+
}
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
row = image.collections_map.keys.size + 1
|
|
118
|
+
|
|
119
|
+
checkbutton {
|
|
120
|
+
grid row: row, column: 0
|
|
121
|
+
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
entry {
|
|
125
|
+
grid row: row, column: 1
|
|
126
|
+
text ''
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
entry {
|
|
130
|
+
grid row: row, column: 2
|
|
131
|
+
text ''
|
|
132
|
+
width 82
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
spinbox {
|
|
136
|
+
grid row: row, column: 3
|
|
137
|
+
from 1
|
|
138
|
+
to 512
|
|
139
|
+
text '24'
|
|
140
|
+
width 3
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
spinbox {
|
|
144
|
+
grid row: row, column: 4
|
|
145
|
+
from 1
|
|
146
|
+
to 512
|
|
147
|
+
text '24'
|
|
148
|
+
width 3
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
spinbox {
|
|
152
|
+
grid row: row, column: 5
|
|
153
|
+
from 1
|
|
154
|
+
to 72
|
|
155
|
+
text '12'
|
|
156
|
+
width 3
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
frame {
|
|
161
|
+
button {
|
|
162
|
+
text 'Reset'
|
|
163
|
+
|
|
164
|
+
on('command') do
|
|
165
|
+
image.initialize_collections_map(reset: true)
|
|
166
|
+
# TODO cause an update to all collections
|
|
167
|
+
end
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
class CryptopunksGui
|
|
2
|
+
module View
|
|
3
|
+
module StyleOptionsFrame
|
|
4
|
+
def led_style_options_frame(image: )
|
|
5
|
+
frame {
|
|
6
|
+
padding 0
|
|
7
|
+
|
|
8
|
+
label {
|
|
9
|
+
grid row: 0, column: 0, column_weight: 0
|
|
10
|
+
text 'Spacing:'
|
|
11
|
+
}
|
|
12
|
+
spinbox {
|
|
13
|
+
grid row: 0, column: 1
|
|
14
|
+
from 1
|
|
15
|
+
to 72
|
|
16
|
+
text <=> [image, :led_spacing]
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
checkbutton {
|
|
20
|
+
grid row: 0, column: 2
|
|
21
|
+
variable <=> [image, :led_round_corner]
|
|
22
|
+
}
|
|
23
|
+
label {
|
|
24
|
+
grid row: 0, column: 3
|
|
25
|
+
text 'Round Corner'
|
|
26
|
+
|
|
27
|
+
on('Button-1') do
|
|
28
|
+
image.led_round_corner = !image.led_round_corner
|
|
29
|
+
end
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def sketch_style_options_frame(image: )
|
|
35
|
+
frame {
|
|
36
|
+
padding 0
|
|
37
|
+
|
|
38
|
+
label {
|
|
39
|
+
grid row: 0, column: 0, column_weight: 0
|
|
40
|
+
text 'Line:'
|
|
41
|
+
}
|
|
42
|
+
spinbox {
|
|
43
|
+
grid row: 0, column: 1
|
|
44
|
+
from 1
|
|
45
|
+
to 72
|
|
46
|
+
text <=> [image, :sketch_line]
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def no_style_options_frame
|
|
52
|
+
frame { # filler
|
|
53
|
+
padding 0
|
|
54
|
+
height 0
|
|
55
|
+
width 0
|
|
56
|
+
}
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
data/bin/cryptopunks-gui
CHANGED
|
File without changes
|