
// Copyright (C) Recursion Company. All rights reserved.

#ifndef __WTL_UI_BASE_H__
#define __WTL_UI_BASE_H__

#define _VOL_WTL_UI

//----------------------------------------------------------------------  火山窗口组件本地类的创建参数

class CVolNativeWndCreateParam
{
public:
    CVolNativeWndCreateParam (HWND hParentWnd, const INT nLeft, const INT nTop, const INT nWidth, const INT nHeight, INT nID, INT nGroupNumber = -1);

    inline_ CVolNativeWndCreateParam (const CVolNativeWndCreateParam* pCopyParam)
    {
        ASSERT (pCopyParam != NULL);
        COPY_MEM (this, pCopyParam, sizeof (CVolNativeWndCreateParam));
    }

public:
    void CheckBorderStyle (CWindow* pWnd) const;

public:
    HWND m_hParentWnd;  // 父窗口句柄,为NULL表示无.
    CVolObject* m_pParentWndObject;  // 父窗口火山对象,为NULL表示无.
    INT m_nLeft, m_nTop, m_nWidth, m_nHeight;  // 位置矩形的左上角坐标和宽度及高度
    UINT m_nID;  // 在父窗口中的ID值
    INT m_nGroupNumber;  // 所属的设计时组件分组

    DWORD m_dwStyle;  // 窗口风格
    DWORD m_dwExStyle;  // 窗口扩展风格
    const TCHAR* m_szCaption;  // 窗口标题

    // 以下成员仅在创建非子组件窗口时被使用
    CRefVolMenu* m_pVolMenu;  // 所使用的菜单,为NULL表示无.
    BOOL m_blModalDialog;  // 指定所创建窗口是否为模态对话框状态
    BOOL m_blForceUseDialogStyle;  // 本成员仅当m_blModalDialog为真时有效,用作记录是否强制使用所指定的对话框风格.
    INT m_nDialogResult;  // 本成员仅当m_blModalDialog为真时有效,用作记录当以对话框方式显示所创建窗口时,用户程序调用EndDialog时所返回的值.

    // 以下成员正常情况下创建时不用处理:
    HFONT m_hFont;  // 所使用的字体句柄,调用CreateControl时必定不为NULL.
};

#define _CREATE_WND_BY_PARAM(pCreateParam)  \
        Create (pCreateParam->m_hParentWnd,  \
            CRect (pCreateParam->m_nLeft, pCreateParam->m_nTop, pCreateParam->m_nLeft + pCreateParam->m_nWidth, pCreateParam->m_nTop + pCreateParam->m_nHeight),  \
            pCreateParam->m_szCaption, pCreateParam->m_dwStyle, pCreateParam->m_dwExStyle, pCreateParam->m_nID, NULL)

//----------------------------------------------------------------------  相关内部宏定义

