#FEATURE by cg draft
authorClaus Gittinger <cg@exept.de>
Fri, 17 Feb 2017 15:35:25 +0100
changeset 3408 86d2e0cd4970
parent 3407 2e0024e012e9
child 3409 d821859c163e
#FEATURE by cg class: ImageEditor improved flood fill; needed to auto-fill uninteresting areas in guiBrowser. added: #cropBoxIsNotDialog #floodFillMaxHueError #floodFillMaxLightError changed: #cropDialogSpec #doCropManual #helpPairs #selectedColorsChanged
ImageEditor.st
--- a/ImageEditor.st	Fri Feb 17 14:29:17 2017 +0100
+++ b/ImageEditor.st	Fri Feb 17 15:35:25 2017 +0100
@@ -280,70 +280,13 @@
      the UIHelpTool may not be able to read the specification."
 
     "
-     UIHelpTool openOnClass:ImageEditor    
+     UIHelpTool openOnClass:ImageEditor
     "
 
     <resource: #help>
 
     ^ #(
 
-#xdrawModeBox
-'Rectangle'
-
-#xdrawModeCopy
-'Copy'
-
-#xdrawModeFill
-'Flood-fill'
-
-#xdrawModeFilledBox
-'Filled rectangle'
-
-#xdrawModePaste
-'Paste'
-
-#xdrawModePasteUnder
-'Paste under'
-
-#xdrawModePasteWithMask
-'Paste with Mask'
-
-#xdrawModePoint
-'Point'
-
-#xfileGrabImage
-'Pick from screen'
-
-#xfileLoadFromClass
-'Load from method...'
-
-#xfileLoadFromFile
-'Load from file...'
-
-#xfileNewImage
-'New image'
-
-#filePrint
-'Print'
-
-#xfileSaveAs
-'Save to file...'
-
-#xfileSaveMaskAs
-'Save mask to file...'
-
-#xfileSaveMethod
-'Save as method'
-
-#xfileSaveMethodAs
-'Save as Method...'
-
-#nextImageInSequence
-'Go to the next image in the animated gif image sequence.'
-
-#previousImageInSequence
-'Go to the previous image in the animated gif image sequence.'
-
 #colorMap
 'ColorMap functions'
 
@@ -416,6 +359,15 @@
 #drawModeFilledBox
 'Filled Rectangle Drawing Mode'
 
+#drawModeFilledCircle
+'Filled Circle Drawing Mode'
+
+#drawModeMaskOutsideCircle
+'Mask everything outside a Circle'
+
+#drawModeMaskOutsideRectangle
+'Mask everything outside a Rectangle'
+
 #drawModePaste
 'Paste Mode'
 
@@ -434,6 +386,9 @@
 #drawModeSpray
 'Spray Drawing Mode'
 
+#edit3DProjection
+'Generate a 3D projection'
+
 #editFlipHorizontal
 'Flip the image horizontally'
 
@@ -452,6 +407,9 @@
 #editRotate
 'Rotate the image'
 
+#fileEditMask
+'Load Mask from a File'
+
 #fileGrabImageFromScreen
 'Pick an image from the screen (specify area)'
 
@@ -477,6 +435,9 @@
 'Paste the image in the clipboard as a mask. Must be a depth-1 image'
 
 #filePrint
+'Print'
+
+#filePrint
 'Print the image on a postscript printer'
 
 #fileSave
@@ -497,42 +458,11 @@
 #fileSaveMethodAs
 'Save the image as resource method in a class'
 
-#magnificationNumber
-'Shows the current magnification'
-
-#magnifyImageDown
-'Decrease magnification'
-
-#magnifyImageUp
-'Increase magnification'
-
-#mouseKeyColorMode
-'Toggle between left and right mouse button color'
-
-#previewView
-'Shows a preview of the image'
-
-#settingsGridMagnification
-'Change the grid magnification of the edit view'
-
-
-
-
-#drawModeFilledCircle
-'Filled Circle Drawing Mode'
-
-#drawModeMaskOutsideCircle
-'Mask everything outside a Circle'
-
-#drawModeMaskOutsideRectangle
-'Mask everything outside a Rectangle'
-
-#edit3DProjection
-'Generate a 3D projection'
-
-#fileEditMask
-'Load Mask from a File'
-
+#floodFillMaxError
+'Specify the max. allowed deviation from the clicked pixel in a flood-fill operation.\Pixels where the hue/light values differ less than that fraction\will be included in the fill.\The range must be between 0 and 1. With 0, only areas with exactly the same pixel will be filled.\With 1, every other pixel is included.\\When filling gradiented areas, start with small values, such as 0.05, and increase slowly.'
+
+#gropAll
+'Crop (cut off) all four sides by the amounts entered into the above fields.'
 
 #gropBottom
 'Cut off the specified number of pixels at the bottom'
