ImageEditor.st
author Claus Gittinger <cg@exept.de>
Wed, 29 Jul 2009 20:02:02 +0200
changeset 2570 4e663bc64364
parent 2567 903843f8a824
child 2571 8b182cc4cac7
permissions -rw-r--r--
changed #requestPackage
     1 "
     2  COPYRIGHT (c) 1997-1998 by eXept Software AG
     3               All Rights Reserved
     4 
     5  This software is furnished under a license and may be used
     6  only in accordance with the terms of that license and with the
     7  inclusion of the above copyright notice. This software may not
     8  be provided or otherwise made available to, or used by, any
     9  other person. No title to or ownership of the software is
    10  hereby transferred.
    11 "
    12 "{ Package: 'stx:libtool2' }"
    13 
    14 ResourceSpecEditor subclass:#ImageEditor
    15 	instanceVariableNames:'imageEditView colorMapMode editMode mouseKeyColorMode
    16 		selectedColorIndex postOpenAction imageSeqNr drawingColormap
    17 		lastShiftUsedWrap'
    18 	classVariableNames:'LastDirectory LastSizeString MaskClipboard LastColormapMode
    19 		DefaultRelativeSizes'
    20 	poolDictionaries:''
    21 	category:'Interface-UIPainter'
    22 !
    23 
    24 !ImageEditor class methodsFor:'documentation'!
    25 
    26 copyright
    27 "
    28  COPYRIGHT (c) 1997-1998 by eXept Software AG
    29               All Rights Reserved
    30 
    31  This software is furnished under a license and may be used
    32  only in accordance with the terms of that license and with the
    33  inclusion of the above copyright notice. This software may not
    34  be provided or otherwise made available to, or used by, any
    35  other person. No title to or ownership of the software is
    36  hereby transferred.
    37 "
    38 !
    39 
    40 documentation
    41 "
    42     Image Editor allows you to create, design, modify or just inspect images.
    43 
    44     [start with:]
    45         ImageEditor open
    46         ImageEditor openOnClass:Icon andSelector:#startIcon
    47 
    48     [see also:]
    49         ImageEditView Image
    50 
    51     [author:]
    52         Thomas Zwick, eXept Software AG
    53         Claus Gittinger, eXept Software AG
    54 "
    55 ! !
    56 
    57 !ImageEditor class methodsFor:'instance creation'!
    58 
    59 openLoadingImageWith:aBlock
    60     "opens an Image Editor on anImage"
    61 
    62     |editor|
    63 
    64     editor := self new.
    65     editor allButOpen.
    66     aBlock value:editor.
    67     editor openWindow
    68 !
    69 
    70 openModalOnClass: aClass andSelector: aSelector
    71     "opens a modal Image Editor on aClass and aSelector.
    72      Returns the real name of the edited resource method (in case, user changed it)."
    73 
    74     |imageEditor imageEditView className resourceClass resourceSelector| 
    75 
    76     imageEditor := self new.
    77 
    78     aClass isClass  ifTrue: [className := aClass name].
    79     aClass isString ifTrue: [className := aClass].      
    80     aClass isNil    ifTrue: [className := ''].      
    81 
    82     imageEditor postOpenAction: [imageEditView := imageEditor imageEditView. 
    83                                  imageEditor loadFromOrPrepareForClass: aClass andSelector: aSelector].
    84     imageEditor openModal.
    85 
    86     resourceClass := imageEditView resourceClass.
    87     resourceSelector := imageEditView resourceSelector.
    88 
    89     (resourceClass isNil or:[resourceSelector isNil]) ifTrue:[^ nil].
    90     ^ Array with:resourceClass with:resourceSelector
    91 
    92     "
    93      self openModalOnClass: self andSelector: #leftMouseKeyIcon
    94     "
    95 !
    96 
    97 openOnClass:aClass andSelector:aSelector
    98     "opens an Image Editor on aClass and aSelector"
    99 
   100     self openLoadingImageWith:[:editor | editor loadFromClass:aClass theNonMetaclass andSelector:aSelector.]
   101 
   102     "
   103      self openOnClass:self andSelector:#leftMouseKeyIcon
   104      self openOnClass:self andSelector:nil
   105     "
   106 
   107     "Modified: / 16.3.1999 / 21:33:49 / cg"
   108 !
   109 
   110 openOnFile:aFileName
   111     "opens an Image Editor on aFileName"
   112 
   113     self openLoadingImageWith:[:editor | editor loadFromFile:aFileName.]
   114 
   115     "
   116      self openOnFile: '../../goodies/bitmaps/gifImages/back.gif'
   117     "
   118 
   119     "Modified: / 16.3.1999 / 21:33:25 / cg"
   120 !
   121 
   122 openOnImage:anImage
   123     "opens an Image Editor on anImage"
   124 
   125     self openLoadingImageWith:[:editor | editor loadFromImage: anImage.]
   126 
   127     "
   128      self openOnImage: Icon startIcon
   129     "
   130 
   131     "Modified: / 11.3.1999 / 16:18:33 / cg"
   132 ! !
   133 
   134 !ImageEditor class methodsFor:'accessing'!
   135 
   136 listOfColorMaps
   137     "returns the list of default color maps for a new image"
   138 
   139     |colorMap|
   140 
   141     (colorMap := OrderedCollection new)
   142         add: Color black;
   143         add: Color white;
   144         add: Color red;
   145         add: Color green;
   146         add: Color blue;
   147         add: Color cyan;
   148         add: Color yellow;
   149         add: Color magenta;
   150         add: (Color redByte: 127 greenByte:   0 blueByte:   0);
   151         add: (Color redByte:   0 greenByte: 127 blueByte:   0);
   152         add: (Color redByte:   0 greenByte:   0 blueByte: 127);
   153         add: (Color redByte:   0 greenByte: 127 blueByte: 127);
   154         add: (Color redByte: 127 greenByte: 127 blueByte:   0);
   155         add: (Color redByte: 127 greenByte:   0 blueByte: 127);
   156         add: (Color redByte: 127 greenByte: 127 blueByte: 127);
   157         add: (Color redByte: 170 greenByte: 170 blueByte: 170).
   158 
   159     0 to: 5 do:
   160     [:r|                                                    
   161         0 to: 5 do:         
   162         [:g|
   163             0 to: 5 do:                             
   164             [:b|
   165                 colorMap add: (Color redByte: (r*255//5) ceiling greenByte: (g*255//5) ceiling blueByte: (b*255//5) ceiling)
   166             ]
   167         ]
   168     ].
   169 
   170     1 to: 25 do:
   171     [:g|                             
   172         colorMap add: (Color redByte: (g*255//26) ceiling greenByte: (g*255//26) ceiling blueByte: (g*255//26) ceiling)
   173     ].
   174 
   175     ^ Dictionary new
   176         at: #depth24 put:(FixedPalette redShift:16 redMask:16rFF greenShift:8 greenMask:16rFF blueShift:0 blueMask:16rFF);
   177         at: #masked24 put:(FixedPalette redShift:16 redMask:16rFF greenShift:8 greenMask:16rFF blueShift:0 blueMask:16rFF);
   178         at: #depth16 put:(FixedPalette redShift:11 redMask:16r1F greenShift:5 greenMask:16r3F blueShift:0 blueMask:16r1F);
   179         at: #masked16 put:(FixedPalette redShift:11 redMask:16r1F greenShift:5 greenMask:16r3F blueShift:0 blueMask:16r1F);
   180         at: #depth8  put: colorMap;
   181         at: #masked8 put: colorMap;
   182         at: #depth4  put: (colorMap copyFrom: 1 to: 16);
   183         at: #masked4 put: (colorMap copyFrom: 1 to: 16);
   184         at: #depth2  put: (colorMap copyFrom: 1 to: 4);
   185         at: #masked2 put: (colorMap copyFrom: 1 to: 4);
   186         at: #depth1  put: (colorMap copyFrom: 1 to: 2);
   187         at: #masked1 put: (colorMap copyFrom: 1 to: 2);
   188         yourself
   189 !
   190 
   191 listOfDefaultSizes
   192     "returns the list of default sizes for a new image"
   193 
   194     ^ #('8x8' '16x16' '22x22' '32x32' '48x48' '64x64')
   195 
   196     "Modified: / 31.7.1998 / 01:57:34 / cg"
   197 !
   198 
   199 namesOfColorMaps
   200     ^ Dictionary new
   201         at: #depth24 put: '24-plane';
   202         at: #masked24 put: '24-plane + mask';
   203         at: #depth16 put: '16-plane';
   204         at: #masked16 put: '16-plane + mask';
   205         at: #depth8  put: ' 8-plane';
   206         at: #masked8 put: ' 8-plane + mask';
   207         at: #depth4  put: ' 4-plane';
   208         at: #masked4 put: ' 4-plane + mask';
   209         at: #depth2  put: ' 2-plane';
   210         at: #masked2 put: ' 2-plane + mask';
   211         at: #depth1  put: ' 1-plane';
   212         at: #masked1 put: ' 1-plane + mask' ;
   213         yourself
   214 ! !
   215 
   216 !ImageEditor class methodsFor:'help specs'!
   217 
   218 flyByHelpSpec
   219     <resource: #help>
   220 
   221     ^super flyByHelpSpec addPairsFrom:#(
   222 
   223 #drawModeBox
   224 'Rectangle'
   225 
   226 #drawModeCopy
   227 'Copy'
   228 
   229 #drawModeFill
   230 'Flood-Fill'
   231 
   232 #drawModeFilledBox
   233 'Filled Rectangle'
   234 
   235 #drawModePaste
   236 'Paste'
   237 
   238 #drawModePasteUnder
   239 'Paste Under'
   240 
   241 #drawModePasteWithMask
   242 'Paste with Mask'
   243 
   244 #drawModePoint
   245 'Point'
   246 
   247 #drawModeSpecial
   248 'Special Operations'
   249 
   250 #fileGrabImage
   251 'Pick from Screen'
   252 
   253 #fileLoadFromClass
   254 'Load from Method...'
   255 
   256 #fileLoadFromFile
   257 'Load from File...'
   258 
   259 #fileNewImage
   260 'New Image'
   261 
   262 #filePrint
   263 'Print'
   264 
   265 #fileSaveAs
   266 'Save to File...'
   267 
   268 #fileSaveMaskAs
   269 'Save Mask to File...'
   270 
   271 #fileSaveMethod
   272 'Save as Method'
   273 
   274 #fileSaveMethodAs
   275 'Save as Method...'
   276 
   277 )
   278 !
   279 
   280 helpSpec
   281     "This resource specification was automatically generated
   282      by the UIHelpTool of ST/X."
   283 
   284     "Do not manually edit this!! If it is corrupted,
   285      the UIHelpTool may not be able to read the specification."
   286 
   287     "
   288      UIHelpTool openOnClass:ImageEditor    
   289     "
   290 
   291     <resource: #help>
   292 
   293     ^super helpSpec addPairsFrom:#(
   294 
   295 #colorMap
   296 'ColorMap functions.'
   297 
   298 #colorMap1
   299 'Convert to depth-1 image.'
   300 
   301 #colorMap1M
   302 'Convert to depth-1 image plus mask.'
   303 
   304 #colorMap2
   305 'Convert to depth-2 image.'
   306 
   307 #colorMap2M
   308 'Convert to depth-2 image plus mask.'
   309 
   310 #colorMap4
   311 'Convert to depth-4 image.'
   312 
   313 #colorMap4M
   314 'Convert to depth-4 image plus mask.'
   315 
   316 #colorMap8
   317 'Convert to depth-8 image.'
   318 
   319 #colorMap8M
   320 'Convert to depth-8 image plus mask.'
   321 
   322 #colorMapTable
   323 'Shows a list of used colors of the image.'
   324 
   325 #compressColormap
   326 'Remove unneeded entries from the colorMap.'
   327 
   328 #cropAll
   329 'Find and remove all borders.'
   330 
   331 #cropBottom
   332 'Find and remove bottom border.'
   333 
   334 #cropLeft
   335 'Find and remove left border.'
   336 
   337 #cropManual
   338 'Specify border(s) to remove.'
   339 
   340 #cropRight
   341 'Find and remove right border.'
   342 
   343 #cropTop
   344 'Find and remove top border.'
   345 
   346 #drawModeBox
   347 'Rectangle Drawing Mode.'
   348 
   349 #drawModeCircle
   350 'Circle Drawing Mode.'
   351 
   352 #drawModeCopy
   353 'Area Copy Mode.'
   354 
   355 #drawModeFill
   356 'Flood Fill Mode.'
   357 
   358 #drawModeFilledBox
   359 'Filled Rectangle Drawing Mode.'
   360 
   361 #drawModePaste
   362 'Paste Mode.'
   363 
   364 #drawModePasteUnder
   365 'Paste-Under Mode.'
   366 
   367 #drawModePasteWithMask
   368 'Paste-with-Mask Mode.'
   369 
   370 #drawModePoint
   371 'Point Drawing Mode.'
   372 
   373 #drawModeSpray
   374 'Spray Drawing Mode.'
   375 
   376 #drawModeSpecial
   377 'Special Operations'
   378 
   379 #editFlipHorizontal
   380 'Flip the image horizontally.'
   381 
   382 #editFlipVertical
   383 'Flip the image vertically.'
   384 
   385 #editMagnifyImage
   386 'Magnify the image.'
   387 
   388 #editNegate
   389 'Invert the images colors.'
   390 
   391 #editResize
   392 'Resize the image (preserving the old image).'
   393 
   394 #editRotate
   395 'Rotate the image.'
   396 
   397 #fileGrabImage
   398 'Pick an image from the screen.'
   399 
   400 #fileLoadFromClass
   401 'Select and load an image from a resource method.'
   402 
   403 #fileLoadFromFile
   404 'Select and load an image from a file.'
   405 
   406 #fileNewImage
   407 'Create a new image'
   408 
   409 #filePrint
   410 'Print the image on a postscript printer.'
   411 
   412 #fileSaveAs
   413 'Save the image to a file.'
   414 
   415 #fileSaveMaskAs
   416 'Save the mask of the image to a file.'
   417 
   418 #fileSaveButtonImageAs
   419 'Save an image of a button with the image to a file (for html use).'
   420 
   421 #fileSaveMethod
   422 'Save the image as resource method in the current class and selector.'
   423 
   424 #fileSaveMethodAs
   425 'Save the image as resource method in a class.'
   426 
   427 #magnificationNumber
   428 'Shows the current magnification.'
   429 
   430 #magnifyImageDown
   431 'Decrease magnification.'
   432 
   433 #magnifyImageUp
   434 'Increase magnification.'
   435 
   436 #mouseKeyColorMode
   437 'Toggle between left and right mouse button color.'
   438 
   439 #previewView
   440 'Shows a preview of the image.'
   441 
   442 #settingsGridMagnification
   443 'Change the grid magnification of the edit view.'
   444 
   445 )
   446 
   447     "Modified: / 7.9.1998 / 18:20:26 / cg"
   448 ! !
   449 
   450 !ImageEditor class methodsFor:'image specs'!
   451 
   452 circleIcon
   453     "This resource specification was automatically generated
   454      by the ImageEditor of ST/X."
   455 
   456     "Do not manually edit this!! If it is corrupted,
   457      the ImageEditor may not be able to read the specification."
   458 
   459     "
   460      self circleIcon inspect
   461      ImageEditor openOnClass:self andSelector:#circleIcon
   462      Icon flushCachedIcons
   463     "
   464 
   465     <resource: #image>
   466 
   467     ^Icon
   468         constantNamed:'ImageEditor class circleIcon'
   469         ifAbsentPut:[(Depth1Image new) width: 14; height: 14; photometric:(#palette); bitsPerSample:(#(1)); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@@@A@@@@@@@@@@@@@@@C@@@@@@@@@@@@@@@a') ; colorMapFromArray:#[0 0 0 255 0 0]; mask:((Depth1Image new) width: 14; height: 14; photometric:(#blackIs0); bitsPerSample:(#(1)); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@@N@CF@PDA@PH@  BB@HDA@PD@1 @8@@@@@a') ; yourself); yourself]
   470 !
   471 
   472 copyIcon
   473     "This resource specification was automatically generated
   474      by the ImageEditor of ST/X."
   475 
   476     "Do not manually edit this!! If it is corrupted,
   477      the ImageEditor may not be able to read the specification."
   478 
   479     "
   480      self copyIcon inspect
   481      ImageEditor openOnClass:self andSelector:#copyIcon
   482      Icon flushCachedIcons
   483     "
   484 
   485     <resource: #image>
   486 
   487     ^Icon
   488         constantNamed:'ImageEditor class copyIcon'
   489         ifAbsentPut:[(Depth2Image new) width: 14; height: 14; photometric:(#palette); bitsPerSample:(#(2)); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@@@@@@@** @@J)UUTB*Z*)@*&**PJ)**$B*Z*)@*&**PJ)**$@@Z*)@@F**P@AUUT@@@@@@b') ; colorMapFromArray:#[0 0 0 0 0 128 255 255 255]; mask:((Depth1Image new) width: 14; height: 14; photometric:(#blackIs0); bitsPerSample:(#(1)); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@C? O>@??3??O?<??3??O?<??3??@_<A?0@@@@a') ; yourself); yourself]
   490 !
   491 
   492 defaultIcon
   493     <resource: #programImage>
   494 
   495     ^ ToolbarIconLibrary startImageEditorIcon
   496 !
   497 
   498 fillIcon
   499     "This resource specification was automatically generated
   500      by the ImageEditor of ST/X."
   501 
   502     "Do not manually edit this!! If it is corrupted,
   503      the ImageEditor may not be able to read the specification."
   504 
   505     "
   506      self fillIcon inspect
   507      ImageEditor openOnClass:self andSelector:#fillIcon
   508      Icon flushCachedIcons
   509     "
   510 
   511     <resource: #image>
   512 
   513     ^Icon
   514         constantNamed:'ImageEditor class fillIcon'
   515         ifAbsentPut:[(Depth2Image new) width: 14; height: 14; photometric:(#palette); bitsPerSample:(#(2)); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@@@@@@@@@ @@@@*H@@D*(@@DUUP@EAUU@AAEU@@@@U@@DDA@@@@@@@@PP@@@@@@@@@@@@@@b') ; colorMapFromArray:#[0 0 0 255 0 0 255 255 255]; mask:((Depth1Image new) width: 14; height: 14; photometric:(#blackIs0); bitsPerSample:(#(1)); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'C @Q@BN@I<@?8C?0[?!!G<@O P\@@ D@@@@@@@@@a') ; yourself); yourself]
   516 !
   517 
   518 fillRectIcon
   519     "This resource specification was automatically generated
   520      by the ImageEditor of ST/X."
   521 
   522     "Do not manually edit this!! If it is corrupted,
   523      the ImageEditor may not be able to read the specification."
   524 
   525     "
   526      self fillRectIcon inspect
   527      ImageEditor openOnClass:self andSelector:#fillRectIcon
   528      Icon flushCachedIcons
   529     "
   530 
   531     <resource: #image>
   532 
   533     ^Icon
   534         constantNamed:'ImageEditor class fillRectIcon'
   535         ifAbsentPut:[(Depth1Image new) width: 14; height: 14; photometric:(#palette); bitsPerSample:(#(1)); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@@@A@@@@@@@@@@@@@@@@@@@@@@@@@@D@@@@a') ; colorMapFromArray:#[0 0 0 255 0 0]; mask:((Depth1Image new) width: 14; height: 14; photometric:(#blackIs0); bitsPerSample:(#(1)); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@C?0O?@?<C?0O?@?<C?0O?@?<C?0@@@@@@@a') ; yourself); yourself]
   536 !
   537 
   538 leftMouseKeyIcon
   539     "This resource specification was automatically generated
   540      by the ImageEditor of ST/X."
   541 
   542     "Do not manually edit this!! If it is corrupted,
   543      the ImageEditor may not be able to read the specification."
   544 
   545     "
   546      self leftMouseKeyIcon inspect
   547      ImageEditor openOnClass:self andSelector:#leftMouseKeyIcon
   548      Icon flushCachedIcons
   549     "
   550 
   551     <resource: #image>
   552 
   553     ^Icon
   554         constantNamed:'ImageEditor class leftMouseKeyIcon'
   555         ifAbsentPut:[(Depth2Image new) width: 16; height: 16; photometric:(#palette); bitsPerSample:(#(2)); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@@@@@@@@@@@@@EJJ@@AR" @@T((@@@@@@@B** @@**(@@J**@@B** @@**(@@J**@@@**@@@@@@@@@@@@@@a') ; colorMapFromArray:#[0 0 0 255 0 0 255 255 255]; mask:((Depth1Image new) width: 16; height: 16; photometric:(#blackIs0); bitsPerSample:(#(1)); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@@?0G? _>A?8G? _>A?8G? _>A?8G? O<@_ @@@b') ; yourself); yourself]
   556 !
   557 
   558 pasteIcon
   559     "This resource specification was automatically generated
   560      by the ImageEditor of ST/X."
   561 
   562     "Do not manually edit this!! If it is corrupted,
   563      the ImageEditor may not be able to read the specification."
   564 
   565     "
   566      self pasteIcon inspect
   567      ImageEditor openOnClass:self andSelector:#pasteIcon
   568      Icon flushCachedIcons
   569     "
   570 
   571     <resource: #image>
   572 
   573     ^Icon
   574         constantNamed:'ImageEditor class pasteIcon'
   575         ifAbsentPut:[(Depth4Image new) width: 14; height: 14; photometric:(#palette); bitsPerSample:(#(4)); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@@@@@@@@AU@@@@@CHE@E@2@@@ QDQD@0@@L@@@@@H@@BL#H2L#@@@QDQDQL @@D3L@@@@@@AL3A&Y&X@@SL0Y A&@@D3LF@@A @AL3A&@FX@@QDPY&Y&
   576 @@@@@@@@@@@b') ; colorMapFromArray:#[0 0 0 0 0 128 128 128 0 128 128 128 212 208 200 255 255 0 255 255 255]; mask:((Depth1Image new) width: 14; height: 14; photometric:(#blackIs0); bitsPerSample:(#(1)); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'C0A?8O?0??C?<O?0??C?>O?8??#?>O?8_? G>@@a') ; yourself); yourself]
   577 !
   578 
   579 pasteUnderIcon
   580     "This resource specification was automatically generated
   581      by the ImageEditor of ST/X."
   582 
   583     "Do not manually edit this!! If it is corrupted,
   584      the ImageEditor may not be able to read the specification."
   585 
   586     "
   587      self pasteUnderIcon inspect
   588      ImageEditor openOnClass:self andSelector:#pasteUnderIcon
   589      Icon flushCachedIcons
   590     "
   591 
   592     <resource: #image>
   593 
   594     ^Icon
   595         constantNamed:'ImageEditor class pasteUnderIcon'
   596         ifAbsentPut:[(Depth4Image new) width: 14; height: 14; photometric:(#palette); bitsPerSample:(#(4)); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@@@@@@@@AU@@@@@CHE@E@2@@@ QDQD@0@@L@@@@@H@@BL#H2L#@@@QDQDQL @@D3L3LP@@@AL3L3E&X@@SL3L0A&@@D3L3@@A @AL3L3@FX@@QDQDQY&
   597 @@@@@@@@@@@b') ; colorMapFromArray:#[0 0 0 0 0 128 128 128 0 128 128 128 212 208 200 255 255 0 255 255 255]; mask:((Depth1Image new) width: 14; height: 14; photometric:(#blackIs0); bitsPerSample:(#(1)); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'C0A?8O?0??C?<O?0??C?>O?8??#?>O?8_? G>@@a') ; yourself); yourself]
   598 !
   599 
   600 pasteWithMaskIcon
   601     "This resource specification was automatically generated
   602      by the ImageEditor of ST/X."
   603 
   604     "Do not manually edit this!! If it is corrupted,
   605      the ImageEditor may not be able to read the specification."
   606 
   607     "
   608      self pasteWithMaskIcon inspect
   609      ImageEditor openOnClass:self andSelector:#pasteWithMaskIcon
   610      Icon flushCachedIcons
   611     "
   612 
   613     <resource: #image>
   614 
   615     ^Icon
   616         constantNamed:'ImageEditor class pasteWithMaskIcon'
   617         ifAbsentPut:[(Depth4Image new) width: 14; height: 14; photometric:(#palette); bitsPerSample:(#(4)); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@@@@@@@@AU@@@@@CHE@E@2@@@ QDQD@0@@L@@@@@H@@BL#H2L#@@@QDQDQL @@D3L@@@@@@AL3@3M&X@@SL0L3A&@@D3LCL0A @AL3@3LFX@@QDPY&Y&
   618 @@@@@@@@@@@b') ; colorMapFromArray:#[0 0 0 0 0 128 128 128 0 128 128 128 212 208 200 255 255 0 255 255 255]; mask:((Depth1Image new) width: 14; height: 14; photometric:(#blackIs0); bitsPerSample:(#(1)); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'C0A?8O?0??C?<O?0??C?>O?8??#?>O?8_? G>@@a') ; yourself); yourself]
   619 !
   620 
   621 pointIcon
   622     "This resource specification was automatically generated
   623      by the ImageEditor of ST/X."
   624 
   625     "Do not manually edit this!! If it is corrupted,
   626      the ImageEditor may not be able to read the specification."
   627 
   628     "
   629      self pointIcon inspect
   630      ImageEditor openOnClass:self andSelector:#pointIcon
   631      Icon flushCachedIcons
   632     "
   633 
   634     <resource: #image>
   635 
   636     ^Icon
   637         constantNamed:'ImageEditor class pointIcon'
   638         ifAbsentPut:[(Depth1Image new) width: 14; height: 14; photometric:(#palette); bitsPerSample:(#(1)); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@@@A@@@@@@@@@@@@@@@C@@@@@@@@@@@@@@@a') ; colorMapFromArray:#[0 0 0 255 255 255]; mask:((Depth1Image new) width: 14; height: 14; photometric:(#blackIs0); bitsPerSample:(#(1)); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@@@0@G@@8@G@@8@G@@8@G@@X@@@@@@@@@@@a') ; yourself); yourself]
   639 !
   640 
   641 rectIcon
   642     "This resource specification was automatically generated
   643      by the ImageEditor of ST/X."
   644 
   645     "Do not manually edit this!! If it is corrupted,
   646      the ImageEditor may not be able to read the specification."
   647 
   648     "
   649      self rectIcon inspect
   650      ImageEditor openOnClass:self andSelector:#rectIcon
   651      Icon flushCachedIcons
   652     "
   653 
   654     <resource: #image>
   655 
   656     ^Icon
   657         constantNamed:'ImageEditor class rectIcon'
   658         ifAbsentPut:[(Depth1Image new) width: 14; height: 14; photometric:(#palette); bitsPerSample:(#(1)); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@@@A@@@@@@@@@@@@@@@C@@@@@@@@@@@@@@@a') ; colorMapFromArray:#[0 0 0 255 0 0]; mask:((Depth1Image new) width: 14; height: 14; photometric:(#blackIs0); bitsPerSample:(#(1)); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@C?0HA@ DB@PHA@ DB@PHA@ DC?0@@@@@@@a') ; yourself); yourself]
   659 !
   660 
   661 rightMouseKeyIcon
   662     "This resource specification was automatically generated
   663      by the ImageEditor of ST/X."
   664 
   665     "Do not manually edit this!! If it is corrupted,
   666      the ImageEditor may not be able to read the specification."
   667 
   668     "
   669      self rightMouseKeyIcon inspect
   670      ImageEditor openOnClass:self andSelector:#rightMouseKeyIcon
   671      Icon flushCachedIcons
   672     "
   673 
   674     <resource: #image>
   675 
   676     ^Icon
   677         constantNamed:'ImageEditor class rightMouseKeyIcon'
   678         ifAbsentPut:[(Depth2Image new) width: 16; height: 16; photometric:(#palette); bitsPerSample:(#(2)); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@@@@@@@@@@@@@JJE@@B"!!P@@((T@@@@@@@B** @@**(@@J**@@B** @@**(@@J**@@@**@@@@@@@@@@@@@@a') ; colorMapFromArray:#[0 0 0 255 0 0 255 255 255]; mask:((Depth1Image new) width: 16; height: 16; photometric:(#blackIs0); bitsPerSample:(#(1)); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@@?0G? _>A?8G? _>A?8G? _>A?8G? O<@_ @@@b') ; yourself); yourself]
   679 !
   680 
   681 specialIcon
   682     "This resource specification was automatically generated
   683      by the ImageEditor of ST/X."
   684 
   685     "Do not manually edit this!! If it is corrupted,
   686      the ImageEditor may not be able to read the specification."
   687 
   688     "
   689      self specialIcon inspect
   690      ImageEditor openOnClass:self andSelector:#specialIcon
   691      Icon flushCachedIcons
   692     "
   693 
   694     <resource: #image>
   695 
   696     ^Icon
   697         constantNamed:'ImageEditor class specialIcon'
   698         ifAbsentPut:[(Depth1Image new) width: 14; height: 14; photometric:(#palette); bitsPerSample:(#(1)); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@L@@@@B@@@@@0@@@@@@@@@@@@@@@P@@@@@@@@@a') ; colorMapFromArray:#[0 0 0 255 0 0]; mask:((Depth1Image new) width: 14; height: 14; photometric:(#blackIs0); bitsPerSample:(#(1)); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@@L@@0@G @^@A8@G @L@@0@@@@L@@0@@@@@a') ; yourself); yourself]
   699 !
   700 
   701 sprayIcon
   702     "This resource specification was automatically generated
   703      by the ImageEditor of ST/X."
   704 
   705     "Do not manually edit this!! If it is corrupted,
   706      the ImageEditor may not be able to read the specification."
   707 
   708     "
   709      self sprayIcon inspect
   710      ImageEditor openOnClass:self andSelector:#sprayIcon
   711      Icon flushCachedIcons
   712     "
   713 
   714     <resource: #image>
   715 
   716     ^Icon
   717         constantNamed:'ImageEditor class sprayIcon'
   718         ifAbsentPut:[(Depth4Image new) width: 14; height: 14; photometric:(#palette); bitsPerSample:(#[4]); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@@@@@@@@@@@@@D@@@@@@@DA@@@@@@D@D@@@@@@A@PD@@@@@@A@P@@@@@@@A@P@@@@@@@A@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   719 @@@@@@@@@@@b') ; colorMapFromArray:#[0 0 0 84 84 84 170 170 170 255 255 255 255 0 0]; mask:((Depth1Image new) width: 14; height: 14; photometric:(#blackIs0); bitsPerSample:(#(1)); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@B@@(A)@F*@IPA2 H$@"@BH@H @"@BH@O @@a') ; yourself); yourself]
   720 ! !
   721 
   722 !ImageEditor class methodsFor:'interface specs'!
   723 
   724 changeHLSDialogSpec
   725     "This resource specification was automatically generated
   726      by the UIPainter of ST/X."
   727 
   728     "Do not manually edit this!! If it is corrupted,
   729      the UIPainter may not be able to read the specification."
   730 
   731     "
   732      UIPainter new openOnClass:ImageEditor andSelector:#changeHLSDialogSpec
   733      ImageEditor new openInterface:#changeHLSDialogSpec
   734     "
   735 
   736     <resource: #canvas>
   737 
   738     ^ 
   739      #(FullSpec
   740         name: changeHLSDialogSpec
   741         window: 
   742        (WindowSpec
   743           label: 'HLS Edit Dialog'
   744           name: 'HLS Edit Dialog'
   745           min: (Point 10 10)
   746           bounds: (Rectangle 0 0 312 258)
   747         )
   748         component: 
   749        (SpecCollection
   750           collection: (
   751            (LabelSpec
   752               label: 'Hue-Shift:'
   753               name: 'HueLabel'
   754               layout: (LayoutFrame 20 0 21 0 120 0 43 0)
   755               translateLabel: true
   756               adjust: right
   757             )
   758            (InputFieldSpec
   759               name: 'HueShiftEntryField'
   760               layout: (LayoutFrame 123 0 21 0 166 0 43 0)
   761               tabable: true
   762               model: hueShiftAmount
   763               type: numberInRange
   764               minValue: 0
   765               maxValue: 360
   766               acceptChannel: acceptChannel
   767               acceptOnPointerLeave: false
   768             )
   769            (ThumbWheelSpec
   770               name: 'HueWheel'
   771               layout: (LayoutFrame 180 0 22 0 297 0 42 0)
   772               model: hueShiftAmount
   773               orientation: horizontal
   774               step: 1
   775               endlessRotation: true
   776             )
   777            (LabelSpec
   778               label: 'Light Factor:'
   779               name: 'LightLabel'
   780               layout: (LayoutFrame 18 0 50 0 120 0 72 0)
   781               translateLabel: true
   782               adjust: right
   783             )
   784            (InputFieldSpec
   785               name: 'LightEntryField'
   786               layout: (LayoutFrame 123 0 50 0 166 0 72 0)
   787               tabable: true
   788               model: lightAmount
   789               type: numberInRange
   790               minValue: 0
   791               maxValue: 1000
   792               acceptChannel: acceptChannel
   793               acceptOnPointerLeave: false
   794             )
   795            (ThumbWheelSpec
   796               name: 'LightWheel'
   797               layout: (LayoutFrame 180 0 51 0 297 0 71 0)
   798               model: lightAmount
   799               orientation: horizontal
   800               stop: 1000
   801               step: 1
   802             )
   803            (LabelSpec
   804               label: 'Saturation Factor:'
   805               name: 'SaturationLabel'
   806               layout: (LayoutFrame 9 0 79 0 120 0 101 0)
   807               translateLabel: true
   808               adjust: right
   809             )
   810            (InputFieldSpec
   811               name: 'SaturationEntryField'
   812               layout: (LayoutFrame 123 0 79 0 166 0 101 0)
   813               tabable: true
   814               model: saturationAmount
   815               type: numberInRange
   816               minValue: 0
   817               maxValue: 1000
   818               acceptChannel: acceptChannel
   819               acceptOnPointerLeave: false
   820             )
   821            (ThumbWheelSpec
   822               name: 'SaturationWheel'
   823               layout: (LayoutFrame 180 0 80 0 297 0 100 0)
   824               model: saturationAmount
   825               orientation: horizontal
   826               stop: 1000
   827               step: 1
   828             )
   829            (LabelSpec
   830               label: 'Color Shift'
   831               name: 'Label2'
   832               layout: (LayoutFrame 5 0 110 0 -15 0.5 132 0)
   833               translateLabel: true
   834             )
   835            (LabelSpec
   836               name: 'HueColorLabel'
   837               layout: (LayoutFrame 18 0.0 133 0 -41 0.5 217 0)
   838               level: -1
   839               backgroundChannel: hlsColor
   840               translateLabel: true
   841             )
   842            (LabelSpec
   843               label: 'Preview'
   844               name: 'Label3'
   845               layout: (LayoutFrame 5 0.5 110 0 -5 1 132 0)
   846               translateLabel: true
   847             )
   848            (LabelSpec
   849               name: 'PreviewLabel'
   850               layout: (LayoutFrame 36 0.5 133 0 -23 1.0 217 0)
   851               level: -1
   852               translateLabel: true
   853               labelChannel: previewImageHolder
   854             )
   855            (HorizontalPanelViewSpec
   856               name: 'HorizontalPanel1'
   857               layout: (LayoutFrame 0 0.0 -30 1 0 1.0 0 1)
   858               horizontalLayout: fitSpace
   859               verticalLayout: center
   860               horizontalSpace: 3
   861               verticalSpace: 3
   862               reverseOrderIfOKAtLeft: true
   863               component: 
   864              (SpecCollection
   865                 collection: (
   866                  (ActionButtonSpec
   867                     label: 'Cancel'
   868                     name: 'Button1'
   869                     translateLabel: true
   870                     tabable: true
   871                     model: cancel
   872                     extent: (Point 151 22)
   873                   )
   874                  (ActionButtonSpec
   875                     label: 'OK'
   876                     name: 'Button2'
   877                     translateLabel: true
   878                     tabable: true
   879                     model: accept
   880                     extent: (Point 152 22)
   881                   )
   882                  )
   883                
   884               )
   885             )
   886            )
   887          
   888         )
   889       )
   890 !
   891 
   892 cropDialogSpec
   893     "This resource specification was automatically generated
   894      by the UIPainter of ST/X."
   895 
   896     "Do not manually edit this!! If it is corrupted,
   897      the UIPainter may not be able to read the specification."
   898 
   899     "
   900      UIPainter new openOnClass:ImageEditor andSelector:#cropDialogSpec
   901      ImageEditor new openInterface:#cropDialogSpec
   902     "
   903 
   904     <resource: #canvas>
   905 
   906     ^ 
   907      #(FullSpec
   908         name: cropDialogSpec
   909         window: 
   910        (WindowSpec
   911           label: 'Crop Border(s)'
   912           name: 'Crop Border(s)'
   913           min: (Point 10 10)
   914           bounds: (Rectangle 14 46 259 229)
   915         )
   916         component: 
   917        (SpecCollection
   918           collection: (
   919            (LabelSpec
   920               label: 'Left:'
   921               name: 'GropLeftLabel'
   922               layout: (LayoutFrame 14 0 21 0 90 0 43 0)
   923               translateLabel: true
   924               adjust: right
   925             )
   926            (InputFieldSpec
   927               name: 'GropLeftEntryField'
   928               layout: (LayoutFrame 95 0 21 0 132 0 43 0)
   929               tabable: true
   930               model: left
   931               type: number
   932               acceptChannel: acceptChannel
   933               acceptOnPointerLeave: false
   934             )
   935            (ActionButtonSpec
   936               label: 'Now'
   937               name: 'GropLeftNowButton'
   938               layout: (LayoutFrame 148 0 21 0 221 0 43 0)
   939               translateLabel: true
   940               tabable: true
   941               model: gropLeftNow
   942               autoRepeat: true
   943             )
   944            (LabelSpec
   945               label: 'Right:'
   946               name: 'GropRightLabel'
   947               layout: (LayoutFrame 14 0 51 0 90 0 73 0)
   948               translateLabel: true
   949               adjust: right
   950             )
   951            (InputFieldSpec
   952               name: 'GropRightEntryField'
   953               layout: (LayoutFrame 95 0 51 0 132 0 73 0)
   954               tabable: true
   955               model: right
   956               type: number
   957               acceptChannel: acceptChannel
   958               acceptOnPointerLeave: false
   959             )
   960            (ActionButtonSpec
   961               label: 'Now'
   962               name: 'GropRightButton'
   963               layout: (LayoutFrame 148 0 51 0 221 0 73 0)
   964               translateLabel: true
   965               tabable: true
   966               model: gropRightNow
   967               autoRepeat: true
   968             )
   969            (LabelSpec
   970               label: 'Top:'
   971               name: 'GropTopLabel'
   972               layout: (LayoutFrame 14 0 81 0 90 0 103 0)
   973               translateLabel: true
   974               adjust: right
   975             )
   976            (InputFieldSpec
   977               name: 'GropTopEntryField'
   978               layout: (LayoutFrame 95 0 81 0 132 0 103 0)
   979               tabable: true
   980               model: top
   981               type: number
   982               acceptChannel: acceptChannel
   983               acceptOnPointerLeave: false
   984             )
   985            (ActionButtonSpec
   986               label: 'Now'
   987               name: 'GropTopButton'
   988               layout: (LayoutFrame 148 0 81 0 221 0 103 0)
   989               translateLabel: true
   990               tabable: true
   991               model: gropTopNow
   992               autoRepeat: true
   993             )
   994            (LabelSpec
   995               label: 'Bottom:'
   996               name: 'GropBottomLabel'
   997               layout: (LayoutFrame 14 0 111 0 90 0 133 0)
   998               translateLabel: true
   999               adjust: right
  1000             )
  1001            (InputFieldSpec
  1002               name: 'GropBottomEntryField'
  1003               layout: (LayoutFrame 95 0 111 0 132 0 133 0)
  1004               tabable: true
  1005               model: bottom
  1006               type: number
  1007               acceptChannel: acceptChannel
  1008               acceptOnPointerLeave: false
  1009             )
  1010            (ActionButtonSpec
  1011               label: 'Now'
  1012               name: 'GropBottomButton'
  1013               layout: (LayoutFrame 148 0 111 0 221 0 133 0)
  1014               translateLabel: true
  1015               tabable: true
  1016               model: gropBottomNow
  1017               autoRepeat: true
  1018             )
  1019            (HorizontalPanelViewSpec
  1020               name: 'HorizontalPanel1'
  1021               layout: (LayoutFrame 0 0.0 -30 1 0 1.0 0 1)
  1022               horizontalLayout: fitSpace
  1023               verticalLayout: center
  1024               horizontalSpace: 3
  1025               verticalSpace: 3
  1026               reverseOrderIfOKAtLeft: true
  1027               component: 
  1028              (SpecCollection
  1029                 collection: (
  1030                  (ActionButtonSpec
  1031                     label: 'Cancel'
  1032                     name: 'Button1'
  1033                     translateLabel: true
  1034                     tabable: true
  1035                     model: cancel
  1036                     extent: (Point 77 22)
  1037                   )
  1038                  (ActionButtonSpec
  1039                     label: 'Apply'
  1040                     name: 'Button3'
  1041                     translateLabel: true
  1042                     tabable: true
  1043                     model: applyAction
  1044                     extent: (Point 78 22)
  1045                   )
  1046                  (ActionButtonSpec
  1047                     label: 'OK'
  1048                     name: 'Button2'
  1049                     translateLabel: true
  1050                     tabable: true
  1051                     model: accept
  1052                     extent: (Point 78 22)
  1053                   )
  1054                  )
  1055                
  1056               )
  1057             )
  1058            )
  1059          
  1060         )
  1061       )
  1062 !
  1063 
  1064 dialogSpecForNewImage
  1065     "This resource specification was automatically generated
  1066      by the UIPainter of ST/X."
  1067 
  1068     "Do not manually edit this!! If it is corrupted,
  1069      the UIPainter may not be able to read the specification."
  1070 
  1071     "
  1072      UIPainter new openOnClass:ImageEditor andSelector:#dialogSpecForNewImage
  1073      ImageEditor new openInterface:#dialogSpecForNewImage
  1074     "
  1075 
  1076     <resource: #canvas>
  1077 
  1078     ^ 
  1079      #(FullSpec
  1080         name: dialogSpecForNewImage
  1081         window: 
  1082        (WindowSpec
  1083           label: 'New Image'
  1084           name: 'New Image'
  1085           min: (Point 10 10)
  1086           bounds: (Rectangle 0 0 301 119)
  1087         )
  1088         component: 
  1089        (SpecCollection
  1090           collection: (
  1091            (ViewSpec
  1092               name: 'View'
  1093               layout: (LayoutFrame 0 0.0 0 0.0 0 1.0 -35 1.0)
  1094               level: 1
  1095               component: 
  1096              (SpecCollection
  1097                 collection: (
  1098                  (FramedBoxSpec
  1099                     label: 'Size'
  1100                     name: 'framedBox1'
  1101                     layout: (LayoutFrame 1 0.0 7 0.0 0 0.4 76 0)
  1102                     style: (FontDescription helvetica medium roman 12)
  1103                     labelPosition: topLeft
  1104                     translateLabel: true
  1105                     component: 
  1106                    (SpecCollection
  1107                       collection: (
  1108                        (ComboBoxSpec
  1109                           name: 'defaultSizesComboBox'
  1110                           layout: (LayoutFrame 0 0.0 10 0.0 0 1 35 0.0)
  1111                           model: selectionOfSize
  1112                           type: string
  1113                           acceptOnPointerLeave: false
  1114                           comboList: listOfDefaultSizes
  1115                           isFilenameBox: false
  1116                         )
  1117                        )
  1118                      
  1119                     )
  1120                   )
  1121                  (FramedBoxSpec
  1122                     label: 'Color Map'
  1123                     name: 'framedBox2'
  1124                     layout: (LayoutFrame 0 0.4 7 0.0 -1 1.0 76 0)
  1125                     style: (FontDescription helvetica medium roman 12)
  1126                     labelPosition: topLeft
  1127                     translateLabel: true
  1128                     component: 
  1129                    (SpecCollection
  1130                       collection: (
  1131                        (ComboListSpec
  1132                           name: 'colorMapComboBox'
  1133                           layout: (LayoutFrame 0 0.0 10 0.0 0 1 35 0.0)
  1134                           model: selectionOfColorMap
  1135                           comboList: listOfColorMaps
  1136                           useIndex: false
  1137                           hidePullDownMenuButton: false
  1138                         )
  1139                        )
  1140                      
  1141                     )
  1142                   )
  1143                  )
  1144                
  1145               )
  1146             )
  1147            (UISubSpecification
  1148               name: 'windowSpecForCommitWithoutChannels'
  1149               layout: (LayoutFrame 2 0.0 -26 1 -2 1.0 -2 1.0)
  1150               minorKey: windowSpecForCommitWithoutChannels
  1151             )
  1152            )
  1153          
  1154         )
  1155       )
  1156 !
  1157 
  1158 shiftDialogSpec
  1159     "This resource specification was automatically generated
  1160      by the UIPainter of ST/X."
  1161 
  1162     "Do not manually edit this!! If it is corrupted,
  1163      the UIPainter may not be able to read the specification."
  1164 
  1165     "
  1166      UIPainter new openOnClass:ImageEditor andSelector:#shiftDialogSpec
  1167      ImageEditor new openInterface:#shiftDialogSpec
  1168     "
  1169 
  1170     <resource: #canvas>
  1171 
  1172     ^ 
  1173      #(FullSpec
  1174         name: shiftDialogSpec
  1175         window: 
  1176        (WindowSpec
  1177           label: 'Shift'
  1178           name: 'Shift'
  1179           min: (Point 10 10)
  1180           bounds: (Rectangle 14 46 259 229)
  1181         )
  1182         component: 
  1183        (SpecCollection
  1184           collection: (
  1185            (LabelSpec
  1186               label: 'Amount:'
  1187               name: 'AmountLabel'
  1188               layout: (LayoutFrame 14 0 21 0 90 0 43 0)
  1189               translateLabel: true
  1190               adjust: right
  1191             )
  1192            (InputFieldSpec
  1193               name: 'AmountEntryField'
  1194               layout: (LayoutFrame 95 0 21 0 139 0 43 0)
  1195               tabable: true
  1196               model: shiftAmount
  1197               type: number
  1198               acceptChannel: acceptChannel
  1199               acceptOnPointerLeave: false
  1200             )
  1201            (HorizontalPanelViewSpec
  1202               name: 'HorizontalPanel1'
  1203               layout: (LayoutFrame 0 0.0 -30 1 0 1.0 0 1)
  1204               horizontalLayout: fitSpace
  1205               verticalLayout: center
  1206               horizontalSpace: 3
  1207               verticalSpace: 3
  1208               reverseOrderIfOKAtLeft: true
  1209               component: 
  1210              (SpecCollection
  1211                 collection: (
  1212                  (ActionButtonSpec
  1213                     label: 'Cancel'
  1214                     name: 'Button1'
  1215                     translateLabel: true
  1216                     tabable: true
  1217                     model: cancel
  1218                     extent: (Point 118 22)
  1219                   )
  1220                  (ActionButtonSpec
  1221                     label: 'OK'
  1222                     name: 'Button2'
  1223                     translateLabel: true
  1224                     tabable: true
  1225                     model: accept
  1226                     extent: (Point 118 22)
  1227                   )
  1228                  )
  1229                
  1230               )
  1231             )
  1232            (ArrowButtonSpec
  1233               name: 'upArrowButton'
  1234               layout: (LayoutFrame 105 0 63 0 127 0 85 0)
  1235               model: shiftUpNow
  1236               isTriggerOnDown: true
  1237               autoRepeat: true
  1238               actionValue: ''
  1239               direction: up
  1240             )
  1241            (ArrowButtonSpec
  1242               name: 'leftArrowButton'
  1243               layout: (LayoutFrame 84 0 86 0 106 0 108 0)
  1244               model: shiftLeftNow
  1245               isTriggerOnDown: true
  1246               autoRepeat: true
  1247               actionValue: ''
  1248               direction: left
  1249             )
  1250            (ArrowButtonSpec
  1251               name: 'rightArrowButton'
  1252               layout: (LayoutFrame 126 0 86 0 148 0 108 0)
  1253               model: shiftRightNow
  1254               isTriggerOnDown: true
  1255               autoRepeat: true
  1256               actionValue: ''
  1257               direction: right
  1258             )
  1259            (ArrowButtonSpec
  1260               name: 'downArrowButton'
  1261               layout: (LayoutFrame 105 0 107 0 127 0 129 0)
  1262               model: shiftDownNow
  1263               isTriggerOnDown: true
  1264               autoRepeat: true
  1265               actionValue: ''
  1266               direction: down
  1267             )
  1268            (CheckBoxSpec
  1269               label: 'Wrap'
  1270               name: 'CheckBox1'
  1271               layout: (LayoutFrame 153 0 22 0 289 0 44 0)
  1272               model: wrap
  1273               translateLabel: true
  1274             )
  1275            )
  1276          
  1277         )
  1278       )
  1279 !
  1280 
  1281 uncropDialogSpec
  1282     "This resource specification was automatically generated
  1283      by the UIPainter of ST/X."
  1284 
  1285     "Do not manually edit this!! If it is corrupted,
  1286      the UIPainter may not be able to read the specification."
  1287 
  1288     "
  1289      UIPainter new openOnClass:ImageEditor andSelector:#uncropDialogSpec
  1290      ImageEditor new openInterface:#uncropDialogSpec
  1291     "
  1292 
  1293     <resource: #canvas>
  1294 
  1295     ^ 
  1296      #(FullSpec
  1297         name: uncropDialogSpec
  1298         window: 
  1299        (WindowSpec
  1300           label: 'Add Border(s)'
  1301           name: 'Add Border(s)'
  1302           min: (Point 10 10)
  1303           max: (Point 800 478)
  1304           bounds: (Rectangle 0 0 261 228)
  1305         )
  1306         component: 
  1307        (SpecCollection
  1308           collection: (
  1309            (LabelSpec
  1310               label: 'Left:'
  1311               name: 'Label1'
  1312               layout: (LayoutFrame 14 0 21 0 90 0 43 0)
  1313               translateLabel: true
  1314               adjust: right
  1315             )
  1316            (InputFieldSpec
  1317               name: 'EntryField1'
  1318               layout: (LayoutFrame 95 0 21 0 132 0 43 0)
  1319               model: left
  1320               type: number
  1321               acceptOnPointerLeave: false
  1322             )
  1323            (LabelSpec
  1324               label: 'Right:'
  1325               name: 'Label2'
  1326               layout: (LayoutFrame 14 0 51 0 90 0 73 0)
  1327               translateLabel: true
  1328               adjust: right
  1329             )
  1330            (InputFieldSpec
  1331               name: 'EntryField2'
  1332               layout: (LayoutFrame 95 0 51 0 132 0 73 0)
  1333               model: right
  1334               type: number
  1335               acceptOnPointerLeave: false
  1336             )
  1337            (LabelSpec
  1338               label: 'Top:'
  1339               name: 'Label3'
  1340               layout: (LayoutFrame 14 0 81 0 90 0 103 0)
  1341               translateLabel: true
  1342               adjust: right
  1343             )
  1344            (InputFieldSpec
  1345               name: 'EntryField3'
  1346               layout: (LayoutFrame 95 0 81 0 132 0 103 0)
  1347               model: top
  1348               type: number
  1349               acceptOnPointerLeave: false
  1350             )
  1351            (LabelSpec
  1352               label: 'Bottom:'
  1353               name: 'Label4'
  1354               layout: (LayoutFrame 14 0 111 0 90 0 133 0)
  1355               translateLabel: true
  1356               adjust: right
  1357             )
  1358            (InputFieldSpec
  1359               name: 'EntryField4'
  1360               layout: (LayoutFrame 95 0 111 0 132 0 133 0)
  1361               model: bottom
  1362               type: number
  1363               acceptOnPointerLeave: false
  1364             )
  1365            (HorizontalPanelViewSpec
  1366               name: 'HorizontalPanel1'
  1367               layout: (LayoutFrame 0 0.0 -30 1 0 1.0 0 1)
  1368               horizontalLayout: fitSpace
  1369               verticalLayout: center
  1370               horizontalSpace: 3
  1371               verticalSpace: 3
  1372               reverseOrderIfOKAtLeft: true
  1373               component: 
  1374              (SpecCollection
  1375                 collection: (
  1376                  (ActionButtonSpec
  1377                     label: 'Cancel'
  1378                     name: 'Button1'
  1379                     translateLabel: true
  1380                     model: cancel
  1381                     extent: (Point 118 22)
  1382                   )
  1383                  (ActionButtonSpec
  1384                     label: 'OK'
  1385                     name: 'Button2'
  1386                     translateLabel: true
  1387                     model: accept
  1388                     extent: (Point 118 22)
  1389                   )
  1390                  )
  1391                
  1392               )
  1393             )
  1394            )
  1395          
  1396         )
  1397       )
  1398 !
  1399 
  1400 windowSpec
  1401     "This resource specification was automatically generated
  1402      by the UIPainter of ST/X."
  1403 
  1404     "Do not manually edit this!! If it is corrupted,
  1405      the UIPainter may not be able to read the specification."
  1406 
  1407     "
  1408      UIPainter new openOnClass:ImageEditor andSelector:#windowSpec
  1409      ImageEditor new openInterface:#windowSpec
  1410      ImageEditor open
  1411     "
  1412 
  1413     <resource: #canvas>
  1414 
  1415     ^ 
  1416      #(FullSpec
  1417         name: windowSpec
  1418         window: 
  1419        (WindowSpec
  1420           label: 'Image Editor'
  1421           name: 'Image Editor'
  1422           min: (Point 400 320)
  1423           bounds: (Rectangle 0 0 450 350)
  1424           menu: menu
  1425           icon: defaultIcon
  1426         )
  1427         component: 
  1428        (SpecCollection
  1429           collection: (
  1430            (MenuPanelSpec
  1431               name: 'menuToolbarView'
  1432               layout: (LayoutFrame 0 0.0 0 0 0 1.0 32 0)
  1433               style: (FontDescription helvetica medium roman 10)
  1434               menu: menuToolbar
  1435               showSeparatingLines: true
  1436             )
  1437            (VariableHorizontalPanelSpec
  1438               name: 'mainPanel'
  1439               layout: (LayoutFrame 0 0.0 34 0.0 0 1.0 -26 1.0)
  1440               snapMode: both
  1441               barLevel: 0
  1442               component: 
  1443              (SpecCollection
  1444                 collection: (
  1445                  (ViewSpec
  1446                     name: 'leftView'
  1447                     level: 1
  1448                     component: 
  1449                    (SpecCollection
  1450                       collection: (
  1451                        (VariableVerticalPanelSpec
  1452                           name: 'verticalPanel'
  1453                           layout: (LayoutFrame 0 0.0 0 0.0 0 1.0 0 1.0)
  1454                           level: 0
  1455                           snapMode: both
  1456                           component: 
  1457                          (SpecCollection
  1458                             collection: (
  1459                              (ViewSpec
  1460                                 name: 'View1'
  1461                                 component: 
  1462                                (SpecCollection
  1463                                   collection: (
  1464                                    (MenuPanelSpec
  1465                                       name: 'MouseButtonColorToolBar'
  1466                                       layout: (LayoutFrame 0 0.0 0 0 0 1.0 24 0)
  1467                                       level: 0
  1468                                       menu: menuMouseButtonColors
  1469                                     )
  1470                                    (DataSetSpec
  1471                                       name: 'colorDataSetView'
  1472                                       layout: (LayoutFrame 0 0.0 26 0.0 0 1.0 0 1.0)
  1473                                       activeHelpKey: colorMapTable
  1474                                       style: (FontDescription helvetica medium roman 10)
  1475                                       model: selectionOfColor
  1476                                       menu: colorMapMenu
  1477                                       hasHorizontalScrollBar: true
  1478                                       hasVerticalScrollBar: true
  1479                                       miniScrollerHorizontal: true
  1480                                       miniScrollerVertical: true
  1481                                       dataList: listOfColors
  1482                                       has3Dseparators: true
  1483                                       doubleClickSelector: doubleClickOnColor:
  1484                                       columnHolder: colorTableColumns
  1485                                       verticalSpacing: 1
  1486                                       columnAdaptor: colorColumnAdaptor
  1487                                     )
  1488                                    )
  1489                                  
  1490                                 )
  1491                               )
  1492                              (ArbitraryComponentSpec
  1493                                 name: 'imagePreView'
  1494                                 activeHelpKey: previewView
  1495                                 menu: previewMenu
  1496                                 hasHorizontalScrollBar: true
  1497                                 hasVerticalScrollBar: true
  1498                                 miniScrollerHorizontal: true
  1499                                 miniScrollerVertical: true
  1500                                 hasBorder: false
  1501                                 component: ImageView
  1502                               )
  1503                              )
  1504                            
  1505                           )
  1506                           handles: (Any 0.5 1.0)
  1507                         )
  1508                        )
  1509                      
  1510                     )
  1511                   )
  1512                  (ViewSpec
  1513                     name: 'rightView'
  1514                     component: 
  1515                    (SpecCollection
  1516                       collection: (
  1517                        (MenuPanelSpec
  1518                           name: 'ToolBar1'
  1519                           layout: (LayoutFrame 0 0 0 0.0 28 0 0 1.0)
  1520                           level: 1
  1521                           menu: toolsMenuToolbar
  1522                           verticalLayout: true
  1523                           centerItems: true
  1524                           textDefault: true
  1525                         )
  1526                        (ViewSpec
  1527                           name: 'editingView'
  1528                           layout: (LayoutFrame 28 0.0 0 0.0 0 1.0 0 1.0)
  1529                           level: 1
  1530                           component: 
  1531                          (SpecCollection
  1532                             collection: (
  1533                              (ArbitraryComponentSpec
  1534                                 name: 'imageEditView'
  1535                                 layout: (LayoutFrame 2 0.0 2 0.0 -2 1.0 -24 1.0)
  1536                                 hasHorizontalScrollBar: true
  1537                                 hasVerticalScrollBar: true
  1538                                 hasBorder: false
  1539                                 component: ImageEditView
  1540                               )
  1541                              (LabelSpec
  1542                                 name: 'coordLabel'
  1543                                 layout: (LayoutFrame 2 0.0 -22 1 -83 1.0 0 1.0)
  1544                                 level: -1
  1545                                 labelChannel: imageInfoHolder
  1546                                 resizeForLabel: false
  1547                                 adjust: left
  1548                               )
  1549                              (ArrowButtonSpec
  1550                                 name: 'magnifyDownButton'
  1551                                 layout: (LayoutFrame -80 1 -22 1 -58 1 0 1)
  1552                                 activeHelpKey: magnifyImageDown
  1553                                 model: doMagnifyDown
  1554                                 enableChannel: imageIsLoaded
  1555                                 isTriggerOnDown: true
  1556                                 direction: left
  1557                               )
  1558                              (ArrowButtonSpec
  1559                                 name: 'magnifyUpButton'
  1560                                 layout: (LayoutFrame -24 1 -22 1 -2 1 0 1)
  1561                                 activeHelpKey: magnifyImageUp
  1562                                 model: doMagnifyUp
  1563                                 enableChannel: imageIsLoaded
  1564                                 isTriggerOnDown: true
  1565                                 direction: right
  1566                               )
  1567                              (InputFieldSpec
  1568                                 name: 'magnificationInputField'
  1569                                 layout: (LayoutFrame -57 1 -22 1 -26 1 0 1)
  1570                                 activeHelpKey: magnificationNumber
  1571                                 enableChannel: imageIsLoaded
  1572                                 model: magnificationHolder
  1573                                 type: numberInRange
  1574                                 acceptOnReturn: true
  1575                                 acceptOnTab: true
  1576                                 numChars: 2
  1577                                 minValue: 1
  1578                                 maxValue: 99
  1579                                 acceptOnPointerLeave: true
  1580                               )
  1581                              )
  1582                            
  1583                           )
  1584                         )
  1585                        )
  1586                      
  1587                     )
  1588                   )
  1589                  )
  1590                
  1591               )
  1592               handles: (Any 0.288889 1.0)
  1593             )
  1594            (UISubSpecification
  1595               name: 'infoBarSubSpec'
  1596               layout: (LayoutFrame 0 0.0 -24 1 0 1.0 0 1.0)
  1597               majorKey: ToolApplicationModel
  1598               minorKey: windowSpecForInfoBar
  1599             )
  1600            )
  1601          
  1602         )
  1603       )
  1604 ! !
  1605 
  1606 !ImageEditor class methodsFor:'menu specs'!
  1607 
  1608 colorMapMenu
  1609     "This resource specification was automatically generated
  1610      by the MenuEditor of ST/X."
  1611 
  1612     "Do not manually edit this!! If it is corrupted,
  1613      the MenuEditor may not be able to read the specification."
  1614 
  1615     "
  1616      MenuEditor new openOnClass:ImageEditor andSelector:#colorMapMenu
  1617      (Menu new fromLiteralArrayEncoding:(ImageEditor colorMapMenu)) startUp
  1618     "
  1619 
  1620     <resource: #menu>
  1621 
  1622     ^ 
  1623      #(Menu
  1624         (
  1625          (MenuItem
  1626             enabled: hasColormap
  1627             label: 'Add Color'
  1628             itemValue: addColorToColormap
  1629             translateLabel: true
  1630           )
  1631          (MenuItem
  1632             enabled: hasColormap
  1633             label: 'Pick and Add Color...'
  1634             itemValue: pickAndAddColorToColormap
  1635             translateLabel: true
  1636           )
  1637          (MenuItem
  1638             label: '-'
  1639           )
  1640          (MenuItem
  1641             enabled: hasColormap
  1642             label: 'Cut Color'
  1643             itemValue: cutColorFromColormap
  1644             translateLabel: true
  1645             isVisible: false
  1646           )
  1647          (MenuItem
  1648             label: 'Copy Color'
  1649             itemValue: copyColorFromColormap
  1650             translateLabel: true
  1651           )
  1652          (MenuItem
  1653             enabled: hasColormap
  1654             label: 'Pick and Paste Color...'
  1655             itemValue: pickAndPasteColor
  1656             translateLabel: true
  1657           )
  1658          (MenuItem
  1659             label: 'Paste Color'
  1660             itemValue: pasteColorIntoColormap
  1661             translateLabel: true
  1662           )
  1663          (MenuItem
  1664             label: '-'
  1665           )
  1666          (MenuItem
  1667             enabled: hasColormap
  1668             label: 'Edit Color...'
  1669             itemValue: editSelectedColor
  1670             translateLabel: true
  1671           )
  1672          (MenuItem
  1673             enabled: hasColormap
  1674             label: 'Brighter'
  1675             itemValue: makeSelectedColorBrighter
  1676             translateLabel: true
  1677           )
  1678          (MenuItem
  1679             enabled: hasColormap
  1680             label: 'Darker'
  1681             itemValue: makeSelectedColorDarker
  1682             translateLabel: true
  1683           )
  1684          (MenuItem
  1685             enabled: hasColormap
  1686             label: 'Make Gray'
  1687             itemValue: makeSelectedColorGray
  1688             translateLabel: true
  1689           )
  1690          (MenuItem
  1691             label: '-'
  1692           )
  1693          (MenuItem
  1694             enabled: hasColormap
  1695             label: 'Inspect Color'
  1696             itemValue: inspectColor
  1697             translateLabel: true
  1698           )
  1699          )
  1700         nil
  1701         nil
  1702       )
  1703 
  1704     "Modified: / 27-10-2007 / 10:24:00 / cg"
  1705 !
  1706 
  1707 menu
  1708     "This resource specification was automatically generated
  1709      by the MenuEditor of ST/X."
  1710 
  1711     "Do not manually edit this!! If it is corrupted,
  1712      the MenuEditor may not be able to read the specification."
  1713 
  1714     "
  1715      MenuEditor new openOnClass:ImageEditor andSelector:#menu
  1716      (Menu new fromLiteralArrayEncoding:(ImageEditor menu)) startUp
  1717     "
  1718 
  1719     <resource: #menu>
  1720 
  1721     ^ 
  1722      #(Menu
  1723         (
  1724          (MenuItem
  1725             label: '&File'
  1726             translateLabel: true
  1727             submenuChannel: menuFile
  1728             keepLinkedMenu: true
  1729           )
  1730          (MenuItem
  1731             label: 'Edit'
  1732             translateLabel: true
  1733             submenuChannel: menuEdit
  1734             keepLinkedMenu: true
  1735           )
  1736          (MenuItem
  1737             enabled: imageIsLoaded
  1738             label: 'Mode'
  1739             translateLabel: true
  1740             submenuChannel: modeMenu
  1741           )
  1742          (MenuItem
  1743             enabled: imageIsLoaded
  1744             label: 'Colors'
  1745             translateLabel: true
  1746             submenu: 
  1747            (Menu
  1748               (
  1749                (MenuItem
  1750                   label: 'Depth'
  1751                   translateLabel: true
  1752                   submenu: 
  1753                  (Menu
  1754                     (
  1755                      (MenuItem
  1756                         activeHelpKey: colorMap1
  1757                         label: '1-Plane'
  1758                         itemValue: colorMapMode:
  1759                         translateLabel: true
  1760                         argument: depth1
  1761                         choice: colorMapMode
  1762                         choiceValue: depth1
  1763                       )
  1764                      (MenuItem
  1765                         activeHelpKey: colorMap1M
  1766                         label: '1-Plane + Mask'
  1767                         itemValue: colorMapMode:
  1768                         translateLabel: true
  1769                         argument: masked1
  1770                         choice: colorMapMode
  1771                         choiceValue: masked1
  1772                       )
  1773                      (MenuItem
  1774                         label: '-'
  1775                       )
  1776                      (MenuItem
  1777                         activeHelpKey: colorMap2
  1778                         label: '2-Plane'
  1779                         itemValue: colorMapMode:
  1780                         translateLabel: true
  1781                         argument: depth2
  1782                         choice: colorMapMode
  1783                         choiceValue: depth2
  1784                       )
  1785                      (MenuItem
  1786                         activeHelpKey: colorMap2M
  1787                         label: '2-Plane + Mask'
  1788                         itemValue: colorMapMode:
  1789                         translateLabel: true
  1790                         argument: masked2
  1791                         choice: colorMapMode
  1792                         choiceValue: masked2
  1793                       )
  1794                      (MenuItem
  1795                         label: '-'
  1796                       )
  1797                      (MenuItem
  1798                         activeHelpKey: colorMap4
  1799                         label: '4-Plane'
  1800                         itemValue: colorMapMode:
  1801                         translateLabel: true
  1802                         argument: depth4
  1803                         choice: colorMapMode
  1804                         choiceValue: depth4
  1805                       )
  1806                      (MenuItem
  1807                         activeHelpKey: colorMap4M
  1808                         label: '4-Plane + Mask'
  1809                         itemValue: colorMapMode:
  1810                         translateLabel: true
  1811                         argument: masked4
  1812                         choice: colorMapMode
  1813                         choiceValue: masked4
  1814                       )
  1815                      (MenuItem
  1816                         label: '-'
  1817                       )
  1818                      (MenuItem
  1819                         activeHelpKey: colorMap8
  1820                         label: '8-Plane'
  1821                         itemValue: colorMapMode:
  1822                         translateLabel: true
  1823                         argument: depth8
  1824                         choice: colorMapMode
  1825                         choiceValue: depth8
  1826                       )
  1827                      (MenuItem
  1828                         activeHelpKey: colorMap8M
  1829                         label: '8-Plane + Mask'
  1830                         itemValue: colorMapMode:
  1831                         translateLabel: true
  1832                         argument: masked8
  1833                         choice: colorMapMode
  1834                         choiceValue: masked8
  1835                       )
  1836                      (MenuItem
  1837                         label: '-'
  1838                       )
  1839                      (MenuItem
  1840                         activeHelpKey: colorMap16
  1841                         label: '16-Plane'
  1842                         itemValue: colorMapMode:
  1843                         translateLabel: true
  1844                         argument: depth16
  1845                         choice: colorMapMode
  1846                         choiceValue: depth16
  1847                       )
  1848                      (MenuItem
  1849                         activeHelpKey: colorMap16M
  1850                         label: '16-Plane + Mask'
  1851                         itemValue: colorMapMode:
  1852                         translateLabel: true
  1853                         argument: masked16
  1854                         choice: colorMapMode
  1855                         choiceValue: masked16
  1856                       )
  1857                      (MenuItem
  1858                         label: '-'
  1859                       )
  1860                      (MenuItem
  1861                         activeHelpKey: colorMap24
  1862                         label: '24-Plane'
  1863                         itemValue: colorMapMode:
  1864                         translateLabel: true
  1865                         argument: depth24
  1866                         choice: colorMapMode
  1867                         choiceValue: depth24
  1868                       )
  1869                      (MenuItem
  1870                         activeHelpKey: colorMap24M
  1871                         label: '24-Plane + Mask'
  1872                         itemValue: colorMapMode:
  1873                         translateLabel: true
  1874                         argument: masked24
  1875                         choice: colorMapMode
  1876                         choiceValue: masked24
  1877                       )
  1878                      )
  1879                     nil
  1880                     nil
  1881                   )
  1882                 )
  1883                (MenuItem
  1884                   label: 'ColorMap'
  1885                   translateLabel: true
  1886                   submenu: 
  1887                  (Menu
  1888                     (
  1889                      (MenuItem
  1890                         activeHelpKey: compressColormap
  1891                         enabled: hasColormap
  1892                         label: 'Compress Colormap'
  1893                         itemValue: compressColorMap
  1894                         translateLabel: true
  1895                       )
  1896                      (MenuItem
  1897                         enabled: hasColormap
  1898                         label: 'Sort Colormap'
  1899                         itemValue: sortColorMap
  1900                         translateLabel: true
  1901                       )
  1902                      (MenuItem
  1903                         label: 'Reduce Number of Colors by Rounding...'
  1904                         itemValue: reduceNumberOfColors2
  1905                         translateLabel: true
  1906                       )
  1907                      (MenuItem
  1908                         label: 'Reduce Number of Colors by Masking Bits...'
  1909                         itemValue: reduceNumberOfColors
  1910                         translateLabel: true
  1911                       )
  1912                      (MenuItem
  1913                         label: 'Dither to Depth...'
  1914                         itemValue: ditherToDepth
  1915                         translateLabel: true
  1916                       )
  1917                      )
  1918                     nil
  1919                     nil
  1920                   )
  1921                 )
  1922                (MenuItem
  1923                   label: 'Process'
  1924                   translateLabel: true
  1925                   submenu: 
  1926                  (Menu
  1927                     (
  1928                      (MenuItem
  1929                         label: 'Make GrayScale'
  1930                         itemValue: makeGrayScaleImage
  1931                         translateLabel: true
  1932                       )
  1933                      (MenuItem
  1934                         enabled: hasNoColormap
  1935                         label: 'Make dithered 8Bit Palette'
  1936                         itemValue: makeDitheredPaletteImage
  1937                         translateLabel: true
  1938                         isVisible: false
  1939                       )
  1940                      (MenuItem
  1941                         label: 'Make Brighter'
  1942                         itemValue: makeBrighter
  1943                         translateLabel: true
  1944                       )
  1945                      (MenuItem
  1946                         label: 'Make Darker'
  1947                         itemValue: makeDarker
  1948                         translateLabel: true
  1949                       )
  1950                      (MenuItem
  1951                         label: 'Make Inverse'
  1952                         itemValue: makeInverse
  1953                         translateLabel: true
  1954                       )
  1955                      (MenuItem
  1956                         label: '-'
  1957                       )
  1958                      (MenuItem
  1959                         label: 'Change HLS...'
  1960                         itemValue: changeHLS
  1961                         translateLabel: true
  1962                       )
  1963                      (MenuItem
  1964                         label: 'Colorize...'
  1965                         itemValue: colorize
  1966                         translateLabel: true
  1967                       )
  1968                      )
  1969                     nil
  1970                     nil
  1971                   )
  1972                 )
  1973                (MenuItem
  1974                   label: 'Mask'
  1975                   translateLabel: true
  1976                   submenu: 
  1977                  (Menu
  1978                     (
  1979                      (MenuItem
  1980                         activeHelpKey: copyMask
  1981                         enabled: hasMask
  1982                         label: 'Copy Mask'
  1983                         itemValue: copyMask
  1984                         translateLabel: true
  1985                       )
  1986                      (MenuItem
  1987                         activeHelpKey: pasteMask
  1988                         enabled: hasMask
  1989                         label: 'Paste Mask'
  1990                         itemValue: pasteMask
  1991                         translateLabel: true
  1992                       )
  1993                      (MenuItem
  1994                         enabled: hasMask
  1995                         label: 'Clear Masked Pixels'
  1996                         itemValue: clearMaskedPixels
  1997                         translateLabel: true
  1998                       )
  1999                      )
  2000                     nil
  2001                     nil
  2002                   )
  2003                 )
  2004                )
  2005               nil
  2006               nil
  2007             )
  2008           )
  2009          (MenuItem
  2010             label: 'Settings'
  2011             translateLabel: true
  2012             submenu: 
  2013            (Menu
  2014               (
  2015                (MenuItem
  2016                   activeHelpKey: settingsGridMagnification
  2017                   label: 'Grid Magnification Limit...'
  2018                   itemValue: doChangeGridMagnification
  2019                   translateLabel: true
  2020                 )
  2021                (MenuItem
  2022                   label: 'Pen'
  2023                   translateLabel: true
  2024                   submenu: 
  2025                  (Menu
  2026                     (
  2027                      (MenuItem
  2028                         label: '1'
  2029                         itemValue: penWidth:
  2030                         translateLabel: true
  2031                         argument: 1
  2032                       )
  2033                      (MenuItem
  2034                         label: '5'
  2035                         itemValue: penWidth:
  2036                         translateLabel: true
  2037                         argument: 5
  2038                       )
  2039                      (MenuItem
  2040                         label: '10'
  2041                         itemValue: penWidth:
  2042                         translateLabel: true
  2043                         argument: 10
  2044                       )
  2045                      )
  2046                     nil
  2047                     nil
  2048                   )
  2049                 )
  2050                (MenuItem
  2051                   label: 'Spray'
  2052                   translateLabel: true
  2053                   submenu: 
  2054                  (Menu
  2055                     (
  2056                      (MenuItem
  2057                         label: '4'
  2058                         itemValue: spraySpot:
  2059                         translateLabel: true
  2060                         argument: 4
  2061                       )
  2062                      (MenuItem
  2063                         label: '8'
  2064                         itemValue: spraySpot:
  2065                         translateLabel: true
  2066                         argument: 8
  2067                       )
  2068                      (MenuItem
  2069                         label: '16'
  2070                         itemValue: spraySpot:
  2071                         translateLabel: true
  2072                         argument: 16
  2073                       )
  2074                      (MenuItem
  2075                         label: '32'
  2076                         itemValue: spraySpot:
  2077                         translateLabel: true
  2078                         argument: 32
  2079                       )
  2080                      )
  2081                     nil
  2082                     nil
  2083                   )
  2084                 )
  2085                )
  2086               nil
  2087               nil
  2088             )
  2089           )
  2090          (MenuItem
  2091             label: 'History'
  2092             translateLabel: true
  2093             isVisible: isStandAlone
  2094             submenuChannel: menuHistory
  2095           )
  2096          (MenuItem
  2097             label: 'MENU_Help'
  2098             translateLabel: true
  2099             startGroup: conditionalRight
  2100             submenuChannel: menuHelp
  2101           )
  2102          )
  2103         nil
  2104         nil
  2105       )
  2106 !
  2107 
  2108 menuEdit
  2109     "This resource specification was automatically generated
  2110      by the MenuEditor of ST/X."
  2111 
  2112     "Do not manually edit this!! If it is corrupted,
  2113      the MenuEditor may not be able to read the specification."
  2114 
  2115     "
  2116      MenuEditor new openOnClass:ImageEditor andSelector:#menuEdit
  2117      (Menu new fromLiteralArrayEncoding:(ImageEditor menuEdit)) startUp
  2118     "
  2119 
  2120     <resource: #menu>
  2121 
  2122     ^ 
  2123      #(Menu
  2124         (
  2125          (MenuItem
  2126             activeHelpKey: editUndo
  2127             enabled: canUndoHolder
  2128             label: 'Undo'
  2129             itemValue: doUndo
  2130             translateLabel: true
  2131           )
  2132          (MenuItem
  2133             label: '-'
  2134           )
  2135          (MenuItem
  2136             activeHelpKey: editResize
  2137             label: 'Resize...'
  2138             itemValue: doResizeImage
  2139             translateLabel: true
  2140           )
  2141          (MenuItem
  2142             activeHelpKey: editMagnifyImage
  2143             label: 'Magnify...'
  2144             itemValue: doMagnifyImage
  2145             translateLabel: true
  2146           )
  2147          (MenuItem
  2148             activeHelpKey: editMagnifyImage
  2149             label: 'Magnify By...'
  2150             itemValue: doMagnifyImageBy
  2151             translateLabel: true
  2152           )
  2153          (MenuItem
  2154             activeHelpKey: editRotate
  2155             label: 'Rotate...'
  2156             itemValue: doRotateImage
  2157             translateLabel: true
  2158           )
  2159          (MenuItem
  2160             activeHelpKey: edit3DProjection
  2161             label: '3D Projection...'
  2162             itemValue: do3DProjection
  2163             translateLabel: true
  2164           )
  2165          (MenuItem
  2166             label: 'Flip'
  2167             translateLabel: true
  2168             submenu: 
  2169            (Menu
  2170               (
  2171                (MenuItem
  2172                   activeHelpKey: editFlipVertical
  2173                   label: 'Flip - Vertical'
  2174                   itemValue: doFlipVertical
  2175                   translateLabel: true
  2176                 )
  2177                (MenuItem
  2178                   activeHelpKey: editFlipHorizontal
  2179                   label: 'Flip - Horizontal'
  2180                   itemValue: doFlipHorizontal
  2181                   translateLabel: true
  2182                 )
  2183                )
  2184               nil
  2185               nil
  2186             )
  2187           )
  2188          (MenuItem
  2189             label: '-'
  2190           )
  2191          (MenuItem
  2192             label: 'Invert'
  2193             itemValue: doNegativeImage
  2194             translateLabel: true
  2195           )
  2196          (MenuItem
  2197             label: 'Brighten'
  2198             itemValue: doBrightenImage
  2199             translateLabel: true
  2200           )
  2201          (MenuItem
  2202             label: 'Darken'
  2203             itemValue: doDarkenImage
  2204             translateLabel: true
  2205           )
  2206          (MenuItem
  2207             label: '-'
  2208           )
  2209          (MenuItem
  2210             label: 'Crop'
  2211             translateLabel: true
  2212             submenu: 
  2213            (Menu
  2214               (
  2215                (MenuItem
  2216                   activeHelpKey: cropManual
  2217                   label: 'Manual...'
  2218                   itemValue: doCropManual
  2219                   translateLabel: true
  2220                 )
  2221                (MenuItem
  2222                   label: '-'
  2223                 )
  2224                (MenuItem
  2225                   activeHelpKey: cropAll
  2226                   label: 'All'
  2227                   itemValue: doCropAll
  2228                   translateLabel: true
  2229                 )
  2230                (MenuItem
  2231                   label: '-'
  2232                 )
  2233                (MenuItem
  2234                   activeHelpKey: cropLeft
  2235                   label: 'Left'
  2236                   itemValue: doCropLeft
  2237                   translateLabel: true
  2238                 )
  2239                (MenuItem
  2240                   activeHelpKey: cropRight
  2241                   label: 'Right'
  2242                   itemValue: doCropRight
  2243                   translateLabel: true
  2244                 )
  2245                (MenuItem
  2246                   activeHelpKey: cropTop
  2247                   label: 'Top'
  2248                   itemValue: doCropTop
  2249                   translateLabel: true
  2250                 )
  2251                (MenuItem
  2252                   activeHelpKey: cropBottom
  2253                   label: 'Bottom'
  2254                   itemValue: doCropBottom
  2255                   translateLabel: true
  2256                 )
  2257                )
  2258               nil
  2259               nil
  2260             )
  2261           )
  2262          (MenuItem
  2263             activeHelpKey: uncropManual
  2264             label: 'Uncrop (Add Border)...'
  2265             itemValue: doUnCropManual
  2266             translateLabel: true
  2267           )
  2268          (MenuItem
  2269             activeHelpKey: shiftManual
  2270             label: 'Shift...'
  2271             itemValue: doShiftManual
  2272             translateLabel: true
  2273           )
  2274          (MenuItem
  2275             label: '-'
  2276           )
  2277          (MenuItem
  2278             label: 'Text...'
  2279             itemValue: doInsertTextFromUser
  2280             translateLabel: true
  2281           )
  2282 
  2283          )
  2284         nil
  2285         nil
  2286       )
  2287 !
  2288 
  2289 menuFile
  2290     "This resource specification was automatically generated
  2291      by the MenuEditor of ST/X."
  2292 
  2293     "Do not manually edit this!! If it is corrupted,
  2294      the MenuEditor may not be able to read the specification."
  2295 
  2296     "
  2297      MenuEditor new openOnClass:ImageEditor andSelector:#menuFile
  2298      (Menu new fromLiteralArrayEncoding:(ImageEditor menuFile)) startUp
  2299     "
  2300 
  2301     <resource: #menu>
  2302 
  2303     ^ 
  2304      #(Menu
  2305         (
  2306          (MenuItem
  2307             activeHelpKey: fileNewImageEditor
  2308             label: 'New ImageEditor'
  2309             itemValue: doNewImageEditor
  2310             translateLabel: true
  2311           )
  2312          (MenuItem
  2313             activeHelpKey: fileNewImage
  2314             label: 'New...'
  2315             itemValue: doNewImage
  2316             translateLabel: true
  2317           )
  2318          (MenuItem
  2319             activeHelpKey: fileNewImage
  2320             label: 'New from ClipBoard'
  2321             itemValue: doNewImageFromClipboard
  2322             translateLabel: true
  2323           )
  2324          (MenuItem
  2325             label: '-'
  2326           )
  2327          (MenuItem
  2328             activeHelpKey: fileLoadFromClass
  2329             label: 'Load...'
  2330             itemValue: doLoadFromClass
  2331             translateLabel: true
  2332           )
  2333          (MenuItem
  2334             activeHelpKey: fileLoadFromFile
  2335             label: 'Load from File...'
  2336             itemValue: doLoadFromFile
  2337             translateLabel: true
  2338           )
  2339          (MenuItem
  2340             activeHelpKey: fileGrabImage
  2341             label: 'Grab from Screen...'
  2342             itemValue: grabScreenImage
  2343             translateLabel: true
  2344           )
  2345          (MenuItem
  2346             enabled: imageHasNextImage
  2347             label: 'Next in Sequence'
  2348             itemValue: nextImageInSequence
  2349             translateLabel: true
  2350             isVisible: isStandAlone
  2351           )
  2352          (MenuItem
  2353             label: '-'
  2354           )
  2355          (MenuItem
  2356             activeHelpKey: fileSaveMethod
  2357             enabled: imageIsLoadedAndClassDefined
  2358             label: 'Save'
  2359             itemValue: doSaveMethod
  2360             translateLabel: true
  2361           )
  2362          (MenuItem
  2363             activeHelpKey: fileSaveMethodAs
  2364             enabled: imageIsLoaded
  2365             label: 'Save As...'
  2366             itemValue: doSaveMethodAs
  2367             translateLabel: true
  2368           )
  2369          (MenuItem
  2370             activeHelpKey: fileSaveAs
  2371             enabled: imageIsLoaded
  2372             label: 'Save to File...'
  2373             itemValue: doSaveImageFileAs
  2374             translateLabel: true
  2375           )
  2376          (MenuItem
  2377             activeHelpKey: fileSaveMaskAs
  2378             enabled: imageIsLoaded
  2379             label: 'Save Mask to File...'
  2380             itemValue: doSaveImageMaskFileAs
  2381             translateLabel: true
  2382           )
  2383          (MenuItem
  2384             activeHelpKey: fileSaveButtonImageAs
  2385             enabled: imageIsLoaded
  2386             label: 'Save as Button to File...'
  2387             itemValue: doSaveButtonImageToFileAs
  2388             translateLabel: true
  2389           )
  2390          (MenuItem
  2391             enabled: imageIsLoaded
  2392             label: 'Copy to Clipboard'
  2393             itemValue: doCopyImageToClipboard
  2394             translateLabel: true
  2395           )
  2396          (MenuItem
  2397             label: '-'
  2398           )
  2399          (MenuItem
  2400             activeHelpKey: fileShowStoreString
  2401             enabled: imageIsLoaded
  2402             label: 'Show storeString'
  2403             itemValue: doShowStoreString
  2404             translateLabel: true
  2405           )
  2406          (MenuItem
  2407             activeHelpKey: fileEditMask
  2408             enabled: imageIsLoaded
  2409             label: 'Edit Mask'
  2410             itemValue: doEditMask
  2411             translateLabel: true
  2412           )
  2413          (MenuItem
  2414             label: '-'
  2415           )
  2416          (MenuItem
  2417             activeHelpKey: filePrint
  2418             enabled: imageIsLoaded
  2419             label: 'Print'
  2420             itemValue: doPrint
  2421             translateLabel: true
  2422           )
  2423          (MenuItem
  2424             label: '-'
  2425             isVisible: isStandAlone
  2426           )
  2427          (MenuItem
  2428             activeHelpKey: fileBrowseClass
  2429             enabled: hasClassDefined
  2430             label: 'Browse Class'
  2431             itemValue: doBrowseClass
  2432             translateLabel: true
  2433             isVisible: isStandAlone
  2434           )
  2435          (MenuItem
  2436             label: 'Inspect Image'
  2437             itemValue: doInspectImage
  2438             translateLabel: true
  2439             isVisible: isStandAlone
  2440           )
  2441          (MenuItem
  2442             label: '-'
  2443             isVisible: isStandAlone
  2444           )
  2445          (MenuItem
  2446             activeHelpKey: fileExit
  2447             label: 'Exit'
  2448             itemValue: closeRequest
  2449             translateLabel: true
  2450             isVisible: isStandAlone
  2451           )
  2452          )
  2453         nil
  2454         nil
  2455       )
  2456 !
  2457 
  2458 menuMouseButtonColors
  2459     "This resource specification was automatically generated
  2460      by the MenuEditor of ST/X."
  2461 
  2462     "Do not manually edit this!! If it is corrupted,
  2463      the MenuEditor may not be able to read the specification."
  2464 
  2465     "
  2466      MenuEditor new openOnClass:ImageEditor andSelector:#menuMouseButtonColors
  2467      (Menu new fromLiteralArrayEncoding:(ImageEditor menuMouseButtonColors)) startUp
  2468     "
  2469 
  2470     <resource: #menu>
  2471 
  2472     ^
  2473      
  2474        #(#Menu
  2475           
  2476            #(
  2477              #(#MenuItem
  2478                 #label: 'Left Mouse Button'
  2479                 #nameKey: #leftMouseKeyButton
  2480                 #activeHelpKey: #mouseKeyColorMode
  2481                 #enabled: #imageIsLoaded
  2482                 #labelImage: #(#ResourceRetriever nil #leftMouseKeyIcon)
  2483                 #choice: #mouseKeyColorMode
  2484                 #choiceValue: 1
  2485             )
  2486              #(#MenuItem
  2487                 #label: 'Right Mouse Button'
  2488                 #nameKey: #rightMouseKeyButton
  2489                 #activeHelpKey: #mouseKeyColorMode
  2490                 #enabled: #imageIsLoaded
  2491                 #labelImage: #(#ResourceRetriever nil #rightMouseKeyIcon)
  2492                 #choice: #mouseKeyColorMode
  2493                 #choiceValue: 2
  2494             )
  2495           ) nil
  2496           nil
  2497       )
  2498 !
  2499 
  2500 menuToolbar
  2501     "This resource specification was automatically generated
  2502      by the MenuEditor of ST/X."
  2503 
  2504     "Do not manually edit this!! If it is corrupted,
  2505      the MenuEditor may not be able to read the specification."
  2506 
  2507     "
  2508      MenuEditor new openOnClass:ImageEditor andSelector:#menuToolbar
  2509      (Menu new fromLiteralArrayEncoding:(ImageEditor menuToolbar)) startUp
  2510     "
  2511 
  2512     <resource: #menu>
  2513 
  2514     ^ 
  2515      #(Menu
  2516         (
  2517          (MenuItem
  2518             activeHelpKey: fileNewImage
  2519             label: 'newImage'
  2520             itemValue: doNewImage
  2521             translateLabel: true
  2522             isButton: true
  2523             labelImage: (ResourceRetriever ToolbarIconLibrary newImageIcon)
  2524           )
  2525          (MenuItem
  2526             label: '-'
  2527           )
  2528          (MenuItem
  2529             activeHelpKey: fileLoadFromClass
  2530             label: 'loadFromClass'
  2531             itemValue: doLoadFromClass
  2532             translateLabel: true
  2533             isButton: true
  2534             isVisible: isStandAlone
  2535             submenuChannel: menuHistory
  2536             labelImage: (ResourceRetriever XPToolbarIconLibrary loadImageFromMethodIcon)
  2537             keepLinkedMenu: true
  2538           )
  2539          (MenuItem
  2540             activeHelpKey: fileSaveMethodAs
  2541             enabled: imageIsLoaded
  2542             label: 'fileSaveMethodAs'
  2543             itemValue: doSaveMethodAs
  2544             translateLabel: true
  2545             isButton: true
  2546             isVisible: isStandAlone
  2547             labelImage: (ResourceRetriever XPToolbarIconLibrary saveImageAsMethodAsIcon)
  2548           )
  2549          (MenuItem
  2550             activeHelpKey: fileSaveMethod
  2551             enabled: imageIsLoaded
  2552             label: 'saveAsMethod'
  2553             itemValue: doSaveMethod
  2554             translateLabel: true
  2555             isButton: true
  2556             isVisible: isNotStandAlone
  2557             labelImage: (ResourceRetriever XPToolbarIconLibrary saveImageAsMethodAsIcon)
  2558           )
  2559          (MenuItem
  2560             label: '-'
  2561           )
  2562          (MenuItem
  2563             activeHelpKey: fileLoadFromFile
  2564             label: 'loadFromFile'
  2565             itemValue: doLoadFromFile
  2566             translateLabel: true
  2567             isButton: true
  2568             labelImage: (ResourceRetriever ToolbarIconLibrary loadImageFromFileIcon)
  2569           )
  2570          (MenuItem
  2571             activeHelpKey: fileSaveAs
  2572             enabled: imageIsLoaded
  2573             label: 'saveAsFile'
  2574             itemValue: doSaveImageFileAs
  2575             translateLabel: true
  2576             isButton: true
  2577             labelImage: (ResourceRetriever ToolbarIconLibrary saveImageToFileAsIcon)
  2578           )
  2579          (MenuItem
  2580             label: '-'
  2581           )
  2582          (MenuItem
  2583             activeHelpKey: editUndo
  2584             enabled: canUndoHolder
  2585             label: 'Undo'
  2586             itemValue: doUndo
  2587             translateLabel: true
  2588             isButton: true
  2589             labelImage: (ResourceRetriever ToolbarIconLibrary undoIcon)
  2590           )
  2591          )
  2592         nil
  2593         nil
  2594       )
  2595 !
  2596 
  2597 modeMenu
  2598     "This resource specification was automatically generated
  2599      by the MenuEditor of ST/X."
  2600 
  2601     "Do not manually edit this!! If it is corrupted,
  2602      the MenuEditor may not be able to read the specification."
  2603 
  2604     "
  2605      MenuEditor new openOnClass:ImageEditor andSelector:#modeMenu
  2606      (Menu new fromLiteralArrayEncoding:(ImageEditor modeMenu)) startUp
  2607     "
  2608 
  2609     <resource: #menu>
  2610 
  2611     ^ 
  2612      #(#Menu
  2613         #(
  2614          #(#MenuItem
  2615             #activeHelpKey: #drawModePoint
  2616             #enabled: #imageIsLoaded
  2617             #label: 'Point'
  2618             #translateLabel: true
  2619             #choice: #editMode
  2620             #choiceValue: #point
  2621           )
  2622          #(#MenuItem
  2623             #activeHelpKey: #drawModeBox
  2624             #enabled: #imageIsLoaded
  2625             #label: 'Rect'
  2626             #translateLabel: true
  2627             #choice: #editMode
  2628             #choiceValue: #box
  2629           )
  2630          #(#MenuItem
  2631             #activeHelpKey: #drawModeFilledBox
  2632             #enabled: #imageIsLoaded
  2633             #label: 'Filled Rectangle'
  2634             #translateLabel: true
  2635             #choice: #editMode
  2636             #choiceValue: #filledBox
  2637           )
  2638          #(#MenuItem
  2639             #activeHelpKey: #drawModeFill
  2640             #enabled: #imageIsLoaded
  2641             #label: 'Fill'
  2642             #translateLabel: true
  2643             #choice: #editMode
  2644             #choiceValue: #fill
  2645           )
  2646          #(#MenuItem
  2647             #activeHelpKey: #drawModeCopy
  2648             #enabled: #imageIsLoaded
  2649             #label: 'Copy'
  2650             #translateLabel: true
  2651             #choice: #editMode
  2652             #choiceValue: #copy
  2653           )
  2654          #(#MenuItem
  2655             #activeHelpKey: #drawModePaste
  2656             #enabled: #imageIsLoaded
  2657             #label: 'Paste'
  2658             #translateLabel: true
  2659             #choice: #editMode
  2660             #choiceValue: #paste
  2661           )
  2662          #(#MenuItem
  2663             #activeHelpKey: #drawModePasteUnder
  2664             #enabled: #imageIsLoaded
  2665             #label: 'Paste Under'
  2666             #translateLabel: true
  2667             #choice: #editMode
  2668             #choiceValue: #pasteUnder
  2669           )
  2670          #(#MenuItem
  2671             #activeHelpKey: #drawModePasteWithMask
  2672             #enabled: #imageIsLoaded
  2673             #label: 'Paste with Mask'
  2674             #translateLabel: true
  2675             #choice: #editMode
  2676             #choiceValue: #pasteWithMask
  2677           )
  2678          #(#MenuItem
  2679             #activeHelpKey: #drawModeSpecial
  2680             #enabled: #imageIsLoaded
  2681             #label: 'Special'
  2682             #translateLabel: true
  2683             #choice: #editMode
  2684             #choiceValue: #specialOperation
  2685           )
  2686          )
  2687         nil
  2688         nil
  2689       )
  2690 !
  2691 
  2692 previewMenu
  2693     "This resource specification was automatically generated
  2694      by the MenuEditor of ST/X."
  2695 
  2696     "Do not manually edit this!! If it is corrupted,
  2697      the MenuEditor may not be able to read the specification."
  2698 
  2699     "
  2700      MenuEditor new openOnClass:ImageEditor andSelector:#previewMenu
  2701      (Menu new fromLiteralArrayEncoding:(ImageEditor previewMenu)) startUp
  2702     "
  2703 
  2704     <resource: #menu>
  2705 
  2706     ^ 
  2707      #(Menu
  2708         (
  2709          (MenuItem
  2710             label: 'TileMode'
  2711             translateLabel: true
  2712             indication: tileModeHolder
  2713           )
  2714          (MenuItem
  2715             label: '-'
  2716           )
  2717          (MenuItem
  2718             label: 'Background Color'
  2719             translateLabel: true
  2720             submenu: 
  2721            (Menu
  2722               (
  2723                (MenuItem
  2724                   label: 'Gray'
  2725                   translateLabel: true
  2726                   choice: previewBackgroundColor
  2727                   choiceValue: nil
  2728                 )
  2729                (MenuItem
  2730                   label: 'Black'
  2731                   translateLabel: true
  2732                   choice: previewBackgroundColor
  2733                   choiceValue: black
  2734                 )
  2735                (MenuItem
  2736                   label: 'White'
  2737                   translateLabel: true
  2738                   choice: previewBackgroundColor
  2739                   choiceValue: white
  2740                 )
  2741                (MenuItem
  2742                   label: '-'
  2743                 )
  2744                (MenuItem
  2745                   label: 'Red'
  2746                   translateLabel: true
  2747                   choice: previewBackgroundColor
  2748                   choiceValue: red
  2749                 )
  2750                (MenuItem
  2751                   label: 'Green'
  2752                   translateLabel: true
  2753                   choice: previewBackgroundColor
  2754                   choiceValue: green
  2755                 )
  2756                (MenuItem
  2757                   label: 'Blue'
  2758                   translateLabel: true
  2759                   choice: previewBackgroundColor
  2760                   choiceValue: blue
  2761                 )
  2762                )
  2763               nil
  2764               nil
  2765             )
  2766           )
  2767          )
  2768         nil
  2769         nil
  2770       )
  2771 !
  2772 
  2773 toolsMenuToolbar
  2774     "This resource specification was automatically generated
  2775      by the MenuEditor of ST/X."
  2776 
  2777     "Do not manually edit this!! If it is corrupted,
  2778      the MenuEditor may not be able to read the specification."
  2779 
  2780     "
  2781      MenuEditor new openOnClass:ImageEditor andSelector:#toolsMenuToolbar
  2782      (Menu new fromLiteralArrayEncoding:(ImageEditor toolsMenuToolbar)) startUp
  2783     "
  2784 
  2785     <resource: #menu>
  2786 
  2787     ^ 
  2788      #(#Menu
  2789         #(
  2790          #(#MenuItem
  2791             #activeHelpKey: #drawModePoint
  2792             #enabled: #imageIsLoaded
  2793             #label: 'Point'
  2794             #translateLabel: true
  2795             #isButton: true
  2796             #labelImage: #(#ResourceRetriever #ImageEditor #pointIcon)
  2797             #choice: #editMode
  2798             #choiceValue: #point
  2799           )
  2800          #(#MenuItem
  2801             #activeHelpKey: #drawModeSpray
  2802             #enabled: #imageIsLoaded
  2803             #label: 'Spray'
  2804             #translateLabel: true
  2805             #isButton: true
  2806             #labelImage: #(#ResourceRetriever #ImageEditor #sprayIcon)
  2807             #choice: #editMode
  2808             #choiceValue: #spray
  2809           )
  2810          #(#MenuItem
  2811             #activeHelpKey: #drawModeBox
  2812             #enabled: #imageIsLoaded
  2813             #label: 'Rect'
  2814             #translateLabel: true
  2815             #isButton: true
  2816             #labelImage: #(#ResourceRetriever #ImageEditor #rectIcon)
  2817             #choice: #editMode
  2818             #choiceValue: #box
  2819           )
  2820          #(#MenuItem
  2821             #activeHelpKey: #drawModeFilledBox
  2822             #enabled: #imageIsLoaded
  2823             #label: 'FillRect'
  2824             #translateLabel: true
  2825             #isButton: true
  2826             #labelImage: #(#ResourceRetriever #ImageEditor #fillRectIcon)
  2827             #choice: #editMode
  2828             #choiceValue: #filledBox
  2829           )
  2830          #(#MenuItem
  2831             #activeHelpKey: #drawModeCircle
  2832             #enabled: #imageIsLoaded
  2833             #label: 'Circle'
  2834             #translateLabel: true
  2835             #isButton: true
  2836             #labelImage: #(#ResourceRetriever #ImageEditor #circleIcon)
  2837             #choice: #editMode
  2838             #choiceValue: #circle
  2839           )
  2840          #(#MenuItem
  2841             #activeHelpKey: #drawModeFill
  2842             #enabled: #imageIsLoaded
  2843             #label: 'Fill'
  2844             #translateLabel: true
  2845             #isButton: true
  2846             #labelImage: #(#ResourceRetriever #ImageEditor #fillIcon)
  2847             #choice: #editMode
  2848             #choiceValue: #fill
  2849           )
  2850          #(#MenuItem
  2851             #activeHelpKey: #drawModeCopy
  2852             #enabled: #imageIsLoaded
  2853             #label: 'Copy'
  2854             #translateLabel: true
  2855             #isButton: true
  2856             #labelImage: #(#ResourceRetriever #ImageEditor #copyIcon)
  2857             #choice: #editMode
  2858             #choiceValue: #copy
  2859           )
  2860          #(#MenuItem
  2861             #activeHelpKey: #drawModePaste
  2862             #enabled: #imageIsLoaded
  2863             #label: 'Paste'
  2864             #translateLabel: true
  2865             #isButton: true
  2866             #labelImage: #(#ResourceRetriever #ImageEditor #pasteIcon)
  2867             #choice: #editMode
  2868             #choiceValue: #paste
  2869           )
  2870          #(#MenuItem
  2871             #activeHelpKey: #drawModePasteUnder
  2872             #enabled: #imageIsLoaded
  2873             #label: 'Paste Under'
  2874             #translateLabel: true
  2875             #isButton: true
  2876             #labelImage: #(#ResourceRetriever #ImageEditor #pasteUnderIcon)
  2877             #choice: #editMode
  2878             #choiceValue: #pasteUnder
  2879           )
  2880          #(#MenuItem
  2881             #activeHelpKey: #drawModePasteWithMask
  2882             #enabled: #imageIsLoaded
  2883             #label: 'Paste With Mask'
  2884             #translateLabel: true
  2885             #isButton: true
  2886             #labelImage: #(#ResourceRetriever #ImageEditor #pasteWithMaskIcon)
  2887             #choice: #editMode
  2888             #choiceValue: #pasteWithMask
  2889           )
  2890          #(#MenuItem
  2891             #activeHelpKey: #drawModeSpecial
  2892             #enabled: #imageIsLoaded
  2893             #label: 'Special'
  2894             #translateLabel: true
  2895             #isButton: true
  2896             #labelImage: #(#ResourceRetriever #ImageEditor #specialIcon)
  2897             #choice: #editMode
  2898             #choiceValue: #specialOperation
  2899           )
  2900          )
  2901         nil
  2902         nil
  2903       )
  2904 ! !
  2905 
  2906 !ImageEditor class methodsFor:'tableColumns specs'!
  2907 
  2908 colorTableColumns
  2909     "This resource specification was automatically generated
  2910      by the DataSetBuilder of ST/X."
  2911 
  2912     "Do not manually edit this!! If it is corrupted,
  2913      the DataSetBuilder may not be able to read the specification."
  2914 
  2915     "
  2916      DataSetBuilder new openOnClass:ImageEditor andSelector:#colorTableColumns
  2917     "
  2918 
  2919     <resource: #tableColumns>
  2920 
  2921     ^#(
  2922       (DataSetColumnSpec
  2923          activeHelpKey: ''
  2924          labelButtonType: Button
  2925          rendererType: rowSelector
  2926          backgroundSelector: theColorItSelf:
  2927          selectedBackgroundSelector: theColorItSelf:
  2928          isResizeable: false
  2929        )
  2930       (DataSetColumnSpec
  2931          label: 'R'
  2932          labelAlignment: left
  2933          labelButtonType: Button
  2934          columnAlignment: right
  2935          editorType: InputField
  2936          type: number
  2937          model: redFromColor:
  2938          writeSelector: redAtColor:put:
  2939          selectSelector: canSelectRedInColor:
  2940        )
  2941       (DataSetColumnSpec
  2942          label: 'G'
  2943          labelAlignment: left
  2944          labelButtonType: Button
  2945          columnAlignment: right
  2946          editorType: InputField
  2947          type: number
  2948          model: greenFromColor:
  2949          writeSelector: greenAtColor:put:
  2950          selectSelector: canSelectGreenInColor:
  2951        )
  2952       (DataSetColumnSpec
  2953          label: 'B'
  2954          labelAlignment: left
  2955          labelButtonType: Button
  2956          columnAlignment: right
  2957          editorType: InputField
  2958          type: number
  2959          model: blueFromColor:
  2960          writeSelector: blueAtColor:put:
  2961          selectSelector: canSelectBlueInColor:
  2962        )
  2963       )
  2964 
  2965     "Modified: / 22-07-2007 / 13:21:57 / cg"
  2966 ! !
  2967 
  2968 !ImageEditor methodsFor:'accessing'!
  2969 
  2970 image
  2971     "returns the current editing image"
  2972 
  2973     ^ imageEditView image
  2974 !
  2975 
  2976 postOpenAction: anAction
  2977    "sets an action which is evaluated after opening"
  2978 
  2979     postOpenAction := anAction
  2980 !
  2981 
  2982 resourceClass:aClass
  2983     imageEditView resourceClass:aClass
  2984 ! !
  2985 
  2986 !ImageEditor methodsFor:'accessing-views'!
  2987 
  2988 colorDataSetView
  2989     "returns the view of the colormap"
  2990 
  2991     ^(self componentAt: #colorDataSetView)
  2992 
  2993     "Created: / 26.7.1998 / 12:02:14 / cg"
  2994 !
  2995 
  2996 coordLabel
  2997     "returns the view the coord label"
  2998 
  2999     ^self componentAt: #coordLabel
  3000 !
  3001 
  3002 imageEditView
  3003     "returns the view of the image"
  3004 
  3005     imageEditView isNil ifTrue:[
  3006         imageEditView := (self componentAt: #imageEditView) scrolledView.
  3007         imageEditView addDependent:self.
  3008     ].
  3009     ^ imageEditView
  3010 
  3011     "Modified: / 10.2.2000 / 23:19:20 / cg"
  3012 !
  3013 
  3014 imagePreView
  3015     "returns the preview of the image"
  3016 
  3017     |imagePreViewSubViews|
  3018 
  3019     imagePreViewSubViews := (self componentAt: #imagePreView) subViews.
  3020 
  3021     "subViews is an empty array at closing image Editor"
  3022     imagePreViewSubViews isEmptyOrNil ifTrue:[
  3023         ^ nil
  3024     ].
  3025 
  3026     ^ imagePreViewSubViews first 
  3027 ! !
  3028 
  3029 !ImageEditor methodsFor:'aspects'!
  3030 
  3031 activityInfoHolder
  3032     ^ self infoLabelHolder
  3033 
  3034     "Modified: / 29.7.1998 / 18:49:03 / cg"
  3035 !
  3036 
  3037 colorColumnAdaptor
  3038     ^ self
  3039 
  3040     "Created: / 26.7.1998 / 12:17:03 / cg"
  3041 !
  3042 
  3043 hasClassAndSelectorDefined
  3044     ^ [
  3045         |cls|
  3046 
  3047         (cls := imageEditView resourceClass) notNil
  3048         and:[imageEditView resourceSelector notNil]
  3049       ]
  3050 
  3051     "Created: / 31.7.1998 / 02:02:54 / cg"
  3052 !
  3053 
  3054 hasClassDefined
  3055     ^ [
  3056         imageEditView resourceClass notNil
  3057       ]
  3058 
  3059     "Created: / 31.7.1998 / 02:02:22 / cg"
  3060 !
  3061 
  3062 hasColormap
  3063     ^ [self image notNil and:[self image colorMap notNil]]
  3064 
  3065     "Created: / 30.9.1998 / 23:53:55 / cg"
  3066 !
  3067 
  3068 hasNoColormap
  3069     ^ [self image notNil and:[self image colorMap isNil]]
  3070 
  3071     "Created: / 30.9.1998 / 23:53:55 / cg"
  3072 !
  3073 
  3074 imageHasNextImage
  3075     "returns whether an image is loaded as value holder"
  3076 
  3077     ^ [self image notNil
  3078        and:[self image imageSequence notNil]]
  3079 
  3080     "Created: / 31.7.1998 / 02:04:18 / cg"
  3081 !
  3082 
  3083 imageInfoHolder
  3084     |holder|
  3085     (holder := builder bindingAt:#imageInfoHolder) isNil ifTrue:[
  3086         builder aspectAt:#imageInfoHolder put:(holder :=  '' asValue).
  3087     ].
  3088     ^ holder
  3089 
  3090     "Modified: / 29.7.1998 / 18:32:08 / cg"
  3091 !
  3092 
  3093 imageIsLoaded
  3094     "returns whether an image is loaded as value holder"
  3095 
  3096     |holder|
  3097     (holder := builder bindingAt:#imageIsLoaded) isNil ifTrue:[
  3098         builder aspectAt:#imageIsLoaded put:(holder :=  false asValue).
  3099     ].
  3100     ^ holder
  3101 !
  3102 
  3103 imageIsLoadedAndClassDefined
  3104     "returns whether an image is loaded as value holder"
  3105 
  3106     ^ [self hasClassAndSelectorDefined value
  3107        and:[self imageIsLoaded value]]
  3108 
  3109     "Created: / 31.7.1998 / 02:04:18 / cg"
  3110 !
  3111 
  3112 listOfColors
  3113     "returns the list of colors"
  3114 
  3115     |list|
  3116 
  3117     (list := builder bindingAt:#listOfColors) isNil ifTrue:[
  3118         builder aspectAt:#listOfColors put:(list :=  List new).
  3119         list addDependent:self.
  3120     ].
  3121     ^ list
  3122 !
  3123 
  3124 magnificationHolder
  3125     "returns current magnification of the image as an AspectAdaptor"
  3126 
  3127     |holder|
  3128     (holder := builder bindingAt:#valueOfMagnification) isNil ifTrue:[
  3129         builder aspectAt:#valueOfMagnification put:(
  3130         holder := AspectAdaptor new subject:self; forAspect:#magnification)
  3131     ].
  3132     ^ holder
  3133 !
  3134 
  3135 previewBackgroundColor
  3136     |holder|
  3137     (holder := builder bindingAt:#previewBackgroundColor) isNil ifTrue:[
  3138         builder aspectAt:#previewBackgroundColor put:(holder := nil asValue).
  3139         holder addDependent:self.
  3140     ].
  3141     ^ holder
  3142 !
  3143 
  3144 selectionOfColor
  3145     "returns a valueHolder for the current selection of the edit color.
  3146      Here, an AspectAdaptor which accesses selectedColorIndex is returned."
  3147 
  3148     |holder|
  3149 
  3150     (holder := builder bindingAt:#selectionOfColor) isNil ifTrue:[
  3151         builder aspectAt:#selectionOfColor put:(
  3152         holder := AspectAdaptor new subject:self; forAspect:#selectedColorIndex ).
  3153     ].
  3154     ^ holder
  3155 !
  3156 
  3157 tileModeHolder
  3158     |holder|
  3159     (holder := builder bindingAt:#tileModeHolder) isNil ifTrue:[
  3160         builder aspectAt:#tileModeHolder put:(holder := false asValue).
  3161         holder addDependent:self.
  3162     ].
  3163     ^ holder
  3164 !
  3165 
  3166 valueOfMagnification
  3167     <resource: #obsolete>
  3168     "returns current magnification of the image as an AspectAdaptor"
  3169 
  3170     self obsoleteMethodWarning:'stupid method name - use #magnificationHolder'.
  3171     ^ self magnificationHolder
  3172 ! !
  3173 
  3174 !ImageEditor methodsFor:'change & update'!
  3175 
  3176 findColorMapMode
  3177     "finds the colorMapMode for a new image"
  3178 
  3179     |image newListOfColors colorMapModeKey drawColor1 drawColor2 someOrAllUsedColors|
  3180 
  3181     image := self image.
  3182     image isNil ifTrue:[^ self ].
  3183 
  3184     image mask notNil ifTrue: [             
  3185         colorMapModeKey := 'masked'.
  3186     ] ifFalse:[
  3187         colorMapModeKey := 'depth'.
  3188     ].
  3189     colorMapModeKey := colorMapModeKey , image depth printString.
  3190     self colorMapMode setValue:colorMapModeKey.
  3191 
  3192 
  3193     image depth > 12 ifTrue:[
  3194         newListOfColors := OrderedCollection new.
  3195         image colorMap isEmptyOrNil ifTrue:[
  3196             someOrAllUsedColors := image usedColorsMax:10000.
  3197             someOrAllUsedColors notNil ifTrue:[
  3198                 someOrAllUsedColors := someOrAllUsedColors asArray.
  3199                 someOrAllUsedColors sort:self sortBlockForColors.
  3200                 newListOfColors addAll:someOrAllUsedColors.
  3201                 "/ listOfColors add:Color black; add:Color white.
  3202             ]
  3203         ] ifFalse:[
  3204             newListOfColors addAll:(image colorMap).
  3205         ].
  3206     ] ifFalse:[
  3207         newListOfColors := OrderedCollection withAll:(self listOfColors).
  3208         newListOfColors isEmpty ifTrue:[   
  3209             self colorMapMode: colorMapMode value.
  3210             image := self image.
  3211         ].                               
  3212     ].  
  3213     newListOfColors notEmptyOrNil ifTrue:[
  3214         drawColor1 := newListOfColors at:1.
  3215         drawColor2 := newListOfColors at:2 ifAbsent:drawColor1.
  3216 
  3217         self hasMask ifTrue: [             
  3218             (newListOfColors contains: [:clr| clr = (Color colorId:0)]) 
  3219             ifFalse:[
  3220                 newListOfColors addFirst:(Color colorId:0).
  3221                 drawColor1 := newListOfColors at:2. 
  3222                 drawColor2 := newListOfColors at:3 ifAbsent:drawColor1.
  3223             ]
  3224         ].
  3225 "/        imageEditView drawingColors:(Array with: drawColor1 with: drawColor2).
  3226 "/        self selectionOfColor 
  3227 "/            setValue: 0;
  3228 "/            value: (listOfColors indexOf: imageEditView selectedColor).
  3229     ].
  3230     self listOfColors asOrderedCollection ~= newListOfColors ifTrue:[
  3231         self listOfColors contents:newListOfColors.
  3232     ].
  3233     "Modified: / 07-07-2006 / 12:27:43 / cg"
  3234 !
  3235 
  3236 update:something with:aParameter from:changedObject
  3237     |clrIndex img imagePreView clr changedColor|
  3238 
  3239     img := self image.
  3240     imagePreView := self imagePreView.
  3241 
  3242     changedObject == self tileModeHolder ifTrue:[
  3243         imagePreView 
  3244             tileMode:(changedObject value) tileOffset:(img extent);
  3245             clear; 
  3246             invalidate.
  3247         ^ self
  3248     ].
  3249     changedObject == self previewBackgroundColor ifTrue:[
  3250         clr := changedObject value isNil 
  3251                     ifTrue:[imageEditView viewBackground]
  3252                     ifFalse:[Color perform:changedObject value].
  3253         imagePreView 
  3254             viewBackground:clr;
  3255             clear; 
  3256             invalidate.
  3257         ^ self
  3258     ].
  3259 
  3260     changedObject == self listOfColors ifTrue:[
  3261         something == #at: ifTrue:[
  3262             "/ colormap entry changed at aParameter
  3263 
  3264             clrIndex := aParameter.
  3265             (self hasMask) ifTrue:[
  3266                 clrIndex := clrIndex - 1.
  3267             ].
  3268             changedColor := changedObject at:aParameter.
  3269             img colorMap notNil ifTrue:[
  3270                 img colorMap at:clrIndex put:changedColor.
  3271                 self colorMapChanged.
  3272             ] ifFalse:[
  3273                 drawingColormap notNil ifTrue:[
  3274                     drawingColormap at:clrIndex put:changedColor.
  3275                 ].
  3276             ].
  3277             ^ self
  3278         ].
  3279         ^ self
  3280     ].
  3281 
  3282     changedObject == imageEditView undoImages ifTrue:[
  3283         self canUndoHolder value:(changedObject notEmpty).
  3284         ^ self.
  3285     ].
  3286 
  3287     changedObject == imageEditView ifTrue:[
  3288         something == #imageColors ifTrue:[
  3289             self updateListOfColorsAndColormapMode.
  3290             ^ self.
  3291         ].
  3292         something == #image ifTrue:[
  3293             imagePreView image:img.
  3294             self updateListOfColorsAndColormapMode.
  3295             self tileModeHolder value ifTrue:[
  3296                 imagePreView tileMode:true tileOffset:(img extent).
  3297             ].
  3298             ^ self.
  3299         ].
  3300         something == #subImageIn ifTrue:[
  3301             imagePreView image ~~ img ifTrue:[
  3302                 self error:'internal error' mayProceed:true.
  3303             ].
  3304             self tileModeHolder value ifTrue:[
  3305                 imagePreView invalidate.
  3306             ] ifFalse:[
  3307                 imagePreView invalidate:aParameter.
  3308             ].
  3309             ^ self.
  3310         ].
  3311         something == #selectedColor ifTrue:[
  3312             (aParameter isNil or:[aParameter = (Color colorId:0)]) ifTrue:[
  3313                 "/ no color/mask */
  3314                 "/ self halt.
  3315                 clrIndex := self hasMask ifTrue:[1] ifFalse:[0].
  3316             ] ifFalse:[
  3317                 clrIndex := self listOfColors indexOf:aParameter.
  3318             ].
  3319             self selectionOfColor value:clrIndex.
  3320             ^ self.
  3321         ].
  3322         ^ self.
  3323     ].
  3324 
  3325     changedObject == imageEditView modifiedHolder ifTrue:[
  3326         "/ self halt:'to be implemented'.
  3327         ^ self
  3328     ].
  3329 
  3330     changedObject == imageEditView image ifTrue:[
  3331         "/ self halt:'to be implemented'.
  3332         ^ self.
  3333     ].
  3334 
  3335     super update:something with:aParameter from:changedObject
  3336 
  3337     "Modified: / 10.2.2000 / 23:36:49 / cg"
  3338 !
  3339 
  3340 updateColorsFromImage:image
  3341     |colors|
  3342 
  3343     colors := image colorMap.
  3344     colors isNil ifTrue:[
  3345         Error handle:[:ex |
  3346             colors := OrderedCollection new.
  3347         ] do:[
  3348             colors := image usedColors asSet.
  3349         ]
  3350     ].
  3351     self listOfColors contents:(colors asOrderedCollection).
  3352 !
  3353 
  3354 updateForNoImage
  3355     "updates channels and view, if image is loaded"
  3356 
  3357     self imageIsLoaded value: false.
  3358     self listOfColors removeAll.
  3359     self imagePreView image: nil
  3360 
  3361 
  3362 
  3363 
  3364 !
  3365 
  3366 updateLabelsAndHistory
  3367     "updates labels and history, if something has changed"
  3368 
  3369     |image|
  3370 
  3371     image := self image.
  3372 
  3373     self imageIsLoaded value: image notNil.
  3374     image isNil ifTrue: [^nil].
  3375 
  3376     self updateInfoLabel.
  3377 
  3378     imageEditView resourceClass notNil ifTrue:[
  3379         imageEditView resourceSelector notNil ifTrue:[
  3380             self addHistoryEntryForClass:imageEditView resourceClass selector:imageEditView resourceSelector.
  3381         ]
  3382     ].
  3383 
  3384     image fileName notNil ifTrue: [
  3385         self addHistoryEntryForFile:image fileName.
  3386     ].
  3387 !
  3388 
  3389 updateListOfColorsAndColormapMode
  3390     |selectedColor colorMap image|
  3391 
  3392     selectedColor := self selectedColorOrNil.
  3393 
  3394     image := self image.
  3395     image isNil ifTrue:[
  3396         self listOfColors removeAll.
  3397     ] ifFalse:[
  3398         colorMap := image colorMap.
  3399         colorMap notNil ifTrue:[
  3400             (colorMap size <= 4096) ifTrue:[
  3401                 image mask notNil ifTrue:[
  3402                     colorMap := (Array with:(Color noColor)),colorMap.
  3403                 ].
  3404                 self listOfColors contents:colorMap.
  3405             ] ifFalse:[
  3406                 self listOfColors removeAll.
  3407                 colorMap isFixedPalette ifTrue:[
  3408                     image colorMap:nil.
  3409                     image photometric:#rgb.
  3410                     image samplesPerPixel:3.
  3411                     
  3412                     image bitsPerSample:(Array 
  3413                                             with:(colorMap bitsRed)
  3414                                             with:(colorMap bitsGreen)
  3415                                             with:(colorMap bitsBlue)).
  3416                 ].
  3417             ]
  3418         ].
  3419     ].
  3420     self findColorMapMode.
  3421     selectedColor notNil ifTrue:[
  3422         self selectColor:selectedColor.
  3423     ].
  3424 ! !
  3425 
  3426 !ImageEditor methodsFor:'data access'!
  3427 
  3428 atColor:anOldColor put:newColor
  3429     "a color changed to a new color"
  3430 
  3431     |index list oldColor image newImage oldSel|
  3432 
  3433     list  := self listOfColors.
  3434     index := list identityIndexOf:anOldColor.
  3435 
  3436     oldSel := self selectionOfColor value.
  3437     index ~~ 0 ifTrue:[
  3438         oldColor := list at:index.
  3439         list at:index put:newColor
  3440     ] ifFalse:[
  3441         self error:'internal error' mayProceed:true.
  3442         list add:newColor
  3443     ].
  3444 
  3445     image := self image.
  3446     (image colorMap isNil 
  3447     and:[drawingColormap isNil]) ifTrue:[
  3448         oldColor notNil ifTrue:[
  3449             imageEditView makeUndo.
  3450             newImage := image copy.
  3451             newImage
  3452                 colorsFromX:0 y:0 toX:(image width-1) y:(image height-1) 
  3453                 do:[:x :y :clr |
  3454                     |newClr|
  3455 
  3456                     newClr := (clr = oldColor) ifTrue:[newColor] ifFalse:[clr].
  3457                     newImage colorAtX:x y:y put:newClr
  3458                 ].
  3459             imageEditView image:newImage.
  3460             imageEditView setModified.
  3461             self updateImage.
  3462             self updateImagePreView.
  3463 
  3464             self selectionOfColor value:oldSel.
  3465             imageEditView selectedColorIndex:oldSel.
  3466             imageEditView selectedColor:(self listOfColors at:oldSel).
  3467         ]
  3468     ].
  3469 !
  3470 
  3471 blueAtColor:aColor put:newBlue
  3472     "helper used to return a new row element, when blue is changed"
  3473 
  3474     |byte|
  3475 
  3476     aColor isNil ifTrue:[^ self].       "/ mask cannot be changed
  3477     byte := newBlue clampBetween:0 and:255.
  3478     byte = aColor blueByte ifTrue:[^ self ].
  3479 
  3480     self atColor:aColor
  3481              put:(Color redByte:(aColor redByte) greenByte:(aColor greenByte) blueByte:byte).
  3482 !
  3483 
  3484 blueFromColor:aColor
  3485     "helper used to access a color as a row in the dataSet view"
  3486 
  3487     aColor isNil ifTrue:[^ 'none'].
  3488     ^ aColor blueByte ? 'mask'
  3489 
  3490     "Created: / 26.7.1998 / 12:30:35 / cg"
  3491     "Modified: / 31.7.1998 / 01:11:18 / cg"
  3492 !
  3493 
  3494 canSelectBlueInColor:aColor
  3495     ^ aColor blueByte notNil
  3496 
  3497     "Created: / 7.8.1998 / 22:50:34 / cg"
  3498     "Modified: / 7.8.1998 / 22:52:57 / cg"
  3499 !
  3500 
  3501 canSelectGreenInColor:aColor
  3502     ^ aColor greenByte notNil
  3503 
  3504     "Created: / 7.8.1998 / 22:50:22 / cg"
  3505     "Modified: / 7.8.1998 / 22:52:46 / cg"
  3506 !
  3507 
  3508 canSelectRedInColor:aColor
  3509     ^ aColor redByte notNil
  3510 
  3511     "Created: / 7.8.1998 / 22:50:00 / cg"
  3512     "Modified: / 7.8.1998 / 22:51:03 / cg"
  3513 !
  3514 
  3515 greenAtColor:aColor put:newGreen
  3516     "helper used to return a new row element, when green is changed"
  3517 
  3518     |byte|
  3519 
  3520     aColor isNil ifTrue:[^ self].       "/ mask cannot be changed
  3521     byte := newGreen clampBetween:0 and:255.
  3522     byte = aColor greenByte ifTrue:[^ self].
  3523 
  3524     self atColor:aColor
  3525              put:(Color redByte:(aColor redByte) greenByte:byte blueByte:(aColor blueByte)).
  3526 !
  3527 
  3528 greenFromColor:aColor
  3529     "helper used to access a color as a row in the dataSet view"
  3530 
  3531     aColor isNil ifTrue:[^ 'none'].
  3532     ^ aColor greenByte ? 'mask'
  3533 
  3534     "Created: / 26.7.1998 / 12:30:29 / cg"
  3535     "Modified: / 31.7.1998 / 01:11:31 / cg"
  3536 !
  3537 
  3538 redAtColor:aColor put:newRed
  3539     "helper used to return a new row element, when red is changed"
  3540 
  3541     |byte|
  3542 
  3543     aColor isNil ifTrue:[^ self].       "/ mask cannot be changed
  3544     byte := newRed clampBetween:0 and:255.
  3545     byte = aColor redByte ifTrue:[^ self].
  3546 
  3547     self atColor:aColor
  3548              put:(Color redByte:byte greenByte:(aColor greenByte) blueByte:(aColor blueByte)).
  3549 !
  3550 
  3551 redFromColor:aColor
  3552     "helper used to access a color as a row in the dataSet view"
  3553 
  3554     aColor isNil ifTrue:[^ 'none'].
  3555     ^ aColor redByte ? 'mask'
  3556 
  3557     "Modified: / 31.7.1998 / 01:11:35 / cg"
  3558 !
  3559 
  3560 theColorItSelf:aColor
  3561     ^ aColor
  3562 ! !
  3563 
  3564 !ImageEditor methodsFor:'drag & drop'!
  3565 
  3566 canDropObjects:aCollectionOfDropObjects in:aWidget
  3567     ^ (aCollectionOfDropObjects size == 1) 
  3568       and:[ aCollectionOfDropObjects 
  3569                 contains:[:dropObject | dropObject isFileObject]]
  3570 !
  3571 
  3572 dropObjects:aCollectionOfDropObjects in:aWidget at:position
  3573     |dropObject|
  3574 
  3575     dropObject := aCollectionOfDropObjects first.
  3576     dropObject isFileObject ifTrue:[
  3577         self loadFromFile:dropObject asFilename.
  3578     ]
  3579 ! !
  3580 
  3581 !ImageEditor methodsFor:'event handling'!
  3582 
  3583 processEvent:anEvent
  3584     "Return true, if I have eaten the event"
  3585 
  3586     |p|
  3587 
  3588     anEvent view == self imagePreView ifTrue:[
  3589         ((anEvent isButtonPressEvent and:[ anEvent button == 1 ])
  3590         or:[ anEvent isButtonMotionEvent and:[ anEvent hasButton1 ]])  ifTrue:[
  3591             p := anEvent x @ anEvent y.
  3592             anEvent view transformation notNil ifTrue:[
  3593                 p := anEvent view transformation applyInverseTo:p.
  3594             ].
  3595             self imageEditView scrollToMakeVisible:p.    
  3596             ^ true.
  3597         ].
  3598     ].
  3599     ^ false.
  3600 ! !
  3601 
  3602 !ImageEditor methodsFor:'help'!
  3603 
  3604 defaultInfoLabel
  3605     "returns the text shown in the info label, when the mouse is NOT over
  3606      some widget with a help text."
  3607 
  3608     |resourceClass resourceSelector|
  3609 
  3610     resourceClass := imageEditView resourceClass.
  3611     resourceClass notNil ifTrue:[
  3612         resourceSelector := imageEditView resourceSelector.
  3613         resourceSelector notNil ifTrue:[
  3614             ^ resourceClass name, ' >> ', resourceSelector
  3615         ].
  3616     ].
  3617     ^ 'No class and selector defined.'
  3618 !
  3619 
  3620 openDocumentation
  3621     "opens the documentation file of the Image Editor"
  3622 
  3623     self openHTMLDocument: 'tools/uipainter/ImageEditor.html'
  3624 
  3625 ! !
  3626 
  3627 !ImageEditor methodsFor:'loading'!
  3628 
  3629 loadFromClass:aClass andSelector:aSelector
  3630     "loads an image from the method specified by class and selector"
  3631 
  3632     self assert:(aClass isNil or:[aClass isClass]).
  3633 
  3634     (aClass isNil or:[aSelector]) isNil ifTrue:[
  3635         imageEditView resourceClass:aClass.
  3636         imageEditView resourceSelector:aSelector.
  3637         imageEditView image:nil.
  3638         self clearModified.
  3639         ^ self.
  3640     ].
  3641 
  3642 "/    (imageEditView resourceClass == aClass
  3643 "/    and:[ imageEditView resourceSelector == aSelector ]) ifTrue:[
  3644 "/        imageEditView modified ifFalse:[
  3645 "/            ^ self.
  3646 "/        ].
  3647 "/    ].
  3648 
  3649     (imageEditView loadFromClass:aClass andSelector:aSelector) notNil ifTrue:[
  3650         self updateAfterImageChange.
  3651         self clearModified.
  3652     ]
  3653 
  3654     "Modified: / 16.3.1999 / 21:44:41 / cg"
  3655 !
  3656 
  3657 loadFromFile:aFileName
  3658     "loads an image from aFileName and sets up color map list and other info labels"
  3659 
  3660     self withCursor:Cursor wait do:[
  3661         (imageEditView loadFromFile: aFileName) notNil ifTrue:[
  3662             self updateAfterImageChange
  3663         ]
  3664     ]
  3665 
  3666     "Modified: / 16.3.1999 / 21:44:26 / cg"
  3667 !
  3668 
  3669 loadFromImage:anImage
  3670     "loads an image from anImage and sets up color map list and other info labels"
  3671 
  3672     |img|
  3673 
  3674     anImage notNil ifTrue:[    
  3675         img := anImage onDevice:device.
  3676     ].
  3677 
  3678     imageEditView image:img.
  3679     imageEditView clearModified.
  3680 
  3681     self updateAfterImageChange.
  3682 "/    img notNil ifTrue:[    
  3683 "/        self updateColorsFromImage:img.
  3684 "/        self findColorMapMode.
  3685 "/        self updateLabelsAndHistory.
  3686 "/    ] ifFalse:[
  3687 "/        self updateForNoImage
  3688 "/    ]
  3689 
  3690     "Modified: / 16.3.1999 / 21:43:56 / cg"
  3691 !
  3692 
  3693 loadFromOrPrepareForClass: aClass andSelector: aSelector
  3694     "loads an image by evaluating aMessage;
  3695      if no image could extract from aMessage; do set the class and the selector from 
  3696      the aMessage for a saving at the end of editing"
  3697 
  3698     (imageEditView loadFromClass:aClass andSelector:aSelector) notNil ifTrue: [
  3699         self updateColorsFromImage:self image.
  3700         self findColorMapMode.
  3701     ] ifFalse: [
  3702         imageEditView resourceClass: aClass.
  3703         imageEditView resourceSelector:aSelector.
  3704     ].
  3705     self updateLabelsAndHistory.
  3706 
  3707     "Modified: / 16.3.1999 / 21:45:07 / cg"
  3708 !
  3709 
  3710 updateAfterImageChange
  3711     |img|
  3712 
  3713     (img := self image) notNil ifTrue:[
  3714         img := img onDevice:device.
  3715         self updateColorsFromImage:img.
  3716         self findColorMapMode.
  3717         self updateLabelsAndHistory.
  3718     ] ifFalse:[
  3719         self updateForNoImage
  3720     ]
  3721 ! !
  3722 
  3723 !ImageEditor methodsFor:'menu modes'!
  3724 
  3725 colorMapMode
  3726     "returns the colorMapMode"
  3727 
  3728     colorMapMode isNil ifTrue: [colorMapMode := '' asValue].
  3729 
  3730     ^colorMapMode
  3731 !
  3732 
  3733 editMode
  3734     "returns editMode"
  3735 
  3736     editMode isNil ifTrue: [
  3737         editMode := #point asValue.
  3738         editMode onChangeEvaluate:[imageEditView editMode:(editMode value)]
  3739     ].
  3740 
  3741     ^editMode
  3742 !
  3743 
  3744 mouseKeyColorMode
  3745     "returns mouseKeyColorMode"
  3746 
  3747     mouseKeyColorMode isNil ifTrue:[
  3748         mouseKeyColorMode := 1 asValue.
  3749         mouseKeyColorMode onChangeEvaluate: [
  3750             imageEditView mouseKeyColorMode:mouseKeyColorMode value. 
  3751             self selectionOfColor value: (self listOfColors indexOf:imageEditView selectedColor).
  3752         ]
  3753     ].
  3754 
  3755     ^mouseKeyColorMode
  3756 
  3757     "Modified: / 10.2.2000 / 23:16:42 / cg"
  3758 ! !
  3759 
  3760 !ImageEditor methodsFor:'private'!
  3761 
  3762 checkModified
  3763     imageEditView modified value ifTrue:[
  3764         (Dialog
  3765             confirm:(resources string:'Image was not saved. Proceed anyway ?')
  3766             yesLabel:(resources string:'Proceed')
  3767             noLabel:(resources string:'Cancel')
  3768             initialAnswer:false
  3769         ) ifFalse: [^false].
  3770 
  3771         imageEditView clearModified.
  3772     ].
  3773     ^ true
  3774 
  3775     "Modified: / 29.7.1998 / 18:55:24 / cg"
  3776 !
  3777 
  3778 pointFromString:aString
  3779     |p s x y|
  3780 
  3781     p := Object readFromString:aString onError:nil.
  3782     p isPoint ifTrue:[^ p].
  3783 
  3784     s := aString readStream.
  3785     x := Number readFrom:s onError:nil.
  3786     x notNil ifTrue:[
  3787         s skipSeparators.
  3788         [s atEnd not and:[s peek isDigit not]] whileTrue:[s next].
  3789         y := Number readFrom:s onError:nil.
  3790         ^ x @ (y ? x)
  3791     ].
  3792     ^ nil
  3793 !
  3794 
  3795 sortBlockForColors
  3796     ^ [:a :b |
  3797             a redByte == b redByte ifTrue:[
  3798                 a greenByte == b greenByte ifTrue:[
  3799                     a blueByte < b blueByte
  3800                 ] ifFalse:[
  3801                     a greenByte < b greenByte 
  3802                 ]
  3803             ] ifFalse:[
  3804                 a redByte < b redByte 
  3805             ]
  3806       ]
  3807 !
  3808 
  3809 updateImage
  3810     |img|
  3811 
  3812     img := imageEditView image.
  3813     imageEditView image:img.
  3814     self fetchImageData.
  3815 !
  3816 
  3817 updateImagePreView
  3818     self tileModeHolder value ifTrue:[
  3819         self imagePreView tileMode:true tileOffset:(self image extent).
  3820     ].
  3821     self imagePreView setImage:(self image) scroll:false invalidate:true.
  3822 ! !
  3823 
  3824 !ImageEditor methodsFor:'queries'!
  3825 
  3826 hasMask
  3827     ^ colorMapMode value notNil and:[colorMapMode value startsWith:'mask']
  3828 
  3829     "Created: / 18.8.1998 / 17:17:38 / cg"
  3830 !
  3831 
  3832 modified
  3833     ^ imageEditView modified
  3834 !
  3835 
  3836 modified:aBoolean
  3837     super modified:aBoolean.
  3838     imageEditView modified:aBoolean
  3839 !
  3840 
  3841 preferredExtent
  3842     "returns the preferred extent"
  3843 
  3844     ^ super preferredExtent max: (Screen current width//3)@(Screen current height//3.5)
  3845 ! !
  3846 
  3847 !ImageEditor methodsFor:'selection'!
  3848 
  3849 magnification
  3850     "returns the magnification of the image"
  3851 
  3852     self imageEditView isNil ifTrue: [^1].
  3853     ^imageEditView magnification x
  3854 !
  3855 
  3856 magnification: aValue
  3857     "sets the magnification of the image"
  3858 
  3859     |magnification|        
  3860     magnification := (aValue ? 1) asPoint.
  3861     (magnification = imageEditView magnification or: [magnification = (0@0)]) ifTrue: [^nil].
  3862     imageEditView magnification: magnification
  3863 !
  3864 
  3865 selectedColorIndex
  3866     "returns the index of the selected color"
  3867 
  3868     ^selectedColorIndex
  3869 !
  3870 
  3871 selectedColorIndex: anIndex
  3872     "sets the index of the selected color"
  3873 
  3874     |clr pixel|
  3875 
  3876     selectedColorIndex := anIndex.
  3877     anIndex isNil ifTrue:[^ self].
  3878     clr := self listOfColors at:anIndex ifAbsent:nil.
  3879     clr isNil ifTrue:[^ self].
  3880 
  3881     pixel := anIndex - 1.
  3882     (self listOfColors at:1) = Color noColor ifTrue:[
  3883         anIndex == 1 ifTrue:[
  3884             pixel := nil.       "/ mask
  3885         ] ifFalse:[
  3886             pixel := pixel - 1
  3887         ]
  3888     ].
  3889     imageEditView selectedColorIndex:pixel.
  3890     imageEditView selectedColor:clr.
  3891 ! !
  3892 
  3893 !ImageEditor methodsFor:'startup & release'!
  3894 
  3895 closeDownViews
  3896     builder notNil ifTrue:[
  3897         DefaultRelativeSizes :=
  3898             Array 
  3899                 with:(builder componentAt:#mainPanel) relativeCorners    
  3900                 with:(builder componentAt:#verticalPanel) relativeCorners.
  3901     ].
  3902     super closeDownViews
  3903 !
  3904 
  3905 closeRequest
  3906     "asks for permission before closing"
  3907 
  3908     imageEditView checkModified ifTrue:[
  3909         super closeRequest
  3910     ]
  3911 !
  3912 
  3913 commonPostBuild
  3914     imageEditView undoImages addDependent:self.
  3915     imageEditView imageInfoHolder:(self imageInfoHolder).
  3916     imageEditView activityInfoHolder:(self activityInfoHolder).
  3917 
  3918     imageEditView clickInfoCallBack:[:button :point | 
  3919                         |mouseButtonColorToolBar|
  3920 
  3921                         mouseButtonColorToolBar := self componentAt:#MouseButtonColorToolBar.
  3922                         (mouseButtonColorToolBar itemAt:button) toggleIndication.
  3923                         mouseButtonColorToolBar do: [:i| i updateIndicators].
  3924                   ].
  3925 
  3926     imageEditView addDependent:self.
  3927     imageEditView modifiedHolder addDependent:self.
  3928 
  3929     DefaultRelativeSizes notNil ifTrue:[
  3930         (builder componentAt:#mainPanel) relativeCorners:DefaultRelativeSizes first.
  3931         (builder componentAt:#verticalPanel) relativeCorners:DefaultRelativeSizes second.
  3932     ].
  3933 
  3934     "/ using masters infoHolder ?
  3935     (builder aspectAt:#useAlienInfoLabelHolder) == true ifTrue:[
  3936         (builder componentAt:#mainPanel) layout bottomOffset:0.
  3937         (builder componentAt:#infoBarSubSpec) beInvisible
  3938     ]
  3939 !
  3940 
  3941 open
  3942     "after opening, sets the masterApplication of the imageEditView to self"
  3943 
  3944     super open.
  3945 
  3946     imageEditView := (self componentAt: #imageEditView) subViews first.
  3947 !
  3948 
  3949 postOpenWith:aBuilder
  3950     "after opening, sets the masterApplication of the imageEditView to self;
  3951      evaluate the postOpenAction"
  3952 
  3953     postOpenAction value.
  3954 
  3955     super postOpenWith:aBuilder.
  3956 
  3957     aBuilder keyboardProcessor menuBar:nil.
  3958     self windowGroup addPreEventHook:self.
  3959 ! !
  3960 
  3961 !ImageEditor methodsFor:'user actions-colormap'!
  3962 
  3963 addColorToColormap
  3964     self addColorToColormap:(Color black)
  3965 !
  3966 
  3967 addColorToColormap:newColor
  3968     |depth img cMap newColorMap newImage oldCListSize newMode listOfColors|
  3969 
  3970     img := self image.
  3971     img isNil ifTrue:[
  3972         self warn:'No Image.'.
  3973         ^ self
  3974     ].
  3975 
  3976     depth := img depth.
  3977     cMap := img colorMap.
  3978     cMap isNil ifTrue:[
  3979         drawingColormap isNil ifTrue:[
  3980             self information:(resources stringWithCRs:'Image has no colormap.\The shown colorMap is for drawing only.').
  3981             drawingColormap := OrderedCollection new.
  3982         ].
  3983         drawingColormap add:newColor.
  3984         self listOfColors contents:drawingColormap.
  3985         self selectionOfColor value:(drawingColormap size).
  3986 
  3987         "/ self warn:'Image has no colormap.\Change colorMap mode first.' withCRs.
  3988         ^ self
  3989     ].
  3990 
  3991     ("(depth == 1)" false
  3992     or:[cMap size == (1 bitShift:depth)]) ifTrue:[
  3993         depth >= 8 ifTrue:[
  3994             self warn:'No space for more colors in colormap.'.
  3995             ^ self
  3996         ].
  3997         (self confirm:(resources stringWithCRs:'No space for more colors in colormap.\Change depth ?'))
  3998         ifFalse:[
  3999             ^ self
  4000         ].
  4001 
  4002         imageEditView makeUndo.
  4003         img mask notNil ifTrue:[
  4004             newMode := 'masked' , (depth*2) printString.
  4005         ] ifFalse:[
  4006             newMode := 'depth' , (depth*2) printString.
  4007         ].
  4008         self colorMapMode:newMode.
  4009     ] ifFalse:[
  4010         imageEditView makeUndo.
  4011     ].
  4012 
  4013     cMap := cMap asArray.
  4014     listOfColors := self listOfColors.
  4015     oldCListSize := listOfColors size.
  4016 
  4017     newColorMap := cMap copyWith:newColor.
  4018 
  4019     newImage := img species new
  4020                     width:img width
  4021                     height:img height
  4022                     depth:depth
  4023                     fromArray:img bits.
  4024 
  4025     newImage colorMap:newColorMap.  
  4026     newImage fileName:img fileName.
  4027     newImage mask:(img mask copy).
  4028 
  4029     (imageEditView image:newImage) notNil ifTrue:[
  4030         listOfColors contents: newImage colorMap.
  4031         self findColorMapMode.
  4032         "/ mhmh - somehow, we get two colors added ... (sigh findColorMapMode adds another one ...)
  4033         listOfColors size > (oldCListSize + 1) ifTrue:[
  4034             listOfColors removeLast
  4035         ].
  4036         self selectionOfColor value:(listOfColors size).
  4037         self updateLabelsAndHistory.
  4038     ]
  4039 
  4040     "Created: / 12.3.1999 / 00:20:28 / cg"
  4041     "Modified: / 16.3.1999 / 21:57:26 / cg"
  4042 !
  4043 
  4044 changeHLS
  4045     "interactive Hue/Light/Saturation editing"
  4046 
  4047     |bindings hueShift lightValue saturationValue originalColormap firstChange acceptChannel 
  4048      shiftAction avgColorHolder avgColor shiftedColor shiftProcess readySema
  4049      originalPixels p previewImage previewImageHolder originalPreviewColormap originalPreviewPixels
  4050      anyChange |
  4051 
  4052     "/ compute the averageColor in the background (while asking user)
  4053     avgColorHolder := nil asValue.
  4054     previewImageHolder := nil asValue.
  4055 
  4056     readySema := Semaphore new.
  4057     [
  4058         |image|
  4059 
  4060         image := imageEditView image.
  4061         originalColormap := image colorMap copy.
  4062         originalPixels := image bits.
  4063         avgColor := image averageColor.
  4064         avgColorHolder value:avgColor.
  4065 
  4066         previewImage := self image magnifiedPreservingRatioTo:100@100.
  4067         previewImageHolder value: previewImage.
  4068         originalPreviewColormap := previewImage colorMap copy.
  4069         originalPreviewPixels := previewImage bits.
  4070 
  4071         readySema signal.
  4072     ] forkAt:7.
  4073 
  4074     acceptChannel := TriggerValue new.
  4075 
  4076     firstChange := true.
  4077     anyChange := false.
  4078 
  4079     shiftedColor := [:clr :hShift :lFactor :sFactor |
  4080                         Color 
  4081                                 hue:((clr hue) ? 0 + hShift) 
  4082                                 light:((clr light * lFactor / 100) "min:100")
  4083                                 saturation:((clr saturation * sFactor / 100) "min:100")].
  4084 
  4085     shiftAction := 
  4086         [
  4087             |hShift lFactor sFactor|
  4088 
  4089             acceptChannel value:true.
  4090 
  4091             firstChange ifTrue:[
  4092                 imageEditView makeUndo.
  4093                 firstChange := false.
  4094                 anyChange := true.
  4095             ].
  4096             readySema notNil ifTrue:[readySema wait. readySema := nil].
  4097 
  4098             hShift := hueShift value.
  4099             lFactor := lightValue value.
  4100             sFactor := saturationValue value.
  4101 
  4102             avgColorHolder value:(shiftedColor value:avgColor value:hShift value:lFactor value:sFactor).
  4103 
  4104             previewImage
  4105                 colorMap:originalPreviewColormap copy;
  4106                 bits:originalPreviewPixels copy;
  4107                 release;
  4108                 colorMapProcessing:[:clr | shiftedColor value:clr value:hShift value:lFactor value:sFactor].
  4109             previewImageHolder value:nil; value:previewImage.
  4110 
  4111             shiftProcess notNil ifTrue:[
  4112                 shiftProcess terminate.
  4113                 shiftProcess waitUntilTerminated.
  4114                 shiftProcess := nil.
  4115             ].
  4116             shiftProcess := 
  4117                 [
  4118                     [
  4119                         imageEditView image 
  4120                             colorMap:originalColormap copy;
  4121                             bits:originalPixels copy;
  4122                             release;
  4123                             colorMapProcessing:[:clr | shiftedColor value:clr value:hShift value:lFactor value:sFactor].
  4124                         self updateImage.
  4125                         self updateInfoLabel.
  4126                         self updateImagePreView.
  4127                     ] ensure:[ shiftProcess := nil ].    
  4128                 ] forkAt:7.
  4129         ].
  4130 
  4131     bindings := IdentityDictionary new.
  4132     bindings at:#hueShiftAmount put:(hueShift := 0 asValue).
  4133     hueShift onChangeEvaluate:shiftAction.
  4134 
  4135     bindings at:#lightAmount put:(lightValue := 100 asValue).
  4136     lightValue onChangeEvaluate:shiftAction.
  4137 
  4138     bindings at:#saturationAmount put:(saturationValue := 100 asValue).
  4139     saturationValue onChangeEvaluate:shiftAction.
  4140 
  4141     bindings at:#acceptChannel put:acceptChannel.
  4142     bindings at:#hlsColor put:avgColorHolder.
  4143     bindings at:#previewImageHolder put:previewImageHolder.
  4144 
  4145     (self openDialogInterface:#changeHLSDialogSpec withBindings:bindings) 
  4146     ifFalse:[ 
  4147         anyChange ifTrue:[
  4148             imageEditView undo
  4149         ]
  4150     ].
  4151 
  4152     (p := shiftProcess) notNil ifTrue:[
  4153         p waitUntilTerminated.
  4154     ].
  4155 
  4156     anyChange ifTrue:[
  4157         self updateImage.
  4158         self updateImagePreView.
  4159     ].
  4160 !
  4161 
  4162 clearMaskedPixels
  4163     "clear all masked pixels (to pixelValue 0)"
  4164 
  4165     |newImage oldImage| 
  4166 
  4167     oldImage := self image.
  4168 
  4169     imageEditView makeUndo.
  4170 
  4171     self withExecuteCursorDo:[
  4172         newImage := oldImage clearMaskedPixels.
  4173         0 to:newImage height - 1 do:[:y |
  4174             0 to:newImage width - 1 do:[:x |
  4175                 (newImage maskAtX:x y:y) == 0 ifTrue:[
  4176                     newImage pixelAtX:x y:y put:0
  4177                 ]
  4178             ]
  4179         ].
  4180 
  4181         (imageEditView image:newImage) notNil ifTrue:[
  4182             self fetchImageData.
  4183         ]
  4184     ]
  4185 !
  4186 
  4187 colorMapChanged
  4188     |img|
  4189 
  4190     img := self image.
  4191     img release.
  4192 
  4193     self imageEditView invalidate.
  4194     self imagePreView invalidate.
  4195 
  4196 "/    (imageEditView image:img) notNil ifTrue:[
  4197 "/        self updateLabelsAndHistory.
  4198 "/        self imagePreView image:img
  4199 "/    ]
  4200 
  4201     "Created: / 7.8.1998 / 22:26:10 / cg"
  4202     "Modified: / 18.8.1998 / 17:08:55 / cg"
  4203 !
  4204 
  4205 colorMapMode:aMode
  4206     "calculates a new color map for the image from aMode"
  4207 
  4208     |depth numColors newColorMap newImage 
  4209      oldImage image newColors realColorMap oldFileName
  4210      usedColors useNearest usageCounts tmpBits tmpMap quest
  4211      prevMode maskThreshold maskImage| 
  4212 
  4213     self withExecuteCursorDo:[
  4214         oldImage := self image.
  4215 
  4216         prevMode := colorMapMode value.
  4217 
  4218         newColorMap := self class listOfColorMaps at:aMode.
  4219         depth       := (newColorMap size log:2) asInteger. 
  4220 
  4221         useNearest := false.
  4222         depth == 1 ifTrue:[
  4223             quest := 'Keep colormap (or use standard B&W)'
  4224         ] ifFalse:[
  4225             prevMode isNil ifTrue:[
  4226                 quest := 'Compute colormap (or use standard)'
  4227             ] ifFalse:[
  4228                 quest := 'Keep colormap (or use standard)'
  4229             ]
  4230         ].
  4231         ((prevMode = aMode)
  4232         or:[depth > oldImage depth
  4233         or:[self confirm:(resources string:quest)]]) ifTrue:[
  4234             (newColorMap isOrderedCollection or:[newColorMap isFixedPalette not]) ifTrue:[
  4235 
  4236                 "/ keep the colormap
  4237                 newColorMap atAllPut:Color black.
  4238                 depth > oldImage depth ifTrue:[
  4239                     "/ easy - simply copy the part
  4240                     numColors := 1 bitShift:oldImage depth.
  4241                     0 to:numColors-1 do:[:pixel |
  4242                         newColorMap at:(pixel+1) put:(oldImage colorFromValue:pixel)
  4243                     ].
  4244                 ] ifFalse:[
  4245                     "/ see if all used color fit the new colormap
  4246                     usedColors := oldImage usedColorsMax:(1 bitShift:depth).
  4247                     (usedColors notNil and:[usedColors size > (1 bitShift:depth)]) ifTrue:[
  4248                         usedColors := oldImage realUsedColors
  4249                     ].
  4250                     (usedColors notNil and:[usedColors size <= (1 bitShift:depth)]) ifTrue:[
  4251                         "/ yea - just install them
  4252                         usedColors asArray keysAndValuesDo:[:idx :clr |
  4253                             newColorMap at:idx put:clr
  4254                         ].
  4255                     ] ifFalse:[
  4256                         "/ copy over those that are most often used.
  4257                         oldImage depth < 8 ifTrue:[
  4258                             tmpBits := ByteArray uninitializedNew:(oldImage width*oldImage height).
  4259                             oldImage bits
  4260                                 expandPixels:(oldImage depth)
  4261                                 width:oldImage width
  4262                                 height:oldImage height 
  4263                                 into:tmpBits
  4264                                 mapping:nil.
  4265                         ] ifFalse:[
  4266                             oldImage depth == 8 ifTrue:[
  4267                                 tmpBits := oldImage bits
  4268                             ] ifFalse:[
  4269                                 colorMapMode value:prevMode.
  4270                                 self findColorMapMode.    
  4271                                 self warn:('Too many used colors in image (', oldImage usedColors size printString , ').').
  4272                                 ^ self
  4273     "/                            (self confirm:('Too many used colors in image (', oldImage usedColors size printString , ').\\Dither ?' withCRs))
  4274     "/                            ifFalse:[.
  4275     "/                                ^ self
  4276     "/                            ].
  4277     "/                            self image: (Image newForDepth:depth) fromImage:oldImage.
  4278     "/                            ^ self.
  4279                             ]
  4280                         ].
  4281                         usageCounts := tmpBits usageCounts.
  4282                         tmpMap := Array new:usageCounts size.
  4283                         oldImage colorMap asArray keysAndValuesDo:[:i :clr |
  4284                             tmpMap at:i put:clr
  4285                         ].
  4286                         usageCounts sort:[:a :b | a > b] with:tmpMap.
  4287 
  4288                         1 to:(1 bitShift:depth) do:[:idx |
  4289                             newColorMap at:idx put:(tmpMap at:idx)
  4290                         ].
  4291 
  4292                         useNearest := Dialog 
  4293                                             confirmWithCancel:(resources 
  4294                                                                   stringWithCRs:'Image requires %1 colors.\ColorMap has only space for %2\\Use nearest (or map to first color) ?'
  4295                                                                   with:usedColors size
  4296                                                                   with:(1 bitShift:depth))
  4297                                             labels:(resources array:#('Cancel' 'First' 'Nearest')).
  4298                         useNearest isNil ifTrue:[
  4299                             colorMapMode value:prevMode.
  4300                             ^ self   "/ cancel
  4301                         ].
  4302                     ]
  4303                 ]
  4304             ]
  4305         ] ifFalse:[
  4306             "/ standard colormap
  4307             usedColors := oldImage usedColors.
  4308             (usedColors conform:[:clr | newColorMap includes:clr]) ifFalse:[
  4309                 useNearest := Dialog 
  4310                                     confirmWithCancel:(resources 
  4311                                                            stringWithCRs:'Not all colors are present in the new colormap.\\Map missing ones to nearest (or map to first color) ?'
  4312                                                        ) 
  4313                                     labels:(resources string:#('Cancel' 'First' 'Nearest')).
  4314                 useNearest isNil ifTrue:[
  4315                     colorMapMode value:prevMode.
  4316                     ^ self   "/ cancel
  4317                 ].
  4318             ].
  4319         ].
  4320 
  4321         imageEditView makeUndo.
  4322 
  4323         newImage := Image newForDepth:depth.
  4324         newImage depth:depth.
  4325         newImage photometric:oldImage photometric.
  4326 
  4327         oldFileName := oldImage fileName.
  4328 
  4329         Image imageErrorSignal handle:[:ex|
  4330             Color colorErrorSignal handle:[:ex|
  4331                 colorMapMode value:prevMode.
  4332                 imageEditView undo.
  4333                 ^ self warn:(resources string:'Conversion failed !!')
  4334             ] do:[
  4335                 newImage := Image newForDepth:depth.
  4336                 newImage width:oldImage width height:oldImage height depth:depth.
  4337                 newImage colorMap:newColorMap.
  4338                 newImage photometric:#palette.
  4339                 newImage bits:(ByteArray new:(newImage bytesPerRow * newImage height)).
  4340 
  4341                 oldImage colorsFromX:0 y:0 toX:(oldImage width-1) y:(oldImage height-1) do:
  4342                 [:x :y :clr |
  4343                     |newColor|
  4344 
  4345                     (newColorMap includes:clr)
  4346                         ifTrue: [newColor := clr]
  4347                         ifFalse: [
  4348                             newColor := clr nearestIn:newColorMap.
  4349                             useNearest ifFalse:[
  4350                                 (newColor deltaFrom:clr) > 0.5 ifTrue:[
  4351                                     newColor := oldImage colorFromValue:0
  4352                                 ]
  4353                             ]
  4354                         ].
  4355                     newImage colorAtX:x y:y put:newColor.
  4356                 ].
  4357                 image := newImage
  4358             ].
  4359         ] do:[ 
  4360             image := newImage fromImage:oldImage.
  4361         ].
  4362 
  4363         (aMode asString startsWith:'mask') ifTrue:[
  4364             image mask isNil ifTrue:[
  4365                 false "(Dialog confirm:'Generate mask from black ?' default:false)" ifTrue:[
  4366                     maskThreshold := 0.1.
  4367                     maskImage := Depth1Image fromImage:(image asThresholdMonochromeImage:maskThreshold). 
  4368                 ] ifFalse:[
  4369                     maskImage := Depth1Image extent:image extent.
  4370                     maskImage bits:(ByteArray 
  4371                                         new:(maskImage bytesPerRow * maskImage height)
  4372                                         withAll:16rFF).
  4373 
  4374 "/                    maskImage fillRectangle:(image bounds) withColor:(Color colorId:1).
  4375                 ].
  4376                 image mask:maskImage.
  4377             ].
  4378         ] ifFalse:[ 
  4379             image mask: nil.
  4380         ]. 
  4381 
  4382         (newColorMap isOrderedCollection or:[newColorMap isFixedPalette not]) ifTrue:[
  4383             realColorMap := OrderedCollection new.
  4384             image realColorMap do:[:clr|
  4385                 (realColorMap includes: clr) ifFalse: [realColorMap add: clr]
  4386             ].
  4387             newColors := realColorMap copyFrom: 1 to: (newColorMap size min: realColorMap size).
  4388             newColorMap do:[:clr|
  4389                 ((newColors size < newColorMap size) and: [(newColors includes: clr) not]) 
  4390                 ifTrue:[      
  4391                     newColors add: clr
  4392                 ]
  4393             ].                  
  4394             image colorMap: newColors.   
  4395         ].
  4396         image fileName: oldFileName.
  4397 
  4398         (imageEditView image: image) notNil ifTrue:[
  4399             self fetchImageData.
  4400         ]
  4401     ]
  4402 
  4403     "Modified: / 20-07-2007 / 09:18:59 / cg"
  4404 !
  4405 
  4406 colorize
  4407     "interactive Hue editing"
  4408 
  4409     |bindings hueShift lightValue saturationValue originalColormap firstChange acceptChannel 
  4410      shiftAction avgColorHolder avgColor shiftedColor shiftProcess readySema
  4411      originalPixels p|
  4412 
  4413     "/ compute the averageColor in the background (while asking user)
  4414     readySema := Semaphore new.
  4415     [
  4416         |image|
  4417 
  4418         image := imageEditView image.
  4419         originalColormap := image colorMap copy.
  4420         avgColor := image averageColor.
  4421         originalPixels := image bits.
  4422         readySema signal.
  4423     ] forkAt:7.
  4424 
  4425     acceptChannel := TriggerValue new.
  4426     avgColorHolder := avgColor asValue.
  4427 
  4428     firstChange := true.
  4429 
  4430     shiftedColor := [:clr :hShift :lFactor :sFactor |
  4431                         Color 
  4432                                 hue:((clr hue) ? 0 + hShift) 
  4433                                 light:((clr light * lFactor / 100) "min:100")
  4434                                 saturation:(((clr saturation max:20) * sFactor / 100) "min:100")].
  4435 
  4436 
  4437     shiftAction := 
  4438         [
  4439             |hShift lFactor sFactor|
  4440 
  4441             acceptChannel value:true.
  4442 
  4443             firstChange ifTrue:[
  4444                 imageEditView makeUndo.
  4445                 firstChange := false.
  4446             ].
  4447             readySema notNil ifTrue:[readySema wait. readySema := nil].
  4448 
  4449             hShift := hueShift value.
  4450             lFactor := lightValue value.
  4451             sFactor := saturationValue value.
  4452 
  4453             avgColorHolder value:(shiftedColor value:avgColor value:hShift value:lFactor value:sFactor).
  4454 
  4455             shiftProcess notNil ifTrue:[
  4456                 shiftProcess terminate.
  4457                 shiftProcess waitUntilTerminated.
  4458                 shiftProcess := nil.
  4459             ].
  4460             shiftProcess := 
  4461                 [
  4462                     [
  4463                         imageEditView image 
  4464                             colorMap:originalColormap copy;
  4465                             bits:originalPixels copy;
  4466                             release;
  4467                             colorMapProcessing:[:clr | shiftedColor value:clr value:hShift value:lFactor value:sFactor].
  4468                         self updateImage.
  4469                         self updateInfoLabel.
  4470                         self updateImagePreView.
  4471                     ] ensure:[ shiftProcess := nil ].    
  4472                 ] forkAt:7.
  4473         ].
  4474 
  4475     bindings := IdentityDictionary new.
  4476     bindings at:#hueShiftAmount put:(hueShift := 0 asValue).
  4477     hueShift onChangeEvaluate:shiftAction.
  4478 
  4479     bindings at:#lightAmount put:(lightValue := 100 asValue).
  4480     lightValue onChangeEvaluate:shiftAction.
  4481 
  4482     bindings at:#saturationAmount put:(saturationValue := 100 asValue).
  4483     saturationValue onChangeEvaluate:shiftAction.
  4484 
  4485     bindings at:#acceptChannel put:acceptChannel.
  4486     bindings at:#hlsColor put:avgColorHolder.
  4487 
  4488     (self openDialogInterface:#changeHLSDialogSpec withBindings:bindings) 
  4489     ifFalse:[ 
  4490         firstChange ~~ true ifTrue:[
  4491             imageEditView undo
  4492         ]
  4493     ].
  4494 
  4495     (p := shiftProcess) notNil ifTrue:[
  4496         p waitUntilTerminated.
  4497     ].
  4498     self updateImage.
  4499     self updateImagePreView.
  4500 
  4501     "Created: / 01-11-2007 / 23:27:37 / cg"
  4502 !
  4503 
  4504 compressColorMap
  4505     "calculates a new color map for the image, using only used colors"
  4506 
  4507     |depth newColorMap newImage oldImage usedColors oldToNew oldBits newBits tmpBits| 
  4508 
  4509     oldImage := self image.
  4510     depth := oldImage depth.
  4511 
  4512     oldImage photometric ~~ #palette ifTrue:[
  4513         self information:'Compress colorMap: Only palette images have colormaps.'.
  4514         ^ self
  4515     ].
  4516 
  4517     usedColors := oldImage realUsedColors.
  4518     usedColors size == (1 bitShift:depth) ifTrue:[
  4519         self information:'Compress colorMap: All colors are used - no compression.'.
  4520         ^ self
  4521     ].
  4522     usedColors size == oldImage colorMap size ifTrue:[
  4523         self information:'Compress colorMap: Colormap already compressed - no compression.'.
  4524         ^ self
  4525     ].
  4526 
  4527     imageEditView makeUndo.
  4528 
  4529 "/    self information:('Compress colorMap: %1 colors used.' bindWith:usedColors size).
  4530 
  4531     self withExecuteCursorDo:[
  4532 "/        newColorMap := Array new:usedColors size.
  4533 
  4534         "/ translation table
  4535         oldToNew := ByteArray new:(1 bitShift:depth).
  4536         newColorMap := usedColors asArray.
  4537         newColorMap sort:self sortBlockForColors.
  4538 
  4539         oldImage colorMap asArray keysAndValuesDo:[:oldIdx :clr |
  4540             |newPixel|
  4541 
  4542             (usedColors includes:clr) ifTrue:[
  4543                 newPixel := newColorMap indexOf:clr.
  4544                 oldToNew at:oldIdx put:newPixel-1.
  4545             ]
  4546         ].
  4547 
  4548         oldBits := oldImage bits.
  4549         newBits := ByteArray new:(oldBits size).
  4550         depth ~~ 8 ifTrue:[
  4551             "/ expand/compress can only handle 8bits
  4552             tmpBits := ByteArray uninitializedNew:(oldImage width*oldImage height).
  4553             oldBits
  4554                 expandPixels:depth
  4555                 width:oldImage width
  4556                 height:oldImage height 
  4557                 into:tmpBits
  4558                 mapping:oldToNew.
  4559             tmpBits
  4560                 compressPixels:depth 
  4561                 width:oldImage width 
  4562                 height:oldImage height 
  4563                 into:newBits 
  4564                 mapping:nil
  4565         ] ifFalse:[
  4566             oldBits
  4567                 expandPixels:depth
  4568                 width:oldImage width
  4569                 height:oldImage height 
  4570                 into:newBits
  4571                 mapping:oldToNew.
  4572         ].
  4573 
  4574         newImage := oldImage species new
  4575                         width:oldImage width
  4576                         height:oldImage height
  4577                         depth:depth
  4578                         fromArray:newBits.
  4579 
  4580         newImage colorMap:newColorMap.  
  4581         newImage fileName:oldImage fileName.
  4582         newImage mask:(oldImage mask copy).
  4583 
  4584         (imageEditView image:newImage) notNil ifTrue:
  4585         [
  4586             self fetchImageData.
  4587         ]
  4588     ]
  4589 
  4590     "Created: / 28.7.1998 / 20:03:11 / cg"
  4591     "Modified: / 15.9.1998 / 17:53:32 / cg"
  4592 !
  4593 
  4594 copyColorFromColormap
  4595     imageEditView setClipboardObject:(self selectedColorOrNil)
  4596 !
  4597 
  4598 copyMask
  4599     |mask|
  4600 
  4601     mask := self image mask.
  4602     MaskClipboard := mask subImageIn: (0@0 extent:mask extent).
  4603 !
  4604 
  4605 ditherToDepth
  4606     |depth|
  4607 
  4608     depth := Dialog request:'New depth ?'.
  4609     depth isEmptyOrNil ifTrue:[^ self].
  4610     depth := Number readFrom:depth onError:nil.
  4611     depth isNil ifTrue:[^ self].
  4612 
  4613     self ditherToDepth:depth
  4614 
  4615     "Created: / 07-07-2006 / 13:22:10 / cg"
  4616 !
  4617 
  4618 ditherToDepth:depth
  4619     |ditherColors newImage|
  4620 
  4621     depth = 1 ifTrue:[
  4622         ditherColors := Array with:(Color black) with:(Color white).
  4623     ] ifFalse:[ depth = 2 ifTrue:[
  4624         ditherColors := Array 
  4625                             with:(Color black) 
  4626                             with:(Color darkGrey)
  4627                             with:(Color lightGrey)
  4628                             with:(Color white).
  4629     ] ifFalse:[ depth = 3 ifTrue:[
  4630         ditherColors := Color colorCubeWithRed:2 green:2 blue:2. 
  4631     ] ifFalse:[ depth = 4 ifTrue:[
  4632         ditherColors := Color vgaColors. 
  4633     ] ifFalse:[ depth = 5 ifTrue:[
  4634         ditherColors := Color colorCubeWithRed:4 green:4 blue:2. 
  4635     ] ifFalse:[ depth = 5 ifTrue:[
  4636         ditherColors := Color colorCubeWithRed:4 green:4 blue:3. 
  4637     ] ifFalse:[ depth <= 8 ifTrue:[
  4638         ditherColors := Color colorCubeWithRed:6 green:6 blue:5. 
  4639     ] ifFalse:[ 
  4640         self error:'unsupported depth'.
  4641     ]]]]]]].                           
  4642 
  4643     self withExecuteCursorDo:[
  4644         newImage := self image asDitheredImageUsing:ditherColors depth:8.
  4645 
  4646         imageEditView makeUndo.
  4647         imageEditView image:newImage.
  4648         imageEditView setModified.
  4649         self updateImage.
  4650         self updateImagePreView.
  4651 
  4652         self fetchImageData.
  4653     ].
  4654 
  4655     "Created: / 07-07-2006 / 13:20:56 / cg"
  4656     "Modified: / 05-09-2006 / 16:13:25 / cg"
  4657 !
  4658 
  4659 doubleClickOnColor:aColorIndex
  4660     self editSelectedColor.
  4661 
  4662     "Created: / 22-07-2007 / 13:14:37 / cg"
  4663 !
  4664 
  4665 editSelectedColor
  4666     self processSelectedColorWith:[:clr | 
  4667         |editor|
  4668 
  4669         editor := ColorEditDialog new.
  4670         editor color:clr.
  4671         editor open.
  4672         editor accepted ifFalse:[
  4673             AbortOperationRequest raise.
  4674         ].
  4675         editor color
  4676     ]
  4677 !
  4678 
  4679 fetchImageData
  4680     |image|
  4681 
  4682     (image := imageEditView image) notNil ifTrue:[
  4683         self findColorMapMode.
  4684         self updateLabelsAndHistory.
  4685     ]
  4686 !
  4687 
  4688 inspectColor
  4689     |clrIndex|
  4690 
  4691     clrIndex := self selectedColorIndexOrNil.
  4692     clrIndex isNil ifTrue:[
  4693         ^ self
  4694     ].
  4695     (self image colorFromValue:clrIndex-1) inspect
  4696 !
  4697 
  4698 makeBrighter
  4699     | anyChange|
  4700 
  4701     self withExecuteCursorDo:[
  4702         anyChange := imageEditView makeBrighter.
  4703         anyChange ifFalse:[
  4704             Dialog warn:'Image unchanged'.
  4705         ] ifTrue:[
  4706             self updateImage.
  4707         ]
  4708     ].
  4709 !
  4710 
  4711 makeDarker
  4712     | anyChange|
  4713 
  4714     self withExecuteCursorDo:[
  4715         anyChange := imageEditView makeDarker.
  4716         anyChange ifFalse:[
  4717             Dialog warn:'Image unchanged'.
  4718         ] ifTrue:[
  4719             self updateImage.
  4720         ]
  4721     ].
  4722 !
  4723 
  4724 makeGrayScaleImage
  4725     |anyChange|
  4726 
  4727     self withExecuteCursorDo:[
  4728         anyChange := imageEditView makeGrayScaleImage.
  4729         anyChange ifFalse:[
  4730             Dialog warn:'Image unchanged'.
  4731         ] ifTrue:[
  4732             self updateImage.
  4733         ]
  4734     ].
  4735 !
  4736 
  4737 makeInverse
  4738     | anyChange|
  4739 
  4740     self withExecuteCursorDo:[
  4741         anyChange := imageEditView makeInverse.
  4742         anyChange ifFalse:[
  4743             Dialog warn:'Image unchanged'.
  4744         ] ifTrue:[
  4745             self updateImage.
  4746         ]
  4747     ].
  4748 !
  4749 
  4750 makeSelectedColorBrighter
  4751     self processSelectedColorWith:[:clr | clr lightened]
  4752 !
  4753 
  4754 makeSelectedColorDarker
  4755     self processSelectedColorWith:[:clr | clr darkened]
  4756 !
  4757 
  4758 makeSelectedColorGray
  4759     self processSelectedColorWith:[:clr | Color brightness:(clr brightness)]
  4760 !
  4761 
  4762 pasteColorIntoColormap
  4763     |copyBufferColor|
  4764 
  4765     copyBufferColor := imageEditView getClipboardObject.
  4766     copyBufferColor isColor ifFalse:[
  4767         UserPreferences current beepInEditor ifTrue:[                
  4768             self window beep.
  4769         ].
  4770         ^ self
  4771     ].
  4772 
  4773     self processSelectedColorWith:[:clr |
  4774         copyBufferColor
  4775     ]
  4776 !
  4777 
  4778 pasteMask
  4779     |img mask|
  4780 
  4781     imageEditView makeUndo.
  4782 
  4783     img := self image.
  4784     mask := img mask.
  4785 
  4786     mask 
  4787          copyFrom:MaskClipboard
  4788          x:0 y:0
  4789          toX:0 y:0 
  4790          width:(mask width min:MaskClipboard width)
  4791          height:(mask height min:MaskClipboard height).
  4792     img mask:mask.
  4793     (imageEditView image:img copy) notNil ifTrue:[
  4794         self fetchImageData.
  4795     ]
  4796 !
  4797 
  4798 pickAndAddColorToColormap
  4799     self addColorToColormap:(Color fromUser)
  4800 !
  4801 
  4802 pickAndPasteColor
  4803     self pickColor.
  4804     self pasteColorIntoColormap.
  4805 !
  4806 
  4807 pickColor
  4808     imageEditView setClipboardObject:(Color fromUser)
  4809 !
  4810 
  4811 processSelectedColorWith:aBlock
  4812     "undoable color processing: the selected color will be replaced by the
  4813      value of aBlock"
  4814 
  4815     |img cMap modifiedColormap oldColor newImage selectedColorIndex oldSelection newColor|
  4816 
  4817     selectedColorIndex := self selectedColorIndexOrNil.
  4818     selectedColorIndex isNil ifTrue:[^ self].
  4819 
  4820     img := self image.
  4821     cMap := img colorMap.
  4822     cMap isNil ifTrue:[
  4823         self warn:(resources stringWithCRs:'Image has no colormap.\Please change the colorMap mode first.').
  4824         ^ self
  4825     ].
  4826 
  4827     oldColor := cMap at:selectedColorIndex.
  4828     imageEditView makeUndo.
  4829 
  4830     modifiedColormap := cMap asArray copy.
  4831 
  4832     newColor := aBlock value:oldColor.
  4833     modifiedColormap at:selectedColorIndex put:newColor.
  4834 
  4835     newImage := img species new
  4836                     width:img width
  4837                     height:img height
  4838                     depth:img depth
  4839                     fromArray:img bits.
  4840 
  4841     newImage colorMap:modifiedColormap.  
  4842     newImage fileName:img fileName.
  4843     newImage mask:(img mask copy).
  4844 
  4845     oldSelection := self selectionOfColor value.
  4846 
  4847     (imageEditView image:newImage) notNil ifTrue:[
  4848         self fetchImageData.
  4849     ].
  4850     self selectionOfColor value:oldSelection.
  4851 
  4852     "Created: / 12.3.1999 / 00:20:28 / cg"
  4853     "Modified: / 16.3.1999 / 21:57:26 / cg"
  4854 !
  4855 
  4856 reduceNumberOfColors
  4857     |s n anyChange img usedColors|
  4858 
  4859     s := Dialog request:'Number of color bits to strip (1-7) ?'.
  4860     s size == 0 ifTrue:[^ self].
  4861 
  4862     n := Integer readFrom:s onError:0.
  4863     (n between:1 and:7) ifFalse:[
  4864         Dialog warn:'Image unchanged'.
  4865         ^ self
  4866     ].
  4867 
  4868     self withExecuteCursorDo:[
  4869         anyChange := imageEditView reduceColorResolutionBy:n.
  4870         anyChange ifFalse:[
  4871             Dialog warn:'Image unchanged'.
  4872         ] ifTrue:[
  4873             img := imageEditView image.
  4874             imageEditView image:img.
  4875 
  4876             self fetchImageData.
  4877             usedColors := img usedColorsMax:10000.
  4878             usedColors size == 10000 ifTrue:[
  4879                 Dialog information:('>= ' , usedColors size printString , ' colors used.')
  4880             ] ifFalse:[
  4881                 Dialog information:(usedColors size printString , ' colors used.')
  4882             ]
  4883         ]
  4884     ].
  4885 !
  4886 
  4887 reduceNumberOfColors2
  4888     |s rndR rndG rndB usedColors image newImage|
  4889 
  4890     s := Dialog request:'Rounding Interval red (2..) ?' initialAnswer:4.
  4891     s size == 0 ifTrue:[^ self].
  4892     rndR := Integer readFrom:s onError:0.
  4893 
  4894     s := Dialog request:'Rounding Interval green (2..) ?' initialAnswer:2.
  4895     s size == 0 ifTrue:[^ self].
  4896     rndG := Integer readFrom:s onError:0.
  4897 
  4898     s := Dialog request:'Rounding Interval blue (2..) ?' initialAnswer:10.
  4899     s size == 0 ifTrue:[^ self].
  4900     rndB := Integer readFrom:s onError:0.
  4901 
  4902     ((rndR > 1) or:[(rndG > 1) or:[(rndB > 1)]]) ifFalse:[
  4903         Dialog warn:'Image unchanged'.
  4904         ^ self
  4905     ].
  4906 
  4907     self withExecuteCursorDo:[
  4908         image := self image.
  4909         "/ usedColors := image usedColorsMax:4096.
  4910         imageEditView makeUndo.
  4911 
  4912         newImage := image copy.
  4913         newImage photometric == #palette ifTrue:[
  4914             newImage colorMap:(OrderedCollection new).
  4915         ].
  4916 
  4917         image
  4918             colorsFromX:0 y:0 toX:(image width-1) y:(image height-1) 
  4919             do:[:x :y :clr |
  4920                 |r g b nr ng nb newClr|
  4921 
  4922                 r := clr redByte.
  4923                 g := clr greenByte.
  4924                 b := clr blueByte. 
  4925                 nr := (r roundTo:rndR) min:255.
  4926                 ng := (g roundTo:rndG) min:255.
  4927                 nb := (b roundTo:rndB) min:255. 
  4928 
  4929                 newClr := Color redByte:nr greenByte:ng blueByte:nb.
  4930                 newImage photometric == #palette ifTrue:[
  4931                     (newImage colorMap includes:newClr) ifFalse:[
  4932                         newImage colorMap add:newClr
  4933                     ].
  4934                 ].
  4935                 newImage colorAtX:x y:y put:newClr
  4936             ].
  4937 
  4938         imageEditView image:newImage.
  4939         imageEditView setModified.
  4940         self updateImage.
  4941         self updateImagePreView.
  4942 
  4943         self fetchImageData.
  4944         usedColors := newImage usedColorsMax:10000.
  4945         usedColors size == 10000 ifTrue:[
  4946             Dialog information:('>= ' , usedColors size printString , ' colors used.')
  4947         ] ifFalse:[
  4948             Dialog information:(usedColors size printString , ' colors used.')
  4949         ]
  4950     ].
  4951 
  4952     "Modified: / 07-07-2006 / 13:10:42 / cg"
  4953 !
  4954 
  4955 selectColor:aColor
  4956     |idx img cMap|
  4957 
  4958     aColor isNil ifTrue:[
  4959         idx := nil.
  4960     ] ifFalse:[
  4961         aColor == Color noColor ifTrue:[
  4962             img mask notNil ifTrue:[
  4963                 idx := 1.
  4964             ]
  4965         ] ifFalse:[
  4966             (img := self image) notNil ifTrue:[
  4967                 (cMap := self listOfColors) notNil ifTrue:[
  4968                     idx := cMap indexOf:aColor ifAbsent:nil.
  4969                 ].
  4970                 idx isNil ifTrue:[
  4971                     "/ should not happen...
  4972                     (cMap := img colorMap) notNil ifTrue:[
  4973                         idx := cMap indexOf:aColor ifAbsent:nil.
  4974                         idx notNil ifTrue:[
  4975                             img mask notNil ifTrue:[
  4976                                 idx := idx + 1.
  4977                             ].
  4978                         ]
  4979                     ].
  4980                 ].
  4981             ].
  4982         ].
  4983     ].
  4984     self selectionOfColor value:idx.
  4985 !
  4986 
  4987 selectedColorIndexOrNil
  4988     | img clrIndex|
  4989 
  4990     img := self image.
  4991     img isNil ifTrue:[
  4992         self warn:'No Image.'.
  4993         ^ nil
  4994     ].
  4995     clrIndex := self selectionOfColor value.
  4996     self hasMask "img mask notNil" ifTrue: [ 
  4997         (clrIndex isInteger and:[clrIndex > 1]) ifTrue:[
  4998             ^ clrIndex - 1 
  4999         ].
  5000         ^ nil
  5001     ].
  5002     ^ clrIndex
  5003 !
  5004 
  5005 selectedColorOrNil
  5006     |cmapIndex img cMap colorList|
  5007 
  5008     cmapIndex := self selectedColorIndexOrNil.
  5009     cmapIndex isNil ifTrue:[^ nil].
  5010     cmapIndex == 0 ifTrue:[^ nil].
  5011 
  5012     img := self image.
  5013     cMap := img colorMap.
  5014     cMap isNil ifTrue:[
  5015         "/ self warn:(resources stringWithCRs:'Image has no colormap.\Please change the colorMap mode first.').
  5016         colorList := self listOfColors.
  5017         colorList notNil ifTrue:[
  5018             ^ colorList at:cmapIndex ifAbsent:nil
  5019         ].
  5020         ^ nil
  5021     ].
  5022     ^ cMap at:cmapIndex.
  5023 !
  5024 
  5025 sortColorMap
  5026     "calculates a new color map for the image, sorting colors"
  5027 
  5028     self 
  5029         sortColorMapWith:self sortBlockForColors
  5030 !
  5031 
  5032 sortColorMapWith:sortBlock
  5033     "calculates a new color map for the image, sorting colors"
  5034 
  5035     |depth newColorMap newImage oldImage usedColors oldToNew oldBits newBits tmpBits| 
  5036 
  5037     oldImage := self image.
  5038     depth := oldImage depth.
  5039 
  5040     oldImage photometric ~~ #palette ifTrue:[
  5041         self information:'Compress colorMap: Only palette images have colormaps.'.
  5042         ^ self
  5043     ].
  5044 
  5045     usedColors := oldImage realColorMap.
  5046 
  5047     imageEditView makeUndo.
  5048 
  5049     self withExecuteCursorDo:[
  5050 "/        newColorMap := Array new:usedColors size.
  5051 
  5052         "/ translation table
  5053         oldToNew := ByteArray new:(1 bitShift:depth).
  5054         newColorMap := usedColors asArray.
  5055         newColorMap sort:sortBlock.
  5056 
  5057         oldImage colorMap asArray keysAndValuesDo:[:oldIdx :clr |
  5058             |newPixel|
  5059 
  5060             (usedColors includes:clr) ifTrue:[
  5061                 newPixel := newColorMap indexOf:clr.
  5062                 oldToNew at:oldIdx put:newPixel-1.
  5063             ]
  5064         ].
  5065 
  5066         oldBits := oldImage bits.
  5067         newBits := ByteArray new:(oldBits size).
  5068         depth ~~ 8 ifTrue:[
  5069             "/ expand/compress can only handle 8bits
  5070             tmpBits := ByteArray uninitializedNew:(oldImage width*oldImage height).
  5071             oldBits
  5072                 expandPixels:depth
  5073                 width:oldImage width
  5074                 height:oldImage height 
  5075                 into:tmpBits
  5076                 mapping:oldToNew.
  5077             tmpBits
  5078                 compressPixels:depth 
  5079                 width:oldImage width 
  5080                 height:oldImage height 
  5081                 into:newBits 
  5082                 mapping:nil
  5083         ] ifFalse:[
  5084             oldBits
  5085                 expandPixels:depth
  5086                 width:oldImage width
  5087                 height:oldImage height 
  5088                 into:newBits
  5089                 mapping:oldToNew.
  5090         ].
  5091 
  5092         newImage := oldImage species new
  5093                         width:oldImage width
  5094                         height:oldImage height
  5095                         depth:depth
  5096                         fromArray:newBits.
  5097 
  5098         newImage colorMap:newColorMap.  
  5099         newImage fileName:oldImage fileName.
  5100         newImage mask:(oldImage mask copy).
  5101 
  5102         (imageEditView image:newImage) notNil ifTrue:[
  5103             self fetchImageData.
  5104         ]
  5105     ]
  5106 
  5107     "Modified: / 15.9.1998 / 17:53:32 / cg"
  5108     "Created: / 30.9.1998 / 23:51:23 / cg"
  5109 ! !
  5110 
  5111 !ImageEditor methodsFor:'user actions-editing'!
  5112 
  5113 do3DProjection
  5114     |box dx1 dx2 image|
  5115 
  5116     image := imageEditView image.
  5117 
  5118     box := EnterBox new.
  5119     box title:(resources string:'dX1 (0 < dx < 0.5):').
  5120     box okText:(resources string:'OK').
  5121     box abortText:(resources string:'Cancel').
  5122     box initialText:'0.1'.
  5123     box showAtPointer.
  5124 
  5125     (box accepted 
  5126     and: [(dx1 := Number readFrom:(box contents) onError:nil) notNil])
  5127     ifTrue:[
  5128         box title:(resources string:'dX2 (0 < dx < 0.5):').
  5129         box initialText:(dx1 printString).
  5130         box showAtPointer.
  5131         (box accepted 
  5132         and: [(dx2 := Number readFrom:(box contents) onError:nil) notNil])
  5133         ifTrue:[
  5134             imageEditView threeDProjection:dx1 and:dx2.
  5135         ]
  5136     ].
  5137 
  5138     self updateInfoLabel
  5139 !
  5140 
  5141 doBrightenImage
  5142     imageEditView brightenImage.
  5143     self listOfColors removeAll.
  5144     self findColorMapMode.     
  5145     imageEditView removelastUndo
  5146 !
  5147 
  5148 doBrowseClass
  5149     "opens a System Browser on the resourceClass and the resourceSelector"
  5150 
  5151     |cls|
  5152 
  5153     cls := imageEditView resourceClass.
  5154     cls isNil ifTrue:[^ self warn:'No Class specified'].
  5155 
  5156     UserPreferences systemBrowserClass
  5157         openInClass:cls class 
  5158         selector:(imageEditView resourceSelector)
  5159 
  5160     "Modified: / 31.7.1998 / 02:01:15 / cg"
  5161 !
  5162 
  5163 doCopyImageToClipboard
  5164     imageEditView copyImageToClipboard.
  5165 !
  5166 
  5167 doCropAll
  5168     "find all borders and cut them off"
  5169 
  5170     imageEditView cropLeft:true right:true top:true bottom:true.   
  5171     self updateInfoLabel
  5172 
  5173     "Modified: / 7.9.1998 / 14:26:23 / cg"
  5174     "Created: / 7.9.1998 / 16:33:43 / cg"
  5175 !
  5176 
  5177 doCropBottom
  5178     "find a bottom border and cut it off"
  5179 
  5180     imageEditView cropLeft:false right:false top:false bottom:true.   
  5181     self updateInfoLabel
  5182 
  5183     "Created: / 7.9.1998 / 13:00:20 / cg"
  5184     "Modified: / 7.9.1998 / 14:26:23 / cg"
  5185 !
  5186 
  5187 doCropLeft
  5188     "find a left border and cut it off"
  5189 
  5190     imageEditView cropLeft:true right:false top:false bottom:false.   
  5191     self updateInfoLabel
  5192 
  5193     "Created: / 7.9.1998 / 13:00:14 / cg"
  5194     "Modified: / 7.9.1998 / 14:26:34 / cg"
  5195 !
  5196 
  5197 doCropManual
  5198     "let user specify borders and cut them off"
  5199 
  5200     |bindings left top right bottom img firstChange gropAction acceptChannel|
  5201 
  5202     acceptChannel := TriggerValue new.
  5203 
  5204     firstChange := true.
  5205 
  5206     gropAction := 
  5207         [:lV :rV :tV :bV | |l r t b|
  5208             acceptChannel value:true.
  5209 
  5210             l := lV value.
  5211             r := rV value.
  5212             t := tV value.
  5213             b := bV value.
  5214             (l + r + t + b) == 0 ifTrue:[
  5215                 UserPreferences current beepInEditor ifTrue:[                
  5216                     self window beep
  5217                 ]
  5218             ] ifFalse:[
  5219                 img := imageEditView image.
  5220                 firstChange ifTrue:[
  5221                     imageEditView makeUndo.
  5222                     firstChange := false.
  5223                 ].
  5224                 imageEditView
  5225                     makeSubImageX:l y:t 
  5226                     width:(img width - l - r)
  5227                     height:(img height - t - b).
  5228 
  5229                 self updateImagePreView.
  5230                 self updateInfoLabel
  5231             ].
  5232         ].
  5233 
  5234     bindings := IdentityDictionary new.
  5235     bindings at:#left put:(left := 1 asValue).
  5236     bindings at:#right put:(right := 1 asValue).
  5237     bindings at:#top put:(top := 1 asValue).
  5238     bindings at:#bottom put:(bottom := 1 asValue).
  5239     bindings at:#acceptChannel put:acceptChannel.
  5240 
  5241     bindings at:#gropLeftNow   put:[ gropAction value:left value:0 value:0 value:0 ].
  5242     bindings at:#gropRightNow  put:[ gropAction value:0 value:right value:0 value:0 ].
  5243     bindings at:#gropTopNow    put:[ gropAction value:0 value:0 value:top value:0 ].
  5244     bindings at:#gropBottomNow put:[ gropAction value:0 value:0 value:0 value:bottom ].
  5245 
  5246     bindings at:#applyAction   put:[ gropAction value:left value:right value:top value:bottom ].
  5247 
  5248     (self openDialogInterface:#cropDialogSpec withBindings:bindings) 
  5249     ifFalse:[ 
  5250         firstChange ~~ true ifTrue:[
  5251             imageEditView undo.
  5252             self updateImagePreView.
  5253         ]
  5254     ].
  5255 
  5256     "Created: / 7.9.1998 / 18:16:07 / cg"
  5257     "Modified: / 7.9.1998 / 18:20:42 / cg"
  5258 !
  5259 
  5260 doCropRight
  5261     "find a right border and cut it off"
  5262 
  5263     imageEditView cropLeft:false right:true top:false bottom:false.   
  5264     self updateInfoLabel
  5265 
  5266     "Created: / 7.9.1998 / 13:00:14 / cg"
  5267     "Modified: / 7.9.1998 / 14:26:44 / cg"
  5268 !
  5269 
  5270 doCropTop
  5271     "find a top border and cut it off"
  5272 
  5273     imageEditView cropLeft:false right:false top:true bottom:false.   
  5274     self updateInfoLabel
  5275 
  5276     "Created: / 7.9.1998 / 13:00:19 / cg"
  5277     "Modified: / 7.9.1998 / 14:26:52 / cg"
  5278 !
  5279 
  5280 doDarkenImage
  5281     imageEditView darkenImage.
  5282     self listOfColors removeAll.
  5283     self findColorMapMode.     
  5284     imageEditView removelastUndo
  5285 !
  5286 
  5287 doEditMask
  5288     self image mask edit
  5289 !
  5290 
  5291 doFlipHorizontal
  5292     "flips horizontally current image"
  5293 
  5294     imageEditView flipHorizontal
  5295 !
  5296 
  5297 doFlipVertical
  5298     "flips vertically current image"
  5299 
  5300     imageEditView flipVertical
  5301 !
  5302 
  5303 doInsertTextFromUser
  5304     |text tempForm tempImage maskImage font w h|
  5305 
  5306     text := Dialog request:'Text to be inserted (placed as bitmap into clipboard for paste):'.
  5307     text isEmptyOrNil ifTrue:[^ self ].
  5308 
  5309     font := Font family:'arial' size:20.
  5310     font := font onDevice:Screen current.
  5311     w := font widthOf:text.
  5312     h := font heightOf:text.
  5313 
  5314     tempForm := Form extent:(w@h) depth:1 onDevice:(Screen current).
  5315     tempForm clear.
  5316     tempForm font:font.
  5317     tempForm paint:(Color colorId:1).
  5318     tempForm displayString:text at:(0@font ascent).
  5319 
  5320     tempImage := tempForm asImage.
  5321     maskImage := tempForm asImage.
  5322     tempImage   
  5323         photometric:#palette;
  5324         colorMap:(Array with:Color white with:imageEditView selectedColor);
  5325         mask:maskImage.
  5326 
  5327     ImageEditView copyImageToClipboard:tempImage.
  5328     self editMode value:#paste.
  5329 
  5330     "Modified: / 11-11-2007 / 12:32:55 / cg"
  5331 !
  5332 
  5333 doInspectImage
  5334     "opens a System Browser on the resourceClass and the resourceSelector"
  5335 
  5336     self image inspect
  5337 !
  5338 
  5339 doMagnifyDown
  5340     "magnifies the current image one step down"
  5341 
  5342     |magHolder mag|
  5343 
  5344     magHolder := self magnificationHolder.
  5345     (mag := magHolder value) > 1 ifTrue: [
  5346         magHolder value: mag - 1
  5347     ]
  5348 
  5349     "Modified: / 26.7.1998 / 20:24:08 / cg"
  5350 !
  5351 
  5352 doMagnifyImage
  5353     "magnifies the current image to a new size"
  5354 
  5355     |box newSize image|
  5356 
  5357     image := imageEditView image.
  5358 
  5359     box := EnterBox new.
  5360     box title:(resources string:'Images new size:').
  5361     box okText:(resources string:'OK').
  5362     box abortText:(resources string:'Cancel').
  5363     box initialText:image extent printString.
  5364     box showAtPointer.
  5365     (box accepted 
  5366     and: [(newSize := self pointFromString:(box contents)) notNil])
  5367     ifTrue:[
  5368         newSize isPoint ifFalse:[
  5369             self warn:'please enter the new size as ''x @ y''.'.
  5370             ^ self.    
  5371         ].
  5372         imageEditView magnifyImageTo:newSize.
  5373     ].
  5374 
  5375     self updateInfoLabel
  5376 !
  5377 
  5378 doMagnifyImageBy
  5379     "magnifies the current image (by a scale)"
  5380 
  5381     |box oldSize newSize scaleString scale image|
  5382 
  5383     image := imageEditView image.
  5384     oldSize := image extent.
  5385 
  5386     scaleString := Dialog 
  5387                    request:(resources string:'Scale factor (<1 to shrink; >1 to magnify):') 
  5388                    initialAnswer:'1'
  5389                    list:#('0.25' '0.5' '2' '4').     
  5390 
  5391 "/    box := EnterBox new.
  5392 "/    box title:(resources string:'Scale factor (<1 to shrink; >1 to magnify):').
  5393 "/    box okText:(resources string:'OK').
  5394 "/    box abortText:(resources string:'Cancel').
  5395 "/    box initialText:1 printString.
  5396 "/    box showAtPointer.
  5397 "/    box accepted ifTrue:[
  5398 "/        scaleString := box contents.
  5399 "/    ].
  5400 
  5401     scale := Object readFromString:scaleString onError:nil.
  5402 
  5403     scale notNil ifTrue:[
  5404         scale isNumber ifFalse:[
  5405             self warn:'please enter a scale factor (<1 to shrink; >1 to magnify).'.
  5406             ^ self.    
  5407         ].
  5408         newSize := oldSize * scale.
  5409         imageEditView magnifyImageTo:newSize.
  5410     ].
  5411 
  5412     self updateInfoLabel
  5413 !
  5414 
  5415 doMagnifyUp
  5416     "magnifies the current image one step up"
  5417 
  5418     |magHolder mag|
  5419 
  5420     magHolder := self magnificationHolder.
  5421     (mag := magHolder value) < 99 ifTrue: [
  5422         magHolder value: mag + 1
  5423     ]
  5424 
  5425     "Modified: / 26.7.1998 / 20:23:52 / cg"
  5426 !
  5427 
  5428 doNegativeImage
  5429     "negates current image by negating the color map"
  5430 
  5431     self image depth ~~ 1 ifTrue:[
  5432         Dialog warn:'Only useful for depth 1 images'.
  5433         ^ self
  5434     ].
  5435     imageEditView negativeImage.
  5436     self listOfColors removeAll.
  5437     self findColorMapMode.     
  5438     imageEditView removelastUndo
  5439 !
  5440 
  5441 doResizeImage
  5442     "resizes the current image"
  5443 
  5444     |box newSize image|
  5445 
  5446     image := imageEditView image.
  5447 
  5448     box := EnterBox new.
  5449     box title:(resources string:'Images new size:').
  5450     box okText:(resources string:'OK').
  5451     box abortText:(resources string:'Cancel').
  5452     box initialText:image extent printString.
  5453     box showAtPointer.
  5454     (box accepted 
  5455     and: [(newSize := self pointFromString:(box contents)) notNil])
  5456     ifTrue:[
  5457         imageEditView resizeImageTo:newSize.
  5458     ].
  5459 !
  5460 
  5461 doRotateImage
  5462     "rotates current image"
  5463 
  5464     |box rotation|
  5465 
  5466     box := EnterBox new.
  5467     box title:(resources string:'Rotate by (degrees, clockwise):').
  5468     box okText:(resources string:'OK').
  5469     box abortText:(resources string:'Cancel').
  5470     box initialText: '0'.
  5471     box showAtPointer.
  5472     (box accepted and: [(rotation := Number readFromString: box contents onError:nil) notNil])
  5473     ifTrue:[
  5474         imageEditView rotateImageBy:rotation.
  5475         self updateInfoLabel.
  5476     ].
  5477 
  5478     "Modified: / 11-11-2007 / 13:21:11 / cg"
  5479 !
  5480 
  5481 doShiftManual
  5482     "let user specify amount and shift"
  5483 
  5484     |bindings amount img firstChange shiftAction acceptChannel wrapHolder|
  5485 
  5486     acceptChannel := TriggerValue new.
  5487     wrapHolder := (lastShiftUsedWrap ? true) asValue.
  5488 
  5489     firstChange := true.
  5490 
  5491     shiftAction := 
  5492         [:shiftH :shiftV | 
  5493             acceptChannel value:true.
  5494 
  5495             img := imageEditView image.
  5496             firstChange ifTrue:[
  5497                 imageEditView makeUndo.
  5498                 firstChange := false.
  5499             ].
  5500             imageEditView shiftImageHorizontal:(shiftH value) vertical:(shiftV value) wrap:(wrapHolder value).
  5501             self updateInfoLabel
  5502         ].
  5503 
  5504     bindings := IdentityDictionary new.
  5505     bindings at:#shiftAmount put:(amount := 1 asValue).
  5506     bindings at:#wrap put:wrapHolder.
  5507     bindings at:#acceptChannel put:acceptChannel.
  5508 
  5509     bindings at:#shiftLeftNow   put:[ shiftAction value:(-1*amount value) value:0 ].
  5510     bindings at:#shiftRightNow  put:[ shiftAction value:amount value value:0 ].
  5511     bindings at:#shiftUpNow     put:[ shiftAction value:0 value:(-1*amount value) ].
  5512     bindings at:#shiftDownNow   put:[ shiftAction value:0 value:amount value ].
  5513 
  5514     (self openDialogInterface:#shiftDialogSpec withBindings:bindings) 
  5515     ifFalse:[ 
  5516         firstChange ~~ true ifTrue:[
  5517           imageEditView undo
  5518         ]
  5519     ].
  5520     lastShiftUsedWrap := wrapHolder value.
  5521 
  5522     "Created: / 7.9.1998 / 18:16:07 / cg"
  5523     "Modified: / 7.9.1998 / 18:20:42 / cg"
  5524 !
  5525 
  5526 doUnCropManual
  5527     "let user specify borders and add them"
  5528 
  5529     |bindings left top right bottom img|
  5530 
  5531     bindings := IdentityDictionary new.
  5532     bindings at:#left put:(left := 1 asValue).
  5533     bindings at:#right put:(right := 1 asValue).
  5534     bindings at:#top put:(top := 1 asValue).
  5535     bindings at:#bottom put:(bottom := 1 asValue).
  5536     (self openDialogInterface:#uncropDialogSpec withBindings:bindings)
  5537     ifTrue:[
  5538         left := left value.
  5539         right := right value.
  5540         top := top value.
  5541         bottom := bottom value.
  5542         img := imageEditView image.
  5543 
  5544         imageEditView
  5545             makeBorderedImageX:left y:top 
  5546             width:(img width + left + right)
  5547             height:(img height + top + bottom).
  5548         self updateInfoLabel
  5549     ].
  5550 
  5551     "Created: / 7.9.1998 / 18:16:07 / cg"
  5552     "Modified: / 7.9.1998 / 18:20:42 / cg"
  5553 !
  5554 
  5555 doUndo
  5556     "reverses last edit action"
  5557 
  5558     imageEditView undo.
  5559 ! !
  5560 
  5561 !ImageEditor methodsFor:'user actions-loading'!
  5562 
  5563 doLoadFromClass
  5564     "opens a dialog for loading an image from class and a (resource-) selector"
  5565 
  5566     |img|
  5567 
  5568     self checkModified ifFalse:[ ^ self ].
  5569 
  5570     (imageEditView loadFromClass) notNil ifTrue:[
  5571         imageSeqNr := nil.
  5572         (img := self image) notNil ifTrue: [
  5573             self updateColorsFromImage:img.
  5574             self findColorMapMode.
  5575             self updateLabelsAndHistory.
  5576         ] ifFalse: [
  5577             self updateForNoImage
  5578         ].
  5579     ]
  5580 !
  5581 
  5582 doLoadFromFile
  5583     "opens a dialog for loading an image from a file"
  5584 
  5585     |img file filters|
  5586 
  5587     self checkModified ifFalse:[ ^ self ].
  5588 
  5589     imageSeqNr := nil.
  5590     img := self image.
  5591     img notNil ifTrue: [
  5592         file := img fileName
  5593     ].
  5594 
  5595     filters := FileSelectionBrowser loadImageFileNameFilters.
  5596 
  5597     file notNil ifTrue:[
  5598         file := FileSelectionBrowser
  5599                     request:'Load Image From'
  5600                     fileName:file
  5601                     withFileFilters:filters.
  5602     ] ifFalse:[
  5603         file := FileSelectionBrowser
  5604                     request:'Load Image From'
  5605                     inDirectory:LastDirectory
  5606                     withFileFilters:filters.
  5607     ].
  5608     file notNil ifTrue:[
  5609         LastDirectory := file asFilename directoryName.
  5610         self loadFromFile:file
  5611     ]
  5612 !
  5613 
  5614 doNewImage
  5615     "opens a dialog with choices of size and color map for creating a new image"
  5616 
  5617     |dialogAspects width height cMapString cMapMode cMap imageClass image szString defaultSize ext|
  5618 
  5619     self checkModified ifFalse:[ ^ self ].
  5620 
  5621     defaultSize := (self class listOfDefaultSizes includes:'32x32') 
  5622                         ifTrue:['32x32'] 
  5623                         ifFalse:[self class listOfDefaultSizes first].
  5624 
  5625     dialogAspects  := IdentityDictionary new
  5626         at:#listOfSizes         put: self class listOfDefaultSizes asValue;
  5627         at:#listOfColorMaps     put: self class namesOfColorMaps values asSortedCollection asValue;
  5628         at:#selectionOfSize     put: (LastSizeString ? defaultSize) asValue;
  5629         at:#selectionOfColorMap put: (LastColormapMode ? self class namesOfColorMaps values asSortedCollection first) asValue;
  5630         yourself.
  5631 
  5632     (self openDialogInterface:#dialogSpecForNewImage withBindings:dialogAspects)
  5633     ifTrue:[
  5634         szString := (dialogAspects at:#selectionOfSize) value.
  5635         ext := self pointFromString:szString.
  5636         ext isNil ifTrue:[
  5637             width := height := 32
  5638         ] ifFalse:[
  5639             width := ext x.
  5640             height := ext y.
  5641         ].
  5642 "/        width  := "128 min: "(Integer readFromString: (szString upTo: $x) onError:[32]).
  5643 "/        height := "128 min: " (Integer readFromString: (szString copy reverse upTo: $x) reverse onError:[32]).
  5644 
  5645         cMapString := (dialogAspects at:#selectionOfColorMap) value.
  5646         cMapMode   := self class namesOfColorMaps keyAtEqualValue:cMapString.
  5647         cMap       := self class listOfColorMaps at:cMapMode.
  5648         imageClass := Image implementorForDepth:(cMap size highBit-1).
  5649         image      := imageClass width: width height: height.
  5650         image bits:(ByteArray new:(image bytesPerRow*height)).
  5651 
  5652         LastSizeString := szString.
  5653         LastColormapMode := cMapString.
  5654 
  5655         (cMapMode startsWith: 'mask') ifTrue:[
  5656             image mask: (Depth1Image width: width height: height depth: 1 fromArray: (ByteArray new: width*height)) clearMaskedPixels
  5657         ].
  5658         image colorMap: cMap.
  5659         (imageEditView image: image) notNil ifTrue:[
  5660             self updateListOfColorsAndColormapMode.
  5661             self updateLabelsAndHistory.
  5662         ].
  5663         image fillRectangleX:0 y:0 width:width height:height with:Color white.
  5664     ]
  5665 !
  5666 
  5667 doNewImageEditor
  5668     "opens a new image editor"
  5669 
  5670     ImageEditor open
  5671 
  5672     "Created: / 17-08-2006 / 09:03:14 / cg"
  5673 !
  5674 
  5675 doNewImageFromClipboard
  5676     |image|
  5677 
  5678     self checkModified ifFalse:[ ^ self ].
  5679 
  5680     image := imageEditView clipBoard.
  5681     imageEditView image:image.
  5682 
  5683     image notNil ifTrue:[
  5684         self updateColorsFromImage:image.
  5685         self findColorMapMode.
  5686         self updateLabelsAndHistory.
  5687     ]
  5688 !
  5689 
  5690 grabScreenImage
  5691     "let user choose an area and grab that are for editing"
  5692 
  5693     self checkModified ifFalse:[ ^ self ].
  5694 
  5695     Processor 
  5696         addTimedBlock:[
  5697             |image d8image img|
  5698 
  5699             imageSeqNr := nil.
  5700             image := Image fromUser.
  5701             image isNil ifFalse:[
  5702                 image depth > 8 ifTrue:[
  5703 false ifTrue:[
  5704                     Error handle:[:ex | |sig|
  5705                         (sig := ex signal) == HaltInterrupt ifTrue:[ex reject].
  5706                         sig == Signal noHandlerSignal ifTrue:[ex reject].
  5707 
  5708                         self warn:'Could not convert to depth8 image (too many colors)'.
  5709                         d8image := nil.
  5710                     ] do:[
  5711                         d8image := Depth8Image fromImage:image photometric:#palette.
  5712                     ].
  5713                     d8image notNil ifTrue:[
  5714                         image := d8image
  5715                     ]
  5716 ].
  5717                 ].
  5718                 (imageEditView image:image) notNil ifTrue:[
  5719                     self listOfColors contents:(image colorMap).
  5720                     self findColorMapMode.
  5721                     self updateLabelsAndHistory.
  5722                 ]
  5723              ] 
  5724         ] 
  5725         afterSeconds:1
  5726 
  5727     "Created: / 29.7.1998 / 21:24:42 / cg"
  5728     "Modified: / 16.11.2001 / 16:21:19 / cg"
  5729 !
  5730 
  5731 nextImageInSequence
  5732     "display the next image in the image sequence"
  5733     |img seq frame listOfColors|
  5734 
  5735     imageEditView releaseUndos.
  5736 
  5737     seq := self image imageSequence.
  5738     imageSeqNr isNil ifTrue:[
  5739         imageSeqNr := 1.
  5740     ].
  5741     imageSeqNr := imageSeqNr + 1.
  5742     imageSeqNr > seq size ifTrue:[
  5743         self information:'Back to first image in sequence'.
  5744         imageSeqNr := 1.
  5745     ].
  5746     frame := seq at:imageSeqNr.
  5747     imageEditView image:(frame image).
  5748 
  5749     (img := self image) notNil ifTrue:[          
  5750         listOfColors := self listOfColors.
  5751         img colorMap notNil ifTrue:[
  5752             listOfColors contents:(img usedColors asSet asOrderedCollection).
  5753         ] ifFalse:[
  5754             listOfColors removeAll.
  5755         ].
  5756         self findColorMapMode.     
  5757         self updateLabelsAndHistory.
  5758         img := img onDevice:device.
  5759         imageEditView image:img.
  5760     ] ifFalse:[
  5761         self updateForNoImage
  5762     ].
  5763 
  5764 ! !
  5765 
  5766 !ImageEditor methodsFor:'user actions-saving'!
  5767 
  5768 doPrint
  5769     "prints current image on the current printer"
  5770 
  5771     self withWaitCursorDo:[
  5772         imageEditView print
  5773     ]
  5774 !
  5775 
  5776 doSaveButtonImageToFileAs
  5777     "opens a dialog for saving current image to a file"
  5778 
  5779     imageEditView saveButtonImageToFileAs.
  5780     self updateLabelsAndHistory.
  5781 !
  5782 
  5783 doSaveImageFile
  5784     "saves current image to current file"
  5785 
  5786     imageEditView save.
  5787     self clearModified.
  5788 !
  5789 
  5790 doSaveImageFileAs
  5791     "opens a dialog for saving an image to a file"
  5792 
  5793     |img file filters|
  5794 
  5795     img := self image.
  5796     img notNil ifTrue: [
  5797         file := img fileName
  5798     ].
  5799 
  5800     filters := FileSelectionBrowser loadImageFileNameFilters.
  5801 
  5802     file notNil ifTrue:[
  5803         file := FileSelectionBrowser
  5804                     request:'Save Image To'
  5805                     fileName:file
  5806                     withFileFilters:filters.
  5807     ] ifFalse:[
  5808         file := FileSelectionBrowser
  5809                     request:'Save Image To'
  5810                     inDirectory:LastDirectory
  5811                     withFileFilters:filters.
  5812     ].
  5813     file notNil ifTrue:[
  5814         imageEditView saveImageFileAs:file.
  5815         LastDirectory := file asFilename directoryName.
  5816         self updateLabelsAndHistory.
  5817         self clearModified.
  5818     ]
  5819 !
  5820 
  5821 doSaveImageMaskFileAs
  5822     "opens a dialog for saving mask of current image to a file"
  5823 
  5824     imageEditView saveImageMaskFileAs.
  5825 !
  5826 
  5827 doSaveMethod
  5828     "saves the image in current class and selector"
  5829 
  5830     imageEditView saveMethod ifTrue:[
  5831         self updateLabelsAndHistory.
  5832         self clearModified.
  5833     ]
  5834 !
  5835 
  5836 doSaveMethodAs
  5837     "opens a dialog for saving current image on a class and a selector"
  5838 
  5839     imageEditView saveMethodAs ifTrue:[
  5840         self updateLabelsAndHistory.
  5841         self clearModified.
  5842     ]
  5843 !
  5844 
  5845 doShowStoreString
  5846     "opens a dialog showing the storeString
  5847      (sometimes useful to embed an image into source code)"
  5848 
  5849     |img|
  5850 
  5851     img := imageEditView image.
  5852     TextBox openOn:img storeString
  5853 !
  5854 
  5855 save
  5856     "saves current image on current class and selector"
  5857 
  5858     self doSaveMethod
  5859 ! !
  5860 
  5861 !ImageEditor methodsFor:'user actions-settings'!
  5862 
  5863 doChangeGridMagnification
  5864     "change grid magnification"
  5865 
  5866     |box oldGridLimit newGridLimit|
  5867 
  5868     oldGridLimit := imageEditView class gridMagnificationLimit asPoint.
  5869 
  5870     box := EnterBox new.
  5871     box title:(resources string:'Grid Magnification Limit:').
  5872     box okText:(resources string:'OK').
  5873     box abortText:(resources string:'Cancel').
  5874     box initialText:(oldGridLimit x printString).
  5875     box showAtPointer.
  5876 
  5877     (box accepted 
  5878     and: [(newGridLimit := Number readFromString:(box contents) onError:[2]) notNil]
  5879     ) ifTrue:[
  5880         newGridLimit := (99 min: (2 max:newGridLimit)) asPoint.
  5881         imageEditView class gridMagnificationLimit:newGridLimit.
  5882         imageEditView invalidate
  5883     ]
  5884 
  5885 !
  5886 
  5887 penWidth:n
  5888     imageEditView penWidth:n
  5889 
  5890     "Created: / 01-11-2007 / 23:47:48 / cg"
  5891 !
  5892 
  5893 spraySpot:n
  5894     imageEditView spraySpot:n
  5895 
  5896     "Created: / 01-11-2007 / 23:47:48 / cg"
  5897 ! !
  5898 
  5899 !ImageEditor class methodsFor:'documentation'!
  5900 
  5901 version
  5902     ^ '$Header$'
  5903 ! !