// 开始定义火山本地窗口类的事件映射表
//   skip_focus_msg: 是否跳过 WM_SETFOCUS 和 WM_KILLFOCUS 消息,此时改由本地窗口类本身来手动发送(因为某些组件譬如编辑框有自己的通知EN_SETFOCUS/EN_KILLFOCUS).
// 用户必须实现OnConstruct方法和CreateControl方法:
#define BEGIN_VOL_MSG_MAP(skip_focus_msg)  \
	    BOOL m_bMsgHandled;  /* "handled" management for cracked handlers */                                                                         \
	    inline_ BOOL IsMsgHandled () const  { return m_bMsgHandled; }                                                                                \
	    inline_ void SetMsgHandled (BOOL bHandled)  { m_bMsgHandled = bHandled; }                                                                    \
	    BOOL ProcessWindowMessage (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lResult, DWORD dwMsgMapID = 0)                       \
	    {                                                                                                                                            \
		    return VolProcessWindowMessage (TRUE, hWnd, uMsg, wParam, lParam, lResult, dwMsgMapID);                                                  \
	    }                                                                                                                                            \
	    BOOL VolProcessWindowMessage (BOOL blProcessNativeMessage, HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lResult, DWORD dwMsgMapID = 0)  \
	    {                                                                                                                                            \
		    BOOL bOldMsgHandled = m_bMsgHandled;                                                                                                     \
		    const BOOL bHandled = _ProcessWindowMessage (blProcessNativeMessage, hWnd, uMsg, wParam, lParam, lResult, dwMsgMapID);                   \
		    m_bMsgHandled = bOldMsgHandled;                                                                                                          \
		    return bHandled;                                                                                                                         \
	    }                                                                                                                                            \
	    BOOL _ProcessWindowMessage (BOOL blProcessNativeMessage, HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lResult, DWORD dwMsgMapID)  \
	    {                                                                                                                                            \
            if (hWnd == m_hWnd)                                                                                                                      \
            {                                                                                                                                        \
                if (ProcessVolSysMessage (hWnd, uMsg, wParam, lParam, lResult, (void*)this, sGetVolClassName (), &m_nGroupNumber, &m_dwControlState, m_filters) ||      \
                        (blProcessNativeMessage && ProcessNativeMessage (hWnd, uMsg, wParam, lParam, lResult, skip_focus_msg, m_pEventListener)))    \
                    return TRUE;                                                                                                                     \
            }                                                                                                                                        \
		    BOOL bHandled = TRUE;                                                                                                                    \
		    switch (dwMsgMapID)                                                                                                                      \
		    {                                                                                                                                        \
		    case 0:

// 仅在基础类也为WTL火山组件类时调用其消息处理函数使用,避免发送多份本地消息. 如果基础类不为WTL火山组件类,请使用CHAIN_MSG_MAP.
#define BASE_CONTROL_CHAIN_MSG_MAP(theChainClass) \
        {                                                                                            \
            if(theChainClass::VolProcessWindowMessage (FALSE, hWnd, uMsg, wParam, lParam, lResult))  \
                return TRUE;                                                                         \
	    }

// 结束定义火山本地窗口类的事件映射表,当前组件必定不为容器类组件.
#define END_VOL_MSG_MAP_NOT_CONTAINER()  \
                DEFAULT_REFLECTION_HANDLER ()  \
                break;                         \
		    DEFAULT_FAIL                       \
		    }                                  \
		    return FALSE;                      \
	    }

// 结束定义火山本地窗口类的事件映射表,当前组件可能为容器类组件.
#define END_VOL_MSG_MAP_MAYBE_CONTAINER()  \
        REFLECT_NOTIFICATIONS_EX ()  \
        END_VOL_MSG_MAP_NOT_CONTAINER ()

//----------------------------------------------------------------------  相关公开宏定义

// nCtlType:
//   CTLCOLOR_MSGBOX     0
//   CTLCOLOR_EDIT       1
//   CTLCOLOR_LISTBOX    2
//   CTLCOLOR_BTN        3
//   CTLCOLOR_DLG        4
//   CTLCOLOR_SCROLLBAR  5
//   CTLCOLOR_STATIC     6
// HBRUSH OnReflectedCtlColor(CDCHandle dc, CWindow wnd, INT nCtlType)
#define MSG_OCM_CTLCOLOR(func)  \
    if (uMsg >= OCM_CTLCOLORMSGBOX && uMsg <= OCM_CTLCOLORSTATIC)  \
    {                                                              \
        this->SetMsgHandled (TRUE);                                \
        lResult = (LRESULT)func ((HDC)wParam, (HWND)lParam, (INT)(uMsg - OCM_CTLCOLORMSGBOX));  \
        if (this->IsMsgHandled ())                                 \
            return TRUE;                                           \
    }

#define MAKE_VOL_UI_CLASS_NAME(name)  _T (#name)

