; Blending (layer) operations for channels

; This program is free software; you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation; either version 2 of the License, or
; (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
; GNU General Public License for more details.


; GIMP 2.6 compatibility procedures
;
(unless (defined? 'gimp-item-is-group)
  (define gimp-item-is-layer gimp-drawable-is-layer)
  (define gimp-item-get-name gimp-drawable-get-name)
  (define gimp-item-set-name gimp-drawable-set-name)
  (define gimp-item-get-visible gimp-drawable-get-visible)
  (define gimp-item-set-visible gimp-drawable-set-visible)
  (define gimp-item-is-layer-mask gimp-drawable-is-layer-mask)
  (define gimp-item-is-channel gimp-drawable-is-channel)
  (define (gimp-item-is-group item) '(0))
  (define (gimp-item-get-parent item) '(-1))
  (define (gimp-item-get-children item) (list 0 #(0)))
  )

(define (script-fu-sg-channel-blend-down image channel mode opacity use-hidden?)
  (set! use-hidden? (not (zero? use-hidden?)))
  (let* ((channels (vector->list (cadr (gimp-image-get-channels image))))
         (base-channel #f)
         (mode-lut '#( 0 1 10 4 16 7 9 3 17 5 19 18 6 8 20 21 15))
         (channel-name (car (gimp-drawable-get-name channel))) )
    (gimp-image-undo-group-start image)
    (unless (or (= (car (gimp-item-is-layer channel)) TRUE)
                (= (car (gimp-item-is-layer-mask channel)) TRUE)
                (not (member channel channels))
                (and (not use-hidden?)
                     (zero? (car (gimp-item-get-visible channel))) ))
      (set! base-channel
            (let loop ((channels (cdr (member channel channels)))
                       (base-channel #f) )
              (if (null? channels)
                base-channel
                (if (or use-hidden? (not (zero? (car (gimp-item-get-visible (car channels))))))
                  (loop '() (car channels))
                  (loop (cdr channels) base-channel) ))))
      (when base-channel
        (let ((orig-sel (car (gimp-selection-save image))))
          (gimp-selection-none image)
          (let* ((buffer (car (gimp-edit-named-copy base-channel "Temp")))
                 (tmp-image (car (gimp-edit-named-paste-as-new buffer)))
                 (bot-layer (car (gimp-image-get-active-layer tmp-image)))
                 (top-layer (car (gimp-layer-new-from-drawable channel tmp-image))) )
            (gimp-image-undo-disable tmp-image)
            (gimp-item-set-visible bot-layer TRUE)
            (gimp-item-set-visible bot-layer TRUE)
            (gimp-image-add-layer tmp-image top-layer 0)
            (gimp-item-set-visible top-layer TRUE)
            (gimp-layer-set-opacity top-layer opacity)
            (gimp-layer-set-mode top-layer (vector-ref mode-lut mode))
            (set! bot-layer (car (gimp-image-merge-down tmp-image top-layer CLIP-TO-IMAGE)))
            (gimp-buffer-delete buffer)
            (set! buffer (car (gimp-edit-named-copy bot-layer "Temp")))
            (gimp-image-remove-channel image channel)
            (gimp-floating-sel-anchor (car (gimp-edit-named-paste base-channel buffer TRUE)))
            (gimp-buffer-delete buffer)
            (when (string=? "Qmask" channel-name)
              (gimp-item-set-name base-channel "Qmask")
              (gimp-item-set-visible base-channel TRUE) )
            (gimp-image-delete tmp-image) )
          (gimp-selection-load orig-sel)
          (gimp-image-remove-channel image orig-sel) )))
    (gimp-image-undo-group-end image)
    (gimp-displays-flush)
    )
  )

(script-fu-register "script-fu-sg-channel-blend-down"
         "Blend Down..."
         "Blend channel with the channel beneath it."
         "Saul Goode"
         "Saul Goode"
         "November"
         "GRAY"
         SF-IMAGE "Image" 0
         SF-CHANNEL "Channel" 0
         SF-OPTION "Blend Mode" '( "Normal"     ; 0
                                   "Dissolve"   ; 1
                                   "Lighten only (Union)" ; 10
                                   "Screen"     ; 4
                                   "Dodge"      ; 16
                                   "Addition"   ; 7
                                   "Darken only (Intersect)" ; 9
                                   "Multiply"   ; 3
                                   "Burn"       ; 17
                                   "Overlay"    ; 5
                                   "Soft light" ; 19
                                   "Hard light" ; 18
                                   "Difference" ; 6
                                   "Subtract"  ; 8
                                   "Grain extract" ; 20
                                   "Grain merge" ; 21
                                   "Divide"     ; 15
                                   )
          SF-ADJUSTMENT "Opacity"  '( 100 0 100 1 10 0 0)
          SF-TOGGLE "Use hidden channels" TRUE
          )

(script-fu-menu-register "script-fu-sg-channel-blend-down"
  "<Channels>/"
  )

(define (script-fu-sg-drawable-show-only image drawable)
  (gimp-image-undo-group-start image)
  (map (lambda (x) (gimp-item-set-visible x FALSE))
       (vector->list (cadr (gimp-image-get-layers image))) )
  (map (lambda (x) (gimp-item-set-visible x FALSE))
       (vector->list (cadr (gimp-image-get-channels image))) )
  (if (= (car (gimp-item-is-layer-mask drawable)) TRUE)
    (let ((layer (car (gimp-layer-from-mask drawable))))
      (gimp-item-set-visible layer TRUE)
      (gimp-layer-set-show-mask layer TRUE) )
    (gimp-item-set-visible drawable TRUE) )
  (if (= (car (gimp-item-is-layer drawable)) TRUE)
    (let loop ((item drawable))
      (let ((parent (car (gimp-item-get-parent item))))
        (unless (= parent -1)
          (map (lambda (x) (gimp-item-set-visible x FALSE))
               (vector->list (cadr (gimp-item-get-children parent))) )
          (gimp-item-set-visible item TRUE)
          (gimp-item-set-visible parent TRUE)
          (loop parent) ))))
  (if (= (car (gimp-item-is-channel drawable)) TRUE)
    (gimp-item-set-visible drawable TRUE) )
  (gimp-image-undo-group-end image)
  (gimp-displays-flush) )

;; Re-use layer-show-only, but with a channel
(define script-fu-sg-channel-show-only script-fu-sg-drawable-show-only)

;; Register to Channels menu

(script-fu-register "script-fu-sg-channel-show-only"
         "Show only"
         "Show only current channel."
         "Saul Goode"
         "Saul Goode"
         "November 2011"
         "GRAY"
         SF-IMAGE "Image" 0
         SF-CHANNEL "Channel" 0
         )

(script-fu-menu-register "script-fu-sg-channel-show-only"
  "<Channels>/"
  )

(script-fu-register "script-fu-sg-drawable-show-only"
         "Show only"
         "Show only current layer."
         "Saul Goode"
         "Saul Goode"
         "November 2011"
         "*"
         SF-IMAGE "Image" 0
         SF-DRAWABLE "Drawable" 0
         )

(script-fu-menu-register "script-fu-sg-drawable-show-only"
  "<Layers>/"
  )
