/* OCaml-Win32
 * win32_imagelist.c
 * Copyright (c) 2002-2004 by Harry Chomsky
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include "win32.h"

/********************************************************************/
/* User Interface: Windows User Experience: Windows Shell: SDK: Windows Controls: Individual Control Information: Image Lists */

static DWORD image_list_draw_styles[] = {
    ILD_BLEND25,
    ILD_BLEND50,
    ILD_IMAGE,
    ILD_MASK,
    ILD_NORMAL,
    ILD_TRANSPARENT
};
Define_static_constants(image_list_draw_styles);

CAMLprim value image_list_add(value iml, value image, value mask)
{
    int result;

    result = ImageList_Add(Handle_val(iml), Handle_val(image), Handle_val(mask));
    if (result == -1)
        raise_win32_error(0);
    return Val_int(result);
}

CAMLprim value image_list_add_icon(value iml, value icon)
{
    int result;

    result = ImageList_AddIcon(Handle_val(iml), Handle_val(icon));
    if (result == -1)
        raise_win32_error(0);
    return Val_int(result);
}

CAMLprim value image_list_add_masked(value iml, value image, value mask)
{
    int result;

    result = ImageList_AddMasked(Handle_val(iml), Handle_val(image), color_val(mask));
    if (result == -1)
        raise_win32_error(0);
    return Val_int(result);
}

CAMLprim value image_list_begin_drag(value iml, value index, value hotspot)
{
    if (!ImageList_BeginDrag(Handle_val(iml), Int_val(index), X(hotspot), Y(hotspot)))
        raise_win32_error(0);
    return Val_unit;
}

static DWORD image_list_copy_modes[] = {
    ILCF_MOVE,
    ILCF_SWAP
};
Define_static_constants(image_list_copy_modes);

CAMLprim value image_list_copy(value dest_iml, value dest_index, value src_iml, value src_index, value mode)
{
    BOOL result;

    result = ImageList_Copy(
        Handle_val(dest_iml),
        Int_val(dest_index),
        Handle_val(src_iml),
        Int_val(src_index),
        Constant_val(mode, image_list_copy_modes));
    if (!result)
        raise_win32_error(0);
    return Val_unit;
}

static DWORD image_list_color_types[] = {
    ILC_COLOR,
    ILC_COLOR4,
    ILC_COLOR8,
    ILC_COLOR16,
    ILC_COLOR24,
    ILC_COLOR32,
    ILC_COLORDDB
};
Define_static_constants(image_list_color_types);

CAMLprim value image_list_create(value size, value color_type, value mask, value initial, value grow)
{
    HIMAGELIST result;

    result = ImageList_Create(
        Cx(size), Cy(size),
        Constant_val(color_type, image_list_color_types) |
            (Bool_val(mask) ? ILC_MASK : 0),
        Int_val(initial),
        Int_val(grow));
    if (!result)
        raise_win32_error(0);
    return alloc_handle(result);
}

CAMLprim value image_list_destroy(value iml)
{
    if (!ImageList_Destroy(Handle_val(iml)))
        raise_win32_error(0);
    return Val_unit;
}

CAMLprim value image_list_drag_enter(value lock, value pt)
{
    if (!ImageList_DragEnter(Handle_val(lock), X(pt), Y(pt)))
        raise_win32_error(0);
    return Val_unit;
}

CAMLprim value image_list_drag_leave(value lock)
{
    if (!ImageList_DragLeave(Handle_val(lock)))
        raise_win32_error(0);
    return Val_unit;
}

CAMLprim value image_list_drag_move(value pt)
{
    if (!ImageList_DragMove(X(pt), Y(pt)))
        raise_win32_error(0);
    return Val_unit;
}

CAMLprim value image_list_drag_show_nolock(value show)
{
    if (!ImageList_DragShowNolock(Bool_val(show)))
        raise_win32_error(0);
    return Val_unit;
}

CAMLprim value image_list_draw_native(value iml, value index, value dst, value pt, value style, value overlay)
{
    DWORD sty;

    sty = Constant_val(style, image_list_draw_styles);
    if (Is_some(overlay))
        sty |= INDEXTOOVERLAYMASK(Int_val(Value_of(overlay)));
    if (!ImageList_Draw(Handle_val(iml), Int_val(index), Handle_val(dst), X(pt), Y(pt), sty))
        raise_win32_error(0);
    return Val_unit;
}

