// タブ用ウィンドウ private { import std.thread; import std.file; import std.path; import std.string; import std.utf; import basewindow; import itemwindow; import entry; import skin; import utils; import config; import resource; import dialogs; import vector; } alias Vector!(ItemWindow) WindowList; // タブ制御用スレッド class TabWindowThread : Thread { private: TabWindow window; tab_setting config; Skin tab; public: this(TabWindow _window) { window = _window; } this(tab_setting conf) { config = conf; char[] skin_path = Config.GetInstance().GetSkinFullPath() ~"\\"~ config.action.skin_name ~ "\\skin.ini"; SkinParts skin_parts = LoadSkinParts(skin_path); tab = skin_parts["tab"]; window = new TabWindow(config, tab); } int run() { int height = tab.GetChild("caption").Height; window.CreateEx(WS_EX_TOOLWINDOW | WS_EX_LAYERED, toUTF16z(std.string.toString(config.index) ~"."~ config.name), toUTF16z(config.name), WS_POPUP | WS_CLIPCHILDREN, config.x, config.y, tab.Width, height, NULL, NULL, NULL); // config.hParentWnd, NULL, NULL); MSG msg; BOOL bRet; while ((bRet = GetMessage(&msg, window.WindowHandle, 0, 0)) != 0) { if (bRet == -1) { assert(0); // error } else { TranslateMessage(&msg); DispatchMessage(&msg); } } return 0; } } // タブの状態 enum { TAB_CLOSED, TAB_OPENED, TAB_OPENING, TAB_CLOSING, TAB_OPENWAITING, TAB_CLOSEWAITING, } // タイマーID enum { TIMER_MOUSECHECK, TIMER_OPENWAIT, TIMER_CLOSEWAIT, TIMER_ANIMATION, } class TabWindow : BaseWindow { private: tab_setting config; Skin tab; bool dragfull_changed; int tab_state; WindowList item_windows; int min_height, max_height; char[][int] skin_names; bool hover, lbutton_pressed; public: this(tab_setting conf, Skin skin) { config = conf; tab = skin; item_windows = new WindowList; min_height = tab.GetChild("caption").Height; } void CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hParentWnd, HMENU nIDorHMenu, LPVOID lpParam) { switch (config.action.position) { case 1: case 3: BaseWindow.CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle, x, y, nHeight, nWidth, hParentWnd, nIDorHMenu, lpParam); break; case 0: case 2: default: BaseWindow.CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle, x, y, nWidth, nHeight, hParentWnd, nIDorHMenu, lpParam); } } extern(Windows) uint WindowProc(HWND hWnd, uint uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_CREATE: OnCreate(hWnd, cast(LPCREATESTRUCT)lParam); break; case WM_NCHITTEST: return OnNCHitTest(hWnd, LOWORD(lParam), HIWORD(lParam)); case WM_NCMOUSEMOVE: return OnMouseMove(hWnd); case WM_NCRBUTTONUP: OnRightButtonUp(hWnd); break; case WM_TIMER: return OnTimer(hWnd, wParam); case WM_WINDOWPOSCHANGING: return OnWindowPosChanging(hWnd, cast(WINDOWPOS*)lParam); case WM_WINDOWPOSCHANGED: return OnWindowPosChanged(hWnd, cast(WINDOWPOS*)lParam); case WM_THEMECHANGED: return OnThemeChanged(hWnd); case WM_COMMAND: switch (LOWORD(wParam)) { case IDM_TAB_EDITENTRIES: OnCommandEditEntries(hWnd); break; case IDM_TAB_TABSETTING: OnCommandTabSetting(hWnd); break; case IDM_TAB_MOVETOCENTER: OnCommandMoveToCenter(hWnd); break; case IDM_TAB_REMOVETAB: OnCommandTabRemove(hWnd); break; case IDM_TAB_INFORMATION: break; default: } if (LOWORD(wParam) >= 10000) { config.action.skin_name = skin_names[LOWORD(wParam)]; OnSkinChanged(skin_names[LOWORD(wParam)]); } break; case WM_DROPFILES: onDropFiles(hWnd, cast(HDROP)wParam); break; case WM_PAINT: OnPaint(hWnd); break; case WM_CLOSE: return OnClose(hWnd); default: return BaseWindow.WindowProc(hWnd, uMsg, wParam, lParam); } return 0; } // ウィンドウ生成前処理 void PreCreateWindow(inout WNDCLASSEX wcex) { wcex.hbrBackground = cast(HBRUSH) GetStockObject(NULL_BRUSH); return; } // 初期化処理 void OnCreate(HWND hWnd, LPCREATESTRUCT lpcs) { // Z-Orderの指定 if (config.action.z_order == Z_ORDER_ALWAYSONTOP) { SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); } // 透過色&透過度設定 SetLayeredWindowAttributes(hWnd, RGB(255,0,255), 255 - config.action.transparency, LWA_COLORKEY | LWA_ALPHA); // Drag'n Dropを許可 DragAcceptFiles(hWnd, TRUE); // 登録されているアイテム CreateItemWindows(hWnd); ShowWindow(hWnd, SW_SHOW); } // void CreateItemWindows(HWND hWnd) { for (int i = 0; i < config.entry.GetChildren().size(); i++) { ItemConfig* pItemConfig = new ItemConfig; pItemConfig.hParentWnd = hWnd; pItemConfig.entry = config.entry.GetChildren()[i]; pItemConfig.width = tab.Width - tab.GetChild("border-left").Width - tab.GetChild("border-right").Width; pItemConfig.position = config.action.position; pItemConfig.skin = tab.GetChild("item"); pItemConfig.tab_skin = tab; switch (config.action.position) { case 1: pItemConfig.x = tab.Width - i * tab.GetChild("item").Height + tab.GetChild("caption").Height; pItemConfig.y = tab.GetChild("border-left").Width; break; case 3: pItemConfig.x = i * tab.GetChild("item").Height + tab.GetChild("caption").Height; pItemConfig.y = tab.GetChild("border-right").Width; break; case 0: default: pItemConfig.x = tab.GetChild("border-left").Width; pItemConfig.y = i * tab.GetChild("item").Height + tab.GetChild("caption").Height; } ItemWindow window = new ItemWindow(*pItemConfig); switch (config.action.position) { case 1: case 3: window.CreateEx(WS_EX_TOOLWINDOW, toUTF16z("TAB." ~ std.string.toString(config.index) ~ ".Item." ~ std.string.toString(i)), toUTF16z(pItemConfig.entry.Name), WS_CHILD, pItemConfig.x, pItemConfig.y, pItemConfig.skin.Height, pItemConfig.width, pItemConfig.hParentWnd, NULL, NULL); break; case 0: case 2: default: window.CreateEx(WS_EX_TOOLWINDOW, toUTF16z("TAB." ~ std.string.toString(config.index) ~ ".Item." ~ std.string.toString(i)), toUTF16z(pItemConfig.entry.Name), WS_CHILD, pItemConfig.x, pItemConfig.y, pItemConfig.width, pItemConfig.skin.Height, pItemConfig.hParentWnd, NULL, NULL); } item_windows.add(window); } } // HRESULT OnNCHitTest(HWND hWnd, int x, int y) { if (GetAsyncKeyState(VK_LBUTTON) < 0) { if (!lbutton_pressed) { lbutton_pressed = true; // 手抜き('A`;) 一時的にウィンドウ内容を表示するように指示 BOOL dragfull; SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, &dragfull, 0); if (dragfull == FALSE) { dragfull_changed = true; SystemParametersInfo(SPI_SETDRAGFULLWINDOWS, TRUE, null, 0); } } } else { if (lbutton_pressed) { lbutton_pressed = false; // 手抜き('A`;) 後始末 if (dragfull_changed) { SystemParametersInfo(SPI_SETDRAGFULLWINDOWS, FALSE, null, 0); } OnLeftButtonUp(hWnd); } } return HTCAPTION; } // 描画 void OnPaint(HWND hWnd) { PAINTSTRUCT paint; HDC hdrawdc = BeginPaint(hWnd, &paint); HDC hdc = CreateCompatibleDC(hdrawdc); RECT virtual_rect, client_rect, draw_rect; GetClientRect(hWnd, &client_rect); switch (config.action.position) { case 1: case 3: virtual_rect.top = 0; virtual_rect.left = 0; virtual_rect.right = client_rect.bottom; virtual_rect.bottom = client_rect.right; break; case 0: case 4: default: virtual_rect = client_rect; } draw_rect = virtual_rect; // メモリDC用仮想BMP HBITMAP hVirtualBmp = CreateCompatibleBitmap(hdrawdc, virtual_rect.right, virtual_rect.bottom); SelectObject(hdc, hVirtualBmp); // 透過ブラシ HBRUSH hBrush = CreateSolidBrush(RGB(255, 0, 255)); // タブ背景 tab.DrawBackground(hWnd, hdc, virtual_rect); // Caption draw_rect.bottom = tab.GetChild("caption").Height; FillRect(hdc, &draw_rect, hBrush); tab.GetChild("caption").DrawBackground(hWnd, hdc, draw_rect); // Caption Text if (config.action.position != 2) { tab.GetChild("caption").GetChild("text").DrawText(hdc, config.name, draw_rect); } // border if (virtual_rect.bottom > tab.GetChild("caption").Height) { // border-bottom draw_rect.top = virtual_rect.bottom - tab.GetChild("border-bottom").Height; draw_rect.left = virtual_rect.left; draw_rect.right = virtual_rect.right; draw_rect.bottom = virtual_rect.bottom; FillRect(hdc, &draw_rect, hBrush); tab.GetChild("border-bottom").DrawBackground(hWnd, hdc, draw_rect); // border-left; draw_rect.top = virtual_rect.top + tab.GetChild("caption").Height; draw_rect.left = virtual_rect.left; draw_rect.right = virtual_rect.left + tab.GetChild("border-left").Width; draw_rect.bottom = virtual_rect.bottom - tab.GetChild("border-bottom").Height; FillRect(hdc, &draw_rect, hBrush); tab.GetChild("border-left").DrawBackground(hWnd, hdc, draw_rect); // border-right; draw_rect.top = virtual_rect.top + tab.GetChild("caption").Height; draw_rect.left = virtual_rect.right - tab.GetChild("border-right").Width; draw_rect.right = virtual_rect.right; draw_rect.bottom = virtual_rect.bottom - tab.GetChild("border-bottom").Height; FillRect(hdc, &draw_rect, hBrush); tab.GetChild("border-right").DrawBackground(hWnd, hdc, draw_rect); } // 転送 POINT* pt = new POINT[3]; switch (config.action.position) { case 1: pt[0].x = client_rect.right; pt[0].y = 0; pt[1].x = client_rect.right; pt[1].y = client_rect.bottom; pt[2].x = 0; pt[2].y = 0; break; case 2:// 逆さまにしたときだけ変?要調査 pt[0].x = client_rect.right -1; pt[0].y = client_rect.bottom -1; pt[1].x = -1; pt[1].y = client_rect.bottom -1; pt[2].x = client_rect.right -1; pt[2].y = -1; break; case 3: pt[0].x = 0; pt[0].y = client_rect.bottom; pt[1].x = 0; pt[1].y = 0; pt[2].x = client_rect.right; pt[2].y = client_rect.bottom; break; case 0: default: pt[0].x = 0; pt[0].y = 0; pt[1].x = client_rect.right; pt[1].y = 0; pt[2].x = 0; pt[2].y = client_rect.bottom; } PlgBlt(hdrawdc, pt, hdc, 0, 0, virtual_rect.right, virtual_rect.bottom, NULL, 0, 0); if (config.action.position == 2) { draw_rect.top = client_rect.bottom - tab.GetChild("caption").Height; draw_rect.left = client_rect.left; draw_rect.right = client_rect.right; draw_rect.bottom = client_rect.bottom; tab.GetChild("caption").GetChild("text").DrawText(hdrawdc, config.name, draw_rect); } // 一時オブジェクト破棄 DeleteObject(hBrush); DeleteObject(hVirtualBmp); DeleteDC(hdc); EndPaint(hdrawdc, &paint); } // マウスが乗った HRESULT OnMouseMove(HWND hWnd) { // マウスクリックで開閉するなら終わり if (config.action.open_type == OPENTYPE_CLICK) { return 0; } // Z-Order指定 if (config.action.z_order == Z_ORDER_MOUSEOVERONTOP) { SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); } // マウスチェック用タイマー hover = true; SetTimer(hWnd, TIMER_MOUSECHECK, 50, NULL); // // OpenWait用タイマー if (config.action.open_type == OPENTYPE_AUTO) { if (tab_state == TAB_CLOSEWAITING) { KillTimer(hWnd, TIMER_CLOSEWAIT); } if (config.action.open_wait > 0) { SetTimer(hWnd, TIMER_OPENWAIT, config.action.open_wait, NULL); } else { if (config.action.animation) { OpenTabWithAnimation(hWnd); } else { OpenTab(hWnd); } } } return 0; } // タイマー HRESULT OnTimer(HWND hWnd, DWORD dwTimerID) { switch (dwTimerID) { case TIMER_MOUSECHECK: POINT mouse_point; RECT window_rect; GetWindowRect(hWnd, &window_rect); GetCursorPos(&mouse_point); if (mouse_point.x < window_rect.left || window_rect.right < mouse_point.x || mouse_point.y < window_rect.top || window_rect.bottom < mouse_point.y) { hover = false; KillTimer(hWnd, TIMER_MOUSECHECK); if (tab_state == TAB_OPENWAITING) { KillTimer(hWnd, TIMER_OPENWAIT); } // Tab Closeタイマー発行 if (config.action.close_wait > 0) { tab_state = TAB_CLOSEWAITING; SetTimer(hWnd, TIMER_CLOSEWAIT, config.action.close_wait, NULL); } else { if (config.action.animation) { CloseTabWithAnimation(hWnd); } else { CloseTab(hWnd); } } } break; case TIMER_OPENWAIT: KillTimer(hWnd, TIMER_OPENWAIT); if (hover) { if (config.action.animation) { OpenTabWithAnimation(hWnd); } else { OpenTab(hWnd); } } break; case TIMER_CLOSEWAIT: KillTimer(hWnd, TIMER_CLOSEWAIT); if (config.action.animation) { CloseTabWithAnimation(hWnd); } else { CloseTab(hWnd); } break; case TIMER_ANIMATION: switch (tab_state) { case TAB_OPENING: OpenTabWithAnimation(hWnd); break; case TAB_CLOSING: CloseTabWithAnimation(hWnd); break; } break; } return 0; } // ウィンドウの移動 HRESULT OnWindowPosChanging(HWND hWnd, WINDOWPOS* lpwp) { if (config.action.lock) { RECT window_rect; GetWindowRect(hWnd, &window_rect); lpwp.x = window_rect.left; lpwp.y = window_rect.top; } else { RECT workarea; SystemParametersInfo(SPI_GETWORKAREA, 0, &workarea, 0); if (lpwp.x < 10) { lpwp.x = 0; } if (workarea.right - (lpwp.x + lpwp.cx) < 10) { lpwp.x = workarea.right - lpwp.cx; } if (lpwp.y < workarea.top + 10) { lpwp.y = workarea.top; } if (workarea.bottom - (lpwp.y + lpwp.cy) < 10) { lpwp.y = workarea.bottom - lpwp.cy; } } return 0; } // ウィンドウが移動した HRESULT OnWindowPosChanged(HWND hWnd, WINDOWPOS* lpwp) { config.x = lpwp.x; config.y = lpwp.y; TabSettings.GetInstance().settings.set(config.index, config); return 0; } // テーマが変更された HRESULT OnThemeChanged(HWND hWnd) { OnSkinChanged(config.action.skin_name); return 0; } // ウィンドウ終了 HRESULT OnClose(HWND hWnd) { TabSettings.GetInstance().SaveSectionToFile(config); PostQuitMessage(0); return 0; } // マウスの左ボタンが離された -> オープン? HRESULT OnLeftButtonUp(HWND hWnd) { switch (config.action.open_type) { case OPENTYPE_AUTO: break; case OPENTYPE_CLICK: if (tab_state == TAB_CLOSED) { if (config.action.animation) { OpenTabWithAnimation(hWnd); } else { OpenTab(hWnd); } } else { if (config.action.animation) { CloseTabWithAnimation(hWnd); } else { CloseTab(hWnd); } } break; case OPENTYPE_CLICKOPENONLY: if (tab_state == TAB_CLOSED) { if (config.action.animation) { OpenTabWithAnimation(hWnd); } else { OpenTab(hWnd); } } break; } return 0; } // マウスの右ボタンが離された -> メニュー表示 void OnRightButtonUp(HWND hWnd) { HMENU hSkinMenu = CreatePopupMenu(); char[] skin_path = Config.GetInstance().GetSkinFullPath(); int i = 0; foreach (char[] item; std.file.listdir(skin_path)) { if (exists(skin_path ~ "\\" ~ item ~ "\\skin.ini")) { AppendMenu(hSkinMenu, MF_STRING, 10000+i, toUTF16z(item)); skin_names[10000+i] = item; i++; } } // SetForegroundWindow(hWnd); POINT pt; HMENU hMenu = LoadMenu(GetModuleHandle(NULL), MAKEINTRESOURCE(IDM_TAB)); HMENU hSubMenu = GetSubMenu(hMenu, 0); InsertMenu(hSubMenu, 2, MF_BYPOSITION | MF_POPUP | MF_STRING, cast(UINT)hSkinMenu, toUTF16z("Skins")); GetCursorPos(&pt); TrackPopupMenu(hSubMenu, TPM_BOTTOMALIGN, pt.x, pt.y, 0, hWnd, NULL); DestroyMenu(hMenu); } // コマンド - Edit Entries void OnCommandEditEntries(HWND hWnd) { TabEntriesDialog dlg = new TabEntriesDialog(&config.entry); if (dlg.CreateModal(hWnd) == IDOK) { for (int i = 0; i < item_windows.size(); i++) { DestroyWindow(item_windows[i].WindowHandle); while (true) { if (UnregisterClass(toUTF16z("TAB." ~ std.string.toString(config.index) ~ ".Item." ~ std.string.toString(i)), GetModuleHandle(NULL)) != 0) { break; } } } item_windows.clear(); // Save char[] filename = Config.GetInstance().GetGroupFullPath ~ "\\" ~ config.group_name; SaveEntry(filename, config.entry, true); CreateItemWindows(hWnd); } } // コマンド - Tab Setting void OnCommandTabSetting(HWND hWnd) { tab_setting new_config = config; TabSettingDialog dlg = new TabSettingDialog(&new_config); if (dlg.CreateModal(hWnd) == IDOK) { bool redraw, skin_changed, recreate_child; if (config.action.skin_name != new_config.action.skin_name) { skin_changed = true; } if (config.name != new_config.name) { redraw = true; } if (config.action.transparency != new_config.action.transparency) { SetLayeredWindowAttributes(hWnd, RGB(255,0,255), 255 - new_config.action.transparency, LWA_COLORKEY | LWA_ALPHA); } if (config.action.z_order != new_config.action.z_order) { if (new_config.action.z_order == Z_ORDER_ALWAYSONTOP) { SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); } else { SetWindowPos(hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); } } if (config.group_name != new_config.group_name) { recreate_child = true; } config = new_config; TabSettings.GetInstance().settings.set(config.index, config); if (redraw) { if (skin_changed) { OnSkinChanged(config.action.skin_name); } else { InvalidateRect(hWnd, NULL, TRUE); UpdateWindow(hWnd); } } if (recreate_child) { for (int i = 0; i < item_windows.size(); i++) { DestroyWindow(item_windows[i].WindowHandle); while (true) { if (UnregisterClass(toUTF16z("TAB." ~ std.string.toString(config.index) ~ ".Item." ~ std.string.toString(i)), GetModuleHandle(NULL)) != 0) { break; } } } item_windows.clear(); config.entry = LoadEntry(Config.GetInstance.GetGroupFullPath ~ "\\" ~ config.group_name); CreateItemWindows(hWnd); } } } // コマンド - Remove Tab void OnCommandTabRemove(HWND hWnd) { config.removed = true; TabSettings.GetInstance().settings.set(config.index, config); DestroyWindow(hWnd); } // コマンド - Move To Center void OnCommandMoveToCenter(HWND hWnd) { int x, y; RECT window_rect, workarea; GetWindowRect(hWnd, &window_rect); SystemParametersInfo(SPI_GETWORKAREA, 0, &workarea, 0); switch (config.action.position) { case 1: case 3: x = window_rect.left; y = ((workarea.bottom - workarea.top) / 2) - ((window_rect.bottom - window_rect.top) / 2); SetWindowPos(hWnd, NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER); break; case 0: case 2: default: x = ((workarea.right - workarea.left) / 2) - ((window_rect.right - window_rect.left) / 2); y = window_rect.top; SetWindowPos(hWnd, NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER); break; } } // ファイルがドロップされた void onDropFiles(HWND hWnd, HDROP hDrop) { uint drop_files = DragQueryFile(hDrop, -1, null, 0); for (int i = 0; i < drop_files; i++) { wchar[] filename = new wchar[MAX_PATH]; uint len = DragQueryFile(hDrop, i, filename.ptr, MAX_PATH); // 内部データ生成 Entry item = new Item; item.ExecFile = toUTF8(filename[0..len]); item.Name = getBaseName(item.ExecFile)[0..length-(getExt(item.ExecFile).length+1)]; item.ExecPath = getDirName(item.ExecFile); item.IconIndex = -1; config.entry.Add(item); // 保存とウィンドウの生成 for (int i = 0; i < item_windows.size(); i++) { DestroyWindow(item_windows[i].WindowHandle); while (true) { if (UnregisterClass(toUTF16z("TAB." ~ std.string.toString(config.index) ~ ".Item." ~ std.string.toString(i)), GetModuleHandle(NULL)) != 0) { break; } } } item_windows.clear(); // Save char[] entry_filename = Config.GetInstance().GetGroupFullPath ~ "\\" ~ config.group_name; SaveEntry(entry_filename, config.entry, true); CreateItemWindows(hWnd); } DragFinish(hDrop); } void OnSkinChanged(char[] skin_name) { char[] skin_path = Config.GetInstance().GetSkinFullPath() ~"\\"~ config.action.skin_name ~ "\\skin.ini"; SkinParts skin_parts = LoadSkinParts(skin_path); tab = skin_parts["tab"]; RECT rect; GetWindowRect(hWnd, &rect); int diff_height = tab.GetChild("caption").Height - min_height; SetWindowPos(hWnd, NULL, rect.left, rect.top - diff_height, tab.Width, tab.GetChild("caption").Height, SWP_NOZORDER); min_height = tab.GetChild("caption").Height; for (int i = 0; i < item_windows.size(); i++) { int x = tab.GetChild("border-left").Width; int y = i * tab.GetChild("item").Height + tab.GetChild("caption").Height; int width = tab.Width - tab.GetChild("border-left").Width - tab.GetChild("border-right").Width; int height = tab.GetChild("item").Height; SetWindowPos(item_windows[i].WindowHandle, NULL, x, y, width, height, SWP_NOZORDER); item_windows[i].OnSkinChanged(tab.GetChild("item")); } InvalidateRect(hWnd, NULL, TRUE); UpdateWindow(hWnd); TabSettings.GetInstance().settings.set(config.index, config); } // タブを開く (アニメーションON) void OpenTabWithAnimation(HWND hWnd) { if (tab_state != TAB_OPENING) { tab_state = TAB_OPENING; SetTimer(hWnd, TIMER_ANIMATION, 10, NULL); } int max_height = tab.GetChild("caption").Height + tab.GetChild("border-bottom").Height + tab.GetChild("item").Height * config.entry.GetChildren.size(); RECT window_rect; GetWindowRect(hWnd, &window_rect); int x, y; int width, height; bool stop; switch (config.action.position) { case 1: x = window_rect.left; y = window_rect.top; width = window_rect.right - window_rect.left + 10; height = window_rect.bottom - window_rect.top; if (width > max_height) { stop = true; width = max_height; } for (int i = 0; i < item_windows.size(); i++) { int item_x, item_y; item_x = width - tab.GetChild("caption").Height - (i + 1) * tab.GetChild("item").Height; item_y = tab.GetChild("border-left").Width; SetWindowPos(item_windows[i].WindowHandle, NULL, item_x, item_y, 0, 0, SWP_NOSIZE | SWP_NOZORDER); } break; case 2: x = window_rect.left; y = window_rect.top; width = window_rect.right - window_rect.left; height = window_rect.bottom - window_rect.top + 10; if (height > max_height) { stop = true; height = max_height; } for (int i = 0; i < item_windows.size(); i++) { int item_x, item_y; item_x = tab.GetChild("border-right").Width; item_y = height - tab.GetChild("caption").Height - (i + 1) * tab.GetChild("item").Height; SetWindowPos(item_windows[i].WindowHandle, NULL, item_x, item_y, 0, 0, SWP_NOSIZE | SWP_NOZORDER); } break; case 3: x = window_rect.left - 10; y = window_rect.top; width = window_rect.right - window_rect.left + 10; height = window_rect.bottom - window_rect.top; if (width > max_height) { stop = true; x = window_rect.right - max_height; width = max_height; } break; case 0: default: x = window_rect.left; y = window_rect.top - 10; width = window_rect.right - window_rect.left; height = window_rect.bottom - window_rect.top + 10; if (height > max_height) { stop = true; y = window_rect.bottom - max_height; height = max_height; } } if (stop) { KillTimer(hWnd, TIMER_ANIMATION); tab_state = TAB_OPENED; SetLayeredWindowAttributes(hWnd, RGB(255,0,255), 255, LWA_COLORKEY | LWA_ALPHA); } SetWindowPos(hWnd, NULL, x, y, width, height, SWP_NOZORDER | SWP_NOMOVE | SWP_NOSENDCHANGING); SetWindowPos(hWnd, NULL, x, y, width, height, SWP_NOZORDER | SWP_NOSIZE | SWP_NOSENDCHANGING); } // タブを閉じる(アニメーションON) void CloseTabWithAnimation(HWND hWnd) { if (tab_state != TAB_CLOSING) { tab_state = TAB_CLOSING; SetTimer(hWnd, TIMER_ANIMATION, 10, NULL); } int min_height = tab.GetChild("caption").Height; RECT window_rect; GetWindowRect(hWnd, &window_rect); int x, y; int width, height; bool stop; switch (config.action.position) { case 1: x = window_rect.left; y = window_rect.top; width = window_rect.right - window_rect.left - 10; height = window_rect.bottom - window_rect.top; if (width < min_height) { stop = true; width = min_height; } for (int i = 0; i < item_windows.size(); i++) { int item_x, item_y; item_x = width - tab.GetChild("caption").Height - (i + 1) * tab.GetChild("item").Height; item_y = tab.GetChild("border-left").Width; SetWindowPos(item_windows[i].WindowHandle, NULL, item_x, item_y, 0, 0, SWP_NOSIZE | SWP_NOZORDER); } break; case 2: x = window_rect.left; y = window_rect.top; width = window_rect.right - window_rect.left; height = window_rect.bottom - window_rect.top - 10; if (height < min_height) { stop = true; height = min_height; } for (int i = 0; i < item_windows.size(); i++) { int item_x, item_y; item_x = tab.GetChild("border-right").Width; item_y = height - tab.GetChild("caption").Height - (i + 1) * tab.GetChild("item").Height; SetWindowPos(item_windows[i].WindowHandle, NULL, item_x, item_y, 0, 0, SWP_NOSIZE | SWP_NOZORDER); } break; case 3: x = window_rect.left + 10; y = window_rect.top; width = window_rect.right - window_rect.left - 10; height = window_rect.bottom - window_rect.top; if (width < min_height) { stop = true; x = window_rect.right - min_height; width = min_height; } break; case 0: default: x = window_rect.left; y = window_rect.top + 10; width = window_rect.right - window_rect.left; height = window_rect.bottom - window_rect.top - 10; if (height < min_height) { stop = true; y = window_rect.bottom - min_height; height = min_height; } } if (stop) { KillTimer(hWnd, TIMER_ANIMATION); // Z-Orderを元に戻す if (config.action.z_order == Z_ORDER_MOUSEOVERONTOP) { SetWindowPos(hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); } tab_state = TAB_CLOSED; } SetWindowPos(hWnd, NULL, x, y, width, height, SWP_NOZORDER | SWP_NOMOVE | SWP_NOSENDCHANGING); SetWindowPos(hWnd, NULL, x, y, width, height, SWP_NOZORDER | SWP_NOSIZE | SWP_NOSENDCHANGING); SetLayeredWindowAttributes(hWnd, RGB(255,0,255), 255 - config.action.transparency, LWA_COLORKEY | LWA_ALPHA); } // タブを開く(アニメーションOFF) void OpenTab(HWND hWnd) { if (tab_state == TAB_CLOSED || tab_state == TAB_OPENWAITING) { RECT rect; GetWindowRect(hWnd, &rect); int x, y; int width, height; switch (config.action.position) { case 1: width = config.entry.GetChildren().size() * tab.GetChild("item").Height + tab.GetChild("caption").Height + tab.GetChild("border-bottom").Height; height = tab.Width; x = rect.left; y = rect.top; for (int i = 0; i < item_windows.size(); i++) { int item_x, item_y; item_x = width - tab.GetChild("caption").Height - (i + 1) * tab.GetChild("item").Height; item_y = tab.GetChild("border-left").Width; SetWindowPos(item_windows[i].WindowHandle, NULL, item_x, item_y, 0, 0, SWP_NOSIZE | SWP_NOZORDER); } break; case 2: width = tab.Width; height = config.entry.GetChildren().size() * tab.GetChild("item").Height + tab.GetChild("caption").Height + tab.GetChild("border-bottom").Height; x = rect.left; y = rect.top; for (int i = 0; i < item_windows.size(); i++) { int item_x, item_y; item_x = tab.GetChild("border-right").Width; item_y = height - tab.GetChild("caption").Height - (i + 1) * tab.GetChild("item").Height; SetWindowPos(item_windows[i].WindowHandle, NULL, item_x, item_y, 0, 0, SWP_NOSIZE | SWP_NOZORDER); } break; case 3: width = config.entry.GetChildren().size() * tab.GetChild("item").Height + tab.GetChild("caption").Height + tab.GetChild("border-bottom").Height; height = tab.Width; x = rect.left - width + tab.GetChild("caption").Height; y = rect.top; break; case 0: default: width = tab.Width; height = config.entry.GetChildren().size() * tab.GetChild("item").Height + tab.GetChild("caption").Height + tab.GetChild("border-bottom").Height; x = rect.left; y = rect.top - height + tab.GetChild("caption").Height; } SetWindowPos(hWnd, NULL, x, y, width, height, SWP_NOZORDER | SWP_NOMOVE | SWP_NOSENDCHANGING); SetWindowPos(hWnd, NULL, x, y, width, height, SWP_NOZORDER | SWP_NOSIZE | SWP_NOSENDCHANGING); SetLayeredWindowAttributes(hWnd, RGB(255,0,255), 255, LWA_COLORKEY | LWA_ALPHA); tab_state = TAB_OPENED; } } // タブを閉じる(アニメーションOFF) void CloseTab(HWND hWnd) { RECT rect; GetWindowRect(hWnd, &rect); int x, y; int width, height; switch (config.action.position) { case 1: width = tab.GetChild("caption").Height; height = rect.bottom - rect.top; x = rect.left; y = rect.top; for (int i = 0; i < item_windows.size(); i++) { int item_x, item_y; item_x = width - tab.GetChild("caption").Height - (i + 1) * tab.GetChild("item").Height; item_y = tab.GetChild("border-left").Width; SetWindowPos(item_windows[i].WindowHandle, NULL, item_x, item_y, 0, 0, SWP_NOSIZE | SWP_NOZORDER); } break; case 2: width = rect.right - rect.left; height = tab.GetChild("caption").Height; x = rect.left; y = rect.top; for (int i = 0; i < item_windows.size(); i++) { int item_x, item_y; item_x = tab.GetChild("border-right").Width; item_y = height - tab.GetChild("caption").Height - (i + 1) * tab.GetChild("item").Height; SetWindowPos(item_windows[i].WindowHandle, NULL, item_x, item_y, 0, 0, SWP_NOSIZE | SWP_NOZORDER); } break; case 3: width = tab.GetChild("caption").Height; height = rect.bottom - rect.top; x = rect.right - width; y = rect.top; break; case 0: default: width = rect.right - rect.left; height = tab.GetChild("caption").Height; x = rect.left; y = rect.bottom - height; } SetWindowPos(hWnd, NULL, x, y, width, height, SWP_NOMOVE | SWP_NOZORDER | SWP_NOSENDCHANGING); SetWindowPos(hWnd, NULL, x, y, width, height, SWP_NOSIZE | SWP_NOZORDER | SWP_NOSENDCHANGING); // Z-Orderを元に戻す if (config.action.z_order == Z_ORDER_MOUSEOVERONTOP) { SetWindowPos(hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); } SetLayeredWindowAttributes(hWnd, RGB(255,0,255), 255 - config.action.transparency, LWA_COLORKEY | LWA_ALPHA); tab_state = TAB_CLOSED; } }