/* OCaml-Win32
 * win32_statusbar.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: Status Bars */

static DWORD statusbar_text_options[] = {
    SBT_NOBORDERS,
    SBT_OWNERDRAW,
    SBT_POPOUT,
    SBT_RTLREADING
};
Define_static_constants(statusbar_text_options);

CAMLprim value create_status_window(value style, value text, value parent, value id)
{
    CAMLparam4(style, text, parent, id);
    LARGE_INTEGER li;
    char* s;
    HWND p;
    HWND hwnd;
    CAMLlocal1(val);

    li.QuadPart = Int64_val(style);
    s = new_string(text);
    p = Handle_val(parent);
    enter_blocking_section();
    hwnd = CreateStatusWindow(li.LowPart, s, p, Int_val(id));
    leave_blocking_section();
    free_string(s);
    if (!hwnd)
        raise_last_error();
    val = alloc_handle(hwnd);
    CAMLreturn(val);
}

CAMLprim value draw_status_text(value dc, value rect, value text, value options)
{
    RECT r;

    rect_val(rect, &r);
    DrawStatusText(Handle_val(dc), &r, String_val(text), flags_val(options, statusbar_text_options));
    return Val_unit;
}

CAMLprim value menu_help(value msg, value menu, value inst, value status, value id_menu_pairs)
{
    CAMLparam5(msg, menu, inst, status, id_menu_pairs);
    WPARAM wparam;
    LPARAM lparam;
    HMENU hmenu;
    HINSTANCE hinst;
    HWND hstatus;
    UINT* ids;
    UINT* p;
    CAMLlocal1(pair);

    wparam = Int32_val(Field(msg, 1));
    lparam = Int32_val(Field(msg, 2));
    hmenu = Handle_val(menu);
    hinst = Handle_val(inst);
    hstatus = Handle_val(status);
    ids = malloc(2 * (list_length(id_menu_pairs) + 1) * sizeof(UINT));
    p = ids;
    for (; !Is_nil(id_menu_pairs); id_menu_pairs = Tail(id_menu_pairs)) {
        pair = Head(id_menu_pairs);
        *p++ = Int_val(Field(pair, 0));
        *p++ = (UINT)Handle_val(Field(pair, 1));
    }
    *p++ = 0;
    *p++ = 0;
    enter_blocking_section();
    MenuHelp(Int_val(Field(msg, 0)), wparam, lparam, hmenu, hinst, hstatus, ids);
    leave_blocking_section();
    free(ids);
    CAMLreturn(Val_unit);
}

/* Styles */

static DWORD statusbar_style_options[] = {
    SBARS_SIZEGRIP
};
Define_static_constants(statusbar_style_options);

CAMLprim value statusbar_style_of_option(value option)
{
    return copy_int64((int64)Constant_val(option, statusbar_style_options));
}

/* Messages */

CAMLprim value issue_sb_getborders(value sender)
{
    CAMLparam1(sender);
    INT borders[3];
    CAMLlocal3(contents, result, val);

    contents = pack_message(SB_GETBORDERS, 0, (LPARAM)borders);
    result = callback(sender, contents);
    if (Int32_val(result) == 0)
        raise_win32_error(0);
    val = alloc_tuple(3);
    Store_field(val, 0, Val_int(borders[0]));
    Store_field(val, 1, Val_int(borders[1]));
    Store_field(val, 2, Val_int(borders[2]));
    CAMLreturn(val);
}

CAMLprim value pack_sb_geticon(value part)
{
    return pack_message(SB_GETICON, Int_val(part), 0);
}

CAMLprim value unpack_sb_geticon(value result)
{
    return alloc_handle((HICON)Int32_val(result));
}

CAMLprim value issue_sb_getparts(value sender, value max_count)
{
    CAMLparam2(sender, max_count);
    int max_cnt, cnt, n, i;
    INT* p;
    CAMLlocal4(contents, result, arr, val);

    max_cnt = Int_val(max_count);
    if (max_cnt > 0)
        p = malloc(max_cnt * sizeof(INT));
    else
        p = NULL;
    contents = pack_message(SB_GETPARTS, max_cnt, (LPARAM)p);
    result = callback(sender, contents);
    cnt = Int32_val(result);
    n = cnt < max_cnt ? cnt : max_cnt;
    arr = n > 0 ? alloc_tuple(n) : Atom(0);
    for (i = 0; i < n; ++i)
        Store_field(arr, i, Val_int(p[i]));
    if (max_cnt > 0)
        free(p);
    val = alloc_tuple(2);
    Store_field(val, 0, Val_int(cnt));
    Store_field(val, 1, arr);
    CAMLreturn(val);
}

CAMLprim value issue_sb_getrect(value sender, value part)
{
    CAMLparam2(sender, part);
    RECT r;
    CAMLlocal3(contents, result, val);

    contents = pack_message(SB_GETRECT, Int_val(part), (LPARAM)&r);
    result = callback(sender, contents);
    if (Int32_val(result) == 0)
        raise_win32_error(0);
    val = alloc_rect(&r);
    CAMLreturn(val);
}