// 火山本地窗口类声明宏
//   class_name: 当前窗口类名
// CreateControl方法: 用作创建所对应的窗口本地组件对象,返回是否成功.
//   原型为: BOOL CreateControl (CVolNativeWndCreateParam* pCreateParam)
//   pCreateParam: 具体创建参数,其中的内容可以被修改.
#define BEGIN_DECLARE_VOL_NATIVE_WND_CLASS_WITHOUT_EVENT_LISTENER(class_name, skip_focus_msg)  \
    public:  \
        inline_ static const TCHAR* sGetVolClassName ()  { return MAKE_VOL_UI_CLASS_NAME (class_name); }  \
        BOOL CreateControl (CVolNativeWndCreateParam* pCreateParam);  \
        BEGIN_VOL_MSG_MAP (skip_focus_msg)

//   event_listener_interface: 其事件监听接口类名,必须直接或间接继承了IBaseEventListener.
#define BEGIN_DECLARE_VOL_NATIVE_WND_CLASS(class_name, event_listener_interface, skip_focus_msg)  \
    public:  \
        event_listener_interface* m_pEventListener = NULL;  \
        INT m_nGroupNumber = -1;                            \
        DWORD m_dwControlState = 0;                         \
        CVolWindowProcFilters m_filters;                    \
        BEGIN_DECLARE_VOL_NATIVE_WND_CLASS_WITHOUT_EVENT_LISTENER (class_name, skip_focus_msg)

// 结束定义火山本地窗口类,当前组件必定不为容器类组件.
#define END_DECLARE_VOL_NATIVE_WND_CLASS_NOT_CONTAINER()  END_VOL_MSG_MAP_NOT_CONTAINER()

// 结束定义火山本地窗口类,当前组件可能为容器类组件.
#define END_DECLARE_VOL_NATIVE_WND_CLASS_MAYBE_CONTAINER()  END_VOL_MSG_MAP_MAYBE_CONTAINER()

//----------------------------------------------------------------------  用作保存WTL窗口对象的类

class CWtlWndObject : public CRefObject
{
    DECLARE_DERIVED_CLASS (CWtlWndObject)

protected:
    inline_ CWtlWndObject (CWindow* pWnd) :
            m_pWnd (pWnd)
    {
        ASSERT (pWnd != NULL);

        m_dwAttrInitialStyle = (WS_VISIBLE | WS_CLIPSIBLINGS);
        m_dwAttrInitialExStyle = 0;
        m_hAttrCustomCursur = NULL;
        m_hFont = NULL;
    }

    virtual ~CWtlWndObject ()
    {
        if (m_hFont != NULL)
            ::DeleteObject (m_hFont);
    }

    virtual void OnBeforeDestory () override
    {
        DestroyWtlWindow ();
    }

public:
    virtual void* GetRefControlPtr () const = 0;

    inline_ void* GetRefControlPtrWithValidHWnd () const
    {
        return (m_pWnd->m_hWnd == NULL ? NULL : GetRefControlPtr ());
    }

    inline_ HWND GetRefWndHandle () const
    {
        return m_pWnd->m_hWnd;
    }

    HFONT CheckGetFont ();  // 检查获取字体句柄值,如果当前未设置字体句柄,则返回默认GUI字体.

protected:
    inline_ void DestroyWtlWindow ()
    {
        if (m_pWnd->m_hWnd != NULL)
        {
            if (::IsWindow (m_pWnd->m_hWnd))
                m_pWnd->DestroyWindow ();
            m_pWnd->m_hWnd = NULL;
        }
    }

public:
    // 用作在本窗口组件尚未创建时记录相关支持在所处组件创建前设置的属性值:
    CVolString m_strAttrCaption;  // 组件标题
    DWORD m_dwAttrInitialStyle, m_dwAttrInitialExStyle;  // 指定相关初始风格
    HCURSOR m_hAttrCustomCursur;  // 所使用的鼠标指针句柄,为NULL表示使用标准鼠标指针.
    HFONT m_hFont;  // 所使用的字体,为NULL表示使用默认字体.

private:
    CWindow* const m_pWnd;  // 记录对应的WTL窗口对象指针,必定不为NULL.
};

