No.004 - 03 自前ドッキング・ツールバー クラス化 (ドッキング・システム) |
自前ドッキング・ツールバーの作成はCのままではつらいので、少しC++に移行します。 |
以下ドッキングツールバーを一式クラス化して、メインウィンドウの負担を軽くしています。 DOCK_SYSクラス内でドッキング・フローティング処理を一括しています。 メインウィンドウはDOCK_SYSクラスをひとつ保持しておいてWM_NCACTIVATE と WM_SIZE で所定の処理をするだけです。 メインウィンドウ と ビューウィンドウ のプロシージャとかはソース下の方で C のままのカタチで残してあります。 |
|
|
|
・ドッキングシステム |
|
前回のDOCK_STRUCT構造体を元にDOCK_SYSという特殊なクラスを作っています。 メインウィンドウはDOCK_SYSクラスをひとつ保持しておいて、ドッキング関連の処理をDOCK_SYSクラスに丸投げする仕組みです。 DOCK_SYSクラスはDOCK_CONTEXTクラスをひとつ持ちドラッグ中の処理はDOCK_CONTEXTクラス内でします。 |
docking_test_03.cpp |
#define _WIN32_IE 0x0501 #include <windows.h> #include <commctrl.h> TBBUTTON tool_bar_buttons[] = { { STD_FILENEW, 1, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0 }, { STD_FILEOPEN, 2, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0 }, { STD_FILESAVE, 3, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0 }, { 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0 }, { STD_COPY, 4, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0 }, { STD_CUT, 5, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0 }, { STD_DELETE, 6, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0 }, { 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0 }, { VIEW_NEWFOLDER, 7, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0 }, { VIEW_PARENTFOLDER, 8, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0 }, }; // ドック・コンテキスト・構造体 class DOCK_CONTEXT { public: HRGN m_apply_rgn, m_work_rgn, m_work_rgn2, m_last_rgn; // リージョン HDC m_desk_hdc; // デスクトップDC int m_now_dragging; // ドラッグ中なら==1 そうでないなら==0 SIZE m_drag_size; // ドラッグ中の矩形サイズ POINT m_cursor_offset; // ドラッグ中の矩形位置のマウス位置との差分 HBRUSH m_desk_old_brush; // デスクトップDC・ブラシ HBRUSH m_half_tone_brush; // ハーフトーン・ブラシ DOCK_CONTEXT(); // コンストラクタ ~DOCK_CONTEXT(); // デストラクタ void start_drag(HWND hwnd); // ドラッグ開始 void drag(); // ドラッグ中 void end_drag(); // ドラッグ終了 }; // ドッキング・ツールバー統括クラス class DOCK_SYS { public: HWND m_main_frame, m_popup_frame, m_htool_bar, m_htool_bar_frame, m_hview, m_hdock_bar; // 各HWND int m_now_nc_activing; // WM_NCACTIVATEフラグ WM_NCACTIVATEの多重再送を防ぐ int m_floating_flag; // フローティング・フラグ 浮いてれば==1 そうでないなら==0 DOCK_CONTEXT m_dock_context; // ドック・コンテキスト・構造体 regist_winc(char *caption, HBRUSH hbr_bg, WNDPROC proc); // ウィンドウクラス登録 create(HWND main_hwnd, HWND child_view_hwnd); // 生成 void on_ncactivate(HWND hwnd, WPARAM wp); // WM_NCACTIVATE 処理 void do_dock(); // ドッキング実行 void do_float(int x, int y); // フローティング実行 void recalc_layout(); // 子ウィンドウ位置再計算 void tool_on_lbuttondown(HWND hwnd); // ツールバー・マウス左ボタン押下 void tool_on_lbuttonup(); // ツールバー・マウス左ボタン押上 void tool_on_mousemove(); // ツールバー・マウス移動 // ポップアップ・フレーム・プロシージャ PopupProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp); static LRESULT CALLBACK StaticPopupProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp); // ツールバー・プロシージャ ToolBarFrameProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp); static LRESULT CALLBACK StaticToolBarFrameProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp); } ; // コンストラクタ DOCK_CONTEXT::DOCK_CONTEXT(){ WORD gray_pattern[8]; HBITMAP gray_bitmap; int i; m_now_dragging=0; // ハーフトーン・パレット生成 for (i=0;i<8;i++) gray_pattern[i] = (WORD)(0x5555 << (i & 1)); // 0x5555 は2bitで 01010101 01010101 gray_bitmap = CreateBitmap(8, 8, 1, 1, &gray_pattern); if (gray_bitmap != NULL) { m_half_tone_brush = ::CreatePatternBrush(gray_bitmap); DeleteObject(gray_bitmap); } } // デストラクタ DOCK_CONTEXT::~DOCK_CONTEXT(){ DeleteObject(m_half_tone_brush); // ハーフトーン・パレット破棄 } // ドラッグ開始 void DOCK_CONTEXT::start_drag(HWND hwnd){ HWND desk_hwnd; RECT rc; m_now_dragging=1; SetCapture(hwnd); // デスクトップDCを得る desk_hwnd=GetDesktopWindow(); LockWindowUpdate(desk_hwnd); m_desk_hdc= GetDCEx(desk_hwnd, NULL, DCX_WINDOW|DCX_CACHE|DCX_LOCKWINDOWUPDATE); m_desk_old_brush=(HBRUSH)SelectObject(m_desk_hdc, m_half_tone_brush); // ドラッグ・サイズとマウスとの座標差 GetWindowRect(hwnd, &rc); m_drag_size.cx = rc.right-rc.left; m_drag_size.cy = rc.bottom-rc.top; GetCursorPos(&m_cursor_offset); m_cursor_offset.x -= rc.left; m_cursor_offset.y -= rc.top; // リージョン生成 m_apply_rgn = CreateRectRgn(0, 0, 0, 0); m_work_rgn = CreateRectRgn(0, 0, 0, 0); m_work_rgn2 = CreateRectRgn(0, 0, 0, 0); m_last_rgn = CreateRectRgn(0, 0, 0, 0); } // ドラッグ中 void DOCK_CONTEXT::drag(){ POINT po; RECT rc; GetCursorPos(&po); po.x-=m_cursor_offset.x; po.y-=m_cursor_offset.y; SetRectRgn(m_work_rgn, po.x, po.y, po.x+m_drag_size.cx, po.y+m_drag_size.cy); SetRectRgn(m_work_rgn2, po.x+4, po.y+4, po.x+m_drag_size.cx-4, po.y+m_drag_size.cy-4); CombineRgn(m_apply_rgn, m_work_rgn, m_work_rgn2, RGN_XOR); CombineRgn(m_work_rgn, m_apply_rgn, m_last_rgn, RGN_XOR); // 反転による矩形描画 GetRgnBox(m_work_rgn, &rc); SelectObject(m_desk_hdc, m_work_rgn); PatBlt(m_desk_hdc, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, PATINVERT); // 最後に描画した部分保持(再反転して消去) CombineRgn(m_last_rgn, m_apply_rgn, NULL, RGN_COPY); } // ドラッグ終了 void DOCK_CONTEXT::end_drag(){ RECT rc; m_now_dragging=0; ReleaseCapture(); // 最後に描画した部分を消去(再反転してるだけ) GetRgnBox(m_apply_rgn, &rc); SelectObject(m_desk_hdc, m_apply_rgn); PatBlt(m_desk_hdc, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, PATINVERT); // リージョン破棄 DeleteObject(m_apply_rgn); DeleteObject(m_work_rgn); DeleteObject(m_work_rgn2); DeleteObject(m_last_rgn); // デスクトップDCを解放 LockWindowUpdate(NULL); if (m_desk_hdc) ReleaseDC(GetDesktopWindow(), m_desk_hdc); SelectObject(m_desk_hdc, m_desk_old_brush); } // ポップアップウィンドウ・プロシージャ(static版) LRESULT CALLBACK DOCK_SYS::StaticPopupProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) { DOCK_SYS *p_dock_sys =(DOCK_SYS*)GetWindowLong(hwnd, GWL_USERDATA); if (!p_dock_sys && (msg==WM_NCCREATE || msg==WM_CREATE)){ p_dock_sys = (DOCK_SYS*)((LPCREATESTRUCT)lp)->lpCreateParams; SetWindowLong(hwnd, GWL_USERDATA, (LONG)p_dock_sys); } if (p_dock_sys) return p_dock_sys->PopupProc(hwnd, msg, wp, lp); return DefWindowProc(hwnd, msg, wp, lp); } // ポップアップウィンドウ・プロシージャ DOCK_SYS::PopupProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) { int res; switch (msg) { case WM_NCACTIVATE: // タイトルバーのアクティブ化・非アクティブ化 on_ncactivate(hwnd, wp); break; case WM_LBUTTONDOWN: tool_on_lbuttondown(hwnd); // ドラッグ開始 break; case WM_LBUTTONUP: tool_on_lbuttonup(); // ドラッグ終了 break; case WM_MOUSEMOVE: tool_on_mousemove(); // マウス移動(ドラッグ中) break; case WM_NCHITTEST: res=DefWindowProc(hwnd, msg, wp, lp); if (res==HTCAPTION) return HTCLIENT; return res; } return DefWindowProc(hwnd, msg, wp, lp); } // ツールバーのフレームウィンドウ・プロシージャ(static版) LRESULT CALLBACK DOCK_SYS::StaticToolBarFrameProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp){ DOCK_SYS *p_dock_sys =(DOCK_SYS*)GetWindowLong(hwnd, GWL_USERDATA); if (!p_dock_sys && (msg==WM_NCCREATE || msg==WM_CREATE)){ p_dock_sys = (DOCK_SYS*)((LPCREATESTRUCT)lp)->lpCreateParams; SetWindowLong(hwnd, GWL_USERDATA, (LONG)p_dock_sys); } if (p_dock_sys) return p_dock_sys->ToolBarFrameProc(hwnd, msg, wp, lp); return DefWindowProc(hwnd, msg, wp, lp); } // ツールバーのフレームウィンドウ・プロシージャ DOCK_SYS::ToolBarFrameProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) { RECT rc, rc2; HDC hdc; PAINTSTRUCT ps; switch (msg) { case WM_CREATE: InitCommonControls(); m_htool_bar = CreateToolbarEx( hwnd, WS_CHILD | WS_VISIBLE | TBSTYLE_AUTOSIZE, 0, 6, (HINSTANCE)HINST_COMMCTRL, IDB_STD_SMALL_COLOR, tool_bar_buttons, 7, 0, 0, 0, 0, sizeof (TBBUTTON) ); GetWindowRect(m_htool_bar, &rc); SetWindowPos(hwnd, NULL, 0,0, rc.right-rc.left, rc.bottom-rc.top, SWP_NOMOVE); break; case WM_PAINT: hdc = BeginPaint(hwnd , &ps); GetClientRect(hwnd, &rc); rc.left=0; rc.top=0; rc.bottom=1; FillRect(hdc, &rc, GetSysColorBrush(COLOR_BTNSHADOW)); rc.top++; rc.bottom++; FillRect(hdc, &rc, GetSysColorBrush(COLOR_BTNHILIGHT)); if (!m_floating_flag){ // グリッパー描画 GetClientRect(hwnd, &rc); rc.left+=2; rc.right=rc.left+3; rc.top+=1; rc.bottom-=2; rc2.left=rc.left; rc2.top=rc.top; rc2.right=rc.right-1; rc2.bottom=rc.top+1; FillRect(hdc, &rc2, GetSysColorBrush(COLOR_BTNHILIGHT)); rc2.right=rc.left+1; rc2.bottom=rc.bottom-1; FillRect(hdc, &rc2, GetSysColorBrush(COLOR_BTNHILIGHT)); rc2.left=rc.right; rc2.top=rc.top; rc2.right=rc.right-1; rc2.bottom=rc.bottom; FillRect(hdc, &rc2, GetSysColorBrush(COLOR_BTNSHADOW)); rc2.left=rc.left; rc2.top=rc.bottom; rc2.right=rc.right; rc2.bottom=rc.bottom-1; FillRect(hdc, &rc2, GetSysColorBrush(COLOR_BTNSHADOW)); } EndPaint(hwnd , &ps); break; case WM_SIZE: SendMessage(m_htool_bar, WM_SIZE, wp, lp); // ツーバーのリサイズ if (!m_floating_flag) SetWindowPos(m_htool_bar, NULL, 10,0, LOWORD(lp),HIWORD(lp), 0); break; case WM_LBUTTONDOWN: // マウス左ボタン押上(ドラッグ終了) tool_on_lbuttondown(hwnd); break; case WM_LBUTTONUP: // マウス左ボタン押上(ドラッグ開始) tool_on_lbuttonup(); break; case WM_MOUSEMOVE: // マウス移動(ドラッグ中) tool_on_mousemove(); break; } return DefWindowProc(hwnd, msg, wp, lp); } // マウス移動 void DOCK_SYS::tool_on_mousemove(){ if (!m_dock_context.m_now_dragging) return; m_dock_context.drag(); // ドラッグ中 } // マウス左ボタン押上 void DOCK_SYS::tool_on_lbuttondown(HWND hwnd){ if (m_dock_context.m_now_dragging) return; m_dock_context.start_drag(hwnd); // ドラッグ開始 } // マウス左ボタン押上 void DOCK_SYS::tool_on_lbuttonup(){ RECT drag_rc, dock_rc; if (!m_dock_context.m_now_dragging) return; m_dock_context.end_drag(); // ドラッグ終了 // ドッキング・フローティング判定 GetWindowRect(m_hdock_bar, &dock_rc); POINT po; GetCursorPos((POINT*)&po); drag_rc.left=po.x-m_dock_context.m_cursor_offset.x; drag_rc.top =po.y-m_dock_context.m_cursor_offset.y; drag_rc.right = drag_rc.left + m_dock_context.m_drag_size.cx; drag_rc.bottom= drag_rc.top + m_dock_context.m_drag_size.cy; // ドッキング判定 if (drag_rc.left<=dock_rc.right && drag_rc.right>=dock_rc.left && drag_rc.top<=dock_rc.bottom && drag_rc.bottom>=dock_rc.top){ do_dock(); } // フローティング判定 else do_float(drag_rc.left, drag_rc.top); } // ドッキングシステム生成 DOCK_SYS::create(HWND main_hwnd, HWND child_view_hwnd){ m_now_nc_activing=0; m_floating_flag=0; m_main_frame=main_hwnd; m_hview=child_view_hwnd; regist_winc(TEXT("popup_frame"), (HBRUSH)(COLOR_BTNFACE+1), StaticPopupProc); // フローティング・フレーム regist_winc(TEXT("tool_bar_frame"), (HBRUSH)(COLOR_BTNFACE+1), StaticToolBarFrameProc); // ツールバーの外枠 regist_winc(TEXT("dock_bar_frame"), (HBRUSH)(COLOR_BTNFACE+1), DefWindowProc); // ドックバー HINSTANCE hInstance=GetModuleHandle(NULL); m_popup_frame= CreateWindowEx( WS_EX_TOOLWINDOW, TEXT("popup_frame"), NULL, WS_OVERLAPPEDWINDOW | WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 300, 170, 200, 100, main_hwnd, NULL, hInstance, (LPVOID)this ); m_htool_bar_frame= CreateWindow( TEXT("tool_bar_frame"), NULL, WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0, 0, 200, 100, main_hwnd, NULL, hInstance, (LPVOID)this ); m_hdock_bar = CreateWindow( TEXT("dock_bar_frame"), NULL, WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0, 0, 200, 100, main_hwnd, NULL, hInstance, (LPVOID)this ); do_dock(); } // タイトルバーのアクティブ化・非アクティブ化 void DOCK_SYS::on_ncactivate(HWND hwnd, WPARAM wp){ if (m_now_nc_activing) return; m_now_nc_activing=1; SendMessage(m_main_frame, WM_NCACTIVATE, wp, 0); SendMessage(m_popup_frame, WM_NCACTIVATE, wp, 0); m_now_nc_activing=0; } // ドッキング void DOCK_SYS::do_dock(){ SetWindowPos(m_htool_bar_frame, NULL, 0,0, 0,0, SWP_NOSIZE); if (!m_floating_flag) return; SetParent(m_htool_bar_frame, m_hdock_bar); m_floating_flag = 0; ShowWindow(m_popup_frame, SW_HIDE); recalc_layout(); } // フローティング void DOCK_SYS::do_float(int x, int y){ SetWindowPos(m_popup_frame, NULL, x, y, 0,0, SWP_NOSIZE); if (m_floating_flag) return; SetParent(m_htool_bar_frame, m_popup_frame); m_floating_flag = 1; SetWindowPos(m_htool_bar_frame, NULL, 0,0, 0,0, SWP_NOSIZE); ShowWindow(m_popup_frame, SW_SHOW); recalc_layout(); } // レイアウト再計算 void DOCK_SYS::recalc_layout(){ if (IsIconic(m_main_frame)) return; RECT rc; SIZE tool_size; // 子ウィンドウ位置の再計算 SendMessage(m_htool_bar, TB_GETMAXSIZE, 0, (LPARAM)&tool_size); // ツールバー・サイズ取得 DWORD padding=SendMessage(m_htool_bar, TB_GETPADDING, 0, 0); tool_size.cx+=LOWORD(padding); tool_size.cy+=HIWORD(padding); GetClientRect(m_main_frame, &rc); if (!m_floating_flag) rc.top =tool_size.cy; // ビューウィンドウ位置サイズ if (IsWindow(m_hview)) SetWindowPos(m_hview, NULL, rc.left, rc.top, rc.right, rc.bottom-rc.top, 0); // ドックバー位置サイズ SetWindowPos(m_hdock_bar, NULL, 0, 0, rc.right, rc.top, 0); // ポップアップ・ウィンドウ位置サイズ if(m_floating_flag){ rc.left=rc.top=0; rc.right=tool_size.cx; rc.bottom=tool_size.cy; AdjustWindowRectEx(&rc, GetWindowLong(m_popup_frame, GWL_STYLE), FALSE, GetWindowLong(m_popup_frame, GWL_EXSTYLE)); SetWindowPos(m_popup_frame, NULL, 0, 0, rc.right-rc.left, rc.bottom-rc.top, SWP_NOMOVE); } // ツールバー横サイズ補正 GetClientRect(GetParent(m_htool_bar_frame), &rc); SetWindowPos(m_htool_bar_frame, NULL, 0, 0, rc.right, tool_size.cy, 0); } // ウィンドウクラス登録 DOCK_SYS::regist_winc(char *caption, HBRUSH hbr_bg, WNDPROC proc){ WNDCLASS winc; winc.style = CS_HREDRAW | CS_VREDRAW; winc.lpfnWndProc = proc; winc.cbClsExtra = winc.cbWndExtra = 0; winc.hInstance = GetModuleHandle(NULL); winc.hIcon = LoadIcon(NULL, IDI_APPLICATION); winc.hCursor = LoadCursor(NULL, IDC_ARROW); winc.hbrBackground = hbr_bg; winc.lpszMenuName = NULL; winc.lpszClassName = caption; if (!RegisterClass(&winc)) return -1; return 0; } //====================================================================================== //============ 以下 メインウィンドウ ・ ビューウィンドウ ============================== //====================================================================================== // ビューウィンドウ・プロシージャ LRESULT CALLBACK ChildViewProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) { HDC hdc; PAINTSTRUCT ps; char str[]="ChildViewウィンドウ(座標0,0)"; switch (msg) { case WM_LBUTTONDOWN: SendMessage(GetParent(hwnd), WM_LBUTTONDOWN, wp, lp); break; case WM_PAINT: hdc = BeginPaint(hwnd , &ps); TextOut(hdc, 0, 0, str, lstrlen(str)); EndPaint(hwnd , &ps); break; } return DefWindowProc(hwnd, msg, wp, lp); } // メインウィンドウ・プロシージャ LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) { static DOCK_SYS dock_sys; // ウィンドウ・ハンドルの一括化 構造体 static HWND hview; switch (msg) { case WM_CREATE: hview= CreateWindowEx( WS_EX_TOOLWINDOW, TEXT("child_view"), NULL, WS_CHILD | WS_VISIBLE, 0, 0, 200, 100, hwnd, NULL, ((LPCREATESTRUCT)(lp))->hInstance, NULL ); dock_sys.create(hwnd, hview); break; case WM_DESTROY: PostQuitMessage(0); break; case WM_NCACTIVATE: // タイトルバーのアクティブ化・非アクティブ化 dock_sys.on_ncactivate(hwnd, wp); break; case WM_SIZE: dock_sys.recalc_layout(); break; } return DefWindowProc(hwnd, msg, wp, lp); } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR lpCmdLine, int nCmdShow ) { MSG msg; WNDCLASS winc; HWND hwnd; winc.style = CS_HREDRAW | CS_VREDRAW; winc.lpfnWndProc = WndProc; winc.cbClsExtra = winc.cbWndExtra = 0; winc.hInstance = hInstance; winc.hIcon = LoadIcon(NULL, IDI_APPLICATION); winc.hCursor = LoadCursor(NULL, IDC_ARROW); winc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); winc.lpszMenuName = NULL; winc.lpszClassName = TEXT("main_frame"); if (!RegisterClass(&winc)) return -1; // メイン・ウィンドウ winc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); winc.lpfnWndProc = ChildViewProc; winc.lpszClassName = TEXT("child_view"); if (!RegisterClass(&winc)) return -1; // ビューウィンドウ hwnd = CreateWindow( TEXT("main_frame"), TEXT("ドッキング・ツールバーのテスト"), WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN, 100, 100, 240, 200, NULL, NULL, hInstance, NULL ); if (hwnd == NULL) return -1; while(GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } |
上記のソースはツールバーもドックバーもごちゃまぜなので
もうちょっとクラス化して下記でTOOL_BARクラスとDOCK_BARクラスを作っています。
動作は全く同じです。
docking_test3_2.cpp |
#define _WIN32_IE 0x0501 #include <windows.h> #include <commctrl.h> // ドック・コンテキスト・構造体 class DOCK_CONTEXT { public: HRGN m_apply_rgn, m_work_rgn, m_work_rgn2, m_last_rgn; // リージョン HDC m_desk_hdc; // デスクトップDC int m_now_dragging; // ドラッグ中なら==1 そうでないなら==0 SIZE m_drag_size; // ドラッグ中の矩形サイズ POINT m_cursor_offset; // ドラッグ中の矩形位置のマウス位置との差分 HBRUSH m_desk_old_brush; // デスクトップDC・ブラシ HBRUSH m_half_tone_brush; // ハーフトーン・ブラシ DOCK_CONTEXT(); // コンストラクタ ~DOCK_CONTEXT(); // デストラクタ void start_drag(HWND hwnd); // ドラッグ開始 void drag(); // ドラッグ中 void end_drag(); // ドラッグ終了 }; // クラスの仮宣言 class DOCK_SYS; // ツールバークラス class TOOL_BAR { public: HWND m_hwnd, m_control_tool_bar, m_popup_frame; // 各HWND DOCK_SYS *m_p_dock_sys; // ドッキング・ツールバー統括クラス・ポインタ int m_floating_flag; // フローティング・フラグ 浮いてれば==1 そうでないなら==0 create(DOCK_SYS *p_dock_sys, TBBUTTON *tb_buttons, int tb_button_len); // ツールバー生成 // ポップアップ・フレーム・プロシージャ PopupProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp); static LRESULT CALLBACK StaticPopupProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp); // ツールバー・プロシージャ ToolBarFrameProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp); static LRESULT CALLBACK StaticToolBarFrameProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp); }; // ドックバークラス class DOCK_BAR { public: HWND m_hwnd; }; // ドッキング・ツールバー統括クラス class DOCK_SYS { public: HWND m_main_frame, m_hview; // 各HWND int m_now_nc_activing; // WM_NCACTIVATEフラグ WM_NCACTIVATEの多重再送を防ぐ DOCK_CONTEXT m_dock_context; // ドック・コンテキスト・構造体 DOCK_BAR m_dock_bar; // ドックバークラス TOOL_BAR m_tool_bar; // ツールバークラス regist_winc(char *caption, HBRUSH hbr_bg, WNDPROC proc); // ウィンドウクラス登録 create(HWND main_hwnd, HWND child_view_hwnd); // 生成 void on_ncactivate(HWND hwnd, WPARAM wp); // WM_NCACTIVATE 処理 void do_dock(); // ドッキング実行 void do_float(int x, int y); // フローティング実行 void recalc_layout(); // 子ウィンドウ位置再計算 void tool_on_lbuttondown(HWND hwnd); // ツールバー・マウス左ボタン押下 void tool_on_lbuttonup(); // ツールバー・マウス左ボタン押上 void tool_on_mousemove(); // ツールバー・マウス移動 } ; // コンストラクタ DOCK_CONTEXT::DOCK_CONTEXT(){ WORD gray_pattern[8]; HBITMAP gray_bitmap; int i; m_now_dragging=0; // ハーフトーン・パレット生成 for (i=0;i<8;i++) gray_pattern[i] = (WORD)(0x5555 << (i & 1)); // 0x5555 は2bitで 01010101 01010101 gray_bitmap = CreateBitmap(8, 8, 1, 1, &gray_pattern); if (gray_bitmap != NULL) { m_half_tone_brush = ::CreatePatternBrush(gray_bitmap); DeleteObject(gray_bitmap); } } // デストラクタ DOCK_CONTEXT::~DOCK_CONTEXT(){ DeleteObject(m_half_tone_brush); // ハーフトーン・パレット破棄 } // ドラッグ開始 void DOCK_CONTEXT::start_drag(HWND hwnd){ HWND desk_hwnd; RECT rc; m_now_dragging=1; SetCapture(hwnd); // デスクトップDCを得る desk_hwnd=GetDesktopWindow(); LockWindowUpdate(desk_hwnd); m_desk_hdc= GetDCEx(desk_hwnd, NULL, DCX_WINDOW|DCX_CACHE|DCX_LOCKWINDOWUPDATE); m_desk_old_brush=(HBRUSH)SelectObject(m_desk_hdc, m_half_tone_brush); // ドラッグ・サイズとマウスとの座標差 GetWindowRect(hwnd, &rc); m_drag_size.cx = rc.right-rc.left; m_drag_size.cy = rc.bottom-rc.top; GetCursorPos(&m_cursor_offset); m_cursor_offset.x -= rc.left; m_cursor_offset.y -= rc.top; // リージョン生成 m_apply_rgn = CreateRectRgn(0, 0, 0, 0); m_work_rgn = CreateRectRgn(0, 0, 0, 0); m_work_rgn2 = CreateRectRgn(0, 0, 0, 0); m_last_rgn = CreateRectRgn(0, 0, 0, 0); } // ドラッグ中 void DOCK_CONTEXT::drag(){ POINT po; RECT rc; GetCursorPos(&po); po.x-=m_cursor_offset.x; po.y-=m_cursor_offset.y; SetRectRgn(m_work_rgn, po.x, po.y, po.x+m_drag_size.cx, po.y+m_drag_size.cy); SetRectRgn(m_work_rgn2, po.x+4, po.y+4, po.x+m_drag_size.cx-4, po.y+m_drag_size.cy-4); CombineRgn(m_apply_rgn, m_work_rgn, m_work_rgn2, RGN_XOR); CombineRgn(m_work_rgn, m_apply_rgn, m_last_rgn, RGN_XOR); // 反転による矩形描画 GetRgnBox(m_work_rgn, &rc); SelectObject(m_desk_hdc, m_work_rgn); PatBlt(m_desk_hdc, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, PATINVERT); // 最後に描画した部分保持(再反転して消去) CombineRgn(m_last_rgn, m_apply_rgn, NULL, RGN_COPY); } // ドラッグ終了 void DOCK_CONTEXT::end_drag(){ RECT rc; m_now_dragging=0; ReleaseCapture(); // 最後に描画した部分を消去(再反転してるだけ) GetRgnBox(m_apply_rgn, &rc); SelectObject(m_desk_hdc, m_apply_rgn); PatBlt(m_desk_hdc, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, PATINVERT); // リージョン破棄 DeleteObject(m_apply_rgn); DeleteObject(m_work_rgn); DeleteObject(m_work_rgn2); DeleteObject(m_last_rgn); // デスクトップDCを解放 LockWindowUpdate(NULL); if (m_desk_hdc) ReleaseDC(GetDesktopWindow(), m_desk_hdc); SelectObject(m_desk_hdc, m_desk_old_brush); } // ツールバー生成 TOOL_BAR::create(DOCK_SYS *p_dock_sys, TBBUTTON *tb_buttons, int tb_button_len){ m_floating_flag=0; m_p_dock_sys=p_dock_sys; HINSTANCE hInstance=GetModuleHandle(NULL); // ポップアップ・フレーム生成 m_popup_frame= CreateWindowEx( WS_EX_TOOLWINDOW, TEXT("popup_frame"), NULL, WS_OVERLAPPEDWINDOW | WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 300, 170, 200, 100, p_dock_sys->m_main_frame, NULL, hInstance, (LPVOID)this ); InitCommonControls(); // コモンコントロールのツールバー生成 m_control_tool_bar = CreateToolbarEx(p_dock_sys->m_main_frame, WS_CHILD | TBSTYLE_AUTOSIZE, 0, 6, (HINSTANCE)HINST_COMMCTRL, IDB_STD_SMALL_COLOR, tb_buttons, tb_button_len, 0, 0, 0, 0, sizeof (TBBUTTON) ); // ツールバーのフレーム生成 m_hwnd= CreateWindow( TEXT("tool_bar_frame"), NULL, WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0, 0, 200, 100, p_dock_sys->m_main_frame, NULL, hInstance, (LPVOID)this ); SetParent(m_control_tool_bar, m_hwnd); ShowWindow(m_control_tool_bar, SW_SHOWNA); } // ポップアップウィンドウ・プロシージャ(static版) LRESULT CALLBACK TOOL_BAR::StaticPopupProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) { TOOL_BAR *p_tool_bar =(TOOL_BAR*)GetWindowLong(hwnd, GWL_USERDATA); if (!p_tool_bar && (msg==WM_NCCREATE || msg==WM_CREATE)){ p_tool_bar = (TOOL_BAR*)((LPCREATESTRUCT)lp)->lpCreateParams; SetWindowLong(hwnd, GWL_USERDATA, (LONG)p_tool_bar); } if (p_tool_bar) return p_tool_bar->PopupProc(hwnd, msg, wp, lp); return DefWindowProc(hwnd, msg, wp, lp); } // ポップアップウィンドウ・プロシージャ TOOL_BAR::PopupProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) { int res; switch (msg) { case WM_NCACTIVATE: // タイトルバーのアクティブ化・非アクティブ化 m_p_dock_sys->on_ncactivate(hwnd, wp); break; case WM_LBUTTONDOWN:m_p_dock_sys->tool_on_lbuttondown(hwnd); break; // ドラッグ開始 case WM_LBUTTONUP: m_p_dock_sys->tool_on_lbuttonup(); break; // ドラッグ終了 case WM_MOUSEMOVE: m_p_dock_sys->tool_on_mousemove(); break; // マウス移動(ドラッグ中) case WM_NCHITTEST: res=DefWindowProc(hwnd, msg, wp, lp); if (res==HTCAPTION) return HTCLIENT; return res; } return DefWindowProc(hwnd, msg, wp, lp); } // ツールバーのフレームウィンドウ・プロシージャ(static版) LRESULT CALLBACK TOOL_BAR::StaticToolBarFrameProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp){ TOOL_BAR *p_tool_bar =(TOOL_BAR*)GetWindowLong(hwnd, GWL_USERDATA); if (!p_tool_bar && (msg==WM_NCCREATE || msg==WM_CREATE)){ p_tool_bar = (TOOL_BAR*)((LPCREATESTRUCT)lp)->lpCreateParams; SetWindowLong(hwnd, GWL_USERDATA, (LONG)p_tool_bar); } if (p_tool_bar) return p_tool_bar->ToolBarFrameProc(hwnd, msg, wp, lp); return DefWindowProc(hwnd, msg, wp, lp); } // ツールバーのフレームウィンドウ・プロシージャ TOOL_BAR::ToolBarFrameProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) { RECT rc, rc2; HDC hdc; PAINTSTRUCT ps; switch (msg) { case WM_PAINT: hdc = BeginPaint(hwnd , &ps); GetClientRect(hwnd, &rc); rc.left=0; rc.top=0; rc.bottom=1; FillRect(hdc, &rc, GetSysColorBrush(COLOR_BTNSHADOW)); rc.top++; rc.bottom++; FillRect(hdc, &rc, GetSysColorBrush(COLOR_BTNHILIGHT)); if (!m_floating_flag){ // グリッパー描画 GetClientRect(hwnd, &rc); rc.left+=2; rc.right=rc.left+3; rc.top+=1; rc.bottom-=2; rc2.left=rc.left; rc2.top=rc.top; rc2.right=rc.right-1; rc2.bottom=rc.top+1; FillRect(hdc, &rc2, GetSysColorBrush(COLOR_BTNHILIGHT)); rc2.right=rc.left+1; rc2.bottom=rc.bottom-1; FillRect(hdc, &rc2, GetSysColorBrush(COLOR_BTNHILIGHT)); rc2.left=rc.right; rc2.top=rc.top; rc2.right=rc.right-1; rc2.bottom=rc.bottom; FillRect(hdc, &rc2, GetSysColorBrush(COLOR_BTNSHADOW)); rc2.left=rc.left; rc2.top=rc.bottom; rc2.right=rc.right; rc2.bottom=rc.bottom-1; FillRect(hdc, &rc2, GetSysColorBrush(COLOR_BTNSHADOW)); } EndPaint(hwnd , &ps); break; case WM_SIZE: SendMessage(m_control_tool_bar, WM_SIZE, wp, lp); // ツーバーのリサイズ if (!m_floating_flag) SetWindowPos(m_control_tool_bar, NULL, 10,0, LOWORD(lp),HIWORD(lp), 0); break; case WM_LBUTTONDOWN:m_p_dock_sys->tool_on_lbuttondown(hwnd);break; // マウス左ボタン押下(ドラッグ終了) case WM_LBUTTONUP: m_p_dock_sys->tool_on_lbuttonup(); break; // マウス左ボタン押上(ドラッグ開始) case WM_MOUSEMOVE: m_p_dock_sys->tool_on_mousemove(); break; // マウス移動(ドラッグ中) } return DefWindowProc(hwnd, msg, wp, lp); } // マウス移動 void DOCK_SYS::tool_on_mousemove(){ if (!m_dock_context.m_now_dragging) return; m_dock_context.drag(); // ドラッグ中 } // マウス左ボタン押下 void DOCK_SYS::tool_on_lbuttondown(HWND hwnd){ if (m_dock_context.m_now_dragging) return; m_dock_context.start_drag(hwnd); // ドラッグ開始 } // マウス左ボタン押上 void DOCK_SYS::tool_on_lbuttonup(){ RECT drag_rc, dock_rc; if (!m_dock_context.m_now_dragging) return; m_dock_context.end_drag(); // ドラッグ終了 // ドッキング・フローティング判定 POINT po; GetCursorPos(&po); drag_rc.left=po.x-m_dock_context.m_cursor_offset.x; drag_rc.top =po.y-m_dock_context.m_cursor_offset.y; drag_rc.right = drag_rc.left + m_dock_context.m_drag_size.cx; drag_rc.bottom= drag_rc.top + m_dock_context.m_drag_size.cy; GetWindowRect(m_dock_bar.m_hwnd, &dock_rc); // ドッキング判定 if (drag_rc.left<=dock_rc.right && drag_rc.right>=dock_rc.left && drag_rc.top<=dock_rc.bottom && drag_rc.bottom>=dock_rc.top){ do_dock(); } // フローティング判定 else do_float(drag_rc.left, drag_rc.top); } // ドッキングシステム生成 DOCK_SYS::create(HWND main_hwnd, HWND child_view_hwnd){ m_now_nc_activing=0; m_main_frame=main_hwnd; m_hview=child_view_hwnd; regist_winc(TEXT("popup_frame"), (HBRUSH)(COLOR_BTNFACE+1), TOOL_BAR::StaticPopupProc); // フローティング・フレーム regist_winc(TEXT("tool_bar_frame"), (HBRUSH)(COLOR_BTNFACE+1), TOOL_BAR::StaticToolBarFrameProc); // ツールバーの外枠 regist_winc(TEXT("dock_bar_frame"), (HBRUSH)(COLOR_BTNFACE+1), DefWindowProc); // ドックバー HINSTANCE hInstance=GetModuleHandle(NULL); m_dock_bar.m_hwnd = CreateWindow( TEXT("dock_bar_frame"), NULL, WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0, 0, 200, 100, main_hwnd, NULL, hInstance, (LPVOID)this ); // ツールバーの生成 TBBUTTON tool_bar_buttons[] = { { STD_FILENEW, 1, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0 }, { STD_FILEOPEN, 2, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0 }, { STD_FILESAVE, 3, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0 }, { 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0 }, { STD_COPY, 4, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0 }, { STD_CUT, 5, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0 }, { STD_DELETE, 6, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0 }, { 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0 }, { VIEW_NEWFOLDER, 7, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0 }, { VIEW_PARENTFOLDER, 8, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0 }, }; m_tool_bar.create(this, tool_bar_buttons, 7); do_dock(); } // タイトルバーのアクティブ化・非アクティブ化 void DOCK_SYS::on_ncactivate(HWND hwnd, WPARAM wp){ if (m_now_nc_activing) return; m_now_nc_activing=1; SendMessage(m_main_frame, WM_NCACTIVATE, wp, 0); SendMessage(m_tool_bar.m_popup_frame, WM_NCACTIVATE, wp, 0); m_now_nc_activing=0; } // ドッキング void DOCK_SYS::do_dock(){ SetParent(m_tool_bar.m_hwnd, m_dock_bar.m_hwnd); m_tool_bar.m_floating_flag = 0; ShowWindow(m_tool_bar.m_popup_frame, SW_HIDE); recalc_layout(); } // フローティング void DOCK_SYS::do_float(int x, int y){ SetWindowPos(m_tool_bar.m_popup_frame, NULL, x, y, 0,0, SWP_NOSIZE); if (m_tool_bar.m_floating_flag) return; SetParent(m_tool_bar.m_hwnd, m_tool_bar.m_popup_frame); m_tool_bar.m_floating_flag = 1; ShowWindow(m_tool_bar.m_popup_frame, SW_SHOW); recalc_layout(); } // レイアウト再計算 void DOCK_SYS::recalc_layout(){ if (IsIconic(m_main_frame)) return; RECT rc; SIZE tool_size; // 子ウィンドウ位置の再計算 SendMessage(m_tool_bar.m_control_tool_bar, TB_GETMAXSIZE, 0, (LPARAM)&tool_size); // ツールバー・サイズ取得 DWORD padding=SendMessage(m_tool_bar.m_control_tool_bar, TB_GETPADDING, 0, 0); tool_size.cx+=LOWORD(padding); tool_size.cy+=HIWORD(padding); GetClientRect(m_main_frame, &rc); if (!m_tool_bar.m_floating_flag) rc.top =tool_size.cy; // ビューウィンドウ位置サイズ if (IsWindow(m_hview)) SetWindowPos(m_hview, NULL, rc.left, rc.top, rc.right, rc.bottom-rc.top, 0); // ドックバー位置サイズ SetWindowPos(m_dock_bar.m_hwnd, NULL, 0, 0, rc.right, rc.top, 0); // ポップアップ・ウィンドウ位置サイズ if(m_tool_bar.m_floating_flag){ rc.left=rc.top=0; rc.right=tool_size.cx; rc.bottom=tool_size.cy; AdjustWindowRectEx(&rc, GetWindowLong(m_tool_bar.m_popup_frame, GWL_STYLE), FALSE, GetWindowLong(m_tool_bar.m_popup_frame, GWL_EXSTYLE)); SetWindowPos(m_tool_bar.m_popup_frame, NULL, 0, 0, rc.right-rc.left, rc.bottom-rc.top, SWP_NOMOVE); } // ツールバー横サイズ補正 GetClientRect(GetParent(m_tool_bar.m_hwnd), &rc); SetWindowPos(m_tool_bar.m_hwnd, NULL, 0, 0, rc.right, tool_size.cy, 0); } // ウィンドウクラス登録 DOCK_SYS::regist_winc(char *caption, HBRUSH hbr_bg, WNDPROC proc){ WNDCLASS winc; winc.style = CS_HREDRAW | CS_VREDRAW; winc.lpfnWndProc = proc; winc.cbClsExtra = winc.cbWndExtra = 0; winc.hInstance = GetModuleHandle(NULL); winc.hIcon = LoadIcon(NULL, IDI_APPLICATION); winc.hCursor = LoadCursor(NULL, IDC_ARROW); winc.hbrBackground = hbr_bg; winc.lpszMenuName = NULL; winc.lpszClassName = caption; if (!RegisterClass(&winc)) return -1; return 0; } //====================================================================================== //============ 以下 メインウィンドウ ・ ビューウィンドウ ============================== //====================================================================================== // ビューウィンドウ・プロシージャ LRESULT CALLBACK ChildViewProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) { HDC hdc; PAINTSTRUCT ps; char str[]="ChildViewウィンドウ(座標0,0)"; switch (msg) { case WM_LBUTTONDOWN: SendMessage(GetParent(hwnd), WM_LBUTTONDOWN, wp, lp); break; case WM_PAINT: hdc = BeginPaint(hwnd , &ps); TextOut(hdc, 0, 0, str, lstrlen(str)); EndPaint(hwnd , &ps); break; } return DefWindowProc(hwnd, msg, wp, lp); } // メインウィンドウ・プロシージャ LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) { static DOCK_SYS dock_sys; // ウィンドウ・ハンドルの一括化 構造体 static HWND hview; switch (msg) { case WM_CREATE: hview= CreateWindowEx( WS_EX_TOOLWINDOW, TEXT("child_view"), NULL, WS_CHILD | WS_VISIBLE, 0, 0, 200, 100, hwnd, NULL, ((LPCREATESTRUCT)(lp))->hInstance, NULL ); dock_sys.create(hwnd, hview); break; case WM_DESTROY: PostQuitMessage(0); break; case WM_NCACTIVATE: // タイトルバーのアクティブ化・非アクティブ化 dock_sys.on_ncactivate(hwnd, wp); break; case WM_SIZE: dock_sys.recalc_layout(); break; } return DefWindowProc(hwnd, msg, wp, lp); } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR lpCmdLine, int nCmdShow ) { MSG msg; WNDCLASS winc; HWND hwnd; winc.style = CS_HREDRAW | CS_VREDRAW; winc.lpfnWndProc = WndProc; winc.cbClsExtra = winc.cbWndExtra = 0; winc.hInstance = hInstance; winc.hIcon = LoadIcon(NULL, IDI_APPLICATION); winc.hCursor = LoadCursor(NULL, IDC_ARROW); winc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); winc.lpszMenuName = NULL; winc.lpszClassName = TEXT("main_frame"); if (!RegisterClass(&winc)) return -1; // メイン・ウィンドウ winc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); winc.lpfnWndProc = ChildViewProc; winc.lpszClassName = TEXT("child_view"); if (!RegisterClass(&winc)) return -1; // ビューウィンドウ hwnd = CreateWindow( TEXT("main_frame"), TEXT("ドッキング・ツールバーのテスト"), WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN, 100, 100, 240, 200, NULL, NULL, hInstance, NULL ); if (hwnd == NULL) return -1; while(GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } |