12차 D-1 - 폴더 비교 위쪽을 한 줄로 · 옵션은 서랍으로

재현: 경로 · 옵션 · 찾기 · 색 범례가 네 줄로 305px(배율 150% 기준 203 DIP)를 먹었고,
비교하기 전에도 그대로였다. 자주 쓰는 [비교] 는 옵션 줄 끝에 묻혀 있었다.

위 한 줄
  [...] 왼쪽 경로  <->  [...] 오른쪽 경로  [최근 v]  켠 옵션  [비교] [취소] [옵션 v]

- 폴더 고르기는 글자 대신 ... 로. 경로 칸 바로 앞에 두어 어느 쪽 것인지 헷갈리지 않는다
- 좌우 바꾸기를 새로 넣었다(사용자 결정) - 반대로 견주려고 두 번 고르지 않아도 된다
- 최근 목록은 화살표만 남겼다

옵션 서랍
- 빠른 비교 · 하위 폴더 포함 · 보기 · 포함 · 제외를 [옵션 v] 안으로. [폴더 안 찾기] 도 여기에
- 서랍에 넣으면 "내가 뭘 켜 뒀더라" 를 알 수 없게 된다 - 특히 제외 규칙은 켠 줄 모르고
  "왜 이 파일이 안 보이지" 로 이어진다. 기본과 다른 것만 한 줄에 짧게 적는다(FolderOptionText).
  기본 그대로면 아무것도 적지 않는다 - 늘 떠 있는 글은 눈에 띄지 않는다

찾기 · 색 범례
- 찾기는 늘 한 줄을 먹던 것을 Ctrl+F 로 부를 때만 편다. Esc · [찾기 접기] 로 접는다
- 색 범례는 아래 상태 줄로 내렸다 - 색은 목록을 보는 동안 필요한 것이라 결과 요약 옆이 제자리다

화면으로 확인
- 위쪽 높이 305px -> 77px (203 -> 51 DIP, -75%)
- 좌우 바꾸기: 누르면 맞바뀌고 다시 누르면 되돌아온다
- 옵션 서랍에 넣은 것이 다 있고, 빠른 비교를 켜면 줄에 "빠른 비교", 제외 규칙이 있어 "규칙 1"
- Ctrl+F 로 77 -> 158px, Esc 로 다시 77px
- 비교 그대로 동작(전체 2개 · 다름 2 · 왼쪽만 0 · 오른쪽만 0 · 같음 0)
- 되던 것이 하나도 없어지지 않았다: 폴더 고르기 · 최근 · 빠른 비교 · 하위 폴더 · 보기 거르기 ·
  포함/제외 · 폴더 안 찾기 · 결과 내보내기 · 복사/삭제 · 줄 단위 비교 · 색 구분(아래로)
- 좁은 창(1920px = 1280 DIP)에서도 여전히 77px 한 줄, [비교] · [옵션] 다 보임

화면을 보고 고친 것: [옵션 v] 를 ToggleButton 으로 뒀더니 플랫폼 기본 스타일이 스위치 모양이라
같은 줄의 다른 단추와 따로 놀았다. 여느 단추로 바꿨다. 최근 목록도 폭을 못 박지 않아
넓게 벌어지던 것을 고쳤다.

하네스 FolderTest 118 -> 131건, 전체 28벌 1,865건 · 실패 0. 빌드 경고 0 · 오류 0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
김승준 2026-09-28 15:25:17 +09:00
parent 101deb2627
commit b28db92515
7 changed files with 361 additions and 114 deletions

View File

@ -285,6 +285,51 @@ BASE 칸 자신은 견줄 것이 없어 `4줄 · 기준` 이라고만 적는다.
실제로 켜서 잰 하단 탭 줄이 **111px · 항목 109px**(배율 150% 기준 72.7 DIP)로 "후" 값과 맞았다. 실제로 켜서 잰 하단 탭 줄이 **111px · 항목 109px**(배율 150% 기준 72.7 DIP)로 "후" 값과 맞았다.
앞서 적었던 "지금 배포 폴더에는 예전 것이 그대로" 는 그 뒤 빌드로 낡은 글이 되어 고쳤다. 앞서 적었던 "지금 배포 폴더에는 예전 것이 그대로" 는 그 뒤 빌드로 낡은 글이 되어 고쳤다.
## D-1. 폴더 비교 위쪽을 한 줄로 · 옵션은 서랍으로 (2026-09-28, 완료)
### 먼저 재현 (화면, 값)
| | |
|---|---|
| 위쪽이 먹던 높이 | **305px (배율 150% 기준 203 DIP)** · 네 줄 |
| 무엇이 있었나 | ① 경로 두 개 + 최근 ② 빠른 비교 · 하위 폴더 · 보기 · 포함 · 제외 · [비교] · [취소] ③ 폴더 안 찾기 한 벌 ④ 색 구분 범례 |
비교하기 <b>전에도</b> 네 줄이 그대로 있었고, 자주 쓰는 [비교] 는 옵션 줄 끝에 묻혀 있었다.
### 고친 것
- **위 한 줄**: `[…] 왼쪽 경로 ⇆ […] 오른쪽 경로 [최근▾] 켠 옵션 [비교] [취소] [옵션 ▾]`
- 폴더 고르기는 글자 대신 `…` 로. 경로 칸 <b>바로 앞</b>에 두어 어느 쪽 것인지 헷갈리지 않는다.
- **좌우 바꾸기(⇆)** 를 새로 넣었다(사용자 결정) - 반대로 견주려고 두 번 고르지 않아도 된다.
- 최근 목록은 화살표만 남겼다.
- **옵션 서랍**: 빠른 비교 · 하위 폴더 포함 · 보기 · 포함 · 제외를 `[옵션 ▾]` 안으로. `[폴더 안 찾기]` 도 여기에 뒀다.
- **켠 옵션 표시**: 서랍에 넣으면 "내가 뭘 켜 뒀더라" 를 알 수 없게 된다 - 특히 제외 규칙은 켠 줄 모르고
"왜 이 파일이 안 보이지" 로 이어진다. <b>기본과 다른 것만</b> 한 줄에 짧게 적는다(`FolderOptionText`).
기본 그대로면 아무것도 적지 않는다 - 늘 떠 있는 글은 눈에 띄지 않는다.
- **찾기**: 늘 한 줄을 먹던 것을 **Ctrl+F 로 부를 때만** 편다. Esc · [찾기 접기] 로 접는다.
- **색 범례**: 위에서 빼고 <b>아래 상태 줄</b>로 내렸다 - 색은 목록을 보는 동안 필요한 것이라 결과 요약 옆이 제자리다.
### 화면으로 확인 (값)
| 확인 | 값 |
|---|---|
| **위쪽 높이** | **305px → 77px** (203 → **51 DIP**, −75%) |
| 한 줄에 있는 것 | […] ⇆ […] · 최근 · [비교] [취소] [옵션 ▾] · 켠 옵션 |
| 좌우 바꾸기 | 누르면 두 경로가 맞바뀌고, 다시 누르면 되돌아온다 |
| 옵션 서랍 | 빠른 비교 · 하위 폴더 · 보기 · 포함 · 제외 · [폴더 안 찾기] 모두 있음 |
| 켠 옵션 표시 | 빠른 비교를 켜면 줄에 "빠른 비교", 처음 제외 규칙이 있어 "규칙 1" |
| 찾기 | Ctrl+F 로 77 → 158px, Esc 로 다시 77px |
| 비교 | 그대로 동작(`전체 2개 · 다름 2 · 왼쪽만 0 · 오른쪽만 0 · 같음 0`) |
| 없어지지 않은 것 | 결과 내보내기 · 줄 단위 비교 · 양쪽 복사 · 양쪽 삭제 · 색 구분(아래로) |
| 좁은 창(1920px = 1280 DIP) | 여전히 **77px 한 줄**, [비교] · [옵션] 다 보임 |
하네스 `FolderTest` 118 → **131건**(D-1 +13), 전체 28벌 **1,865건** 통과 · 실패 0(빌드 경고 0 · 오류 0).
### 화면을 보고 고친 것
`[옵션 ▾]` 를 `ToggleButton` 으로 뒀더니 플랫폼 기본 스타일이 <b>스위치 모양</b>이라 같은 줄의 다른 단추와
따로 놀았다. 여느 단추로 바꾸고 누를 때마다 서랍을 여닫게 했다. 최근 목록도 폭을 못 박지 않아 넓게 벌어지던 것을 고쳤다.
## E-1. 꺼도 작업 내용이 남아 있게 (2026-09-28, 완료) ## E-1. 꺼도 작업 내용이 남아 있게 (2026-09-28, 완료)
E-2 가 만든 **보관함**(탭이 사라져도 고친 글이 짝 이름으로 남는 자리)을 그대로 파일로 옮겨 적는 일이다. E-2 가 만든 **보관함**(탭이 사라져도 고친 글이 짝 이름으로 남는 자리)을 그대로 파일로 옮겨 적는 일이다.

