/**********************************************************************

	Copyright (C) 2003-2004
	Hirohisa MORI <joshua@nichibun.ac.jp>
	Tomohito Nakajima <nakajima@zeta.co.jp>
	Tomoki Sekiyama <sekiyama@yahoo.co.jp>

	This program is free software; you can redistribute it
	and/or modify it under the terms of the GLOBALBASE
	Library General Public License (G-LGPL) as published by

	http://www.globalbase.org/

	This program 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.

**********************************************************************/


#include "v/VSeparator.h"
#include "VApplication.h"
#include "vobject_main.h"
#include "vwin_control.h"

class SeparatorRegister{
public:
	
	SeparatorRegister(char *class_name, WNDPROC wp){
		WNDCLASSEX wc;
		wc.cbSize = sizeof(WNDCLASSEX);
		wc.style = CS_HREDRAW|CS_VREDRAW;
		wc.lpfnWndProc = wp;
		wc.cbClsExtra = 0;
		wc.cbWndExtra = sizeof(DWORD);
		wc.hInstance = ::GetModuleHandle(NULL);
		wc.hIcon = LoadIcon(NULL,IDI_APPLICATION);
		wc.hCursor = LoadCursor(NULL,IDC_ARROW);
		wc.hbrBackground = CreateSolidBrush(GetSysColor(COLOR_3DFACE));
		wc.lpszMenuName = NULL;
		wc.lpszClassName = class_name;
		wc.hIconSm = NULL;
		
		if(!::RegisterClassEx(&wc)){
			VWinError();
			er_panic("SeparatorRegister");
		}
	}

	static LRESULT CALLBACK SeparatorWndProc(HWND hWnd, UINT message,
				WPARAM wParam, LPARAM lParam, void(*Draw)(HDC,RECT&)) {
		switch(message){
			case WM_PAINT:
			{
				if ( GetUpdateRect(hWnd, NULL, TRUE) ) {
					PAINTSTRUCT ps;
					HDC hdc = BeginPaint(hWnd,&ps);
					Draw(hdc, ps.rcPaint);
					EndPaint(hWnd, &ps);
				}		
			}
		}
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
};


HPEN penHilight = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_3DHIGHLIGHT));
HPEN penShadow  = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_3DSHADOW));

class HSeparatorRegister : public SeparatorRegister {
public:
	static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
		return SeparatorWndProc(hWnd, message, wParam, lParam, Draw);
	}

	HSeparatorRegister() : SeparatorRegister("vobj_h_separator",WndProc) {}

	static void Draw(HDC dc, RECT &rect) {
		SelectObject(dc, penShadow);
		MoveToEx(dc, 0, 0, NULL);
		LineTo(dc, rect.right-1, 0);
		SelectObject(dc, penHilight);
		MoveToEx(dc, 0, 1, NULL);
		LineTo(dc, rect.right-1, 1);
	}
}hseparator_register;

class VSeparatorRegister : public SeparatorRegister {
public:
	static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
		return SeparatorWndProc(hWnd, message, wParam, lParam, Draw);
	}

	VSeparatorRegister() : SeparatorRegister("vobj_v_separator",WndProc) {}

	static void Draw(HDC dc, RECT &rect) {
		SelectObject(dc, penShadow);
		MoveToEx(dc, 0, 0, NULL);
		LineTo(dc, 0, rect.bottom-1);
		SelectObject(dc, penHilight);
		MoveToEx(dc, 1, 0, NULL);
		LineTo(dc, 1, rect.bottom-1);
	}
}vseparator_register;

static HWND CreateSeparatorWindow(int style, HWND hwnd, int id, bool vert){
	return ::CreateWindowEx(
		0, 
		vert ? "vobj_v_separator" : "vobj_h_separator",
		"",
		style,
		0,
		0,
		0,
		0,
		hwnd,
		(HMENU)id,
		theApp->get_instance(),
		NULL);
}


VExError 
VHSeparator::create_do(const VObjectStatus* s, int flags, VObject *parent, void * arg)
{
	sts.min_size.w = sts.min_size.h = 2;

	DWORD style=WS_CHILD;
	if(!s->enabled){
		style |= WS_DISABLED;
	}
	if(s->visible){
		style |= WS_VISIBLE;
	}
	
	/* find container window that will own this button.*/
	VContainerInfo *container_info = VInfo::get_container_info(parent);
	int id = container_info->get_next_control_id();
	HWND hwnd = v_serialized_exec_func(CreateSeparatorWindow, style, container_info->get_hwnd(), id, false);
	info = new VInfo(this, hwnd, id);
	
	return parent->add_child_do(this);
}

VExError 
VVSeparator::create_do(const VObjectStatus* s, int flags, VObject *parent, void * arg)
{
	sts.min_size.w = sts.min_size.h = 2;

	DWORD style=WS_CHILD;
	if(!s->enabled){
		style |= WS_DISABLED;
	}
	if(s->visible){
		style |= WS_VISIBLE;
	}
	
	/* find container window that will own this button.*/
	VContainerInfo *container_info = VInfo::get_container_info(parent);
	int id = container_info->get_next_control_id();
	HWND hwnd = v_serialized_exec_func(CreateSeparatorWindow, style, container_info->get_hwnd(), id, true);
	info = new VInfo(this, hwnd, id);
	
	return parent->add_child_do(this);
}

void
VSeparator::destroy_do(VObject *parent)
{
	parent->remove_child_do(this);
	if(info){
		v_serialized_exec_sub(::DestroyWindow, info->get_hwnd());
		delete info;
		info = NULL;
	}
	sts.parent->redraw();
}

VSeparator::~VSeparator()
{
}

VExError
VSeparator::get_status(VObjectStatus *s, int flags) const
{
	V_OP_START_EX
	VExError err = VObject::get_status(s,flags);
	win_control_default_get_status(info->get_hwnd(), s, flags, &err);
	V_OP_END
	return err;
};

VExError
VSeparator::set_status(const VObjectStatus *s, int flags)
{
	V_OP_START_EX

	VExError err = VObject::set_status(s,flags);
	HWND hwnd = info->get_hwnd();
	win_control_default_set_status(hwnd, s, flags&~VSF_DESC, &err);

	if ( flags & VSF_CALC_MIN ) {
		// min is calculated when desc is set
		err.subcode1 &= ~VSF_CALC_MIN;
	}

	if ( flags & VSF_VISIBLE ) {
		if ( s->visible != (::IsWindowVisible(info->get_hwnd())==TRUE) ){
			v_serialized_exec_sub(::ShowWindow, hwnd, s->visible ? SW_SHOW : SW_HIDE);
		}
		err.subcode1 &= ~VSF_VISIBLE;
	}

	V_OP_END
	
	if ( flags & (VSF_ALIGN | VSF_PADDING | VSF_VISIBLE) )
		VLayout::mark(this);
	return err;
}

void
VSeparator::redraw(VRect *rect) const
{
	if ( ! info )
		return;
	_V_OP_START_VOID
	win_redraw(info->get_hwnd(), rect);
	V_OP_END
}