template<class T>
class CWtlWndObjectImpl : public CWtlWndObject
{
public:
    inline_ CWtlWndObjectImpl (T* pControl) :
            CWtlWndObject (pControl),
            m_pControl (pControl)
    {
    }

    virtual ~CWtlWndObjectImpl ()
    {
        DestroyWtlWindow ();

        if (m_pControl != NULL)
            delete m_pControl;
    }

    virtual void* GetRefControlPtr () const override
    {
        return (void*)m_pControl;
    }

private:
    T* const m_pControl;
};

//----------------------------------------------------------------------  相关事件监听接口

// 所有事件监听接口的基础类
class IBaseEventListener
{
public:
    // 用作预先处理本地窗口的消息,返回真表示该消息已经被处理且不再需要继续向后传递,返回假表示该消息未被处理.
    virtual BOOL OnNativeWndMsg (MSG* pMsg) = 0;
};

// 发送本地窗口消息到IBaseEventListener的OnNativeWndMsg接口方法
//   pMsg: 所欲处理的消息,必定不为NULL.
//   pEventListener: 所欲发送到的接口对象,如无则为NULL.
//   blpSkipFocusMessage: 是否跳过WM_SETFOCUS和WM_KILLFOCUS消息.
// 返回真表示消息已经被成功处理且不需要后续处理
BOOL_P SendNativeMessage (MSG* pMsg, IBaseEventListener* pEventListener);
BOOL_P SendNativeMessage (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, IBaseEventListener* pEventListener);
BOOL_P SendNativeMessage (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, IBaseEventListener* pEventListener, const BOOL_P blpSkipFocusMessage);

BOOL_P ProcessVolSysMessage (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lResult,
        void* pWndObject, const TCHAR* szClassName, INT* pnGroupNumber, DWORD* pdwControlState, CVolWindowProcFilters& filters);
BOOL_P ProcessNativeMessage (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lResult,
        const BOOL_P blpSkipFocusMessage, IBaseEventListener* pEventListener);

// 发送WM_SETFOCUS本地窗口消息到IBaseEventListener的OnNativeWndMsg接口方法
inline_ BOOL_P SendSetFocusNativeMessage (const HWND hThisWnd, IBaseEventListener* pEventListener)
{
    return SendNativeMessage (hThisWnd, WM_SETFOCUS, 0, 0, pEventListener);
}

// 发送WM_KILLFOCUS本地窗口消息到IBaseEventListener的OnNativeWndMsg接口方法
inline_ BOOL_P SendKillFocusNativeMessage (const HWND hThisWnd, IBaseEventListener* pEventListener)
{
    return SendNativeMessage (hThisWnd, WM_KILLFOCUS, 0, 0, pEventListener);
}

//----------------------------------------------------------------------

class CVolDummyWnd : public CWindowImpl<CVolDummyWnd>
{
public:
    BEGIN_MSG_MAP_EX (CVolDummyWnd)
    #ifdef _VOL_FOR_UI_DESIGNER  // 为编译布局设计器专用版本?
        MSG_WM_PAINT (OnPaint)
    #endif
    END_MSG_MAP_EX ()

#ifdef _VOL_FOR_UI_DESIGNER  // 为编译布局设计器专用版本?
    inline_ CVolDummyWnd ()
    {
        m_uIDMarkBitmap = 0;
    }
#endif

    BOOL CreateDummyControl (CVolNativeWndCreateParam* pCreateParam);

#ifdef _VOL_FOR_UI_DESIGNER  // 为编译布局设计器专用版本?
protected:
    void OnPaint (HDC hNotUsed);

    UINT m_uIDMarkBitmap;
#endif
};

//----------------------------------------------------------------------

#include "tr_wtl_ui_res.h"
#include "wtl_ui_functions.h"

#endif
