cryptopunks-gui 0.0.11 → 0.0.12
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 +10 -0
- data/LICENSE.txt +1 -1
- data/README.md +5 -5
- data/VERSION +1 -1
- data/app/cryptopunks_gui.rb +17 -298
- 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/cryptopunks-gui.gemspec +12 -6
- metadata +13 -7
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: ce9f96af3964a08b2afadfa66fffae558338ced44cc09871fb3e967eeff84bc0
         | 
| 4 | 
            +
              data.tar.gz: 669c2e11acfda26508c3494b4cf66bfd3213fac457b30257dfb6edf2dd590fc8
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 0e8be7e8519cb582a373acfa18d93ad4f62f954c7c8f0278694a66481e828ee248133caffbf2f0a73ce86ae7c8398ef24287d7b834da637b5db7923847ea4aad
         | 
| 7 | 
            +
              data.tar.gz: '068c1cc0ea6687d2e5c915673973897febd2613b37569d349502031414b798b53aa7de85ab591c69968d21e99a6f81c223710dd476653ee8a0f69fc37f2b65bd'
         | 
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -1,5 +1,15 @@ | |
| 1 1 | 
             
            # Change Log
         | 
| 2 2 |  | 
| 3 | 
            +
            ## 0.0.12
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            - Upgrade to glimmer-dsl-tk 0.0.46
         | 
| 6 | 
            +
            - File & Help Menus
         | 
| 7 | 
            +
            - Update COLLECTIONS_YAML_URL to point to cryptopunksnotdead repository (recently moved there)
         | 
| 8 | 
            +
            - Add 'Mirror', 'Flip', 'Led' and 'Sketch' details (e.g. spacing or line) to output file name (e.g. '...-mirror.png')
         | 
| 9 | 
            +
            - Fix issue with allowing out of bounds image index when entering index that is equal to count of images in a collection (off by 1 error)
         | 
| 10 | 
            +
            - Fix written file name for downloaded sprites (was excluding .png before)
         | 
| 11 | 
            +
            - Fix issue with @punk_directory mistakenly referenced after being removed through refactoring
         | 
| 12 | 
            +
             | 
| 3 13 | 
             
            ## 0.0.11
         | 
| 4 14 |  | 
| 5 15 | 
             
            - Support configuring default collections through a web hosted yaml file at: https://raw.githubusercontent.com/AndyObtiva/cryptopunks-gui/master/cryptopunks-collections.yml
         | 
    
        data/LICENSE.txt
    CHANGED
    
    
    
        data/README.md
    CHANGED
    
    | @@ -1,8 +1,8 @@ | |
| 1 | 
            -
            # <img src="https://raw.githubusercontent.com/AndyObtiva/cryptopunks-gui/master/icons/cryptopunks-gui.png" height=85 /> CryptoPunks GUI 0.0. | 
| 1 | 
            +
            # <img src="https://raw.githubusercontent.com/AndyObtiva/cryptopunks-gui/master/icons/cryptopunks-gui.png" height=85 /> CryptoPunks GUI 0.0.12
         | 
| 2 2 | 
             
            ## Simplified Minting
         | 
