Class: CryptopunksGui

Inherits:
Object
  • Object
show all
Includes:
Glimmer
Defined in:
app/cryptopunks_gui.rb

Constant Summary collapse

PALETTES =
['Standard'] + (Palette8bit.constants).map(&:name).map {|palette| palette.split('_').map(&:capitalize).join(' ')}.reject { |palette| palette.include?(' ') }.sort
STYLES =
['Normal', 'Led', 'Sketch']
COLLECTION_URL_MAP =
{
  'Punks' => {url: 'https://raw.githubusercontent.com/larvalabs/cryptopunks/master/punks.png', width: 24, height: 24, default_zoom: 12},
  'Mohawks' => {url: 'https://raw.githubusercontent.com/cryptopunksnotdead/programming-cryptopunks/master/i/mohawks.png', width: 24, height: 24, default_zoom: 12},
  'Blondies' => {url: 'https://raw.githubusercontent.com/cryptopunksnotdead/programming-cryptopunks/master/i/blondies.png', width: 24, height: 24, default_zoom: 12},
  'Zombies' => {url: 'https://raw.githubusercontent.com/cryptopunksnotdead/programming-cryptopunks/master/i/zombies.png', width: 24, height: 24, default_zoom: 12},
  'Apes' => {url: 'https://raw.githubusercontent.com/cryptopunksnotdead/programming-cryptopunks/master/i/apes.png', width: 24, height: 24, default_zoom: 12},
  'Aliens' => {url: 'https://raw.githubusercontent.com/cryptopunksnotdead/programming-cryptopunks/master/i/aliens.png', width: 24, height: 24, default_zoom: 12},
  'Golden Punks' => {url: 'https://raw.githubusercontent.com/cryptopunksnotdead/awesome-24px/master/collection/goldenpunks.png', width: 24, height: 24, default_zoom: 12},
  'Halloween Punks' => {url: 'https://raw.githubusercontent.com/cryptopunksnotdead/awesome-24px/master/collection/halloweenpunks.png', width: 24, height: 24, default_zoom: 12},
  'Scream Punks' => {url: 'https://raw.githubusercontent.com/cryptopunksnotdead/cryptopunks/master/halloween/i/screampunks%402x.png', width: 48, height: 48, default_zoom: 6},
  "Jack 'O' Lantern Punks" => {url: 'https://raw.githubusercontent.com/cryptopunksnotdead/cryptopunks/master/halloween/i/jackpunks%402x.png', width: 48, height: 48, default_zoom: 6},
  'Joker Punks' => {url: 'https://raw.githubusercontent.com/cryptopunksnotdead/cryptopunks/master/halloween/i/jokerpunks%402x.png', width: 48, height: 48, default_zoom: 6},
  'Frankenstein Punks' => {url: 'https://raw.githubusercontent.com/cryptopunksnotdead/cryptopunks/master/halloween/i/frankensteinpunks%402x.png', width: 48, height: 48, default_zoom: 6},
  'Front Punks' => {url: 'https://raw.githubusercontent.com/cryptopunksnotdead/programming-cryptopunks/master/i/frontpunks.png', width: 24, height: 24, default_zoom: 12},
  'More Punks' => {url: 'https://raw.githubusercontent.com/cryptopunksnotdead/programming-cryptopunks/master/i/morepunks.png', width: 24, height: 24, default_zoom: 12},
  'Expansion Punks' => {url: 'https://expansionpunks.com/provenance/expansionpunks.png', width: 24, height: 24, default_zoom: 12},
  'Avalanche Punks' => {url: 'https://raw.githubusercontent.com/cryptopunksnotdead/awesome-24px/master/collection/avalanchepunks.png', width: 24, height: 24, default_zoom: 12},
  'International Punks' => {url: 'https://raw.githubusercontent.com/cryptopunksnotdead/awesome-24px/master/collection/intlpunks.png', width: 24, height: 24, default_zoom: 12},
  'Ape Punks' => {url: 'https://raw.githubusercontent.com/cryptopunksnotdead/awesome-24px/master/collection/apepunks.png', width: 24, height: 24, default_zoom: 12},
  'Alien Clan' => {url: 'https://raw.githubusercontent.com/cryptopunksnotdead/programming-cryptopunks/master/i/alienclan.png', width: 24, height: 24, default_zoom: 12},
  'Bored Apes' => {url: 'https://raw.githubusercontent.com/cryptopunksnotdead/awesome-24px/master/collection/boredapes.png', width: 28, height: 28, default_zoom: 10},
  'Bored Apes Blue' => {url: 'https://raw.githubusercontent.com/cryptopunksnotdead/awesome-24px/master/collection/boredapes_blue.png', width: 28, height: 28, default_zoom: 10},
  'Bored Apes Red' => {url: 'https://raw.githubusercontent.com/cryptopunksnotdead/awesome-24px/master/collection/boredapes_red.png', width: 28, height: 28, default_zoom: 10},
  'Bored Apes Neon Glow' => {url: 'https://raw.githubusercontent.com/cryptopunksnotdead/awesome-24px/master/collection/boredapes_neon_glow.png', width: 28, height: 28, default_zoom: 10},
  'Bored Apes Stars and Stripes' => {url: 'https://raw.githubusercontent.com/cryptopunksnotdead/awesome-24px/master/collection/boredapes_stars_and_stripes.png', width: 28, height: 28, default_zoom: 10},
  'Bored Apes Acid' => {url: 'https://raw.githubusercontent.com/cryptopunksnotdead/awesome-24px/master/collection/boredapes_acid.png', width: 28, height: 28, default_zoom: 10},
  'Cool Cats' => {url: 'https://raw.githubusercontent.com/cryptopunksnotdead/awesome-24px/master/collection/coolcats.png', width: 24, height: 24, default_zoom: 12},
  'Cool Cats Mohawks' => {url: 'https://raw.githubusercontent.com/cryptopunksnotdead/awesome-24px/master/collection/coolcats_mohawks.png', width: 24, height: 24, default_zoom: 12},
  'Cool Cats Ninjas' => {url: 'https://raw.githubusercontent.com/cryptopunksnotdead/awesome-24px/master/collection/coolcats_ninjas.png', width: 24, height: 24, default_zoom: 12},
  'Cool Cats TV Heads' => {url: 'https://raw.githubusercontent.com/cryptopunksnotdead/awesome-24px/master/collection/coolcats_tvheads.png', width: 24, height: 24, default_zoom: 12},
  'Cool Cats Pirates' => {url: 'https://raw.githubusercontent.com/cryptopunksnotdead/awesome-24px/master/collection/coolcats_pirates.png', width: 24, height: 24, default_zoom: 12},
  'Cool Cats Unicorns' => {url: 'https://raw.githubusercontent.com/cryptopunksnotdead/awesome-24px/master/collection/coolcats_unicorns.png', width: 24, height: 24, default_zoom: 12},
  'Cool Cats Dragons' => {url: 'https://raw.githubusercontent.com/cryptopunksnotdead/awesome-24px/master/collection/coolcats_dragons.png', width: 24, height: 24, default_zoom: 12},
  'Cool Cats Frogs' => {url: 'https://raw.githubusercontent.com/cryptopunksnotdead/awesome-24px/master/collection/coolcats_frogs.png', width: 24, height: 24, default_zoom: 12},
  'Pudgy Penguins' => {url: 'https://raw.githubusercontent.com/cryptopunksnotdead/awesome-24px/master/collection/pudgypenguins.png', width: 24, height: 24, default_zoom: 12},
  'Dodge' => {url: 'https://raw.githubusercontent.com/cryptopunksnotdead/programming-cryptopunks/master/i/dodge.png', width: 24, height: 24, default_zoom: 12},
  'Rocks' => {url: 'https://raw.githubusercontent.com/cryptopunksnotdead/awesome-24px/master/collection/rocks.png', width: 24, height: 24, default_zoom: 12},
  'Punk Rocks' => {url: 'https://raw.githubusercontent.com/cryptopunksnotdead/programming-cryptopunks/master/i/punkrocks.png', width: 24, height: 24, default_zoom: 12},
  'Tulips' => {url: 'https://raw.githubusercontent.com/cryptopunksnotdead/awesome-24px/master/collection/tulips.png', width: 24, height: 24, default_zoom: 12},
}

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeCryptopunksGui

Returns a new instance of CryptopunksGui.



59
60
61
62
63
64
65
66
67
68
# File 'app/cryptopunks_gui.rb', line 59

def initialize
  initialize_punk_directory
  initialize_collection
  load_config
  initialize_defaults
  observe_image_attribute_changes
  create_gui
  self.image_index = 0
  @root.open
end

Instance Attribute Details

#collectionObject

Returns the value of attribute collection.



57
58
59
# File 'app/cryptopunks_gui.rb', line 57

def collection
  @collection
end

#flipObject

Returns the value of attribute flip.



57
58
59
# File 'app/cryptopunks_gui.rb', line 57

def flip
  @flip
end

#image_indexObject

Returns the value of attribute image_index.



57
58
59
# File 'app/cryptopunks_gui.rb', line 57

def image_index
  @image_index
end

#led_round_cornerObject

Returns the value of attribute led_round_corner.



57
58
59
# File 'app/cryptopunks_gui.rb', line 57

def led_round_corner
  @led_round_corner
end

#led_spacingObject

Returns the value of attribute led_spacing.



57
58
59
# File 'app/cryptopunks_gui.rb', line 57

def led_spacing
  @led_spacing
end

#mirrorObject

Returns the value of attribute mirror.



57
58
59
# File 'app/cryptopunks_gui.rb', line 57

