diff --git a/doc/history/2026-09-23-12차.md b/doc/history/2026-09-23-12차.md index c02951a..8fdebed 100644 --- a/doc/history/2026-09-23-12차.md +++ b/doc/history/2026-09-23-12차.md @@ -2,6 +2,23 @@ 지시서: [../작업지시/12차.md](../작업지시/12차.md) +## Shift+휠 가로 · Ctrl+↓ 와 아래 "지금 줄" 칸 · Ctrl+W 로 폴더 비교 · 다크 모드 (2026-10-01, 사용자 요청 · 결정 · 완료) + +1. **Shift+휠 = 가로 스크롤**(파일 비교 · 메모, 사용자 결정). 예전에는 Ctrl+휠(글자 크기)만 따로 받고 Shift+휠은 세로로 굴렀다. + 파일 비교는 가로 휠(틸트)과 같은 길(`ScrollSourcePanes` · `ScrollEditor`)로 보낸다 — 마우스가 놓인 칸이 움직이고 나머지는 지금처럼 따라온다. 휠 아래 = 오른쪽. +2. **Ctrl+↓ / Ctrl+↑ = 다음 · 이전 차이**(대체 키, 단축키 표에 더함 — 설명 창에도 나온다). 그리고 **아래 "지금 줄" 칸**(사용자 결정: 캐럿 줄 두 줄) — + 칸과 상태 줄 사이에 캐럿 행의 BASE(변경 전) · LOCAL(변경 후)을 위아래로. 칸과 같은 `CodeTextBlock`(문법 색 · 바뀐 글자 칠하기 · 줄 색), 긴 줄은 접어 끝까지, + 한쪽에 없는 줄이면 `(이 줄 없음 …)`. `HomeViewModel.CaretLine` — 캐럿이 옮겨지거나 행이 다시 만들어지면(`UpdateSummaries`) 다시 알린다. +3. **Ctrl+W 로 닫으면 폴더 비교로**(사용자 결정: 폴더 비교에서 연 파일일 때만). `RequestPlainCompare(fromFolder:)` 로 표시를 실어 보내고 + (폴더 비교 두 번 누르기 · 폴더 검색 결과), 파일 비교가 문서 탭(`DocTab.FromFolder`)에 붙인다. ◀ 이전 파일 · 다음 파일 ▶ 로 짝을 바꿔도(탭을 새로 만드는 `Replace`) 이어 받는다. + 그 탭을 닫으면 `TabManager.Activate(ViewIds.Folder)`. 남은 탭은 그대로 다음 탭을 띄워 둔다. + "폴더 비교에서 파일을 열면 하단 탭도 파일 비교로" 는 플랫폼 `8158bbf`(배포본 `2026-10-01 13:37:46`)에서 이미 고쳤다 — 그 전 플랫폼인 PC 에서 보인 것. +4. **다크 모드 가독성** — 어두운 테마로 켜서 찍어 봤다. 가장 큰 것은 **폴더 비교 목록만 흰 바탕**: 플랫폼 테마가 ListBox · ListView · DataGrid 는 칠하지만 + TreeView 는 칠하지 않아 WPF 기본(흰 바탕 · 검은 글자)으로 남았다 → 바탕 · 글자색을 테마에서 받고 항목(TreeViewItem) 글자색도 준다(줄 상태 색은 반투명이라 그대로 맞는다). + 색 구분의 0 항목 흐리기 0.35 → 0.55(어두운 바탕에서 거의 묻혔다). 차이 줄 바탕색 대비는 두 테마가 비슷해(1.2~1.5) 그대로. 꺼진 단추 글자가 흐린 것은 플랫폼 테마 몫이라 손대지 않았다. + +시험(이것만): `g27-five`(새, 어두운 테마) — Shift+휠 편집기 가로 0 → 20%(세로 그대로) · BASE 칸 위에서도 · 메모 0 → 5.7%, Ctrl+↓ 로 차이 2/2 → 1/2 · 아래 칸 BASE · LOCAL 이름표, +기본 짝은 Ctrl+W 뒤 파일 비교 그대로 · 폴더 비교에서 연 alpha 는 하단 탭 파일 비교(1) → Ctrl+W 뒤 폴더 비교(0), 사진으로 폴더 목록 어두운 바탕 · 아래 칸 확인. 실패 0. 기존 회귀는 돌리지 않았다. ## 전체 반영 · 자동 병합의 주석이 너무 많다 (2026-10-01, 사용자 요청 · 결정 · 완료) [전체 반영] 은 반영할 줄마다 `Apply` 를 따로 불러 **바뀐 줄마다 머지 주석 한 줄**, 되돌리기도 줄마다 한 걸음이었다. diff --git a/doc/history/changelog.md b/doc/history/changelog.md index 7882c32..e0285cf 100644 --- a/doc/history/changelog.md +++ b/doc/history/changelog.md @@ -8,6 +8,7 @@ | 날짜 | 항목 | 커밋 | |---|---|---| +| 2026-10-01 | **Shift+휠 가로 · Ctrl+↓ 와 아래 "지금 줄" 칸 · Ctrl+W 로 폴더 비교 · 다크 모드(사용자 요청 · 결정)** — ① Shift+휠 = 가로(파일 비교는 가로 휠과 같은 길, 메모도) ② Ctrl+↓/↑ = 다음 · 이전 차이(대체 키) + 칸과 상태 줄 사이에 캐럿 행의 BASE(변경 전) · LOCAL(변경 후)을 위아래로(같은 `CodeTextBlock`, 긴 줄은 접음, `CaretLine`) ③ 폴더 비교에서 연 탭(`DocTab.FromFolder`, `RequestPlainCompare(fromFolder:)`, ◀ ▶ 로 바꿔도 이어 받음)을 닫으면 폴더 비교로 ④ 폴더 비교 목록이 어두운 테마에서도 흰 바탕 · 검은 글자 — 플랫폼 테마가 TreeView 는 안 칠함 → 테마 바탕 · 글자색, 색 구분 0 항목 흐리기 0.35 → 0.55. 하단 탭이 파일 비교로 안 바뀌던 것은 플랫폼 `8158bbf` 에서 이미 고침. 화면 `g27-five`(새, 어두운 테마) 실패 0. 기존 회귀는 돌리지 않음. 빌드 경고 0 · 오류 0 | 아래 | | 2026-10-01 | **배포 묶음 스크립트를 런처 기준으로(사용자 요청)** — `scripts\make-bundle.ps1` 은 11차(셸을 켜던 때) 것이라 새 플랫폼의 `UbisamBase.Launcher.exe` · 그 설정 · `platform-version.json` 을 "까닭 미상" 으로 경고했다. 셋에 까닭을 적고, 런처와 런처 설정을 꼭 있어야 하는 파일로, 런처 설정의 바인딩 리디렉트 검사를 더함(없으면 켜자마자 죽는다 - 플랫폼 `publish-platform.ps1` 과 같은 검사). `배포묶음.txt` 는 "런처를 켠다" · 런처가 켤 때 하는 일 · 플랫폼 버전. 확인: `-NoBuild` 로 44개 · 경고 없음, 묶음에서 런처로 켜고 끔. 같은 날 알파판 ZIP(`배포\MergeHub_v0.12_alpha_20261001.zip`, 커밋 `b717f4e` · 플랫폼 `2026-10-01 13:37:46`)은 지난번 알파판 구성(Release 출력 + `UbisamPlatform\bin` + 설치안내)으로 따로 만들었다 | 아래 | | 2026-10-01 | **전체 반영 · 자동 병합의 주석을 구간마다 한 줄로(사용자 요청 · 결정)** — 줄마다 머지 주석이 붙던 것. ① 두 파일 비교 [전체 반영]: 반영할 수 있는 줄이 이어진 구간마다 [구간 반영] 과 같게(`ApplyGroup`), 지우는 반영은 `삭제 N줄`, 모든 구간을 한 묶음으로 Undo 한 번 ② 3-Way [전체 반영] 끔 — 차이 나는 모든 줄을 공통 조상으로 바꾸던 동작(꺼져도 툴팁으로 까닭) ③ 3-Way [자동 병합]: 저쪽만 고친 줄 구간마다 주석 한 줄 · Undo 한 번(충돌 · 내 줄은 구간을 끊고 그대로). 화면 `g22-accept-all` 주석 7 → 3, `g23-three-way`(`--merge`) 5 → 2, 실패 0. 기존 회귀는 돌리지 않음. 빌드 경고 0 · 오류 0 | 아래 | | 2026-10-01 | **스크롤을 내리면 프로그램이 뻗던 것(사용자 보고)** — 어제 칸 맞추기(`f105bab`) 뒤 응답 없음. ① 사람이 BASE 를 굴려도 LOCAL 기준으로 되돌려 초당 32번 밀고 당김 → 손이 닿은 칸(휠 · 누름 · 키)을 기준으로, LOCAL 쪽일 때만 BASE 를 맞춤 ② 따라 굴러가는 도중에 재서 보정값이 휠 한 칸씩 6,619px 까지 쌓임 → 메아리 막기 중이면 큰 맞추기는 앱이 한가할 때 한 번, 못 굴리면 실제로 움직인 만큼만 ③ 칸 목록(그 칸에 있는 줄만)의 항목 번호를 정렬 행 번호로 써 엉뚱한 줄끼리 견줌 → 줄 객체로 오감 ④ 빠르게 굴리면 사람의 스크롤이 메아리로 버려져 따라가는 칸이 멈춤 → 멈춘 뒤 한 번 따라잡기, BASE 를 굴릴 때 보정값을 보이는 줄에서 다시 잼. 화면 `g20-scroll-end` · `g21-blocks-fast`(새) 응답 · 따라옴, `g7` 실패 0, `g17` 통과. 사용자 파일로는 확인 안 함 · 기존 회귀는 돌리지 않음. 빌드 경고 0 · 오류 0 | 아래 | diff --git a/doc/진행상황.md b/doc/진행상황.md index 97972d0..12526b9 100644 --- a/doc/진행상황.md +++ b/doc/진행상황.md @@ -446,6 +446,7 @@ | 상태 | 항목 | |---|---| +| **완료** | **Shift+휠 가로 · Ctrl+↓ 와 아래 "지금 줄" 칸 · Ctrl+W 로 폴더 비교 · 다크 모드**(사용자 요청 · 결정) — Shift+휠 가로(파일 비교 · 메모), Ctrl+↓/↑ 차이 이동 대체 키 + 캐럿 행의 BASE · LOCAL 을 아래에 위아래로, 폴더 비교에서 연 탭을 닫으면 폴더 비교로, 폴더 비교 목록이 어두운 테마에서도 흰 바탕이던 것(TreeView 는 플랫폼 테마가 안 칠함) · 0 항목 흐리기 완화. 화면 `g27-five` 실패 0 | | **완료** | **전체 반영 · 자동 병합의 주석이 너무 많다**(사용자 요청 · 결정) — 두 파일 비교 [전체 반영] 을 구간 반영처럼(구간마다 주석 한 줄 · Undo 한 번), 3-Way [전체 반영] 은 끔(공통 조상으로 되돌리는 동작이었다), 3-Way [자동 병합] 도 구간마다 주석 한 줄 · Undo 한 번. 화면 `g22` 주석 7 → 3, `g23` 5 → 2, 실패 0 | | **완료** | **스크롤을 내리면 프로그램이 뻗는다**(사용자 보고, 어제 `f105bab` 뒤) — 응답 없음(AppHang). 원인 넷: BASE 를 굴려도 LOCAL 쪽으로 되돌려 밀고 당김 · 따라 굴러가는 도중에 재서 보정값이 6,619px 까지 쌓임 · 칸 목록 항목 번호를 정렬 행 번호로 씀(한쪽에만 있는 줄만큼 엉뚱한 줄끼리 견줌) · 빠르게 굴리면 사람의 스크롤이 버려짐. 손이 닿은 칸을 기준으로, 큰 맞추기는 한가할 때 한 번, 줄 객체로 오가기, 버려지면 멈춘 뒤 따라잡기. 화면 `g20` · `g21`(새) 응답, `g7` 실패 0, `g17` 통과 | | **완료** | **끌 때 저장하지 않은 편집을 묻는다**(사용자 요청 · 결정) — 파일 비교의 모든 탭(Git 모드 · 뒤 탭 · 닫은 탭 포함, 메모 제외)에 편집이 있으면 [저장하고 종료] · [저장하지 않고 종료] · [취소]. 버리면 보관본도 비워 다음에 안 살아남. 플랫폼 `ICloseGuard` 를 그대로 씀(플랫폼 수정 없음). 화면 `g19-exit-confirm` 실패 0. Git 모드는 화면 시험 안 함 · 기존 회귀는 사용자 지시로 안 돌림 | diff --git a/src/MergeHub/Services/DocTabs.cs b/src/MergeHub/Services/DocTabs.cs index 2d40427..b8ccd44 100644 --- a/src/MergeHub/Services/DocTabs.cs +++ b/src/MergeHub/Services/DocTabs.cs @@ -68,6 +68,9 @@ namespace MergeHub.Services /// 화면에 없는 동안 맡아 둔 편집. 떠 있는 탭은 화면이 주인이라 비어 있다. public DocTabState? Parked { get; set; } + /// 폴더 비교에서 연 탭. 닫으면 폴더 비교로 돌아간다(2026-10-01 사용자 요청). + public bool FromFolder { get; set; } + private bool _isDirty; /// 저장하지 않은 편집이 있는가. 탭 이름 앞 · 표시에 쓴다. diff --git a/src/MergeHub/Services/GitWorkspace.cs b/src/MergeHub/Services/GitWorkspace.cs index 09a2201..c06472e 100644 --- a/src/MergeHub/Services/GitWorkspace.cs +++ b/src/MergeHub/Services/GitWorkspace.cs @@ -653,11 +653,13 @@ namespace MergeHub.Services /// 찾은 줄을 눈으로 다시 찾아야 한다. /// /// 그 번호가 왼쪽 파일 기준인지. 아니면 오른쪽 기준이다. - public void RequestPlainCompare(string leftFile, string rightFile, int line = 0, bool lineIsLeft = true) + /// 폴더 비교에서 열었는지. 파일 비교가 그 문서 탭에 적어 두고, 탭을 닫으면 폴더 비교로 돌려보낸다. + public void RequestPlainCompare(string leftFile, string rightFile, int line = 0, bool lineIsLeft = true, bool fromFolder = false) { _pendingPlainCompare = (leftFile, rightFile); RequestedLine = line; RequestedLineIsLeft = lineIsLeft; + RequestedFromFolder = fromFolder; OnUi(DeliverPendingPlainCompare); } @@ -695,6 +697,17 @@ namespace MergeHub.Services /// 그 번호가 왼쪽 파일 기준인지. public bool RequestedLineIsLeft { get; private set; } + /// 넘긴 짝을 폴더 비교에서 열었는지. + public bool RequestedFromFolder { get; private set; } + + /// 폴더 비교에서 열었는지를 한 번 쓰고 지운다 - 다음에 다른 길로 연 짝까지 끌려가지 않게. + public bool TakeRequestedFromFolder() + { + var one = RequestedFromFolder; + RequestedFromFolder = false; + return one; + } + /// /// 짚어 줄 자리를 한 번 쓰고 지운다. /// 지우지 않으면 그 다음에 연 파일까지 같은 줄로 끌려간다. diff --git a/src/MergeHub/Services/ShortcutMap.cs b/src/MergeHub/Services/ShortcutMap.cs index ff479da..ad9a1fb 100644 --- a/src/MergeHub/Services/ShortcutMap.cs +++ b/src/MergeHub/Services/ShortcutMap.cs @@ -114,6 +114,8 @@ namespace MergeHub.Services new ShortcutEntry(ShortcutAction.PrevDiff, Key.Up, ModifierKeys.Alt, "차이 이동", "이전 차이"), new ShortcutEntry(ShortcutAction.NextDiff, Key.F4, ModifierKeys.None, "차이 이동", "다음 차이 (대체 키)"), new ShortcutEntry(ShortcutAction.PrevDiff, Key.F4, ModifierKeys.Shift, "차이 이동", "이전 차이 (대체 키)"), + new ShortcutEntry(ShortcutAction.NextDiff, Key.Down, ModifierKeys.Control, "차이 이동", "다음 차이 (대체 키)"), + new ShortcutEntry(ShortcutAction.PrevDiff, Key.Up, ModifierKeys.Control, "차이 이동", "이전 차이 (대체 키)"), new ShortcutEntry(ShortcutAction.FirstDiff, Key.Home, ModifierKeys.Alt, "차이 이동", "파일의 첫 차이"), new ShortcutEntry(ShortcutAction.LastDiff, Key.End, ModifierKeys.Alt, "차이 이동", "파일의 마지막 차이"), new ShortcutEntry(ShortcutAction.FirstDiff, Key.Home, ModifierKeys.Control, "차이 이동", "첫 차이 (대체 키)"), diff --git a/src/MergeHub/ViewModels/FolderViewModel.cs b/src/MergeHub/ViewModels/FolderViewModel.cs index a4f8c72..ccf5eda 100644 --- a/src/MergeHub/ViewModels/FolderViewModel.cs +++ b/src/MergeHub/ViewModels/FolderViewModel.cs @@ -650,7 +650,7 @@ namespace MergeHub.ViewModels // 오른쪽에서만 나온 줄이면 오른쪽 파일 기준 번호다. _workspace.RequestPlainCompare(hit.LeftPath, hit.RightPath, hit.LineNumber, - lineIsLeft: hit.Side != SearchSide.Right); + lineIsLeft: hit.Side != SearchSide.Right, fromFolder: true); UbisamBase.Core.Modules.TabManager.Activate(ViewIds.Home); } @@ -762,7 +762,7 @@ namespace MergeHub.ViewModels // 요청을 먼저 걸고 탭을 연다. 파일 비교 화면이 아직 없으면 그 화면이 만들어지면서 // 남아 있는 요청을 직접 집어 간다(GitWorkspace.RequestPlainCompare 설명 참고). - _workspace.RequestPlainCompare(node.LeftPath, node.RightPath); + _workspace.RequestPlainCompare(node.LeftPath, node.RightPath, fromFolder: true); UbisamBase.Core.Modules.TabManager.Activate(ViewIds.Home); } diff --git a/src/MergeHub/ViewModels/HomeViewModel.Tabs.cs b/src/MergeHub/ViewModels/HomeViewModel.Tabs.cs index 9551757..b20e88d 100644 --- a/src/MergeHub/ViewModels/HomeViewModel.Tabs.cs +++ b/src/MergeHub/ViewModels/HomeViewModel.Tabs.cs @@ -319,6 +319,10 @@ namespace MergeHub.ViewModels SyncTabItems(); SaveSession(); // 12차 E-1 - 닫아도 글은 남는다. 그 자리에서 적어 둔다. + // 폴더 비교에서 연 파일을 닫았으면 폴더 비교로 돌아간다(2026-10-01 사용자 요청 - 목록에서 하나씩 열어 보고 닫는 손버릇). + // 남은 탭은 그대로 다음 탭을 띄워 둔다 - 파일 비교 탭으로 돌아오면 거기서 이어진다. + if (tab.FromFolder) UbisamBase.Core.Modules.TabManager.Activate(ViewIds.Folder); + if (next is null || ReferenceEquals(next, tab)) return; _resumeTab = next; diff --git a/src/MergeHub/ViewModels/HomeViewModel.cs b/src/MergeHub/ViewModels/HomeViewModel.cs index 10b682b..768a697 100644 --- a/src/MergeHub/ViewModels/HomeViewModel.cs +++ b/src/MergeHub/ViewModels/HomeViewModel.cs @@ -133,7 +133,12 @@ namespace MergeHub.ViewModels // 탭을 먼저 잡아 둔다. 아래 LoadPlainFilesAsync 가 다 읽은 뒤 맡겨 둔 편집을 되살린다. var replaceTab = _replaceTab; _replaceTab = false; + + // 폴더 비교에서 연 짝이면 탭에 적어 둔다 - 닫으면 폴더 비교로 돌아간다. ◀ 이전 파일 · 다음 파일 ▶ 은 폴더 목록을 + // 훑는 것이라 탭을 새로 만들어도(Replace) 그 표시를 이어 받는다. + var fromFolder = _workspace.TakeRequestedFromFolder() || (replaceTab && Tabs.Current?.FromFolder == true); OpenPairInTab(leftFile, rightFile, replaceTab); + if (fromFolder && Tabs.Current is { } openedTab) openedTab.FromFolder = true; // 3-Way 를 끄되 그 때문에 본문을 다시 읽지는 않게 한다 - 그 재로드가 작업 게이트를 // 먼저 잡으면 바로 아래 파일 비교가 "다른 작업 진행 중"으로 건너뛰어진다. @@ -3668,8 +3673,15 @@ namespace MergeHub.ViewModels AcceptBlockToBaseCommand.NotifyCanExecuteChanged(); // 12차 G-2 - 왼쪽으로 보내는 짝 AcceptMemberCommand.NotifyCanExecuteChanged(); OnPropertyChanged(nameof(MemberHint)); + OnPropertyChanged(nameof(CaretLine)); } + /// + /// 캐럿이 있는 행. 화면 아래 "지금 줄" 칸이 이 행의 BASE · LOCAL 을 위아래로 보여 준다(2026-10-01 사용자 요청 - + /// 다음 차이로 옮겨 가면 무엇이 바뀌었는지 아래에서 한 줄씩 견줘 보고 싶다). 행이 다시 만들어지면 가 다시 알린다. + /// + public MergeLine? CaretLine => CaretRow >= 0 && CaretRow < Lines.Count ? Lines[CaretRow] : null; + /// 상태바에 띄우는 "차이 3 / 15". [ObservableProperty] private string _diffPosition = "차이 -"; @@ -4233,6 +4245,8 @@ namespace MergeHub.ViewModels private void UpdateSummaries() { + OnPropertyChanged(nameof(CaretLine)); // 행이 다시 만들어지면 아래 "지금 줄" 칸이 옛 행을 붙들지 않게 + // 줄을 고르거나 머지 주석이 끼어들면 결과 줄 수가 바뀐다. 그릴 때마다 번호를 다시 매긴다(8차 B-3). RenumberMerged(Lines); RenumberBase(Lines); // 왼쪽도 마찬가지다(12차 B-1 로 왼쪽이 바뀔 수 있게 됐다) diff --git a/src/MergeHub/Views/Controls/ZeroToDimConverter.cs b/src/MergeHub/Views/Controls/ZeroToDimConverter.cs index 8097b27..2c45605 100644 --- a/src/MergeHub/Views/Controls/ZeroToDimConverter.cs +++ b/src/MergeHub/Views/Controls/ZeroToDimConverter.cs @@ -12,8 +12,11 @@ namespace MergeHub.Views.Controls /// public sealed class ZeroToDimConverter : IValueConverter { - /// 0 일 때의 흐리기. 읽히기는 하되 눈이 먼저 가지는 않는 정도. - private const double Dim = 0.35; + /// + /// 0 일 때의 흐리기. 읽히기는 하되 눈이 먼저 가지는 않는 정도. + /// 0.35 는 어두운 테마에서 바탕에 거의 묻혔다(2026-10-01 사용자 보고) - 두 테마 모두 읽히는 0.55 로. + /// + private const double Dim = 0.55; public object Convert(object value, Type targetType, object parameter, CultureInfo culture) => value is int count && count == 0 ? Dim : 1.0; diff --git a/src/MergeHub/Views/FolderView.xaml b/src/MergeHub/Views/FolderView.xaml index 978b9da..b0ca6de 100644 --- a/src/MergeHub/Views/FolderView.xaml +++ b/src/MergeHub/Views/FolderView.xaml @@ -107,6 +107,8 @@ + + @@ -366,8 +368,12 @@ + + + @@ -1991,6 +1993,94 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - diff --git a/src/MergeHub/Views/HomeView.xaml.cs b/src/MergeHub/Views/HomeView.xaml.cs index f712f28..fd5d229 100644 --- a/src/MergeHub/Views/HomeView.xaml.cs +++ b/src/MergeHub/Views/HomeView.xaml.cs @@ -241,6 +241,15 @@ namespace MergeHub.Views // Ctrl+휠로 코드 글자 크기(11차 F-5). 휠 한 칸에 1씩. 목록 · 편집기의 스크롤보다 먼저 가로챈다. PreviewMouseWheel += (_, e) => { + // Shift+휠은 가로로(2026-10-01 사용자 요청 - VS · 브라우저와 같은 손버릇). 가로 휠(틸트)과 같은 길로 보낸다 - + // 마우스가 놓인 칸이 움직이고 나머지는 지금처럼 따라온다. 휠을 아래로 굴리면 오른쪽으로 간다. + if (Keyboard.Modifiers == ModifierKeys.Shift) + { + var step = -e.Delta / 120.0 * 48; + if (ScrollSourcePanes(step) || ScrollEditor(step)) e.Handled = true; + return; + } + if (Keyboard.Modifiers != ModifierKeys.Control || DataContext is not HomeViewModel vm) return; var command = e.Delta > 0 ? vm.FontBiggerCommand : vm.FontSmallerCommand; _scrollDriver = MergeLine.TextPane.Local; // 확대 뒤에는 BASE 를 LOCAL 에 맞춘다 diff --git a/src/MergeHub/Views/MemoView.xaml.cs b/src/MergeHub/Views/MemoView.xaml.cs index 31bd99f..88d01f7 100644 --- a/src/MergeHub/Views/MemoView.xaml.cs +++ b/src/MergeHub/Views/MemoView.xaml.cs @@ -68,6 +68,14 @@ namespace MergeHub.Views // Ctrl+휠로 글자 크기(파일 비교 F-5 와 같은 손버릇). PreviewMouseWheel += (_, e) => { + // Shift+휠은 가로로(2026-10-01 사용자 요청, 파일 비교와 같게). 휠을 아래로 굴리면 오른쪽으로. + if (Keyboard.Modifiers == ModifierKeys.Shift) + { + Editor.ScrollToHorizontalOffset(Math.Max(0, Editor.HorizontalOffset - e.Delta / 120.0 * 48)); + e.Handled = true; + return; + } + if (Keyboard.Modifiers != ModifierKeys.Control) return; var size = Editor.FontSize + (e.Delta > 0 ? 1 : -1); Editor.FontSize = Math.Max(8, Math.Min(28, size));