CAMLprim value image_list_draw_bytecode(value* argv, int argn)
{
    return image_list_draw_native(argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]);
}

CAMLprim value image_list_draw_indirect(value params)
{
    IMAGELISTDRAWPARAMS ildp;

    ildp.cbSize = sizeof(ildp);
    ildp.himl = Handle_val(Field(params, 0));
    ildp.i = Int_val(Field(params, 1));
    ildp.hdcDst = Handle_val(Field(params, 2));
    ildp.x = X(Field(params, 3));
    ildp.y = Y(Field(params, 3));
    if (Is_some(Field(params, 4))) {
        ildp.cx = Cx(Value_of(Field(params, 4)));
        ildp.cy = Cy(Value_of(Field(params, 4)));
    } else
        ildp.cx = ildp.cy = 0;
    ildp.xBitmap = X(Field(params, 5));
    ildp.yBitmap = Y(Field(params, 5));
    ildp.rgbBk = color_val(Field(params, 6));
    ildp.rgbFg = color_val(Field(params, 7));
    ildp.fStyle = Constant_val(Field(params, 8), image_list_draw_styles);
    if (Is_some(Field(params, 9)))
        ildp.fStyle |= INDEXTOOVERLAYMASK(Int_val(Value_of(Field(params, 9))));
    if (Is_some(Field(params, 10))) {
        ildp.fStyle |= ILD_ROP;
        ildp.dwRop = Int_val(Value_of(Field(params, 10)));
    } else
        ildp.dwRop = 0;
    if (!ImageList_DrawIndirect(&ildp))
        raise_win32_error(0);
    return Val_unit;
}

CAMLprim value image_list_duplicate(value iml)
{
    HIMAGELIST result;

    result = ImageList_Duplicate(Handle_val(iml));
    if (!result)
        raise_win32_error(0);
    return alloc_handle(result);
}

CAMLprim value image_list_end_drag(value unit)
{
    ImageList_EndDrag();
    return Val_unit;
}

CAMLprim value image_list_extract_icon(value iml, value index)
{
    HICON icon;

    icon = ImageList_ExtractIcon(NULL, Handle_val(iml), Int_val(index));
    if (!icon)
        raise_win32_error(0);
    return alloc_handle(icon);
}

CAMLprim value image_list_get_bk_color(value iml)
{
    return alloc_color(ImageList_GetBkColor(Handle_val(iml)));
}

CAMLprim value image_list_get_drag_image(value unit)
{
    CAMLparam1(unit);
    POINT pt, hotspot;
    HIMAGELIST iml;
    CAMLlocal2(val, v);

    iml = ImageList_GetDragImage(&pt, &hotspot);
    if (!iml)
        raise_win32_error(0);
    val = alloc_tuple(3);
    v = alloc_handle(iml);
    Store_field(val, 0, v);
    v = alloc_point(pt);
    Store_field(val, 1, v);
    v = alloc_point(hotspot);
    Store_field(val, 2, v);
    CAMLreturn(val);
}

CAMLprim value image_list_get_icon(value iml, value index, value style, value overlay)
{
    DWORD sty;
    HICON icon;

    sty = Constant_val(style, image_list_draw_styles);
    if (Is_some(overlay))
        sty |= INDEXTOOVERLAYMASK(Int_val(Value_of(overlay)));
    icon = ImageList_GetIcon(Handle_val(iml), Int_val(index), sty);
    if (!icon)
        raise_win32_error(0);
    return alloc_handle(icon);
}

CAMLprim value image_list_get_icon_size(value iml)
{
    SIZE s;

    if (!ImageList_GetIconSize(Handle_val(iml), &s.cx, &s.cy))
        raise_win32_error(0);
    return alloc_size(s);
}

CAMLprim value image_list_get_image_count(value iml)
{
    return Val_int(ImageList_GetImageCount(Handle_val(iml)));
}

CAMLprim value image_list_get_image_info(value iml, value index)
{
    CAMLparam2(iml, index);
    IMAGEINFO ii;
    CAMLlocal2(val, v);

    if (!ImageList_GetImageInfo(Handle_val(iml), Int_val(index), &ii))
        raise_win32_error(0);
    val = alloc_tuple(3);
    v = alloc_handle(ii.hbmImage);
    Store_field(val, 0, v);
    v = alloc_handle(ii.hbmMask);
    Store_field(val, 1, v);
    v = alloc_rect(&ii.rcImage);
    Store_field(val, 2, v);
    CAMLreturn(val);
}

