mirror of
https://github.com/notepad-plus-plus/notepad-plus-plus.git
synced 2025-07-03 03:54:47 +02:00
Enhance DoubleBuffer and fix the debug assert issue
Refactor DoubleBuffer, fix bugs, add comments, allow easy disabling. Fixes #15363, close #15389
This commit is contained in:
parent
bdbd65182c
commit
955b042fcb
@ -104,6 +104,7 @@ SET(src_files
|
|||||||
./ScintillaComponent/DocTabView.cpp
|
./ScintillaComponent/DocTabView.cpp
|
||||||
./WinControls/DocumentMap/documentMap.cpp
|
./WinControls/DocumentMap/documentMap.cpp
|
||||||
./WinControls/DocumentMap/documentSnapshot.cpp
|
./WinControls/DocumentMap/documentSnapshot.cpp
|
||||||
|
./WinControls/DoubleBuffer/DoubleBuffer.cpp
|
||||||
./EncodingMapper.cpp
|
./EncodingMapper.cpp
|
||||||
./WinControls/FindCharsInRange/FindCharsInRange.cpp
|
./WinControls/FindCharsInRange/FindCharsInRange.cpp
|
||||||
./ScintillaComponent/FindReplaceDlg.cpp
|
./ScintillaComponent/FindReplaceDlg.cpp
|
||||||
@ -262,6 +263,7 @@ SET(include_files
|
|||||||
./ScintillaComponent/DocTabView.h
|
./ScintillaComponent/DocTabView.h
|
||||||
./WinControls/DocumentMap/documentMap.h
|
./WinControls/DocumentMap/documentMap.h
|
||||||
./WinControls/DocumentMap/documentSnapshot.h
|
./WinControls/DocumentMap/documentSnapshot.h
|
||||||
|
./WinControls/DoubleBuffer/DoubleBuffer.h
|
||||||
./EncodingMapper.h
|
./EncodingMapper.h
|
||||||
./MISC/FileNameStringSplitter.h
|
./MISC/FileNameStringSplitter.h
|
||||||
./WinControls/FindCharsInRange/FindCharsInRange.h
|
./WinControls/FindCharsInRange/FindCharsInRange.h
|
||||||
|
@ -1,101 +0,0 @@
|
|||||||
// This file is part of Notepad++ project
|
|
||||||
// Copyright (C) 2024 Jiri Hruska <jirka@fud.cz>
|
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// at your option any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include <windows.h>
|
|
||||||
#include <cassert>
|
|
||||||
|
|
||||||
class DoubleBuffer final
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
SIZE _size{};
|
|
||||||
HDC _hMemoryDC = nullptr;
|
|
||||||
HBITMAP _hDefaultBitmap = nullptr;
|
|
||||||
HBITMAP _hBufferBitmap = nullptr;
|
|
||||||
|
|
||||||
public:
|
|
||||||
DoubleBuffer() {}
|
|
||||||
DoubleBuffer(const DoubleBuffer&) = delete;
|
|
||||||
DoubleBuffer& operator=(const DoubleBuffer&) = delete;
|
|
||||||
|
|
||||||
~DoubleBuffer()
|
|
||||||
{
|
|
||||||
if (_hBufferBitmap)
|
|
||||||
{
|
|
||||||
::SelectObject(_hMemoryDC, _hDefaultBitmap);
|
|
||||||
::DeleteObject(_hBufferBitmap);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_hMemoryDC)
|
|
||||||
{
|
|
||||||
::DeleteDC(_hMemoryDC);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
HDC beginPaint(HWND hWnd, PAINTSTRUCT* ps)
|
|
||||||
{
|
|
||||||
if (!::BeginPaint(hWnd, ps))
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_hMemoryDC)
|
|
||||||
{
|
|
||||||
_hMemoryDC = ::CreateCompatibleDC(ps->hdc);
|
|
||||||
}
|
|
||||||
|
|
||||||
RECT clientRc{};
|
|
||||||
::GetClientRect(hWnd, &clientRc);
|
|
||||||
if (clientRc.right != _size.cx || clientRc.bottom != _size.cy || !_hBufferBitmap)
|
|
||||||
{
|
|
||||||
_size = { clientRc.right, clientRc.bottom };
|
|
||||||
|
|
||||||
if (_hBufferBitmap)
|
|
||||||
{
|
|
||||||
::SelectObject(_hMemoryDC, _hDefaultBitmap);
|
|
||||||
::DeleteObject(_hBufferBitmap);
|
|
||||||
}
|
|
||||||
|
|
||||||
_hBufferBitmap = ::CreateCompatibleBitmap(ps->hdc, _size.cx, _size.cy);
|
|
||||||
_hDefaultBitmap = static_cast<HBITMAP>(::SelectObject(_hMemoryDC, _hBufferBitmap));
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(ps->rcPaint.left < _size.cx && ps->rcPaint.top < _size.cy);
|
|
||||||
assert(ps->rcPaint.right <= _size.cx && ps->rcPaint.bottom <= _size.cy);
|
|
||||||
|
|
||||||
return _hMemoryDC;
|
|
||||||
}
|
|
||||||
|
|
||||||
void endPaint(HWND hWnd, PAINTSTRUCT* ps)
|
|
||||||
{
|
|
||||||
::BitBlt(
|
|
||||||
ps->hdc, ps->rcPaint.left, ps->rcPaint.top, ps->rcPaint.right - ps->rcPaint.left, ps->rcPaint.bottom - ps->rcPaint.top,
|
|
||||||
_hMemoryDC, ps->rcPaint.left, ps->rcPaint.top,
|
|
||||||
SRCCOPY);
|
|
||||||
|
|
||||||
::EndPaint(hWnd, ps);
|
|
||||||
}
|
|
||||||
|
|
||||||
int getWidth() const
|
|
||||||
{
|
|
||||||
return _size.cx;
|
|
||||||
}
|
|
||||||
|
|
||||||
int getHeight() const
|
|
||||||
{
|
|
||||||
return _size.cy;
|
|
||||||
}
|
|
||||||
};
|
|
149
PowerEditor/src/WinControls/DoubleBuffer/DoubleBuffer.cpp
Normal file
149
PowerEditor/src/WinControls/DoubleBuffer/DoubleBuffer.cpp
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
// This file is part of Notepad++ project
|
||||||
|
// Copyright (C) 2024 Jiri Hruska <jirka@fud.cz>
|
||||||
|
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// at your option any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include "DoubleBuffer.h"
|
||||||
|
#include <CommCtrl.h>
|
||||||
|
#include <cassert>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
void DoubleBuffer::subclass(HWND hWnd)
|
||||||
|
{
|
||||||
|
std::unique_ptr<DoubleBuffer> self(new DoubleBuffer);
|
||||||
|
if (::SetWindowSubclass(hWnd, s_subclassWndProc, 0, reinterpret_cast<DWORD_PTR>(self.get())))
|
||||||
|
{
|
||||||
|
self.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DoubleBuffer::~DoubleBuffer()
|
||||||
|
{
|
||||||
|
if (_hBufferBitmap)
|
||||||
|
{
|
||||||
|
::SelectObject(_hMemoryDC, _hDefaultBitmap);
|
||||||
|
::DeleteObject(_hBufferBitmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_hMemoryDC)
|
||||||
|
{
|
||||||
|
::DeleteDC(_hMemoryDC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DoubleBuffer::prepareBuffer(HDC hOriginalDC, const RECT& clientRc)
|
||||||
|
{
|
||||||
|
if (!_hMemoryDC)
|
||||||
|
{
|
||||||
|
_hMemoryDC = ::CreateCompatibleDC(hOriginalDC);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_hBufferBitmap || _size.cx != clientRc.right || _size.cy != clientRc.bottom)
|
||||||
|
{
|
||||||
|
_size = { clientRc.right, clientRc.bottom };
|
||||||
|
|
||||||
|
if (_hBufferBitmap)
|
||||||
|
{
|
||||||
|
::SelectObject(_hMemoryDC, _hDefaultBitmap);
|
||||||
|
::DeleteObject(_hBufferBitmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
_hBufferBitmap = ::CreateCompatibleBitmap(hOriginalDC, _size.cx, _size.cy);
|
||||||
|
if (_hBufferBitmap)
|
||||||
|
{
|
||||||
|
_hDefaultBitmap = static_cast<HBITMAP>(::SelectObject(_hMemoryDC, _hBufferBitmap));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LRESULT CALLBACK DoubleBuffer::s_subclassWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR, DWORD_PTR dwRefData)
|
||||||
|
{
|
||||||
|
return reinterpret_cast<DoubleBuffer*>(dwRefData)->subclassWndProc(hWnd, uMsg, wParam, lParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
LRESULT DoubleBuffer::subclassWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||||
|
{
|
||||||
|
switch (uMsg)
|
||||||
|
{
|
||||||
|
case WM_PAINT:
|
||||||
|
{
|
||||||
|
PAINTSTRUCT ps{};
|
||||||
|
HDC hPaintDC = ::BeginPaint(hWnd, &ps);
|
||||||
|
if (!hPaintDC)
|
||||||
|
{
|
||||||
|
// Something is wrong, no point trying to do anything further
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ps.rcPaint.right <= ps.rcPaint.left || ps.rcPaint.bottom <= ps.rcPaint.top)
|
||||||
|
{
|
||||||
|
// There is nothing to actually paint
|
||||||
|
::EndPaint(hWnd, &ps);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
RECT clientRc{};
|
||||||
|
::GetClientRect(hWnd, &clientRc);
|
||||||
|
prepareBuffer(hPaintDC, clientRc);
|
||||||
|
|
||||||
|
// Save DC state and set an appropriate clipping rectangle every time. There are two reasons:
|
||||||
|
// - Set the clipping at all, to speed up drawing operations the same as a real WM_PAINT would do
|
||||||
|
// - Reset the clipping region, as some controls leave something set on the DC (e.g. the Tab control)
|
||||||
|
int savedState = ::SaveDC(_hMemoryDC);
|
||||||
|
assert(ps.rcPaint.left < _size.cx && ps.rcPaint.top < _size.cy);
|
||||||
|
assert(ps.rcPaint.right <= _size.cx && ps.rcPaint.bottom <= _size.cy);
|
||||||
|
::IntersectClipRect(_hMemoryDC, ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right, ps.rcPaint.bottom);
|
||||||
|
|
||||||
|
// If not further overriden, DefWindowProc() will send WM_ERASEBKGND and WM_PRINTCLIENT messages
|
||||||
|
// to the window. At least the latter must be supported by the target for all this to work.
|
||||||
|
// The background must be erased always, the contents of the memory DC cannot rely on ps.fErase.
|
||||||
|
::DefSubclassProc(hWnd, WM_PRINT, reinterpret_cast<WPARAM>(_hMemoryDC), PRF_ERASEBKGND | PRF_CLIENT);
|
||||||
|
|
||||||
|
::RestoreDC(_hMemoryDC, savedState);
|
||||||
|
::BitBlt(
|
||||||
|
hPaintDC, ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top,
|
||||||
|
_hMemoryDC, ps.rcPaint.left, ps.rcPaint.top,
|
||||||
|
SRCCOPY);
|
||||||
|
::EndPaint(hWnd, &ps);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
case WM_ERASEBKGND:
|
||||||
|
{
|
||||||
|
if (reinterpret_cast<HDC>(wParam) == _hMemoryDC)
|
||||||
|
{
|
||||||
|
// The target DC is our back buffer, so drawing anything there is safe.
|
||||||
|
// Proceed to the original window procedure and let it do whatever it wants.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// This is BeginPaint() calling from WM_PAINT above, or some ad-hoc WM_ERASEBKGND
|
||||||
|
// triggered by other operations. Erasing background directly in the window DC passed
|
||||||
|
// in wParam now would be done unbuffered and thus prone to causing visual glitches.
|
||||||
|
// Do nothing and return FALSE, which will only set fErase in PAINTSTRUCT for later.
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case WM_NCDESTROY:
|
||||||
|
{
|
||||||
|
::RemoveWindowSubclass(hWnd, s_subclassWndProc, 0);
|
||||||
|
delete this;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ::DefSubclassProc(hWnd, uMsg, wParam, lParam);
|
||||||
|
}
|
59
PowerEditor/src/WinControls/DoubleBuffer/DoubleBuffer.h
Normal file
59
PowerEditor/src/WinControls/DoubleBuffer/DoubleBuffer.h
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
// This file is part of Notepad++ project
|
||||||
|
// Copyright (C) 2024 Jiri Hruska <jirka@fud.cz>
|
||||||
|
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// at your option any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Subclasses a window to use double buffering for paint operations
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Unfortunately, many controls - even those provided by Windows as part of
|
||||||
|
/// Common Controls, like Status bar or Tab bar - suffer from flickering and
|
||||||
|
/// other paint artifacts during frequent updates. This is mainly caused by
|
||||||
|
/// erasing background first in WM_ERASEBKGND and only then painting the
|
||||||
|
/// actual window content over it in WM_PAINT.
|
||||||
|
///
|
||||||
|
/// This class solves the problem by subclassing any window and transparently
|
||||||
|
/// allowing it to paint to a double/back buffer, thus avoiding the blinking.
|
||||||
|
///
|
||||||
|
/// The original window (or whatever parent window procedure) must support the
|
||||||
|
/// WM_PRINTCLIENT message. Most standard controls do, otherwise it is simple
|
||||||
|
/// to add - reuse WM_PAINT code, just get HDC from wParam instead of calling
|
||||||
|
/// BeginPaint() and EndPaint() later. If optimizing with ps.rcPaint, rely on
|
||||||
|
/// the clipping rectangle and functions like PtVisible() or RectVisible().
|
||||||
|
/// </remarks>
|
||||||
|
class DoubleBuffer final
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static void subclass(HWND hWnd);
|
||||||
|
~DoubleBuffer();
|
||||||
|
|
||||||
|
private:
|
||||||
|
DoubleBuffer() = default;
|
||||||
|
DoubleBuffer(const DoubleBuffer&) = delete;
|
||||||
|
DoubleBuffer& operator=(const DoubleBuffer&) = delete;
|
||||||
|
|
||||||
|
void prepareBuffer(HDC hOriginalDC, const RECT& clientRc);
|
||||||
|
static LRESULT CALLBACK s_subclassWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR, DWORD_PTR dwRefData);
|
||||||
|
LRESULT subclassWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||||
|
|
||||||
|
private:
|
||||||
|
SIZE _size{};
|
||||||
|
HDC _hMemoryDC = nullptr;
|
||||||
|
HBITMAP _hDefaultBitmap = nullptr;
|
||||||
|
HBITMAP _hBufferBitmap = nullptr;
|
||||||
|
};
|
@ -24,7 +24,7 @@
|
|||||||
#include "NppDarkMode.h"
|
#include "NppDarkMode.h"
|
||||||
#include <uxtheme.h>
|
#include <uxtheme.h>
|
||||||
#include <vssym32.h>
|
#include <vssym32.h>
|
||||||
#include "DoubleBuffer.h"
|
#include "DoubleBuffer/DoubleBuffer.h"
|
||||||
|
|
||||||
//#define IDC_STATUSBAR 789
|
//#define IDC_STATUSBAR 789
|
||||||
|
|
||||||
@ -51,7 +51,6 @@ struct StatusBarSubclassInfo
|
|||||||
{
|
{
|
||||||
HTHEME hTheme = nullptr;
|
HTHEME hTheme = nullptr;
|
||||||
HFONT _hFont = nullptr;
|
HFONT _hFont = nullptr;
|
||||||
DoubleBuffer _dblBuf;
|
|
||||||
|
|
||||||
StatusBarSubclassInfo() = default;
|
StatusBarSubclassInfo() = default;
|
||||||
StatusBarSubclassInfo(const HFONT& hFont)
|
StatusBarSubclassInfo(const HFONT& hFont)
|
||||||
@ -109,26 +108,28 @@ static LRESULT CALLBACK StatusBarSubclass(HWND hWnd, UINT uMsg, WPARAM wParam, L
|
|||||||
{
|
{
|
||||||
case WM_ERASEBKGND:
|
case WM_ERASEBKGND:
|
||||||
{
|
{
|
||||||
// Skip background erasing and set fErase in PAINTSTRUCT instead,
|
if (!NppDarkMode::isEnabled())
|
||||||
// WM_PAINT does all the painting in all cases
|
{
|
||||||
return FALSE;
|
break; // Let the control paint background the default way
|
||||||
|
}
|
||||||
|
|
||||||
|
RECT rc{};
|
||||||
|
::GetClientRect(hWnd, &rc);
|
||||||
|
::FillRect(reinterpret_cast<HDC>(wParam), &rc, NppDarkMode::getBackgroundBrush());
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
case WM_PAINT:
|
case WM_PAINT:
|
||||||
|
case WM_PRINTCLIENT:
|
||||||
{
|
{
|
||||||
PAINTSTRUCT ps{};
|
|
||||||
HDC hdc = pStatusBarInfo->_dblBuf.beginPaint(hWnd, &ps);
|
|
||||||
|
|
||||||
if (!NppDarkMode::isEnabled())
|
if (!NppDarkMode::isEnabled())
|
||||||
{
|
{
|
||||||
// Even if the standard status bar common control is used directly in non-dark mode,
|
break; // Let the control paint itself the default way
|
||||||
// it suffers from flickering during updates, so let it paint into a back buffer
|
|
||||||
DefSubclassProc(hWnd, WM_ERASEBKGND, reinterpret_cast<WPARAM>(hdc), 0);
|
|
||||||
DefSubclassProc(hWnd, WM_PRINTCLIENT, reinterpret_cast<WPARAM>(hdc), PRF_NONCLIENT | PRF_CLIENT);
|
|
||||||
pStatusBarInfo->_dblBuf.endPaint(hWnd, &ps);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PAINTSTRUCT ps{};
|
||||||
|
HDC hdc = (uMsg == WM_PAINT) ? ::BeginPaint(hWnd, &ps) : reinterpret_cast<HDC>(wParam);
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
int horizontal = 0;
|
int horizontal = 0;
|
||||||
int vertical = 0;
|
int vertical = 0;
|
||||||
@ -144,16 +145,13 @@ static LRESULT CALLBACK StatusBarSubclass(HWND hWnd, UINT uMsg, WPARAM wParam, L
|
|||||||
|
|
||||||
auto holdFont = static_cast<HFONT>(::SelectObject(hdc, pStatusBarInfo->_hFont));
|
auto holdFont = static_cast<HFONT>(::SelectObject(hdc, pStatusBarInfo->_hFont));
|
||||||
|
|
||||||
FillRect(hdc, &ps.rcPaint, NppDarkMode::getBackgroundBrush());
|
|
||||||
|
|
||||||
int nParts = static_cast<int>(SendMessage(hWnd, SB_GETPARTS, 0, 0));
|
int nParts = static_cast<int>(SendMessage(hWnd, SB_GETPARTS, 0, 0));
|
||||||
std::wstring str;
|
std::wstring str;
|
||||||
for (int i = 0; i < nParts; ++i)
|
for (int i = 0; i < nParts; ++i)
|
||||||
{
|
{
|
||||||
RECT rcPart{};
|
RECT rcPart{};
|
||||||
SendMessage(hWnd, SB_GETRECT, i, (LPARAM)&rcPart);
|
SendMessage(hWnd, SB_GETRECT, i, (LPARAM)&rcPart);
|
||||||
RECT rcIntersect{};
|
if (!::RectVisible(hdc, &rcPart))
|
||||||
if (!IntersectRect(&rcIntersect, &rcPart, &ps.rcPaint))
|
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -218,7 +216,8 @@ static LRESULT CALLBACK StatusBarSubclass(HWND hWnd, UINT uMsg, WPARAM wParam, L
|
|||||||
{
|
{
|
||||||
pStatusBarInfo->ensureTheme(hWnd);
|
pStatusBarInfo->ensureTheme(hWnd);
|
||||||
SIZE gripSize{};
|
SIZE gripSize{};
|
||||||
RECT rc = { 0, 0, pStatusBarInfo->_dblBuf.getWidth(), pStatusBarInfo->_dblBuf.getHeight() };
|
RECT rc{};
|
||||||
|
::GetClientRect(hWnd, &rc);
|
||||||
GetThemePartSize(pStatusBarInfo->hTheme, hdc, SP_GRIPPER, 0, &rc, TS_DRAW, &gripSize);
|
GetThemePartSize(pStatusBarInfo->hTheme, hdc, SP_GRIPPER, 0, &rc, TS_DRAW, &gripSize);
|
||||||
rc.left = rc.right - gripSize.cx;
|
rc.left = rc.right - gripSize.cx;
|
||||||
rc.top = rc.bottom - gripSize.cy;
|
rc.top = rc.bottom - gripSize.cy;
|
||||||
@ -228,7 +227,10 @@ static LRESULT CALLBACK StatusBarSubclass(HWND hWnd, UINT uMsg, WPARAM wParam, L
|
|||||||
::SelectObject(hdc, holdFont);
|
::SelectObject(hdc, holdFont);
|
||||||
::SelectObject(hdc, holdPen);
|
::SelectObject(hdc, holdPen);
|
||||||
|
|
||||||
pStatusBarInfo->_dblBuf.endPaint(hWnd, &ps);
|
if (uMsg == WM_PAINT)
|
||||||
|
{
|
||||||
|
::EndPaint(hWnd, &ps);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -280,6 +282,8 @@ void StatusBar::init(HINSTANCE hInst, HWND hPere, int nbParts)
|
|||||||
|
|
||||||
SetWindowSubclass(_hSelf, StatusBarSubclass, g_statusBarSubclassID, reinterpret_cast<DWORD_PTR>(pStatusBarInfo));
|
SetWindowSubclass(_hSelf, StatusBarSubclass, g_statusBarSubclassID, reinterpret_cast<DWORD_PTR>(pStatusBarInfo));
|
||||||
|
|
||||||
|
DoubleBuffer::subclass(_hSelf);
|
||||||
|
|
||||||
_partWidthArray.clear();
|
_partWidthArray.clear();
|
||||||
if (nbParts > 0)
|
if (nbParts > 0)
|
||||||
_partWidthArray.resize(nbParts, defaultPartWidth);
|
_partWidthArray.resize(nbParts, defaultPartWidth);
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include "TabBar.h"
|
#include "TabBar.h"
|
||||||
#include "Parameters.h"
|
#include "Parameters.h"
|
||||||
|
#include "DoubleBuffer/DoubleBuffer.h"
|
||||||
|
|
||||||
#define IDC_DRAG_TAB 1404
|
#define IDC_DRAG_TAB 1404
|
||||||
#define IDC_DRAG_INTERDIT_TAB 1405
|
#define IDC_DRAG_INTERDIT_TAB 1405
|
||||||
@ -344,6 +345,8 @@ void TabBarPlus::init(HINSTANCE hInst, HWND parent, bool isVertical, bool isMult
|
|||||||
::SetWindowLongPtr(_hSelf, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
|
::SetWindowLongPtr(_hSelf, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
|
||||||
_tabBarDefaultProc = reinterpret_cast<WNDPROC>(::SetWindowLongPtr(_hSelf, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(TabBarPlus_Proc)));
|
_tabBarDefaultProc = reinterpret_cast<WNDPROC>(::SetWindowLongPtr(_hSelf, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(TabBarPlus_Proc)));
|
||||||
|
|
||||||
|
DoubleBuffer::subclass(_hSelf);
|
||||||
|
|
||||||
setFont();
|
setFont();
|
||||||
|
|
||||||
setCloseBtnImageList();
|
setCloseBtnImageList();
|
||||||
@ -962,30 +965,30 @@ LRESULT TabBarPlus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPara
|
|||||||
|
|
||||||
case WM_ERASEBKGND:
|
case WM_ERASEBKGND:
|
||||||
{
|
{
|
||||||
// Skip background erasing and set fErase in PAINTSTRUCT instead,
|
if (!NppDarkMode::isEnabled())
|
||||||
// WM_PAINT does all the painting in all cases
|
{
|
||||||
return FALSE;
|
break; // Let the control paint background the default way
|
||||||
|
}
|
||||||
|
|
||||||
|
RECT rc{};
|
||||||
|
::GetClientRect(hwnd, &rc);
|
||||||
|
::FillRect(reinterpret_cast<HDC>(wParam), &rc, NppDarkMode::getDarkerBackgroundBrush());
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
case WM_PAINT:
|
case WM_PAINT:
|
||||||
|
case WM_PRINTCLIENT:
|
||||||
{
|
{
|
||||||
PAINTSTRUCT ps{};
|
|
||||||
HDC hdc = _dblBuf.beginPaint(hwnd, &ps);
|
|
||||||
|
|
||||||
LONG_PTR dwStyle = GetWindowLongPtr(hwnd, GWL_STYLE);
|
LONG_PTR dwStyle = GetWindowLongPtr(hwnd, GWL_STYLE);
|
||||||
if (!NppDarkMode::isEnabled() || !(dwStyle & TCS_OWNERDRAWFIXED))
|
if (!NppDarkMode::isEnabled() || !(dwStyle & TCS_OWNERDRAWFIXED))
|
||||||
{
|
{
|
||||||
// Even if the tab bar common control is used directly, e.g. in non-dark mode,
|
break; // Let the control paint itself the default way
|
||||||
// it suffers from flickering during updates, so let it paint into a back buffer
|
|
||||||
::DefWindowProc(hwnd, WM_ERASEBKGND, reinterpret_cast<WPARAM>(hdc), 0);
|
|
||||||
::DefWindowProc(hwnd, WM_PRINT, reinterpret_cast<WPARAM>(hdc), PRF_NONCLIENT | PRF_CLIENT);
|
|
||||||
_dblBuf.endPaint(hwnd, &ps);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool hasMultipleLines = ((dwStyle & TCS_BUTTONS) == TCS_BUTTONS);
|
PAINTSTRUCT ps{};
|
||||||
|
HDC hdc = (Message == WM_PAINT) ? ::BeginPaint(hwnd, &ps) : reinterpret_cast<HDC>(wParam);
|
||||||
|
|
||||||
FillRect(hdc, &ps.rcPaint, NppDarkMode::getDarkerBackgroundBrush());
|
const bool hasMultipleLines = ((dwStyle & TCS_BUTTONS) == TCS_BUTTONS);
|
||||||
|
|
||||||
UINT id = ::GetDlgCtrlID(hwnd);
|
UINT id = ::GetDlgCtrlID(hwnd);
|
||||||
|
|
||||||
@ -1020,8 +1023,7 @@ LRESULT TabBarPlus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPara
|
|||||||
|
|
||||||
dis.itemState |= ODS_NOFOCUSRECT; // maybe, does it handle it already?
|
dis.itemState |= ODS_NOFOCUSRECT; // maybe, does it handle it already?
|
||||||
|
|
||||||
RECT rcIntersect{};
|
if (::RectVisible(hdc, &dis.rcItem))
|
||||||
if (IntersectRect(&rcIntersect, &ps.rcPaint, &dis.rcItem))
|
|
||||||
{
|
{
|
||||||
if (!hasMultipleLines)
|
if (!hasMultipleLines)
|
||||||
{
|
{
|
||||||
@ -1113,7 +1115,11 @@ LRESULT TabBarPlus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPara
|
|||||||
|
|
||||||
SelectObject(hdc, holdPen);
|
SelectObject(hdc, holdPen);
|
||||||
|
|
||||||
_dblBuf.endPaint(hwnd, &ps);
|
if (Message == WM_PAINT)
|
||||||
|
{
|
||||||
|
::EndPaint(hwnd, &ps);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +28,6 @@
|
|||||||
#include <commctrl.h>
|
#include <commctrl.h>
|
||||||
#include "Window.h"
|
#include "Window.h"
|
||||||
#include "dpiManagerV2.h"
|
#include "dpiManagerV2.h"
|
||||||
#include "DoubleBuffer.h"
|
|
||||||
|
|
||||||
//Notification message
|
//Notification message
|
||||||
#define TCN_TABDROPPED (TCN_FIRST - 10)
|
#define TCN_TABDROPPED (TCN_FIRST - 10)
|
||||||
@ -244,7 +243,6 @@ protected:
|
|||||||
int _previousTabSwapped = -1;
|
int _previousTabSwapped = -1;
|
||||||
POINT _draggingPoint{}; // coordinate of Screen
|
POINT _draggingPoint{}; // coordinate of Screen
|
||||||
WNDPROC _tabBarDefaultProc = nullptr;
|
WNDPROC _tabBarDefaultProc = nullptr;
|
||||||
DoubleBuffer _dblBuf;
|
|
||||||
|
|
||||||
RECT _currentHoverTabRect{};
|
RECT _currentHoverTabRect{};
|
||||||
int _currentHoverTabItem = -1; // -1 : no mouse on any tab
|
int _currentHoverTabItem = -1; // -1 : no mouse on any tab
|
||||||
|
@ -119,6 +119,7 @@
|
|||||||
<ClCompile Include="..\src\ScintillaComponent\AutoCompletion.cpp" />
|
<ClCompile Include="..\src\ScintillaComponent\AutoCompletion.cpp" />
|
||||||
<ClCompile Include="..\src\WinControls\AnsiCharPanel\asciiListView.cpp" />
|
<ClCompile Include="..\src\WinControls\AnsiCharPanel\asciiListView.cpp" />
|
||||||
<ClCompile Include="..\src\WinControls\DocumentMap\documentSnapshot.cpp" />
|
<ClCompile Include="..\src\WinControls\DocumentMap\documentSnapshot.cpp" />
|
||||||
|
<ClCompile Include="..\src\WinControls\DoubleBuffer\DoubleBuffer.cpp" />
|
||||||
<ClCompile Include="..\src\WinControls\Grid\BabyGrid.cpp" />
|
<ClCompile Include="..\src\WinControls\Grid\BabyGrid.cpp" />
|
||||||
<ClCompile Include="..\src\WinControls\Grid\BabyGridWrapper.cpp" />
|
<ClCompile Include="..\src\WinControls\Grid\BabyGridWrapper.cpp" />
|
||||||
<ClCompile Include="..\src\ScintillaComponent\Buffer.cpp" />
|
<ClCompile Include="..\src\ScintillaComponent\Buffer.cpp" />
|
||||||
@ -298,7 +299,7 @@
|
|||||||
<ClInclude Include="..\src\WinControls\DockingWnd\DockingSplitter.h" />
|
<ClInclude Include="..\src\WinControls\DockingWnd\DockingSplitter.h" />
|
||||||
<ClInclude Include="..\src\ScintillaComponent\DocTabView.h" />
|
<ClInclude Include="..\src\ScintillaComponent\DocTabView.h" />
|
||||||
<ClInclude Include="..\src\WinControls\DocumentMap\documentMap.h" />
|
<ClInclude Include="..\src\WinControls\DocumentMap\documentMap.h" />
|
||||||
<ClInclude Include="..\src\WinControls\DoubleBuffer.h" />
|
<ClInclude Include="..\src\WinControls\DoubleBuffer\DoubleBuffer.h" />
|
||||||
<ClInclude Include="..\src\EncodingMapper.h" />
|
<ClInclude Include="..\src\EncodingMapper.h" />
|
||||||
<ClInclude Include="..\src\MISC\FileNameStringSplitter.h" />
|
<ClInclude Include="..\src\MISC\FileNameStringSplitter.h" />
|
||||||
<ClInclude Include="..\src\WinControls\FindCharsInRange\FindCharsInRange.h" />
|
<ClInclude Include="..\src\WinControls\FindCharsInRange\FindCharsInRange.h" />
|
||||||
|
Loading…
x
Reference in New Issue
Block a user