CAMLprim value issue_sb_gettext(value sender, value part, value max_length)
{
    CAMLparam3(sender, part, max_length);
    char* p;
    CAMLlocal4(contents, result, val, v);

    p = malloc(Int_val(max_length) + 1);
    contents = pack_message(SB_GETTEXT, Int_val(part), (LPARAM)p);
    result = callback(sender, contents);
    val = alloc_tuple(2);
    v = copy_string(p);
    Store_field(val, 0, v);
    v = Alloc_flags(HIWORD(Int32_val(result)), statusbar_text_options);
    Store_field(val, 1, v);
    free(p);
    CAMLreturn(val);
}

CAMLprim value pack_sb_gettext_ownerdraw(value part)
{
    return pack_message(SB_GETTEXT, Int_val(part), 0);
}

CAMLprim value unpack_sb_gettext_ownerdraw(value result)
{
    return result;
}

CAMLprim value pack_sb_gettextlength(value part)
{
    return pack_message(SB_GETTEXTLENGTH, Int_val(part), 0);
}

CAMLprim value unpack_sb_gettextlength(value result)
{
    CAMLparam1(result);
    DWORD dw;
    CAMLlocal2(val, v);

    dw = Int32_val(result);
    val = alloc_tuple(2);
    Store_field(val, 0, Val_int(LOWORD(dw)));
    v = Alloc_flags(HIWORD(dw), statusbar_text_options);
    Store_field(val, 1, v);
    CAMLreturn(val);
}

CAMLprim value issue_sb_gettiptext(value sender, value part, value max_length)
{
    CAMLparam3(sender, part, max_length);
    int len;
    char* p;
    CAMLlocal2(contents, val);

    len = Int_val(max_length) + 1;
    p = malloc(len);
    contents = pack_message(SB_GETTIPTEXT, MAKEWPARAM(Int_val(part), len), (LPARAM)p);
    callback(sender, contents);
    val = copy_string(p);
    free(p);
    CAMLreturn(val);
}

CAMLprim value unpack_sb_issimple(value result)
{
    return Val_bool(Int32_val(result) != 0);
}

CAMLprim value pack_sb_setbkcolor(value color)
{
    return pack_message(SB_SETBKCOLOR, 0, (LPARAM)color_val(color));
}

CAMLprim value unpack_sb_setbkcolor(value result)
{
    return alloc_color((COLORREF)Int32_val(result));
}

CAMLprim value pack_sb_seticon(value part, value icon)
{
    return pack_message(SB_SETICON, Int_val(part), (LPARAM)Handle_val(icon));
}

CAMLprim value unpack_sb_seticon(value result)
{
    if (Int32_val(result) == 0)
        raise_win32_error(0);
    return Val_unit;
}

CAMLprim value pack_sb_setminheight(value height)
{
    return pack_message(SB_SETMINHEIGHT, Int_val(height), 0);
}

CAMLprim value issue_sb_setparts(value sender, value widths)
{
    CAMLparam2(sender, widths);
    int cnt, i;
    INT* p;
    CAMLlocal2(contents, result);

    cnt = Wosize_val(widths);
    if (cnt > 0)
        p = malloc(cnt * sizeof(INT));
    else
        p = NULL;
    for (i = 0; i < cnt; ++i)
        p[i] = Int_val(Field(widths, i));
    contents = pack_message(SB_SETPARTS, cnt, (LPARAM)p);
    result = callback(sender, contents);
    if (cnt > 0)
        free(p);
    if (Int32_val(result) == 0)
        raise_win32_error(0);
    CAMLreturn(Val_unit);
}

CAMLprim value issue_sb_settext(value sender, value part, value text, value options)
{
    CAMLparam4(sender, part, text, options);
    char* p;
    DWORD opt;
    CAMLlocal2(contents, result);

    p = new_string(text);
    opt = flags_val(options, statusbar_text_options);
    contents = pack_message(SB_SETTEXT, Int_val(part) | opt, (LPARAM)p);
    result = callback(sender, contents);
    free_string(p);
    if (Int32_val(result) == 0)
        raise_win32_error(0);
    CAMLreturn(Val_unit);
}

CAMLprim value pack_sb_settext_ownerdraw(value part, value data)
{
    return pack_message(SB_SETTEXT, Int_val(part) | SBT_OWNERDRAW, Int32_val(data));
}

CAMLprim value unpack_sb_settext_ownerdraw(value result)
{
    if (Int32_val(result) == 0)
        raise_win32_error(0);
    return Val_unit;
}

CAMLprim value issue_sb_settiptext(value sender, value part, value text)
{
    CAMLparam3(sender, part, text);
    char* p;
    CAMLlocal1(contents);

    p = new_string(text);
    contents = pack_message(SB_SETTIPTEXT, Int_val(part), (LPARAM)p);
    callback(sender, contents);
    free_string(p);
    CAMLreturn(Val_unit);
}

CAMLprim value pack_sb_simple(value simple)
{
    return pack_message(SB_SIMPLE, Bool_val(simple), 0);
}

CAMLprim value unpack_sb_simple(value result)
{
    if (Int32_val(result) == 0)
        raise_win32_error(0);
    return Val_unit;
}
