/******************************************************************************
 *
 * Copyright (c) 1999	TOSHIYUKI ARAI. ALL RIGHTS RESERVED. 
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions, and the following disclaimer.
 *  
 * 2. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *
 *	PopupView.cpp
 *
 *****************************************************************************/

// SOL++2000
// 1999.10.09 Added a layout method.
// 2001.03.11 Added a create method.

#include <sol\PopupView.h>
#include <sol\Application.h>


long PopupView::defaultProc(Event& event) 
{
	return FALSE;
}

PopupView::PopupView(View* parent)
		:Composite(parent) 
{ 
	owner = NULL;
	focusId = 0;
}


// 2001/03/11
Boolean PopupView::create(View* parent)
{
	Boolean rc = Composite::create(parent) ;
 
	owner = NULL;
	focusId = 0;
	return rc;
}

PopupView::PopupView(View* parent, const char* name, Args& args)
	:Composite(parent, name,
		     args.set(XmNstyle, 
						(ulong)(WS_POPUP|WS_SYSMENU|WS_CAPTION))
			     .set(XmNpredefined, TRUE)
		         .set(XmNclassName, (ulong)WC_DIALOG))
{
	owner  = NULL;
	focusId = 0;

	addEventHandler(WM_CLOSE, this,
			(Handler)&PopupView::close, NULL);

	setWindowLong(DWL_DLGPROC, (LPARAM)PopupView::procedure);
	ulong val;
	if (args.get(XmNfocusId, &val)) {
		focusId = (int)val;
	}
}


Boolean PopupView::create(View* parent, const char* name, Args& args)
{
	Boolean rc = Composite::create(parent, name,
		     args.set(XmNstyle, 
						(ulong)(WS_POPUP|WS_SYSMENU|WS_CAPTION))
			     .set(XmNpredefined, TRUE)
		         .set(XmNclassName, (ulong)WC_DIALOG));

	owner  = NULL;
	focusId = 0;

	addEventHandler(WM_CLOSE, this,
			(Handler)&PopupView::close, NULL);

	setWindowLong(DWL_DLGPROC, (LPARAM)PopupView::procedure);
	ulong val;
	if (args.get(XmNfocusId, &val)) {
		focusId = (int)val;
	}
	return rc;
}


void PopupView::disableOwner()
{
	if(owner) {
		owner ->enableWindow(FALSE);
	}
}


void PopupView::enableOwner()
{
	if(owner) {
		owner -> enableWindow(TRUE);
	}
}


long PopupView::close(Event& event)
{
	Action action(null, event);
	popdown(action);
	return 0L;
}


void PopupView::popup(Action& action)
{
	RECT rect;
	getWindowRect(&rect);
	int x 	   = 0;
	int y 	   = 0;
	int width  = rect.right - rect.left;
	int height = rect.bottom - rect.top;
	int scWidth  = ::GetSystemMetrics(SM_CXSCREEN);
	int scHeight = ::GetSystemMetrics(SM_CYSCREEN);
	
	View* parent = getParent();
	if(parent) {
		// Move to the center of a parent.
		RECT pr;
		parent -> getWindowRect(&pr);
		x = pr.left + (pr.right - pr.left - width)/2;
		y = pr.top  + (pr.bottom - pr.top - height)/2;
	}
	if((x+width) >scWidth) x = scWidth - width;
	if(x <0 ) x = 0;

	if((y+height) >scHeight) y = scHeight - height;
	if(y < 0) y = 0;

	disableOwner();
	reshape(x, y, width, height);
	raise();
	show(SW_SHOWNORMAL);
}


void PopupView::setPopupFocus()
{
	if(focusId) {
		HWND child = getItem(focusId);
		if(child) {
			::SetFocus(child);
		}
	}
}


void PopupView::popdown(Action& action)
{
	enableOwner();
	show(SW_HIDE);
}


void PopupView::popupAt(Action& action)
{
	RECT rect;
	getWindowRect(&rect);
	int w   = rect.right - rect.left;
	int h   = rect.bottom - rect.top;
	int x = (::GetSystemMetrics(SM_CXSCREEN) - w)/2;
	int y = (::GetSystemMetrics(SM_CYSCREEN) - h)/2;
	reshape(x, y,  w, h);
	disableOwner();
	raise();
	show(SW_SHOWNORMAL);
}


void PopupView::popupAsItIs(Action& action)
{
	disableOwner();
	raise();
	show(SW_SHOWNORMAL);
}



long PopupView::command(Event& event) 
{
	WORD controlId = event.getControlId();
// PopupView has no menuCallbacks.
	HWND child     = event.getChild();
	if(controlId > 0) {
		HWND item = getItem(controlId);
		if(::IsWindow(item))
			child = item;
	}

	UINT notify = event.getNotification();
	const char* name = findCallbackName(event, child);

	WPARAM wParam = event.getWParam();
	if(name == XmNactivateCallback  && wParam ==IDOK) {
		child = ::GetFocus();
	}
	callCallback(name, (Key)child, NULL, event);

	return 0;
}


void PopupView::resize()
{
	RECT r;
	getClientRect(&r);
	int w = r.right-r.left;
	int h = r.bottom-r.top;
	send(WM_SIZE, 0, MAKELONG(w, h));
}

// 1999.10.09 Added the following method to fix a problem on Layoutmanager.
void PopupView::layout(int x, int y, int w, int h)
{
	/*if (getParent() != null) {
		reshape(x, y, w, h);
	}*/
	LayoutManager* layoutManager = getLayoutManager();
	if (layoutManager) {
		layoutManager->layout(0, 0, w, h);
	}
}




BOOL CALLBACK PopupView::procedure(HWND hwnd, 
		UINT message, WPARAM wParam, LPARAM lParam)
{
	Event event(message, wParam, lParam);

	View* view = Application::lookup(hwnd);
	BOOL result = FALSE;
	if (view) {
		result = (BOOL) view -> dispatch(event);
	}
	return result;
}


void PopupView::setViewId(int vid)
{
	setId(vid);
}


void PopupView::centerOn()
{
	RECT rect;
	getWindowRect(&rect);
	int x 	   = 0;
	int y 	   = 0;
	int width  = rect.right - rect.left;
	int height = rect.bottom - rect.top;
	int scWidth  = ::GetSystemMetrics(SM_CXSCREEN);
	int scHeight = ::GetSystemMetrics(SM_CYSCREEN);
	
	View* parent = getParent();
	if(parent) {
		RECT pr;
		parent -> getWindowRect(&pr);
		x = pr.left + (pr.right - pr.left - width)/2;
		y = pr.top  + (pr.bottom - pr.top - height)/2;
	}
	if((x+width) >scWidth) {
		x = scWidth - width;
	}
	if(x <0 ) { 
		x = 0;
	}
	if((y+height) >scHeight){
		y = scHeight - height;
	}
	if(y < 0) { 
		y = 0;
	}

	reshape(x, y, width, height);
}	
