;+
; NAME:
;	SHOW_ZOOMED
;
;
; PURPOSE:
;	Show a zoomed section of an image.
;
;
; CATEGORY:
;	Utils
;
;
; CALLING SEQUENCE:
;	wid = show_zoomed(window, x, y)
;
;
; INPUTS:
;	window	long	The window from which to read the image to zoom.
;	x, y	int	The centre of the region to be zoomed.
;
; OUTPUTS:
;	wid	long	The widget ID of the top-level base.
;
; KEYWORD PARAMETERS:
;	zoom	int	The initial zoom factor (default = 4)
;	/smooth		If set, then use the smoothing in REBIN
;	size	int	The size of the window to create (if it's a
;			scalar then make a square window; default = 256)
;	group	long	A group leader of the widget heirarchy.
;	base	long	If this is a valid widget, then it is an
;			already existing zoom tool, then a new tool is
;			not created.
;
;
; MODIFICATION HISTORY:
;	Original: 28/7/03; SJT
;	Add modifier support and change to function: 29/7/03; SJT
;	Add support for systems that differentiate button and wheel
;	events: 10/12/07; SJT
;	Add image drag mode: 2/2/10; SJT
;-

pro sh_zoom_event, event

widget_control, event.top, get_uvalue = state
widget_control, event.id, get_uvalue = mnu

case mnu of
    'QUIT': widget_control, event.top, /destroy
    'SMOOTH': state.smooth = event.select
    'ZOOM': state.zoom = event.value
    'REFRESH':                  ; Only needs to get us in
    'NMODE': state.nmode = event.index

    'CANVAS': begin
        case event.type of
            0: if state.nmode eq 1 then begin
                if event.press ne 1 then return
                widget_control, event.id, draw_motion_events = 1
                state.px = event.x
                state.py = event.y
                acode = -1
            endif else return
            1: if state.nmode eq 1 and event.release eq 1 then begin
                widget_control, event.id, draw_motion_events = 0 
                acode = -1
            endif else acode = event.release 
            2: acode = 0
            7: begin
                if event.clicks lt 0 then acode = 16 $
                else acode = 8
            end
            else: return
        endcase
        zflag = 1b
        case event.modifiers of
            0: dz = 1
            2: dz = 2
            1: dz = 5
            3: dz = 10
            else: dz = 1
        endcase
        case acode of
            1: begin            ; LHB Release centre to click point
                state.x = state.x+(event.x - $
                                   state.wsize[0]/2)/state.zoom 
                state.y = state.y+(event.y - state.yoff - $
                                   state.wsize[1]/2)/state.zoom
                zflag = 0b
            end
            2: begin            ; MB Release centre and zoom out
                state.x = state.x+(event.x - $
                                   state.wsize[0]/2)/state.zoom 
                state.y = state.y+(event.y - $
                                   state.wsize[1]/2)/state.zoom
                state.zoom = (state.zoom-dz) > 1
            end
            4: begin            ; RHB Release centre & zoom in
                state.x = state.x+(event.x - $
                                   state.wsize[0]/2)/state.zoom 
                state.y = state.y+(event.y - $
                                   state.wsize[1]/2)/state.zoom
                state.zoom = (state.zoom+dz) < min(state.wsize)
            end
            8: begin            ; Wheel back zoom out
                state.zoom = (state.zoom-dz) > 1
            end
            16: begin           ; Wheel forward zoom in
                state.zoom = (state.zoom+dz) < min(state.wsize)
            end
            0: begin            ; Drag drag
                zflag = 0b
                state.x = state.x + (state.px-event.x)/state.zoom
                state.y = state.y + (state.py-event.y)/state.zoom
                state.px = event.x
                state.py = event.y
            end
            -1: zflag = 0       ;Dummy - end drag
            else: print, "What kind of a rodent is that"
        endcase
        if zflag then begin
            sbase = widget_info(state.slid, /parent)
            widget_control, sbase, map = state.zoom le 25
            if state.zoom le 25 then $
              widget_control, state.slid, set_value = $
              state.zoom
        endif
    end
endcase

if widget_info(/valid, event.top) then begin 
    zmcopy, state.window, state.zwindow, round(state.x), round(state.y), $
            state.wsize, state.zoom, state.smooth, xoff, yoff
    state.xoff = xoff
    state.xoff = yoff
    widget_control, event.top, set_uvalue = state
