Skip to content

Commit 4cabcc9

Browse files
authored
[Feature]: Zoom tree view with ctrl+ mouse wheel and slider (#207)
* Add zoom feature for treeview on ctrl+mouse scroll * Add zoom feature using slider * Const functions * Implement reset on double click on the zoomer value * Rename variable * FIx x86 compilation * Fix ui fluctuations #closes #89 #closes #192 #fixes #89 #fixes #192
1 parent 3f37522 commit 4cabcc9

8 files changed

+246
-2
lines changed

src/NppJsonViewer/JsonViewDlg.cpp

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ JsonViewDlg::JsonViewDlg(HINSTANCE hInstance, const NppData& nppData, const bool
1919
, m_nDlgId(nCmdId)
2020
, m_pEditor(std::make_unique<ScintillaEditor>(nppData))
2121
, m_pTreeView(std::make_unique<TreeViewCtrl>())
22+
, m_pTreeViewZoom(std::make_unique<SliderCtrl>())
2223
, m_pSetting(pSetting)
2324
, m_pCurrFileName(std::make_unique<wchar_t[]>(FILENAME_LEN_IN_TITLE))
2425
{
@@ -895,6 +896,74 @@ void JsonViewDlg::EnableControls(const std::vector<DWORD>& ids, bool enable)
895896
EnableWindow(GetDlgItem(getHSelf(), id), enable ? TRUE : FALSE);
896897
}
897898

899+
auto JsonViewDlg::GetZoomLevel() const -> int
900+
{
901+
return m_pTreeViewZoom->GetPosition();
902+
}
903+
904+
void JsonViewDlg::SetZoomLevel(int pos) const
905+
{
906+
m_pTreeViewZoom->SetPosition(pos);
907+
}
908+
909+
void JsonViewDlg::SetTreeViewZoom(double dwZoomFactor) const
910+
{
911+
HWND hTreeView = GetDlgItem(getHSelf(), IDC_TREE);
912+
static HFONT hCurrentFont = reinterpret_cast<HFONT>(SendMessage(hTreeView, WM_GETFONT, 0, 0));
913+
914+
LOGFONT logFont {};
915+
GetObject(hCurrentFont, sizeof(LOGFONT), &logFont);
916+
logFont.lfHeight = static_cast<LONG>(logFont.lfHeight * dwZoomFactor);
917+
918+
static HFONT hTreeFont = nullptr;
919+
if (hTreeFont)
920+
{
921+
DeleteObject(hTreeFont);
922+
}
923+
hTreeFont = CreateFontIndirect(&logFont);
924+
925+
SendMessage(hTreeView, WM_SETFONT, reinterpret_cast<WPARAM>(hTreeFont), TRUE);
926+
InvalidateRect(hTreeView, nullptr, TRUE);
927+
}
928+
929+
void JsonViewDlg::UpdateUIOnZoom(int zoomPercentage) const
930+
{
931+
// Update zoom level on slider
932+
SetZoomLevel(zoomPercentage);
933+
934+
// Update the Tree view
935+
double zoomFactor = zoomPercentage / 100.0;
936+
SetTreeViewZoom(zoomFactor);
937+
}
938+
939+
void JsonViewDlg::HandleZoomOnScroll(WPARAM wParam) const
940+
{
941+
int pos = GetZoomLevel(); // Current zoom level
942+
int delta = GET_WHEEL_DELTA_WPARAM(wParam);
943+
944+
const auto& zoomRange = m_pTreeViewZoom->GetRange();
945+
const bool isZoomIn = delta > 0;
946+
bool bRefreshUI = true;
947+
948+
if (isZoomIn && pos < zoomRange.m_nMaxZoom)
949+
{
950+
pos += 10; // Zoom in
951+
}
952+
else if (!isZoomIn && pos > zoomRange.m_nMinZoom)
953+
{
954+
pos -= 10; // Zoom out
955+
}
956+
else
957+
{
958+
bRefreshUI = false;
959+
}
960+
961+
if (bRefreshUI)
962+
{
963+
UpdateUIOnZoom(pos);
964+
}
965+
}
966+
898967
void JsonViewDlg::HandleTreeEvents(LPARAM lParam) const
899968
{
900969
LPNMHDR lpnmh = reinterpret_cast<LPNMHDR>(lParam);
@@ -1030,6 +1099,7 @@ INT_PTR JsonViewDlg::run_dlgProc(UINT message, WPARAM wParam, LPARAM lParam)
10301099
::SetWindowLongPtr(getHSelf(), GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
10311100

10321101
m_pTreeView->OnInit(getHSelf(), IDC_TREE);
1102+
m_pTreeViewZoom->OnInit(getHSelf(), IDC_ZOOM_SLIDER, IDC_ZOOM_PERCENT);
10331103

10341104
PrepareButtons();
10351105

@@ -1107,6 +1177,31 @@ INT_PTR JsonViewDlg::run_dlgProc(UINT message, WPARAM wParam, LPARAM lParam)
11071177
return TRUE;
11081178
}
11091179

1180+
case WM_MOUSEWHEEL:
1181+
{
1182+
if (GetKeyState(VK_CONTROL) & 0x8000)
1183+
{
1184+
HandleZoomOnScroll(wParam);
1185+
return TRUE;
1186+
}
1187+
return FALSE;
1188+
}
1189+
1190+
case WM_HSCROLL:
1191+
{
1192+
HWND hSlider = GetDlgItem(getHSelf(), IDC_ZOOM_SLIDER);
1193+
1194+
if (reinterpret_cast<HWND>(lParam) == hSlider)
1195+
{
1196+
int pos = m_pTreeViewZoom->GetPosition();
1197+
UpdateUIOnZoom(pos);
1198+
1199+
return TRUE;
1200+
}
1201+
return FALSE;
1202+
}
1203+
1204+
11101205
default:
11111206
return DockingDlgInterface::run_dlgProc(message, wParam, lParam);
11121207
}

src/NppJsonViewer/JsonViewDlg.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "PluginInterface.h"
1010
#include "resource.h"
1111
#include "TreeViewCtrl.h"
12+
#include "SliderCtrl.h"
1213
#include "ScintillaEditor.h"
1314
#include "JsonHandler.h"
1415
#include "JsonNode.h"
@@ -89,6 +90,12 @@ class JsonViewDlg
8990
void ShowControls(const std::vector<DWORD>& ids, bool show);
9091
void EnableControls(const std::vector<DWORD>& ids, bool enable);
9192

93+
auto GetZoomLevel() const -> int;
94+
void SetZoomLevel(int pos) const;
95+
void SetTreeViewZoom(double dwZoomFactor) const;
96+
void UpdateUIOnZoom(int zoomPercentage) const;
97+
void HandleZoomOnScroll(WPARAM wParam) const;
98+
9299
void HandleTreeEvents(LPARAM lParam) const;
93100

94101
auto GetFormatSetting() const -> std::tuple<LE, LF, char, unsigned>;
@@ -118,5 +125,6 @@ class JsonViewDlg
118125
std::unique_ptr<wchar_t[]> m_pCurrFileName;
119126
std::unique_ptr<ScintillaEditor> m_pEditor = nullptr;
120127
std::unique_ptr<TreeViewCtrl> m_pTreeView = nullptr;
128+
std::unique_ptr<SliderCtrl> m_pTreeViewZoom = nullptr;
121129
std::shared_ptr<Setting> m_pSetting = nullptr;
122130
};

src/NppJsonViewer/NPPJSONViewer.vcxproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@
197197
<ClCompile Include="ScintillaEditor.cpp" />
198198
<ClCompile Include="SettingsDlg.cpp" />
199199
<ClCompile Include="ShortcutCommand.cpp" />
200+
<ClCompile Include="SliderCtrl.cpp" />
200201
<ClCompile Include="TreeViewCtrl.cpp" />
201202
</ItemGroup>
202203
<ItemGroup>
@@ -221,6 +222,7 @@
221222
<ClInclude Include="ScintillaEditor.h" />
222223
<ClInclude Include="SettingsDlg.h" />
223224
<ClInclude Include="ShortcutCommand.h" />
225+
<ClInclude Include="SliderCtrl.h" />
224226
<ClInclude Include="StopWatch.h" />
225227
<ClCompile Include="TreeHandler.h" />
226228
<ClInclude Include="TrackingStream.h" />

src/NppJsonViewer/NPPJSONViewer.vcxproj.filters

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@
6060
<ClCompile Include="TreeHandler.h">
6161
<Filter>Header Files</Filter>
6262
</ClCompile>
63+
<ClCompile Include="SliderCtrl.cpp">
64+
<Filter>Source Files</Filter>
65+
</ClCompile>
6366
</ItemGroup>
6467
<ItemGroup>
6568
<ClInclude Include="resource.h">
@@ -134,6 +137,9 @@
134137
<ClInclude Include="TrackingStream.h">
135138
<Filter>Header Files</Filter>
136139
</ClInclude>
140+
<ClInclude Include="SliderCtrl.h">
141+
<Filter>Header Files</Filter>
142+
</ClInclude>
137143
</ItemGroup>
138144
<ItemGroup>
139145
<ResourceCompile Include="resource.rc">

src/NppJsonViewer/SliderCtrl.cpp

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
#include "SliderCtrl.h"
2+
3+
#include <string>
4+
5+
SliderCtrl::SliderCtrl(const SliderRange& sliderRange)
6+
: m_sliderRange(sliderRange)
7+
{
8+
}
9+
10+
SliderCtrl::~SliderCtrl()
11+
{
12+
// Restore the original window procedure on cleanup
13+
SetWindowLongPtr(m_hSelf, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(m_oldSliderProc));
14+
}
15+
16+
void SliderCtrl::OnInit(HWND hParent, int sliderID, int sliderInfoID)
17+
{
18+
m_hParent = hParent;
19+
m_hSelf = GetDlgItem(m_hParent, sliderID);
20+
m_hSelfInfo = GetDlgItem(m_hParent, sliderInfoID);
21+
22+
// Set slider range and initial position
23+
SendMessage(m_hSelf, TBM_SETRANGE, TRUE, MAKELPARAM(m_sliderRange.m_nMinZoom, m_sliderRange.m_nMaxZoom));
24+
SendMessage(m_hSelf, TBM_SETPOS, TRUE, m_sliderRange.m_nDefault);
25+
SendMessage(m_hSelf, TBM_SETPAGESIZE, 0, m_sliderRange.m_nSteps);
26+
27+
UpdateInfo(m_sliderRange.m_nDefault);
28+
29+
// Subclass the slider control to handle double-click events
30+
m_oldSliderProc = reinterpret_cast<WNDPROC>(SetWindowLongPtr(m_hSelfInfo, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(runWinProc)));
31+
32+
// Save this instance for access in the static window procedure
33+
SetWindowLongPtr(m_hSelfInfo, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
34+
}
35+
36+
auto SliderCtrl::GetPosition() const -> int
37+
{
38+
int pos = static_cast<int>(SendMessage(m_hSelf, TBM_GETPOS, 0, 0));
39+
return pos;
40+
}
41+
42+
void SliderCtrl::SetPosition(int pos) const
43+
{
44+
// Set slider position
45+
SendMessage(m_hSelf, TBM_SETPOS, TRUE, pos);
46+
47+
// Set slider position in text value
48+
UpdateInfo(pos);
49+
}
50+
51+
void SliderCtrl::UpdateInfo(int zoomPercentage) const
52+
{
53+
std::wstring sliderInfoText = std::to_wstring(zoomPercentage) + L"%";
54+
SetWindowText(m_hSelfInfo, sliderInfoText.c_str());
55+
}
56+
57+
LRESULT SliderCtrl::runWinProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
58+
{
59+
SliderCtrl* pThis = reinterpret_cast<SliderCtrl*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
60+
61+
if (pThis)
62+
{
63+
if (message == WM_LBUTTONDBLCLK)
64+
{
65+
// Reset slider to 100% on double-click
66+
// Also notify its parent to adjust tree view as well
67+
pThis->SetPosition(100);
68+
SendMessage(pThis->m_hParent, WM_HSCROLL, NULL, reinterpret_cast<LPARAM>(pThis->m_hSelf));
69+
}
70+
71+
// Call the original window procedure for other messages
72+
return CallWindowProc(pThis->m_oldSliderProc, hWnd, message, wParam, lParam);
73+
}
74+
75+
return FALSE;
76+
}

src/NppJsonViewer/SliderCtrl.h

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#pragma once
2+
3+
4+
#include <Windows.h>
5+
#include <CommCtrl.h>
6+
7+
struct SliderRange
8+
{
9+
int m_nDefault = 100;
10+
int m_nMinZoom = 80;
11+
int m_nMaxZoom = 250;
12+
int m_nSteps = 10;
13+
}; // namespace SliderRange
14+
15+
class SliderCtrl
16+
{
17+
HWND m_hParent = nullptr;
18+
HWND m_hSelf = nullptr;
19+
HWND m_hSelfInfo = nullptr;
20+
HWND m_hTreeView = nullptr;
21+
WNDPROC m_oldSliderProc = nullptr;
22+
const SliderRange m_sliderRange {};
23+
24+
public:
25+
explicit SliderCtrl(const SliderRange& sliderRange = {});
26+
27+
~SliderCtrl();
28+
29+
void OnInit(HWND hParent, int sliderID, int sliderInfoID);
30+
31+
HWND GetSliderHandle() const
32+
{
33+
return m_hSelf;
34+
}
35+
36+
HWND GetSliderInfoHandle() const
37+
{
38+
return m_hSelfInfo;
39+
}
40+
41+
auto GetRange() const -> const SliderRange&
42+
{
43+
return m_sliderRange;
44+
}
45+
46+
auto GetPosition() const -> int;
47+
void SetPosition(int pos) const;
48+
void UpdateInfo(int zoomPercentage) const;
49+
50+
private:
51+
// Static window procedure for the slider
52+
static LRESULT CALLBACK runWinProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
53+
};

src/NppJsonViewer/resource.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@
4242
#define IDC_CHK_IGNORE_COMMENT 1031
4343
#define IDC_CHK_JSON_HIGHLIGHT 1032
4444
#define IDC_CHK_REPLACE_UNDEFINED 1033
45+
#define IDC_ZOOM_SLIDER 1034
46+
#define IDC_ZOOM_PERCENT 1035
4547
#define IDM_COPY_TREEITEM 40001
4648
#define IDM_COPY_NODENAME 40002
4749
#define IDM_COPY_NODEVALUE 40003
@@ -55,7 +57,7 @@
5557
#ifndef APSTUDIO_READONLY_SYMBOLS
5658
#define _APS_NEXT_RESOURCE_VALUE 110
5759
#define _APS_NEXT_COMMAND_VALUE 40007
58-
#define _APS_NEXT_CONTROL_VALUE 1034
60+
#define _APS_NEXT_CONTROL_VALUE 1036
5961
#define _APS_NEXT_SYMED_VALUE 101
6062
#endif
6163
#endif

src/NppJsonViewer/resource.rc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,9 @@ BEGIN
8888
CONTROL "",IDC_DIVIDER,"Static",SS_ETCHEDVERT,56,1,2,16
8989
EDITTEXT IDC_EDT_SEARCH,60,2,99,12,ES_AUTOHSCROLL
9090
PUSHBUTTON "",IDC_BTN_SEARCH,160,2,16,12,BS_ICON
91-
CONTROL "",IDC_TREE,"SysTreeView32",TVS_HASBUTTONS | TVS_HASLINES | TVS_DISABLEDRAGDROP | TVS_SHOWSELALWAYS | TVS_FULLROWSELECT | WS_HSCROLL | WS_TABSTOP,2,18,173,274,WS_EX_CLIENTEDGE
91+
CONTROL "",IDC_ZOOM_SLIDER,"msctls_trackbar32",TBS_AUTOTICKS | TBS_BOTH | TBS_NOTICKS | WS_TABSTOP,2,16,58,12
92+
RTEXT "100%",IDC_ZOOM_PERCENT,60,16,22,12,SS_NOTIFY | NOT WS_GROUP,WS_EX_RIGHT
93+
CONTROL "",IDC_TREE,"SysTreeView32",TVS_HASBUTTONS | TVS_HASLINES | TVS_DISABLEDRAGDROP | TVS_SHOWSELALWAYS | TVS_FULLROWSELECT | WS_HSCROLL | WS_TABSTOP,2,30,173,264,WS_EX_CLIENTEDGE
9294
EDITTEXT IDC_EDT_NODEPATH,2,296,173,12,ES_AUTOHSCROLL | ES_READONLY
9395
END
9496

0 commit comments

Comments
 (0)