# ### Image viewer using MiniFB
# This example displays the PNG files in a directory, rotating through the available images on each mouse click. 

# This code needs Images.jl and ImageTransformations.jl. Add those packages to your environment before proceeding
using Images
using ImageTransformations
using MiniFB

# Set the size of the window
global const WIDTH = 600
global const HEIGHT = 400

# Global state 
global ni = 1
global num_images = 1

# A function that will be called when a mouse button is clicked. It simply rotates the current image by storing a global integer. 
function onclick(window, button, mod, isPressed)::Cvoid
    global ni, num_images
    if Bool(isPressed)
        if ni < num_images
            ni = ni+1
        else 
            ni = 1
        end
    end
    return nothing
end

# The callback needs to be passed to the C library. The @cfunction macro creates a 
onclick_c = @cfunction(onclick, Cvoid, (Ptr{Cvoid}, mfb_mouse_button, mfb_key_mod, UInt8) )

# Populate a MiniFB buffer from the image data. 
# First, resize the image to the window dimensions. Calculate it's position so that it is centered in the window. 
# Finally, inside the loop, convert each pixel to the 32 bit MiniFB buffer format. 
function populate_buffer!(buffer, img)
    global WIDTH, HEIGHT
    buffer[:] = zeros(UInt32, HEIGHT*WIDTH)
    h, w = size(img)
    ratio = min(1, HEIGHT/h, WIDTH/w)
    nimg = imresize(img, ratio=ratio)
    nh, nw = size(nimg)
    oh = (HEIGHT-nh) ÷ 2
    ow = (WIDTH-nw) ÷ 2 
    for i in 1:nh
        for j in 1:nw
            buffer[(oh+i-1)*WIDTH + ow+j] = mfb_rgb(nimg[i,j])
        end
    end
end

# This is the main function. It takes a directory, calls `loadfiles` to get the image data. 
# Creates the windows, and sets up the callback. Then, inside the `while` loop, renders the buffer into the window. 
# The `mfb_update` not only renders the buffer, but also flushes the input event queue.   
# The buffer is changed only when the state changes. The `mfb_wait_sync` method enforces the required frame rate. 
function imageview(dir::String=".")
    global ni, num_images
    images = loadfiles(dir)
    num_images = length(images)
    buffer = zeros(UInt32, HEIGHT*WIDTH)
    mfb_set_target_fps(10)
    window = mfb_open_ex("Image Viewer", WIDTH, HEIGHT, MiniFB.WF_RESIZABLE);
    mfb_set_mouse_button_callback(window, onclick_c);
    old_ni=0
    while mfb_wait_sync(window)
        if ni != old_ni
            populate_buffer!(buffer, images[ni])
            old_ni = ni
        end
        state = mfb_update(window, buffer);
        if state != MiniFB.STATE_OK
            break;
        end
    end
    mfb_close(window)
end


# Load the files from disk. Select all png files, and then use ImageIO to load them into memory. 
function loadfiles(dir::String=".")
    files = readdir(dir)
    filter!(x->occursin(r"\.png"i, x), files)
    [load(joinpath(dir,x)) for x in files]
end

# Finally, call the main method to display the application
imageview(joinpath(dirname(pathof(MiniFB)),"..", "example"))

# ![](../assets/imageviewer.png)