def mirror
  @mirror
end

#paletteObject

Returns the value of attribute palette.



57
58
59
# File 'app/cryptopunks_gui.rb', line 57

def palette
  @palette
end

#sketch_lineObject

Returns the value of attribute sketch_line.



57
58
59
# File 'app/cryptopunks_gui.rb', line 57

def sketch_line
  @sketch_line
end

#styleObject

Returns the value of attribute style.



57
58
59
# File 'app/cryptopunks_gui.rb', line 57

def style
  @style
end

#zoomObject

Returns the value of attribute zoom.



57
58
59
# File 'app/cryptopunks_gui.rb', line 57

def zoom
  @zoom
end

Instance Method Details

#add_style_optionsObject



289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
# File 'app/cryptopunks_gui.rb', line 289

def add_style_options
  @style_options_frame.content {
    @style_options_frame.children.each(&:destroy)
    if @style == 'Led'
      frame {
        padding 0
        
        label {
          grid row: 0, column: 0, column_weight: 0
          text 'Spacing:'
        }
        spinbox {
          grid row: 0, column: 1
          from 1
          to 72
          text <=> [self, :led_spacing]
        }
        
        checkbutton {
          grid row: 0, column: 2
          variable <=> [self, :led_round_corner]
        }
        label {
          grid row: 0, column: 3
          text 'Round Corner'
          
          on('Button-1') do
            self.led_round_corner = !led_round_corner
          end
        }
      }
    elsif @style == 'Sketch'
      frame {
        padding 0
        
        label {
          grid row: 0, column: 0, column_weight: 0
          text 'Line:'
        }
        spinbox {
          grid row: 0, column: 1
          from 1
          to 72
          text <=> [self, :sketch_line]
        }
      }
    else
      frame { # filler
        padding 0
        height 0
        width 0
      }
    end
  }
end

#collection_optionsObject



70
71
72
# File 'app/cryptopunks_gui.rb', line 70

def collection_options
  COLLECTION_URL_MAP.keys
end

#create_guiObject



172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
# File 'app/cryptopunks_gui.rb', line 172

def create_gui
  @root = root {
    title 'CryptoPunks GUI'
    iconphoto File.expand_path('../icons/cryptopunks-gui.png', __dir__)
    
    frame {
      label {
        text 'Collection:'
      }
      combobox {
        readonly true
        text <=> [self, :collection]
      }
      
      label {
        text 'Image Index:'
      }
      @image_index_spinbox = spinbox {
        from 0
        to @images[@collection].size - 1
        text <=> [self, :image_index]
      }
      
      label {
        text 'Zoom:'
      }
      spinbox {
        from 1
        to 72
        text <=> [self, :zoom]
      }
      
      label {
        text 'Palette:'
      }
      combobox {
        readonly true
        text <=> [self, :palette]
      }
      
      label {
        text 'Style:'
      }
      combobox {
        readonly true
        text <=> [self, :style, after_write: ->(val) {add_style_options}]
      }
      
      @style_options_frame = frame {
        padding 0
      }
      
      frame {
        padding 0
        
        checkbutton {
          grid row: 0, column: 0, column_weight: 0
          variable <=> [self, :mirror]
        }
        label {
          grid row: 0, column: 1
          text 'Mirror'
          
          on('Button-1') do
            self.mirror = !mirror
          end
        }
        
        checkbutton {
          grid row: 0, column: 2
          variable <=> [self, :flip]
        }
        label {
          grid row: 0, column: 3
          text 'Flip'
          
          on('Button-1') do
            self.flip = !flip
          end
        }
      }
      
      label {
        text 'Output Location:'
      }
      frame {
        padding 0
        
        @output_location_entry = entry {
          grid row: 0, column: 0
          readonly true
          width 47
        }
        button {
          grid row: 0, column: 1
          text '...'
          width 1.1
          
          on('command') do
            new_punk_directory = choose_directory(parent: @root)
            unless new_punk_directory.to_s.empty?
              @punk_directory = new_punk_directory
              @punk_config[:punk_directory] = @punk_directory
              save_config
              generate_image
            end
          end
        }
      }
      
      @image_label = label {
        grid row_weight: 1
      }
    }
  }
end

#generate_imageObject



139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'app/cryptopunks_gui.rb', line 139

