From ed89596d1170e8ee759a8a74e46643eb574c5698 Mon Sep 17 00:00:00 2001 From: katsuhisa yuasa Date: Sat, 30 Aug 2025 21:25:29 +0900 Subject: [PATCH] =?UTF-8?q?Darkmodelib=E3=82=92=E4=BD=BF=E7=94=A8=E3=81=97?= =?UTF-8?q?Dark=20Mode=E3=81=B8=E5=AF=BE=E5=BF=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/build-on-msys2.yml | 2 + .github/workflows/build-sakura.yml | 2 +- .github/workflows/sonarscan.yml | 2 +- .gitmodules | 3 + resource/mytool.bmp | Bin 63478 -> 63478 bytes sakura/sakura.vcxproj | 12 +- sakura/sakura.vcxproj.filters | 33 ++ sakura_core/CPropertyManager.cpp | 1 + sakura_core/_main/CControlTray.cpp | 23 - sakura_core/_main/WinMain.cpp | 8 + sakura_core/apiwrap/CommonControl.h | 7 + sakura_core/cmd/CViewCommander_Outline.cpp | 4 +- sakura_core/cmd/CViewCommander_Settings.cpp | 5 + sakura_core/dlg/CDialog.cpp | 9 + sakura_core/outline/CDlgFuncList.cpp | 30 +- sakura_core/print/CPrintPreview.cpp | 10 +- sakura_core/prop/CPropComGeneral.cpp | 2 +- sakura_core/prop/CPropComToolbar.cpp | 25 +- sakura_core/prop/CPropCommon.cpp | 3 + sakura_core/typeprop/CPropTypes.cpp | 2 + sakura_core/typeprop/CPropTypesColor.cpp | 26 +- sakura_core/uiparts/CImageListMgr.cpp | 388 ++++------------ sakura_core/uiparts/CImageListMgr.h | 28 +- sakura_core/uiparts/CMenuDrawer.cpp | 472 ++------------------ sakura_core/uiparts/CMenuDrawer.h | 8 +- sakura_core/util/shell.cpp | 11 +- sakura_core/view/CEditView.cpp | 3 + sakura_core/view/CEditView_Scroll.cpp | 4 + sakura_core/window/CEditWnd.cpp | 58 +-- sakura_core/window/CMainStatusBar.cpp | 5 + sakura_core/window/CMainToolBar.cpp | 126 +++--- sakura_core/window/CMainToolBar.h | 5 +- sakura_core/window/CSplitBoxWnd.cpp | 35 +- sakura_core/window/CSplitterWnd.cpp | 24 +- sakura_core/window/CSplitterWnd.h | 1 - sakura_core/window/CTabWnd.cpp | 181 ++++---- sakura_core/window/CTabWnd.h | 1 + 37 files changed, 491 insertions(+), 1068 deletions(-) diff --git a/.github/workflows/build-on-msys2.yml b/.github/workflows/build-on-msys2.yml index f9adee36b3..a6b9fe1b93 100644 --- a/.github/workflows/build-on-msys2.yml +++ b/.github/workflows/build-on-msys2.yml @@ -25,6 +25,8 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v5 + with: + submodules: true - name: Set up MSYS2 uses: msys2/setup-msys2@v2 diff --git a/.github/workflows/build-sakura.yml b/.github/workflows/build-sakura.yml index e868125871..40bb0909da 100644 --- a/.github/workflows/build-sakura.yml +++ b/.github/workflows/build-sakura.yml @@ -37,7 +37,7 @@ jobs: ## see https://github.com/actions/checkout - uses: actions/checkout@v5 with: - fetch-depth: 0 + submodules: true ## see https://github.com/microsoft/setup-msbuild - name: Add msbuild to PATH diff --git a/.github/workflows/sonarscan.yml b/.github/workflows/sonarscan.yml index 43705ca7ca..7701a13056 100644 --- a/.github/workflows/sonarscan.yml +++ b/.github/workflows/sonarscan.yml @@ -34,7 +34,7 @@ jobs: uses: actions/checkout@v5 with: ref: '${{ github.event.pull_request.head.sha }}' - fetch-depth: 0 + submodules: true - name: Setup environment variables run: | diff --git a/.gitmodules b/.gitmodules index d41dd11d1a..6529257a9e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "tests/googletest"] path = tests/googletest url = https://github.com/google/googletest.git +[submodule "externals/darkmodelib"] + path = externals/darkmodelib + url = https://github.com/ozone10/darkmodelib.git diff --git a/resource/mytool.bmp b/resource/mytool.bmp index 01a1591dee3f3ae5a201086902ef2ef67a571649..cb81c0b6f296f3baa1016577eb6d449f12ab4629 100644 GIT binary patch literal 63478 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%0D^2jxa%w92xd6t*0iw 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 X`hg2?w9-}M!ZTUC3%3FitImG~s5ETU diff --git a/sakura/sakura.vcxproj b/sakura/sakura.vcxproj index 433b6b59bc..6cb4b58dc7 100644 --- a/sakura/sakura.vcxproj +++ b/sakura/sakura.vcxproj @@ -54,7 +54,7 @@ - ..\sakura_core;%(AdditionalIncludeDirectories) + ..\sakura_core;..\externals\darkmodelib\include;%(AdditionalIncludeDirectories) _WIN32_WINNT=_WIN32_WINNT_WIN10;%(PreprocessorDefinitions) true true @@ -500,6 +500,16 @@ + + + + + + + + + + diff --git a/sakura/sakura.vcxproj.filters b/sakura/sakura.vcxproj.filters index 3444152fb6..217a0d122b 100644 --- a/sakura/sakura.vcxproj.filters +++ b/sakura/sakura.vcxproj.filters @@ -119,6 +119,9 @@ {930f3f82-ab3f-49e3-af4a-d4f9c2d51f46} + + {57c87b7d-0c3b-4adb-9840-ce2292af594e} + @@ -2309,6 +2312,36 @@ Cpp Source Files\parse + + Cpp Source Files\darkmodelib + + + Cpp Source Files\darkmodelib + + + Cpp Source Files\darkmodelib + + + Cpp Source Files\darkmodelib + + + Cpp Source Files\darkmodelib + + + Cpp Source Files\darkmodelib + + + Cpp Source Files\darkmodelib + + + Cpp Source Files\darkmodelib + + + Cpp Source Files\darkmodelib + + + Cpp Source Files\darkmodelib + diff --git a/sakura_core/CPropertyManager.cpp b/sakura_core/CPropertyManager.cpp index 309e4431e6..6c210703e1 100644 --- a/sakura_core/CPropertyManager.cpp +++ b/sakura_core/CPropertyManager.cpp @@ -13,6 +13,7 @@ #include "apiwrap/StdApi.h" #include #include "config/system_constants.h" +#include "DarkModeSubclass.h" void CPropertyManager::Create( HWND hwndOwner, CImageListMgr* pImageList, CMenuDrawer* pMenuDrawer ) { diff --git a/sakura_core/_main/CControlTray.cpp b/sakura_core/_main/CControlTray.cpp index 361dea5f04..df9194f744 100644 --- a/sakura_core/_main/CControlTray.cpp +++ b/sakura_core/_main/CControlTray.cpp @@ -390,30 +390,7 @@ LRESULT CControlTray::DispatchEvent( case WM_MENUCHAR: /* メニューアクセスキー押下時の処理(WM_MENUCHAR処理) */ return m_cMenuDrawer.OnMenuChar( hwnd, uMsg, wParam, lParam ); - case WM_DRAWITEM: - lpdis = (DRAWITEMSTRUCT*) lParam; /* 項目描画情報 */ - switch( lpdis->CtlType ){ - case ODT_MENU: /* オーナー描画メニュー */ - /* メニューアイテム描画 */ - m_cMenuDrawer.DrawItem( lpdis ); - return TRUE; - } - return FALSE; - case WM_MEASUREITEM: - lpmis = (MEASUREITEMSTRUCT*) lParam; // item-size information - switch( lpmis->CtlType ){ - case ODT_MENU: /* オーナー描画メニュー */ - /* メニューアイテムの描画サイズを計算 */ - nItemWidth = m_cMenuDrawer.MeasureItem( lpmis->itemID, &nItemHeight ); - if( 0 < nItemWidth ){ - lpmis->itemWidth = nItemWidth; - lpmis->itemHeight = nItemHeight; - } - return TRUE; - } - return FALSE; case WM_EXITMENULOOP: - m_cMenuDrawer.EndDrawMenu(); break; /* タスクトレイ左クリックメニューへのショートカットキー登録 */ diff --git a/sakura_core/_main/WinMain.cpp b/sakura_core/_main/WinMain.cpp index 66b8e4fd87..51902217b9 100644 --- a/sakura_core/_main/WinMain.cpp +++ b/sakura_core/_main/WinMain.cpp @@ -32,6 +32,7 @@ #include "version.h" #include "util/std_macro.h" #include "env/DLLSHAREDATA.h" +#include "DarkModeSubclass.h" /*! Windows Entry point @@ -71,6 +72,13 @@ int WINAPI wWinMain( DEBUG_TRACE(L"-- -- WinMain -- --\n"); DEBUG_TRACE(L"sizeof(DLLSHAREDATA) = %d\n",sizeof(DLLSHAREDATA)); +#if 1 + DarkMode::initDarkMode(); + //DarkMode::setDarkModeConfigEx(static_cast(DarkMode::DarkModeType::classic)); + DarkMode::setDarkModeConfigEx(static_cast(DarkMode::DarkModeType::dark)); + DarkMode::setDefaultColors(true); +#endif + //コマンドラインクラスのインスタンスを確保する CCommandLine cCommandLine; diff --git a/sakura_core/apiwrap/CommonControl.h b/sakura_core/apiwrap/CommonControl.h index 7a573a2ea9..ea4665fde7 100644 --- a/sakura_core/apiwrap/CommonControl.h +++ b/sakura_core/apiwrap/CommonControl.h @@ -77,6 +77,13 @@ namespace ApiWrap inline DWORD Toolbar_SetExtendedStyle(HWND hwndCtl, DWORD styles) { return (DWORD)::SendMessage(hwndCtl, TB_SETEXTENDEDSTYLE, 0L, (LPARAM)styles); } inline int Toolbar_GetState(HWND hwndCtl, int index) { return (int)::SendMessage(hwndCtl, TB_GETSTATE, (WPARAM)index, 0L); } inline BOOL Toolbar_SetState(HWND hwndCtl, int index, WORD state) { return (BOOL)::SendMessage(hwndCtl, TB_SETSTATE, (WPARAM)index, state); } + inline HIMAGELIST Toolbar_SetImageList(HWND hwndCtl, int index, HIMAGELIST hImageList) { return (HIMAGELIST)::SendMessage(hwndCtl, TB_SETIMAGELIST, (WPARAM)index, (LPARAM)hImageList); } + inline HIMAGELIST Toolbar_SetDisabledImageList(HWND hwndCtl, int index, HIMAGELIST hImageList) { return (HIMAGELIST)::SendMessage(hwndCtl, TB_SETDISABLEDIMAGELIST, (WPARAM)index, (LPARAM)hImageList); } + inline int Toolbar_LoadImages(HWND hwndCtl, int id) { return (int)::SendMessage(hwndCtl, TB_LOADIMAGES, (WPARAM)id, (LPARAM)HINST_COMMCTRL); } + inline void Toolbar_AutoSize(HWND hwndCtl) { ::SendMessage(hwndCtl, TB_AUTOSIZE, 0, 0); } + inline BOOL Toolbar_SetBitmapSize(HWND hwndCtl, int width, int height) { + return (BOOL)::SendMessage(hwndCtl, TB_SETBITMAPSIZE, 0, MAKELPARAM(width, height)); + } // -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- // // Tooltip コントロール // diff --git a/sakura_core/cmd/CViewCommander_Outline.cpp b/sakura_core/cmd/CViewCommander_Outline.cpp index d220bf7db5..0aed6d060a 100644 --- a/sakura_core/cmd/CViewCommander_Outline.cpp +++ b/sakura_core/cmd/CViewCommander_Outline.cpp @@ -28,6 +28,7 @@ #include "plugin/COutlineIfObj.h" #include "apiwrap/StdApi.h" #include "sakura_rc.h" +#include "DarkModeSubclass.h" /*! アウトライン解析 @@ -167,7 +168,7 @@ BOOL CViewCommander::Command_FUNCLIST( /* アウトライン ダイアログの表示 */ CLayoutPoint poCaret = GetCaret().GetCaretLayoutPos(); if( nullptr == GetEditWindow()->m_cDlgFuncList.GetHwnd() ){ - GetEditWindow()->m_cDlgFuncList.DoModeless( + HWND hWnd = GetEditWindow()->m_cDlgFuncList.DoModeless( G_AppInstance(), m_pCommanderView->GetHwnd(), (LPARAM)m_pCommanderView, @@ -178,6 +179,7 @@ BOOL CViewCommander::Command_FUNCLIST( nListType, m_pCommanderView->m_pTypeData->m_bLineNumIsCRLF /* 行番号の表示 false=折り返し単位/true=改行単位 */ ); + DarkMode::setDarkWndSafe(hWnd); }else{ /* アクティブにする */ GetEditWindow()->m_cDlgFuncList.Redraw( nOutlineType, nListType, &cFuncInfoArr, poCaret.GetY2() + 1, poCaret.GetX2() + 1 ); diff --git a/sakura_core/cmd/CViewCommander_Settings.cpp b/sakura_core/cmd/CViewCommander_Settings.cpp index 3b2fad2bc2..980b27b2d9 100644 --- a/sakura_core/cmd/CViewCommander_Settings.cpp +++ b/sakura_core/cmd/CViewCommander_Settings.cpp @@ -33,6 +33,7 @@ #include #include "config/system_constants.h" #include "config/app_constants.h" +#include "DarkModeSubclass.h" /*! ツールバーの表示/非表示 @@ -67,6 +68,10 @@ void CViewCommander::Command_SHOWFUNCKEY( void ) pCEditWnd->LayoutFuncKey(); pCEditWnd->EndLayoutBars(); + auto hWnd = pCEditWnd->GetHwnd(); + DarkMode::setChildCtrlsTheme(hWnd); + DarkMode::setWindowMenuBarSubclass(hWnd); + //全ウインドウに変更を通知する。 CAppNodeGroupHandle(0).PostMessageToAllEditors( MYWM_BAR_CHANGE_NOTIFY, diff --git a/sakura_core/dlg/CDialog.cpp b/sakura_core/dlg/CDialog.cpp index 7a4e7d3f7d..94387c5a03 100644 --- a/sakura_core/dlg/CDialog.cpp +++ b/sakura_core/dlg/CDialog.cpp @@ -34,6 +34,7 @@ #include "util/window.h" #include "apiwrap/StdApi.h" #include "apiwrap/StdControl.h" +#include "DarkModeSubclass.h" /* ダイアログプロシージャ */ INT_PTR CALLBACK MyDialogProc( @@ -187,6 +188,14 @@ BOOL CDialog::OnInitDialog( HWND hwndDlg, WPARAM wParam, LPARAM lParam ) m_hFontDialog = UpdateDialogFont( hwndDlg ); + // --- Dark Mode --- + auto hWnd = m_hWnd; + DarkMode::setColorizeTitleBarConfig(true); + DarkMode::setDarkWndNotifySafeEx(hWnd, true, true); + DarkMode::setWindowEraseBgSubclass(hWnd); + DarkMode::setWindowMenuBarSubclass(hWnd); + DarkMode::setWindowExStyle(hWnd, false, WS_EX_COMPOSITED); + /* ダイアログデータの設定 */ SetData(); diff --git a/sakura_core/outline/CDlgFuncList.cpp b/sakura_core/outline/CDlgFuncList.cpp index 7b4bda2695..82a2a2063d 100644 --- a/sakura_core/outline/CDlgFuncList.cpp +++ b/sakura_core/outline/CDlgFuncList.cpp @@ -55,6 +55,7 @@ #include "config/system_constants.h" #include "config/app_constants.h" #include "String_define.h" +#include "DarkModeSubclass.h" // 画面ドッキング用の定義 // 2010.06.05 ryoji #define DEFINE_SYNCCOLOR @@ -3114,33 +3115,30 @@ INT_PTR CDlgFuncList::OnNcPaint( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lPa default: break; } - ::MyFillRect( gr, rcWk, COLOR_3DFACE ); + //::MyFillRect( gr, rcWk, COLOR_3DFACE ); + ::MyFillRect(gr, rcWk, DarkMode::getBackgroundColor()); ::DrawEdge( gr, &rcWk, EDGE_ETCHED, BF_TOPLEFT ); // タイトルを描画する BOOL bThemeActive = ::IsThemeActive(); - BOOL bGradient = FALSE; - ::SystemParametersInfo( SPI_GETGRADIENTCAPTIONS, 0, &bGradient, 0 ); - if( !bThemeActive ) bGradient = FALSE; // 適当に調整 HWND hwndFocus = ::GetFocus(); BOOL bActive = (GetHwnd() == hwndFocus || ::IsChild(GetHwnd(), hwndFocus)); RECT rcCaption; GetCaptionRect( &rcCaption ); ::OffsetRect( &rcCaption, -rcScr.left, -rcScr.top ); rcWk = rcCaption; - rcWk.top += 1; - rcWk.right -= DOCK_BUTTON_NUM * (::GetSystemMetrics( SM_CXSMSIZE )); // ↓DrawCaption() に DC_SMALLCAP を指定してはいけないっぽい // ↓DC_SMALLCAP 指定のものを Win7(64bit版) で動かしてみたら描画位置が下にずれて上半分しか見えなかった(x86ビルド/x64ビルドのどちらも NG) - ::DrawCaption( hwnd, gr, &rcWk, DC_TEXT | (bGradient? DC_GRADIENT: 0) /*| DC_SMALLCAP*/ | (bActive? DC_ACTIVE: 0) ); - rcWk.left = rcCaption.right; - int nClrCaption; - if( bGradient ) - nClrCaption = ( bActive? COLOR_GRADIENTACTIVECAPTION: COLOR_GRADIENTINACTIVECAPTION ); - else - nClrCaption = ( bActive? COLOR_ACTIVECAPTION: COLOR_INACTIVECAPTION ); - ::MyFillRect( gr, rcWk, nClrCaption ); + gr.SetTextForeColor(DarkMode::getTextColor()); + gr.SetTextBackColor(DarkMode::getBackgroundColor()); + //::DrawCaption( hwnd, gr, &rcWk, DC_TEXT /*| DC_SMALLCAP*/ | (bActive? DC_ACTIVE: 0) ); + wchar_t buff[256]; + ::GetWindowText(GetHwnd(), buff, 256); + //COLORREF clrCaption = ::GetSysColor( bActive? COLOR_ACTIVECAPTION: COLOR_INACTIVECAPTION ); + COLORREF clrCaption = bActive ? DarkMode::getHotBackgroundColor() : DarkMode::getBackgroundColor(); + ::MyFillRect( gr, rcWk, clrCaption ); ::DrawEdge( gr, &rcCaption, BDR_SUNKENOUTER, BF_TOP ); + ::DrawText(gr, buff, -1, &rcCaption, DT_TOP|DT_LEFT); // タイトル上のボタンを描画する NONCLIENTMETRICS ncm; @@ -3170,8 +3168,8 @@ INT_PTR CDlgFuncList::OnNcPaint( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lPa int nClrCaptionText; // マウスカーソルがボタン上にあればハイライト if( ::PtInRect( &rcBtn, pt ) ){ - ::MyFillRect( gr, rcBtn, (bGradient && !bActive)? COLOR_INACTIVECAPTION: COLOR_ACTIVECAPTION ); - nClrCaptionText = ( (bGradient && !bActive)? COLOR_INACTIVECAPTIONTEXT: COLOR_CAPTIONTEXT ); + ::MyFillRect( gr, rcBtn, COLOR_ACTIVECAPTION ); + nClrCaptionText = COLOR_CAPTIONTEXT; }else{ nClrCaptionText = ( bActive? COLOR_CAPTIONTEXT: COLOR_INACTIVECAPTIONTEXT ); } diff --git a/sakura_core/print/CPrintPreview.cpp b/sakura_core/print/CPrintPreview.cpp index 0a89690515..0526d21df7 100644 --- a/sakura_core/print/CPrintPreview.cpp +++ b/sakura_core/print/CPrintPreview.cpp @@ -38,6 +38,7 @@ #include "sakura_rc.h" #include "config/system_constants.h" #include "String_define.h" +#include "DarkModeSubclass.h" #define MIN_PREVIEW_ZOOM 10 #define MAX_PREVIEW_ZOOM 400 @@ -1958,7 +1959,6 @@ void CPrintPreview::CreatePrintPreviewControls( void ) si.nPos = 0; si.nTrackPos = 1; ::SetScrollInfo( m_hwndVScrollBar, SB_CTL, &si, TRUE ); - ::ShowScrollBar( m_hwndVScrollBar, SB_CTL, TRUE ); /* 横スクロールバーの作成 */ m_hwndHScrollBar = ::CreateWindowEx( @@ -1983,7 +1983,6 @@ void CPrintPreview::CreatePrintPreviewControls( void ) si.nPos = 0; si.nTrackPos = 1; ::SetScrollInfo( m_hwndHScrollBar, SB_CTL, &si, TRUE ); - ::ShowScrollBar( m_hwndHScrollBar, SB_CTL, TRUE ); /* サイズボックスの作成 */ m_hwndSizeBox = ::CreateWindowEx( @@ -2000,7 +1999,12 @@ void CPrintPreview::CreatePrintPreviewControls( void ) CEditApp::getInstance()->GetAppInstance(), /* instance owning this window */ (LPVOID) nullptr /* pointer not needed */ ); - ::ShowWindow( m_hwndPrintPreviewBar, SW_SHOW ); + + DarkMode::setDarkWndSafe(m_hwndPrintPreviewBar); + DarkMode::setChildCtrlsTheme(m_pParentWnd->GetHwnd()); + ::ShowScrollBar(m_hwndVScrollBar, SB_CTL, TRUE); + ::ShowScrollBar(m_hwndHScrollBar, SB_CTL, TRUE); + ::ShowWindow(m_hwndPrintPreviewBar, SW_SHOW); /* WM_SIZE 処理 */ RECT rc1; diff --git a/sakura_core/prop/CPropComGeneral.cpp b/sakura_core/prop/CPropComGeneral.cpp index dc0e6dd2a2..aff4687341 100644 --- a/sakura_core/prop/CPropComGeneral.cpp +++ b/sakura_core/prop/CPropComGeneral.cpp @@ -28,6 +28,7 @@ #include "String_define.h" #include "recent/CRecentFile.h" #include "recent/CRecentFolder.h" +#include "DarkModeSubclass.h" //@@@ 2001.02.04 Start by MIK: Popup Help TYPE_NAME_ID SpecialScrollModeArr[] = { @@ -123,7 +124,6 @@ INT_PTR CPropGeneral::DispatchEvent( SetData( hwndDlg ); // Modified by KEITA for WIN64 2003.9.6 ::SetWindowLongPtr( hwndDlg, DWLP_USER, lParam ); - /* ユーザーがエディット コントロールに入力できるテキストの長さを制限する */ return TRUE; diff --git a/sakura_core/prop/CPropComToolbar.cpp b/sakura_core/prop/CPropComToolbar.cpp index 73df8cfd16..b782f3aed7 100644 --- a/sakura_core/prop/CPropComToolbar.cpp +++ b/sakura_core/prop/CPropComToolbar.cpp @@ -30,6 +30,7 @@ #include "sakura_rc.h" #include "sakura.hh" #include "String_define.h" +#include "DarkModeSubclass.h" //@@@ 2001.02.04 Start by MIK: Popup Help static const DWORD p_helpids[] = { //11000 @@ -573,25 +574,29 @@ void CPropToolbar::DrawToolBarItemList( DRAWITEMSTRUCT* pDis ) RECT rcFrame = rcText; // アイテム背景をウインドウ背景色で塗りつぶす - ::MyFillRect( pDis->hDC, rcItem, COLOR_WINDOW ); + ::MyFillRect( pDis->hDC, rcItem, DarkMode::getCtrlBackgroundColor() ); // 背景色と前景色 - int bkColor; - int textColor; + COLORREF bkColor; + COLORREF textColor; /* アイテムが選択されている */ if( pDis->itemState & ODS_SELECTED ){ - bkColor = COLOR_HIGHLIGHT; - textColor = COLOR_HIGHLIGHTTEXT; + //bkColor = ::GetSysColor(COLOR_HIGHLIGHT); + //textColor = ::GetSysColor(COLOR_HIGHLIGHTTEXT); + bkColor = ::GetSysColor(COLOR_HIGHLIGHT); + textColor = DarkMode::getTextColor(); }else{ - bkColor = COLOR_WINDOW; - textColor = COLOR_WINDOWTEXT; + //bkColor = ::GetSysColor(COLOR_WINDOW); + //textColor = ::GetSysColor(COLOR_WINDOWTEXT); + bkColor = DarkMode::getCtrlBackgroundColor(); + textColor = DarkMode::getTextColor(); } // デバイスコンテキストのオプションを設定する int bkModeOld = ::SetBkMode( pDis->hDC, TRANSPARENT ); - COLORREF bkColorOld = ::SetBkColor( pDis->hDC, ::GetSysColor( bkColor ) ); - COLORREF textColorOld = ::SetTextColor( pDis->hDC, ::GetSysColor( textColor ) ); + COLORREF bkColorOld = ::SetBkColor( pDis->hDC, bkColor ); + COLORREF textColorOld = ::SetTextColor( pDis->hDC, textColor ); // itemDataに紐づくボタン情報を取得する TBBUTTON tbb = m_pcMenuDrawer->getButton(pDis->itemData); @@ -618,7 +623,7 @@ void CPropToolbar::DrawToolBarItemList( DRAWITEMSTRUCT* pDis ) rcItem.left + cxEdge, rcItem.top + cyEdge + (rcItem.bottom - rcItem.top - cySmIcon) / 2, tbb.iBitmap, - ILD_NORMAL, + true, cxSmIcon, cySmIcon ); diff --git a/sakura_core/prop/CPropCommon.cpp b/sakura_core/prop/CPropCommon.cpp index 583681bbb1..ff0fae7c79 100644 --- a/sakura_core/prop/CPropCommon.cpp +++ b/sakura_core/prop/CPropCommon.cpp @@ -31,6 +31,7 @@ #include "apiwrap/StdControl.h" #include "sakura_rc.h" #include "String_define.h" +#include "DarkModeSubclass.h" int CPropCommon::SearchIntArr( int nKey, int* pnArr, int nArrNum ) { @@ -66,6 +67,7 @@ INT_PTR CPropCommon::DlgProc( pCPropCommon = ( CPropCommon* )(pPsp->lParam); if( nullptr != pCPropCommon ){ UpdateDialogFont( hwndDlg ); + DarkMode::setDarkWndSafe(hwndDlg); return (pCPropCommon->*DispatchPage)( hwndDlg, uMsg, wParam, pPsp->lParam ); }else{ return FALSE; @@ -94,6 +96,7 @@ INT_PTR CPropCommon::DlgProc2( pCPropCommon = ( CPropCommon* )(lParam); if( nullptr != pCPropCommon ){ UpdateDialogFont( hwndDlg ); + DarkMode::setDarkWndSafe(hwndDlg); return (pCPropCommon->*DispatchPage)( hwndDlg, uMsg, IDOK, lParam ); }else{ return FALSE; diff --git a/sakura_core/typeprop/CPropTypes.cpp b/sakura_core/typeprop/CPropTypes.cpp index 89c629b7fe..b976f22785 100644 --- a/sakura_core/typeprop/CPropTypes.cpp +++ b/sakura_core/typeprop/CPropTypes.cpp @@ -33,6 +33,7 @@ #include "env/DLLSHAREDATA.h" #include "sakura_rc.h" #include "String_define.h" +#include "DarkModeSubclass.h" // -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- // // メッセージ処理 // @@ -49,6 +50,7 @@ INT_PTR CALLBACK PropTypesCommonProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPA case WM_INITDIALOG: pPsp = (PROPSHEETPAGE*)lParam; pCPropTypes = reinterpret_cast(pPsp->lParam); + DarkMode::setDarkWndSafe(hwndDlg); if( nullptr != pCPropTypes ){ UpdateDialogFont( hwndDlg ); return (pCPropTypes->*pDispatch)( hwndDlg, uMsg, wParam, pPsp->lParam ); diff --git a/sakura_core/typeprop/CPropTypesColor.cpp b/sakura_core/typeprop/CPropTypesColor.cpp index 678da68f2d..59b41326d1 100644 --- a/sakura_core/typeprop/CPropTypesColor.cpp +++ b/sakura_core/typeprop/CPropTypesColor.cpp @@ -40,6 +40,7 @@ #include "apiwrap/StdControl.h" #include "config/app_constants.h" #include "String_define.h" +#include "DarkModeSubclass.h" namespace { //! カスタムカラー用の識別文字列 @@ -1094,7 +1095,7 @@ void CPropTypesColor::DrawColorListItem( DRAWITEMSTRUCT* pDis ) ColorInfo* pColorInfo; // RECT rc0,rc1,rc2; RECT rc1; - COLORREF cRim = (COLORREF)::GetSysColor( COLOR_3DSHADOW ); + COLORREF cRim = (COLORREF)DarkMode::getEdgeColor(); if( pDis == nullptr || pDis->itemData == 0 ) return; @@ -1109,27 +1110,27 @@ void CPropTypesColor::DrawColorListItem( DRAWITEMSTRUCT* pDis ) pColorInfo = (ColorInfo*)pDis->itemData; /* アイテム矩形塗りつぶし */ - gr.SetBrushColor( ::GetSysColor( COLOR_WINDOW ) ); + gr.SetBrushColor( DarkMode::getCtrlBackgroundColor() ); gr.FillMyRect( pDis->rcItem ); /* アイテムが選択されている */ if( pDis->itemState & ODS_SELECTED ){ - gr.SetBrushColor( ::GetSysColor( COLOR_HIGHLIGHT ) ); - gr.SetTextForeColor( ::GetSysColor( COLOR_HIGHLIGHTTEXT ) ); + gr.SetBrushColor(::GetSysColor(COLOR_HIGHLIGHT)); + gr.SetTextForeColor( DarkMode::getTextColor() ); }else{ - gr.SetBrushColor( ::GetSysColor( COLOR_WINDOW ) ); - gr.SetTextForeColor( ::GetSysColor( COLOR_WINDOWTEXT ) ); + gr.SetBrushColor(DarkMode::getCtrlBackgroundColor()); + gr.SetTextForeColor(DarkMode::getTextColor()); } const int xOffset = ::MulDiv(m_uFocusBorderWidth, 2, 3); const int yOffset = ::MulDiv(m_uFocusBorderHeight, 2, 3); // 少し重ならせる const int colorSampleWidth = DpiScaleX(12); - rc1.left += xOffset + DpiScaleX(16); rc1.top += yOffset; rc1.right -= 2 * (colorSampleWidth + xOffset) + DpiScaleX(2); rc1.bottom -= yOffset; /* 選択ハイライト矩形 */ gr.FillMyRect(rc1); + rc1.left += xOffset + DpiScaleX(16); /* テキスト */ ::SetBkMode( gr, TRANSPARENT ); SFontAttr sFontAttr; @@ -1152,7 +1153,7 @@ void CPropTypesColor::DrawColorListItem( DRAWITEMSTRUCT* pDis ) rc1.bottom = rc1.top + DpiScaleY(12); if( pColorInfo->m_bDisp ){ /* 色分け/表示する */ // 2006.04.26 ryoji テキスト色を使う(「ハイコントラスト黒」のような設定でも見えるように) - gr.SetPen( ::GetSysColor( COLOR_WINDOWTEXT ) ); + gr.SetPen( DarkMode::getTextColor() ); // チェックマークを2本の直線で描画する際に使用する3点の座標 const POINT pts[3] = { { rc1.left + DpiScaleX(2), rc1.top + DpiScaleY(3) }, // 左 @@ -1208,16 +1209,13 @@ void CPropTypesColor::DrawColorListItem( DRAWITEMSTRUCT* pDis ) /* 色選択ダイアログ */ BOOL CPropTypesColor::SelectColor( HWND hwndParent, COLORREF* pColor, DWORD* pCustColors ) { - CHOOSECOLOR cc; - cc.lStructSize = sizeof_raw( cc ); + CHOOSECOLOR cc = {sizeof(cc)}; cc.hwndOwner = hwndParent; cc.hInstance = nullptr; cc.rgbResult = *pColor; cc.lpCustColors = pCustColors; - cc.Flags = /*CC_PREVENTFULLOPEN |*/ CC_RGBINIT; - cc.lCustData = 0; - cc.lpfnHook = nullptr; - cc.lpTemplateName = nullptr; + cc.Flags = CC_FULLOPEN | CC_RGBINIT | CC_ENABLEHOOK; + cc.lpfnHook = static_cast(DarkMode::HookDlgProc); if( !::ChooseColor( &cc ) ){ return FALSE; } diff --git a/sakura_core/uiparts/CImageListMgr.cpp b/sakura_core/uiparts/CImageListMgr.cpp index 85813a082d..c768207278 100644 --- a/sakura_core/uiparts/CImageListMgr.cpp +++ b/sakura_core/uiparts/CImageListMgr.cpp @@ -41,6 +41,7 @@ CImageListMgr::CImageListMgr() : m_cx( 16 ), m_cy( 16 ) , m_cTrans( RGB( 0, 0, 0 )) , m_hIconBitmap( nullptr ) + , m_hDC( nullptr ) , m_nIconCount( MAX_TOOLBAR_ICON_COUNT ) { } @@ -85,10 +86,13 @@ CImageListMgr::~CImageListMgr() if( m_hIconBitmap != nullptr ){ DeleteObject( m_hIconBitmap ); } + if (m_hDC != nullptr) { + ::DeleteDC(m_hDC); + } } static -HBITMAP ConvertTo32bppBMP(HBITMAP hbmpSrc) +HBITMAP ConvertTo32bppBMP(HBITMAP hbmpSrc, uint32_t*& pBits, LONG& bmpWidth, LONG& bmpHeight) { BITMAP bmp; if (0 == GetObject(hbmpSrc, sizeof(BITMAP), &bmp )) { @@ -100,7 +104,7 @@ HBITMAP ConvertTo32bppBMP(HBITMAP hbmpSrc) BITMAPINFO bmi; bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader); bmi.bmiHeader.biWidth = bmp.bmWidth; - bmi.bmiHeader.biHeight = bmp.bmHeight; + bmi.bmiHeader.biHeight = -bmp.bmHeight; bmi.bmiHeader.biPlanes = bmp.bmPlanes; bmi.bmiHeader.biBitCount = 32; bmi.bmiHeader.biCompression = BI_RGB; @@ -109,7 +113,7 @@ HBITMAP ConvertTo32bppBMP(HBITMAP hbmpSrc) bmi.bmiHeader.biYPelsPerMeter = 0; bmi.bmiHeader.biClrUsed = 0; bmi.bmiHeader.biClrImportant = 0; - HBITMAP hdib = CreateDIBSection(nullptr, &bmi, DIB_RGB_COLORS, nullptr, nullptr, 0); + HBITMAP hdib = CreateDIBSection(nullptr, &bmi, DIB_RGB_COLORS, (void**)&pBits, nullptr, 0); if (hdib == nullptr) { return hbmpSrc; } @@ -132,6 +136,8 @@ HBITMAP ConvertTo32bppBMP(HBITMAP hbmpSrc) DeleteDC(hdcSrc); DeleteDC(hdcDst); DeleteObject(hbmpSrc); + bmpWidth = bmp.bmWidth; + bmpHeight = bmp.bmHeight; return hdib; } @@ -172,7 +178,7 @@ bool CImageListMgr::Create(HINSTANCE hInstance) } } - hRscbmp = ConvertTo32bppBMP(hRscbmp); + hRscbmp = ConvertTo32bppBMP(hRscbmp, m_pBits, m_bmpWidth, m_bmpHeight); // To Here 2001.7.1 GAE @@ -197,7 +203,7 @@ bool CImageListMgr::Create(HINSTANCE hInstance) m_cy = ::GetSystemMetrics( SM_CYSMICON ); // アイコンサイズが異なる場合、拡大縮小する - hRscbmp = ResizeToolIcons( hRscbmp, m_cTrans ); + hRscbmp = ResizeToolIcons( hRscbmp, m_pBits, m_bmpWidth, m_bmpHeight, m_cTrans ); if( hRscbmp == nullptr ){ // リソースからBitmapを読み込む hRscbmp = LoadMyToolFromModule( hInstance ); @@ -205,10 +211,10 @@ bool CImageListMgr::Create(HINSTANCE hInstance) return false; } - hRscbmp = ConvertTo32bppBMP(hRscbmp); + hRscbmp = ConvertTo32bppBMP(hRscbmp, m_pBits, m_bmpWidth, m_bmpHeight); // アイコンサイズが異なる場合、拡大縮小する - hRscbmp = ResizeToolIcons( hRscbmp, m_cTrans ); + hRscbmp = ResizeToolIcons( hRscbmp, m_pBits, m_bmpWidth, m_bmpHeight, m_cTrans ); if( hRscbmp == nullptr ){ return false; } @@ -217,281 +223,11 @@ bool CImageListMgr::Create(HINSTANCE hInstance) // クラスメンバに変更を保存する m_hIconBitmap = hRscbmp; - return true; -} - -/*! RGBQUADラッパー - * STLコンテナに入れられるよう == 演算子を実装したもの。 - */ -struct MyRGBQUAD : tagRGBQUAD -{ - using tagRGBQUAD::rgbRed; - using tagRGBQUAD::rgbGreen; - using tagRGBQUAD::rgbBlue; - using tagRGBQUAD::rgbReserved; - - MyRGBQUAD() noexcept - : tagRGBQUAD() - { - rgbBlue = 0; - rgbGreen = 0; - rgbRed = 0; - rgbReserved = 0; - } - bool operator == ( const RGBQUAD &rhs ) const noexcept - { - return rgbBlue == rhs.rgbBlue - && rgbGreen == rhs.rgbGreen - && rgbRed == rhs.rgbRed - && rgbReserved == rhs.rgbReserved; - } - bool operator != ( const RGBQUAD &rhs ) const noexcept - { - return !(*this == rhs); - } - operator COLORREF ( void ) const noexcept - { - return RGB( rgbRed, rgbGreen, rgbBlue ); - } -}; - -// HLS色情報タプル -typedef std::tuple _HlsTuple; -enum { HLS_H, HLS_S, HLS_L, }; - -/*! - * @brief RGB⇒HLS(円柱モデル)変換する - */ -_HlsTuple ToHLS( const COLORREF color ) -{ - auto R = (double) GetRValue( color ) / 255.; - auto G = (double) GetGValue( color ) / 255.; - auto B = (double) GetBValue( color ) / 255.; - auto MIN = std::min( { R, G, B } ); - auto MAX = std::max( { R, G, B } ); - auto M = MAX + MIN; - auto m = MAX - MIN; - double H; - if ( MIN == MAX ) { - H = std::numeric_limits::infinity(); - } - else if ( MIN == B ) { - H = 60. * (m == 0 ? 0 : ((G - R) / m)) + 60.; - } - else if ( MIN == R ) { - H = 60. * (m == 0 ? 0 : ((B - G) / m)) + 180.; - } - else if ( MIN == G ) { - H = 60. * (m == 0 ? 0 : ((R - B) / m)) + 300.; - } - auto L = M / 2.; - auto S = M == 0 ? 0 : m / (1 - std::abs( M - 1 )); - return std::make_tuple( H, S, L ); -} - -/*! - * @brief HLS(円柱モデル)⇒RGB変換する - */ -COLORREF FromHLS( const _HlsTuple &hls ) -{ - auto H = std::get( hls ); - auto S = std::get( hls ); - auto L = std::get( hls ); - - // 彩度の範囲を補正する - if ( S < 0 ) S = 0; - if ( 1 < S ) S = 1; - - // 輝度の範囲を補正する - if ( L < 0 ) L = 0; - if ( 1 < L ) L = 1; - - // 色相が無効値(=白黒)の場合 - if ( std::isinf( H ) ) { - return RGB( L * 255, L * 255, L * 255 ); - } - - // 色相の範囲を補正する - while ( H < 0 ) H = 360 - H; - while ( 360 <= H ) H = H - 360; - - double R, G, B; - double MIN = L + S * (1 - std::abs( 2 * L - 1 )) / 2; - double MAX = L - S * (1 - std::abs( 2 * L - 1 )) / 2; - if ( H < 60 ) { - R = MAX; - G = MAX + (MAX - MIN) * H / 60; - B = MIN; - } - else if ( H < 120 ) { - R = MIN + (MAX - MIN) * (120 - H) / 60; - G = MAX; - B = MIN; - } - else if ( H < 180 ) { - R = MIN; - G = MAX; - B = MIN + (MAX - MIN) * (H - 120) / 60; - } - else if ( H < 240 ) { - R = MIN; - G = MIN + (MAX - MIN) * (240 - H) / 60; - B = MAX; - } - else if ( H < 300 ) { - R = MIN + (MAX - MIN) * (H - 240) / 60; - G = MIN; - B = MAX; - } - else { //if ( H < 360 ) { - R = MAX; - G = MIN; - B = MIN + (MAX - MIN) * (360 - H) / 60; - } - return RGB( R * 255, G * 255, B * 255 ); -} - -/*! ビットマップの表示 灰色を透明描画 - - @author Nakatani - @date 2003.07.21 genta 以前のCMenuDrawerより移転復活 - @date 2003.08.27 Moca 背景は透過処理に変更し、colBkColorを削除 - @date 2010.01.30 syat 透明にする色を引数に移動 -*/ -void CImageListMgr::MyBitBlt( - HDC drawdc, - int nXDest, - int nYDest, - int nWidth, - int nHeight, - int nXSrc, - int nYSrc -) const -{ - // 仮想DCを生成してビットマップを展開する - const HBITMAP &bmpSrc = m_hIconBitmap; - HDC hdcSrc = ::CreateCompatibleDC( drawdc ); - HGDIOBJ bmpSrcOld = ::SelectObject( hdcSrc, bmpSrc ); - - // 透過色の変数名が分かりづらいので別名定義する - const COLORREF &cTransparent = m_cTrans; - - // 透過色を考慮して転送 - ::TransparentBlt( drawdc, nXDest, nYDest, nWidth, nHeight, - hdcSrc, nXSrc, nYSrc, cx(), cy(), cTransparent ); + m_hDC = ::CreateCompatibleDC(nullptr); - // 後始末 - ::SelectObject( hdcSrc, bmpSrcOld ); - ::DeleteDC( hdcSrc ); - return; -} - - -/*! メニューアイコンの淡色表示 - - @author Nakatani - - @date 2003.07.21 genta 以前のCMenuDrawerより移転復活 - @date 2003.08.27 Moca 背景色は透過処理する -*/ -void CImageListMgr::MyDitherBlt( HDC drawdc, int nXDest, int nYDest, - int nWidth, int nHeight, int nXSrc, int nYSrc ) const -{ - // 仮想DCを生成してビットマップを展開する - const HBITMAP &bmpSrc = m_hIconBitmap; - HDC hdcSrc = ::CreateCompatibleDC( drawdc ); - HGDIOBJ bmpSrcOld = ::SelectObject( hdcSrc, bmpSrc ); - - // 作業DCを作成 - HDC hdcWork = ::CreateCompatibleDC( drawdc ); - - // DIB作成 - BITMAPINFO bmi; - char* pBits; - BITMAPINFOHEADER& bmih = bmi.bmiHeader; - bmih.biSize = sizeof(BITMAPINFOHEADER); - bmih.biWidth = nWidth; - assert(nHeight > 0); - bmih.biHeight = -nHeight; // top down - bmih.biPlanes = 1; - bmih.biBitCount = 32; - bmih.biCompression = BI_RGB; - const int lineStride = ((((bmih.biWidth * bmih.biBitCount) + 31) & ~31) / 8); - bmih.biSizeImage = lineStride * nHeight; - bmih.biXPelsPerMeter = 0; - bmih.biYPelsPerMeter = 0; - bmih.biClrUsed = 0; - bmih.biClrImportant = 0; - HBITMAP bmpWork = ::CreateDIBSection(nullptr, &bmi, DIB_RGB_COLORS, (void**)&pBits, nullptr, 0); - HGDIOBJ bmpWorkOld = ::SelectObject( hdcWork, bmpWork ); - - // 作業DCに転送 - ::StretchBlt( hdcWork, 0, 0, nWidth, nHeight, - hdcSrc, nXSrc, nYSrc, cx(), cy(), SRCCOPY ); - - // ディザカラーを決める - // 淡色テキスト色が背景色と同じなら灰色に避ける、違うなら淡色テキストを使う。 - COLORREF grayText = ::GetSysColor( COLOR_GRAYTEXT ); - COLORREF btnFace = ::GetSysColor( COLOR_3DFACE ); - COLORREF textColor = grayText == btnFace ? RGB( 0x80, 0x80, 0x80 ) : grayText; - auto textColorH = ToHLS( textColor ); - double textColorL; - { - auto r = GetRValue( textColor ); - auto g = GetGValue( textColor ); - auto b = GetBValue( textColor ); - textColorL = (0.299 * r + 0.587 * g + 0.114 * b) / 255.0; //[0,1] - } - double textColorR = (1.0 - textColorL) / 255.0; - - // ディザカラー256諧調の配列を作る - std::array ditherColors; - for ( size_t i = 0; i < ditherColors.size(); ++i ) { - auto ditherColorH( textColorH ); - std::get(ditherColorH) = textColorL + i * textColorR; - ditherColors[i] = FromHLS( ditherColorH ); - } - - // 透過色の変数名が分かりづらいので別名定義する - const COLORREF cTransparent = m_cTrans; - - // スキャンライン全行を順に取得して処理する - for (auto n = 0; n < nHeight; ++n) { - - // スキャンラインを1ピクセルずつ処理する - auto pixels = reinterpret_cast(pBits); - for ( auto m = 0; m < nWidth; ++m ) { - MyRGBQUAD& px = pixels[m]; - - // 透過色はスキップする - if ( px == cTransparent ) continue; - - // ピクセル色をディザカラーに変換する - auto r = px.rgbRed; - auto g = px.rgbGreen; - auto b = px.rgbBlue; - auto mono = (77 * r + 150 * g + 29 * b) >> 8; //[0,255] - - // ディザカラーを書き込む - px.rgbRed = GetRValue( ditherColors[mono] ); - px.rgbGreen = GetGValue( ditherColors[mono] ); - px.rgbBlue = GetBValue( ditherColors[mono] ); - } + ::SelectObject(m_hDC, m_hIconBitmap); - pBits += lineStride; - } - - // 背景を透過させつつ転送 - ::TransparentBlt( drawdc, nXDest, nYDest, nWidth, nHeight, - hdcWork, 0, 0, nWidth, nHeight, cTransparent ); - - // 後始末 - ::SelectObject( hdcWork, bmpWorkOld ); - ::DeleteObject( bmpWork ); - ::DeleteDC( hdcWork ); - ::SelectObject( hdcSrc, bmpSrcOld ); - ::DeleteDC( hdcSrc ); - return; + return true; } /*! @@ -514,20 +250,42 @@ void CImageListMgr::MyDitherBlt( HDC drawdc, int nXDest, int nYDest, * @date 2007.11.02 ryoji アイコン番号が負の場合は描画しない */ bool CImageListMgr::DrawToolIcon( HDC drawdc, LONG x, LONG y, - int imageNo, DWORD fStyle, LONG cx, LONG cy ) const + int imageNo, bool enabled, LONG cx, LONG cy ) const { if ( m_hIconBitmap == nullptr ) return false; if ( imageNo < 0 || m_nIconCount < imageNo ) return false; - if ( (fStyle&ILD_MASK) == ILD_MASK ) { - MyDitherBlt( drawdc, x, y, cx, cy, - (imageNo % MAX_X) * m_cx, (imageNo / MAX_X) * m_cy ); - } else { - MyBitBlt( drawdc, x, y, cx, cy, - (imageNo % MAX_X) * m_cx, (imageNo / MAX_X) * m_cy ); + BLENDFUNCTION bf = { 0 }; + bf.BlendOp = AC_SRC_OVER; + bf.SourceConstantAlpha = enabled ? 255 : 127; // 0-255, 全体の不透明度 + bf.AlphaFormat = AC_SRC_ALPHA; // ピクセル単位の α を使う + ::AlphaBlend(drawdc, x, y, cx, cy, m_hDC, (imageNo % MAX_X) * m_cx, (imageNo / MAX_X) * m_cy, cx, cy, bf); + return true; +} + +bool CImageListMgr::DrawToolIcon(uint32_t* pixels, int imageNo, bool enabled, LONG cx, LONG cy) const +{ + if (m_hIconBitmap == nullptr) + return false; + if (imageNo < 0 || m_nIconCount < imageNo) + return false; + + auto sy = (imageNo / MAX_X) * m_cy; + auto sx = (imageNo % MAX_X) * m_cx; + for (LONG y = 0; y < cy; ++y) { + const auto* srcLine = &m_pBits[m_bmpWidth * (sy + y) + sx]; + auto* dstLine = &pixels[cx * y]; + for (LONG x = 0; x < cx; ++x) { + auto srcPixel = srcLine[x]; + if (!enabled && (srcPixel & 0xFF000000)) { + srcPixel = 0x80000000 | (0x00FFFFFF & srcPixel); + } + dstLine[x] = srcPixel; + } } + return true; } @@ -611,6 +369,9 @@ int CImageListMgr::Add( const WCHAR* szPath ) // ツールイメージをリサイズする HBITMAP CImageListMgr::ResizeToolIcons( HBITMAP bmpSrc, //!< [in] 変換前Bmpのハンドル + uint32_t*& pBits, + LONG& bmpWidth, + LONG& bmpHeight, COLORREF& clrTransparent //!< [out] 透過色 ) const noexcept { @@ -677,12 +438,36 @@ HBITMAP CImageListMgr::ResizeToolIcons( const int cxSmIcon = m_cx; const int cySmIcon = m_cy; + auto setAlpha = [&]() { + uint32_t* pixels = (uint32_t*)pBits; + auto clrTransparent = pixels[0]; + for (int j = 0; j < cxSmIcon * cols * cySmIcon * rows; ++j) { + uint32_t& pixel = pixels[j]; + if (pixel == clrTransparent) { + pixel = 0; + } + else { + pixel |= 0xFF000000; + } + } + }; // アイコンサイズが異なる場合、拡大縮小する if ( cx != cxSmIcon ) { // 作業DCを作成する HDC hdcWork = ::CreateCompatibleDC( hdcSrc ); - HBITMAP bmpWork = ::CreateCompatibleBitmap( hdcSrc, cxSmIcon * cols, cySmIcon * rows ); + + BITMAPINFO bmi = {}; + bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader); + bmi.bmiHeader.biWidth = cxSmIcon * cols; + bmi.bmiHeader.biHeight = -cySmIcon * rows; + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 32; + bmi.bmiHeader.biCompression = BI_RGB; + + bmpWidth = cxSmIcon * cols; + bmpHeight = cySmIcon * rows; + HBITMAP bmpWork = CreateDIBSection(nullptr, &bmi, DIB_RGB_COLORS, (void**)&pBits, nullptr, 0); HGDIOBJ bmpWorkOld = ::SelectObject( hdcWork, bmpWork ); // 作業DCを透過色で塗りつぶす @@ -698,7 +483,7 @@ HBITMAP CImageListMgr::ResizeToolIcons( for ( int row = 0; row < rows; ++row ) { for ( int col = 0; col < cols; ++col ) { // 拡大・縮小する - ::TransparentBlt( + ::StretchBlt( hdcWork, col * cxSmIcon, row * cySmIcon, @@ -709,11 +494,13 @@ HBITMAP CImageListMgr::ResizeToolIcons( row * cy, cx, cy, - m_cTrans + SRCCOPY ); } } + setAlpha(); + // 作業DCで元Bmpを選択して変換後Bmpを解放する ::SelectObject( hdcWork, bmpWorkOld ); @@ -731,6 +518,9 @@ HBITMAP CImageListMgr::ResizeToolIcons( return bmpWork; } + else { + setAlpha(); + } // 仮想DCで元Bmpを選択して変換前Bmpを解放する ::SelectObject( hdcSrc, hFOldbmp ); @@ -748,30 +538,26 @@ void CImageListMgr::Extend(bool bExtend) if( curY < MAX_Y ) curY = MAX_Y; - HDC hSrcDC = ::CreateCompatibleDC( nullptr ); - HBITMAP hSrcBmpOld = (HBITMAP)::SelectObject( hSrcDC, m_hIconBitmap ); + ::SelectObject( m_hDC, m_hIconBitmap ); //1行拡張したビットマップを作成 - HDC hDestDC = ::CreateCompatibleDC( hSrcDC ); - HBITMAP hDestBmp = ::CreateCompatibleBitmap( hSrcDC, MAX_X * cx(), (curY + (bExtend ? 1 : 0)) * cy() ); - HBITMAP hDestBmpOld = (HBITMAP)::SelectObject( hDestDC, hDestBmp ); + HDC hDestDC = ::CreateCompatibleDC( nullptr ); + HBITMAP hDestBmp = ::CreateCompatibleBitmap( hDestDC, MAX_X * cx(), (curY + (bExtend ? 1 : 0)) * cy() ); + ::SelectObject( hDestDC, hDestBmp ); - ::BitBlt( hDestDC, 0, 0, MAX_X * cx(), curY * cy(), hSrcDC, 0, 0, SRCCOPY ); + ::BitBlt( hDestDC, 0, 0, MAX_X * cx(), curY * cy(), m_hDC, 0, 0, SRCCOPY ); //拡張した部分は透過色で塗る if( bExtend ){ FillSolidRect( hDestDC, 0, curY * cy(), MAX_X * cx(), cy(), m_cTrans ); } - ::SelectObject( hSrcDC, hSrcBmpOld ); ::DeleteObject( m_hIconBitmap ); - ::DeleteDC( hSrcDC ); - - ::SelectObject( hDestDC, hDestBmpOld ); - ::DeleteDC( hDestDC ); + ::DeleteDC( m_hDC ); //ビットマップの差し替え m_hIconBitmap = hDestBmp; + m_hDC = hDestDC; } void CImageListMgr::ResetExtend() diff --git a/sakura_core/uiparts/CImageListMgr.h b/sakura_core/uiparts/CImageListMgr.h index 81031ce22a..707ab3486b 100644 --- a/sakura_core/uiparts/CImageListMgr.h +++ b/sakura_core/uiparts/CImageListMgr.h @@ -61,7 +61,9 @@ class CImageListMgr { @param [in] cy アイコン高さ */ bool DrawToolIcon( HDC drawdc, LONG x, LONG y, - int imageNo, DWORD fStyle, LONG cx, LONG cy ) const; + int imageNo, bool enabled, LONG cx, LONG cy ) const; + + bool DrawToolIcon(uint32_t* pixels, int imageNo, bool enabled, LONG cx, LONG cy) const; //! アイコン数を返す int Count(void) const; // アイコン数 @@ -77,17 +79,6 @@ class CImageListMgr { //! アイコンの追加を元に戻す void ResetExtend(); - /*! - イメージのToolBarへの登録 - - @param hToolBar [in] 登録するToolBar - @param id [in] 登録する先頭アイコン番号 - - @date 2003.07.21 genta ここでは何も行わないが,受け皿だけ残しておく - @date 2003.07.21 genta 戻り型をvoidに変更 - */ - void SetToolBarImages(HWND hToolBar, int id = 0) const {} - protected: int m_cx; //!< width of icon int m_cy; //!< height of icon @@ -102,17 +93,16 @@ class CImageListMgr { @date 2003.07.21 genta */ HBITMAP m_hIconBitmap; + uint32_t* m_pBits = nullptr; + LONG m_bmpWidth = 0; + LONG m_bmpHeight = 0; - int m_nIconCount; //!< アイコンの個数 + HDC m_hDC; - // アイコン描画関数 - void MyBitBlt( HDC drawdc, int nXDest, int nYDest, - int nWidth, int nHeight, int nXSrc, int nYSrc ) const; - void MyDitherBlt( HDC drawdc, int nXDest, int nYDest, - int nWidth, int nHeight, int nXSrc, int nYSrc ) const; + int m_nIconCount; //!< アイコンの個数 //! ツールイメージをリサイズする - HBITMAP ResizeToolIcons( HBITMAP hRscbmp, COLORREF& clrTransparent ) const noexcept; + HBITMAP ResizeToolIcons( HBITMAP hRscbmp, uint32_t*& pBits, LONG& bmpWidth, LONG& bmpHeight, COLORREF& clrTransparent ) const noexcept; //! ビットマップを一行拡張する void Extend(bool = true); diff --git a/sakura_core/uiparts/CMenuDrawer.cpp b/sakura_core/uiparts/CMenuDrawer.cpp index 704d73b04c..76703cb10d 100644 --- a/sakura_core/uiparts/CMenuDrawer.cpp +++ b/sakura_core/uiparts/CMenuDrawer.cpp @@ -28,12 +28,12 @@ #include "func/CKeyBind.h" #include "uiparts/CGraphics.h" #include "util/window.h" +#include "DarkModeSubclass.h" +#include "CEditApp.h" +#include "sakura_rc.h" -// メニューアイコンの背景をボタンの色にする -#define DRAW_MENU_ICON_BACKGROUND_3DFACE - -// メニューの選択色を淡くする -#define DRAW_MENU_SELECTION_LIGHT +#include +#include // @date 2002.2.17 YAZAKI CShareDataのインスタンスは、CProcessにひとつあるのみ。 CMenuDrawer::CMenuDrawer() @@ -726,7 +726,26 @@ void CMenuDrawer::Create( HINSTANCE hInstance, HWND hWndOwner, CImageListMgr* pc m_hInstance = hInstance; m_hWndOwner = hWndOwner; m_pcIcons = pcIcons; - + m_dibs.resize(pcIcons->Count()); + + BITMAPINFO bminfo = {}; + BITMAPINFOHEADER& bmih = bminfo.bmiHeader; + bmih.biSize = sizeof(BITMAPINFOHEADER); + auto cx = ::GetSystemMetrics(SM_CXSMICON); + auto cy = ::GetSystemMetrics(SM_CYSMICON); + bmih.biWidth = (LONG)cx; + bmih.biHeight = -(LONG)cy; + bmih.biPlanes = 1; + bmih.biBitCount = 32; + bmih.biCompression = BI_RGB; + HDC hdc = CreateCompatibleDC(nullptr); + for (int i = 0; i < pcIcons->Count(); ++i) { + DIB& dib = m_dibs[i]; + dib.hBMP = ::CreateDIBSection(hdc, &bminfo, DIB_RGB_COLORS, &dib.pvBits, nullptr, 0); + ::SelectObject(hdc, dib.hBMP); + m_pcIcons->DrawToolIcon(hdc, 0, 0, i, true, cx, cy); + } + ::DeleteDC(hdc); return; } @@ -808,58 +827,49 @@ void CMenuDrawer::MyAppendMenu( _countof(szLabel) ); - /* アイコン用ビットマップを持つものは、オーナードロウにする */ { MyMenuItemInfo item; - item.m_nBitmapIdx = -1; item.m_nFuncId = nFuncId; item.m_cmemLabel.SetString( szLabel ); - // メニュー項目をオーナー描画にして、アイコンを表示する - // 2010.03.29 アクセスキーの分を詰めるためいつもオーナードローにする。ただしVista未満限定 - // Vista以上ではメニューもテーマが適用されるので、オーナードローにすると見た目がXP風になってしまう。 - if( m_pShareData->m_Common.m_sWindow.m_bMenuIcon ){ - nFlagAdd = MF_OWNERDRAW; - } /* 機能のビットマップの情報を覚えておく */ item.m_nBitmapIdx = GetIconIdByFuncId( nForceIconId ); + if( m_pShareData->m_Common.m_sWindow.m_bMenuIcon && item.m_nBitmapIdx != -1 ){ + nFlagAdd = MF_BITMAP; + } m_menuItems.push_back( item ); } }else{ -#ifdef DRAW_MENU_ICON_BACKGROUND_3DFACE - // セパレータかサブメニュー - if( nFlag & (MF_SEPARATOR | MF_POPUP) ){ - if( m_pShareData->m_Common.m_sWindow.m_bMenuIcon ){ - nFlagAdd = MF_OWNERDRAW; - } - } -#endif } // メニュー項目に関する情報を設定します。 MENUITEMINFO mii = { sizeof(MENUITEMINFO) }; mii.cbSize = sizeof(MENUITEMINFO); - mii.fMask = MIIM_CHECKMARKS | MIIM_DATA | MIIM_ID | MIIM_STATE | MIIM_SUBMENU | MIIM_TYPE; + mii.fMask = MIIM_CHECKMARKS | MIIM_DATA | MIIM_ID | MIIM_STATE | MIIM_SUBMENU | MIIM_FTYPE | MIIM_STRING; mii.fType = 0; - if( MF_OWNERDRAW & ( nFlag | nFlagAdd ) ) mii.fType |= MFT_OWNERDRAW; if( MF_SEPARATOR & ( nFlag | nFlagAdd ) ) mii.fType |= MFT_SEPARATOR; if( MF_STRING & ( nFlag | nFlagAdd ) ) mii.fType |= MFT_STRING; if( MF_MENUBREAK & ( nFlag | nFlagAdd ) ) mii.fType |= MFT_MENUBREAK; if( MF_MENUBARBREAK & ( nFlag | nFlagAdd ) ) mii.fType |= MFT_MENUBARBREAK; mii.fState = 0; - if( MF_GRAYED & ( nFlag | nFlagAdd ) ) mii.fState |= MFS_GRAYED; + //if( MF_GRAYED & ( nFlag | nFlagAdd ) ) mii.fState |= MFS_GRAYED; if( MF_CHECKED & ( nFlag | nFlagAdd ) ) mii.fState |= MFS_CHECKED; mii.wID = nFuncId; mii.hSubMenu = (nFlag&MF_POPUP)?((HMENU)nFuncId):nullptr; mii.hbmpChecked = nullptr; mii.hbmpUnchecked = nullptr; + if (MF_BITMAP & (nFlag | nFlagAdd)) { + mii.fMask |= MIIM_BITMAP; + mii.hbmpItem = m_dibs[GetIconIdByFuncId(nForceIconId)].hBMP; + } mii.dwItemData = (ULONG_PTR)this; mii.dwTypeData = szLabel; mii.cch = 0; // メニュー内の指定された位置に、新しいメニュー項目を挿入します。 ::InsertMenuItem( hMenu, 0xFFFFFFFF, TRUE, &mii ); + return; } @@ -891,418 +901,6 @@ inline int CMenuDrawer::GetIconIdByFuncId( int nFuncID ) const return m_tbMyButton[index].iBitmap; } -/*! メニューアイテムの描画サイズを計算 - @param pnItemHeight [out] 高さ。いつも高さを返す - @retval 0 機能がない場合 - @retval 1 <= val 機能のメニュー幅/セパレータの場合はダミーの値 -*/ -int CMenuDrawer::MeasureItem( int nFuncID, int* pnItemHeight ) -{ - // pixel数をベタ書きするとHighDPI環境でずれるのでシステム値を取得して使う - const int cxBorder = ::GetSystemMetrics(SM_CXBORDER); - const int cyBorder = ::GetSystemMetrics(SM_CYBORDER); - const int cxEdge = ::GetSystemMetrics(SM_CXEDGE); - const int cyEdge = ::GetSystemMetrics(SM_CYEDGE); - const int cxFrame = ::GetSystemMetrics(SM_CXFRAME); - const int cyFrame = ::GetSystemMetrics(SM_CYFRAME); - const int cxSmIcon = ::GetSystemMetrics(SM_CXSMICON); - const int cySmIcon = ::GetSystemMetrics(SM_CYSMICON); - - const WCHAR* pszLabel; - CMyRect rc, rcSp; - HDC hdc; - HFONT hFontOld; - - if( F_0 == nFuncID ){ // F_0, なぜか F_SEPARATOR ではない - // セパレータ。フォントの方の通常項目の半分の高さ - *pnItemHeight = m_nMenuFontHeight / 2; - return 30; // ダミーの幅 - }else if( nullptr == ( pszLabel = GetLabel( nFuncID ) ) ){ - *pnItemHeight = m_nMenuHeight; - return 0; - } - //正常な高さは幅と一緒に決める - - hdc = ::GetDC( m_hWndOwner ); - hFontOld = (HFONT)::SelectObject( hdc, m_hFontMenu ); - // DT_EXPANDTABSをやめる - ::DrawText( hdc, pszLabel, -1, &rc, DT_SINGLELINE | DT_VCENTER | DT_CALCRECT ); - ::SelectObject( hdc, hFontOld ); - ::ReleaseDC( m_hWndOwner, hdc ); - -// *pnItemHeight = 20; -// *pnItemHeight = 2 + 15 + 1; - //@@@ 2002.2.2 YAZAKI Windowsの設定でメニューのフォントを大きくすると表示が崩れる問題に対処 - - // インデント + テキスト幅 + アクセスキー隙間 - int nMenuWidth = cxSmIcon / 4 + rc.Width() + cxSmIcon / 2; - if( m_pShareData->m_Common.m_sWindow.m_bMenuIcon ){ - // アイコンと枠 + 縦線隙間 + 縦線 - // 2+[2+16+2]+2 + 2+2 + 1 - nMenuWidth += cxSmIcon + cxEdge * 6 + cxBorder; - }else{ - // WM_MEASUREITEMで報告するメニュー幅より実際の幅は1文字分相当位広いので、その分は加えない - nMenuWidth += ::GetSystemMetrics(SM_CXMENUCHECK) + 2 + 2; - } - // アイコンと枠 or フォント高さと太枠 - // 2+[2+16+2]+2 or 2+9+2 - *pnItemHeight = std::max(cySmIcon + cyEdge * 4, m_nMenuHeight + cyEdge * 2); - return nMenuWidth; -} - -/*! メニューアイテム描画 - @date 2001.12.21 YAZAKI デバッグモードでもメニューを選択したらハイライト。 - @date 2003.08.27 Moca システムカラーのブラシはCreateSolidBrushをやめGetSysColorBrushに - @date 2010.07.24 Moca アイコン部分をボタン色にしてフラット表示にするなどの変更 - 大きいフォント、黒背景対応 -*/ -void CMenuDrawer::DrawItem( DRAWITEMSTRUCT* lpdis ) -{ - // pixel数をベタ書きするとHighDPI環境でずれるのでシステム値を取得して使う - const int cxBorder = ::GetSystemMetrics(SM_CXBORDER); - const int cyBorder = ::GetSystemMetrics(SM_CYBORDER); - const int cxEdge = ::GetSystemMetrics(SM_CXEDGE); - const int cyEdge = ::GetSystemMetrics(SM_CYEDGE); - const int cxFrame = ::GetSystemMetrics(SM_CXFRAME); - const int cyFrame = ::GetSystemMetrics(SM_CYFRAME); - const int cxSmIcon = ::GetSystemMetrics(SM_CXSMICON); - const int cySmIcon = ::GetSystemMetrics(SM_CYSMICON); - - CMyRect rcItem( lpdis->rcItem ); - - const bool bMenuIconDraw = !!m_pShareData->m_Common.m_sWindow.m_bMenuIcon; - const int nCxCheck = ::GetSystemMetrics(SM_CXMENUCHECK); - const int nCyCheck = ::GetSystemMetrics(SM_CYMENUCHECK); - - // アイコンとテキストの間の縦線の位置 - const int nIndentLeft = bMenuIconDraw - ? cxSmIcon + cxEdge * 6 + cxBorder - : cxEdge * 2 + nCxCheck; - - // サブメニューの|>の分は必要 最低8ぐらい - const int nIndentRight = cxSmIcon / 2; - - // 2010.07.24 Moca アイコンを描くときにチラつくので、バックサーフェスを使う - const bool bBackSurface = bMenuIconDraw; - const int nTargetWidth = lpdis->rcItem.right - lpdis->rcItem.left; - const int nTargetHeight = lpdis->rcItem.bottom - lpdis->rcItem.top; - HDC hdcOrg = nullptr; - HDC hdc = nullptr; - if( bBackSurface ){ - hdcOrg = lpdis->hDC; - if( m_hCompDC && nTargetWidth <= m_nCompBitmapWidth && nTargetHeight <= m_nCompBitmapHeight ){ - hdc = m_hCompDC; - }else{ - if( m_hCompDC ){ - DeleteCompDC(); - } - hdc = m_hCompDC = ::CreateCompatibleDC( hdcOrg ); - m_hCompBitmap = ::CreateCompatibleBitmap( hdcOrg, nTargetWidth + 20, nTargetHeight + 4 ); - m_hCompBitmapOld = (HBITMAP)::SelectObject( hdc, m_hCompBitmap ); - m_nCompBitmapWidth = nTargetWidth + 20; - m_nCompBitmapHeight = nTargetHeight + 4; - } - ::SetWindowOrgEx( hdc, lpdis->rcItem.left, lpdis->rcItem.top, nullptr ); - }else{ - hdc = lpdis->hDC; - } - - // 作画範囲を背景色で矩形塗りつぶし - if( lpdis->itemState & ODS_SELECTED ){ - // アイテムが選択されている - RECT rc1 = lpdis->rcItem; - if( bMenuIconDraw -#ifdef DRAW_MENU_ICON_BACKGROUND_3DFACE -#else - && -1 != m_menuItems[nItemIndex].m_nBitmapIdx || lpdis->itemState & ODS_CHECKED -#endif - ){ - //rc1.left += (nIndentLeft - 3); - } -#ifdef DRAW_MENU_SELECTION_LIGHT - HPEN hPenBorder = ::CreatePen( PS_SOLID, 1, ::GetSysColor( COLOR_HIGHLIGHT ) ); - HPEN hOldPen = (HPEN)::SelectObject( hdc, hPenBorder ); - COLORREF colHilight = ::GetSysColor( COLOR_HIGHLIGHT ); - COLORREF colMenu = ::GetSysColor( COLOR_MENU ); - BYTE valR = ((GetRValue(colHilight) * 4 + GetRValue(colMenu) * 6) / 10) | 0x18; - BYTE valG = ((GetGValue(colHilight) * 4 + GetGValue(colMenu) * 6) / 10) | 0x18; - BYTE valB = ((GetBValue(colHilight) * 4 + GetBValue(colMenu) * 6) / 10) | 0x18; - HBRUSH hBrush = ::CreateSolidBrush( RGB(valR, valG, valB) ); - HBRUSH hOldBrush = (HBRUSH)::SelectObject( hdc, hBrush ); - ::Rectangle( hdc, rc1.left, rc1.top, rc1.right, rc1.bottom ); - ::SelectObject( hdc, hOldPen ); - ::SelectObject( hdc, hOldBrush ); - ::DeleteObject( hPenBorder ); - ::DeleteObject( hBrush ); -#else - /* 選択ハイライト矩形 */ - ::MyFillRect( hdc, rc1, COLOR_HIGHLIGHT ); -#endif -#ifdef DRAW_MENU_ICON_BACKGROUND_3DFACE - }else if( bMenuIconDraw ){ - // アイコン部分の背景を灰色にする - CMyRect rcFillMenuBack( rcItem ); - rcFillMenuBack.left += nIndentLeft; - ::MyFillRect( hdc, rcFillMenuBack, COLOR_MENU ); - -// hBrush = ::GetSysColorBrush( COLOR_3DFACE ); - COLORREF colMenu = ::GetSysColor( COLOR_MENU ); - COLORREF colFace = ::GetSysColor( COLOR_3DFACE ); - COLORREF colIconBack; - // 明度らしきもの - if( 64 < t_abs(t_max(t_max(GetRValue(colFace),GetGValue(colFace)),GetBValue(colFace)) - - t_max(t_max(GetRValue(colMenu),GetGValue(colMenu)),GetBValue(colMenu))) ){ - colIconBack = colFace; - }else{ - // 明るさが近いなら混色にして(XPテーマ等で)違和感を減らす - BYTE valR = ((GetRValue(colFace) * 7 + GetRValue(colMenu) * 3) / 10); - BYTE valG = ((GetGValue(colFace) * 7 + GetGValue(colMenu) * 3) / 10); - BYTE valB = ((GetBValue(colFace) * 7 + GetBValue(colMenu) * 3) / 10); - colIconBack = RGB(valR, valG, valB); - } - - CMyRect rcIconBk( rcItem ); - rcIconBk.right = rcItem.left + nIndentLeft; - ::MyFillRect( hdc, rcIconBk, colIconBack ); - - }else{ - // アイテム矩形塗りつぶし - ::MyFillRect( hdc, lpdis->rcItem, COLOR_MENU ); - } -#else - }else{ - ::MyFillRect( hdc, lpdis->rcItem, COLOR_MENU ); - } -#endif - - if( bMenuIconDraw ){ - // アイコンとテキストの間に縦線を描画する - int nSepColor = (::GetSysColor(COLOR_3DSHADOW) != ::GetSysColor(COLOR_MENU) ? COLOR_3DSHADOW : COLOR_3DHIGHLIGHT); - HPEN hPen = ::CreatePen( PS_SOLID, cxBorder, ::GetSysColor(nSepColor) ); - HPEN hPenOld = (HPEN)::SelectObject( hdc, hPen ); - ::MoveToEx( hdc, lpdis->rcItem.left + nIndentLeft, lpdis->rcItem.top, nullptr ); - ::LineTo( hdc, lpdis->rcItem.left + nIndentLeft, lpdis->rcItem.bottom ); - ::SelectObject( hdc, hPenOld ); - ::DeleteObject( hPen ); - - } - - if( lpdis->itemID == F_0 ){ - // セパレータの作画(セパレータのFuncCodeはF_SEPARETORではなくF_0) - int y = lpdis->rcItem.top + (lpdis->rcItem.bottom - lpdis->rcItem.top) / 2; - int nSepColor = (::GetSysColor(COLOR_3DSHADOW) != ::GetSysColor(COLOR_MENU) ? COLOR_3DSHADOW : COLOR_3DHIGHLIGHT); - HPEN hPen = ::CreatePen( PS_SOLID, 1, ::GetSysColor(nSepColor) ); - HPEN hPenOld = (HPEN)::SelectObject( hdc, hPen ); - ::MoveToEx( hdc, lpdis->rcItem.left + (bMenuIconDraw ? nIndentLeft : cxEdge + cxBorder) + cxEdge, y, nullptr ); - ::LineTo( hdc, lpdis->rcItem.right - cxEdge, y ); - ::SelectObject( hdc, hPenOld ); - ::DeleteObject( hPen ); - - if( bBackSurface ){ - ::BitBlt( hdcOrg, lpdis->rcItem.left, lpdis->rcItem.top, nTargetWidth, nTargetHeight, - hdc, lpdis->rcItem.left, lpdis->rcItem.top, SRCCOPY ); - } - return; // セパレータ。作画終了 - } - - // テキスト前景色を決定する - COLORREF textColor; - if( lpdis->itemState & ODS_DISABLED ){ - // アイテムが使用不可(淡色表示にする) - textColor = ::GetSysColor( COLOR_GRAYTEXT ); - }else if( lpdis->itemState & ODS_SELECTED ){ -#ifdef DRAW_MENU_SELECTION_LIGHT - textColor = ::GetSysColor( COLOR_MENUTEXT ); -#else - textColor = ::GetSysColor( COLOR_HIGHLIGHTTEXT ); -#endif - }else{ - textColor = ::GetSysColor( COLOR_MENUTEXT ); - } - -#ifdef _DEBUG - // デバッグ用:メニュー項目に対して、ヘルプがない場合に前景色を青くする - // メニュー項目に関する情報を取得します。 - MENUITEMINFO mii = { sizeof(MENUITEMINFO) }; - mii.fMask = MIIM_ID | MIIM_STATE | MIIM_SUBMENU; - if( 0 != ::GetMenuItemInfo( (HMENU)lpdis->hwndItem, lpdis->itemID, FALSE, &mii ) - && nullptr == mii.hSubMenu - && 0 == ::FuncID_To_HelpContextID( (EFunctionCode)lpdis->itemID ) /* 機能IDに対応するメニューコンテキスト番号を返す */ - ){ - //@@@ 2001.12.21 YAZAKI - if( lpdis->itemState & ODS_SELECTED ){ - textColor = ::GetSysColor( COLOR_HIGHLIGHTTEXT ); // ハイライトカラー - } - else { - textColor = RGB( 0, 0, 255 ); // 青くしてる。 - } - } -#endif - - // テキスト矩形(インデント込み) - CMyRect rcText( lpdis->rcItem ); - rcText.left += nIndentLeft + cxSmIcon / 4; - rcText.right -= nIndentRight; - - const int nItemIndex = Find( (int)lpdis->itemID ); - LPCWSTR pszItemStr = m_menuItems[nItemIndex].m_cmemLabel.GetStringPtr(); - size_t nItemStrLen = m_menuItems[nItemIndex].m_cmemLabel.GetStringLength(); - - int nBkModeOld = ::SetBkMode( hdc, TRANSPARENT ); - HFONT hFontOld = (HFONT)::SelectObject( hdc, m_hFontMenu ); - COLORREF textColorOld = (COLORREF)::SetTextColor( hdc, textColor ); - - /* TAB文字の前と後ろに分割してテキストを描画する */ - size_t j; - for( j = 0; j < nItemStrLen; ++j ){ - if( pszItemStr[j] == L'\t' ){ - break; - } - } - /* TAB文字の前側のテキストを描画する */ - ::DrawText( - hdc, - pszItemStr, - static_cast(j), - &rcText, - DT_LEFT | DT_VCENTER | DT_SINGLELINE - ); - /* TAB文字の後ろ側のテキストを描画する */ - if( j < nItemStrLen ){ - ::DrawText( - hdc, - &pszItemStr[j + 1], - static_cast(nItemStrLen - ( j + 1 )), - &rcText, - DT_RIGHT | DT_VCENTER | DT_SINGLELINE - ); - } - ::SetTextColor( hdc, textColorOld ); - ::SelectObject( hdc, hFontOld ); - ::SetBkMode( hdc, nBkModeOld ); - - // アイコン矩形 - CMyRect rcIcon( rcItem ); - rcIcon.left += ( rcItem.Height() - m_pcIcons->cy() ) / 2; - rcIcon.top += ( rcItem.Height() - m_pcIcons->cy() ) / 2; - rcIcon.SetSize( m_pcIcons->cx(), m_pcIcons->cy() ); - - // 枠は アイコン横幅xメニュー縦幅で表示し真ん中にアイコンを置く - if( bMenuIconDraw && (lpdis->itemState & ODS_CHECKED) ){ - { - // フラットな枠 + 半透明の背景色 - CMyRect rcFrame( rcIcon ); - ::InflateRect( &rcFrame, cxEdge * 2, cyEdge * 2 ); - ::MyFillRect( hdc, rcFrame, COLOR_HIGHLIGHT ); - - COLORREF colHilight = ::GetSysColor( COLOR_HIGHLIGHT ); - COLORREF colMenu = ::GetSysColor( COLOR_MENU ); - // 16bitカラーの黒色でも少し明るくするように or 0x18 する - BYTE valR; - BYTE valG; - BYTE valB; - if( lpdis->itemState & ODS_SELECTED ){ // 選択状態 - valR = ((GetRValue(colHilight) * 6 + GetRValue(colMenu) * 4) / 10) | 0x18; - valG = ((GetGValue(colHilight) * 6 + GetGValue(colMenu) * 4) / 10) | 0x18; - valB = ((GetBValue(colHilight) * 6 + GetBValue(colMenu) * 4) / 10) | 0x18; - } else { // 非選択状態 - valR = ((GetRValue(colHilight) * 2 + GetRValue(colMenu) * 8) / 10) | 0x18; - valG = ((GetGValue(colHilight) * 2 + GetGValue(colMenu) * 8) / 10) | 0x18; - valB = ((GetBValue(colHilight) * 2 + GetBValue(colMenu) * 8) / 10) | 0x18; - } - CMyRect rcBkFrame( rcIcon ); - ::InflateRect( &rcBkFrame, cxEdge , cyEdge ); - ::MyFillRect( hdc, rcBkFrame, RGB( valR, valG, valB ) ); - } - } - - /* 機能の画像が存在するならメニューアイコン?を描画する */ - if( bMenuIconDraw && -1 != m_menuItems[nItemIndex].m_nBitmapIdx ){ - // アイコン番号 - int nIconNo = m_menuItems[nItemIndex].m_nBitmapIdx; - - // メニューアイコン描画 - m_pcIcons->DrawToolIcon( - hdc, - rcIcon.left, - rcIcon.top, - nIconNo, - ( lpdis->itemState & ODS_DISABLED ) ? ILD_MASK : ILD_NORMAL, - cxSmIcon, - cySmIcon - ); - - }else{ - // チェックボックスを表示 - if( lpdis->itemState & ODS_CHECKED ){ - /* チェックマークの表示 */ - if( bMenuIconDraw ){ - // だいたい中心座標 - int nX = rcItem.left + rcIcon.Height() / 2; - int nY = rcIcon.top + rcIcon.Height() /2; - HPEN hPen = nullptr; - HPEN hPenOld = nullptr; - // 2010.05.31 チェックの色を黒(未指定)からテキスト色に変更 - hPen = ::CreatePen( PS_SOLID, 1, ::GetSysColor(COLOR_MENUTEXT) ); - hPenOld = (HPEN)::SelectObject( hdc, hPen ); -#if 0 -// チェックマークも自分で書く場合 - if( !bMenuIconDraw ){ - nX -= 4; // iconがない場合、左マージン=2アイコン枠=2分がない - } -#endif - const int nBASE = 100*100; // 座標,nScale共に0.01単位 - // 16dot幅しかないので 1.0倍から2.1倍までスケールする(10-23) - const int nScale = t_max(100, t_min(210, int((lpdis->rcItem.bottom - lpdis->rcItem.top - 2) * 100) / (16-2) )); - for( int nBold = 1; nBold <= (281*nScale)/nBASE; nBold++ ){ - ::MoveToEx( hdc, nX - (187*nScale)/nBASE, nY - (187*nScale)/nBASE, nullptr ); - ::LineTo( hdc, nX - (0*nScale)/nBASE, nY - (0*nScale)/nBASE ); - ::LineTo( hdc, nX + (468*nScale)/nBASE, nY - (468*nScale)/nBASE ); - nY++; - } - if( hPen ){ - ::SelectObject( hdc, hPenOld ); - ::DeleteObject( hPen ); - } - }else{ - // OSにアイコン作画をしてもらう(黒背景等対応) - HDC hdcMem = ::CreateCompatibleDC( hdc ); - HBITMAP hBmpMono = ::CreateBitmap( nCxCheck, nCyCheck, 1, 1, nullptr ); - HBITMAP hOld = (HBITMAP)::SelectObject( hdcMem, hBmpMono ); - RECT rcCheck = {0,0, nCxCheck, nCyCheck}; - ::DrawFrameControl( hdcMem, &rcCheck, DFC_MENU, DFCS_MENUCHECK ); - COLORREF colTextOld = ::SetTextColor(hdc, RGB(0,0,0) ); - COLORREF colBackOld = ::SetBkColor(hdc, RGB(255,255,255) ); - ::BitBlt( hdc, lpdis->rcItem.left+2, lpdis->rcItem.top+2, nCxCheck, nCyCheck, hdcMem, 0, 0, SRCAND ); - ::SetTextColor( hdc, textColor ); - ::SetBkColor( hdc, RGB(0,0,0) ); - ::BitBlt( hdc, lpdis->rcItem.left+2, lpdis->rcItem.top+2, nCxCheck, nCyCheck, hdcMem, 0, 0, SRCPAINT ); - ::SetTextColor( hdc, colTextOld ); - ::SetBkColor( hdc, colBackOld ); - ::SelectObject( hdcMem, hOld ); - ::DeleteObject( hBmpMono ); - ::DeleteDC( hdcMem ); - } - } - } - if( bBackSurface ){ - ::BitBlt( hdcOrg, lpdis->rcItem.left, lpdis->rcItem.top, nTargetWidth, nTargetHeight, - hdc, lpdis->rcItem.left, lpdis->rcItem.top, SRCCOPY ); - } - return; -} - -/*! - 作画終了 - メニューループ終了時に呼び出すとリソース節約になる - - @date 20100724 Moca バックサーフェス用に新設 -*/ -void CMenuDrawer::EndDrawMenu() -{ - DeleteCompDC(); -} - void CMenuDrawer::DeleteCompDC() { if( m_hCompDC ){ diff --git a/sakura_core/uiparts/CMenuDrawer.h b/sakura_core/uiparts/CMenuDrawer.h index af7b8af203..0f13ad3ed1 100644 --- a/sakura_core/uiparts/CMenuDrawer.h +++ b/sakura_core/uiparts/CMenuDrawer.h @@ -70,9 +70,6 @@ class CMenuDrawer { MyAppendMenu(hMenu,nFlag,nFuncId,pszLabel,L"",bAddKeyStr,nForceIconId); } - int MeasureItem( int nFuncID, int* pnItemHeight ); /* メニューアイテムの描画サイズを計算 */ - void DrawItem( DRAWITEMSTRUCT* ); /* メニューアイテム描画 */ - void EndDrawMenu(); LRESULT OnMenuChar( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ); int FindToolbarNoFromCommandId( int idCommand, bool bOnlyFunc = true )const; // ツールバーNoの取得 int GetIconIdByFuncId( int nIndex ) const; @@ -122,6 +119,11 @@ class CMenuDrawer HDC m_hCompDC; int m_nCompBitmapHeight; int m_nCompBitmapWidth; + struct DIB { + HBITMAP hBMP; + void* pvBits; + }; + std::vector m_dibs; public: // 2010.01.30 syat アイコンイメージリストをprivate->public diff --git a/sakura_core/util/shell.cpp b/sakura_core/util/shell.cpp index c6a09ad6bc..1d432e849d 100644 --- a/sakura_core/util/shell.cpp +++ b/sakura_core/util/shell.cpp @@ -11,6 +11,7 @@ #include #include #include // Nov. 3, 2005 genta //CDERR_FINDRESFAILURE等 +#include #include "util/shell.h" #include "util/string_ex2.h" #include "util/file.h" @@ -22,8 +23,7 @@ #include "extmodule/CHtmlHelp.h" #include "config/app_constants.h" #include "String_define.h" -#include - +#include "DarkModeSubclass.h" /* フォルダー選択ダイアログ */ BOOL SelectDir( HWND hWnd, const WCHAR* pszTitle, const WCHAR* pszInitFolder, WCHAR* strFolderName, size_t nMaxCount ) @@ -123,6 +123,7 @@ static LRESULT CALLBACK PropSheetWndProc( HWND hwnd, UINT uMsg, WPARAM wParam, L pt.y = rcOk.top; ::ScreenToClient( hwnd, &pt ); ::MoveWindow( hwndBtn, pt.x, pt.y, DpiScaleX(140), rcOk.bottom - rcOk.top, FALSE ); + } break; @@ -230,6 +231,8 @@ static int CALLBACK PropSheetProc( HWND hwndDlg, UINT uMsg, [[maybe_unused]] LPA ::SendMessage( hwndBtn, WM_SETFONT, (WPARAM)hFont, MAKELPARAM( FALSE, 0 ) ); ::SetWindowPos( hwndBtn, ::GetDlgItem( hwndDlg, IDHELP), 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE ); } + + DarkMode::setDarkWndSafe(hwndDlg); } return 0; } @@ -553,12 +556,14 @@ BOOL MySelectFont( LOGFONT* plf, INT* piPointSize, HWND hwndDlgOwner, bool Fixed cf.lStructSize = sizeof( cf ); cf.hwndOwner = hwndDlgOwner; cf.hDC = nullptr; - cf.Flags = CF_SCREENFONTS | CF_INITTOLOGFONTSTRUCT; + cf.Flags = CF_SCREENFONTS | CF_INITTOLOGFONTSTRUCT | CF_EFFECTS | CF_ENABLEHOOK; if( FixedFontOnly ){ //FIXEDフォント cf.Flags |= CF_FIXEDPITCHONLY; } cf.lpLogFont = plf; + cf.lpfnHook = static_cast(DarkMode::HookDlgProc); + cf.hInstance = GetModuleHandleW(nullptr); if( !ChooseFont( &cf ) ){ #ifdef _DEBUG DWORD nErr; diff --git a/sakura_core/view/CEditView.cpp b/sakura_core/view/CEditView.cpp index fef1b9d7bf..7ee3ff8feb 100644 --- a/sakura_core/view/CEditView.cpp +++ b/sakura_core/view/CEditView.cpp @@ -48,6 +48,7 @@ #include "CSelectLang.h" #include "String_define.h" +#include "DarkModeSubclass.h" LRESULT CALLBACK EditViewWndProc( HWND, UINT, WPARAM, LPARAM ); VOID CALLBACK EditViewTimerProc( HWND, UINT, UINT_PTR, DWORD ); @@ -294,6 +295,7 @@ BOOL CEditView::Create( if( nullptr == GetHwnd() ){ return FALSE; } + DarkMode::setDarkRichEdit(GetHwnd()); if( !m_bMiniMap ){ m_pcDropTarget = new CDropTarget( this ); @@ -455,6 +457,7 @@ LRESULT CEditView::DispatchEvent( if (m_hwndSizeBoxPlaceholder == nullptr) { return -1; } + DarkMode::setWindowCtlColorSubclass(hwnd); return 0L; // From Here 2007.09.09 Moca 互換BMPによる画面バッファ diff --git a/sakura_core/view/CEditView_Scroll.cpp b/sakura_core/view/CEditView_Scroll.cpp index 384b3041d5..f65680498f 100644 --- a/sakura_core/view/CEditView_Scroll.cpp +++ b/sakura_core/view/CEditView_Scroll.cpp @@ -31,6 +31,7 @@ #include "types/CTypeSupport.h" #include #include "config/app_constants.h" +#include "DarkModeSubclass.h" /*! スクロールバー作成 @date 2006.12.19 ryoji 新規作成(CEditView::Createから分離) @@ -100,6 +101,9 @@ BOOL CEditView::CreateScrollBar() ::ShowWindow( m_hwndSizeBox, SW_HIDE ); ::ShowWindow( m_hwndSizeBoxPlaceholder, SW_SHOW ); } + + DarkMode::setChildCtrlsTheme(GetHwnd()); + return TRUE; } diff --git a/sakura_core/window/CEditWnd.cpp b/sakura_core/window/CEditWnd.cpp index 226160357e..87f4f8ab11 100644 --- a/sakura_core/window/CEditWnd.cpp +++ b/sakura_core/window/CEditWnd.cpp @@ -61,6 +61,7 @@ #include "recent/CRecentEditNode.h" #include "recent/CRecentFile.h" #include "recent/CRecentFolder.h" +#include "DarkModeSubclass.h" //@@@ 2002.01.14 YAZAKI 印刷プレビューをCPrintPreviewに独立させたので // 定義を削除 @@ -615,6 +616,8 @@ HWND CEditWnd::Create( if(!hWnd)return nullptr; m_hWnd = hWnd; + DarkMode::setDarkTitleBarEx(hWnd, true); + // 初回アイドリング検出用のゼロ秒タイマーをセットする // 2008.04.19 ryoji // ゼロ秒タイマーが発動(初回アイドリング検出)したら MYWM_FIRST_IDLE を起動元プロセスにポストする。 // ※起動元での起動先アイドリング検出については CControlTray::OpenNewEditor を参照 @@ -686,6 +689,10 @@ HWND CEditWnd::Create( /* バーの配置終了 */ EndLayoutBars( FALSE ); + DarkMode::setChildCtrlsTheme(hWnd); + DarkMode::setWindowMenuBarSubclass(hWnd); + DarkMode::setChildCtrlsSubclassAndTheme(hWnd); + // -- -- -- -- その他調整など -- -- -- -- // // 画面表示直前にDispatchEventを有効化する @@ -910,6 +917,7 @@ void CEditWnd::LayoutMainMenu() DestroyMenu( hMenuOld ); } + DarkMode::setWindowMenuBarSubclass(hWnd); DrawMenuBar( hWnd ); } @@ -1055,6 +1063,9 @@ void CEditWnd::MessageLoop( void ) MSG msg; int ret; + auto hWnd = GetHwnd(); + DarkMode::setDarkWndNotifySafeEx(hWnd, false, true); + while(GetHwnd()) { //メッセージ取得 @@ -1204,34 +1215,8 @@ LRESULT CEditWnd::DispatchEvent( } } return 0; - }else{ - switch( lpdis->CtlType ){ - case ODT_MENU: /* オーナー描画メニュー */ - /* メニューアイテム描画 */ - m_cMenuDrawer.DrawItem( lpdis ); - return TRUE; - } } return FALSE; - case WM_MEASUREITEM: - idCtl = (UINT) wParam; // control identifier - lpmis = (MEASUREITEMSTRUCT*) lParam; // item-size information - switch( lpmis->CtlType ){ - case ODT_MENU: /* オーナー描画メニュー */ -// CMenuDrawer* pCMenuDrawer; -// pCMenuDrawer = (CMenuDrawer*)lpmis->itemData; - -// MYTRACE( L"WM_MEASUREITEM lpmis->itemID=%d\n", lpmis->itemID ); - /* メニューアイテムの描画サイズを計算 */ - nItemWidth = m_cMenuDrawer.MeasureItem( lpmis->itemID, &nItemHeight ); - if( 0 < nItemWidth ){ - lpmis->itemWidth = nItemWidth; - lpmis->itemHeight = nItemHeight; - } - return TRUE; - } - return FALSE; - case WM_PAINT: return OnPaint( hwnd, uMsg, wParam, lParam ); @@ -1371,7 +1356,6 @@ LRESULT CEditWnd::DispatchEvent( if( nullptr != m_cStatusBar.GetStatusHwnd() ){ m_cStatusBar.SetStatusText(0, SBT_NOBORDERS, L""); } - m_cMenuDrawer.EndDrawMenu(); /* メッセージの配送 */ return Views_DispatchEvent( hwnd, uMsg, wParam, lParam ); @@ -1499,14 +1483,6 @@ LRESULT CEditWnd::DispatchEvent( if( nId != 0 ) OnCommand( (WORD)0 /*メニュー*/, (WORD)nId, nullptr ); } return FALSE; - // From Here Jul. 21, 2003 genta - case NM_CUSTOMDRAW: - if( pnmh->hwndFrom == m_cToolbar.GetToolbarHwnd() ){ - // ツールバーのOwner Draw - return m_cToolbar.ToolBarOwnerDraw( (LPNMCUSTOMDRAW)pnmh ); - } - break; - // To Here Jul. 21, 2003 genta } return 0L; case WM_COMMAND: @@ -1988,6 +1964,7 @@ LRESULT CEditWnd::DispatchEvent( } EndLayoutBars(); // 2006.12.19 ryoji } + DarkMode::setChildCtrlsSubclassAndTheme(hwnd); return 0L; //by 鬼 (2) MYWM_CHECKSYSMENUDBLCLKは不要に, WM_LBUTTONDBLCLK追加 @@ -2256,6 +2233,11 @@ void CEditWnd::InitMenu( HMENU hMenu, UINT uPos, BOOL fSystemMenu ) int i; HMENU hMenuPopUp; + MENUINFO mi = { sizeof(mi) }; + mi.fMask = MIM_STYLE; + mi.dwStyle = MNS_CHECKORBMP; + SetMenuInfo(hMenu, &mi); + if( hMenu == ::GetSubMenu( ::GetMenu( GetHwnd() ), uPos ) && !fSystemMenu ){ // 情報取得 @@ -2359,7 +2341,7 @@ void CEditWnd::InitMenu( HMENU hMenu, UINT uPos, BOOL fSystemMenu ) /* 機能が利用可能か調べる */ // Jan. 8, 2006 genta 機能が有効な場合には明示的に再設定しないようにする. if( ! IsFuncEnable( GetDocument(), m_pShareData, id ) ){ - fuFlags = MF_BYCOMMAND | MF_GRAYED; + fuFlags = MF_BYCOMMAND | MF_DISABLED; ::EnableMenuItem(hMenu, id, fuFlags); } @@ -3944,8 +3926,8 @@ void CEditWnd::PrintMenubarMessage( const WCHAR* msg ) rc.right = rc.left + nStrLen * m_nCaretPosInfoCharWidth + 2; rc.top = po.y - m_nCaretPosInfoCharHeight - 2; rc.bottom = rc.top + m_nCaretPosInfoCharHeight; - ::SetTextColor( hdc, ::GetSysColor( COLOR_MENUTEXT ) ); - ::SetBkColor( hdc, ::GetSysColor( COLOR_MENUBAR ) ); + ::SetTextColor( hdc, DarkMode::getTextColor() ); + ::SetBkColor( hdc, DarkMode::getDlgBackgroundColor()); { const WCHAR* pchText = m_pszMenubarMessage; const ULONG cchText = nStrLen; diff --git a/sakura_core/window/CMainStatusBar.cpp b/sakura_core/window/CMainStatusBar.cpp index b8004f7110..c068fcef7b 100644 --- a/sakura_core/window/CMainStatusBar.cpp +++ b/sakura_core/window/CMainStatusBar.cpp @@ -9,6 +9,7 @@ #include "window/CEditWnd.h" #include "CEditApp.h" #include "apiwrap/CommonControl.h" +#include "DarkModeSubclass.h" CMainStatusBar::CMainStatusBar(CEditWnd* pOwner) : m_pOwner(pOwner) @@ -34,6 +35,8 @@ void CMainStatusBar::CreateStatusBar() nullptr ); + DarkMode::setStatusBarCtrlSubclass(m_hwndStatusBar); + /* プログレスバー */ m_hwndProgressBar = ::CreateWindowEx( WS_EX_TOOLWINDOW, @@ -50,6 +53,8 @@ void CMainStatusBar::CreateStatusBar() nullptr ); + DarkMode::setProgressBarCtrlSubclass(m_hwndProgressBar); + if( nullptr != m_pOwner->m_cFuncKeyWnd.GetHwnd() ){ m_pOwner->m_cFuncKeyWnd.SizeBox_ONOFF( FALSE ); } diff --git a/sakura_core/window/CMainToolBar.cpp b/sakura_core/window/CMainToolBar.cpp index 2e8d1a3fec..c2fc4a4c6b 100644 --- a/sakura_core/window/CMainToolBar.cpp +++ b/sakura_core/window/CMainToolBar.cpp @@ -19,6 +19,7 @@ #include "apiwrap/StdControl.h" #include "CSelectLang.h" #include "String_define.h" +#include "DarkModeSubclass.h" CMainToolBar::CMainToolBar(CEditWnd* pOwner) : m_pOwner(pOwner) @@ -129,6 +130,8 @@ void CMainToolBar::CreateToolBar( void ) CEditApp::getInstance()->GetAppInstance(), nullptr ); + SetWindowTheme(m_hwndReBar, L"", L""); + SendMessage(m_hwndReBar, RB_SETBKCOLOR, 0, DarkMode::getBackgroundColor()); if( nullptr == m_hwndReBar ){ TopWarningMessage( m_pOwner->GetHwnd(), LS(STR_ERR_DLGEDITWND04) ); @@ -176,7 +179,6 @@ void CMainToolBar::CreateToolBar( void ) // 2006.09.06 ryoji ツールバーをサブクラス化する ::SetWindowSubclass(m_hwndToolBar, &ToolBarWndProc, 0, 0); - // pixel数をベタ書きするとHighDPI環境でずれるのでシステム値を取得して使う const int cxBorder = DpiScaleX( 1 ); const int cyBorder = DpiScaleY( 1 ); const int cxEdge = DpiScaleX( 1 ); @@ -187,16 +189,15 @@ void CMainToolBar::CreateToolBar( void ) const int cyToolButton = cyBorder + cyEdge + cySmIcon + cyEdge + cyBorder; //22 Toolbar_SetButtonSize( m_hwndToolBar, cxToolButton, cyToolButton ); // 2009.10.01 ryoji 高DPI対応スケーリング Toolbar_ButtonStructSize( m_hwndToolBar, sizeof(TBBUTTON) ); - // Oct. 12, 2000 genta - // 既に用意されているImage Listをアイコンとして登録 - m_pcIcons->SetToolBarImages( m_hwndToolBar ); /* ツールバーにボタンを追加 */ int count = 0; //@@@ 2002.06.15 MIK int nToolBarButtonNum = 0;// 2005/8/29 aroka // From Here 2005.08.29 aroka // はじめにツールバー構造体の配列を作っておく - TBBUTTON *pTbbArr = new TBBUTTON[GetDllShareData().m_Common.m_sToolBar.m_nToolBarButtonNum]; - for( i = 0; i < GetDllShareData().m_Common.m_sToolBar.m_nToolBarButtonNum; ++i ){ + const auto nButtons = GetDllShareData().m_Common.m_sToolBar.m_nToolBarButtonNum; + + TBBUTTON* pTbbArr = new TBBUTTON[nButtons]; + for (i = 0; i < nButtons; ++i) { nIdx = GetDllShareData().m_Common.m_sToolBar.m_nToolBarButtonIdxArr[i]; pTbbArr[nToolBarButtonNum] = m_pOwner->GetMenuDrawer().getButton(nIdx); // セパレータが続くときはひとつにまとめる @@ -219,6 +220,42 @@ void CMainToolBar::CreateToolBar( void ) } // To Here 2005.08.29 aroka + BITMAPINFO bminfo = {}; + BITMAPINFOHEADER& bmih = bminfo.bmiHeader; + bmih.biSize = sizeof(BITMAPINFOHEADER); + bmih.biWidth = (LONG)cxSmIcon; + bmih.biHeight = -(LONG)cySmIcon; + bmih.biPlanes = 1; + bmih.biBitCount = 32; + bmih.biCompression = BI_RGB; + HDC hdc = CreateCompatibleDC(nullptr); + m_hImageList = ImageList_Create(cxSmIcon, cySmIcon, ILC_COLOR32, nButtons, 0); + m_hDisabledImageList = ImageList_Create(cxSmIcon, cySmIcon, ILC_COLOR32, nButtons, 0); + for (int i = 0; i < nButtons; ++i) { + TBBUTTON& tbb = pTbbArr[i]; + if (tbb.fsStyle == TBSTYLE_BUTTON || tbb.fsStyle == TBSTYLE_DROPDOWN) { + uint32_t* pBits; + HBITMAP hBMP; + { + hBMP = ::CreateDIBSection(hdc, &bminfo, DIB_RGB_COLORS, (void**)&pBits, nullptr, 0); + m_pcIcons->DrawToolIcon(pBits, tbb.iBitmap, true, cxSmIcon, cySmIcon); + auto ret = ImageList_Add(m_hImageList, hBMP, nullptr); + ::DeleteObject(hBMP); + } + { + hBMP = ::CreateDIBSection(hdc, &bminfo, DIB_RGB_COLORS, (void**)&pBits, nullptr, 0); + m_pcIcons->DrawToolIcon(pBits, tbb.iBitmap, false, cxSmIcon, cySmIcon); + auto ret = ImageList_Add(m_hDisabledImageList, hBMP, nullptr); + tbb.iBitmap = ret; + ::DeleteObject(hBMP); + } + } + } + ::DeleteDC(hdc); + + Toolbar_SetImageList(m_hwndToolBar, 0, m_hImageList); + Toolbar_SetDisabledImageList(m_hwndToolBar, 0, m_hDisabledImageList); + for( i = 0; i < nToolBarButtonNum; ++i ){ tbb = pTbbArr[i]; @@ -337,6 +374,7 @@ void CMainToolBar::CreateToolBar( void ) } //@@@ 2002.06.15 MIK end } + Toolbar_SetBitmapSize(m_hwndToolBar, cxSmIcon, cySmIcon); if( GetDllShareData().m_Common.m_sToolBar.m_bToolBarIsFlat ){ /* フラットツールバーにする/しない */ lToolType = ::GetWindowLongPtr(m_hwndToolBar, GWL_STYLE); lToolType |= (TBSTYLE_FLAT); @@ -366,6 +404,7 @@ void CMainToolBar::CreateToolBar( void ) // バンドを追加する Rebar_InsertBand( m_hwndReBar, -1, &rbBand ); ::ShowWindow( m_hwndToolBar, SW_SHOW ); + DarkMode::setDarkWndSafe(m_hwndReBar); } return; @@ -402,6 +441,17 @@ void CMainToolBar::DestroyToolBar( void ) m_hwndReBar = nullptr; } + if (m_hImageList) + { + ImageList_Destroy(m_hImageList); + m_hImageList = nullptr; + } + if (m_hDisabledImageList) + { + ImageList_Destroy(m_hDisabledImageList); + m_hDisabledImageList = nullptr; + } + return; } @@ -415,70 +465,6 @@ bool CMainToolBar::EatMessage(MSG* msg) return false; } -/*! @brief ToolBarのOwnerDraw - - @param pnmh [in] Owner Draw情報 - - @note Common Control V4.71以降はNMTBCUSTOMDRAWを送ってくるが, - Common Control V4.70はLPNMCUSTOMDRAWしか送ってこないので - 安全のため小さい方に合わせて処理を行う. - - @author genta - @date 2003.07.21 作成 - -*/ -LPARAM CMainToolBar::ToolBarOwnerDraw( LPNMCUSTOMDRAW pnmh ) -{ - switch( pnmh->dwDrawStage ){ - case CDDS_PREPAINT: - // 描画開始前 - // アイテムを自前で描画する旨を通知する - return CDRF_NOTIFYITEMDRAW; - - case CDDS_ITEMPREPAINT: - // 面倒くさいので,枠はToolbarに描いてもらう - // アイコンが登録されていないので中身は何も描かれない - // 2010.07.15 Moca 検索(ボックス)なら枠を描かない - if( pnmh->dwItemSpec == F_SEARCH_BOX ){ - return CDRF_SKIPDEFAULT; - } - return CDRF_NOTIFYPOSTPAINT; - - case CDDS_ITEMPOSTPAINT: - { - // 描画 - // コマンド番号(pnmh->dwItemSpec)からアイコン番号を取得する // 2007.11.02 ryoji - int nIconId = Toolbar_GetBitmap( pnmh->hdr.hwndFrom, (WPARAM)pnmh->dwItemSpec ); - - // アイテム矩形からの画像のオフセット // 2007.03.25 ryoji - CMyRect rc( pnmh->rc ); - int offset = ( rc.Height() - m_pcIcons->cy() ) / 2; - - const int cxEdge = DpiScaleX( 1 ); - const int cyEdge = DpiScaleY( 1 ); - const int cxSmIcon = DpiScaleX( 16 ); - const int cySmIcon = DpiScaleY( 16 ); - - // ボタンを押されたらちょっと画像をずらす // Aug. 30, 2003 genta - int shift = pnmh->uItemState & ( CDIS_SELECTED | CDIS_CHECKED ) ? cxEdge : 0; - - // アイコン描画 - m_pcIcons->DrawToolIcon( - pnmh->hdc, - rc.left + offset + shift, - rc.top + offset + shift, // 押下時は右だけでなく下にもずらす // Sep. 6, 2003 genta - nIconId, - ( pnmh->uItemState & CDIS_DISABLED ) ? ILD_MASK : ILD_NORMAL, - cxSmIcon, cySmIcon - ); - } - break; - default: - break; - } - return CDRF_DODEFAULT; -} - /*! ツールバー更新用タイマーの処理 @date 2002.01.03 YAZAKI m_tbMyButtonなどをCShareDataからCMenuDrawerへ移動したことによる修正。 @date 2003.08.29 wmlhq, ryoji nTimerCountの導入 diff --git a/sakura_core/window/CMainToolBar.h b/sakura_core/window/CMainToolBar.h index aae44742ad..0178f84a3e 100644 --- a/sakura_core/window/CMainToolBar.h +++ b/sakura_core/window/CMainToolBar.h @@ -32,9 +32,6 @@ class CMainToolBar{ void OnToolbarTimer( void ); //!< タイマーの処理 20060128 aroka void UpdateToolbar( void ); //!< ツールバーの表示を更新する // 2008.09.23 nasukoji - //描画 - LPARAM ToolBarOwnerDraw( LPNMCUSTOMDRAW pnmh ); - //共有データとの同期 void AcceptSharedSearchKey(); @@ -62,5 +59,7 @@ class CMainToolBar{ CRecentSearch m_cRecentSearch; CImageListMgr* m_pcIcons = nullptr; + HIMAGELIST m_hImageList = nullptr; + HIMAGELIST m_hDisabledImageList = nullptr; }; #endif /* SAKURA_CMAINTOOLBAR_FEA7E388_DFEC_4E15_94CC_90A7E779797B_H_ */ diff --git a/sakura_core/window/CSplitBoxWnd.cpp b/sakura_core/window/CSplitBoxWnd.cpp index 7d9be74443..95f9d2ba29 100644 --- a/sakura_core/window/CSplitBoxWnd.cpp +++ b/sakura_core/window/CSplitBoxWnd.cpp @@ -52,7 +52,7 @@ HWND CSplitBoxWnd::Create( HINSTANCE hInstance, HWND hwndParent, int bVertical ) nullptr, // Handle to the class icon. nullptr, // Handle to a small icon hCursor,// Handle to the class cursor. - (HBRUSH)(COLOR_3DFACE + 1),// Handle to the class background brush. + (HBRUSH)(COLOR_3DSHADOW + 1),// Handle to the class background brush. nullptr/*MAKEINTRESOURCE( MYDOCUMENT )*/,// Pointer to a null-terminated character string that specifies the resource name of the class menu, as the name appears in the resource file. pszClassName// Pointer to a null-terminated string or is an atom. ); @@ -74,8 +74,8 @@ HWND CSplitBoxWnd::Create( HINSTANCE hInstance, HWND hwndParent, int bVertical ) WS_CHILD | WS_VISIBLE, // window style bVertical ? ( rc.right - nCxVScroll ):( 0 ), // horizontal position of window bVertical ? ( 0 ):( rc.bottom - nCyHScroll ), // vertical position of window - bVertical ? ( nCxVScroll ):( 7 ), // window width - bVertical ? ( 7 ):( nCyHScroll ), // window height + bVertical ? ( nCxVScroll ):( 37 ), // window width + bVertical ? ( 37 ):( nCyHScroll ), // window height nullptr // handle to menu, or child-window identifier ); } @@ -124,23 +124,26 @@ LRESULT CSplitBoxWnd::OnPaint( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lPara nVSplitHeight = 7; /* 垂直分割ボックスの高さ */ nHSplitWidth = 7; /* 水平分割ボックスの幅 */ +#if 1 + COLORREF cTL0 = RGB(136, 136, 136); + COLORREF cBR0 = RGB(63, 63, 63); + COLORREF cTL1 = RGB(153, 153, 153); + COLORREF cBR1 = RGB(96, 96, 96); +#else + COLORREF cTL0 = ::GetSysColor(COLOR_3DLIGHT); + COLORREF cBR0 = ::GetSysColor(COLOR_3DDKSHADOW); + COLORREF cTL1 = ::GetSysColor(COLOR_3DHILIGHT); + COLORREF cBR1 = ::GetSysColor(COLOR_3DSHADOW); +#endif + if( m_bVertical ){ /* 垂直分割ボックスの描画 */ - Draw3dRect( hdc, 0, 0, nCxVScroll, nVSplitHeight, - ::GetSysColor( COLOR_3DLIGHT ), ::GetSysColor( COLOR_3DDKSHADOW ) - ); - Draw3dRect( hdc, 1, 1, nCxVScroll - 2, nVSplitHeight - 2, - ::GetSysColor( COLOR_3DHILIGHT ), ::GetSysColor( COLOR_3DSHADOW ) - ); + Draw3dRect(hdc, 0, 0, nCxVScroll, nVSplitHeight, cTL0, cBR0); + Draw3dRect(hdc, 1, 1, nCxVScroll - 2, nVSplitHeight - 2, cTL1, cBR1); }else{ /* 水平分割ボックスの描画 */ - Draw3dRect( hdc, 0, 0, nHSplitWidth, nCyHScroll, - ::GetSysColor( COLOR_3DLIGHT ), ::GetSysColor( COLOR_3DDKSHADOW ) - ); - - Draw3dRect( hdc, 1, 1, nHSplitWidth - 2, nCyHScroll - 2, - ::GetSysColor( COLOR_3DHILIGHT ), ::GetSysColor( COLOR_3DSHADOW ) - ); + Draw3dRect(hdc, 0, 0, nHSplitWidth, nCyHScroll, cTL0, cBR0); + Draw3dRect(hdc, 1, 1, nHSplitWidth - 2, nCyHScroll - 2, cTL1, cBR1); } ::EndPaint(hwnd, &ps); diff --git a/sakura_core/window/CSplitterWnd.cpp b/sakura_core/window/CSplitterWnd.cpp index 46663a3525..20b4bb6037 100644 --- a/sakura_core/window/CSplitterWnd.cpp +++ b/sakura_core/window/CSplitterWnd.cpp @@ -27,6 +27,7 @@ #include "CSelectLang.h" #include "config/system_constants.h" #include "String_define.h" +#include "DarkModeSubclass.h" constexpr auto SPLITTER_FRAME_WIDTH = 3; constexpr auto SPLITTER_MARGIN = 2; @@ -83,7 +84,7 @@ HWND CSplitterWnd::Create( HWND hwndParent ) } /* 基底クラスメンバ呼び出し */ - return CWnd::Create( + HWND hWnd = CWnd::Create( hwndParent, 0, // extended window style pszClassName, // Pointer to a null-terminated string or is an atom. @@ -95,6 +96,8 @@ HWND CSplitterWnd::Create( HWND hwndParent ) 0, // window height nullptr // handle to menu, or child-window identifier ); + DarkMode::setDarkWndSafe(hWnd); + return hWnd; } /* 子ウィンドウの設定 @@ -119,20 +122,6 @@ void CSplitterWnd::SetChildWndArr( HWND* hwndEditViewArr ) return; } -/* 分割フレーム描画 */ -void CSplitterWnd::DrawFrame( HDC hdc, RECT* prc ) -{ - CSplitBoxWnd::Draw3dRect( hdc, prc->left, prc->top, prc->right, prc->bottom, - ::GetSysColor( COLOR_3DSHADOW ), - ::GetSysColor( COLOR_3DHILIGHT ) - ); - CSplitBoxWnd::Draw3dRect( hdc, prc->left + 1, prc->top + 1, prc->right - 2, prc->bottom - 2, - RGB( 0, 0, 0 ), - ::GetSysColor( COLOR_3DFACE ) - ); - return; -} - /* 分割トラッカーの表示 */ void CSplitterWnd::DrawSplitter( int xPos, int yPos, int bEraseOld ) { @@ -787,13 +776,14 @@ LRESULT CSplitterWnd::OnPaint( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lPara const int nFrameWidth = DpiScaleX(SPLITTER_FRAME_WIDTH); hdc = ::BeginPaint( hwnd, &ps ); ::GetClientRect( GetHwnd(), &rc ); + auto color = DarkMode::getViewBackgroundColor(); if( m_nAllSplitRows > 1 ){ ::SetRect( &rcFrame, rc.left, m_nVSplitPos, rc.right, m_nVSplitPos + nFrameWidth ); - ::MyFillRect( hdc, rcFrame, COLOR_3DFACE ); + ::MyFillRect( hdc, rcFrame, color ); } if( m_nAllSplitCols > 1 ){ ::SetRect( &rcFrame, m_nHSplitPos, rc.top, m_nHSplitPos + nFrameWidth, rc.bottom ); - ::MyFillRect( hdc, rcFrame, COLOR_3DFACE ); + ::MyFillRect( hdc, rcFrame, color ); } ::EndPaint(hwnd, &ps); return 0L; diff --git a/sakura_core/window/CSplitterWnd.h b/sakura_core/window/CSplitterWnd.h index a0a4499637..487a55a67b 100644 --- a/sakura_core/window/CSplitterWnd.h +++ b/sakura_core/window/CSplitterWnd.h @@ -88,7 +88,6 @@ class CSplitterWnd final : public CWnd /* || 実装ヘルパ関数 */ - void DrawFrame(HDC hdc, RECT* prc); /* 分割フレーム描画 */ int HitTestSplitter(int xPos, int yPos); /* 分割バーへのヒットテスト */ void DrawSplitter(int xPos, int yPos, int bEraseOld); /* 分割トラッカーの表示 */ }; diff --git a/sakura_core/window/CTabWnd.cpp b/sakura_core/window/CTabWnd.cpp index f6379de714..63d3846827 100644 --- a/sakura_core/window/CTabWnd.cpp +++ b/sakura_core/window/CTabWnd.cpp @@ -38,6 +38,7 @@ #include #include "config/system_constants.h" #include "String_define.h" +#include "DarkModeSubclass.h" // 2006.01.30 ryoji タブのサイズ/位置に関する定義 // 2009.10.01 ryoji 高DPI対応スケーリング @@ -945,6 +946,7 @@ HWND CTabWnd::Open( HINSTANCE hInstance, HWND hwndParent ) GetAppInstance(), nullptr ); + DarkMode::setDarkTooltips(m_hwndToolTip, static_cast(DarkMode::ToolTipsType::tooltip)); // ツールチップをマルチライン可能にする(SHRT_MAX: Win95でINT_MAXだと表示されない) // 2007.03.03 ryoji Tooltip_SetMaxTipWidth( m_hwndToolTip, SHRT_MAX ); @@ -1060,6 +1062,12 @@ LRESULT CTabWnd::OnDestroy( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) m_hIml = nullptr; } + for (auto [key, value] : m_bmpMap) + { + ::DeleteObject(value); + } + m_bmpMap.clear(); + ::KillTimer( hwnd, 1 ); // 2006.02.01 ryoji _SetHwnd(nullptr); @@ -1244,67 +1252,8 @@ LRESULT CTabWnd::OnMeasureItem( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lPar LRESULT CTabWnd::OnDrawItem( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { DRAWITEMSTRUCT* lpdis = (DRAWITEMSTRUCT*)lParam; - if( lpdis->CtlType == ODT_MENU ) - { - // タブ一覧メニューを描画する - TABMENU_DATA* pData = (TABMENU_DATA*)lpdis->itemData; - - //描画対象 - HDC hdc = lpdis->hDC; - CGraphics gr(hdc); - RECT rcItem = lpdis->rcItem; - - // 状態に従ってテキストと背景色を決める - COLORREF clrText; - int nSysClrBk; - if (lpdis->itemState & ODS_SELECTED) - { - clrText = ::GetSysColor( COLOR_HIGHLIGHTTEXT ); - nSysClrBk = COLOR_HIGHLIGHT; - } - else - { - clrText = ::GetSysColor( COLOR_MENUTEXT ); - nSysClrBk = COLOR_MENU; - } - - // 背景描画 - ::MyFillRect( gr, rcItem, nSysClrBk ); - - // アイコン描画 - int cxIcon = CX_SMICON; - int cyIcon = CY_SMICON; - if( nullptr != m_hIml ) - { - ImageList_GetIconSize( m_hIml, &cxIcon, &cyIcon ); - if( 0 <= pData->iImage ) - { - int top = rcItem.top + ( rcItem.bottom - rcItem.top - cyIcon ) / 2; - ImageList_Draw( m_hIml, pData->iImage, lpdis->hDC, rcItem.left + DpiScaleX(2), top, ILD_TRANSPARENT ); - } - } - - // テキスト描画 - gr.PushTextForeColor( clrText ); - gr.SetTextBackTransparent(true); - HFONT hFont = CreateMenuFont(); - gr.PushMyFont(hFont); - RECT rcText = rcItem; - rcText.left += (cxIcon + DpiScaleX(8)); - - ::DrawText( gr, pData->szText, -1, &rcText, DT_SINGLELINE | DT_LEFT | DT_VCENTER ); - - gr.PopTextForeColor(); - gr.PopMyFont(); - ::DeleteObject( hFont ); - - // チェック状態なら外枠描画 - if( lpdis->itemState & ODS_CHECKED ) - { - gr.SetPen( ::GetSysColor(COLOR_HIGHLIGHT) ); - gr.SetBrushColor(-1); //NULL_BRUSH - ::Rectangle( gr, rcItem.left, rcItem.top, rcItem.right, rcItem.bottom ); - } + if( lpdis->CtlType == ODT_MENU ) { + assert(0); } else if( lpdis->CtlType == ODT_TAB ) { // タブを描画する @@ -1335,7 +1284,7 @@ LRESULT CTabWnd::OnDrawItem( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam }else{ int iPartId = TABP_TABITEM; int iStateId = TIS_NORMAL; - HTHEME hTheme = ::OpenThemeData( m_hwndTab, L"TAB" ); + HTHEME hTheme = ::OpenThemeData( m_hwndTab, L"Explorer" ); if( hTheme ) { if( !bSelected ){ ::InflateRect( &rcFullItem, DpiScaleX(2), DpiScaleY(2) ); @@ -1404,7 +1353,8 @@ LRESULT CTabWnd::OnDrawItem( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam // テキスト描画 COLORREF clrText; - clrText = ::GetSysColor(COLOR_MENUTEXT); + //clrText = ::GetSysColor(COLOR_MENUTEXT); + clrText = DarkMode::getTextColor(); gr.PushTextForeColor( clrText ); gr.SetTextBackTransparent(true); RECT rcText = rcItem; @@ -1574,14 +1524,19 @@ LRESULT CTabWnd::OnPaint( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) // 背景を描画する ::GetClientRect( hwnd, &rc ); - ::MyFillRect( gr, rc, COLOR_3DFACE ); + ::MyFillRect( gr, rc, DarkMode::getBackgroundColor() ); // ボタンを描画する DrawListBtn( gr, &rc ); DrawCloseBtn( gr, &rc ); // 2006.10.21 ryoji 追加 // 上側に境界線を描画する - ::DrawEdge(gr, &rc, EDGE_ETCHED, BF_TOP); + // Sunken outer edge. + gr.SetPen(RGB(60, 60, 60)); + gr.DrawLine(0, 0, rc.right, 0); + // Raised inner edge. + gr.SetPen(RGB(100, 100, 100)); + gr.DrawLine(0, 1, rc.right, 1); // トップバンドを描画する if( auto nCurSel = TabCtrl_GetCurSel( m_hwndTab ); 0 <= nCurSel ){ @@ -2351,6 +2306,17 @@ void CTabWnd::LayoutTab( void ) } } +static HBITMAP getIconBmp(HICON hIcon) +{ + ICONINFOEX ii; + ii.cbSize = sizeof(ii); + ::GetIconInfoEx(hIcon, &ii); + auto ret = (HBITMAP)CopyImage(ii.hbmColor, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION); + ::DeleteObject(ii.hbmColor); + ::DeleteObject(ii.hbmMask); + return ret; +} + /*! イメージリストの初期化処理 @date 2006.02.22 ryoji 新規作成 */ @@ -2401,9 +2367,15 @@ HIMAGELIST CTabWnd::InitImageList( void ) // (利用しないアイコンと差し替える) m_hIconApp = GetAppIcon( GetAppInstance(), ICON_DEFAULT_APP, FN_APP_ICON, true ); ImageList_ReplaceIcon( hImlNew, m_iIconApp, m_hIconApp ); + if (m_bmpMap.count(m_iIconApp) == 0) { + m_bmpMap[m_iIconApp] = getIconBmp(m_hIconApp); + } if( m_iIconApp != m_iIconGrep ){ m_hIconGrep = GetAppIcon( GetAppInstance(), ICON_DEFAULT_GREP, FN_GREP_ICON, true ); ImageList_ReplaceIcon( hImlNew, m_iIconGrep, m_hIconGrep ); + if (m_bmpMap.count(m_iIconGrep) == 0) { + m_bmpMap[m_iIconGrep] = getIconBmp(m_hIconGrep); + } } } @@ -2415,6 +2387,7 @@ HIMAGELIST CTabWnd::InitImageList( void ) if( nullptr != m_hIml ) ImageList_Destroy( m_hIml ); m_hIml = hImlNew; + auto cnt = ImageList_GetImageCount(m_hIml); return m_hIml; // 新しいイメージリストを返す } @@ -2443,6 +2416,14 @@ int CTabWnd::GetImageIndex( EditNode* pNode ) hImlSys = (HIMAGELIST)::SHGetFileInfo( szExt, FILE_ATTRIBUTE_NORMAL, &sfi, sizeof(sfi), SHGFI_SYSICONINDEX | SHGFI_SMALLICON | SHGFI_USEFILEATTRIBUTES ); if( nullptr == hImlSys ) return -1; + if (m_bmpMap.count(sfi.iIcon) == 0) + { + HICON hIcon = ::ImageList_GetIcon(hImlSys, sfi.iIcon, ILD_TRANSPARENT); + if (hIcon != nullptr) + { + m_bmpMap[sfi.iIcon] = getIconBmp(hIcon); + } + } if( ImageList_GetImageCount( m_hIml ) > sfi.iIcon ) return sfi.iIcon; // インデックスを返す @@ -2529,8 +2510,9 @@ void CTabWnd::DrawBtnBkgnd( HDC hdc, const LPRECT lprcBtn, BOOL bBtnHilighted ) if( bBtnHilighted ) { CGraphics gr(hdc); - gr.SetPen( ::GetSysColor(COLOR_HIGHLIGHT) ); - gr.SetBrushColor( ::GetSysColor(COLOR_MENU) ); + auto color = DarkMode::getHotBackgroundColor(); + gr.SetPen(color); + gr.SetBrushColor(color); ::Rectangle( gr, lprcBtn->left, lprcBtn->top, lprcBtn->right, lprcBtn->bottom ); } } @@ -2555,9 +2537,10 @@ void CTabWnd::DrawListBtn( CGraphics& gr, const LPRECT lprcClient ) rcBtn.right = rcBtn.left + (rcBtnBase.right - rcBtnBase.left); rcBtn.bottom = rcBtn.top + (rcBtnBase.bottom - rcBtnBase.left); - int nIndex = m_bListBtnHilighted? COLOR_MENUTEXT: COLOR_BTNTEXT; - gr.SetPen( ::GetSysColor( nIndex ) ); - gr.SetBrushColor( ::GetSysColor( nIndex ) ); //$$ GetSysColorBrushを用いた実装のほうが効率は良い + //auto color = ::GetSysColor(m_bListBtnHilighted ? COLOR_MENUTEXT : COLOR_BTNTEXT); + auto color = DarkMode::getTextColor(); + gr.SetPen( color ); + gr.SetBrushColor( color ); //$$ GetSysColorBrushを用いた実装のほうが効率は良い for( int i = 0; i < _countof(ptBase); i++ ) { pt[i].x = ptBase[i].x + rcBtn.left; @@ -2621,7 +2604,8 @@ void CTabWnd::DrawCloseBtn( CGraphics& gr, const LPRECT lprcClient ) GetCloseBtnRect( lprcClient, &rcBtn ); // ボタンの左側にセパレータを描画する // 2007.02.27 ryoji - gr.SetPen( ::GetSysColor( COLOR_3DSHADOW ) ); + gr.SetPen( DarkMode::getDlgBackgroundColor() ); + //gr.SetPen( ::GetSysColor( COLOR_3DSHADOW ) ); ::MoveToEx( gr, rcBtn.left - DpiScaleX(4), rcBtn.top + 1, nullptr ); ::LineTo( gr, rcBtn.left - DpiScaleX(4), rcBtn.bottom - 1 ); @@ -2633,9 +2617,10 @@ void CTabWnd::DrawCloseBtn( CGraphics& gr, const LPRECT lprcClient ) rcBtn.right = rcBtn.left + (rcBtnBase.right - rcBtnBase.left); rcBtn.bottom = rcBtn.top + (rcBtnBase.bottom - rcBtnBase.left); - int nIndex = m_bCloseBtnHilighted? COLOR_MENUTEXT: COLOR_BTNTEXT; - gr.SetPen( ::GetSysColor(nIndex) ); - gr.SetBrushColor( ::GetSysColor(nIndex) ); + //auto color = ::GetSysColor(m_bCloseBtnHilighted ? COLOR_MENUTEXT : COLOR_BTNTEXT); + auto color = DarkMode::getTextColor(); + gr.SetPen( color ); + gr.SetBrushColor( color ); if( m_pShareData->m_Common.m_sTabBar.m_bDispTabWnd && !m_pShareData->m_Common.m_sTabBar.m_bDispTabWndMultiWin && !m_pShareData->m_Common.m_sTabBar.m_bTab_CloseOneWin // 2007.02.13 ryoji 条件追加(ウィンドウの閉じるボタンは全部閉じる) @@ -2673,9 +2658,10 @@ void CTabWnd::DrawTabCloseBtn( CGraphics& gr, const LPRECT lprcClient, bool sele rcBtn.right = rcBtn.left + (rcBtnBase.right - rcBtnBase.left); rcBtn.bottom = rcBtn.top + (rcBtnBase.bottom - rcBtnBase.left); - int nIndex = COLOR_BTNTEXT; - gr.SetPen( ::GetSysColor(nIndex) ); - gr.SetBrushColor( ::GetSysColor(nIndex) ); + //auto color = ::GetSysColor(COLOR_BTNTEXT); + auto color = DarkMode::getTextColor(); + gr.SetPen( color ); + gr.SetBrushColor( color ); DrawCloseFigure( gr, rcBtn ); } @@ -2907,20 +2893,26 @@ LRESULT CTabWnd::TabListMenu( POINT pt, BOOL bSel/* = TRUE*/, BOOL bFull/* = FAL // メニューを作成する // 2007.02.28 ryoji 表示切替をメニューに追加 - int iMenuSel = -1; - UINT uFlags = MF_BYPOSITION | (m_hIml? MF_OWNERDRAW: MF_STRING); + UINT fMask = MIIM_STATE | MIIM_ID | MIIM_DATA | MIIM_STRING | (m_hIml ? MIIM_BITMAP : 0); HMENU hMenu = ::CreatePopupMenu(); + MENUITEMINFO mii{}; + mii.cbSize = sizeof(mii); + mii.fMask = fMask; + mii.fType = 0; + IMAGEINFO ii; for( i = 0; i < nSelfTab; i++ ) { - ::InsertMenu( hMenu, i, uFlags, IDM_SELWINDOW + i, m_hIml? (LPCWSTR)&pData[i]: pData[i].szText ); - if( pData[i].hwnd == GetParentHwnd() ) - iMenuSel = i; - } - - // 自ウィンドウに対応するメニューをチェック状態にする - if( iMenuSel >= 0 ) - { - ::CheckMenuRadioItem( hMenu, 0, nSelfTab - 1, iMenuSel, MF_BYPOSITION ); + mii.wID = IDM_SELWINDOW + i; + mii.dwTypeData = pData[i].szText; + mii.dwItemData = (ULONG_PTR)pData[i].hwnd; + mii.cch = wcslen(pData[i].szText); + if (m_hIml) + { + auto it = m_bmpMap.find(pData[i].iImage); + mii.hbmpItem = it == m_bmpMap.end() ? nullptr : it->second; + } + mii.fState = (pData[i].hwnd == GetParentHwnd()) ? (MFS_HILITE|MFS_DEFAULT) : MF_UNHILITE; + auto ret = ::InsertMenuItem( hMenu, i, TRUE, &mii ); } // 他グループのウィンドウ一覧を追加する @@ -2930,7 +2922,17 @@ LRESULT CTabWnd::TabListMenu( POINT pt, BOOL bSel/* = TRUE*/, BOOL bFull/* = FAL { for( i = nSelfTab; i < nTab; i++ ) { - ::InsertMenu( hMenu, i, uFlags, IDM_SELWINDOW + i, m_hIml? (LPCWSTR)&pData[i]: pData[i].szText ); + mii.wID = IDM_SELWINDOW + i; + mii.dwTypeData = pData[i].szText; + mii.dwItemData = (ULONG_PTR)pData[i].hwnd; + mii.cch = wcslen(pData[i].szText); + if (m_hIml) + { + auto it = m_bmpMap.find(pData[i].iImage); + mii.hbmpItem = it == m_bmpMap.end() ? nullptr : it->second; + } + mii.fState = MF_UNHILITE; + ::InsertMenuItem(hMenu, i, TRUE, &mii); } } else @@ -3260,6 +3262,7 @@ void CTabWnd::SizeBox_ONOFF( bool bSizeBox ) GetAppInstance(), /* instance owning this window */ (LPVOID) nullptr /* pointer not needed */ ); + DarkMode::setDarkWndSafe(GetHwnd()); ::ShowWindow( m_hwndSizeBox, SW_SHOW ); m_bSizeBox = true; OnSize(); diff --git a/sakura_core/window/CTabWnd.h b/sakura_core/window/CTabWnd.h index f959173646..a67f5f6b59 100644 --- a/sakura_core/window/CTabWnd.h +++ b/sakura_core/window/CTabWnd.h @@ -169,6 +169,7 @@ class CTabWnd final : public CWnd HICON m_hIconGrep; //!< Grepアイコン int m_iIconApp; //!< アプリケーションアイコンのインデックス int m_iIconGrep; //!< Grepアイコンのインデックス + std::map m_bmpMap; BOOL m_bVisualStyle; //!< ビジュアルスタイルかどうか // 2007.04.01 ryoji BOOL m_bHovering;