-----------------------------------------------------------------------------
-- Name:        art.wx.lua
-- Purpose:     wxArtProvider wxLua sample
-- Author:      John Labenski
-- Modified by:
-- Created:     16/11/2012
-- Copyright:   (c) 2012 John Labenski. All rights reserved.
-- Licence:     wxWidgets licence
-----------------------------------------------------------------------------

-- Load the wxLua module, does nothing if running from wxLua, wxLuaFreeze, or wxLuaEdit
package.cpath = package.cpath..";./?.dll;./?.so;../lib/?.so;../lib/vc_dll/?.dll;../lib/bcc_dll/?.dll;../lib/mingw_dll/?.dll;"
require("wx")

-- --------------------------------------------------------------------------

frame = nil

-- --------------------------------------------------------------------------
-- Initialize the wxArtProvider variables

local artClients = {}
local artIds     = {}

for k, v in pairs(wx) do
    if (k:find("wxART_[A-Z_]*") ~= nil) then
        -- wxArtClients values end with "_C"
        if v:sub(-2,-1) == "_C" then
            artClients[#artClients+1] = k
        else
            artIds[#artIds+1] = k
        end
    end
end

table.sort(artClients)
table.sort(artIds)

local char_width         = nil -- cache value
local char_height        = nil
local colLefts           = nil
local colWidths          = nil
local rowTops            = nil
local rowHeights         = nil
local did_set_scrollbars = false

-- --------------------------------------------------------------------------
-- paint event handler for the panel that's called by wxEVT_PAINT
function OnPaint(event)
    -- must always create a wxPaintDC in a wxEVT_PAINT handler
    local dc = wx.wxPaintDC(panel)
    panel:PrepareDC(dc)

    local row_height = 50
    local x_padding  = 10

    -- Find the sizes of things for later
    if not char_height then
        local textExtentSize = dc:GetTextExtentSize("MMMM")
        char_height = textExtentSize:GetHeight()/2
        char_width  = textExtentSize:GetWidth()/4

        -- find the max width of the wxArtID strings
        local col0_width = 0

        for r = 1, #artIds do
            local artIdTextExtent = dc:GetTextExtentSize(artIds[r])
            local w = artIdTextExtent:GetWidth();
            if w > col0_width then
                col0_width = w
            end
        end

        colWidths     = {};
        colWidths[0]  = col0_width + x_padding

        colLefts      = {};
        colLefts[0]   = 0
        colLefts[1]   = colWidths[0]

        rowHeights    = {}
        rowHeights[0] = 50

        rowTops       = {}
        rowTops[0]    = 0
        rowTops[1]    = rowHeights[0]

        for c = 1, #artClients do
            local artClientTextExtent = dc:GetTextExtentSize(artClients[c])
            local w = artClientTextExtent:GetWidth();

            colWidths[c]  = w + x_padding
            colLefts[c+1] = colLefts[c] + colWidths[c]

            for r = 1, #artIds do
                local artClient = wx[artClients[c]]
                local artId     = wx[artIds[r]]

                local bmp = wx.wxArtProvider.GetBitmap(artId, artClient)
                if bmp:Ok() then
                    local w, h = bmp:GetWidth(), bmp:GetHeight()
                    if (not rowHeights[r]) or (rowHeights[r] < h + 10) then
                        rowHeights[r] = h + 10
                    end
                else
                    rowHeights[r] = 50
                end
                bmp:delete()
            end
        end

        for r = 0, #rowHeights do
            rowTops[r+1] = rowTops[r]+rowHeights[r]
        end
        rowTops[#rowTops+1] = rowTops[#rowTops] + rowHeights[#rowHeights]
    end

    dc:DrawText("wxArtID  /  wxArtClient", x_padding/2, rowHeights[0]/2-char_height/2)

    for c = 0, #artClients do
        for r = 0, #artIds do

            local artClient = wx[artClients[c]]
            local artId     = wx[artIds[r]]

            local row_top    = rowTops[r+1]
            local row_height = rowHeights[r]

            if r == 0 then
                if c > 0 then
                    dc:DrawText(artClients[c], colLefts[c]+x_padding/2, rowTops[r]+rowHeights[r]/2-char_height/2)

                    local artSizePlatform = wx.wxArtProvider.GetSizeHint(artClient, true)
                    local artSize = wx.wxArtProvider.GetSizeHint(artClient, false)

                    local art_size_platform_str = string.format("(%d, %d)", artSizePlatform:GetWidth(), artSizePlatform:GetHeight())
                    local art_size_str          = string.format("(%d, %d)", artSize:GetWidth(),         artSize:GetHeight())

                    local textExtentPlatformStr = dc:GetTextExtentSize(art_size_platform_str)
                    local textExtentSizeStr     = dc:GetTextExtentSize(art_size_str)

                    dc:DrawText(art_size_platform_str,
                                colLefts[c]+colWidths[c]/2 - textExtentPlatformStr:GetWidth()/2 + x_padding/2,
                                rowTops[r+1] + (rowHeights[r+1]/2 - textExtentPlatformStr:GetHeight())/2 )
                    dc:DrawText(art_size_str,
                                colLefts[c]+colWidths[c]/2 - textExtentSizeStr:GetWidth()/2     + x_padding/2,
                                rowTops[r+1] + rowHeights[r+1]/2 + (rowHeights[r+1]/2 - textExtentSizeStr:GetHeight())/2 )
                elseif c == 0 then
                    dc:DrawText("Native Size",      x_padding/2, rowTops[r+1]                     + (rowHeights[r+1]/2 - char_height)/2 )
                    dc:DrawText("ArtProvider Size", x_padding/2, rowTops[r+1] + rowHeights[r+1]/2 + (rowHeights[r+1]/2 - char_height)/2 )
                end
            elseif c == 0 then
                if r > 0 then
                    dc:DrawText(artId, colLefts[c]+x_padding/2, rowTops[r+1]+rowHeights[r]/2-char_height/2)
                end
            else
                local bmp = wx.wxArtProvider.GetBitmap(artId, artClient)
                if bmp:Ok() then
                    local w, h = bmp:GetWidth(), bmp:GetHeight()
                    dc:DrawBitmap(bmp, colLefts[c]+colWidths[c]/2-w/2, rowTops[r+1]+rowHeights[r]/2-h/2, true)
                end
                bmp:delete()
            end

            dc:DrawLine(colLefts[0],         rowTops[r+1],
                        colLefts[#colLefts], rowTops[r+1])
        end

        dc:DrawLine(colLefts[c]+colWidths[c], 0,
                    colLefts[c]+colWidths[c], rowTops[#rowTops])
    end

    dc:DrawLine(colLefts[0],         rowTops[#rowTops],
                colLefts[#colLefts], rowTops[#rowTops])

    if not did_set_scrollbars then
        did_set_scrollbars = true
        panel:SetScrollbars(20, 20,
                            math.ceil((colLefts[#colLefts]-10)/20),
                            math.ceil((rowTops[#rowTops])/20), 0, 0, false);
    end

    -- the paint DC will be automatically destroyed by the garbage collector,
    -- however on Windows 9x/Me this may be too late (DC's are precious resource)
    -- so delete it here
    dc:delete() -- ALWAYS delete() any wxDCs created when done
end

-- Create a function to encapulate the code, not necessary, but it makes it
--  easier to debug in some cases.
function main()

    -- create the wxFrame window
    frame = wx.wxFrame( wx.NULL,                    -- no parent for toplevel windows
                        wx.wxID_ANY,                -- don't need a wxWindow ID
                        "wxLua wxArtProvider Demo", -- caption on the frame
                        wx.wxDefaultPosition,       -- let system place the frame
                        wx.wxSize(450, 450),        -- set the size of the frame
                        wx.wxDEFAULT_FRAME_STYLE )  -- use default frame styles

    -- create a single child window, wxWidgets will set the size to fill frame
    panel = wx.wxScrolledWindow(frame, wx.wxID_ANY)
    panel:SetScrollbars(200, 200, 20, 20, 0, 0, true);

    -- connect the paint event handler function with the paint event
    panel:Connect(wx.wxEVT_PAINT, OnPaint)

    -- create a simple file menu
    local fileMenu = wx.wxMenu()
    fileMenu:Append(wx.wxID_EXIT, "E&xit", "Quit the program")

    -- create a simple help menu
    local helpMenu = wx.wxMenu()
    helpMenu:Append(wx.wxID_ABOUT, "&About", "About the wxLua Minimal Application")

    -- create a menu bar and append the file and help menus
    local menuBar = wx.wxMenuBar()
    menuBar:Append(fileMenu, "&File")
    menuBar:Append(helpMenu, "&Help")

    -- attach the menu bar into the frame
    frame:SetMenuBar(menuBar)

    -- create a simple status bar
    frame:CreateStatusBar(1)
    frame:SetStatusText("Welcome to wxLua.")

    -- connect the selection event of the exit menu item to an
    -- event handler that closes the window
    frame:Connect(wx.wxID_EXIT, wx.wxEVT_COMMAND_MENU_SELECTED,
                  function (event) frame:Close(true) end )

    -- connect the selection event of the about menu item
    frame:Connect(wx.wxID_ABOUT, wx.wxEVT_COMMAND_MENU_SELECTED,
        function (event)
            wx.wxMessageBox('This is the "About" dialog of the Minimal wxLua sample.\n'..
                            wxlua.wxLUA_VERSION_STRING.." built with "..wx.wxVERSION_STRING,
                            "About wxLua",
                            wx.wxOK + wx.wxICON_INFORMATION,
                            frame)
        end )

    -- show the frame window
    frame:Show(true)
end

main()

-- Call wx.wxGetApp():MainLoop() last to start the wxWidgets event loop,
-- otherwise the wxLua program will exit immediately.
-- Does nothing if running from wxLua, wxLuaFreeze, or wxLuaEdit since the
-- MainLoop is already running or will be started by the C++ program.
wx.wxGetApp():MainLoop()