@@ -546,10 +476,81 @@
 #gropTop
 'Cut off the specified number of pixels at the top'
 
+#magnificationNumber
+'Shows the current magnification'
+
+#magnifyImageDown
+'Decrease magnification'
+
+#magnifyImageUp
+'Increase magnification'
+
+#mouseKeyColorMode
+'Toggle between left and right mouse button color'
+
+#nextImageInSequence
+'Go to the next image in the animated gif image sequence.'
+
+#previewView
+'Shows a preview of the image'
+
+#previousImageInSequence
+'Go to the previous image in the animated gif image sequence.'
+
+#settingsGridMagnification
+'Change the grid magnification of the edit view'
+
+#xdrawModeBox
+'Rectangle'
+
+#xdrawModeCopy
+'Copy'
+
+#xdrawModeFill
+'Flood-fill'
+
+#xdrawModeFilledBox
+'Filled rectangle'
+
+#xdrawModePaste
+'Paste'
+
+#xdrawModePasteUnder
+'Paste under'
+
+#xdrawModePasteWithMask
+'Paste with Mask'
+
+#xdrawModePoint
+'Point'
+
+#xfileGrabImage
+'Pick from screen'
+
+#xfileLoadFromClass
+'Load from method...'
+
+#xfileLoadFromFile
+'Load from file...'
+
+#xfileNewImage
+'New image'
+
+#xfileSaveAs
+'Save to file...'
+
+#xfileSaveMaskAs
+'Save mask to file...'
+
+#xfileSaveMethod
+'Save as method'
+
+#xfileSaveMethodAs
+'Save as Method...'
 
 )
 
-    "Created: / 16-02-2017 / 12:29:54 / cg"
+    "Modified: / 17-02-2017 / 15:32:45 / cg"
 !
 
 helpSpec
@@ -1462,7 +1463,7 @@
          label: 'Crop Border(s)'
          name: 'Crop Border(s)'
          min: (Point 10 10)
-         bounds: (Rectangle 0 0 343 225)
+         bounds: (Rectangle 0 0 364 312)
        )
        component: 
       (SpecCollection
@@ -1587,6 +1588,17 @@
              autoRepeat: true
              usePreferredWidth: true
            )
+          (ActionButtonSpec
+             label: 'Crop All'
+             name: 'Button4'
+             layout: (LayoutFrame 133 0 148 0 237 0 176 0)
+             activeHelpKey: gropAll
+             visibilityChannel: cropBoxIsNotDialog
+             translateLabel: true
+             resizeForLabel: true
+             tabable: true
+             model: applyCropAction
+           )
           (HorizontalPanelViewSpec
              name: 'HorizontalPanel1'
              layout: (LayoutFrame 0 0.0 -30 1 -16 1.0 0 1)
@@ -1602,12 +1614,11 @@
                 (ActionButtonSpec
                    label: 'Cancel'
                    name: 'Button1'
-                   visibilityChannel: cropBoxIsDialog
                    translateLabel: true
                    resizeForLabel: true
                    tabable: true
                    model: cancel
-                   extent: (Point 103 28)
+                   extent: (Point 110 28)
                  )
                 (ActionButtonSpec
                    label: 'Apply'
@@ -1615,24 +1626,72 @@
                    translateLabel: true
                    resizeForLabel: true
                    tabable: true
-                   model: applyAction
-                   extent: (Point 104 28)
+                   model: applyCropAction
+                   extent: (Point 111 28)
                  )
                 (ActionButtonSpec
                    label: 'OK'
                    name: 'Button2'
-                   visibilityChannel: cropBoxIsDialog
                    translateLabel: true
                    resizeForLabel: true
                    tabable: true
                    model: accept
-                   extent: (Point 104 28)
+                   extent: (Point 111 28)
                  )
                 )
               
              )
              keepSpaceForOSXResizeHandleH: true
            )