CAMLprim value image_list_load_bitmap(value inst, value name, value width, value grow, value mask)
{
    CAMLparam5(inst, name, width, grow, mask);
    HINSTANCE h;
    LPTSTR n;
    COLORREF m;
    HIMAGELIST result;
    CAMLlocal1(val);

    h = Handle_val(inst);
    n = new_resname(name);
    m = color_val(mask);
    enter_blocking_section();
    result = ImageList_LoadBitmap(h, n, Int_val(width), Int_val(grow), m);
    leave_blocking_section();
    free_resname(n);
    if (!result)
        raise_win32_error(0);
    val = alloc_handle(result);
    CAMLreturn(val);
}

CAMLprim value image_list_load_image_native(value src, value width, value grow, value mask, value typ, value options)
{
    CAMLparam5(src, width, grow, mask, typ);
    CAMLxparam1(options);
    HINSTANCE h;
    LPTSTR n;
    COLORREF m;
    UINT opt;
    HIMAGELIST result;
    CAMLlocal1(val);

    opt = flags_val(options, load_image_options);
    if (Tag_val(src) == 0) {
        h = Handle_val(Field(src, 0));
        n = new_resname(Field(src, 1));
    } else {
        h = NULL;
        n = new_string(Field(src, 0));
        opt |= LR_LOADFROMFILE;
    }
    m = color_val(mask);
    enter_blocking_section();
    result = ImageList_LoadImage(
        h,
        n,
        Int_val(width),
        Int_val(grow),
        m,
        Constant_val(typ, image_types),
        opt);
    leave_blocking_section();
    if (Tag_val(src) == 0)
        free_resname(n);
    else
        free_string(n);
    if (!result)
        raise_win32_error(0);
    val = alloc_handle(result);
    CAMLreturn(val);
}

CAMLprim value image_list_load_image_bytecode(value* argv, int argn)
{
    return image_list_load_image_native(argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]);
}

CAMLprim value image_list_merge(value iml1, value index1, value iml2, value index2, value offset)
{
    HIMAGELIST result;

    result = ImageList_Merge(
        Handle_val(iml1), Int_val(index1), Handle_val(iml2), Int_val(index2),
        X(offset), Y(offset));
    if (!result)
        raise_win32_error(0);
    return alloc_handle(result);
}

CAMLprim value image_list_remove(value iml, value index)
{
    if (!ImageList_Remove(Handle_val(iml), Int_val(index)))
        raise_win32_error(0);
    return Val_unit;
}

CAMLprim value image_list_remove_all(value iml)
{
    if (!ImageList_RemoveAll(Handle_val(iml)))
        raise_win32_error(0);
    return Val_unit;
}

CAMLprim value image_list_replace(value iml, value index, value image, value mask)
{
    if (!ImageList_Replace(Handle_val(iml), Int_val(index), Handle_val(image), Handle_val(mask)))
        raise_win32_error(0);
    return Val_unit;
}

CAMLprim value image_list_replace_icon(value iml, value index, value icon)
{
    int result;

    result = ImageList_ReplaceIcon(Handle_val(iml), Int_val(index), Handle_val(icon));
    if (result == -1)
        raise_win32_error(0);
    return Val_int(result);
}

CAMLprim value image_list_set_bk_color(value iml, value color)
{
    COLORREF result;

    result = ImageList_SetBkColor(Handle_val(iml), color_val(color));
    return alloc_color(result);
}

CAMLprim value image_list_set_drag_cursor_image(value iml, value index, value hotspot)
{
    if (!ImageList_SetDragCursorImage(Handle_val(iml), Int_val(index), X(hotspot), Y(hotspot)))
        raise_win32_error(0);
    return Val_unit;
}

CAMLprim value image_list_set_icon_size(value iml, value size)
{
    if (!ImageList_SetIconSize(Handle_val(iml), Cx(size), Cy(size)))
        raise_win32_error(0);
    return Val_unit;
}

CAMLprim value image_list_set_image_count(value iml, value count)
{
    if (!ImageList_SetImageCount(Handle_val(iml), Int_val(count)))
        raise_win32_error(0);
    return Val_unit;
}

CAMLprim value image_list_set_overlay_image(value iml, value index, value overlay)
{
    if (!ImageList_SetOverlayImage(Handle_val(iml), Int_val(index), Int_val(overlay)))
        raise_win32_error(0);
    return Val_unit;
}