def generate_image
  initialize_collection
  return if @image_index.to_i > @images[@collection].size
  image_location = File.join(@punk_directory, "#{@collection.gsub(' ', '').downcase}-#{@image_index}#{"x#{@zoom}" if @zoom.to_i > 1}#{"-#{@palette.underscore}" if @palette != PALETTES.first}#{"-#{@style.underscore}" if @style != STYLES.first}.png")
  puts "Writing punk image to #{image_location}"
  selected_punk = @images[@collection][@image_index.to_i]
  selected_punk = selected_punk.change_palette8bit(Palette8bit.const_get(@palette.gsub(' ', '_').upcase.to_sym)) if @palette != PALETTES.first
  @original_zoom = @zoom
  if @previous_collection && @collection != @previous_collection && COLLECTION_URL_MAP[@collection][:width] != COLLECTION_URL_MAP[@previous_collection][:width]
    @zoom = COLLECTION_URL_MAP[@collection][:default_zoom]
  end
  if @style != STYLES.first
    style_options = {}
    if @style == 'Led'
      style_options[:spacing] = @led_spacing.to_i
      style_options[:round_corner] = @led_round_corner
    end
    if @style == 'Sketch'
      style_options[:line] = @sketch_line.to_i
    end
    selected_punk = selected_punk.send(@style.underscore, @zoom.to_i, **style_options)
  end
  selected_punk = selected_punk.mirror if @mirror
  selected_punk = selected_punk.flip if @flip
  selected_punk = selected_punk.zoom(@zoom.to_i) if @style == STYLES.first
  selected_punk.save(image_location)
  @image_label.image = image_location
  @output_location_entry.text = image_location
  @previous_style = @style
  @previous_collection = @collection
  notify_observers(:zoom) if @zoom != @original_zoom
end

#initialize_collectionObject



87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'app/cryptopunks_gui.rb', line 87

def initialize_collection
  return if @collection && @collection == @last_collection
  @collection ||= COLLECTION_URL_MAP.keys.first
  url = COLLECTION_URL_MAP[@collection][:url]
  width = COLLECTION_URL_MAP[@collection][:width]
  height = COLLECTION_URL_MAP[@collection][:height]
  @punk_file = File.join(@punk_config_directory, File.basename(url, '.png'))
  File.write(@punk_file, Net::HTTP.get(URI(url))) unless File.exist?(@punk_file)
  @images ||= {}
  @images[@collection] ||= Punks::Image::Composite.read(@punk_file, width: width, height: height)
  @last_collection = @collection
  self.image_index = 0
  @image_index_spinbox.to = @images[@collection].size - 1 if @image_index_spinbox
end

#initialize_defaultsObject



113
114
115
116
117
118
119
120
121
122
123
# File 'app/cryptopunks_gui.rb', line 113

def initialize_defaults
  @collection = COLLECTION_URL_MAP.keys.first
  @zoom = 12
  @palette = PALETTES.first
  @style = STYLES.first
  @led_spacing = 2
  @led_round_corner = false
  @sketch_line = 1
  @mirror = false
  @flip = false
end

#initialize_punk_directoryObject



82
83
84
85
# File 'app/cryptopunks_gui.rb', line 82

def initialize_punk_directory
  @punk_directory = @punk_config_directory = File.join(Dir.home, 'cryptopunks')
  FileUtils.mkdir_p(@punk_directory)
end

#load_configObject



102
103
104
105
106
107
# File 'app/cryptopunks_gui.rb', line 102

def load_config
  @punk_config_file = File.join(@punk_config_directory, 'cryptopunks.yml')
  FileUtils.touch(@punk_config_file)
  @punk_config = YAML.load(File.read(@punk_config_file)) || {punk_directory: @punk_directory}
  @punk_directory = @punk_config[:punk_directory]
end

#observe_image_attribute_changesObject



125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'app/cryptopunks_gui.rb', line 125

def observe_image_attribute_changes
  observer = Glimmer::DataBinding::Observer.proc { generate_image }
  observer.observe(self, :collection)
  observer.observe(self, :image_index)
  observer.observe(self, :zoom)
  observer.observe(self, :palette)
  observer.observe(self, :style)
  observer.observe(self, :led_spacing)
  observer.observe(self, :led_round_corner)
  observer.observe(self, :sketch_line)
  observer.observe(self, :mirror)
  observer.observe(self, :flip)
end

#palette_optionsObject



74
75
76
# File 'app/cryptopunks_gui.rb', line 74

def palette_options
  PALETTES
end

#save_configObject



109
110
111
# File 'app/cryptopunks_gui.rb', line 109

def save_config
  File.write(@punk_config_file, YAML.dump(@punk_config))
end

#style_optionsObject



78
79
80
# File 'app/cryptopunks_gui.rb', line 78

def style_options
  STYLES
end