View File

@ -8,6 +8,7 @@
| 날짜 | 항목 | 커밋 | | 날짜 | 항목 | 커밋 |
|---|---|---| |---|---|---|
| 2026-09-28 | **12차 D-1** — 폴더 비교 위쪽을 한 줄로. 경로 · 옵션 · 찾기 · 색 범례가 네 줄로 **305px(203 DIP)** 를 먹었고 비교하기 전에도 그대로였다. 위 줄은 `[…] 왼쪽 경로 ⇆ […] 오른쪽 경로 [최근▾] 켠옵션 [비교] [취소] [옵션 ▾]` — 폴더 고르기는 `…` 로 줄이고 **좌우 바꾸기(⇆)** 를 새로 넣었다(사용자 결정). 빠른 비교 · 하위 폴더 포함 · 보기 · 포함 · 제외는 `[옵션 ▾]` 서랍으로 넣되, 서랍에 넣으면 "뭘 켜 뒀더라" 를 알 수 없게 되므로 **기본과 다른 것만** 한 줄에 짧게 적는다(`FolderOptionText`). 찾기는 늘 한 줄을 먹던 것을 **Ctrl+F 로 부를 때만** 펴고(Esc 로 접음), 색 범례는 아래 상태 줄로 내렸다(색은 목록을 보는 동안 필요한 것이다). 결과: **305px → 77px(203 → 51 DIP, −75%)**, 좁은 창 1280 DIP 에서도 한 줄. 되던 것은 하나도 없어지지 않았다 (폴더 고르기 · 최근 · 빠른 비교 · 하위 폴더 · 보기 거르기 · 포함/제외 · 폴더 안 찾기 · 결과 내보내기 · 복사/삭제 · 줄 단위 비교 — 값으로 확인). 화면을 보다 `[옵션 ▾]` 이 플랫폼 기본 ToggleButton 스타일 탓에 스위치 모양으로 그려지던 것과 최근 목록이 넓게 벌어지던 것을 고쳤다. 하네스 `FolderTest` 118 → 131건, 전체 28벌 1,865건 · 실패 0 | 아래 |
| 2026-09-28 | **12차 E-1** — 저장하지 않은 편집이 껐다 켜도 남는다(notepad++ 식). E-2 가 만든 보관함을 `{설정 폴더}\Session\MergeHub\` 에 그대로 옮겨 적는다 — 차례 · 자리는 `목록.txt` 에 탭으로 나눈 글, 편집한 글은 짝마다 따로 파일. JSON 을 쓰지 않은 까닭은 최근 목록과 같다(사람이 고칠 수 있고, 글 안에 무엇이 들었든 본문을 따로 두면 탈이 없다). **원본 글은 담지 않는다** — 파일에서 다시 읽고, 그때 파일의 길이 · 수정 시각만 적어 두었다가 다르면 알린다. 목록은 맨 나중에 쓴다(있다는 것이 곧 글 파일이 다 있다는 뜻). 보관은 글자가 멈춘 뒤 2초에 한 번, 탭을 옮기거나 닫거나 새 짝을 열 때는 그 자리에서 바로, 쓰는 일은 다른 실로 넘긴다. 켤 때는 묻지 않고 되살리되 사용자가 지금 열라고 한 것(충돌 파일 · mergetool · 폴더 비교에서 고른 파일)이 먼저다. 원본이 그 사이 바뀌었으면 되살리고 알린다("파일을 연 시점" 은 새로 읽은 글로 두어 [전체 되돌리기] 가 지금 파일로 간다). 다 저장하면 보관본을 치운다. 화면으로 확인: 두 짝을 고치고 **강제로 끝낸 뒤** 다시 켜면 묻지 않고 탭 2개가 글 그대로 되살아나고, 저장하면 가운뎃점이 빠지고, 다 저장하면 보관본이 사라진다. 하네스 `SessionTest` 65건 새로 만듦 · 전체 28벌 1,852건 · 실패 0. 빠르기는 글자당 31ms 로 4줄짜리와 같았으나, **"친 뒤 화면에 보이기까지" 는 UIA 로 재는 비용이 타이핑보다 커서 값으로 확정하지 못했다**. E-1 이 도니 지난 시험이 남긴 편집이 다음 시험에서 되살아나 화면 시험 도구도 보관 자리를 치우고 시작하도록 고쳤다 | 아래 | | 2026-09-28 | **12차 E-1** — 저장하지 않은 편집이 껐다 켜도 남는다(notepad++ 식). E-2 가 만든 보관함을 `{설정 폴더}\Session\MergeHub\` 에 그대로 옮겨 적는다 — 차례 · 자리는 `목록.txt` 에 탭으로 나눈 글, 편집한 글은 짝마다 따로 파일. JSON 을 쓰지 않은 까닭은 최근 목록과 같다(사람이 고칠 수 있고, 글 안에 무엇이 들었든 본문을 따로 두면 탈이 없다). **원본 글은 담지 않는다** — 파일에서 다시 읽고, 그때 파일의 길이 · 수정 시각만 적어 두었다가 다르면 알린다. 목록은 맨 나중에 쓴다(있다는 것이 곧 글 파일이 다 있다는 뜻). 보관은 글자가 멈춘 뒤 2초에 한 번, 탭을 옮기거나 닫거나 새 짝을 열 때는 그 자리에서 바로, 쓰는 일은 다른 실로 넘긴다. 켤 때는 묻지 않고 되살리되 사용자가 지금 열라고 한 것(충돌 파일 · mergetool · 폴더 비교에서 고른 파일)이 먼저다. 원본이 그 사이 바뀌었으면 되살리고 알린다("파일을 연 시점" 은 새로 읽은 글로 두어 [전체 되돌리기] 가 지금 파일로 간다). 다 저장하면 보관본을 치운다. 화면으로 확인: 두 짝을 고치고 **강제로 끝낸 뒤** 다시 켜면 묻지 않고 탭 2개가 글 그대로 되살아나고, 저장하면 가운뎃점이 빠지고, 다 저장하면 보관본이 사라진다. 하네스 `SessionTest` 65건 새로 만듦 · 전체 28벌 1,852건 · 실패 0. 빠르기는 글자당 31ms 로 4줄짜리와 같았으나, **"친 뒤 화면에 보이기까지" 는 UIA 로 재는 비용이 타이핑보다 커서 값으로 확정하지 못했다**. E-1 이 도니 지난 시험이 남긴 편집이 다음 시험에서 되살아나 화면 시험 도구도 보관 자리를 치우고 시작하도록 고쳤다 | 아래 |
| 2026-09-28 | **`[<]` 단추가 있는 줄만 글이 밀리던 것**(사용자 보고 — 그림으로 짚어 준 것이 이것이다). 12차 B-1 로 넣은 `[<]` 단추가 든 칸의 폭이 `Auto` 여서, 단추가 보이는 줄에서만 칸이 벌어져 뒤 칸이 통째로 오른쪽으로 밀렸다 — BASE 는 맨 앞 칸이라 <b>번호까지</b>, LOCAL 은 번호 뒤 칸이라 <b>코드가</b> 밀렸고 단추가 하나 늘 때마다 더 밀렸다. `Visibility="Collapsed"` 는 자리까지 없애므로 칸 폭이 고정이어야 한다. `GutterBothWaysWidth` 를 두어 두 칸이 같은 자리를 늘 잡아 두고, 두 파일 비교에서는 단추 폭 · Git 모드와 네 칸에서는 0 으로 화면이 갈아 끼운다(`ApplyGutterReserve`). 투명한 편집기가 아래 표시층과 어긋나지 않도록 `EditorGutterMargin` 도 같은 값만큼 민다. 글자 크기(11차 F-5)를 바꾸면 단추 폭이 따라 바뀌므로 잡아 두는 자리도 `CodeFontMetrics` 한 벌에서 나온다. 값으로 확인: 한 칸의 모든 줄이 같은 x(BASE 137 · LOCAL 1283), 글자 크기 · Git 모드도 그대로. BASE 줄 끝의 `[>]`(11차 F-10)는 왼쪽 가장자리를 밀지 않아 이번에는 `Auto` 로 두었다 | 아래 | | 2026-09-28 | **`[<]` 단추가 있는 줄만 글이 밀리던 것**(사용자 보고 — 그림으로 짚어 준 것이 이것이다). 12차 B-1 로 넣은 `[<]` 단추가 든 칸의 폭이 `Auto` 여서, 단추가 보이는 줄에서만 칸이 벌어져 뒤 칸이 통째로 오른쪽으로 밀렸다 — BASE 는 맨 앞 칸이라 <b>번호까지</b>, LOCAL 은 번호 뒤 칸이라 <b>코드가</b> 밀렸고 단추가 하나 늘 때마다 더 밀렸다. `Visibility="Collapsed"` 는 자리까지 없애므로 칸 폭이 고정이어야 한다. `GutterBothWaysWidth` 를 두어 두 칸이 같은 자리를 늘 잡아 두고, 두 파일 비교에서는 단추 폭 · Git 모드와 네 칸에서는 0 으로 화면이 갈아 끼운다(`ApplyGutterReserve`). 투명한 편집기가 아래 표시층과 어긋나지 않도록 `EditorGutterMargin` 도 같은 값만큼 민다. 글자 크기(11차 F-5)를 바꾸면 단추 폭이 따라 바뀌므로 잡아 두는 자리도 `CodeFontMetrics` 한 벌에서 나온다. 값으로 확인: 한 칸의 모든 줄이 같은 x(BASE 137 · LOCAL 1283), 글자 크기 · Git 모드도 그대로. BASE 줄 끝의 `[>]`(11차 F-10)는 왼쪽 가장자리를 밀지 않아 이번에는 `Auto` 로 두었다 | 아래 |
| 2026-09-28 | **왼쪽 줄 번호가 밀리던 것**(사용자 보고) — 12차 B-1 로 왼쪽에도 반영할 수 있게 되면서 왼쪽 줄이 늘고 주는데, 번호는 정렬기가 처음 준 것 그대로였다. 오른쪽에만 있던 줄을 왼쪽에 넣으면 그 줄은 번호가 비고 뒤 줄은 옛 번호를 달아 `01 02 · 03 04 05 · 06` 으로 보였다 — 왼쪽 파일은 8줄인데 번호는 6까지라 어느 줄을 고쳤는지 짚을 수 없었다. `RenumberBase` 를 `RenumberMerged`(8차 B-3) 옆에 두고 두 파일 비교에서만 왼쪽 줄을 1부터 다시 맨다. Git 모드 · 네 칸의 BASE 는 고칠 수 없는 쪽이라 건드리지 않는다. "머지 반영함" 표시가 BASE 줄 번호를 열쇠로 붙들고 있어 번호가 실제로 달라질 때만 그 열쇠도 옛 번호 → 새 번호로 옮긴다. 화면으로 넣기 · 빼기 · 되돌리기 · 저장 · Git 회귀 확인, 하네스 27벌 1,787건 · 실패 0. **왼쪽에만 있는 줄을 뺄 때 줄 수가 주는지는 값으로 확정하지 못했다**(시험 도구가 낡은 줄 칸을 집는 한계) | 아래 | | 2026-09-28 | **왼쪽 줄 번호가 밀리던 것**(사용자 보고) — 12차 B-1 로 왼쪽에도 반영할 수 있게 되면서 왼쪽 줄이 늘고 주는데, 번호는 정렬기가 처음 준 것 그대로였다. 오른쪽에만 있던 줄을 왼쪽에 넣으면 그 줄은 번호가 비고 뒤 줄은 옛 번호를 달아 `01 02 · 03 04 05 · 06` 으로 보였다 — 왼쪽 파일은 8줄인데 번호는 6까지라 어느 줄을 고쳤는지 짚을 수 없었다. `RenumberBase` 를 `RenumberMerged`(8차 B-3) 옆에 두고 두 파일 비교에서만 왼쪽 줄을 1부터 다시 맨다. Git 모드 · 네 칸의 BASE 는 고칠 수 없는 쪽이라 건드리지 않는다. "머지 반영함" 표시가 BASE 줄 번호를 열쇠로 붙들고 있어 번호가 실제로 달라질 때만 그 열쇠도 옛 번호 → 새 번호로 옮긴다. 화면으로 넣기 · 빼기 · 되돌리기 · 저장 · Git 회귀 확인, 하네스 27벌 1,787건 · 실패 0. **왼쪽에만 있는 줄을 뺄 때 줄 수가 주는지는 값으로 확정하지 못했다**(시험 도구가 낡은 줄 칸을 집는 한계) | 아래 |

View File

@ -419,6 +419,12 @@
| **완료** | C-1 트레이 아이콘 — 최소화하면 알림 영역으로, 왼쪽 단추로 되살리기 · 우클릭 [열기]/[종료]. 새 플랫폼(`D:\Sorce\ubsrepo`) 에 넣음(11차 뒤 G-2 와 같은 작업) | | **완료** | C-1 트레이 아이콘 — 최소화하면 알림 영역으로, 왼쪽 단추로 되살리기 · 우클릭 [열기]/[종료]. 새 플랫폼(`D:\Sorce\ubsrepo`) 에 넣음(11차 뒤 G-2 와 같은 작업) |
| **완료** | C-2 탭 줄 크기 줄이기 — 하단 탭 줄 항목을 74 → 61 DIP 로(여백 13/14→9/10 · 아이콘 22→20 · 틈 7→5 · 글자 13.5→12.5). 실측 133 → 109px(−18%), 파일 비교 코드 칸 47 → 48줄. **배포됨** — 새 플랫폼을 빌드하면서 함께 나갔고, 2026-09-28 배포본 해시 · 화면 실측(111px · 항목 109px)으로 확인 | | **완료** | C-2 탭 줄 크기 줄이기 — 하단 탭 줄 항목을 74 → 61 DIP 로(여백 13/14→9/10 · 아이콘 22→20 · 틈 7→5 · 글자 13.5→12.5). 실측 133 → 109px(−18%), 파일 비교 코드 칸 47 → 48줄. **배포됨** — 새 플랫폼을 빌드하면서 함께 나갔고, 2026-09-28 배포본 해시 · 화면 실측(111px · 항목 109px)으로 확인 |
### D. 폴더 비교 화면 다시 만들기
| 상태 | 항목 |
|---|---|
| **완료** | D-1 위쪽을 한 줄로 · 옵션은 서랍으로 — 네 줄 305px(203 DIP) → **한 줄 77px(51 DIP)**. 위 줄은 `[…] 왼쪽 ⇆ […] 오른쪽 [최근▾] 켠옵션 [비교][취소][옵션 ▾]`, 좌우 바꾸기를 새로 넣음. 빠른 비교 · 하위 폴더 · 보기 · 포함 · 제외는 서랍으로 넣되 **켠 것만 한 줄에 짧게** 적는다. 찾기는 Ctrl+F 로 펼 때만, 색 범례는 아래 상태 줄로. 되던 것은 하나도 없어지지 않음(값으로 확인). 좁은 창 1280 DIP 에서도 한 줄 |
### E. 저장하지 않아도 남는 편집 ### E. 저장하지 않아도 남는 편집
| 상태 | 항목 | | 상태 | 항목 |

View File

@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
namespace MergeHub.Services
{
/// <summary>
/// 옵션 서랍에 넣어 둔 것 가운데 <b>지금 켜 둔 것</b>을 한 줄에 짧게 적는다(12차 D-1).
///
/// 서랍에 넣으면 자리는 아끼지만 "내가 뭘 켜 뒀더라" 를 알 수 없게 된다 -
/// 특히 제외 규칙은 켜 둔 줄 모르고 "왜 이 파일이 안 보이지" 로 이어진다.
/// 그래서 <b>기본과 다른 것만</b> 짧게 적는다. 기본 그대로면 아무것도 적지 않는다(눈에 띄어야 뜻이 있다).
/// </summary>
public static class FolderOptionText
{
/// <summary>기본값 - 이것과 같으면 적지 않는다.</summary>
public const bool DefaultQuick = false;
public const bool DefaultSubfolders = true;
/// <param name="filterName">보기 거르개 이름. 기본("다른 것만")이면 적지 않는다.</param>
public static string Of(bool quick, bool subfolders, string? filterName,
string? include, string? exclude)
{
var parts = new List<string>();
if (quick != DefaultQuick) parts.Add("빠른 비교");
// 하위 폴더는 켜 두는 것이 기본이라, <b>끈 것</b>이 알릴 일이다.
if (subfolders != DefaultSubfolders) parts.Add("이 폴더만");
if (!string.IsNullOrWhiteSpace(filterName) && filterName != "다른 것만") parts.Add(filterName!);
var rules = 0;
if (!string.IsNullOrWhiteSpace(include)) rules++;
if (!string.IsNullOrWhiteSpace(exclude)) rules++;
if (rules == 1) parts.Add("규칙 1");
else if (rules == 2) parts.Add("규칙 2");
return parts.Count == 0 ? string.Empty : string.Join(" · ", parts);
}
/// <summary>적을 것이 있는가. 없으면 화면이 그 자리를 아예 내주지 않는다.</summary>
public static bool Any(bool quick, bool subfolders, string? filterName, string? include, string? exclude) =>
Of(quick, subfolders, filterName, include, exclude).Length > 0;
}
}

View File

@ -255,7 +255,11 @@ namespace MergeHub.ViewModels
_ => "다른 것만" _ => "다른 것만"
}; };
partial void OnFilterChanged(FolderFilter value) => Rebuild(); partial void OnFilterChanged(FolderFilter value)
{
Rebuild();
RefreshOptionSummary(); // 12차 D-1 - 서랍에 넣은 것이라 한 줄에 켠 것을 알려야 한다
}
/// <summary>마지막 비교 결과. 필터를 바꿀 때 다시 훑지 않으려고 들고 있는다.</summary> /// <summary>마지막 비교 결과. 필터를 바꿀 때 다시 훑지 않으려고 들고 있는다.</summary>
private FolderCompareResult? _lastResult; private FolderCompareResult? _lastResult;
@ -268,6 +272,59 @@ namespace MergeHub.ViewModels
partial void OnSelectedNodeChanged(FolderNode? value) => RaiseCanExecuteChanged(); partial void OnSelectedNodeChanged(FolderNode? value) => RaiseCanExecuteChanged();
// ================= 위쪽 한 줄 · 옵션 서랍 (12차 D-1) =================
/// <summary>옵션 서랍이 열려 있는가. 서랍에 넣은 것은 빠른 비교 · 하위 폴더 · 보기 · 포함 · 제외다.</summary>
[ObservableProperty] private bool _isOptionsOpen;
/// <summary>
/// 폴더 안 찾기 줄이 열려 있는가(12차 D-1). 늘 한 줄을 차지하던 것을 <b>Ctrl+F 로 부를 때만</b> 편다 -
/// 찾기는 가끔 쓰는데 자리는 늘 먹었다. 파일 비교의 찾기와 같은 방식이다.
/// </summary>
[ObservableProperty] private bool _isFindOpen;
/// <summary>
/// 서랍에 넣어 둔 것 가운데 지금 켜 둔 것. 서랍에 넣으면 "내가 뭘 켜 뒀더라" 를 알 수 없게 되므로
/// <b>기본과 다른 것만</b> 한 줄에 짧게 적는다(<see cref="FolderOptionText"/>).
/// </summary>
public string OptionSummary =>
FolderOptionText.Of(QuickCompare, IncludeSubfolders, FilterName(Filter), IncludePattern, ExcludePattern);
public bool HasOptionSummary => OptionSummary.Length > 0;
private void RefreshOptionSummary()
{
OnPropertyChanged(nameof(OptionSummary));
OnPropertyChanged(nameof(HasOptionSummary));
}
partial void OnQuickCompareChanged(bool value) => RefreshOptionSummary();
partial void OnIncludeSubfoldersChanged(bool value) => RefreshOptionSummary();
partial void OnIncludePatternChanged(string value) => RefreshOptionSummary();
partial void OnExcludePatternChanged(string value) => RefreshOptionSummary();
/// <summary>왼쪽 · 오른쪽 폴더를 맞바꾼다(12차 D-1). 반대로 견주려고 두 번 고르지 않게.</summary>
[RelayCommand]
private void SwapFolders()
{
var left = LeftFolder;
LeftFolder = RightFolder;
RightFolder = left;
_workspace.AppendLog($"폴더 좌우 바꿈: {LeftFolder} ↔ {RightFolder}");
}
/// <summary>폴더 안 찾기 줄을 편다(Ctrl+F · 옵션 서랍).</summary>
[RelayCommand]
private void OpenFind()
{
IsFindOpen = true;
IsOptionsOpen = false;
}
/// <summary>찾기 줄을 접는다(Esc). 찾은 결과는 [결과 닫기] 가 따로 치운다.</summary>
[RelayCommand]
private void CloseFind() => IsFindOpen = false;
private void RaiseCanExecuteChanged() private void RaiseCanExecuteChanged()
{ {
CompareCommand.NotifyCanExecuteChanged(); CompareCommand.NotifyCanExecuteChanged();

View File

@ -112,49 +112,67 @@
</UserControl.Resources> </UserControl.Resources>
<Grid Margin="10"> <Grid Margin="10">
<!--
12차 D-1: 위쪽을 <b>한 줄</b>로. 예전에는 경로 · 옵션 · 찾기 · 색 범례가 네 줄(203 DIP)을 먹었다.
자주 쓰는 것만 줄에 두고(경로 · 좌우 바꾸기 · 비교), 가끔 쓰는 것은 [옵션 ▾] 서랍으로 넣었다.
찾기는 Ctrl+F 로 부를 때만 펴고, 색 범례는 아래 상태 줄로 옮겼다.
-->
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <!-- ① 위 한 줄 -->
<RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <!-- ② 폴더 안 찾기(Ctrl+F 로 펼 때만) -->
<RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <!-- ③ 목록 머리글 -->
<RowDefinition Height="Auto"/> <RowDefinition Height="*"/> <!-- ④ 트리 -->
<RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <!-- ⑤ 아래 상태 줄(색 범례 · 요약 · 동작) -->
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions> </Grid.RowDefinitions>
<!-- ① 폴더 두 개 --> <!-- ① 위 한 줄: 왼쪽 경로 ⇄ 오른쪽 경로 · [비교] · [옵션 ▾] -->
<Border Grid.Row="0" Padding="8" BorderThickness="1" Margin="0,0,0,6" <Border Grid.Row="0" Padding="6,5" BorderThickness="1" Margin="0,0,0,4"
BorderBrush="{DynamicResource Ubisam.Brush.Input.Border}"> BorderBrush="{DynamicResource Ubisam.Brush.Input.Border}">
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/> <ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/> <ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/> <ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/> <ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Button Grid.Column="0" Content="왼쪽 폴더..." Command="{Binding PickLeftFolderCommand}" <!-- 폴더 고르기는 글자 대신 점 셋으로. 경로 칸 바로 앞에 두어 어느 쪽 것인지 헷갈리지 않는다. -->
Height="28" Padding="10,2" FontSize="11" Margin="0,0,6,0"/> <Button Grid.Column="0" Content="..." Command="{Binding PickLeftFolderCommand}"
<TextBox Grid.Column="1" Text="{Binding LeftFolder, UpdateSourceTrigger=PropertyChanged}" Width="28" Height="26" MinWidth="28" Padding="0" FontSize="11" Margin="0,0,3,0"
ToolTip="왼쪽(기준) 폴더 고르기"/>
<TextBox Grid.Column="1" x:Name="LeftFolderBox"
Text="{Binding LeftFolder, UpdateSourceTrigger=PropertyChanged}"
AllowDrop="True" PreviewDragOver="View_DragOver" PreviewDrop="LeftFolder_Drop" AllowDrop="True" PreviewDragOver="View_DragOver" PreviewDrop="LeftFolder_Drop"
FontFamily="Consolas" FontSize="11" Height="28" VerticalContentAlignment="Center" FontFamily="Consolas" FontSize="11" Height="26" MinWidth="120"
Margin="0,0,14,0" ToolTip="비교 기준이 되는 폴더"/> VerticalContentAlignment="Center"
ToolTip="비교 기준이 되는 폴더. 끌어다 놓아도 됩니다"/>
<Button Grid.Column="2" Content="오른쪽 폴더..." Command="{Binding PickRightFolderCommand}" <!-- 좌우 바꾸기. 반대로 견주려고 두 번 고르지 않게 한다(12차 D-1). -->
Height="28" Padding="10,2" FontSize="11" Margin="0,0,6,0"/> <Button Grid.Column="2" x:Name="SwapButton" Content="&#8646;" Command="{Binding SwapFoldersCommand}"
<TextBox Grid.Column="3" Text="{Binding RightFolder, UpdateSourceTrigger=PropertyChanged}" Width="28" Height="26" MinWidth="28" Padding="0" FontSize="13" Margin="4,0,4,0"
ToolTip="왼쪽 · 오른쪽 폴더 맞바꾸기"/>
<Button Grid.Column="3" Content="..." Command="{Binding PickRightFolderCommand}"
Width="28" Height="26" MinWidth="28" Padding="0" FontSize="11" Margin="0,0,3,0"
ToolTip="오른쪽(비교 대상) 폴더 고르기"/>
<TextBox Grid.Column="4" x:Name="RightFolderBox"
Text="{Binding RightFolder, UpdateSourceTrigger=PropertyChanged}"
AllowDrop="True" PreviewDragOver="View_DragOver" PreviewDrop="RightFolder_Drop" AllowDrop="True" PreviewDragOver="View_DragOver" PreviewDrop="RightFolder_Drop"
FontFamily="Consolas" FontSize="11" Height="28" VerticalContentAlignment="Center" FontFamily="Consolas" FontSize="11" Height="26" MinWidth="120"
ToolTip="견줄 폴더"/> VerticalContentAlignment="Center"
ToolTip="견줄 폴더. 끌어다 놓아도 됩니다"/>
<TextBlock Grid.Column="4" Text="최근" VerticalAlignment="Center" Style="{StaticResource Muted}" <!-- 최근 짝. 글자 없이 화살표만 - 고르면 바로 연다. -->
FontSize="11" Margin="14,0,4,0"/>
<ComboBox x:Name="RecentBox" ItemsSource="{Binding RecentFolders}" <ComboBox x:Name="RecentBox" ItemsSource="{Binding RecentFolders}"
SelectionChanged="Recent_SelectionChanged" SelectionChanged="Recent_SelectionChanged" Grid.Column="5"
Width="200" Height="28" FontSize="11" Grid.Column="5" Margin="0" Width="34" MinWidth="34" MaxWidth="34" Height="26" FontSize="11" Margin="6,0,0,0"
VerticalContentAlignment="Center" HorizontalAlignment="Left" VerticalContentAlignment="Center"
ToolTip="최근에 견준 짝. 고르면 바로 엽니다"> ToolTip="최근에 견준 짝. 고르면 바로 엽니다">
<ComboBox.ItemTemplate> <ComboBox.ItemTemplate>
<DataTemplate> <DataTemplate>
@ -173,56 +191,88 @@
</TextBlock> </TextBlock>
</DataTemplate> </DataTemplate>
</ComboBox.ItemTemplate> </ComboBox.ItemTemplate>
</ComboBox> </Grid>
</Border>
<!-- ② 비교 방식 · 필터 -->
<Border Grid.Row="1" Padding="8" BorderThickness="1" Margin="0,0,0,6"
BorderBrush="{DynamicResource Ubisam.Brush.Input.Border}">
<WrapPanel Orientation="Horizontal">
<CheckBox Content="빠른 비교 (크기·수정일만)" IsChecked="{Binding QuickCompare}"
VerticalAlignment="Center" Margin="0,0,16,0"
ToolTip="내용을 읽지 않습니다. 파일이 아주 많거나 네트워크 드라이브일 때 씁니다"/>
<CheckBox Content="하위 폴더 포함" IsChecked="{Binding IncludeSubfolders}"
VerticalAlignment="Center" Margin="0,0,16,0"/>
<!-- 보기 필터는 다시 비교하지 않고 목록만 다시 그린다. -->
<TextBlock Text="보기" VerticalAlignment="Center" Style="{StaticResource Muted}"
FontSize="11" Margin="0,0,4,0"/>
<ComboBox ItemsSource="{Binding Filters}" SelectedItem="{Binding Filter}"
Width="110" Height="26" FontSize="11" Margin="0,0,16,0"
VerticalContentAlignment="Center"
ToolTip="파일이 수백 개면 눈으로 고르는 것이 제일 느립니다">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Converter={StaticResource FolderFilterName}}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox> </ComboBox>
<TextBlock Text="포함" VerticalAlignment="Center" Style="{StaticResource Muted}" <!-- 서랍에 넣은 것 가운데 켜 둔 것. 안 그러면 "왜 이 파일이 안 보이지" 가 된다. -->
FontSize="11" Margin="0,0,4,0"/> <TextBlock Grid.Column="6" Text="{Binding OptionSummary}" Style="{StaticResource Muted}"
<TextBox Text="{Binding IncludePattern, UpdateSourceTrigger=PropertyChanged}" FontSize="11" Margin="10,0,0,0" MaxWidth="260" TextTrimming="CharacterEllipsis"
Width="150" Height="26" FontFamily="Consolas" FontSize="11" ToolTip="지금 켜 둔 옵션입니다. [옵션 ▾] 에서 고칩니다"
VerticalContentAlignment="Center" Margin="0,0,12,0" Visibility="{Binding HasOptionSummary, Converter={StaticResource BoolToVis}}"/>
ToolTip="정규식. 비우면 전부 포함합니다 (예: \.cs$)"/>
<TextBlock Text="제외" VerticalAlignment="Center" Style="{StaticResource Muted}" <Button Grid.Column="7" Content="비교" Command="{Binding CompareCommand}"
FontSize="11" Margin="0,0,4,0"/> Height="26" MinWidth="70" Margin="10,0,4,0"
<TextBox Text="{Binding ExcludePattern, UpdateSourceTrigger=PropertyChanged}"
Width="260" Height="26" FontFamily="Consolas" FontSize="11"
VerticalContentAlignment="Center" Margin="0,0,16,0"
ToolTip="정규식. 포함 규칙보다 우선합니다"/>
<Button Content="비교" Command="{Binding CompareCommand}" Height="28" MinWidth="80"
Margin="0,0,6,0"
Style="{StaticResource FilledButton}" Style="{StaticResource FilledButton}"
Background="{DynamicResource Ubisam.Brush.Accent.Fill}" Background="{DynamicResource Ubisam.Brush.Accent.Fill}"
Foreground="{DynamicResource Ubisam.Brush.Accent.OnFill}" FontWeight="Bold"/> Foreground="{DynamicResource Ubisam.Brush.Accent.OnFill}" FontWeight="Bold"/>
<!-- 큰 폴더를 잘못 고르면 기다리는 수밖에 없었다. 비교하는 동안에만 켜진다. --> <!-- 큰 폴더를 잘못 고르면 기다리는 수밖에 없었다. 비교하는 동안에만 켜진다. -->
<Button Content="취소" Command="{Binding CancelCompareCommand}" Height="28" MinWidth="60" <Button Grid.Column="8" Content="취소" Command="{Binding CancelCompareCommand}"
Height="26" MinWidth="54" Margin="0,0,4,0"
ToolTip="비교를 멈춥니다. 앞서 본 결과는 그대로 남습니다"/> ToolTip="비교를 멈춥니다. 앞서 본 결과는 그대로 남습니다"/>
</WrapPanel>
<!-- 여느 단추로 둔다. 플랫폼 기본 ToggleButton 은 <b>스위치 모양</b>이라
이 줄의 다른 단추와 따로 논다(화면에서 보고 고침). -->
<Button Grid.Column="9" x:Name="OptionsButton" Content="옵션 &#9662;"
Click="Options_Click"
Height="26" MinWidth="62" Padding="8,0" FontSize="11"
ToolTip="빠른 비교 · 하위 폴더 · 보기 · 포함 · 제외 규칙"/>
<!-- 옵션 서랍. 가끔 쓰는 것을 여기에 넣어 위쪽 세 줄을 없앴다(12차 D-1). -->
<Popup Grid.Column="9" PlacementTarget="{Binding ElementName=OptionsButton}"
Placement="Bottom" HorizontalOffset="-220" StaysOpen="False"
IsOpen="{Binding IsOptionsOpen, Mode=TwoWay}" AllowsTransparency="True">
<Border Background="{DynamicResource Ubisam.Brush.ContentBackground}"
BorderBrush="{DynamicResource Ubisam.Brush.Input.Border}" BorderThickness="1"
Padding="12" Margin="0,2,8,8">
<Border.Effect>
<DropShadowEffect BlurRadius="10" ShadowDepth="2" Opacity="0.25"/>
</Border.Effect>
<StackPanel MinWidth="360">
<CheckBox Content="빠른 비교 (크기·수정일만)" IsChecked="{Binding QuickCompare}"
Margin="0,0,0,8"
ToolTip="내용을 읽지 않습니다. 파일이 아주 많거나 네트워크 드라이브일 때 씁니다"/>
<CheckBox Content="하위 폴더 포함" IsChecked="{Binding IncludeSubfolders}"
Margin="0,0,0,10"/>
<!-- 보기 필터는 다시 비교하지 않고 목록만 다시 그린다. -->
<StackPanel Orientation="Horizontal" Margin="0,0,0,8">
<TextBlock Text="보기" Style="{StaticResource Muted}" FontSize="11"
Width="40"/>
<ComboBox ItemsSource="{Binding Filters}" SelectedItem="{Binding Filter}"
Width="160" Height="26" FontSize="11"
VerticalContentAlignment="Center"
ToolTip="파일이 수백 개면 눈으로 고르는 것이 제일 느립니다">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Converter={StaticResource FolderFilterName}}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,0,0,8">
<TextBlock Text="포함" Style="{StaticResource Muted}" FontSize="11" Width="40"/>
<TextBox Text="{Binding IncludePattern, UpdateSourceTrigger=PropertyChanged}"
Width="300" Height="26" FontFamily="Consolas" FontSize="11"
VerticalContentAlignment="Center"
ToolTip="정규식. 비우면 전부 포함합니다 (예: \.cs$)"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,0,0,10">
<TextBlock Text="제외" Style="{StaticResource Muted}" FontSize="11" Width="40"/>
<TextBox Text="{Binding ExcludePattern, UpdateSourceTrigger=PropertyChanged}"
Width="300" Height="26" FontFamily="Consolas" FontSize="11"
VerticalContentAlignment="Center"
ToolTip="정규식. 포함 규칙보다 우선합니다"/>
</StackPanel>
<Button Content="폴더 안 찾기 (Ctrl+F)" Command="{Binding OpenFindCommand}"
Height="26" HorizontalAlignment="Left" Padding="10,0" FontSize="11"
ToolTip="폴더 안에서 글자를 찾는 줄을 폅니다"/>
</StackPanel>
</Border>
</Popup>
</Grid>
</Border> </Border>
<!-- <!--
@ -231,7 +281,8 @@
폴더 비교는 "무엇이 다른가"에 답하지만 "이 함수를 쓰는 곳이 어디인가"에는 답하지 못한다. 폴더 비교는 "무엇이 다른가"에 답하지만 "이 함수를 쓰는 곳이 어디인가"에는 답하지 못한다.
그때마다 다른 도구를 켜는 대신 여기서 찾고 결과를 눌러 바로 그 줄로 넘어간다. 그때마다 다른 도구를 켜는 대신 여기서 찾고 결과를 눌러 바로 그 줄로 넘어간다.
--> -->
<Border Grid.Row="2" Padding="8" BorderThickness="1" Margin="0,0,0,6" <Border Grid.Row="1" Padding="8,5" BorderThickness="1" Margin="0,0,0,4"
Visibility="{Binding IsFindOpen, Converter={StaticResource BoolToVis}}"
BorderBrush="{DynamicResource Ubisam.Brush.Input.Border}"> BorderBrush="{DynamicResource Ubisam.Brush.Input.Border}">
<WrapPanel Orientation="Horizontal"> <WrapPanel Orientation="Horizontal">
<TextBlock Text="폴더 안 찾기" VerticalAlignment="Center" FontSize="11" FontWeight="Bold" <TextBlock Text="폴더 안 찾기" VerticalAlignment="Center" FontSize="11" FontWeight="Bold"
@ -266,58 +317,20 @@
Margin="0,0,6,0" Margin="0,0,6,0"
ToolTip="고른 줄을 '파일 비교' 탭에서 그 자리에 서서 엽니다. 더블클릭·Enter 도 같습니다"/> ToolTip="고른 줄을 '파일 비교' 탭에서 그 자리에 서서 엽니다. 더블클릭·Enter 도 같습니다"/>
<Button Content="결과 닫기" Command="{Binding ClearSearchCommand}" Height="28" MinWidth="70" <Button Content="결과 닫기" Command="{Binding ClearSearchCommand}" Height="28" MinWidth="70"
Margin="0,0,12,0" Margin="0,0,6,0"
ToolTip="결과 칸을 접고 목록에 자리를 돌려줍니다"/> ToolTip="결과 칸을 접고 목록에 자리를 돌려줍니다"/>
<!-- 12차 D-1: 찾기 줄 자체를 접는다. Esc 로도 접힌다. -->
<Button Content="찾기 접기" Command="{Binding CloseFindCommand}" Height="28" MinWidth="70"
Margin="0,0,12,0"
ToolTip="찾기 줄을 접습니다 (Esc). 다시 부르려면 Ctrl+F"/>
<TextBlock Text="{Binding SearchSummary}" VerticalAlignment="Center" FontSize="11" <TextBlock Text="{Binding SearchSummary}" VerticalAlignment="Center" FontSize="11"
Style="{StaticResource Muted}" TextTrimming="CharacterEllipsis" MaxWidth="520"/> Style="{StaticResource Muted}" TextTrimming="CharacterEllipsis" MaxWidth="520"/>
</WrapPanel> </WrapPanel>
</Border> </Border>
<!--
④ 색 뜻풀이. 색만 칠해 두면 무슨 뜻인지 아무도 모른다 -
파일 비교 화면의 "색 구분" 줄과 같은 성격이다.
-->
<Border Grid.Row="3" Padding="8,4" BorderThickness="1,1,1,0" Margin="0,0,0,0"
BorderBrush="{DynamicResource Ubisam.Brush.Input.Border}">
<WrapPanel Orientation="Horizontal">
<TextBlock Text="색 구분" Style="{StaticResource Muted}" FontSize="11" Margin="0,0,10,0"
VerticalAlignment="Center"/>
<Border Width="12" Height="12" Margin="0,0,4,0" VerticalAlignment="Center"
Background="{Binding Source={x:Static svc:FolderEntryStatus.Different},
Converter={StaticResource StatusBrush}}"
BorderThickness="1" BorderBrush="{DynamicResource Ubisam.Brush.Input.Border}"/>
<TextBlock Text="다름" FontSize="11" Margin="0,0,14,0" VerticalAlignment="Center"/>
<Border Width="12" Height="12" Margin="0,0,4,0" VerticalAlignment="Center"
Background="{Binding Source={x:Static svc:FolderEntryStatus.CommentOnly},
Converter={StaticResource StatusBrush}}"
BorderThickness="1" BorderBrush="{DynamicResource Ubisam.Brush.Input.Border}"/>
<TextBlock Text="다름(코드는 같음)" FontSize="11" Margin="0,0,14,0" VerticalAlignment="Center"
ToolTip="코드는 같고 주석 · 공백 · 빈 줄 · 줄끝 · BOM · 인코딩만 다른 파일입니다"/>
<Border Width="12" Height="12" Margin="0,0,4,0" VerticalAlignment="Center"
Background="{Binding Source={x:Static svc:FolderEntryStatus.LeftOnly},
Converter={StaticResource StatusBrush}}"
BorderThickness="1" BorderBrush="{DynamicResource Ubisam.Brush.Input.Border}"/>
<TextBlock Text="왼쪽에만" FontSize="11" Margin="0,0,14,0" VerticalAlignment="Center"/>
<Border Width="12" Height="12" Margin="0,0,4,0" VerticalAlignment="Center"
Background="{Binding Source={x:Static svc:FolderEntryStatus.RightOnly},
Converter={StaticResource StatusBrush}}"
BorderThickness="1" BorderBrush="{DynamicResource Ubisam.Brush.Input.Border}"/>
<TextBlock Text="오른쪽에만" FontSize="11" Margin="0,0,14,0" VerticalAlignment="Center"/>
<Border Width="12" Height="12" Margin="0,0,4,0" VerticalAlignment="Center"
Background="{Binding Source={x:Static svc:FolderEntryStatus.Binary},
Converter={StaticResource StatusBrush}}"
BorderThickness="1" BorderBrush="{DynamicResource Ubisam.Brush.Input.Border}"/>
<TextBlock Text="다름(이진)" FontSize="11" VerticalAlignment="Center"/>
</WrapPanel>
</Border>
<!-- ③ 목록 머리글. 트리 항목의 칸 폭과 같은 값을 쓴다. --> <!-- ③ 목록 머리글. 트리 항목의 칸 폭과 같은 값을 쓴다. -->
<Border Grid.Row="4" Padding="8,4" BorderThickness="1,1,1,0" <Border Grid.Row="2" Padding="8,4" BorderThickness="1,1,1,0"
Background="{DynamicResource Ubisam.Brush.Sidebar.Background}" Background="{DynamicResource Ubisam.Brush.Sidebar.Background}"
BorderBrush="{DynamicResource Ubisam.Brush.Input.Border}"> BorderBrush="{DynamicResource Ubisam.Brush.Input.Border}">
<Grid Margin="12,0,0,0"> <Grid Margin="12,0,0,0">
@ -347,7 +360,7 @@
채움 칸(*)이 0 이 되고 줄 배경이 글자 끝에서 끊긴다. 칸 폭이 고정이라 채움 칸(*)이 0 이 되고 줄 배경이 글자 끝에서 끊긴다. 칸 폭이 고정이라
가로로 넘칠 일이 없으므로 꺼 두는 편이 맞다. 가로로 넘칠 일이 없으므로 꺼 두는 편이 맞다.
--> -->
<Grid Grid.Row="5"> <Grid Grid.Row="3">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="*"/> <RowDefinition Height="*"/>
<RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/>
@ -437,7 +450,7 @@
</Grid> </Grid>
<!-- ⑤ 요약 · 동작 --> <!-- ⑤ 요약 · 동작 -->
<Border Grid.Row="6" Padding="8" BorderThickness="1,0,1,1" Margin="0,0,0,0" <Border Grid.Row="4" Padding="8,6" BorderThickness="1,0,1,1" Margin="0,0,0,0"
BorderBrush="{DynamicResource Ubisam.Brush.Input.Border}"> BorderBrush="{DynamicResource Ubisam.Brush.Input.Border}">
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
@ -447,8 +460,49 @@
<StackPanel Grid.Column="0" VerticalAlignment="Center"> <StackPanel Grid.Column="0" VerticalAlignment="Center">
<TextBlock Text="{Binding Summary}" FontSize="12" FontWeight="Bold"/> <TextBlock Text="{Binding Summary}" FontSize="12" FontWeight="Bold"/>
<!--
12차 D-1: 색 뜻풀이를 위에서 여기로 내렸다. 색은 <b>목록을 보는 동안</b> 필요한 것이라
결과 요약 옆이 제자리다 - 위에 두면 비교하기 전부터 한 줄을 먹었다.
-->
<WrapPanel Orientation="Horizontal" Margin="0,3,0,0">
<TextBlock Text="색 구분" Style="{StaticResource Muted}" FontSize="11" Margin="0,0,10,0"
VerticalAlignment="Center"/>
<TextBlock Text="색 구분" Style="{StaticResource Muted}" FontSize="11" Margin="0,0,10,0"
VerticalAlignment="Center"/>
<Border Width="12" Height="12" Margin="0,0,4,0" VerticalAlignment="Center"
Background="{Binding Source={x:Static svc:FolderEntryStatus.Different},
Converter={StaticResource StatusBrush}}"
BorderThickness="1" BorderBrush="{DynamicResource Ubisam.Brush.Input.Border}"/>
<TextBlock Text="다름" FontSize="11" Margin="0,0,14,0" VerticalAlignment="Center"/>
<Border Width="12" Height="12" Margin="0,0,4,0" VerticalAlignment="Center"
Background="{Binding Source={x:Static svc:FolderEntryStatus.CommentOnly},
Converter={StaticResource StatusBrush}}"
BorderThickness="1" BorderBrush="{DynamicResource Ubisam.Brush.Input.Border}"/>
<TextBlock Text="다름(코드는 같음)" FontSize="11" Margin="0,0,14,0" VerticalAlignment="Center"
ToolTip="코드는 같고 주석 · 공백 · 빈 줄 · 줄끝 · BOM · 인코딩만 다른 파일입니다"/>
<Border Width="12" Height="12" Margin="0,0,4,0" VerticalAlignment="Center"
Background="{Binding Source={x:Static svc:FolderEntryStatus.LeftOnly},
Converter={StaticResource StatusBrush}}"
BorderThickness="1" BorderBrush="{DynamicResource Ubisam.Brush.Input.Border}"/>
<TextBlock Text="왼쪽에만" FontSize="11" Margin="0,0,14,0" VerticalAlignment="Center"/>
<Border Width="12" Height="12" Margin="0,0,4,0" VerticalAlignment="Center"
Background="{Binding Source={x:Static svc:FolderEntryStatus.RightOnly},
Converter={StaticResource StatusBrush}}"
BorderThickness="1" BorderBrush="{DynamicResource Ubisam.Brush.Input.Border}"/>
<TextBlock Text="오른쪽에만" FontSize="11" Margin="0,0,14,0" VerticalAlignment="Center"/>
<Border Width="12" Height="12" Margin="0,0,4,0" VerticalAlignment="Center"
Background="{Binding Source={x:Static svc:FolderEntryStatus.Binary},
Converter={StaticResource StatusBrush}}"
BorderThickness="1" BorderBrush="{DynamicResource Ubisam.Brush.Input.Border}"/>
<TextBlock Text="다름(이진)" FontSize="11" VerticalAlignment="Center"/>
</WrapPanel>
<TextBlock Text="파일을 더블클릭하거나 Enter 를 누르면 &quot;파일 비교&quot; 탭에서 줄 단위로 엽니다. 한쪽에만 있는 파일도 열립니다." <TextBlock Text="파일을 더블클릭하거나 Enter 를 누르면 &quot;파일 비교&quot; 탭에서 줄 단위로 엽니다. 한쪽에만 있는 파일도 열립니다."
Style="{StaticResource Muted}" FontSize="11"/> Style="{StaticResource Muted}" FontSize="11" Margin="0,3,0,0"/>
</StackPanel> </StackPanel>
<WrapPanel Grid.Column="1" Orientation="Horizontal"> <WrapPanel Grid.Column="1" Orientation="Horizontal">

View File

@ -14,6 +14,45 @@ namespace MergeHub.Views
public FolderView() public FolderView()
{ {
InitializeComponent(); InitializeComponent();
// 12차 D-1: 찾기 줄은 늘 한 줄을 먹었다. 이제 Ctrl+F 로 부를 때만 편다(파일 비교의 찾기와 같은 방식).
PreviewKeyDown += OnPreviewKeyDown;
}
/// <summary>
/// Ctrl+F 로 찾기 줄을 펴고 칸에 손을 옮긴다. Esc 로 접는다(12차 D-1).
///
/// 손을 옮기는 것은 <b>배치가 끝난 뒤</b>여야 한다 - 접혀 있던 칸은 아직 화면에 없어서
/// 그 자리에서 Focus() 를 불러도 받지 않는다.
/// </summary>
private void OnPreviewKeyDown(object sender, KeyEventArgs e)
{
if (DataContext is not FolderViewModel vm) return;
if (e.Key == Key.F && Keyboard.Modifiers == ModifierKeys.Control)
{
vm.OpenFindCommand.Execute(null);
Dispatcher.BeginInvoke(new System.Action(() =>
{
SearchBox.Focus();
SearchBox.SelectAll();
}), System.Windows.Threading.DispatcherPriority.Loaded);
e.Handled = true;
return;
}
// 찾기 칸이 접혀 있으면 Esc 는 손대지 않는다 - 다른 곳에서 쓸 자리를 뺏지 않는다.
if (e.Key == Key.Escape && vm.IsFindOpen)
{
vm.CloseFindCommand.Execute(null);
e.Handled = true;
}
}
/// <summary>[옵션 ▾] 를 누르면 서랍을 여닫는다(12차 D-1).</summary>
private void Options_Click(object sender, RoutedEventArgs e)
{
if (DataContext is FolderViewModel vm) vm.IsOptionsOpen = !vm.IsOptionsOpen;
} }
/// <summary>TreeView.SelectedItem 은 읽기 전용이라 바인딩할 수 없다. 여기서 옮겨 준다.</summary> /// <summary>TreeView.SelectedItem 은 읽기 전용이라 바인딩할 수 없다. 여기서 옮겨 준다.</summary>