#ifndef _KILIB_WINDOW_H_
#define _KILIB_WINDOW_H_
#include "types.h"
#include "memory.h"
#include "ktlaptr.h"
#ifndef __ccdoc__
namespace ki {
#endif
// タイムアウト付きMsgBoxの返値
#define IDTIMEOUT 0
//=========================================================================
//@{ @pkg ki.Window //@}
//@{
// 窓操作用クラス
//
// 外側から、ダイアログやコントロールやプロパティシートや
// 普通のウインドウを全部まとめて共通に扱うためのインターフェイス。
// 実際の実装は、下位クラス XxxImpl で行われている。
//@}
//=========================================================================
class Window : public Object
{
public:
//@{ メインメッセージループ //@}
void MsgLoop();
//@{ メッセージを送って処理されるまで待機 //@}
LRESULT SendMsg( UINT msg, WPARAM wp=0, LPARAM lp=0 );
//@{ メッセージを送ってすぐ帰る //@}
BOOL PostMsg( UINT msg, WPARAM wp=0, LPARAM lp=0 );
//@{
// 自動消滅機能付きメッセージボックス
// @param msg 表示する文字列
// @param caption ダイアログの題名
// @param type Win32SDKの説明を見てね
//@}
int MsgBox( LPCTSTR msg, LPCTSTR caption=NULL, UINT type=MB_OK ) const;
//@{ テキスト設定 //@}
void SetText( const TCHAR* str );
//@{ 表示 //@}
void ShowUp( int sw=SW_SHOW );
//@{ 移動 //@}
void MoveTo( int l, int t, int r, int b );
//@{ フォーカス //@}
void SetFocus();
//@{ 最前面へGo! //@}
void SetFront();
//@{ 画面中央へGo! //@}
void SetCenter();
public:
//@{ ウインドウハンドル //@}
HWND hwnd() const;
//@{ 位置・サイズ //@}
void getPos( RECT* rc ) const;
//@{ サイズ //@}
void getClientRect( RECT* rc ) const;
//@{ メインループを回してるウインドウかどうか //@}
bool isMainWnd() const;
//@{ 生きてる? //@}
bool isAlive() const;
public:
//@{ 未処理メッセージを適当に処理 //@}
static void ProcessMsg();
//@{ 最前面へGo! //@}
static void SetFront( HWND hwnd );
//@{
// 画面中央へGo!
// @param hwnd 動かすウインドウ
// @param rel 基準にするウインドウ
//@}
static void SetCenter( HWND hwnd, HWND rel=NULL );
protected:
// 何もしないコンストラクタ
Window();
// Hwndをセット
void SetHwnd( HWND wnd );
// アクセラレータを通すとかダイアログメッセージの処理とか
virtual bool PreTranslateMessage( MSG* ) = 0;
private:
HWND wnd_;
bool isLooping_;
private:
NOCOPY(Window);
};
//-------------------------------------------------------------------------
#ifndef __ccdoc__
inline LRESULT Window::SendMsg( UINT msg, WPARAM wp, LPARAM lp )
{ return ::SendMessage( wnd_, msg, wp, lp ); }
inline BOOL Window::PostMsg( UINT msg, WPARAM wp, LPARAM lp )
{ return ::PostMessage( wnd_, msg, wp, lp ); }
inline int Window::MsgBox( LPCTSTR m, LPCTSTR c, UINT y ) const
{ return ::MessageBox( wnd_, m, c, y ); }
inline void Window::ShowUp( int sw )
{ ::ShowWindow( wnd_, sw ), ::UpdateWindow( wnd_ ); }
inline void Window::SetText( const TCHAR* str )
{ ::SetWindowText( wnd_, str ); }
inline void Window::MoveTo( int l, int t, int r, int b )
{ ::MoveWindow( wnd_, l, t, r-l, b-t, TRUE ); }
inline void Window::SetFocus()
{ ::SetFocus( wnd_ ); }
inline void Window::SetFront()
{ SetFront( wnd_ ); }
inline void Window::SetCenter()
{ SetCenter( wnd_ ); }
inline HWND Window::hwnd() const
{ return wnd_; }
inline bool Window::isMainWnd() const
{ return isLooping_; }
inline void Window::getPos( RECT* rc ) const
{ ::GetWindowRect( wnd_, rc ); }
inline void Window::getClientRect( RECT* rc ) const
{ ::GetClientRect( wnd_, rc ); }
inline bool Window::isAlive() const
{ return FALSE != ::IsWindow( wnd_ ); }
#endif // __ccdoc__
//=========================================================================
//@{
// IME制御マネージャ
//
// Global IME をサポートするには、ウインドウメッセージの処理を
// 根本的に入れ替える必要がある。そこで、処理をこのクラスにまとめ
// Windowクラスと連携処理を行うことで、ライブラリの外からは一切
// 気にせず処理をできるようにしておく。なお、Global IMEに対応
// するにはバージョンの新しいPlatform SDKが必要なため
// マクロ USEGLOBALIME が定義されていなければその辺は処理しない。
//@}
//=========================================================================
class IMEManager
{
public:
//@{ フォント指定 //@}
void SetFont( HWND wnd, const LOGFONT& lf );
//@{ 位置指定 //@}
void SetPos( HWND wnd, int x, int y );
//@{ 確定文字列ゲット。受け取ったら delete すること。 //@}
void GetString( HWND wnd, unicode** str, ulong* len );
//@{ GlobalIMEを利用可能状態にする //@}
void EnableGlobalIME( bool enable );
//@{ GlobalIMEを使えるWindowのリストを登録 //@}
void FilterWindows( ATOM* lst, UINT siz );
private:
IMEManager();
~IMEManager();
void TranslateMsg( MSG* msg );
LRESULT DefProc( HWND wnd, UINT msg, WPARAM wp, LPARAM lp );
void MsgLoopBegin();
void MsgLoopEnd();
private:
#ifdef USEGLOBALIME
IActiveIMMApp* immApp_;
IActiveIMMMessagePumpOwner* immMsg_;
#endif
static IMEManager* pUniqueInstance_;
private:
friend class Window;
friend class WndImpl;
friend void APIENTRY Startup();
friend inline IMEManager& ime();
NOCOPY(IMEManager);
};
//-------------------------------------------------------------------------
//@{ 唯一のIME管理オブジェクトを返す //@}
inline IMEManager& ime()
{ return *IMEManager::pUniqueInstance_; }
//=========================================================================
//@{
// 普通のウインドウ実装
//
// 派生クラスを定義して、コンストラクタの引数で WndImpl に
// WNDCLASS名やスタイルを渡し、初回なら WNDCLASS を Register
// して、あとは適当なタイミングで Create() という使い方を想定。
//
// HWNDからWndImpl*への変換はx86/x86-64専用のサンクで行っています。
// ので、他のアーキテクチャではこのままでは動作しません。移植
// する場合は、GWL_USERDATA を使うなり clsExtra に入れるなりで
// もう少し汎用性のある方法に適宜変えてください。
//@}
//=========================================================================
class WndImpl : public Window
{
enum { THUNK_SIZE = 22 };
public:
//@{ ウインドウ作成 //@}
bool Create( LPCTSTR wndName=NULL, HWND parent=NULL,
int x =CW_USEDEFAULT, int y =CW_USEDEFAULT,
int width =CW_USEDEFAULT, int height =CW_USEDEFAULT,
void* param=NULL );
//@{ ウインドウ破棄 //@}
void Destroy();
protected:
//@{
// コンストラクタ
// @param className ウインドウクラス名
// @param style 標準スタイル
// @param styleEx 標準拡張スタイル
//@}
WndImpl( LPCTSTR className, DWORD style, DWORD styleEx=0 );
~WndImpl();
//@{ クラス名用の型 //@}
typedef const TCHAR* const ClsName;
//@{ ウインドウクラス登録 //@}
static ATOM Register( WNDCLASSEX* cls );
// てけとーに実装して反応してください。
// on_commandは、処理しなかったらfalseを返すこと。
// on_messageは、処理しなかったらWndImpl::on_messageを呼び出すこと。
// PreTranslateMessageは、処理してもしなくても中で呼び出すこと。
virtual void on_create( CREATESTRUCT* cs );
virtual void on_destroy();
virtual bool on_command( UINT id, HWND ctrl );
virtual LRESULT on_message( UINT msg, WPARAM wp, LPARAM lp );
virtual bool PreTranslateMessage( MSG* msg );
private:
static LRESULT CALLBACK StartProc( HWND, UINT, WPARAM, LPARAM );
static LRESULT CALLBACK MainProc( WndImpl*, UINT, WPARAM, LPARAM );
void SetUpThunk( HWND wnd );
private:
LPCTSTR className_;
const DWORD style_, styleEx_;
byte* thunk_;
};
//=========================================================================
//@{
// ダイアログ実装
//
// 派生クラスを定義して、コンストラクタの引数で DlgImpl に
// リソースIDを渡し、後は適当なタイミングで GoModal なり
// Modeless なり、という使い方を想定。
//
// HWNDからDlgImpl*への変換は GWL_USERDATA で行っています。
// ので、それは使わないようにしましょう。
//@}
//=========================================================================
class DlgImpl : public Window
{
public:
enum dlgtype { MODAL, MODELESS };
//@{ モーダルで実行 //@}
void GoModal( HWND parent=NULL );
//@{ モードレスで作成 //@}
void GoModeless( HWND parent=NULL );
//@{ 強制的に終わらせる //@}
void End( UINT code );
public:
//@{ モーダルかモードレスか //@}
dlgtype type() const;
//@{ 終了コード取得 //@}
UINT endcode() const;
protected:
//@{ コンストラクタ //@}
DlgImpl( UINT id );
~DlgImpl();
//@{ 子アイテムID→HWND変換 //@}
HWND item( UINT id ) const;
//@{ アイテムに対してメッセージ送信 //@}
LRESULT SendMsgToItem( UINT id, UINT msg, WPARAM wp=0, LPARAM lp=0 );
//@{ アイテムに対してメッセージ送信(ポインタ送る版) //@}
LRESULT SendMsgToItem( UINT id, UINT msg, void* lp );
//@{ アイテムに対してメッセージ送信(文字列送る版) //@}
LRESULT SendMsgToItem( UINT id, UINT msg, const TCHAR* lp );
// てけとーに実装して反応してください。
// on_ok/on_cancelは、終了して良いならtrueを返すこと。
// on_cmd/on_msgは、処理済みならtrueを返すこと。
virtual void on_init();
virtual void on_destroy();
virtual bool on_ok();
virtual bool on_cancel();
virtual bool on_command( UINT cmd, UINT id, HWND ctrl );
virtual bool on_message( UINT msg, WPARAM wp, LPARAM lp );
virtual bool PreTranslateMessage( MSG* msg );
private:
static BOOL CALLBACK MainProc( HWND, UINT, WPARAM, LPARAM );
private:
dlgtype type_;
UINT endCode_;
const UINT rsrcID_;
};
//-------------------------------------------------------------------------
#ifndef __ccdoc__
inline DlgImpl::dlgtype DlgImpl::type() const
{ return type_; }
inline UINT DlgImpl::endcode() const
{ return endCode_; }
inline HWND DlgImpl::item( UINT id ) const
{ return ::GetDlgItem( hwnd(), id ); }
inline LRESULT DlgImpl::SendMsgToItem
( UINT id, UINT msg, WPARAM wp, LPARAM lp )
{ return ::SendDlgItemMessage( hwnd(), id, msg, wp, lp ); }
inline LRESULT DlgImpl::SendMsgToItem( UINT id, UINT msg, void* lp )
{ return ::SendDlgItemMessage( hwnd(), id, msg, 0,
reinterpret_cast<LPARAM>(lp) ); }
inline LRESULT DlgImpl::SendMsgToItem( UINT id, UINT msg, const TCHAR* lp )
{ return ::SendDlgItemMessage( hwnd(), id, msg, 0,
reinterpret_cast<LPARAM>(lp) ); }
//=========================================================================
#endif // __ccdoc__
} // namespace ki
#endif // _KILIB_WINDOW_H_