endif

end

pro zmcopy, iwind, owind, x, y, wsize, zoom, smooth, xoff, yoff

x0 = x-wsize[0]/(2*zoom)
y0 = y-wsize[1]/(2*zoom)
nx = wsize[0]/zoom
ny = wsize[1]/zoom
xoff = (wsize[0] - nx*zoom)/2
yoff = (wsize[1] - ny*zoom)/2


wset, iwind                     ; Should already be but just make sure
if x0 lt 0 then begin
    nx = nx+x0
    xoff = xoff-x0
    x0 = 0
endif
if y0 lt 0 then begin
    ny = ny+y0
    yoff = yoff-y0
    y0 = 0
endif

if x0+nx ge !d.x_size then nx = !d.x_size-x0
if y0+ny ge !d.y_size then ny = !d.y_size-y0
if nx le 0 or ny le 0 then return


img = tvrd(x0, y0, nx, ny)

; We use nx
img = rebin(img, nx*zoom, ny*zoom, sample = smooth eq 0)

wset, owind
erase
tv, img, xoff, yoff

wset, iwind

end

function show_zoomed, window, x, y, zoom = zoom, smooth = smooth, size $
                      = size, group = group, base = base

imake = 1b
if keyword_set(base) then if widget_info(/valid, base) then imake = 0b

if imake then begin
    case n_elements(size) of
        0: wsize = [512, 512]
        1: wsize = [size, size]
        2: wsize = size
        else: wsize = size[0:1]
    endcase

    if not keyword_set(zoom) then zoom = 4 $
    else zoom = int(zoom)

    if n_elements(smooth) eq 0 then smooth = 0

    base = widget_base(/column, $
                       group = group)

    junk = widget_label(base, $
                        value = 'Zoomed View')

    if float(!version.release) ge 6.2 then $
      canvas = widget_draw(base, $
                           xsize = wsize[0], $
                           ysize = wsize[1], $
                           /button_events, $
                           /wheel_events, $
                           uvalue = 'CANVAS') $
    else canvas = widget_draw(base, $
                              xsize = wsize[0], $
                              ysize = wsize[1], $
                              /button_events, $
                              uvalue = 'CANVAS')

    sbase = widget_base(base)
    zslide = widget_slider(sbase, $
                           min = 1, $
                           max = 25, $
                           xsize = wsize[0], $
                           value = zoom, $
                           uvalue = 'ZOOM', $
                           title = 'Zoom factor')


    jb = widget_base(base, $
                     /row)

    junk = widget_button(jb, $
                         value = 'Refresh', $
                         uvalue = 'REFRESH')

    jjb = widget_base(jb, $
                      /nonexclusive)

    junk = widget_button(jjb, $
                         value = 'Smooth image', $
                         uvalue = 'SMOOTH')
    widget_control, junk, set_button = smooth

    junk = widget_droplist(jb, $
                           title = "Navigation Mode", $
                           value = ["Click to centre", $
                                    "Drag image"], $
                           uvalue = "NMODE")

    junk = widget_button(base, $
                         value = 'Dismiss', $
                         uvalue = 'QUIT')

    widget_control, base, /real

    widget_control, canvas, get_value = zwindow
endif else begin
    widget_control, base, get_uvalue = state
    state.window = window
    state.x = x
    state.y = y
    wsize = state.wsize
    if not keyword_set(zoom) then zoom = state.zoom $
    else state.zoom = zoom
    if n_elements(smooth) eq 0 then smooth = state.smooth $
    else state.smooth = smooth
    zwindow = state.zwindow
endelse

wset, window

zmcopy, window, zwindow, x, y, wsize, zoom, smooth, xoff, yoff

if imake then $
  state = {sz_state, $
           window: window, $
           zwindow: zwindow, $
           x: float(x), $
           y: float(y), $
           px: 0., $
           py: 0., $
           xoff: xoff, $
           yoff: yoff, $
           wsize: wsize, $
           zoom: zoom, $
           smooth: smooth, $
           nmode: 0, $
           slid: zslide}

widget_control, base, set_uvalue = state

xmanager, 'sh_zoom', base, /no_block

return, base

end