| 3 3 | 
             
            [](http://badge.fury.io/rb/cryptopunks-gui)
         | 
| 4 4 |  | 
| 5 | 
            -
            This is a Graphical User Interface for the  | 
| 5 | 
            +
            This is a Graphical User Interface for the [cryptopunks Ruby gem](https://github.com/cryptopunksnotdead/cryptopunks/tree/master/cryptopunks).
         | 
| 6 6 |  | 
| 7 7 | 
             
            It automatically downloads image collection sprites on first use (e.g. `punks.png` from https://github.com/larvalabs/cryptopunks).
         | 
| 8 8 |  | 
| @@ -18,14 +18,14 @@ Minted cryptopunks are stored at `~/cryptopunks/` by default ([output location c | |
| 18 18 |  | 
| 19 19 | 
             
            ## Setup
         | 
| 20 20 |  | 
| 21 | 
            -
            You can use CryptoPunks GUI via gem or via cloning repository.
         | 
| 21 | 
            +
            You can use CryptoPunks GUI via gem or via cloning repository (if you encounter any issues, please try older versions of the gem and report the issues encountered).
         | 
| 22 22 |  | 
| 23 23 | 
             
            ### Gem
         | 
| 24 24 |  | 
| 25 25 | 
             
            Run:
         | 
| 26 26 |  | 
| 27 27 | 
             
            ```
         | 
| 28 | 
            -
            gem install cryptopunks-gui -v0.0. | 
| 28 | 
            +
            gem install cryptopunks-gui -v0.0.12
         | 
| 29 29 | 
             
            ```
         | 
| 30 30 |  | 
| 31 31 | 
             
            Afterwards, run app via:
         | 
| @@ -236,7 +236,7 @@ You may select a new output location by clicking on the `...` button. | |
| 236 236 |  | 
| 237 237 | 
             
            [MIT](LICENSE.txt)
         | 
| 238 238 |  | 
| 239 | 
            -
            Copyright (c) 2021 - Cryptopunks GUI by [ | 
| 239 | 
            +
            Copyright (c) 2021 - Cryptopunks GUI by [Crypto Punk's Not Dead](https://github.com/cryptopunksnotdead)
         | 
| 240 240 |  | 
| 241 241 | 
             
            --
         | 
| 242 242 |  | 
    
        data/VERSION
    CHANGED
    
    | @@ -1 +1 @@ | |
| 1 | 
            -
            0.0. | 
| 1 | 
            +
            0.0.12
         | 
    
        data/app/cryptopunks_gui.rb
    CHANGED
    
    | @@ -1,323 +1,42 @@ | |
| 1 1 | 
             
            require 'glimmer-dsl-tk'
         | 
| 2 | 
            +
            require 'glimmer/data_binding/observer'
         | 
| 2 3 | 
             
            require 'cryptopunks'
         | 
| 3 4 | 
             
            require 'facets'
         | 
| 4 5 | 
             
            require 'fileutils'
         | 
| 5 6 | 
             
            require 'net/http'
         | 
| 6 7 | 
             
            require 'uri'
         | 
| 7 | 
            -
            require 'glimmer/data_binding/observer'
         | 
| 8 8 | 
             
            require 'yaml'
         | 
| 9 9 | 
             
            require 'puts_debuggerer'
         | 
| 10 10 |  | 
| 11 | 
            +
            require_relative 'model/image'
         | 
| 12 | 
            +
            require_relative 'view/menu_bar'
         | 
| 13 | 
            +
            require_relative 'view/image_frame'
         | 
| 14 | 
            +
            require_relative 'view/style_options_frame'
         | 
| 15 | 
            +
             | 
| 11 16 | 
             
            class CryptopunksGui
         | 
| 12 17 | 
             
              include Glimmer
         | 
| 13 | 
            -
              
         | 
| 14 | 
            -
               | 
| 15 | 
            -
               | 
| 16 | 
            -
              COLLECTIONS_YAML_URL = 'https://raw.githubusercontent.com/AndyObtiva/cryptopunks-gui/master/cryptopunks-collections.yml'
         | 
| 17 | 
            -
              COLLECTIONS_YAML_PATH = File.expand_path('../cryptopunks-collections.yml', __dir__)
         | 
| 18 | 
            -
              
         | 
| 19 | 
            -
              attr_accessor :collection, :image_index, :zoom, :palette, :style, :led_spacing, :led_round_corner, :sketch_line, :flip, :mirror
         | 
| 18 | 
            +
              include View::MenuBar
         | 
| 19 | 
            +
              include View::ImageFrame
         | 
| 20 | 
            +
              include View::StyleOptionsFrame
         | 
| 20 21 |  | 
| 21 22 | 
             
              def initialize
         | 
| 22 | 
            -
                 | 
| 23 | 
            -
                initialize_collections_map
         | 
| 24 | 
            -
                initialize_collection
         | 
| 25 | 
            -
                load_config
         | 
| 26 | 
            -
                initialize_defaults
         | 
| 27 | 
            -
                observe_image_attribute_changes
         | 
| 23 | 
            +
                @image = Model::Image.new
         | 
| 28 24 | 
             
                create_gui
         | 
| 29 | 
            -
                 | 
| 30 | 
            -
                @root.open
         | 
| 31 | 
            -
              end
         | 
| 32 | 
            -
              
         | 
| 33 | 
            -
              def collection_options
         | 
| 34 | 
            -
                @collections_map.keys
         | 
| 35 | 
            -
              end
         | 
| 36 | 
            -
              
         | 
| 37 | 
            -
              def palette_options
         | 
| 38 | 
            -
                PALETTES
         | 
| 39 | 
            -
              end
         | 
| 40 | 
            -
              
         | 
| 41 | 
            -
              def style_options
         | 
| 42 | 
            -
                STYLES
         | 
| 43 | 
            -
              end
         | 
| 44 | 
            -
              
         | 
| 45 | 
            -
              def initialize_punk_directory
         | 
| 46 | 
            -
                @punk_directory = @punk_config_directory = File.join(Dir.home, 'cryptopunks')
         | 
| 47 | 
            -
                FileUtils.mkdir_p(@punk_directory)
         | 
| 48 | 
            -
              end
         | 
| 49 | 
            -
              
         | 
| 50 | 
            -
              def initialize_collections_map
         | 
| 51 | 
            -
                begin
         | 
| 52 | 
            -
                  http_response = Net::HTTP.get_response(URI(COLLECTIONS_YAML_URL))
         | 
| 53 | 
            -
                  if http_response.is_a?(Net::HTTPSuccess)
         | 
| 54 | 
            -
                    @collections_map = YAML.load(http_response.body)
         | 
| 55 | 
            -
                  else
         | 
| 56 | 
            -
                    raise "code: #{http_response.code} message: #{http_response.message}"
         | 
| 57 | 
            -
                  end
         | 
| 58 | 
            -
                rescue StandardError, SocketError => e
         | 
| 59 | 
            -
                  puts "Failed to utilize collection YAML from: #{COLLECTIONS_YAML_URL}"
         | 
| 60 | 
            -
                  puts e.full_message
         | 
| 61 | 
            -
                  puts "Utilizing local collection YAML instead: #{COLLECTIONS_YAML_PATH}"
         | 
| 62 | 
            -
                  @collections_map = YAML.load(File.read(COLLECTIONS_YAML_PATH))
         | 
| 63 | 
            -
                end
         | 
| 25 | 
            +
                @image.image_index = 0
         | 
| 64 26 | 
             
              end
         | 
| 65 27 |  | 
| 66 | 
            -
              def  | 
| 67 | 
            -
                 | 
| 68 | 
            -
                @collection ||= @collections_map.keys.first
         | 
| 69 | 
            -
                url = @collections_map[@collection][:url]
         | 
| 70 | 
            -
                width = @collections_map[@collection][:width]
         | 
| 71 | 
            -
                height = @collections_map[@collection][:height]
         | 
| 72 | 
            -
                @punk_file = File.join(@punk_config_directory, File.basename(url, '.png'))
         | 
| 73 | 
            -
                File.write(@punk_file, Net::HTTP.get(URI(url))) unless File.exist?(@punk_file)
         | 
| 74 | 
            -
                @images ||= {}
         | 
| 75 | 
            -
                @images[@collection] ||= Punks::Image::Composite.read(@punk_file, width: width, height: height)
         | 
| 76 | 
            -
                @last_collection = @collection
         | 
| 77 | 
            -
                self.image_index = 0
         | 
| 78 | 
            -
                @image_index_spinbox.to = @images[@collection].size - 1 if @image_index_spinbox
         | 
| 79 | 
            -
              end
         | 
| 80 | 
            -
              
         | 
| 81 | 
            -
              def load_config
         | 
| 82 | 
            -
                @punk_config_file = File.join(@punk_config_directory, 'cryptopunks.yml')
         | 
| 83 | 
            -
                FileUtils.touch(@punk_config_file)
         | 
| 84 | 
            -
                @punk_config = YAML.load(File.read(@punk_config_file)) || {punk_directory: @punk_directory}
         | 
| 85 | 
            -
                @punk_directory = @punk_config[:punk_directory]
         | 
| 86 | 
            -
              end
         | 
| 87 | 
            -
              
         | 
| 88 | 
            -
              def save_config
         | 
| 89 | 
            -
                File.write(@punk_config_file, YAML.dump(@punk_config))
         | 
| 90 | 
            -
              end
         | 
| 91 | 
            -
              
         | 
| 92 | 
            -
              def initialize_defaults
         | 
| 93 | 
            -
                @collection = @collections_map.keys.first
         | 
| 94 | 
            -
                @zoom = 12
         | 
| 95 | 
            -
                @palette = PALETTES.first
         | 
| 96 | 
            -
                @style = STYLES.first
         | 
| 97 | 
            -
                @led_spacing = 2
         | 
| 98 | 
            -
                @led_round_corner = false
         | 
| 99 | 
            -
                @sketch_line = 1
         | 
| 100 | 
            -
                @mirror = false
         | 
| 101 | 
            -
                @flip = false
         | 
| 102 | 
            -
              end
         | 
| 103 | 
            -
              
         | 
| 104 | 
            -
              def observe_image_attribute_changes
         | 
| 105 | 
            -
                observer = Glimmer::DataBinding::Observer.proc { generate_image }
         | 
| 106 | 
            -
                observer.observe(self, :collection)
         | 
| 107 | 
            -
                observer.observe(self, :image_index)
         | 
| 108 | 
            -
                observer.observe(self, :zoom)
         | 
| 109 | 
            -
                observer.observe(self, :palette)
         | 
| 110 | 
            -
                observer.observe(self, :style)
         | 
| 111 | 
            -
                observer.observe(self, :led_spacing)
         | 
| 112 | 
            -
                observer.observe(self, :led_round_corner)
         | 
| 113 | 
            -
                observer.observe(self, :sketch_line)
         | 
| 114 | 
            -
                observer.observe(self, :mirror)
         | 
| 115 | 
            -
                observer.observe(self, :flip)
         | 
| 116 | 
            -
              end
         | 
| 117 | 
            -
              
         | 
| 118 | 
            -
              def generate_image
         | 
| 119 | 
            -
                initialize_collection
         | 
| 120 | 
            -
                return if @image_index.to_i > @images[@collection].size
         | 
| 121 | 
            -
                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")
         | 
| 122 | 
            -
                puts "Writing punk image to #{image_location}"
         | 
| 123 | 
            -
                selected_punk = @images[@collection][@image_index.to_i]
         | 
| 124 | 
            -
                selected_punk = selected_punk.change_palette8bit(Palette8bit.const_get(@palette.gsub(' ', '_').upcase.to_sym)) if @palette != PALETTES.first
         | 
| 125 | 
            -
                @original_zoom = @zoom
         | 
| 126 | 
            -
                if @previous_collection && @collection != @previous_collection && @collections_map[@collection][:width] != @collections_map[@previous_collection][:width]
         | 
| 127 | 
            -
                  @zoom = @collections_map[@collection][:default_zoom]
         | 
| 128 | 
            -
                end
         | 
| 129 | 
            -
                if @style != STYLES.first
         | 
| 130 | 
            -
                  style_options = {}
         | 
| 131 | 
            -
                  if @style == 'Led'
         | 
| 132 | 
            -
                    style_options[:spacing] = @led_spacing.to_i
         | 
| 133 | 
            -
                    style_options[:round_corner] = @led_round_corner
         | 
| 134 | 
            -
                  end
         | 
| 135 | 
            -
                  if @style == 'Sketch'
         | 
| 136 | 
            -
                    style_options[:line] = @sketch_line.to_i
         | 
| 137 | 
            -
                  end
         | 
| 138 | 
            -
                  selected_punk = selected_punk.send(@style.underscore, @zoom.to_i, **style_options)
         | 
| 139 | 
            -
                end
         | 
| 140 | 
            -
                selected_punk = selected_punk.mirror if @mirror
         | 
| 141 | 
            -
                selected_punk = selected_punk.flip if @flip
         | 
| 142 | 
            -
                selected_punk = selected_punk.zoom(@zoom.to_i) if @style == STYLES.first
         | 
| 143 | 
            -
                selected_punk.save(image_location)
         | 
| 144 | 
            -
                @image_label.image = image_location
         | 
| 145 | 
            -
                @output_location_entry.text = image_location
         | 
| 146 | 
            -
                @previous_style = @style
         | 
| 147 | 
            -
                @previous_collection = @collection
         | 
| 148 | 
            -
                notify_observers(:zoom) if @zoom != @original_zoom
         | 
| 28 | 
            +
              def launch
         | 
| 29 | 
            +
                @root.open
         | 
| 149 30 | 
             
              end
         | 
| 150 31 |  | 
| 151 32 | 
             
              def create_gui
         | 
| 152 | 
            -
                @root = root {
         | 
| 33 | 
            +
                @root = root { |root_proxy|
         | 
| 153 34 | 
             
                  title 'CryptoPunks GUI'
         | 
| 154 35 | 
             
                  iconphoto File.expand_path('../icons/cryptopunks-gui.png', __dir__)
         | 
| 155 36 |  | 
| 156 | 
            -
                   | 
| 157 | 
            -
             | 
| 158 | 
            -
             | 
| 159 | 
            -
                    }
         | 
| 160 | 
            -
                    combobox {
         | 
| 161 | 
            -
                      readonly true
         | 
| 162 | 
            -
                      text <=> [self, :collection]
         | 
| 163 | 
            -
                    }
         | 
| 164 | 
            -
                    
         | 
| 165 | 
            -
                    label {
         | 
| 166 | 
            -
                      text 'Image Index:'
         | 
| 167 | 
            -
                    }
         | 
| 168 | 
            -
                    @image_index_spinbox = spinbox {
         | 
| 169 | 
            -
                      from 0
         | 
| 170 | 
            -
                      to @images[@collection].size - 1
         | 
| 171 | 
            -
                      text <=> [self, :image_index]
         | 
| 172 | 
            -
                    }
         | 
| 173 | 
            -
                    
         | 
| 174 | 
            -
                    label {
         | 
| 175 | 
            -
                      text 'Zoom:'
         | 
| 176 | 
            -
                    }
         | 
| 177 | 
            -
                    spinbox {
         | 
| 178 | 
            -
                      from 1
         | 
| 179 | 
            -
                      to 72
         | 
| 180 | 
            -
                      text <=> [self, :zoom]
         | 
| 181 | 
            -
                    }
         | 
| 182 | 
            -
                    
         | 
| 183 | 
            -
                    label {
         | 
| 184 | 
            -
                      text 'Palette:'
         | 
| 185 | 
            -
                    }
         | 
| 186 | 
            -
                    combobox {
         | 
| 187 | 
            -
                      readonly true
         | 
| 188 | 
            -
                      text <=> [self, :palette]
         | 
| 189 | 
            -
                    }
         | 
| 190 | 
            -
                    
         | 
| 191 | 
            -
                    label {
         | 
| 192 | 
            -
                      text 'Style:'
         | 
| 193 | 
            -
                    }
         | 
| 194 | 
            -
                    combobox {
         | 
| 195 | 
            -
                      readonly true
         | 
| 196 | 
            -
                      text <=> [self, :style, after_write: ->(val) {add_style_options}]
         | 
| 197 | 
            -
                    }
         | 
| 198 | 
            -
                    
         | 
| 199 | 
            -
                    @style_options_frame = frame {
         | 
| 200 | 
            -
                      padding 0
         | 
| 201 | 
            -
                    }
         | 
| 202 | 
            -
                    
         | 
| 203 | 
            -
                    frame {
         | 
| 204 | 
            -
                      padding 0
         | 
| 205 | 
            -
                      
         | 
| 206 | 
            -
                      checkbutton {
         | 
| 207 | 
            -
                        grid row: 0, column: 0, column_weight: 0
         | 
| 208 | 
            -
                        variable <=> [self, :mirror]
         | 
| 209 | 
            -
                      }
         | 
| 210 | 
            -
                      label {
         | 
| 211 | 
            -
                        grid row: 0, column: 1
         | 
| 212 | 
            -
                        text 'Mirror'
         | 
| 213 | 
            -
                        
         | 
| 214 | 
            -
                        on('Button-1') do
         | 
| 215 | 
            -
                          self.mirror = !mirror
         | 
| 216 | 
            -
                        end
         | 
| 217 | 
            -
                      }
         | 
| 218 | 
            -
                      
         | 
| 219 | 
            -
                      checkbutton {
         | 
| 220 | 
            -
                        grid row: 0, column: 2
         | 
| 221 | 
            -
                        variable <=> [self, :flip]
         | 
| 222 | 
            -
                      }
         | 
| 223 | 
            -
                      label {
         | 
| 224 | 
            -
                        grid row: 0, column: 3
         | 
| 225 | 
            -
                        text 'Flip'
         | 
| 226 | 
            -
                        
         | 
| 227 | 
            -
                        on('Button-1') do
         | 
| 228 | 
            -
                          self.flip = !flip
         | 
| 229 | 
            -
                        end
         | 
| 230 | 
            -
                      }
         | 
| 231 | 
            -
                    }
         | 
| 232 | 
            -
                    
         | 
| 233 | 
            -
                    label {
         | 
| 234 | 
            -
                      text 'Output Location:'
         | 
| 235 | 
            -
                    }
         | 
| 236 | 
            -
                    frame {
         | 
| 237 | 
            -
                      padding 0
         | 
| 238 | 
            -
                      
         | 
| 239 | 
            -
                      @output_location_entry = entry {
         | 
| 240 | 
            -
                        grid row: 0, column: 0
         | 
| 241 | 
            -
                        readonly true
         | 
| 242 | 
            -
                        width 47
         | 
| 243 | 
            -
                      }
         | 
| 244 | 
            -
                      button {
         | 
| 245 | 
            -
                        grid row: 0, column: 1
         | 
| 246 | 
            -
                        text '...'
         | 
| 247 | 
            -
                        width 1.1
         | 
| 248 | 
            -
                        
         | 
| 249 | 
            -
                        on('command') do
         | 
| 250 | 
            -
                          new_punk_directory = choose_directory(parent: @root)
         | 
| 251 | 
            -
                          unless new_punk_directory.to_s.empty?
         | 
| 252 | 
            -
                            @punk_directory = new_punk_directory
         | 
| 253 | 
            -
                            @punk_config[:punk_directory] = @punk_directory
         | 
| 254 | 
            -
                            save_config
         | 
| 255 | 
            -
                            generate_image
         | 
| 256 | 
            -
                          end
         | 
| 257 | 
            -
                        end
         | 
| 258 | 
            -
                      }
         | 
| 259 | 
            -
                    }
         | 
| 260 | 
            -
                    
         | 
| 261 | 
            -
                    @image_label = label {
         | 
| 262 | 
            -
                      grid row_weight: 1
         | 
| 263 | 
            -
                    }
         | 
| 264 | 
            -
                  }
         | 
| 265 | 
            -
                }
         | 
| 266 | 
            -
              end
         | 
| 267 | 
            -
              
         | 
| 268 | 
            -
              def add_style_options
         | 
| 269 | 
            -
                @style_options_frame.content {
         | 
| 270 | 
            -
                  @style_options_frame.children.each(&:destroy)
         | 
| 271 | 
            -
                  if @style == 'Led'
         | 
| 272 | 
            -
                    frame {
         | 
| 273 | 
            -
                      padding 0
         | 
| 274 | 
            -
                      
         | 
| 275 | 
            -
                      label {
         | 
| 276 | 
            -
                        grid row: 0, column: 0, column_weight: 0
         | 
| 277 | 
            -
                        text 'Spacing:'
         | 
| 278 | 
            -
                      }
         | 
| 279 | 
            -
                      spinbox {
         | 
| 280 | 
            -
                        grid row: 0, column: 1
         | 
| 281 | 
            -
                        from 1
         | 
| 282 | 
            -
                        to 72
         | 
| 283 | 
            -
                        text <=> [self, :led_spacing]
         | 
| 284 | 
            -
                      }
         | 
| 285 | 
            -
                      
         | 
| 286 | 
            -
                      checkbutton {
         | 
| 287 | 
            -
                        grid row: 0, column: 2
         | 
| 288 | 
            -
                        variable <=> [self, :led_round_corner]
         | 
| 289 | 
            -
                      }
         | 
| 290 | 
            -
                      label {
         | 
| 291 | 
            -
                        grid row: 0, column: 3
         | 
| 292 | 
            -
                        text 'Round Corner'
         | 
| 293 | 
            -
                        
         | 
| 294 | 
            -
                        on('Button-1') do
         | 
| 295 | 
            -
                          self.led_round_corner = !led_round_corner
         | 
| 296 | 
            -
                        end
         | 
| 297 | 
            -
                      }
         | 
| 298 | 
            -
                    }
         | 
| 299 | 
            -
                  elsif @style == 'Sketch'
         | 
| 300 | 
            -
                    frame {
         | 
| 301 | 
            -
                      padding 0
         | 
| 302 | 
            -
                      
         | 
| 303 | 
            -
                      label {
         | 
| 304 | 
            -
                        grid row: 0, column: 0, column_weight: 0
         | 
| 305 | 
            -
                        text 'Line:'
         | 
| 306 | 
            -
                      }
         | 
| 307 | 
            -
                      spinbox {
         | 
| 308 | 
            -
                        grid row: 0, column: 1
         | 
| 309 | 
            -
                        from 1
         | 
| 310 | 
            -
                        to 72
         | 
| 311 | 
            -
                        text <=> [self, :sketch_line]
         | 
| 312 | 
            -
                      }
         | 
| 313 | 
            -
                    }
         | 
| 314 | 
            -
                  else
         | 
| 315 | 
            -
                    frame { # filler
         | 
| 316 | 
            -
                      padding 0
         | 
| 317 | 
            -
                      height 0
         | 
| 318 | 
            -
                      width 0
         | 
| 319 | 
            -
                    }
         | 
| 320 | 
            -
                  end
         | 
| 37 | 
            +
                  cryptopunks_gui_menu_bar(root: root_proxy, image: @image)
         | 
| 38 | 
            +
                  
         | 
| 39 | 
            +
                  image_frame(root: root_proxy, image: @image)
         | 
| 321 40 | 
             
                }
         | 
| 322 41 | 
             
              end
         | 
| 323 42 | 
             
            end
         | 
    
        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(&:name).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.write(@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, :images)
         | 
| 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/cryptopunks-gui.gemspec
    CHANGED
    
    | @@ -2,16 +2,16 @@ | |
| 2 2 | 
             
            # DO NOT EDIT THIS FILE DIRECTLY
         | 
| 3 3 | 
             
            # Instead, edit Juwelier::Tasks in Rakefile, and run 'rake gemspec'
         | 
| 4 4 | 
             
            # -*- encoding: utf-8 -*-
         | 
| 5 | 
            -
            # stub: cryptopunks-gui 0.0. | 
| 5 | 
            +
            # stub: cryptopunks-gui 0.0.12 ruby app
         | 
| 6 6 |  | 
| 7 7 | 
             
            Gem::Specification.new do |s|
         | 
| 8 8 | 
             
              s.name = "cryptopunks-gui".freeze
         | 
| 9 | 
            -
              s.version = "0.0. | 
| 9 | 
            +
              s.version = "0.0.12"
         | 
| 10 10 |  | 
| 11 11 | 
             
              s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
         | 
| 12 12 | 
             
              s.require_paths = ["app".freeze]
         | 
| 13 13 | 
             
              s.authors = ["Andy Maleh".freeze]
         | 
| 14 | 
            -
              s.date = "2021-11- | 
| 14 | 
            +
              s.date = "2021-11-22"
         | 
| 15 15 | 
             
              s.description = "CryptoPunks GUI for Simplified Minting - Built with Glimmer DSL for Tk (requires ActiveTcl to run cryptopunks-gui command)".freeze
         | 
| 16 16 | 
             
              s.email = "andy.am@gmail.com".freeze
         | 
| 17 17 | 
             
              s.executables = ["cryptopunks-gui".freeze]
         | 
| @@ -26,6 +26,12 @@ Gem::Specification.new do |s| | |
| 26 26 | 
             
                "README.md",
         | 
| 27 27 | 
             
                "VERSION",
         | 
| 28 28 | 
             
                "app/cryptopunks_gui.rb",
         | 
| 29 | 
            +
                "app/model/image.rb",
         | 
| 30 | 
            +
                "app/view/help_dialog.rb",
         | 
| 31 | 
            +
                "app/view/image_frame.rb",
         | 
| 32 | 
            +
                "app/view/menu_bar.rb",
         | 
| 33 | 
            +
                "app/view/preferences_dialog.rb",
         | 
| 34 | 
            +
                "app/view/style_options_frame.rb",
         | 
| 29 35 | 
             
                "bin/cryptopunks-gui",
         | 
| 30 36 | 
             
                "cryptopunks-gui.gemspec",
         | 
| 31 37 | 
             
                "icons/cryptopunks-gui.icns",
         | 
| @@ -34,7 +40,7 @@ Gem::Specification.new do |s| | |
| 34 40 | 
             
              s.homepage = "http://github.com/AndyObtiva/cryptopunks-gui".freeze
         | 
| 35 41 | 
             
              s.licenses = ["MIT".freeze]
         | 
| 36 42 | 
             
              s.post_install_message = "To launch CryptoPunks GUI, run command: cryptopunks-gui".freeze
         | 
| 37 | 
            -
              s.rubygems_version = "3.2. | 
| 43 | 
            +
              s.rubygems_version = "3.2.31".freeze
         | 
| 38 44 | 
             
              s.summary = "CryptoPunks GUI for Simplified Minting".freeze
         | 
| 39 45 |  | 
| 40 46 | 
             
              if s.respond_to? :specification_version then
         | 
| @@ -42,7 +48,7 @@ Gem::Specification.new do |s| | |
| 42 48 | 
             
              end
         | 
| 43 49 |  | 
| 44 50 | 
             
              if s.respond_to? :add_runtime_dependency then
         | 
| 45 | 
            -
                s.add_runtime_dependency(%q<glimmer-dsl-tk>.freeze, [" | 
| 51 | 
            +
                s.add_runtime_dependency(%q<glimmer-dsl-tk>.freeze, ["= 0.0.47"])
         | 
| 46 52 | 
             
                s.add_runtime_dependency(%q<cryptopunks>.freeze, ["~> 2.0.1"])
         | 
| 47 53 | 
             
                s.add_development_dependency(%q<rspec>.freeze, ["~> 3.5.0"])
         | 
| 48 54 | 
             
                s.add_development_dependency(%q<rdoc>.freeze, ["~> 3.12"])
         | 
| @@ -50,7 +56,7 @@ Gem::Specification.new do |s| | |
| 50 56 | 
             
                s.add_development_dependency(%q<simplecov>.freeze, [">= 0"])
         | 
| 51 57 | 
             
                s.add_development_dependency(%q<rake-tui>.freeze, [">= 0"])
         | 
| 52 58 | 
             
              else
         | 
| 53 | 
            -
                s.add_dependency(%q<glimmer-dsl-tk>.freeze, [" | 
| 59 | 
            +
                s.add_dependency(%q<glimmer-dsl-tk>.freeze, ["= 0.0.47"])
         | 
| 54 60 | 
             
                s.add_dependency(%q<cryptopunks>.freeze, ["~> 2.0.1"])
         | 
| 55 61 | 
             
                s.add_dependency(%q<rspec>.freeze, ["~> 3.5.0"])
         | 
| 56 62 | 
             
                s.add_dependency(%q<rdoc>.freeze, ["~> 3.12"])
         | 
    
        metadata
    CHANGED
    
    | @@ -1,29 +1,29 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: cryptopunks-gui
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0.0. | 
| 4 | 
            +
              version: 0.0.12
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Andy Maleh
         | 
| 8 8 | 
             
            autorequire:
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2021-11- | 
| 11 | 
            +
            date: 2021-11-22 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: glimmer-dsl-tk
         | 
| 15 15 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 16 16 | 
             
                requirements:
         | 
| 17 | 
            -
                - -  | 
| 17 | 
            +
                - - '='
         | 
| 18 18 | 
             
                  - !ruby/object:Gem::Version
         | 
| 19 | 
            -
                    version: 0.0. | 
| 19 | 
            +
                    version: 0.0.47
         | 
| 20 20 | 
             
              type: :runtime
         | 
| 21 21 | 
             
              prerelease: false
         | 
| 22 22 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 23 23 | 
             
                requirements:
         | 
| 24 | 
            -
                - -  | 
| 24 | 
            +
                - - '='
         | 
| 25 25 | 
             
                  - !ruby/object:Gem::Version
         | 
| 26 | 
            -
                    version: 0.0. | 
| 26 | 
            +
                    version: 0.0.47
         | 
| 27 27 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 28 28 | 
             
              name: cryptopunks
         | 
| 29 29 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -124,6 +124,12 @@ files: | |
| 124 124 | 
             
            - README.md
         | 
| 125 125 | 
             
            - VERSION
         | 
| 126 126 | 
             
            - app/cryptopunks_gui.rb
         | 
| 127 | 
            +
            - app/model/image.rb
         | 
| 128 | 
            +
            - app/view/help_dialog.rb
         | 
| 129 | 
            +
            - app/view/image_frame.rb
         | 
| 130 | 
            +
            - app/view/menu_bar.rb
         | 
| 131 | 
            +
            - app/view/preferences_dialog.rb
         | 
| 132 | 
            +
            - app/view/style_options_frame.rb
         | 
| 127 133 | 
             
            - bin/cryptopunks-gui
         | 
| 128 134 | 
             
            - cryptopunks-gui.gemspec
         | 
| 129 135 | 
             
            - icons/cryptopunks-gui.icns
         | 
| @@ -147,7 +153,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 147 153 | 
             
                - !ruby/object:Gem::Version
         | 
| 148 154 | 
             
                  version: '0'
         | 
| 149 155 | 
             
            requirements: []
         | 
| 150 | 
            -
            rubygems_version: 3.2. | 
| 156 | 
            +
            rubygems_version: 3.2.31
         | 
| 151 157 | 
             
            signing_key:
         | 
| 152 158 | 
             
            specification_version: 4
         | 
| 153 159 | 
             
            summary: CryptoPunks GUI for Simplified Minting
         |