+          (LabelSpec
+             label: 'Floodfill Tolerance:'
+             name: 'Label1'
+             layout: (LayoutFrame 14 0 192 0 242 0 214 0)
+             activeHelpKey: floodFillMaxError
+             visibilityChannel: cropBoxIsNotDialog
+             translateLabel: true
+             adjust: left
+           )
+          (LabelSpec
+             label: 'Hue:'
+             name: 'Label2'
+             layout: (LayoutFrame 51 0 220 0 127 0 242 0)
+             activeHelpKey: floodFillMaxError
+             visibilityChannel: cropBoxIsNotDialog
+             translateLabel: true
+             adjust: left
+           )
+          (InputFieldSpec
+             name: 'EntryField2'
+             layout: (LayoutFrame 132 0 220 0 190 0 242 0)
+             activeHelpKey: floodFillMaxError
+             visibilityChannel: cropBoxIsNotDialog
+             tabable: true
+             model: floodFillMaxHueError
+             type: number
+             acceptChannel: acceptChannel
+             acceptOnPointerLeave: true
+           )
+          (LabelSpec
+             label: 'Light:'
+             name: 'Label3'
+             layout: (LayoutFrame 51 0 246 0 127 0 268 0)
+             activeHelpKey: floodFillMaxError
+             visibilityChannel: cropBoxIsNotDialog
+             translateLabel: true
+             adjust: left
+           )
+          (InputFieldSpec
+             name: 'EntryField3'
+             layout: (LayoutFrame 132 0 246 0 190 0 268 0)
+             activeHelpKey: floodFillMaxError
+             visibilityChannel: cropBoxIsNotDialog
+             tabable: true
+             model: floodFillMaxLightError
+             type: number
+             acceptChannel: acceptChannel
+             acceptOnPointerLeave: true
+           )
           )
         
        )
@@ -3973,6 +4032,12 @@
     "Created: / 03-02-2017 / 11:23:50 / cg"
 !
 
+cropBoxIsNotDialog
+    ^ self cropBoxIsDialog not
+
+    "Created: / 17-02-2017 / 14:38:04 / cg"
+!
+
 cropBoxVisibleHolder
     |holder|
 
@@ -3984,6 +4049,30 @@
     "Created: / 03-02-2017 / 11:20:13 / cg"
 !
 
+floodFillMaxHueError
+    |holder|
+
+    (holder := builder bindingAt:#floodFillMaxHueError) isNil ifTrue:[
+        builder aspectAt:#floodFillMaxHueError put:(holder := 0 asValue).
+        holder onChangeEvaluate:[ imageEditView floodFillMaxHueError:holder value ].
+    ].
+    ^ holder
+
+    "Created: / 17-02-2017 / 15:19:17 / cg"
+!
+
+floodFillMaxLightError
+    |holder|
+
+    (holder := builder bindingAt:#floodFillMaxLightError) isNil ifTrue:[
+        builder aspectAt:#floodFillMaxLightError put:(holder := 0 asValue).
+        holder onChangeEvaluate:[ imageEditView floodFillMaxLightError:holder value ].
+    ].
+    ^ holder
+
+    "Created: / 17-02-2017 / 15:19:11 / cg"
+!
+
 hasClassAndSelectorDefinedHolder
     ^ [
         |cls|
@@ -4356,19 +4445,15 @@
 !
 
 selectedColorsChanged
-    |colorIndices|
-
-    (colorIndices := self selectedColors value) isEmptyOrNil ifTrue:[
-        self selectionOfColor value:nil
-    ] ifFalse:[
-        colorIndices size == 1 ifTrue:[
-            "/ as single color selected
-            self selectionOfColor value:colorIndices first
-        ] ifFalse:[
-            "/ multipl selected
-            self selectionOfColor value:nil
-        ].
-    ].
+    |colorIndices selectedIndex|
+
+    (colorIndices := self selectedColors value) size == 1 ifTrue:[        
+        "/ a single color selected
+        selectedIndex := colorIndices first
+    ].    
+    self selectionOfColor value:selectedIndex
+
+    "Modified: / 17-02-2017 / 14:40:33 / cg"
 !
 
 update:something with:aParameter from:changedObject
@@ -6821,7 +6906,7 @@
     bindings at:#gropTopNow    put:[ gropAction value:0 value:0 value:top value:0 ].
     bindings at:#gropBottomNow put:[ gropAction value:0 value:0 value:0 value:bottom ].
 
-    bindings at:#applyAction   put:[ gropAction value:left value:right value:top value:bottom ].
+    bindings at:#applyCropAction   put:[ gropAction value:left value:right value:top value:bottom ].
 
     (self openDialogInterface:#cropDialogSpec withBindings:bindings) 
     ifFalse:[ 
@@ -6832,7 +6917,7 @@
     ].
 
     "Created: / 07-09-1998 / 18:16:07 / cg"
-    "Modified: / 16-02-2017 / 01:33:36 / cg"
+    "Modified: / 17-02-2017 / 14:33:19 / cg"
 !
 
 doCropRight