[전체 반영] 은 줄마다 Apply 를 따로 불러 바뀐 줄마다 머지 주석이 붙고 Undo 도 줄마다 한 걸음이었다. [구간 반영] 처럼 구간마다 주석 한 줄로 바꾼다. - 두 파일 비교 [전체 반영]: 반영할 수 있는 줄이 이어진 구간(BlockAround 와 같은 기준)을 먼저 나눠 구간마다 ApplyGroup. 지우는 반영은 "삭제 N줄". 모든 구간을 한 묶음 번호로 넘겨 Undo 한 번에 전체가 돌아간다. ApplyGroup 에 group · finish 를 더함. - 3-Way [전체 반영] 은 끈다(사용자 결정) - 차이 나는 모든 줄을 공통 조상(BASE)으로 바꾸던 동작이라 병합에서 쓸 데가 없고 양쪽 작업을 지운다. 꺼져도 툴팁으로 까닭. - 3-Way [자동 병합] 도 저쪽만 고친 줄 구간마다 주석 한 줄 · Undo 한 번. 사이에 낀 충돌 · 내가 고친 줄은 구간을 끊고 그대로 둔다. 시험: 빌드 경고 0 · 오류 0. 화면 g22-accept-all(새) 주석 7 -> 3 · 삭제 2줄 · BASE 와 같음 · Undo 한 번, g23-three-way(새, --merge) 전체 반영 꺼짐 · 주석 5 -> 2 · 내 줄 · 충돌 줄 그대로 · Undo 한 번. 실패 0. 기존 회귀는 사용자 지시로 돌리지 않았다. Agent: main (claude-opus-5-5) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2126 lines
151 KiB
XML
2126 lines
151 KiB
XML
<UserControl x:Class="MergeHub.Views.HomeView"
|
||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||
xmlns:local="clr-namespace:MergeHub.Views"
|
||
xmlns:ctl="clr-namespace:MergeHub.Views.Controls"
|
||
xmlns:system="clr-namespace:System;assembly=mscorlib"
|
||
xmlns:models="clr-namespace:MergeHub.Models"
|
||
xmlns:shell="clr-namespace:UbisamBase.Core.Shell;assembly=UbisamBase.Core"
|
||
shell:PlatformChrome.FullBleed="True"
|
||
mc:Ignorable="d"
|
||
PreviewKeyDown="View_PreviewKeyDown"
|
||
AllowDrop="True" DragOver="View_DragOver" Drop="View_Drop">
|
||
<UserControl.Resources>
|
||
<ResourceDictionary>
|
||
<ResourceDictionary.MergedDictionaries>
|
||
<ResourceDictionary Source="/MergeHub;component/Views/Controls/AppStyles.xaml"/>
|
||
</ResourceDictionary.MergedDictionaries>
|
||
|
||
<!-- BASE / LOCAL 머리 영역 공통 높이. 두 패널의 줄이 같은 눈높이에 오게 하는 기준값. -->
|
||
<system:Double x:Key="PaneHeaderHeight">124</system:Double>
|
||
|
||
<!-- 코드 한 줄의 높이. BASE/LOCAL 이 이 값을 똑같이 써야 두 패널의 같은 행이 같은 눈높이에 온다. -->
|
||
<system:Double x:Key="CodeLineHeight">16</system:Double>
|
||
|
||
<!-- 코드 글자 크기와 그에 따르는 여백(11차 F-5). 기본 12 의 값이다 - 화면(ApplyCodeFont)이
|
||
CodeFontMetrics 로 함께 바꾼다. DynamicResource 로 읽어야 바뀐 값이 바로 그려진다. -->
|
||
<system:Double x:Key="CodeFontSize">12</system:Double>
|
||
<!-- 칸 사이 잇는 선 자리 폭(11차 F-10) -->
|
||
<GridLength x:Key="LinkGapWidth">48</GridLength>
|
||
<GridLength x:Key="GutterWidth">66</GridLength>
|
||
<GridLength x:Key="GutterNumberWidth">46</GridLength>
|
||
<GridLength x:Key="GutterNarrowNumberWidth">40</GridLength>
|
||
<GridLength x:Key="GutterMarkWidth">6</GridLength>
|
||
<GridLength x:Key="GutterButtonWidth">20</GridLength>
|
||
<!-- 두 파일 비교에서만 나오는 [<] 단추 자리(12차 B-1). Auto 로 두면 단추가 있는 줄만
|
||
글이 오른쪽으로 밀려, 같은 칸 안에서도 줄마다 글 시작 자리가 달랐다(2026-09-28 사용자 보고).
|
||
모드가 바뀔 때 화면이 0 ↔ 단추 폭으로 갈아 끼운다(ApplyGutterReserve). -->
|
||
<GridLength x:Key="GutterBothWaysWidth">0</GridLength>
|
||
<system:Double x:Key="GutterButtonHeight">14</system:Double>
|
||
<system:Double x:Key="GutterButtonFontSize">9</system:Double>
|
||
<system:Double x:Key="BookmarkHeight">10</system:Double>
|
||
<Thickness x:Key="EditorGutterMargin">66,0,0,0</Thickness>
|
||
|
||
<!-- BASE / LOCAL 하단 요약 칸 공통 높이. 두 패널의 코드 영역이 같은 크기여야 나란히 읽힌다. -->
|
||
<system:Double x:Key="PaneFooterHeight">54</system:Double>
|
||
|
||
<BooleanToVisibilityConverter x:Key="BoolToVis"/>
|
||
<ctl:LineHighlightBrushConverter x:Key="HighlightBrush"/>
|
||
<!-- 편집 칸 바탕: 밝음 #FAFAFA · 어두움 #252830(2026-09-30 사용자 선택). PaneBackgroundConverter 참고. -->
|
||
<ctl:PaneBackgroundConverter x:Key="PaneBackground"/>
|
||
<ctl:HighlightNameToBrushConverter x:Key="HighlightByName"/>
|
||
<ctl:TextToVisibilityConverter x:Key="TextToVis"/>
|
||
|
||
<Style TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
|
||
<Setter Property="Margin" Value="2,0"/>
|
||
</Style>
|
||
|
||
<!-- 범례의 색 칩. 코드 패널의 줄 배경과 정확히 같은 브러시를 쓴다. -->
|
||
<Style x:Key="LegendChip" TargetType="Border">
|
||
<Setter Property="Width" Value="14"/>
|
||
<Setter Property="Height" Value="14"/>
|
||
<Setter Property="Margin" Value="0,0,4,0"/>
|
||
<Setter Property="CornerRadius" Value="2"/>
|
||
<Setter Property="BorderThickness" Value="1"/>
|
||
<Setter Property="BorderBrush" Value="{DynamicResource Ubisam.Brush.Input.Border}"/>
|
||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||
</Style>
|
||
|
||
<ctl:ZeroToDimConverter x:Key="ZeroToDim"/>
|
||
|
||
<!--
|
||
범례 한 칸(4차 C-4). 읽기만 하던 설명을 <b>누르면 그 갈래로 가는 도구</b>로 바꿨다.
|
||
단추처럼 보이지 않게 테두리와 배경을 지운다 - 줄이 단추 열 개로 보이면 시끄럽다.
|
||
대신 손 모양 커서와 마우스를 올렸을 때의 옅은 배경으로 "누르는 것"임을 알린다.
|
||
-->
|
||
<Style x:Key="LegendButton" TargetType="Button">
|
||
<Setter Property="Background" Value="Transparent"/>
|
||
<Setter Property="BorderThickness" Value="0"/>
|
||
<Setter Property="Padding" Value="3,1"/>
|
||
<Setter Property="Margin" Value="0"/>
|
||
<Setter Property="MinWidth" Value="0"/>
|
||
<Setter Property="MinHeight" Value="0"/>
|
||
<Setter Property="Cursor" Value="Hand"/>
|
||
<Setter Property="Template">
|
||
<Setter.Value>
|
||
<ControlTemplate TargetType="Button">
|
||
<Border x:Name="Back" Background="{TemplateBinding Background}"
|
||
Padding="{TemplateBinding Padding}" CornerRadius="3">
|
||
<ContentPresenter VerticalAlignment="Center"/>
|
||
</Border>
|
||
<ControlTemplate.Triggers>
|
||
<Trigger Property="IsMouseOver" Value="True">
|
||
<Setter TargetName="Back" Property="Background"
|
||
Value="{DynamicResource Ubisam.Brush.Sidebar.Background}"/>
|
||
</Trigger>
|
||
</ControlTemplate.Triggers>
|
||
</ControlTemplate>
|
||
</Setter.Value>
|
||
</Setter>
|
||
</Style>
|
||
|
||
<Style x:Key="LegendText" TargetType="TextBlock">
|
||
<Setter Property="FontSize" Value="11"/>
|
||
<Setter Property="Margin" Value="0,0,3,0"/>
|
||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||
</Style>
|
||
|
||
<!-- 범례에 붙는 실시간 개수. 줄 하나만 반영해도 바로 바뀐다. -->
|
||
<Style x:Key="LegendCount" TargetType="TextBlock">
|
||
<Setter Property="FontSize" Value="11"/>
|
||
<Setter Property="FontWeight" Value="Bold"/>
|
||
<Setter Property="Margin" Value="0,0,14,0"/>
|
||
<Setter Property="MinWidth" Value="14"/>
|
||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||
</Style>
|
||
|
||
<!-- 범례의 문법 예시. 실제 코드 패널과 같은 컨트롤이라 색이 어긋날 수 없다. -->
|
||
<Style x:Key="LegendCode" TargetType="ctl:CodeTextBlock">
|
||
<Setter Property="FontFamily" Value="Consolas"/>
|
||
<Setter Property="FontSize" Value="11"/>
|
||
<Setter Property="Margin" Value="0,0,10,0"/>
|
||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||
</Style>
|
||
|
||
<Style x:Key="PanelTitle" TargetType="TextBlock">
|
||
<Setter Property="FontWeight" Value="Bold"/>
|
||
<Setter Property="Foreground" Value="{DynamicResource Ubisam.Brush.Accent}"/>
|
||
</Style>
|
||
|
||
<Style x:Key="Muted" TargetType="TextBlock">
|
||
<Setter Property="Foreground" Value="{DynamicResource Ubisam.Brush.Muted}"/>
|
||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||
</Style>
|
||
|
||
<Style x:Key="Mono" TargetType="TextBlock">
|
||
<Setter Property="FontFamily" Value="Consolas"/>
|
||
<Setter Property="FontSize" Value="{DynamicResource CodeFontSize}"/>
|
||
</Style>
|
||
|
||
<!--
|
||
코드 줄 컨테이너. 평소에는 높이를 고정해 두 패널의 행이 1:1로 맞물리게 한다.
|
||
높이를 풀어 두면 컨테이너 자체 여백 때문에 20px 를 조금씩 넘어 아래로 갈수록 어긋난다.
|
||
워드랩일 때만 풀어 준다 - 그때는 줄마다 높이가 달라야 하기 때문이다.
|
||
-->
|
||
<Style x:Key="CodeLineItem" TargetType="ListBoxItem" BasedOn="{StaticResource {x:Type ListBoxItem}}">
|
||
<Setter Property="Height" Value="{DynamicResource CodeLineHeight}"/>
|
||
<Setter Property="MinHeight" Value="{DynamicResource CodeLineHeight}"/>
|
||
<Setter Property="Padding" Value="0"/>
|
||
<Setter Property="Margin" Value="0"/>
|
||
<Setter Property="VerticalContentAlignment" Value="Top"/>
|
||
<Style.Triggers>
|
||
<DataTrigger Binding="{Binding DataContext.WordWrap,
|
||
RelativeSource={RelativeSource AncestorType=ListBox}}" Value="True">
|
||
<Setter Property="Height" Value="{x:Static system:Double.NaN}"/>
|
||
</DataTrigger>
|
||
</Style.Triggers>
|
||
</Style>
|
||
|
||
<!-- BASE 한 줄. 줄 배경 = 색 범례, 글자색 = C# 문법.
|
||
코드 본문에는 <b>툴팁을 달지 않는다</b> - 글이 이미 보이는데 그 위에 같은 글이 상자로
|
||
겹쳐 뜨면 가리기만 한다. 잘려서 안 보이는 부분은 가로 스크롤로 본다. -->
|
||
<DataTemplate x:Key="BaseLineTemplate">
|
||
<!-- 여백 폭(66)을 LOCAL 과 맞춘다. 접히는 자리가 같아야 워드랩에서도 행이 어긋나지 않는다.
|
||
66 인 까닭은 LocalLineTemplate 에 적었다(6차 B-4). -->
|
||
<Grid MinHeight="{Binding BaseRowHeight}">
|
||
<Grid.ColumnDefinitions>
|
||
<!-- [<] 자리. 단추가 없는 줄에서도 자리를 잡아 둔다 - Auto 로 두면 이 줄만 글이 밀린다. -->
|
||
<ColumnDefinition Width="{DynamicResource GutterBothWaysWidth}"/>
|
||
<ColumnDefinition Width="{DynamicResource GutterWidth}"/>
|
||
<ColumnDefinition Width="*"/>
|
||
<ColumnDefinition Width="Auto"/>
|
||
</Grid.ColumnDefinitions>
|
||
|
||
<!-- [<] 이 줄을 왼쪽 파일로 반영(12차 B-1). 두 파일 비교에서만 보인다 -
|
||
Git 모드의 왼쪽은 지난 커밋이라 쓸 파일이 없다. -->
|
||
<Button Grid.Column="0" Content="<" Padding="0" Margin="2,0,2,0" MinWidth="16"
|
||
Height="{DynamicResource GutterButtonHeight}" MinHeight="{DynamicResource GutterButtonHeight}"
|
||
FontSize="{DynamicResource GutterButtonFontSize}" VerticalAlignment="Top"
|
||
Command="{Binding DataContext.TakeLineToBaseCommand, RelativeSource={RelativeSource AncestorType=UserControl}}"
|
||
CommandParameter="{Binding}"
|
||
ToolTip="이 줄을 오른쪽 내용으로 왼쪽 파일에 반영">
|
||
<Button.Style>
|
||
<Style TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
|
||
<Setter Property="Visibility" Value="Collapsed"/>
|
||
<Style.Triggers>
|
||
<MultiDataTrigger>
|
||
<MultiDataTrigger.Conditions>
|
||
<Condition Binding="{Binding CanTakeBase}" Value="True"/>
|
||
<Condition Binding="{Binding DataContext.BothWays,
|
||
RelativeSource={RelativeSource AncestorType=UserControl}}" Value="True"/>
|
||
</MultiDataTrigger.Conditions>
|
||
<Setter Property="Visibility" Value="Visible"/>
|
||
</MultiDataTrigger>
|
||
</Style.Triggers>
|
||
</Style>
|
||
</Button.Style>
|
||
</Button>
|
||
<!-- LOCAL 에서 지운 줄을 되살리는 [>] (11차 F-10). 예전에는 LOCAL 의 빈 줄(필러)에 달려 있었는데
|
||
이제 LOCAL 칸에는 그 줄이 없으므로 BASE 쪽 줄 끝에 단다(Araxis 처럼). LOCAL 에 있는 줄은 LOCAL 여백의 [>] 그대로. -->
|
||
<Button Grid.Column="3" Content=">" Padding="0" Margin="2,0,2,0" MinWidth="16"
|
||
Height="{DynamicResource GutterButtonHeight}" MinHeight="{DynamicResource GutterButtonHeight}"
|
||
FontSize="{DynamicResource GutterButtonFontSize}" VerticalAlignment="Top"
|
||
Command="{Binding DataContext.TakeLineCommand, RelativeSource={RelativeSource AncestorType=UserControl}}"
|
||
CommandParameter="{Binding}"
|
||
ToolTip="LOCAL 에서 지운 이 줄을 되살리기 (BASE 내용으로 가져오기)">
|
||
<Button.Style>
|
||
<Style TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
|
||
<Setter Property="Visibility" Value="Collapsed"/>
|
||
<Style.Triggers>
|
||
<MultiDataTrigger>
|
||
<MultiDataTrigger.Conditions>
|
||
<Condition Binding="{Binding CanTakeBase}" Value="True"/>
|
||
<Condition Binding="{Binding HasLocal}" Value="False"/>
|
||
</MultiDataTrigger.Conditions>
|
||
<Setter Property="Visibility" Value="Visible"/>
|
||
</MultiDataTrigger>
|
||
</Style.Triggers>
|
||
</Style>
|
||
</Button.Style>
|
||
</Button>
|
||
<TextBlock Grid.Column="1" Text="{Binding BaseNumberText}" Style="{StaticResource Mono}" LineHeight="{DynamicResource CodeLineHeight}" LineStackingStrategy="BlockLineHeight"
|
||
Foreground="{DynamicResource Ubisam.Brush.Muted}" TextAlignment="Right"
|
||
VerticalAlignment="Top" Margin="0,0,8,0"/>
|
||
<Border Grid.Column="2" Padding="2,0"
|
||
Background="{Binding Highlight, Converter={StaticResource HighlightBrush}}">
|
||
<Grid ClipToBounds="True">
|
||
<ctl:CodeTextBlock Code="{Binding BaseText}" Words="{Binding BaseWords}"
|
||
InBlockComment="{Binding BaseInComment}"
|
||
CodeLanguage="{Binding DataContext.Language,
|
||
RelativeSource={RelativeSource AncestorType=UserControl}}"
|
||
HighlightSyntax="{Binding DataContext.SyntaxHighlight,
|
||
RelativeSource={RelativeSource AncestorType=UserControl}}"
|
||
TextWrapping="{Binding WrapMode,
|
||
RelativeSource={RelativeSource AncestorType=UserControl}}"
|
||
FontFamily="Consolas" FontSize="{DynamicResource CodeFontSize}"
|
||
LineHeight="{DynamicResource CodeLineHeight}"
|
||
LineStackingStrategy="BlockLineHeight"
|
||
VerticalAlignment="Top"
|
||
SizeChanged="BaseText_SizeChanged">
|
||
<ctl:CodeTextBlock.RenderTransform>
|
||
<TranslateTransform X="{Binding SourceShiftX,
|
||
RelativeSource={RelativeSource AncestorType=UserControl}}"/>
|
||
</ctl:CodeTextBlock.RenderTransform>
|
||
</ctl:CodeTextBlock>
|
||
</Grid>
|
||
</Border>
|
||
</Grid>
|
||
</DataTemplate>
|
||
|
||
<!--
|
||
LOCAL 원본 한 줄 (3-Way). 파일을 연 시점의 내 줄이라 편집하지 않는다.
|
||
여백의 [<] 를 누르면 그 줄을 결과(MERGED)로 되돌린다 - "Accept Mine".
|
||
-->
|
||
<DataTemplate x:Key="OriginalLocalLineTemplate">
|
||
<Grid MinHeight="{Binding OriginalLocalRowHeight}">
|
||
<Grid.ColumnDefinitions>
|
||
<ColumnDefinition Width="{DynamicResource GutterNumberWidth}"/>
|
||
<ColumnDefinition Width="{DynamicResource GutterButtonWidth}"/>
|
||
<ColumnDefinition Width="*"/>
|
||
</Grid.ColumnDefinitions>
|
||
|
||
<TextBlock Grid.Column="0" Text="{Binding OriginalLocalNumberText}" Style="{StaticResource Mono}" LineHeight="{DynamicResource CodeLineHeight}" LineStackingStrategy="BlockLineHeight"
|
||
Foreground="{DynamicResource Ubisam.Brush.Muted}" TextAlignment="Right"
|
||
VerticalAlignment="Top" Margin="0,0,4,0"/>
|
||
|
||
<Button Grid.Column="1" Content="<" Padding="0" Margin="0" MinWidth="16"
|
||
Height="{DynamicResource GutterButtonHeight}" MinHeight="{DynamicResource GutterButtonHeight}" FontSize="{DynamicResource GutterButtonFontSize}" VerticalAlignment="Top"
|
||
Visibility="{Binding CanTakeLocal, Converter={StaticResource BoolToVis}}"
|
||
Command="{Binding DataContext.TakeLocalLineCommand,
|
||
RelativeSource={RelativeSource AncestorType=UserControl}}"
|
||
CommandParameter="{Binding}"
|
||
ToolTip="이 줄을 내 원본으로 되돌리기"/>
|
||
|
||
<Border Grid.Column="2" Padding="2,0"
|
||
Background="{Binding Highlight, Converter={StaticResource HighlightBrush}}">
|
||
<Grid ClipToBounds="True">
|
||
<ctl:CodeTextBlock Code="{Binding OriginalLocalText}"
|
||
InBlockComment="{Binding LocalInComment}"
|
||
CodeLanguage="{Binding DataContext.Language,
|
||
RelativeSource={RelativeSource AncestorType=UserControl}}"
|
||
HighlightSyntax="{Binding DataContext.SyntaxHighlight,
|
||
RelativeSource={RelativeSource AncestorType=UserControl}}"
|
||
TextWrapping="{Binding WrapMode,
|
||
RelativeSource={RelativeSource AncestorType=UserControl}}"
|
||
FontFamily="Consolas" FontSize="{DynamicResource CodeFontSize}"
|
||
LineHeight="{DynamicResource CodeLineHeight}"
|
||
LineStackingStrategy="BlockLineHeight"
|
||
VerticalAlignment="Top"
|
||
SizeChanged="OriginalLocalText_SizeChanged">
|
||
<ctl:CodeTextBlock.RenderTransform>
|
||
<TranslateTransform X="{Binding SourceShiftX,
|
||
RelativeSource={RelativeSource AncestorType=UserControl}}"/>
|
||
</ctl:CodeTextBlock.RenderTransform>
|
||
</ctl:CodeTextBlock>
|
||
</Grid>
|
||
</Border>
|
||
</Grid>
|
||
</DataTemplate>
|
||
|
||
<!--
|
||
REMOTE 한 줄 (3-Way). BASE 와 같은 모양이되, 여백에 [<] 버튼이 붙는다 -
|
||
누르면 그 줄을 LOCAL 로 가져온다. 방향을 헷갈리지 않게 LOCAL 쪽 [>] 와 화살표를 반대로 했다.
|
||
-->
|
||
<DataTemplate x:Key="RemoteLineTemplate">
|
||
<Grid MinHeight="{Binding RemoteRowHeight}">
|
||
<Grid.ColumnDefinitions>
|
||
<ColumnDefinition Width="{DynamicResource GutterNumberWidth}"/>
|
||
<ColumnDefinition Width="{DynamicResource GutterButtonWidth}"/>
|
||
<ColumnDefinition Width="*"/>
|
||
</Grid.ColumnDefinitions>
|
||
|
||
<TextBlock Grid.Column="0" Text="{Binding RemoteNumberText}" Style="{StaticResource Mono}" LineHeight="{DynamicResource CodeLineHeight}" LineStackingStrategy="BlockLineHeight"
|
||
Foreground="{DynamicResource Ubisam.Brush.Muted}" TextAlignment="Right"
|
||
VerticalAlignment="Top" Margin="0,0,4,0"/>
|
||
|
||
<Button Grid.Column="1" Content="<" Padding="0" Margin="0" MinWidth="16"
|
||
Height="{DynamicResource GutterButtonHeight}" MinHeight="{DynamicResource GutterButtonHeight}" FontSize="{DynamicResource GutterButtonFontSize}" VerticalAlignment="Top"
|
||
Visibility="{Binding CanTakeRemote, Converter={StaticResource BoolToVis}}"
|
||
Command="{Binding DataContext.TakeRemoteLineCommand,
|
||
RelativeSource={RelativeSource AncestorType=UserControl}}"
|
||
CommandParameter="{Binding}"
|
||
ToolTip="이 줄을 내 작업으로 가져오기"/>
|
||
|
||
<Border Grid.Column="2" Padding="2,0"
|
||
Background="{Binding Highlight, Converter={StaticResource HighlightBrush}}">
|
||
<Grid ClipToBounds="True">
|
||
<ctl:CodeTextBlock Code="{Binding RemoteText}" Words="{Binding RemoteWords}"
|
||
InBlockComment="{Binding RemoteInComment}"
|
||
CodeLanguage="{Binding DataContext.Language,
|
||
RelativeSource={RelativeSource AncestorType=UserControl}}"
|
||
HighlightSyntax="{Binding DataContext.SyntaxHighlight,
|
||
RelativeSource={RelativeSource AncestorType=UserControl}}"
|
||
TextWrapping="{Binding WrapMode,
|
||
RelativeSource={RelativeSource AncestorType=UserControl}}"
|
||
FontFamily="Consolas" FontSize="{DynamicResource CodeFontSize}"
|
||
LineHeight="{DynamicResource CodeLineHeight}"
|
||
LineStackingStrategy="BlockLineHeight"
|
||
VerticalAlignment="Top"
|
||
SizeChanged="RemoteText_SizeChanged">
|
||
<ctl:CodeTextBlock.RenderTransform>
|
||
<TranslateTransform X="{Binding SourceShiftX,
|
||
RelativeSource={RelativeSource AncestorType=UserControl}}"/>
|
||
</ctl:CodeTextBlock.RenderTransform>
|
||
</ctl:CodeTextBlock>
|
||
</Grid>
|
||
</Border>
|
||
</Grid>
|
||
</DataTemplate>
|
||
|
||
<!--
|
||
LOCAL 한 줄 = 여백(북마크·줄번호·[>]) + 본문(색 배경 + 문법 색).
|
||
|
||
여백과 본문을 한 행에 두는 것이 요점이다. 따로 두면 워드랩을 켰을 때
|
||
줄마다 높이가 달라져 여백과 본문이 어긋난다. 한 행이면 높이가 저절로 맞는다.
|
||
|
||
대신 가로로 밀 때 여백까지 밀리면 안 되므로, 본문 글자만
|
||
TextShiftX(편집기의 가로 스크롤 값)만큼 밀고 열 안에서 잘라낸다.
|
||
글자를 고치는 일은 이 위에 겹쳐 놓은 편집기(LocalEditor)가 맡는다.
|
||
|
||
여백 폭은 66 = 북마크 6 + 줄 번호 40 + [>] 20. 네 칸이 모두 66 이다(6차 B-4).
|
||
예전에는 54 = 10 + 24 + 20 이라 줄 번호 글자 자리가 20px(Consolas 12 로 세 자리)뿐이어서
|
||
2949 가 "294" 로 잘렸다. 위의 세 칸은 번호 자리가 30px 이상이라 멀쩡했다.
|
||
지금은 번호 자리 36px 로 다섯 자리(99,999줄)까지 들어간다.
|
||
-->
|
||
<DataTemplate x:Key="LocalLineTemplate">
|
||
<Grid Background="Transparent"
|
||
MinHeight="{Binding RowHeight}"
|
||
MouseLeftButtonDown="Gutter_MouseLeftButtonDown">
|
||
<Grid.ColumnDefinitions>
|
||
<ColumnDefinition Width="{DynamicResource GutterMarkWidth}"/>
|
||
<ColumnDefinition Width="{DynamicResource GutterNarrowNumberWidth}"/>
|
||
<ColumnDefinition Width="{DynamicResource GutterButtonWidth}"/>
|
||
<!-- [<] 자리(12차 B-1). BASE 와 같은 값이라 두 칸의 글 시작 자리가 늘 같다. -->
|
||
<ColumnDefinition Width="{DynamicResource GutterBothWaysWidth}"/>
|
||
<ColumnDefinition Width="*"/>
|
||
</Grid.ColumnDefinitions>
|
||
|
||
<!-- 북마크 표식. 켜진 줄만 색 막대가 보인다. -->
|
||
<Border Grid.Column="0" Width="4" HorizontalAlignment="Left" CornerRadius="1"
|
||
Margin="1,3" VerticalAlignment="Top" Height="{DynamicResource BookmarkHeight}"
|
||
Background="{DynamicResource Ubisam.Brush.Accent}"
|
||
Visibility="{Binding IsBookmarked, Converter={StaticResource BoolToVis}}"/>
|
||
|
||
<TextBlock Grid.Column="1" Text="{Binding LocalNumberText}" Style="{StaticResource Mono}" LineHeight="{DynamicResource CodeLineHeight}" LineStackingStrategy="BlockLineHeight"
|
||
Foreground="{DynamicResource Ubisam.Brush.Muted}" TextAlignment="Right"
|
||
VerticalAlignment="Top" Margin="0,0,4,0"
|
||
ToolTip="더블클릭하면 북마크를 켜고 끕니다 (F2 로 이동)"/>
|
||
|
||
<Button Grid.Column="2" Content=">" Padding="0" Margin="0" MinWidth="16"
|
||
Height="{DynamicResource GutterButtonHeight}" MinHeight="{DynamicResource GutterButtonHeight}" FontSize="{DynamicResource GutterButtonFontSize}" VerticalAlignment="Top"
|
||
Visibility="{Binding CanTakeBase, Converter={StaticResource BoolToVis}}"
|
||
Command="{Binding DataContext.TakeLineCommand,
|
||
RelativeSource={RelativeSource AncestorType=UserControl}}"
|
||
CommandParameter="{Binding}"
|
||
ToolTip="이 줄만 BASE 내용으로 가져오기"/>
|
||
|
||
<!-- [<] 왼쪽에 없는 줄(오른쪽에서 새로 생긴 줄)을 왼쪽 파일에 넣는다(12차 B-1).
|
||
왼쪽에 있는 줄은 BASE 칸의 [<] 를 쓴다 - 거기 줄이 있으니 그 자리에 다는 것이 맞다. -->
|
||
<Button Grid.Column="3" Content="<" Padding="0" Margin="0" MinWidth="16"
|
||
Height="{DynamicResource GutterButtonHeight}" MinHeight="{DynamicResource GutterButtonHeight}"
|
||
FontSize="{DynamicResource GutterButtonFontSize}" VerticalAlignment="Top"
|
||
Command="{Binding DataContext.TakeLineToBaseCommand,
|
||
RelativeSource={RelativeSource AncestorType=UserControl}}"
|
||
CommandParameter="{Binding}"
|
||
ToolTip="이 줄을 왼쪽 파일에 넣기">
|
||
<Button.Style>
|
||
<Style TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
|
||
<Setter Property="Visibility" Value="Collapsed"/>
|
||
<Style.Triggers>
|
||
<MultiDataTrigger>
|
||
<MultiDataTrigger.Conditions>
|
||
<Condition Binding="{Binding CanTakeBase}" Value="True"/>
|
||
<Condition Binding="{Binding HasBase}" Value="False"/>
|
||
<Condition Binding="{Binding DataContext.BothWays,
|
||
RelativeSource={RelativeSource AncestorType=UserControl}}" Value="True"/>
|
||
</MultiDataTrigger.Conditions>
|
||
<Setter Property="Visibility" Value="Visible"/>
|
||
</MultiDataTrigger>
|
||
</Style.Triggers>
|
||
</Style>
|
||
</Button.Style>
|
||
</Button>
|
||
|
||
<!--
|
||
색 배경은 칸 전체를 채우고 제자리에 있는다. 미는 것은 글자뿐이다.
|
||
|
||
Padding 을 0 으로 두는 것이 중요하다. 문제 줄 표시용 왼쪽 테두리(2)도
|
||
자리를 차지하므로, BASE·REMOTE 의 Padding 2 와 합이 같아야 세 패널의 글자가
|
||
같은 x 에서 시작한다. 여기가 2 더 밀려 있으면 그 위에 겹친 편집기의 캐럿이
|
||
글자 가운데에 박힌 것처럼 보인다.
|
||
-->
|
||
<Border Grid.Column="4" Padding="0"
|
||
Background="{Binding Highlight, Converter={StaticResource HighlightBrush}}"
|
||
BorderThickness="2,0,0,0">
|
||
<Border.ToolTip>
|
||
<MultiBinding StringFormat="{}{0} {1}">
|
||
<Binding Path="Problem"/>
|
||
<Binding Path="MoveHint"/>
|
||
</MultiBinding>
|
||
</Border.ToolTip>
|
||
<Border.Style>
|
||
<Style TargetType="Border">
|
||
<Setter Property="BorderBrush" Value="Transparent"/>
|
||
<Style.Triggers>
|
||
<DataTrigger Binding="{Binding HasProblem}" Value="True">
|
||
<Setter Property="BorderBrush" Value="{DynamicResource Ubisam.Brush.Danger}"/>
|
||
</DataTrigger>
|
||
</Style.Triggers>
|
||
</Style>
|
||
</Border.Style>
|
||
|
||
<Grid ClipToBounds="True">
|
||
<ctl:CodeTextBlock Code="{Binding LocalText}" Words="{Binding LocalWords}"
|
||
InBlockComment="{Binding LocalInComment}"
|
||
CodeLanguage="{Binding DataContext.Language,
|
||
RelativeSource={RelativeSource AncestorType=UserControl}}"
|
||
HighlightSyntax="{Binding DataContext.SyntaxHighlight,
|
||
RelativeSource={RelativeSource AncestorType=UserControl}}"
|
||
TextWrapping="{Binding WrapMode,
|
||
RelativeSource={RelativeSource AncestorType=UserControl}}"
|
||
FontFamily="Consolas" FontSize="{DynamicResource CodeFontSize}"
|
||
LineHeight="{DynamicResource CodeLineHeight}"
|
||
LineStackingStrategy="BlockLineHeight"
|
||
VerticalAlignment="Top"
|
||
SizeChanged="LocalText_SizeChanged">
|
||
<ctl:CodeTextBlock.RenderTransform>
|
||
<TranslateTransform X="{Binding TextShiftX,
|
||
RelativeSource={RelativeSource AncestorType=UserControl}}"/>
|
||
</ctl:CodeTextBlock.RenderTransform>
|
||
</ctl:CodeTextBlock>
|
||
</Grid>
|
||
</Border>
|
||
</Grid>
|
||
</DataTemplate>
|
||
</ResourceDictionary>
|
||
</UserControl.Resources>
|
||
|
||
<DockPanel Margin="2" TextElement.Foreground="{DynamicResource Ubisam.Brush.ContentForeground}">
|
||
|
||
<!-- ===== 문서 탭 줄 (12차 E-2) =====
|
||
짝 여러 개를 동시에 든다. 짝이 하나뿐일 때는 줄을 내주지 않는다(ShowTabStrip).
|
||
탭 이름은 파일 이름이고, 양쪽 이름이 다르면 "왼 ↔ 오". 저장하지 않은 탭에는 앞에 가운뎃점.
|
||
가운데 단추로도 닫힌다 - 브라우저와 같은 손버릇. -->
|
||
<!-- ItemsControl 이 아니라 ListBox 다 - 그쪽은 UIA 에 "컨트롤" 로 안 보여서 화면 시험이 탭 줄을
|
||
아예 못 읽고, 키로 탭을 옮기는 것도 공짜로 얻을 수 없다. 고르기가 곧 탭 옮기기(CurrentTab) 다. -->
|
||
<ListBox DockPanel.Dock="Top" x:Name="DocTabStrip"
|
||
ItemsSource="{Binding TabItems}"
|
||
SelectedItem="{Binding CurrentTab, Mode=TwoWay}"
|
||
Visibility="{Binding ShowTabStrip, Converter={StaticResource BoolToVis}}"
|
||
Margin="0,0,0,3" Padding="0" BorderThickness="0" Background="Transparent"
|
||
ScrollViewer.HorizontalScrollBarVisibility="Auto"
|
||
ScrollViewer.VerticalScrollBarVisibility="Disabled">
|
||
<ListBox.ItemsPanel>
|
||
<ItemsPanelTemplate>
|
||
<StackPanel Orientation="Horizontal"/>
|
||
</ItemsPanelTemplate>
|
||
</ListBox.ItemsPanel>
|
||
<ListBox.ItemContainerStyle>
|
||
<!-- 고른 항목의 파란 바탕을 없앤다 - 탭 모양은 아래 DataTemplate 이 그린다.
|
||
이 스타일이 플랫폼 ListBoxItem 스타일을 대신하므로 글자색도 여기서 준다 - 없으면 WPF 기본(검정)이라
|
||
어두운 테마에서 탭 이름이 바탕에 묻혔다(12차 G-8 곁, 잉크 차이 157 · 116 으로 확인). -->
|
||
<Style TargetType="ListBoxItem">
|
||
<Setter Property="Padding" Value="0"/>
|
||
<Setter Property="Margin" Value="0"/>
|
||
<Setter Property="Foreground" Value="{DynamicResource Ubisam.Brush.ContentForeground}"/>
|
||
<Setter Property="Template">
|
||
<Setter.Value>
|
||
<ControlTemplate TargetType="ListBoxItem">
|
||
<ContentPresenter/>
|
||
</ControlTemplate>
|
||
</Setter.Value>
|
||
</Setter>
|
||
</Style>
|
||
</ListBox.ItemContainerStyle>
|
||
<ListBox.ItemTemplate>
|
||
<DataTemplate>
|
||
<Border x:Name="TabShell" Margin="0,0,3,0" CornerRadius="3,3,0,0" BorderThickness="1,1,1,0"
|
||
Background="{DynamicResource Ubisam.Brush.Input.Background}"
|
||
BorderBrush="{DynamicResource Ubisam.Brush.Input.Border}"
|
||
MouseDown="DocTab_MouseDown"
|
||
ToolTip="{Binding Tip}">
|
||
<StackPanel Orientation="Horizontal" Height="24">
|
||
<!-- 저장하지 않은 표시. 이름이 움직이지 않게 자리를 늘 차지한다. -->
|
||
<TextBlock Text="•" Width="10" FontSize="13" FontWeight="Bold"
|
||
VerticalAlignment="Center" TextAlignment="Center" Margin="4,0,0,0"
|
||
Foreground="{DynamicResource Ubisam.Brush.Accent}"
|
||
Visibility="{Binding IsDirty, Converter={StaticResource BoolToVis}}"/>
|
||
<TextBlock Text="{Binding Title}" FontSize="11" VerticalAlignment="Center"
|
||
Margin="2,0,2,0" MaxWidth="240" TextTrimming="CharacterEllipsis"/>
|
||
<Button Content="×" FontSize="12" Width="18" Height="18" Padding="0" Margin="2,0,3,0"
|
||
VerticalAlignment="Center" Focusable="False"
|
||
Command="{Binding DataContext.CloseTabCommand, RelativeSource={RelativeSource AncestorType=UserControl}}"
|
||
CommandParameter="{Binding}"
|
||
ToolTip="이 탭을 닫습니다 (저장하지 않은 편집은 그대로 보관됩니다)"/>
|
||
</StackPanel>
|
||
</Border>
|
||
<DataTemplate.Triggers>
|
||
<!-- 떠 있는 탭은 본문과 같은 바탕 · 진한 테두리로 이어 보이게 한다. -->
|
||
<DataTrigger Binding="{Binding IsCurrent}" Value="True">
|
||
<Setter TargetName="TabShell" Property="Background"
|
||
Value="{DynamicResource Ubisam.Brush.ContentBackground}"/>
|
||
<Setter TargetName="TabShell" Property="BorderBrush"
|
||
Value="{DynamicResource Ubisam.Brush.Accent}"/>
|
||
<Setter TargetName="TabShell" Property="BorderThickness" Value="1,2,1,0"/>
|
||
</DataTrigger>
|
||
</DataTemplate.Triggers>
|
||
</DataTemplate>
|
||
</ListBox.ItemTemplate>
|
||
</ListBox>
|
||
|
||
<Grid>
|
||
<Grid.RowDefinitions>
|
||
<RowDefinition Height="Auto"/>
|
||
<RowDefinition Height="Auto"/>
|
||
<RowDefinition Height="*"/>
|
||
<!-- 상태바. 패널 안이 아니라 창 아래 한 줄로 둔다(4차 C-2). -->
|
||
<RowDefinition Height="Auto"/>
|
||
</Grid.RowDefinitions>
|
||
|
||
<!-- ===== 상단 상태 바 ===== -->
|
||
<Border Grid.Row="0" Padding="10,4" Margin="0,0,0,4"
|
||
Background="{DynamicResource Ubisam.Brush.Input.Background}"
|
||
BorderBrush="{DynamicResource Ubisam.Brush.Input.Border}" BorderThickness="1">
|
||
<DockPanel>
|
||
<!--
|
||
단축키 안내는 화면 오른쪽 위 끝에 둔다. 위 상태 바는 내용에 따라 줄이 늘었다
|
||
줄었다 하는 WrapPanel 이라 그 안에 넣으면 자리가 떠다닌다 - DockPanel 로
|
||
오른쪽에 붙박아 어느 모드에서든 같은 자리에 있게 했다.
|
||
-->
|
||
<!-- 12차 B-2: 프로그램 정보(관리 목적). 단축키 바로 옆 - 둘 다 "이 프로그램에 대한 안내" 다. -->
|
||
<Button DockPanel.Dock="Right" Content="정보" Click="About_Click"
|
||
Height="26" MinHeight="26" Padding="10,2" FontSize="11" Margin="10,0,0,0"
|
||
VerticalAlignment="Top"
|
||
ToolTip="이 프로그램의 버전 · 빌드 날짜 · 만든 사람 · 사내 문의처를 봅니다"/>
|
||
<Button DockPanel.Dock="Right" Content="단축키" Click="ShortcutHelp_Click"
|
||
Height="26" MinHeight="26" Padding="10,2" FontSize="11" Margin="10,0,0,0"
|
||
VerticalAlignment="Top"
|
||
ToolTip="단축키 목록을 봅니다 (F1)"/>
|
||
<!-- 11차 F-4: 오른쪽 ACTIONS 칸을 감춰 코드 칸을 넓힌다. 감춘 칸에 있으면 되살릴 길이 없으니 늘 보이는 이 줄에 둔다. -->
|
||
<Button DockPanel.Dock="Right" Content="{Binding ActionsToggleLabel}" Command="{Binding ToggleActionsCommand}"
|
||
Height="26" MinHeight="26" Padding="10,2" FontSize="11" Margin="10,0,0,0"
|
||
VerticalAlignment="Top"
|
||
ToolTip="오른쪽 ACTIONS 칸을 감추거나 다시 보입니다 (F9). 감춰도 Ctrl+S · Alt+←/→ 는 그대로 듣습니다"/>
|
||
<Button DockPanel.Dock="Right" Content="결과 내보내기" Command="{Binding ExportReportCommand}"
|
||
Height="26" MinHeight="26" Padding="10,2" FontSize="11" Margin="10,0,0,0"
|
||
VerticalAlignment="Top"
|
||
ToolTip="비교 결과를 글로 뽑아 파일에 저장합니다. 메일이나 결재에 그대로 붙일 수 있습니다"/>
|
||
|
||
|
||
<WrapPanel Orientation="Horizontal">
|
||
<!-- 지금 어느 모드인지 늘 보이게 한다 - 커밋 이력이 없는 이유를 알 수 있어야 한다. -->
|
||
<Border Padding="6,1" CornerRadius="2" Margin="0,0,10,0" VerticalAlignment="Center"
|
||
Background="{DynamicResource Ubisam.Brush.Input.Background}"
|
||
BorderBrush="{DynamicResource Ubisam.Brush.Input.Border}" BorderThickness="1">
|
||
<TextBlock Text="{Binding ModeLabel}" FontSize="11" FontWeight="Bold"
|
||
Foreground="{DynamicResource Ubisam.Brush.Accent}"/>
|
||
</Border>
|
||
|
||
<!-- Git 이 아닐 때: 비교할 파일 두 개를 직접 고른다 -->
|
||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center"
|
||
Visibility="{Binding IsPlainMode, Converter={StaticResource BoolToVis}}">
|
||
<!--
|
||
잘린 경로 두 줄을 뺐다(4차 C-1). 260px 안에서 잘린 경로는 읽을 수 없어
|
||
자리만 먹었고, 같은 값이 각 패널 머리글에 이미 있다.
|
||
<b>놓는 자리는 단추로 옮겼다</b> - 끌어다 놓기(3차 D-7)의 자리가 사라지면 안 되고,
|
||
잘린 글자보다 단추가 겨냥하기 쉽다.
|
||
-->
|
||
<Button Content="기준 파일..." Command="{Binding PickLeftFileCommand}"
|
||
Height="26" MinHeight="26" Padding="8,2" FontSize="11" Margin="0,0,4,0"
|
||
AllowDrop="True" DragOver="View_DragOver" Drop="LeftFile_Drop"
|
||
ToolTip="{Binding LeftFile}"/>
|
||
<Button Content="내 파일..." Command="{Binding PickRightFileCommand}"
|
||
Height="26" MinHeight="26" Padding="8,2" FontSize="11"
|
||
AllowDrop="True" DragOver="View_DragOver" Drop="RightFile_Drop"
|
||
ToolTip="{Binding RightFile}"/>
|
||
|
||
<!-- 폴더 비교에서 열었을 때만 켜진다. 목록 없이 연 파일에는 딛고 갈 자리가 없다. -->
|
||
<Button Content="◀ 이전 파일" Command="{Binding PrevFileCommand}"
|
||
Height="26" MinHeight="26" Padding="8,2" FontSize="11" Margin="14,0,4,0"
|
||
ToolTip="폴더 비교 목록에서 앞 파일로 (Ctrl+PageUp)"/>
|
||
<TextBlock Text="{Binding FileQueuePosition}" VerticalAlignment="Center"
|
||
Style="{StaticResource Muted}" FontSize="11" MinWidth="42"
|
||
TextAlignment="Center"/>
|
||
<Button Content="다음 파일 ▶" Command="{Binding NextFileCommand}"
|
||
Height="26" MinHeight="26" Padding="8,2" FontSize="11" Margin="4,0,0,0"
|
||
ToolTip="폴더 비교 목록에서 다음 파일로 (Ctrl+PageDown)"/>
|
||
|
||
<TextBlock Text="최근" VerticalAlignment="Center" Style="{StaticResource Muted}"
|
||
FontSize="11" Margin="14,0,4,0"/>
|
||
<ComboBox x:Name="RecentBox" ItemsSource="{Binding RecentFiles}"
|
||
SelectionChanged="Recent_SelectionChanged"
|
||
Width="200" Height="26" MinHeight="26" FontSize="11"
|
||
VerticalContentAlignment="Center"
|
||
ToolTip="최근에 견준 파일 짝. 고르면 바로 엽니다">
|
||
<ComboBox.ItemTemplate>
|
||
<DataTemplate>
|
||
<!-- 자리를 옮겼거나 지워진 짝은 흐리게. 목록에서 지우지는 않는다 -
|
||
네트워크 드라이브나 USB 는 잠깐 안 보일 뿐이다. -->
|
||
<TextBlock Text="{Binding Label}" ToolTip="{Binding Tip}" FontSize="11">
|
||
<TextBlock.Style>
|
||
<Style TargetType="TextBlock">
|
||
<Style.Triggers>
|
||
<DataTrigger Binding="{Binding Exists}" Value="False">
|
||
<Setter Property="Opacity" Value="0.45"/>
|
||
</DataTrigger>
|
||
</Style.Triggers>
|
||
</Style>
|
||
</TextBlock.Style>
|
||
</TextBlock>
|
||
</DataTemplate>
|
||
</ComboBox.ItemTemplate>
|
||
</ComboBox>
|
||
</StackPanel>
|
||
|
||
<!-- Git 일 때: 비교할 파일과 3-Way 상대 브랜치를 여기서 고른다.
|
||
파일 목록은 BASE 머리에 있었는데, 그러면 BASE 쪽에만 줄이 하나 더 생겨
|
||
LOCAL 과 경로 줄 높이가 어긋난다. -->
|
||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center"
|
||
Visibility="{Binding IsGitMode, Converter={StaticResource BoolToVis}}">
|
||
<TextBlock Text="파일" Style="{StaticResource Muted}" FontSize="11"
|
||
VerticalAlignment="Center" Margin="0,0,6,0"/>
|
||
<ComboBox ItemsSource="{Binding Files}" SelectedItem="{Binding SelectedFile}"
|
||
MinWidth="260" Height="26" MinHeight="26" FontSize="11" Margin="0,0,14,0"
|
||
ToolTip="비교할 파일"/>
|
||
</StackPanel>
|
||
|
||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center"
|
||
Visibility="{Binding IsGitMode, Converter={StaticResource BoolToVis}}">
|
||
<TextBlock Text="3-Way" Style="{StaticResource Muted}" FontSize="11"
|
||
VerticalAlignment="Center" Margin="0,0,6,0"/>
|
||
<ComboBox ItemsSource="{Binding RemoteBranches}"
|
||
SelectedItem="{Binding RemoteBranch, Mode=TwoWay}"
|
||
Visibility="{Binding ShowBranchCombo, Converter={StaticResource BoolToVis}}"
|
||
MinWidth="180" Height="26" MinHeight="26" FontSize="11"
|
||
ToolTip="고른 브랜치를 REMOTE(Theirs) 로 놓고 merge base 기준 3-Way 로 봅니다"/>
|
||
<!-- 병합 충돌 파일은 콤보를 안 건드리고 네 칸이 뜬다(6차 A-3). 콤보는 그때 "(3-Way 안 씀)" 이라
|
||
화면과 다른 말을 했다(7차 A-2). 대신 무엇과 견주는지 글로 보인다. -->
|
||
<TextBlock Text="{Binding ConflictSideText}" FontSize="11" FontWeight="SemiBold"
|
||
VerticalAlignment="Center" MinWidth="180"
|
||
Visibility="{Binding IsConflictThreeWay, Converter={StaticResource BoolToVis}}"
|
||
ToolTip="병합 중인 충돌 파일이라 REMOTE 는 병합 상대 쪽입니다. 브랜치를 고르지 않아도 됩니다"/>
|
||
</StackPanel>
|
||
|
||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center"
|
||
Visibility="{Binding IsGitMode, Converter={StaticResource BoolToVis}}">
|
||
<TextBlock Text="Repo" Style="{StaticResource Muted}" Margin="0,0,6,0"/>
|
||
<TextBlock Text="{Binding Workspace.RepositoryName}" FontWeight="Bold" Margin="0,0,16,0"
|
||
VerticalAlignment="Center"
|
||
ToolTip="{Binding Workspace.RepositoryPath}"/>
|
||
|
||
<TextBlock Text="Branch" Style="{StaticResource Muted}" Margin="0,0,6,0"/>
|
||
<TextBlock Text="{Binding Workspace.CurrentBranch}" FontWeight="Bold" Margin="0,0,16,0"
|
||
Foreground="{DynamicResource Ubisam.Brush.Accent}" VerticalAlignment="Center"/>
|
||
|
||
<!-- Git 주소 + 최신 여부 -->
|
||
<TextBlock Text="Git" Style="{StaticResource Muted}" Margin="0,0,6,0"/>
|
||
<TextBlock Text="{Binding Workspace.RemoteUrlText}" Margin="0,0,10,0" MaxWidth="300"
|
||
TextTrimming="CharacterEllipsis" VerticalAlignment="Center"
|
||
ToolTip="{Binding Workspace.RemoteUrlText}"/>
|
||
<Border CornerRadius="3" Padding="6,1" Margin="0,0,6,0" VerticalAlignment="Center">
|
||
<Border.Style>
|
||
<Style TargetType="Border">
|
||
<!-- 최신이면 초록, 아니면 주황. 범례의 반영/미반영 색과 같은 뜻으로 맞췄다. -->
|
||
<Setter Property="Background"
|
||
Value="{Binding Source=Changed, Converter={StaticResource HighlightByName}, ConverterParameter=Changed}"/>
|
||
<Style.Triggers>
|
||
<DataTrigger Binding="{Binding Workspace.IsUpToDate}" Value="True">
|
||
<Setter Property="Background"
|
||
Value="{Binding Source=Applied, Converter={StaticResource HighlightByName}, ConverterParameter=Applied}"/>
|
||
</DataTrigger>
|
||
</Style.Triggers>
|
||
</Style>
|
||
</Border.Style>
|
||
<TextBlock Text="{Binding Workspace.SyncStatusText}" FontSize="11" FontWeight="Bold"
|
||
VerticalAlignment="Center"/>
|
||
</Border>
|
||
<TextBlock Text="{Binding Workspace.LastFetchText}" Style="{StaticResource Muted}"
|
||
FontSize="11" Margin="0,0,16,0"
|
||
ToolTip="앞섬/뒤처짐 수치는 마지막 fetch 시점 기준입니다. Git 탭에서 Fetch 하면 갱신됩니다."/>
|
||
|
||
<TextBlock Text="Selected Commit" Style="{StaticResource Muted}" Margin="0,0,6,0"/>
|
||
<TextBlock Text="{Binding CommitHash}" FontFamily="Consolas" Margin="0,0,4,0"
|
||
Foreground="{DynamicResource Ubisam.Brush.Warning}" VerticalAlignment="Center"/>
|
||
<TextBlock Text="{Binding CommitSubject}" Margin="0,0,16,0" MaxWidth="240"
|
||
TextTrimming="CharacterEllipsis" VerticalAlignment="Center"/>
|
||
|
||
<TextBlock Text="Working Tree" Style="{StaticResource Muted}" Margin="0,0,6,0"/>
|
||
<TextBlock Text="{Binding Workspace.WorkingTreeSummary}" FontWeight="Bold" Margin="0,0,16,0"
|
||
VerticalAlignment="Center"/>
|
||
|
||
<TextBlock Text="{Binding Workspace.PendingOperationText}" FontWeight="Bold" Margin="0,0,16,0"
|
||
Foreground="{DynamicResource Ubisam.Brush.Danger}" VerticalAlignment="Center"/>
|
||
|
||
</StackPanel>
|
||
|
||
<Button Content="새로고침" Command="{Binding ReloadCommand}"
|
||
Height="26" MinHeight="26" Padding="10,2" FontSize="12"
|
||
Visibility="{Binding IsGitMode, Converter={StaticResource BoolToVis}}"/>
|
||
</WrapPanel>
|
||
</DockPanel>
|
||
</Border>
|
||
|
||
<!-- ===== 색 구분 안내(범례) =====
|
||
칩 색은 LineHighlightBrushes 한 곳에서 오므로 코드 패널과 항상 같은 색이다. -->
|
||
<StackPanel Grid.Row="1">
|
||
|
||
<!-- ===== 한쪽이 지운 충돌 (6차 A-4) =====
|
||
이런 충돌에서 정할 것은 "이 파일을 남길까 지울까" 하나다. 줄 단위로 끌고 가면 그 물음이 안 보였다.
|
||
범례 바로 위, 코드보다 먼저 눈에 들어오는 자리에 둔다. -->
|
||
<Border Padding="10,6" Margin="0,0,0,5" BorderThickness="1"
|
||
Visibility="{Binding IsDeletionConflict, Converter={StaticResource BoolToVis}}"
|
||
Background="{DynamicResource Ubisam.Brush.Input.Background}"
|
||
BorderBrush="{DynamicResource Ubisam.Brush.Danger}">
|
||
<DockPanel LastChildFill="True">
|
||
<StackPanel DockPanel.Dock="Right" Orientation="Horizontal" VerticalAlignment="Center">
|
||
<Button Content="파일 남기기" MinWidth="110" Margin="8,0,0,0"
|
||
Command="{Binding KeepFileCommand}"
|
||
Style="{StaticResource FilledButton}" FontWeight="Bold"
|
||
ToolTip="파일이 있는 쪽을 골라 남기고 스테이징합니다. 고친 것이 있으면 고친 대로 남깁니다"/>
|
||
<Button Content="파일 지우기" MinWidth="110" Margin="8,0,0,0"
|
||
Command="{Binding DeleteFileCommand}"
|
||
ToolTip="지운 쪽을 따라 파일을 지우고 스테이징합니다"/>
|
||
</StackPanel>
|
||
<TextBlock Text="{Binding DeletionConflictText}" TextWrapping="Wrap" VerticalAlignment="Center"
|
||
FontWeight="Bold" Foreground="{DynamicResource Ubisam.Brush.Danger}"/>
|
||
</DockPanel>
|
||
</Border>
|
||
|
||
<Border Padding="10,3" Margin="0,0,0,5"
|
||
Background="{DynamicResource Ubisam.Brush.Input.Background}"
|
||
BorderBrush="{DynamicResource Ubisam.Brush.Input.Border}" BorderThickness="1">
|
||
<WrapPanel Orientation="Horizontal">
|
||
<!--
|
||
줄 왼쪽 안내(4차 C-4). 항목을 눌러 이동할 수 있게 만들었는데
|
||
<b>눌러진다는 사실 자체가 안 보였다</b> - 테두리를 지운 값이다.
|
||
항목마다 테두리를 주면 줄이 단추 여덟 개로 보여 시끄럽다.
|
||
대신 줄 머리에서 한 번만 말해 준다.
|
||
-->
|
||
<TextBlock Text="색 구분" Style="{StaticResource Muted}" FontWeight="Bold"
|
||
FontSize="11" Margin="0,0,4,0"/>
|
||
<TextBlock Text="(눌러서 이동)" Style="{StaticResource Muted}" FontSize="11" Margin="0,0,12,0"
|
||
ToolTip="개수를 누르면 그 갈래의 줄로 갑니다. 다시 누르면 다음 줄로 갑니다"/>
|
||
|
||
<!-- 각 항목 뒤의 숫자는 지금 화면에 있는 줄 수. 한 줄만 반영해도 즉시 바뀐다. -->
|
||
<Button Style="{StaticResource LegendButton}" Command="{Binding GoToKindCommand}"
|
||
CommandParameter="{x:Static models:LineHighlight.Changed}"
|
||
Opacity="{Binding ChangedCount, Converter={StaticResource ZeroToDim}}"
|
||
ToolTip="누르면 'BASE와 다름' 줄로 갑니다. 다시 누르면 다음 줄">
|
||
<StackPanel Orientation="Horizontal">
|
||
<Border Style="{StaticResource LegendChip}"
|
||
Background="{Binding Source=Changed, Converter={StaticResource HighlightByName}, ConverterParameter=Changed}"/>
|
||
<TextBlock Text="BASE와 다름" Style="{StaticResource LegendText}"/>
|
||
<TextBlock Text="{Binding ChangedCount}" Style="{StaticResource LegendCount}"/>
|
||
</StackPanel>
|
||
</Button>
|
||
|
||
<Button Style="{StaticResource LegendButton}" Command="{Binding GoToKindCommand}"
|
||
CommandParameter="{x:Static models:LineHighlight.Applied}"
|
||
Opacity="{Binding AppliedCount, Converter={StaticResource ZeroToDim}}"
|
||
ToolTip="누르면 '머지 반영함' 줄로 갑니다. 다시 누르면 다음 줄">
|
||
<StackPanel Orientation="Horizontal">
|
||
<Border Style="{StaticResource LegendChip}"
|
||
Background="{Binding Source=Applied, Converter={StaticResource HighlightByName}, ConverterParameter=Applied}"/>
|
||
<TextBlock Text="머지 반영함" Style="{StaticResource LegendText}"/>
|
||
<TextBlock Text="{Binding AppliedCount}" Style="{StaticResource LegendCount}"
|
||
Foreground="{DynamicResource Ubisam.Brush.Success}"/>
|
||
</StackPanel>
|
||
</Button>
|
||
|
||
<Button Style="{StaticResource LegendButton}" Command="{Binding GoToKindCommand}"
|
||
CommandParameter="{x:Static models:LineHighlight.Edited}"
|
||
Opacity="{Binding EditedCount, Converter={StaticResource ZeroToDim}}"
|
||
ToolTip="누르면 '직접 수정' 줄로 갑니다. 다시 누르면 다음 줄">
|
||
<StackPanel Orientation="Horizontal">
|
||
<Border Style="{StaticResource LegendChip}"
|
||
Background="{Binding Source=Edited, Converter={StaticResource HighlightByName}, ConverterParameter=Edited}"/>
|
||
<TextBlock Text="직접 수정" Style="{StaticResource LegendText}"/>
|
||
<TextBlock Text="{Binding EditedCount}" Style="{StaticResource LegendCount}"/>
|
||
</StackPanel>
|
||
</Button>
|
||
|
||
<Button Style="{StaticResource LegendButton}" Command="{Binding GoToKindCommand}"
|
||
CommandParameter="{x:Static models:LineHighlight.Added}"
|
||
Opacity="{Binding AddedCount, Converter={StaticResource ZeroToDim}}"
|
||
ToolTip="누르면 '추가' 줄로 갑니다. 다시 누르면 다음 줄">
|
||
<StackPanel Orientation="Horizontal">
|
||
<Border Style="{StaticResource LegendChip}"
|
||
Background="{Binding Source=Added, Converter={StaticResource HighlightByName}, ConverterParameter=Added}"/>
|
||
<TextBlock Text="추가" Style="{StaticResource LegendText}"/>
|
||
<TextBlock Text="{Binding AddedCount}" Style="{StaticResource LegendCount}"/>
|
||
</StackPanel>
|
||
</Button>
|
||
|
||
<Button Style="{StaticResource LegendButton}" Command="{Binding GoToKindCommand}"
|
||
CommandParameter="{x:Static models:LineHighlight.Removed}"
|
||
Opacity="{Binding RemovedCount, Converter={StaticResource ZeroToDim}}"
|
||
ToolTip="누르면 '삭제' 줄로 갑니다. 다시 누르면 다음 줄">
|
||
<StackPanel Orientation="Horizontal">
|
||
<Border Style="{StaticResource LegendChip}"
|
||
Background="{Binding Source=Removed, Converter={StaticResource HighlightByName}, ConverterParameter=Removed}"/>
|
||
<TextBlock Text="삭제" Style="{StaticResource LegendText}"/>
|
||
<TextBlock Text="{Binding RemovedCount}" Style="{StaticResource LegendCount}"/>
|
||
</StackPanel>
|
||
</Button>
|
||
|
||
<!-- 무시 규칙에 걸린 줄. 차이로 세지 않는다. -->
|
||
<Button Style="{StaticResource LegendButton}" Command="{Binding GoToKindCommand}"
|
||
CommandParameter="{x:Static models:LineHighlight.Ignored}"
|
||
Opacity="{Binding IgnoredCount, Converter={StaticResource ZeroToDim}}"
|
||
ToolTip="누르면 '무시' 줄로 갑니다. 다시 누르면 다음 줄">
|
||
<StackPanel Orientation="Horizontal">
|
||
<Border Style="{StaticResource LegendChip}"
|
||
Background="{Binding Source=Ignored, Converter={StaticResource HighlightByName}, ConverterParameter=Ignored}"/>
|
||
<TextBlock Text="무시" Style="{StaticResource LegendText}"/>
|
||
<TextBlock Text="{Binding IgnoredCount}" Style="{StaticResource LegendCount}"/>
|
||
</StackPanel>
|
||
</Button>
|
||
|
||
<!-- 자리만 옮긴 줄. 삭제+추가로 두 번 세지 않도록 따로 표시한다. -->
|
||
<Button Style="{StaticResource LegendButton}" Command="{Binding GoToKindCommand}"
|
||
CommandParameter="{x:Static models:LineHighlight.Moved}"
|
||
Opacity="{Binding MovedCount, Converter={StaticResource ZeroToDim}}"
|
||
ToolTip="누르면 '자리 옮김' 줄로 갑니다. 다시 누르면 다음 줄">
|
||
<StackPanel Orientation="Horizontal">
|
||
<Border Style="{StaticResource LegendChip}"
|
||
Background="{Binding Source=Moved, Converter={StaticResource HighlightByName}, ConverterParameter=Moved}"/>
|
||
<TextBlock Text="자리 옮김" Style="{StaticResource LegendText}"/>
|
||
<TextBlock Text="{Binding MovedCount}" Style="{StaticResource LegendCount}"/>
|
||
</StackPanel>
|
||
</Button>
|
||
|
||
<!-- 3-Way 일 때만 뜻이 있는 두 가지. 2-Way 에서는 늘 0 이라 자리만 차지한다. -->
|
||
<Button Style="{StaticResource LegendButton}" Command="{Binding GoToKindCommand}"
|
||
CommandParameter="{x:Static models:LineHighlight.RemoteChange}"
|
||
Opacity="{Binding RemoteChangeCount, Converter={StaticResource ZeroToDim}}"
|
||
Visibility="{Binding IsThreeWay, Converter={StaticResource BoolToVis}}"
|
||
ToolTip="누르면 '저쪽만 고친 줄'로 갑니다. 다시 누르면 다음 줄">
|
||
<StackPanel Orientation="Horizontal">
|
||
<Border Style="{StaticResource LegendChip}"
|
||
Background="{Binding Source=RemoteChange, Converter={StaticResource HighlightByName}, ConverterParameter=RemoteChange}"/>
|
||
<TextBlock Text="Theirs only" Style="{StaticResource LegendText}"/>
|
||
<TextBlock Text="{Binding RemoteChangeCount}" Style="{StaticResource LegendCount}"/>
|
||
</StackPanel>
|
||
</Button>
|
||
|
||
<Button Style="{StaticResource LegendButton}" Command="{Binding GoToKindCommand}"
|
||
CommandParameter="{x:Static models:LineHighlight.Conflict}"
|
||
Opacity="{Binding ConflictCount, Converter={StaticResource ZeroToDim}}"
|
||
Visibility="{Binding IsThreeWay, Converter={StaticResource BoolToVis}}"
|
||
ToolTip="누르면 충돌 줄로 갑니다. 다시 누르면 다음 줄">
|
||
<StackPanel Orientation="Horizontal">
|
||
<Border Style="{StaticResource LegendChip}"
|
||
Background="{Binding Source=Conflict, Converter={StaticResource HighlightByName}, ConverterParameter=Conflict}"/>
|
||
<TextBlock Text="Conflict" Style="{StaticResource LegendText}"/>
|
||
<TextBlock Text="{Binding ConflictCount}" Style="{StaticResource LegendCount}"/>
|
||
</StackPanel>
|
||
</Button>
|
||
|
||
<Border Style="{StaticResource LegendChip}" Background="#66E0A020"/>
|
||
<TextBlock Text="줄 안에서 바뀐 부분" Style="{StaticResource LegendText}"/>
|
||
<!-- 2026-09-30 사용자 요청: 이 칸만 개수가 없었다. 단어 단위로 달라진 곳이 있는 "BASE와 다름" 줄 수. -->
|
||
<TextBlock x:Name="InlineChangeCountText" Text="{Binding InlineChangeCount}" Style="{StaticResource LegendCount}" Margin="0,0,14,0"/>
|
||
|
||
</WrapPanel>
|
||
</Border>
|
||
</StackPanel>
|
||
|
||
<!--
|
||
이진 파일을 열었을 때. 코드 패널 위를 덮는다.
|
||
|
||
"줄 단위로 비교할 수 없습니다" 한 줄로 끝내면 정작 알고 싶은 <b>같은지 다른지</b>를
|
||
모른 채 화면을 닫게 된다. 그림이면 나란히 띄우고, 아니면 앞부분을 16진으로 늘어놓는다.
|
||
-->
|
||
<Border Grid.Row="2" Padding="10" Panel.ZIndex="10"
|
||
Visibility="{Binding IsBinaryFile, Converter={StaticResource BoolToVis}}"
|
||
Background="{DynamicResource Ubisam.Brush.ContentBackground}"
|
||
BorderBrush="{DynamicResource Ubisam.Brush.Input.Border}" BorderThickness="1">
|
||
<Grid>
|
||
<Grid.RowDefinitions>
|
||
<RowDefinition Height="Auto"/>
|
||
<RowDefinition Height="*"/>
|
||
</Grid.RowDefinitions>
|
||
|
||
<StackPanel Grid.Row="0" Margin="0,0,0,8">
|
||
<TextBlock Text="이진 파일" FontWeight="Bold" FontSize="13"
|
||
Foreground="{DynamicResource Ubisam.Brush.Accent}"/>
|
||
<TextBlock Text="{Binding BinarySummary}" FontSize="12" Margin="0,2,0,0"
|
||
TextWrapping="Wrap"/>
|
||
</StackPanel>
|
||
|
||
<!-- 그림: 나란히 띄운다. 16진으로 보는 것보다 훨씬 빠르다. -->
|
||
<Grid Grid.Row="1" Visibility="{Binding IsImageFile, Converter={StaticResource BoolToVis}}">
|
||
<Grid.ColumnDefinitions>
|
||
<ColumnDefinition Width="*"/>
|
||
<ColumnDefinition Width="8"/>
|
||
<ColumnDefinition Width="*"/>
|
||
</Grid.ColumnDefinitions>
|
||
|
||
<Border Grid.Column="0" BorderThickness="1" Padding="6"
|
||
BorderBrush="{DynamicResource Ubisam.Brush.Input.Border}">
|
||
<DockPanel>
|
||
<TextBlock DockPanel.Dock="Top" Text="{Binding BaseHeader}" Style="{StaticResource Muted}"
|
||
FontSize="11" TextTrimming="CharacterEllipsis" Margin="0,0,0,6"/>
|
||
<Image Source="{Binding LeftImagePath}" Stretch="Uniform"
|
||
RenderOptions.BitmapScalingMode="HighQuality"/>
|
||
</DockPanel>
|
||
</Border>
|
||
|
||
<Border Grid.Column="2" BorderThickness="1" Padding="6"
|
||
BorderBrush="{DynamicResource Ubisam.Brush.Input.Border}">
|
||
<DockPanel>
|
||
<TextBlock DockPanel.Dock="Top" Text="{Binding LocalHeader}" Style="{StaticResource Muted}"
|
||
FontSize="11" TextTrimming="CharacterEllipsis" Margin="0,0,0,6"/>
|
||
<Image Source="{Binding RightImagePath}" Stretch="Uniform"
|
||
RenderOptions.BitmapScalingMode="HighQuality"/>
|
||
</DockPanel>
|
||
</Border>
|
||
</Grid>
|
||
|
||
<!-- 그림이 아니면 16진 나란히 보기. 다른 줄만 색을 준다. -->
|
||
<DataGrid Grid.Row="1" ItemsSource="{Binding HexRows}"
|
||
Visibility="{Binding ShowHexView, Converter={StaticResource BoolToVis}}"
|
||
AutoGenerateColumns="False" IsReadOnly="True"
|
||
HeadersVisibility="Column" GridLinesVisibility="None"
|
||
FontFamily="Consolas" FontSize="11"
|
||
Background="Transparent" BorderThickness="1"
|
||
BorderBrush="{DynamicResource Ubisam.Brush.Input.Border}">
|
||
<DataGrid.RowStyle>
|
||
<Style TargetType="DataGridRow">
|
||
<Style.Triggers>
|
||
<DataTrigger Binding="{Binding IsDifferent}" Value="True">
|
||
<Setter Property="Background"
|
||
Value="{Binding Source=Changed, Converter={StaticResource HighlightByName}, ConverterParameter=Changed}"/>
|
||
</DataTrigger>
|
||
</Style.Triggers>
|
||
</Style>
|
||
</DataGrid.RowStyle>
|
||
<DataGrid.Columns>
|
||
<DataGridTextColumn Header="위치" Binding="{Binding OffsetText}" Width="Auto"/>
|
||
<DataGridTextColumn Header="왼쪽 (16진)" Binding="{Binding LeftHex}" Width="Auto"/>
|
||
<DataGridTextColumn Header="왼쪽" Binding="{Binding LeftText}" Width="Auto"/>
|
||
<DataGridTextColumn Header="오른쪽 (16진)" Binding="{Binding RightHex}" Width="Auto"/>
|
||
<DataGridTextColumn Header="오른쪽" Binding="{Binding RightText}" Width="*"/>
|
||
</DataGrid.Columns>
|
||
</DataGrid>
|
||
</Grid>
|
||
</Border>
|
||
|
||
|
||
<!-- ===== 본문 4분할 =====
|
||
ScrollViewer 로 감싸면 내부 Grid 가 "무한 폭"으로 측정되어 star 열이 콘텐츠 크기로
|
||
부풀고 오른쪽 패널이 창 밖으로 밀려난다. 셸이 이미 정확한 폭을 주므로 그대로 채운다. -->
|
||
<Grid Grid.Row="2" x:Name="BodyGrid" Grid.IsSharedSizeScope="True">
|
||
<Grid.ColumnDefinitions>
|
||
<!-- Git 저장소가 아니면 커밋 이력 칸을 접는다. 보여 줄 이력이 없기 때문이다. -->
|
||
<ColumnDefinition MinWidth="0">
|
||
<ColumnDefinition.Style>
|
||
<Style TargetType="ColumnDefinition">
|
||
<Setter Property="Width" Value="228"/>
|
||
<Style.Triggers>
|
||
<DataTrigger Binding="{Binding IsGitMode}" Value="False">
|
||
<Setter Property="Width" Value="0"/>
|
||
</DataTrigger>
|
||
</Style.Triggers>
|
||
</Style>
|
||
</ColumnDefinition.Style>
|
||
</ColumnDefinition>
|
||
<ColumnDefinition Width="4"/>
|
||
<ColumnDefinition x:Name="LocalColumn" Width="*" MinWidth="200"/>
|
||
<!-- 칸 사이 틈(11차 F-10). 바뀐 덩어리를 잇는 선을 그리는 자리라 구분선보다 넓다. 끌면 구분선처럼 폭이 바뀐다. -->
|
||
<ColumnDefinition Width="{StaticResource LinkGapWidth}"/>
|
||
<ColumnDefinition x:Name="BaseColumn" Width="*" MinWidth="200"/>
|
||
|
||
<!-- 3-Way 를 안 쓰면 REMOTE 칸과 그 앞 구분선을 폭 0 으로 접는다.
|
||
Visibility 만 숨기면 star 열이 자리를 그대로 차지해 빈 칸이 남는다. -->
|
||
<ColumnDefinition>
|
||
<ColumnDefinition.Style>
|
||
<Style TargetType="ColumnDefinition">
|
||
<Setter Property="Width" Value="0"/>
|
||
<Style.Triggers>
|
||
<DataTrigger Binding="{Binding IsThreeWay}" Value="True">
|
||
<Setter Property="Width" Value="{StaticResource LinkGapWidth}"/>
|
||
</DataTrigger>
|
||
</Style.Triggers>
|
||
</Style>
|
||
</ColumnDefinition.Style>
|
||
</ColumnDefinition>
|
||
<ColumnDefinition x:Name="RemoteColumn" MinWidth="0">
|
||
<ColumnDefinition.Style>
|
||
<Style TargetType="ColumnDefinition">
|
||
<Setter Property="Width" Value="0"/>
|
||
<Style.Triggers>
|
||
<DataTrigger Binding="{Binding IsThreeWay}" Value="True">
|
||
<Setter Property="Width" Value="*"/>
|
||
</DataTrigger>
|
||
</Style.Triggers>
|
||
</Style>
|
||
</ColumnDefinition.Style>
|
||
</ColumnDefinition>
|
||
|
||
<ColumnDefinition x:Name="ActionsSplitColumn" Width="4"/>
|
||
|
||
<!--
|
||
ACTIONS 칸. 접어도 폭은 그대로 둔다(4차 C-5). 칸 전체를 감추는 것은 11차 F-4(단추 · F9).
|
||
<b>접는다고 폭이 줄지 않는다</b> - 폭을 정하는 것은 두 칸짜리 단추(Undo/Redo ·
|
||
이전 차이/다음 차이)와 Accept 인데, 그것들은 접어도 남는 쪽이다.
|
||
실제로 176 으로 좁혀 봤더니 "Undo" 가 "Undc" 로, "이전 차이" 가 "이전 차" 로 잘렸다.
|
||
C-5 가 얻는 것은 폭이 아니라 <b>세로 자리와 덜 어지러운 칸</b>이다.
|
||
-->
|
||
<ColumnDefinition x:Name="ActionsColumn" Width="214" MinWidth="170"/>
|
||
</Grid.ColumnDefinitions>
|
||
|
||
<!--
|
||
3-Way 는 위에 원본 세 개(LOCAL · BASE · REMOTE)를 나란히 놓고,
|
||
아래에 결과(MERGED)를 폭 전체로 둔다. 원본을 넷째 칸으로 붙이면 한 칸이
|
||
40자도 안 돼서 코드를 읽을 수 없다 - 세로를 쓰는 편이 훨씬 넓다.
|
||
2-Way 에서는 아래 두 줄이 높이 0 이라 지금까지의 좌우 배치 그대로다.
|
||
-->
|
||
<Grid.RowDefinitions>
|
||
<RowDefinition Height="*"/>
|
||
<RowDefinition>
|
||
<RowDefinition.Style>
|
||
<Style TargetType="RowDefinition">
|
||
<Setter Property="Height" Value="0"/>
|
||
<Style.Triggers>
|
||
<DataTrigger Binding="{Binding IsThreeWay}" Value="True">
|
||
<Setter Property="Height" Value="4"/>
|
||
</DataTrigger>
|
||
</Style.Triggers>
|
||
</Style>
|
||
</RowDefinition.Style>
|
||
</RowDefinition>
|
||
<RowDefinition MinHeight="0">
|
||
<RowDefinition.Style>
|
||
<Style TargetType="RowDefinition">
|
||
<Setter Property="Height" Value="0"/>
|
||
<Style.Triggers>
|
||
<DataTrigger Binding="{Binding IsThreeWay}" Value="True">
|
||
<Setter Property="Height" Value="1*"/>
|
||
</DataTrigger>
|
||
</Style.Triggers>
|
||
</Style>
|
||
</RowDefinition.Style>
|
||
</RowDefinition>
|
||
</Grid.RowDefinitions>
|
||
|
||
<!-- ① 수정 이력 -->
|
||
<Border Grid.Column="0" Grid.RowSpan="3" BorderThickness="1"
|
||
Visibility="{Binding IsGitMode, Converter={StaticResource BoolToVis}}"
|
||
BorderBrush="{DynamicResource Ubisam.Brush.Input.Border}">
|
||
<Grid>
|
||
<Grid.RowDefinitions>
|
||
<RowDefinition Height="Auto"/>
|
||
<RowDefinition Height="*"/>
|
||
<RowDefinition Height="Auto"/>
|
||
</Grid.RowDefinitions>
|
||
|
||
<StackPanel Grid.Row="0" Margin="8,6">
|
||
<TextBlock Text="1. 수정 이력 (Commit)" Style="{StaticResource PanelTitle}"/>
|
||
<StackPanel Orientation="Horizontal">
|
||
<TextBlock Text="브랜치 및 커밋 히스토리 · " Style="{StaticResource Muted}" FontSize="11"/>
|
||
<TextBlock Text="{Binding Workspace.Commits.Count}" Style="{StaticResource Muted}" FontSize="11"/>
|
||
<TextBlock Text=" commits" Style="{StaticResource Muted}" FontSize="11"/>
|
||
</StackPanel>
|
||
</StackPanel>
|
||
|
||
<ListBox Grid.Row="1" BorderThickness="0" Background="Transparent"
|
||
ItemsSource="{Binding Workspace.CommitNodes}"
|
||
SelectedItem="{Binding SelectedNode}"
|
||
HorizontalContentAlignment="Stretch"
|
||
ScrollViewer.HorizontalScrollBarVisibility="Auto">
|
||
<ListBox.ItemContainerStyle>
|
||
<!-- 그래프 선이 행 경계에서 정확히 이어지려면 여백이 없어야 한다 -->
|
||
<Style TargetType="ListBoxItem" BasedOn="{StaticResource {x:Type ListBoxItem}}">
|
||
<Setter Property="Padding" Value="0"/>
|
||
<Setter Property="Margin" Value="0"/>
|
||
<Setter Property="MinHeight" Value="44"/>
|
||
</Style>
|
||
</ListBox.ItemContainerStyle>
|
||
<ListBox.ItemTemplate>
|
||
<DataTemplate>
|
||
<Grid MinHeight="44">
|
||
<Grid.ColumnDefinitions>
|
||
<ColumnDefinition Width="Auto"/>
|
||
<ColumnDefinition Width="*"/>
|
||
</Grid.ColumnDefinitions>
|
||
|
||
<!-- 브랜치 그래프: 행 높이 전체를 채워야 위아래 선이 이어진다 -->
|
||
<ctl:CommitGraphCell Grid.Column="0" Row="{Binding Graph}"
|
||
VerticalAlignment="Stretch"/>
|
||
|
||
<StackPanel Grid.Column="1" Margin="4,3" VerticalAlignment="Center">
|
||
<StackPanel Orientation="Horizontal">
|
||
<ItemsControl ItemsSource="{Binding Commit.Refs}" Margin="0,0,4,0">
|
||
<ItemsControl.ItemsPanel>
|
||
<ItemsPanelTemplate><StackPanel Orientation="Horizontal"/></ItemsPanelTemplate>
|
||
</ItemsControl.ItemsPanel>
|
||
<ItemsControl.ItemTemplate>
|
||
<DataTemplate>
|
||
<Border Background="{DynamicResource Ubisam.Brush.Tag.AccentBackground}"
|
||
CornerRadius="3" Padding="4,0" Margin="0,0,3,0">
|
||
<TextBlock Text="{Binding}" FontSize="10"
|
||
Foreground="{DynamicResource Ubisam.Brush.Tag.AccentForeground}"/>
|
||
</Border>
|
||
</DataTemplate>
|
||
</ItemsControl.ItemTemplate>
|
||
</ItemsControl>
|
||
<TextBlock Text="{Binding Commit.MessageShort}" TextTrimming="CharacterEllipsis"/>
|
||
</StackPanel>
|
||
<StackPanel Orientation="Horizontal">
|
||
<TextBlock Text="{Binding Commit.ShortSha}" FontFamily="Consolas" FontSize="11"
|
||
Foreground="{DynamicResource Ubisam.Brush.Warning}"/>
|
||
<TextBlock Text=" · " FontSize="11" Foreground="{DynamicResource Ubisam.Brush.Muted}"/>
|
||
<TextBlock Text="{Binding Commit.AuthorName}" FontSize="11"
|
||
Foreground="{DynamicResource Ubisam.Brush.Muted}"/>
|
||
<TextBlock Text=" · " FontSize="11" Foreground="{DynamicResource Ubisam.Brush.Muted}"/>
|
||
<TextBlock Text="{Binding Commit.When, StringFormat=yyyy-MM-dd}" FontSize="11"
|
||
Foreground="{DynamicResource Ubisam.Brush.Muted}"/>
|
||
</StackPanel>
|
||
</StackPanel>
|
||
</Grid>
|
||
</DataTemplate>
|
||
</ListBox.ItemTemplate>
|
||
</ListBox>
|
||
|
||
<Border Grid.Row="2" Padding="8,6" BorderThickness="0,1,0,0"
|
||
BorderBrush="{DynamicResource Ubisam.Brush.Input.Border}">
|
||
<StackPanel>
|
||
<TextBlock Text="선택된 커밋 정보" Style="{StaticResource Muted}" FontSize="11"/>
|
||
<TextBlock Text="{Binding CommitSubject}" TextTrimming="CharacterEllipsis"/>
|
||
</StackPanel>
|
||
</Border>
|
||
</Grid>
|
||
</Border>
|
||
|
||
<GridSplitter Grid.Column="1" Grid.RowSpan="3" Width="4" HorizontalAlignment="Stretch" DragCompleted="PaneSplitter_DragCompleted"
|
||
Background="{DynamicResource Ubisam.Brush.Table.GridLine}"/>
|
||
|
||
<!--
|
||
②-0 LOCAL 원본 (3-Way 전용, 읽기 전용).
|
||
파일을 연 시점의 내 줄을 그대로 붙들어 보여 준다. 이게 없으면 REMOTE 를
|
||
한 번 가져오는 순간 내 원래 내용이 화면에서 사라져 판단 근거를 잃는다.
|
||
-->
|
||
<Border Grid.Column="2" Grid.Row="0" BorderThickness="1"
|
||
Visibility="{Binding IsThreeWay, Converter={StaticResource BoolToVis}}"
|
||
BorderBrush="{DynamicResource Ubisam.Brush.Input.Border}"
|
||
Background="{Binding (TextElement.Foreground), RelativeSource={RelativeSource Self}, Converter={StaticResource PaneBackground}}">
|
||
<!-- 칸 밖으로 그려지지 않게 자른다. 표시층은 RenderTransform 으로 살짝 밀어 놓는데,
|
||
그건 배치가 아니라 그리기라 자르지 않으면 <b>아래 상태바 위에 코드가 겹쳐 그려진다.</b>
|
||
차이로 이동(Alt+↑↓)할 때 실제로 그렇게 보였다. -->
|
||
<Grid ClipToBounds="True">
|
||
<Grid.RowDefinitions>
|
||
<RowDefinition Height="Auto" SharedSizeGroup="PaneHeader"/>
|
||
<RowDefinition Height="*"/>
|
||
<RowDefinition Height="Auto"/>
|
||
<!-- 12차 B-3: 칸 아래 한 줄 요약 -->
|
||
<RowDefinition Height="Auto"/>
|
||
</Grid.RowDefinitions>
|
||
|
||
<StackPanel Grid.Row="0" Margin="8,6">
|
||
<TextBlock Text="LOCAL(Mine)" Style="{StaticResource PanelTitle}"/>
|
||
<!-- 내 쪽 · 파일(11차 F-1). 예전에는 MERGED 칸과 같은 값(브랜치 이름)이라 git mergetool 에서 실제로 읽은 LOCAL 임시 파일과 달랐다.
|
||
네 칸 머리를 모두 같은 모양(읽으라고 쓰는 글씨 · 한 줄 · 가운데 줄이기 · 툴팁 전체)으로 둔다. -->
|
||
<TextBlock ctl:MiddleTrim.Text="{Binding MineHeader}" ToolTip="{Binding MineHeader}"
|
||
FontFamily="Consolas" FontSize="12" Margin="0,1,0,0"
|
||
TextTrimming="CharacterEllipsis"
|
||
Foreground="{DynamicResource Ubisam.Brush.ContentForeground}"/>
|
||
</StackPanel>
|
||
|
||
<!-- 코드 칸을 제 자리 밖으로 못 나가게 자른다. 표시층의 미세 보정은 배치가 아니라
|
||
그리기라 자르지 않으면 아래 바닥 글 위에 코드가 겹쳐 그려진다. -->
|
||
<Grid Grid.Row="1" ClipToBounds="True">
|
||
<ListBox x:Name="OriginalLocalLines" BorderThickness="0" Background="Transparent"
|
||
SelectedItem="{Binding SelectedLine, Mode=OneWay}" SelectionChanged="PaneLines_SelectionChanged"
|
||
ItemTemplate="{StaticResource OriginalLocalLineTemplate}"
|
||
ItemContainerStyle="{StaticResource CodeLineItem}"
|
||
VirtualizingPanel.ScrollUnit="Pixel"
|
||
HorizontalContentAlignment="Stretch"
|
||
ScrollViewer.VerticalScrollBarVisibility="Visible"
|
||
ScrollViewer.HorizontalScrollBarVisibility="{Binding SourceBars,
|
||
RelativeSource={RelativeSource AncestorType=UserControl}}"
|
||
ScrollViewer.ScrollChanged="Lines_ScrollChanged"/>
|
||
</Grid>
|
||
|
||
<!--
|
||
원본 칸의 가로 스크롤 막대. 3-Way 에서 워드랩을 끄고 긴 줄이 있을 때만 보인다.
|
||
|
||
ScrollViewer 가 만들어 주는 막대를 쓰지 못하는 이유가 있다 - 이 칸들은
|
||
ScrollViewer 를 가로로 굴리지 않고(줄 번호까지 밀려 나가고 세 칸이 어긋난다)
|
||
글자만 SourceShiftX 로 민다. 그래서 그 막대는 <b>움직이지 않는 막대</b>가 된다.
|
||
세 칸은 늘 같이 움직이므로 세 막대의 손잡이도 같은 자리에 있다.
|
||
-->
|
||
<ScrollBar Grid.Row="2" Orientation="Horizontal" Height="14"
|
||
Minimum="0" SmallChange="24"
|
||
LargeChange="{Binding SourceViewport, RelativeSource={RelativeSource AncestorType=UserControl}}"
|
||
Maximum="{Binding SourceScrollMax, RelativeSource={RelativeSource AncestorType=UserControl}}"
|
||
ViewportSize="{Binding SourceViewport, RelativeSource={RelativeSource AncestorType=UserControl}}"
|
||
Value="{Binding SourceScrollValue, Mode=TwoWay, RelativeSource={RelativeSource AncestorType=UserControl}}"
|
||
Visibility="{Binding SourceBarVisibility, RelativeSource={RelativeSource AncestorType=UserControl}}"/>
|
||
|
||
<!-- 3-Way 에서는 세로가 빠듯하다. 아래 MERGED 의 상태바에 같은 정보가 있어 여기는 접는다. -->
|
||
<Border Grid.Row="2" Padding="8,5" BorderThickness="0,1,0,0"
|
||
Height="{StaticResource PaneFooterHeight}"
|
||
Visibility="{Binding IsTwoWay, Converter={StaticResource BoolToVis}}"
|
||
BorderBrush="{DynamicResource Ubisam.Brush.Input.Border}">
|
||
<StackPanel VerticalAlignment="Center">
|
||
<TextBlock Text="내 변경" Style="{StaticResource Muted}" FontSize="11"/>
|
||
<TextBlock Text="[<] 를 누르면 그 줄을 결과로 되돌립니다" FontSize="11"
|
||
Style="{StaticResource Muted}"/>
|
||
</StackPanel>
|
||
</Border>
|
||
|
||
<!-- 12차 B-3: 이 칸이 저쪽과 무엇이 다른가. 맨 아래 상태 줄의 "파일 전체" 와 다른 값이다. -->
|
||
<Border Grid.Row="3" Padding="8,3" BorderThickness="0,1,0,0"
|
||
BorderBrush="{DynamicResource Ubisam.Brush.Input.Border}"
|
||
Background="{DynamicResource Ubisam.Brush.Sidebar.Background}">
|
||
<TextBlock x:Name="MineSummaryText" Text="{Binding MineSummary}" FontSize="11"
|
||
TextTrimming="CharacterEllipsis"
|
||
Foreground="{DynamicResource Ubisam.Brush.Muted}"/>
|
||
</Border>
|
||
</Grid>
|
||
</Border>
|
||
|
||
<!-- ② BASE -->
|
||
<Border Grid.Row="0" BorderThickness="1"
|
||
BorderBrush="{DynamicResource Ubisam.Brush.Input.Border}"
|
||
Background="{Binding (TextElement.Foreground), RelativeSource={RelativeSource Self}, Converter={StaticResource PaneBackground}}">
|
||
<Border.Style>
|
||
<Style TargetType="Border">
|
||
<!-- 2-Way: 왼쪽 칸. 3-Way: 가운데 칸(LOCAL 과 REMOTE 사이가 공통 조상의 자리다). -->
|
||
<Setter Property="Grid.Column" Value="2"/>
|
||
<Style.Triggers>
|
||
<DataTrigger Binding="{Binding IsThreeWay}" Value="True">
|
||
<Setter Property="Grid.Column" Value="4"/>
|
||
</DataTrigger>
|
||
</Style.Triggers>
|
||
</Style>
|
||
</Border.Style>
|
||
<!-- 칸 밖으로 그려지지 않게 자른다. 표시층은 RenderTransform 으로 살짝 밀어 놓는데,
|
||
그건 배치가 아니라 그리기라 자르지 않으면 <b>아래 상태바 위에 코드가 겹쳐 그려진다.</b>
|
||
차이로 이동(Alt+↑↓)할 때 실제로 그렇게 보였다. -->
|
||
<Grid ClipToBounds="True">
|
||
<Grid.RowDefinitions>
|
||
<RowDefinition Height="Auto" SharedSizeGroup="PaneHeader"/>
|
||
<RowDefinition Height="*"/>
|
||
<RowDefinition Height="Auto"/>
|
||
<!-- 12차 B-3: 칸 아래 한 줄 요약 -->
|
||
<RowDefinition Height="Auto"/>
|
||
</Grid.RowDefinitions>
|
||
|
||
<!-- BASE / LOCAL 의 머리 영역 높이를 같게 고정해야 두 패널의 01행이 같은 눈높이에 온다 -->
|
||
<StackPanel Grid.Row="0" Margin="8,6">
|
||
<TextBlock Text="{Binding BaseTitle}" Style="{StaticResource PanelTitle}"/>
|
||
<!--
|
||
경로 줄을 따로 두지 않는다(4차 C-1).
|
||
같은 값이 위 툴바 · 이 머리글 · 아래 경로 상자 셋에 있었고, 그중 경로 상자만
|
||
패널마다 세로 40px 남짓을 먹었다. 전체 경로는 툴팁으로 옮기고
|
||
<b>복사는 우클릭 메뉴로</b> 지켰다 - 읽기전용 TextBox 를 뒀던 까닭이 복사였다.
|
||
-->
|
||
<!--
|
||
경로가 이 칸의 정체다(4차 C-1). 늘 똑같은 "BASE" 는 위 제목이 이미 말하므로
|
||
여기서는 경로만, 그것도 <b>회색 작은 글씨가 아니라 읽으라고</b> 적는다.
|
||
갈리는 첫 칸만 굵게 칠해 어디가 다른지 눈이 바로 가게 한다.
|
||
-->
|
||
<TextBlock FontFamily="Consolas" FontSize="12" Margin="0,1,0,0"
|
||
TextTrimming="CharacterEllipsis"
|
||
Foreground="{DynamicResource Ubisam.Brush.ContentForeground}"
|
||
ToolTip="{Binding BaseFileLocation}"
|
||
ctl:MiddleTrim.Lead="{Binding BaseHeaderLead}" ctl:MiddleTrim.Text="{Binding BaseHeader}">
|
||
<TextBlock.ContextMenu>
|
||
<ContextMenu>
|
||
<MenuItem Header="전체 경로 복사" Click="CopyBasePath_Click"/>
|
||
</ContextMenu>
|
||
</TextBlock.ContextMenu>
|
||
</TextBlock>
|
||
</StackPanel>
|
||
|
||
<!-- 코드 칸을 제 자리 밖으로 못 나가게 자른다. 표시층의 미세 보정은 배치가 아니라
|
||
그리기라 자르지 않으면 아래 바닥 글 위에 코드가 겹쳐 그려진다. -->
|
||
<Grid Grid.Row="1" ClipToBounds="True">
|
||
<ListBox x:Name="BaseLines" BorderThickness="0" Background="Transparent"
|
||
SelectedItem="{Binding SelectedLine, Mode=OneWay}" SelectionChanged="PaneLines_SelectionChanged"
|
||
ItemTemplate="{StaticResource BaseLineTemplate}"
|
||
ItemContainerStyle="{StaticResource CodeLineItem}"
|
||
VirtualizingPanel.ScrollUnit="Pixel"
|
||
HorizontalContentAlignment="Stretch"
|
||
ScrollViewer.VerticalScrollBarVisibility="Visible"
|
||
ScrollViewer.HorizontalScrollBarVisibility="{Binding SourceBars,
|
||
RelativeSource={RelativeSource AncestorType=UserControl}}"
|
||
ScrollViewer.ScrollChanged="Lines_ScrollChanged"/>
|
||
</Grid>
|
||
|
||
<!--
|
||
원본 칸의 가로 스크롤 막대. 3-Way 에서 워드랩을 끄고 긴 줄이 있을 때만 보인다.
|
||
|
||
ScrollViewer 가 만들어 주는 막대를 쓰지 못하는 이유가 있다 - 이 칸들은
|
||
ScrollViewer 를 가로로 굴리지 않고(줄 번호까지 밀려 나가고 세 칸이 어긋난다)
|
||
글자만 SourceShiftX 로 민다. 그래서 그 막대는 <b>움직이지 않는 막대</b>가 된다.
|
||
세 칸은 늘 같이 움직이므로 세 막대의 손잡이도 같은 자리에 있다.
|
||
-->
|
||
<ScrollBar Grid.Row="2" Orientation="Horizontal" Height="14"
|
||
Minimum="0" SmallChange="24"
|
||
LargeChange="{Binding SourceViewport, RelativeSource={RelativeSource AncestorType=UserControl}}"
|
||
Maximum="{Binding SourceScrollMax, RelativeSource={RelativeSource AncestorType=UserControl}}"
|
||
ViewportSize="{Binding SourceViewport, RelativeSource={RelativeSource AncestorType=UserControl}}"
|
||
Value="{Binding SourceScrollValue, Mode=TwoWay, RelativeSource={RelativeSource AncestorType=UserControl}}"
|
||
Visibility="{Binding SourceBarVisibility, RelativeSource={RelativeSource AncestorType=UserControl}}"/>
|
||
|
||
<!-- Diff 요약도 아래 한 줄로 갔다(4차 C-2). 같은 숫자가 세 군데 있었다.
|
||
칸마다의 요약은 아래 한 줄에 따로 적는다(12차 B-3) - 파일 전체 요약과 다른 값이다. -->
|
||
|
||
<!-- 12차 B-3: 이 칸이 저쪽과 무엇이 다른가. 맨 아래 상태 줄의 "파일 전체" 와 다른 값이다. -->
|
||
<Border Grid.Row="3" Padding="8,3" BorderThickness="0,1,0,0"
|
||
BorderBrush="{DynamicResource Ubisam.Brush.Input.Border}"
|
||
Background="{DynamicResource Ubisam.Brush.Sidebar.Background}">
|
||
<TextBlock x:Name="BaseSummaryText" Text="{Binding BaseSummary}" FontSize="11"
|
||
TextTrimming="CharacterEllipsis"
|
||
Foreground="{DynamicResource Ubisam.Brush.Muted}"/>
|
||
</Border>
|
||
</Grid>
|
||
</Border>
|
||
|
||
<!-- 칸 사이 틈 전체가 구분선이다(11차 F-10). 바탕은 비워 두고 잇는 선은 LinkOverlay 가 그 위에 그린다. -->
|
||
<GridSplitter Grid.Column="3" Grid.Row="0" HorizontalAlignment="Stretch" DragCompleted="PaneSplitter_DragCompleted"
|
||
Background="Transparent"/>
|
||
|
||
<!--
|
||
③ LOCAL(2-Way) = MERGED(3-Way).
|
||
실제로 고치고 저장하는 칸은 언제나 여기 하나다. 3-Way 에서는 아래 줄로 내려가
|
||
폭 전체를 쓰고, 위 세 칸(LOCAL 원본 · BASE · REMOTE)은 읽기 전용 참고가 된다.
|
||
-->
|
||
<Border BorderThickness="1"
|
||
BorderBrush="{DynamicResource Ubisam.Brush.Input.Border}"
|
||
Background="{Binding (TextElement.Foreground), RelativeSource={RelativeSource Self}, Converter={StaticResource PaneBackground}}">
|
||
<Border.Style>
|
||
<Style TargetType="Border">
|
||
<Setter Property="Grid.Row" Value="0"/>
|
||
<Setter Property="Grid.Column" Value="4"/>
|
||
<Setter Property="Grid.ColumnSpan" Value="1"/>
|
||
<Style.Triggers>
|
||
<DataTrigger Binding="{Binding IsThreeWay}" Value="True">
|
||
<Setter Property="Grid.Row" Value="2"/>
|
||
<Setter Property="Grid.Column" Value="2"/>
|
||
<Setter Property="Grid.ColumnSpan" Value="5"/>
|
||
</DataTrigger>
|
||
</Style.Triggers>
|
||
</Style>
|
||
</Border.Style>
|
||
<!-- 칸 밖으로 그려지지 않게 자른다. 표시층은 RenderTransform 으로 살짝 밀어 놓는데,
|
||
그건 배치가 아니라 그리기라 자르지 않으면 <b>아래 상태바 위에 코드가 겹쳐 그려진다.</b>
|
||
차이로 이동(Alt+↑↓)할 때 실제로 그렇게 보였다. -->
|
||
<Grid ClipToBounds="True">
|
||
<Grid.RowDefinitions>
|
||
<RowDefinition x:Name="MergedHeaderRow" Height="Auto"/>
|
||
<RowDefinition Height="*"/>
|
||
<RowDefinition Height="Auto"/>
|
||
</Grid.RowDefinitions>
|
||
|
||
<!--
|
||
BASE 와 같은 높이. 두 패널의 줄이 정확히 같은 눈높이에 오도록 맞춘다.
|
||
|
||
"전체 반영 / 전체 되돌리기" 는 여기 있다가 ACTIONS 로 옮겼다.
|
||
이쪽에만 버튼 줄이 하나 더 있으면 그만큼 경로 줄이 아래로 밀려
|
||
BASE 의 경로와 높이가 어긋난다. 어차피 줄 단위 반영·되돌리기 버튼이
|
||
ACTIONS 에 있으니 같은 성격끼리 한자리에 모이는 편이 낫기도 하다.
|
||
-->
|
||
<StackPanel Grid.Row="0" Margin="8,6">
|
||
<TextBlock Text="{Binding LocalTitle}" Style="{StaticResource PanelTitle}"/>
|
||
<!-- BASE 와 같은 처리(4차 C-1). 전체 경로는 툴팁, 복사는 우클릭 메뉴. -->
|
||
<TextBlock FontFamily="Consolas" FontSize="12" Margin="0,1,0,0"
|
||
TextTrimming="CharacterEllipsis"
|
||
Foreground="{DynamicResource Ubisam.Brush.ContentForeground}"
|
||
ToolTip="{Binding SelectedFileFullPath}"
|
||
ctl:MiddleTrim.Lead="{Binding LocalHeaderLead}" ctl:MiddleTrim.Text="{Binding LocalHeader}">
|
||
<TextBlock.ContextMenu>
|
||
<ContextMenu>
|
||
<MenuItem Header="전체 경로 복사" Click="CopyLocalPath_Click"/>
|
||
</ContextMenu>
|
||
</TextBlock.ContextMenu>
|
||
</TextBlock>
|
||
</StackPanel>
|
||
|
||
<!-- 코드 칸을 제 자리 밖으로 못 나가게 자른다 - 표시층 보정은 그리기라 자르지 않으면 바닥 글 위에 겹친다. -->
|
||
<Grid Grid.Row="1" ClipToBounds="True">
|
||
<Grid.ColumnDefinitions>
|
||
<ColumnDefinition Width="*"/>
|
||
<ColumnDefinition Width="Auto"/>
|
||
</Grid.ColumnDefinitions>
|
||
|
||
<!--
|
||
아래층은 여백과 색·문법을 그리는 표시용, 위층은 실제로 글자를 고치는 편집기다.
|
||
편집기 글자는 투명이라 아래층 색이 그대로 보이고, 캐럿·선택 영역만 편집기가 그린다.
|
||
둘의 글꼴·줄 높이가 정확히 같아야 어긋나지 않는다.
|
||
|
||
편집기는 여백 폭(66)만큼 왼쪽을 비워 두어, 그 자리의 [>] 버튼과
|
||
북마크 더블클릭이 아래층까지 닿게 한다.
|
||
-->
|
||
<Grid Grid.Column="0">
|
||
<ListBox x:Name="LocalLines" BorderThickness="0" Background="Transparent"
|
||
SelectedItem="{Binding SelectedLine, Mode=OneWay}" SelectionChanged="PaneLines_SelectionChanged"
|
||
ItemTemplate="{StaticResource LocalLineTemplate}"
|
||
ItemContainerStyle="{StaticResource CodeLineItem}"
|
||
VirtualizingPanel.ScrollUnit="Pixel"
|
||
HorizontalContentAlignment="Stretch"
|
||
ScrollViewer.VerticalScrollBarVisibility="Hidden"
|
||
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
|
||
ScrollViewer.ScrollChanged="Lines_ScrollChanged"/>
|
||
|
||
<!--
|
||
Style="{x:Null}" 이 중요하다. 플랫폼의 암시적 TextBox 스타일은
|
||
템플릿 안에서 배경을 직접 칠해서(TemplateBinding 아님) 여기서 준
|
||
Background="Transparent" 가 무시되고, 아래층 표시가 덮여 안 보인다.
|
||
|
||
세로 스크롤 막대를 늘 띄워 두는 이유 - 나타났다 사라지면 글 너비가 바뀌어
|
||
워드랩 접히는 자리가 아래층과 어긋난다.
|
||
-->
|
||
<!--
|
||
IsUndoEnabled="False" - 12차 G-1 "undo 가 계속 이어진다".
|
||
|
||
Ctrl+Z 는 우리 목록(_undo · _textUndo)이 비면 <b>키를 먹지 않는다</b>
|
||
(RunShortcut - 그래야 글자 되돌리기가 살아 있다는 뜻이었다). 그러면 그 키가
|
||
TextBox 자체 되돌리기로 넘어가는데, WPF 의 그것은 한도가 없고 <b>프로그램이
|
||
코드로 넣은 글까지</b> 기록한다. 그래서 짝을 바꿔 새 파일을 실으면 그 글도 기록에
|
||
쌓이고, Ctrl+Z 가 <b>앞 파일 글을 편집기에 되살렸다.</b>
|
||
|
||
거기서 끝이 아니다. 되살아난 앞 파일 글을 Reflow 가 "사용자가 친 것"으로 보고
|
||
모델을 그쪽으로 되돌리며 되돌리기에 다시 쌓고 다시하기를 지운다. 다음 Ctrl+Z 는
|
||
우리 목록으로 되돌리고, 그러면 또 TextBox 것이 되살리고 - <b>두 상태를 끝없이
|
||
오간다.</b> 실측: 짝 A(234자) ↔ 짝 B(228자) 를 40번을 눌러도 안 끝났다.
|
||
|
||
자체 되돌리기를 끄면 그 고리가 통째로 사라진다. 되돌리기는 우리 목록만 쓴다 -
|
||
줄 단위(_undo)와 글 단위(_textUndo, 타이핑이 멈출 때마다 한 걸음).
|
||
-->
|
||
<TextBox x:Name="LocalEditor" Style="{x:Null}" Margin="{DynamicResource EditorGutterMargin}"
|
||
IsUndoEnabled="False"
|
||
FontFamily="Consolas" FontSize="{DynamicResource CodeFontSize}"
|
||
TextBlock.LineHeight="{DynamicResource CodeLineHeight}"
|
||
TextBlock.LineStackingStrategy="BlockLineHeight"
|
||
AcceptsReturn="True" AcceptsTab="True"
|
||
TextWrapping="{Binding WrapMode,
|
||
RelativeSource={RelativeSource AncestorType=UserControl}}"
|
||
Background="Transparent" BorderThickness="0" Padding="2,0,0,0"
|
||
Foreground="Transparent" SelectionTextBrush="Transparent"
|
||
CaretBrush="{DynamicResource Ubisam.Brush.ContentForeground}"
|
||
SelectionBrush="{DynamicResource Ubisam.Brush.Accent}"
|
||
SelectionOpacity="0.35"
|
||
VerticalContentAlignment="Top"
|
||
VerticalScrollBarVisibility="Visible"
|
||
HorizontalScrollBarVisibility="{Binding HorizontalBars,
|
||
RelativeSource={RelativeSource AncestorType=UserControl}}"
|
||
IsReadOnly="{Binding IsReadOnly}"
|
||
SelectionChanged="LocalEditor_SelectionChanged"
|
||
TextChanged="LocalEditor_TextChanged"/>
|
||
|
||
<!--
|
||
찾기 칸. 편집기 위에 떠 있게 둔다 - 패널 머리나 바닥에 끼워 넣으면
|
||
열 때마다 BASE 와 높이가 어긋나 두 패널의 같은 행이 다른 눈높이로 간다.
|
||
-->
|
||
<Border x:Name="FindBar" Visibility="Collapsed"
|
||
HorizontalAlignment="Right" VerticalAlignment="Top"
|
||
Margin="0,4,20,0" Padding="6,4" CornerRadius="3"
|
||
Background="{DynamicResource Ubisam.Brush.Input.Background}"
|
||
BorderBrush="{DynamicResource Ubisam.Brush.Accent}" BorderThickness="1"
|
||
Effect="{DynamicResource Ubisam.Effect.Popup}">
|
||
<StackPanel>
|
||
<StackPanel Orientation="Horizontal">
|
||
<TextBox x:Name="FindBox" Width="180" Height="24" MinHeight="24"
|
||
FontSize="11" VerticalContentAlignment="Center"
|
||
KeyDown="FindBox_KeyDown"
|
||
ToolTip="찾을 말 (Enter 다음 · Shift+Enter 이전 · Esc 닫기)"/>
|
||
|
||
<TextBlock x:Name="FindStatus" Style="{StaticResource Muted}" FontSize="11"
|
||
VerticalAlignment="Center" Margin="6,0,2,0" MinWidth="42"/>
|
||
|
||
<Button Content="▲" Click="FindPrev_Click" Padding="6,0" MinHeight="24"
|
||
FontSize="10" ToolTip="이전 찾기 (Shift+F3)"/>
|
||
<Button Content="▼" Click="FindNext_Click" Padding="6,0" MinHeight="24"
|
||
FontSize="10" Margin="2,0,6,0" ToolTip="다음 찾기 (F3)"/>
|
||
|
||
<CheckBox x:Name="FindMatchCase" Content="Aa" FontSize="11"
|
||
VerticalAlignment="Center" Margin="0,0,6,0"
|
||
ToolTip="대소문자를 가려서 찾습니다"/>
|
||
|
||
<Button Content="✕" Click="CloseFind_Click" Padding="6,0" MinHeight="24"
|
||
FontSize="10" Background="Transparent" BorderThickness="0"
|
||
ToolTip="닫기 (Esc)"/>
|
||
</StackPanel>
|
||
|
||
<!-- 바꾸기 줄은 Ctrl+H 로 열 때만 뜬다. 찾기만 할 때 자리를 뺏지 않는다. -->
|
||
<StackPanel x:Name="ReplaceRow" Orientation="Horizontal" Margin="0,4,0,0"
|
||
Visibility="Collapsed">
|
||
<TextBox x:Name="ReplaceBox" Width="180" Height="24" MinHeight="24"
|
||
FontSize="11" VerticalContentAlignment="Center"
|
||
ToolTip="바꿀 말"/>
|
||
<Button Content="바꾸기" Click="Replace_Click" Padding="8,0" MinHeight="24"
|
||
FontSize="11" Margin="6,0,2,0"
|
||
ToolTip="고른 자리를 바꾸고 다음으로 넘어갑니다"/>
|
||
<Button Content="모두" Click="ReplaceAll_Click" Padding="8,0" MinHeight="24"
|
||
FontSize="11"
|
||
ToolTip="글 전체에서 한 번에 바꿉니다 (Ctrl+Z 로 되돌립니다)"/>
|
||
</StackPanel>
|
||
</StackPanel>
|
||
|
||
</Border>
|
||
</Grid>
|
||
|
||
<!-- 목업 ③ 코드 미니맵 -->
|
||
<ctl:ChangeMiniMap Grid.Column="1" x:Name="MiniMap"
|
||
Source="{Binding Lines}"
|
||
Version="{Binding DiffVersion}"
|
||
SelectedLine="{Binding SelectedLine}"
|
||
LineRequested="MiniMap_LineRequested"/>
|
||
</Grid>
|
||
|
||
<!-- 상태바는 창 아래 한 줄로 옮겼다(4차 C-2). 두 패널이 같은 높이를 갖게 된다.
|
||
칸마다의 요약만 여기 한 줄로 적는다(12차 B-3). -->
|
||
|
||
<!-- 12차 B-3: 이 칸이 저쪽과 무엇이 다른가. 맨 아래 상태 줄의 "파일 전체" 와 다른 값이다. -->
|
||
<Border Grid.Row="2" Padding="8,3" BorderThickness="0,1,0,0"
|
||
BorderBrush="{DynamicResource Ubisam.Brush.Input.Border}"
|
||
Background="{DynamicResource Ubisam.Brush.Sidebar.Background}">
|
||
<TextBlock x:Name="LocalSummaryText" Text="{Binding LocalSummary}" FontSize="11"
|
||
TextTrimming="CharacterEllipsis"
|
||
Foreground="{DynamicResource Ubisam.Brush.Muted}"/>
|
||
</Border>
|
||
</Grid>
|
||
</Border>
|
||
|
||
<GridSplitter Grid.Column="5" Grid.Row="0" HorizontalAlignment="Stretch" DragCompleted="PaneSplitter_DragCompleted"
|
||
Visibility="{Binding IsThreeWay, Converter={StaticResource BoolToVis}}"
|
||
Background="Transparent"/>
|
||
|
||
<!--
|
||
③-2 REMOTE (3-Way). 머리·바닥 높이를 BASE/LOCAL 과 똑같이 맞춰야
|
||
세 패널의 같은 행이 같은 눈높이에 온다.
|
||
-->
|
||
<Border Grid.Column="6" Grid.Row="0" BorderThickness="1"
|
||
Visibility="{Binding IsThreeWay, Converter={StaticResource BoolToVis}}"
|
||
BorderBrush="{DynamicResource Ubisam.Brush.Input.Border}"
|
||
Background="{Binding (TextElement.Foreground), RelativeSource={RelativeSource Self}, Converter={StaticResource PaneBackground}}">
|
||
<!-- 칸 밖으로 그려지지 않게 자른다. 표시층은 RenderTransform 으로 살짝 밀어 놓는데,
|
||
그건 배치가 아니라 그리기라 자르지 않으면 <b>아래 상태바 위에 코드가 겹쳐 그려진다.</b>
|
||
차이로 이동(Alt+↑↓)할 때 실제로 그렇게 보였다. -->
|
||
<Grid ClipToBounds="True">
|
||
<Grid.RowDefinitions>
|
||
<RowDefinition Height="Auto" SharedSizeGroup="PaneHeader"/>
|
||
<RowDefinition Height="*"/>
|
||
<RowDefinition Height="Auto"/>
|
||
<!-- 12차 B-3: 칸 아래 한 줄 요약 -->
|
||
<RowDefinition Height="Auto"/>
|
||
</Grid.RowDefinitions>
|
||
|
||
<!-- BASE/LOCAL 과 같은 머리 높이. 세 패널의 01행이 같은 눈높이에 와야 한다.
|
||
RowDefinition 이 아니라 StackPanel 에 거는 이유 - 리소스가 Double 이라
|
||
GridLength 자리에 넣으면 화면을 만들 때 그대로 터진다. -->
|
||
<StackPanel Grid.Row="0" Margin="8,6">
|
||
<TextBlock Text="REMOTE(Theirs)" Style="{StaticResource PanelTitle}"/>
|
||
<!-- 상대 쪽 · 파일(11차 F-1). 큰 제목이 REMOTE 라고 말하므로 "REMOTE · " 를 되풀이하지 않는다. -->
|
||
<TextBlock ctl:MiddleTrim.Text="{Binding RemoteHeader}" ToolTip="{Binding RemoteHeader}"
|
||
FontFamily="Consolas" FontSize="12" Margin="0,1,0,0"
|
||
TextTrimming="CharacterEllipsis"
|
||
Foreground="{DynamicResource Ubisam.Brush.ContentForeground}"/>
|
||
|
||
<StackPanel Orientation="Horizontal" Margin="0,4,0,0">
|
||
<TextBlock Text="{Binding ConflictCount, StringFormat=Conflict {0}}"
|
||
FontSize="11" FontWeight="Bold"
|
||
Foreground="{DynamicResource Ubisam.Brush.Danger}"/>
|
||
<TextBlock Text=" · " Style="{StaticResource Muted}" FontSize="11"/>
|
||
<TextBlock Text="{Binding RemoteChangeCount, StringFormat=Theirs only {0}}"
|
||
Style="{StaticResource Muted}" FontSize="11"/>
|
||
</StackPanel>
|
||
</StackPanel>
|
||
|
||
<!-- 코드 칸을 제 자리 밖으로 못 나가게 자른다. 표시층의 미세 보정은 배치가 아니라
|
||
그리기라 자르지 않으면 아래 바닥 글 위에 코드가 겹쳐 그려진다. -->
|
||
<Grid Grid.Row="1" ClipToBounds="True">
|
||
<ListBox x:Name="RemoteLines" BorderThickness="0" Background="Transparent"
|
||
SelectedItem="{Binding SelectedLine, Mode=OneWay}" SelectionChanged="PaneLines_SelectionChanged"
|
||
ItemTemplate="{StaticResource RemoteLineTemplate}"
|
||
ItemContainerStyle="{StaticResource CodeLineItem}"
|
||
VirtualizingPanel.ScrollUnit="Pixel"
|
||
HorizontalContentAlignment="Stretch"
|
||
ScrollViewer.VerticalScrollBarVisibility="Visible"
|
||
ScrollViewer.HorizontalScrollBarVisibility="{Binding SourceBars,
|
||
RelativeSource={RelativeSource AncestorType=UserControl}}"
|
||
ScrollViewer.ScrollChanged="Lines_ScrollChanged"/>
|
||
</Grid>
|
||
|
||
<!--
|
||
원본 칸의 가로 스크롤 막대. 3-Way 에서 워드랩을 끄고 긴 줄이 있을 때만 보인다.
|
||
|
||
ScrollViewer 가 만들어 주는 막대를 쓰지 못하는 이유가 있다 - 이 칸들은
|
||
ScrollViewer 를 가로로 굴리지 않고(줄 번호까지 밀려 나가고 세 칸이 어긋난다)
|
||
글자만 SourceShiftX 로 민다. 그래서 그 막대는 <b>움직이지 않는 막대</b>가 된다.
|
||
세 칸은 늘 같이 움직이므로 세 막대의 손잡이도 같은 자리에 있다.
|
||
-->
|
||
<ScrollBar Grid.Row="2" Orientation="Horizontal" Height="14"
|
||
Minimum="0" SmallChange="24"
|
||
LargeChange="{Binding SourceViewport, RelativeSource={RelativeSource AncestorType=UserControl}}"
|
||
Maximum="{Binding SourceScrollMax, RelativeSource={RelativeSource AncestorType=UserControl}}"
|
||
ViewportSize="{Binding SourceViewport, RelativeSource={RelativeSource AncestorType=UserControl}}"
|
||
Value="{Binding SourceScrollValue, Mode=TwoWay, RelativeSource={RelativeSource AncestorType=UserControl}}"
|
||
Visibility="{Binding SourceBarVisibility, RelativeSource={RelativeSource AncestorType=UserControl}}"/>
|
||
|
||
<Border Grid.Row="2" Padding="8,5" BorderThickness="0,1,0,0"
|
||
Height="{StaticResource PaneFooterHeight}"
|
||
Visibility="{Binding IsTwoWay, Converter={StaticResource BoolToVis}}"
|
||
BorderBrush="{DynamicResource Ubisam.Brush.Input.Border}">
|
||
<StackPanel VerticalAlignment="Center">
|
||
<TextBlock Text="저쪽 변경" Style="{StaticResource Muted}" FontSize="11"/>
|
||
<TextBlock FontSize="11">
|
||
<Run Text="{Binding RemoteChangeCount, Mode=OneWay}"/>
|
||
<Run Text="줄은 받아들이기만 하면 됩니다"/>
|
||
</TextBlock>
|
||
</StackPanel>
|
||
</Border>
|
||
|
||
<!-- 12차 B-3: 이 칸이 저쪽과 무엇이 다른가. 맨 아래 상태 줄의 "파일 전체" 와 다른 값이다. -->
|
||
<Border Grid.Row="3" Padding="8,3" BorderThickness="0,1,0,0"
|
||
BorderBrush="{DynamicResource Ubisam.Brush.Input.Border}"
|
||
Background="{DynamicResource Ubisam.Brush.Sidebar.Background}">
|
||
<TextBlock x:Name="RemoteSummaryText" Text="{Binding RemoteSummary}" FontSize="11"
|
||
TextTrimming="CharacterEllipsis"
|
||
Foreground="{DynamicResource Ubisam.Brush.Muted}"/>
|
||
</Border>
|
||
</Grid>
|
||
</Border>
|
||
|
||
<!-- 원본 세 칸과 결과 칸 사이. 3-Way 일 때만 자리를 차지한다. -->
|
||
<GridSplitter Grid.Row="1" Grid.Column="2" Grid.ColumnSpan="5"
|
||
Height="4" VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
|
||
Visibility="{Binding IsThreeWay, Converter={StaticResource BoolToVis}}"
|
||
Background="{DynamicResource Ubisam.Brush.Table.GridLine}"/>
|
||
|
||
<!--
|
||
12차 B-3: 가운데(칸 사이 틈) 아래에 진행을 적는다.
|
||
틈이 48 DIP 뿐이라 두 줄로 짧게 - "3 / 7"(몇 번째 차이) 과 "남은 2"(아직 다른 줄 수).
|
||
잇는 선 그림판보다 앞에 두어 선에 가리지 않게 한다.
|
||
-->
|
||
<StackPanel Grid.Row="0" Grid.Column="3" VerticalAlignment="Bottom" HorizontalAlignment="Center"
|
||
Margin="0,0,0,6" Panel.ZIndex="6" IsHitTestVisible="False">
|
||
<TextBlock x:Name="DiffProgressText" Text="{Binding DiffProgress}" FontSize="11" FontWeight="Bold"
|
||
HorizontalAlignment="Center"
|
||
Foreground="{DynamicResource Ubisam.Brush.ContentForeground}"/>
|
||
<TextBlock x:Name="DiffRemainingText" Text="{Binding DiffRemaining}" FontSize="10"
|
||
HorizontalAlignment="Center"
|
||
Foreground="{DynamicResource Ubisam.Brush.Muted}"/>
|
||
</StackPanel>
|
||
|
||
<!-- 잇는 선(11차 F-10). 위 칸들 위에 겹친 투명한 그림판 - 마우스는 통과한다. -->
|
||
<ctl:PaneLinkOverlay x:Name="LinkOverlay" Grid.Row="0" Grid.Column="2" Grid.ColumnSpan="5" Panel.ZIndex="5"/>
|
||
|
||
<GridSplitter x:Name="ActionsSplitter" Grid.Column="7" Grid.RowSpan="3" Width="4" HorizontalAlignment="Stretch" DragCompleted="PaneSplitter_DragCompleted"
|
||
Background="{DynamicResource Ubisam.Brush.Table.GridLine}"/>
|
||
|
||
<!-- ④ ACTIONS -->
|
||
<Border x:Name="ActionsPanel" Grid.Column="8" Grid.RowSpan="3" BorderThickness="1" Padding="8"
|
||
BorderBrush="{DynamicResource Ubisam.Brush.Input.Border}">
|
||
<DockPanel>
|
||
<!-- 설정 "저장할 때 백업" 을 켰을 때만(11차 F-9). 맨 아래 - 저장 단추들 밑. -->
|
||
<Button DockPanel.Dock="Bottom" Content="백업 폴더 열기" Margin="0,6,0,0" FontSize="11"
|
||
Command="{Binding OpenBackupFolderCommand}"
|
||
Visibility="{Binding IsBackupOn, Converter={StaticResource BoolToVis}}"
|
||
ToolTip="저장할 때 남긴 백업을 모아 둔 폴더를 엽니다. 날짜 폴더마다 목록.txt 에 원본과 백업이 적혀 있습니다"/>
|
||
|
||
<!-- 왼쪽 파일에 쓰는 단추(12차 B-1). 두 파일 비교에서만 보이고, 왼쪽에 고친 것이 없으면 꺼진다. -->
|
||
<Button DockPanel.Dock="Bottom" Content="◀ 왼쪽 저장" MinHeight="32" Margin="0,8,0,0" FontSize="11"
|
||
Command="{Binding SaveLeftPlainCommand}"
|
||
Visibility="{Binding BothWays, Converter={StaticResource BoolToVis}}"
|
||
ToolTip="왼쪽으로 반영한 내용을 왼쪽 파일에 씁니다"/>
|
||
|
||
<!-- Git 이 아니면 커밋할 곳이 없다. 파일에 쓰기만 한다. -->
|
||
<Button DockPanel.Dock="Bottom" Content="오른쪽 저장 ▶" MinHeight="38" Margin="0,8,0,0"
|
||
Command="{Binding SavePlainCommand}"
|
||
Visibility="{Binding IsPlainMode, Converter={StaticResource BoolToVis}}"
|
||
Style="{StaticResource FilledButton}"
|
||
Background="{DynamicResource Ubisam.Brush.Success}"
|
||
Foreground="{DynamicResource Ubisam.Brush.Accent.OnFill}"
|
||
FontWeight="Bold"
|
||
ToolTip="고친 내용을 오른쪽 파일에 씁니다"/>
|
||
|
||
<Button DockPanel.Dock="Bottom" Content="Save & Commit" MinHeight="38" Margin="0,8,0,0"
|
||
Command="{Binding SaveAndCommitCommand}"
|
||
Visibility="{Binding IsGitMode, Converter={StaticResource BoolToVis}}"
|
||
Style="{StaticResource FilledButton}"
|
||
Background="{DynamicResource Ubisam.Brush.Success}"
|
||
Foreground="{DynamicResource Ubisam.Brush.Accent.OnFill}"
|
||
FontWeight="Bold"
|
||
ToolTip="LOCAL 내용을 파일에 쓰고 스테이징 후 커밋"/>
|
||
|
||
<!-- 병합 중에만 보인다. 이 파일만 풀어서 저장하고 커밋은 하지 않는다(6차 A-2).
|
||
Git 모드가 아니면 병합도 없으므로 바깥에서 한 번 더 가린다. -->
|
||
<StackPanel DockPanel.Dock="Bottom"
|
||
Visibility="{Binding IsGitMode, Converter={StaticResource BoolToVis}}">
|
||
<Button Content="Save" MinHeight="34" Margin="0,8,0,0"
|
||
Command="{Binding SaveResolvedCommand}"
|
||
Visibility="{Binding Workspace.IsMergeInProgress, Converter={StaticResource BoolToVis}}"
|
||
Style="{StaticResource FilledButton}"
|
||
FontWeight="Bold"
|
||
ToolTip="이 파일만 풀어서 저장하고 스테이징합니다. 커밋은 하지 않습니다 (Ctrl+S)"/>
|
||
</StackPanel>
|
||
|
||
<!-- 창이 낮거나 커밋 메시지가 길어지면 아래가 잘리므로 스크롤을 둔다. -->
|
||
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">
|
||
<StackPanel>
|
||
<TextBlock Text="ACTIONS" Style="{StaticResource Muted}" FontSize="11" Margin="0,0,0,4"/>
|
||
<UniformGrid Columns="2">
|
||
<Button Content="Undo" Command="{Binding UndoCommand}"/>
|
||
<Button Content="Redo" Command="{Binding RedoCommand}"/>
|
||
</UniformGrid>
|
||
|
||
<!-- LOCAL 머리에 있던 것을 옮겨 왔다. 줄 단위 반영과 성격이 같아 여기가 맞고,
|
||
옮긴 덕에 BASE 와 LOCAL 의 경로 줄 높이가 같아졌다. -->
|
||
<TextBlock Text="파일 전체" Style="{StaticResource Muted}" FontSize="11" Margin="0,12,0,4"/>
|
||
<!-- 두 칸으로 나누면 "전체 되돌리기" 글자가 잘린다. 한 줄에 하나씩 둔다. -->
|
||
<Button Content="전체 반영" Command="{Binding AcceptAllCommand}" MinHeight="28"
|
||
FontSize="11" ToolTipService.ShowOnDisabled="True"
|
||
ToolTip="차이나는 모든 줄을 BASE 내용으로 - 구간마다 주석 한 줄, Undo 한 번에 전체가 되돌아갑니다. 3-Way 에서는 쓰지 않습니다(저쪽만 고친 줄은 [자동 병합], 충돌은 한 줄씩)"/>
|
||
<Button Content="전체 되돌리기" Command="{Binding RevertAllCommand}" MinHeight="28"
|
||
FontSize="11" Margin="0,4,0,0" ToolTip="파일을 연 시점으로 되돌립니다"/>
|
||
|
||
<TextBlock Text="선택 라인 반영" Style="{StaticResource Muted}" FontSize="11" Margin="0,12,0,4"/>
|
||
<Button Content="Accept" Command="{Binding AcceptCommand}" MinHeight="30"
|
||
Style="{StaticResource FilledButton}"
|
||
Background="{DynamicResource Ubisam.Brush.Accent.Fill}"
|
||
Foreground="{DynamicResource Ubisam.Brush.Accent.OnFill}"
|
||
ToolTip="선택한 줄을 BASE 내용으로"/>
|
||
|
||
<!-- 3-Way 일 때만 뜬다. -->
|
||
<Button Content="Take Mine" Command="{Binding AcceptLocalCommand}"
|
||
MinHeight="30" Margin="2,4,2,0"
|
||
Visibility="{Binding IsThreeWay, Converter={StaticResource BoolToVis}}"
|
||
Style="{StaticResource FilledButton}"
|
||
Background="{DynamicResource Ubisam.Brush.Accent.Fill}"
|
||
Foreground="{DynamicResource Ubisam.Brush.Accent.OnFill}"
|
||
ToolTip="선택한 줄을 LOCAL(Mine) 내용으로"/>
|
||
|
||
<Button Content="Take Theirs" Command="{Binding AcceptRemoteCommand}"
|
||
MinHeight="30" Margin="2,4,2,0"
|
||
Visibility="{Binding IsThreeWay, Converter={StaticResource BoolToVis}}"
|
||
Style="{StaticResource FilledButton}"
|
||
Background="{DynamicResource Ubisam.Brush.Accent.Fill}"
|
||
Foreground="{DynamicResource Ubisam.Brush.Accent.OnFill}"
|
||
ToolTip="선택한 줄을 REMOTE(Theirs) 내용으로"/>
|
||
|
||
<Button Content="구간 반영" x:Name="AcceptBlockButton" Command="{Binding AcceptBlockCommand}"
|
||
MinHeight="30" Margin="2,4,2,0" FontSize="11"
|
||
ToolTip="차이가 이어지는 구간을 한 번에 반영합니다 (Alt+Shift+Right)"/>
|
||
|
||
<!-- 12차 G-2: 위 단추의 거울. 두 파일 비교(BothWays)에서만 뜬다 -
|
||
Git 모드의 왼쪽은 지난 커밋이라 쓸 파일이 없다. -->
|
||
<Button Content="구간 왼쪽으로" x:Name="AcceptBlockToBaseButton"
|
||
Command="{Binding AcceptBlockToBaseCommand}"
|
||
MinHeight="30" Margin="2,4,2,0" FontSize="11"
|
||
Visibility="{Binding BothWays, Converter={StaticResource BoolToVis}}"
|
||
ToolTip="차이가 이어지는 구간을 한 번에 왼쪽 파일로 보냅니다 (Alt+Shift+Left)"/>
|
||
|
||
<!-- 11차 F-2: 캐럿이 놓인 클래스 멤버를 통째로. 못 잡으면 꺼지고 아래 한 줄이 까닭을 말한다. -->
|
||
<Button Content="이 메서드 반영" Command="{Binding AcceptMemberCommand}"
|
||
MinHeight="30" Margin="2,4,2,0" FontSize="11"
|
||
ToolTipService.ShowOnDisabled="True"
|
||
ToolTip="{Binding MemberHint}"/>
|
||
<TextBlock Text="{Binding MemberHint}" Style="{StaticResource Muted}" FontSize="10"
|
||
Margin="4,2,2,0" TextWrapping="Wrap"/>
|
||
|
||
<!--
|
||
저장 형식. 기본은 "원본 유지"라 지금까지와 똑같이 나간다.
|
||
사내 소스에 CP949 가 섞여 있어, 새로 만드는 파일과 형식이 갈릴 때 여기서 맞춘다.
|
||
-->
|
||
<!--
|
||
한 번 정하면 그대로인 것들은 접어 둔다(4차 C-5).
|
||
매번 쓰는 것(반영 · 되돌리기 · 차이 이동 · 저장)과 섞여 있어 오른쪽 칸이 길었다.
|
||
단추 글자가 무엇이 숨어 있는지 말한다 - 화살표만으로는 전해지지 않는다(C-3 · C-4).
|
||
-->
|
||
|
||
|
||
|
||
<!--
|
||
3-Way 흐름. "안 겹치는 변경은 자동으로, 사람은 충돌만" 이 순서다.
|
||
남은 충돌이 0 이 되면 그 자리에서 다 됐다고 알려 준다.
|
||
-->
|
||
<Border Margin="2,10,2,0" Padding="6,4" CornerRadius="3"
|
||
Visibility="{Binding IsThreeWay, Converter={StaticResource BoolToVis}}"
|
||
Background="{DynamicResource Ubisam.Brush.Input.Background}"
|
||
BorderBrush="{DynamicResource Ubisam.Brush.Input.Border}" BorderThickness="1">
|
||
<TextBlock Text="{Binding MergeStatusText}" FontWeight="Bold" FontSize="11.5"
|
||
HorizontalAlignment="Center"
|
||
ToolTip="아직 사람이 골라야 하는 줄 수입니다">
|
||
<TextBlock.Style>
|
||
<Style TargetType="TextBlock">
|
||
<Setter Property="Foreground" Value="{DynamicResource Ubisam.Brush.Danger}"/>
|
||
<Style.Triggers>
|
||
<DataTrigger Binding="{Binding IsMergeComplete}" Value="True">
|
||
<Setter Property="Foreground" Value="{DynamicResource Ubisam.Brush.Success}"/>
|
||
</DataTrigger>
|
||
</Style.Triggers>
|
||
</Style>
|
||
</TextBlock.Style>
|
||
</TextBlock>
|
||
</Border>
|
||
|
||
<Button Content="자동 병합" Command="{Binding AutoMergeCommand}"
|
||
MinHeight="30" Margin="2,4,2,0"
|
||
Visibility="{Binding IsThreeWay, Converter={StaticResource BoolToVis}}"
|
||
ToolTip="저쪽만 고친 줄을 한 번에 가져옵니다. 충돌과 내가 고친 줄은 건드리지 않습니다"/>
|
||
|
||
<UniformGrid Columns="2" Margin="0,4,0,0"
|
||
Visibility="{Binding IsThreeWay, Converter={StaticResource BoolToVis}}">
|
||
<Button Content="이전 충돌" Command="{Binding PrevConflictCommand}"
|
||
MinHeight="28" FontSize="11"
|
||
ToolTip="아직 안 정한 충돌만 딛습니다 (Alt+Shift+Up)"/>
|
||
<Button Content="다음 충돌" Command="{Binding NextConflictCommand}"
|
||
MinHeight="28" FontSize="11"
|
||
ToolTip="아직 안 정한 충돌만 딛습니다 (Alt+Shift+Down)"/>
|
||
</UniformGrid>
|
||
|
||
<Button Content="Revert" Command="{Binding RevertCommand}" MinHeight="30" Margin="2,4,2,0"
|
||
Style="{StaticResource FilledButton}"
|
||
Background="{DynamicResource Ubisam.Brush.Warning}"
|
||
Foreground="{DynamicResource Ubisam.Brush.Accent.OnFill}"
|
||
ToolTip="선택한 줄의 마지막 편집만 취소"/>
|
||
|
||
<!-- 머지 주석: 설명은 선택, 작성자·날짜는 항상 들어간다 -->
|
||
<TextBlock Text="머지 설명 (선택)" Style="{StaticResource Muted}" FontSize="11" Margin="0,12,0,4"/>
|
||
<TextBox Text="{Binding MergeComment, UpdateSourceTrigger=PropertyChanged}"
|
||
AcceptsReturn="False" MinHeight="24"
|
||
ToolTip="반영한 줄 끝에 주석으로 붙습니다. 비워두면 작성자·날짜만 들어갑니다."/>
|
||
<TextBlock Text="{Binding MergeNotePreview}" Style="{StaticResource Muted}"
|
||
FontSize="10" FontFamily="Consolas" TextWrapping="Wrap" Margin="0,3,0,0"
|
||
ToolTip="{Binding MergeNotePreview}"/>
|
||
|
||
<TextBlock Text="커밋 상세" Style="{StaticResource Muted}" FontSize="11" Margin="0,12,0,4"
|
||
Visibility="{Binding IsGitMode, Converter={StaticResource BoolToVis}}"/>
|
||
<Grid Visibility="{Binding IsGitMode, Converter={StaticResource BoolToVis}}">
|
||
<Grid.ColumnDefinitions>
|
||
<ColumnDefinition Width="Auto"/>
|
||
<ColumnDefinition Width="*"/>
|
||
</Grid.ColumnDefinitions>
|
||
<Grid.RowDefinitions>
|
||
<RowDefinition Height="Auto"/>
|
||
<RowDefinition Height="Auto"/>
|
||
<RowDefinition Height="Auto"/>
|
||
<RowDefinition Height="Auto"/>
|
||
</Grid.RowDefinitions>
|
||
<TextBlock Grid.Row="0" Grid.Column="0" Text="Hash" Style="{StaticResource Muted}" FontSize="11"/>
|
||
<TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding CommitHash}" FontFamily="Consolas"
|
||
FontSize="11" TextAlignment="Right"/>
|
||
<TextBlock Grid.Row="1" Grid.Column="0" Text="Date" Style="{StaticResource Muted}" FontSize="11"/>
|
||
<TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding CommitDate}" FontSize="11" TextAlignment="Right"/>
|
||
<TextBlock Grid.Row="2" Grid.Column="0" Text="Author" Style="{StaticResource Muted}" FontSize="11"/>
|
||
<TextBlock Grid.Row="2" Grid.Column="1" Text="{Binding CommitAuthor}" FontSize="11"
|
||
TextAlignment="Right" TextTrimming="CharacterEllipsis"/>
|
||
<TextBlock Grid.Row="3" Grid.Column="0" Text="Branch" Style="{StaticResource Muted}" FontSize="11"/>
|
||
<TextBlock Grid.Row="3" Grid.Column="1" Text="{Binding CommitBranch}" FontSize="11"
|
||
TextAlignment="Right" TextTrimming="CharacterEllipsis"/>
|
||
</Grid>
|
||
|
||
<TextBlock Text="커밋 메시지" Style="{StaticResource Muted}" FontSize="11" Margin="0,12,0,4"
|
||
Visibility="{Binding IsGitMode, Converter={StaticResource BoolToVis}}"/>
|
||
<TextBox Text="{Binding CommitMessage, UpdateSourceTrigger=PropertyChanged}"
|
||
AcceptsReturn="True" TextWrapping="Wrap" MinHeight="60"
|
||
Visibility="{Binding IsGitMode, Converter={StaticResource BoolToVis}}"
|
||
VerticalScrollBarVisibility="Auto"/>
|
||
|
||
<!--
|
||
차이 탐색과 비교 규칙. 코드 패널 위가 아니라 여기 둔 이유는,
|
||
읽는 자리(코드)와 조작하는 자리(오른쪽 패널)를 섞지 않기 위해서다.
|
||
-->
|
||
<TextBlock Text="차이 이동" Style="{StaticResource Muted}" FontSize="11" Margin="0,14,0,4"/>
|
||
<!-- 화살표 글리프는 이 서체에 없어 빈 칸으로 나온다. 글자로 적는다. -->
|
||
<UniformGrid Columns="2">
|
||
<Button Content="이전 차이" Command="{Binding PrevDiffCommand}" MinHeight="28" FontSize="11"
|
||
ToolTip="이전 차이 (Alt+Up)"/>
|
||
<Button Content="다음 차이" Command="{Binding NextDiffCommand}" MinHeight="28" FontSize="11"
|
||
ToolTip="다음 차이 (Alt+Down)"/>
|
||
<Button Content="처음" Command="{Binding FirstDiffCommand}" MinHeight="28" FontSize="11"
|
||
Margin="2,4,2,0" ToolTip="첫 차이 (Ctrl+Home)"/>
|
||
<Button Content="마지막" Command="{Binding LastDiffCommand}" MinHeight="28" FontSize="11"
|
||
Margin="2,4,2,0" ToolTip="마지막 차이 (Ctrl+End)"/>
|
||
</UniformGrid>
|
||
|
||
<Grid Margin="0,4,0,0">
|
||
<Grid.ColumnDefinitions>
|
||
<ColumnDefinition Width="Auto"/>
|
||
<ColumnDefinition Width="*"/>
|
||
</Grid.ColumnDefinitions>
|
||
<TextBlock Grid.Column="0" Text="이동" Style="{StaticResource Muted}"
|
||
FontSize="11" Margin="2,0,6,0"/>
|
||
<TextBox Grid.Column="1" x:Name="GoToBox" MinHeight="26" FontSize="11"
|
||
VerticalContentAlignment="Center"
|
||
Text="{Binding GoToText, UpdateSourceTrigger=PropertyChanged}"
|
||
KeyDown="GoToBox_KeyDown"
|
||
ToolTip="줄 번호로 이동 (Ctrl+G)"/>
|
||
</Grid>
|
||
|
||
<!--
|
||
여기서부터가 <b>한 번 정하면 그대로인 것들</b>이다(4차 C-5).
|
||
위쪽(반영 · 되돌리기 · 차이 이동 · 저장)과 성격이 달라 한자리에 모으고 접었다.
|
||
단추 글자가 무엇이 숨어 있는지 말한다 - 화살표만으로는 전해지지 않는다(C-3 · C-4).
|
||
-->
|
||
<Button Content="{Binding RulesToggleLabel}" Command="{Binding ToggleRulesCommand}"
|
||
MinHeight="26" FontSize="11" FontWeight="Bold" Margin="2,14,2,0"
|
||
Cursor="Hand"
|
||
Foreground="{DynamicResource Ubisam.Brush.Accent}"
|
||
ToolTip="저장 형식 · 비교 규칙 · 편집 잠금을 접거나 폅니다. 접힌 상태는 다음에 켤 때도 그대로입니다"/>
|
||
|
||
<TextBlock Text="저장 형식" Style="{StaticResource Muted}" FontSize="11" Margin="0,10,0,4"
|
||
Visibility="{Binding IsRulesOpen, Converter={StaticResource BoolToVis}}"/>
|
||
<UniformGrid Columns="2" Visibility="{Binding IsRulesOpen, Converter={StaticResource BoolToVis}}">
|
||
<!-- 12차 G-4: 보이는 글(Label)과 저장되는 값(Value)을 가른다. 값은 세션 보관본에 그대로 적힌다. -->
|
||
<ComboBox ItemsSource="{Binding SaveEncodings}" x:Name="SaveEncodingBox"
|
||
DisplayMemberPath="Label" SelectedValuePath="Value" SelectedValue="{Binding SaveEncoding}"
|
||
MinHeight="26" FontSize="11" Margin="2,0"
|
||
ToolTip="저장할 때 쓸 인코딩"/>
|
||
<ComboBox ItemsSource="{Binding SaveNewLines}" x:Name="SaveNewLineBox"
|
||
DisplayMemberPath="Label" SelectedValuePath="Value" SelectedValue="{Binding SaveNewLine}"
|
||
MinHeight="26" FontSize="11" Margin="2,0"
|
||
ToolTip="저장할 때 쓸 줄바꿈"/>
|
||
</UniformGrid>
|
||
|
||
<TextBlock Text="비교 규칙" Style="{StaticResource Muted}" FontSize="11" Margin="0,10,0,4"
|
||
Visibility="{Binding IsRulesOpen, Converter={StaticResource BoolToVis}}"/>
|
||
<UniformGrid Columns="2" Visibility="{Binding IsRulesOpen, Converter={StaticResource BoolToVis}}">
|
||
<Button Content="{Binding WhitespaceLabel}" Command="{Binding CycleWhitespaceCommand}"
|
||
MinHeight="28" FontSize="11"
|
||
ToolTip="공백을 얼마나 무시할지 - 전부 비교 → 개수만 무시 → 전부 무시"/>
|
||
<Button Content="{Binding IgnoreCaseLabel}" Command="{Binding ToggleIgnoreCaseCommand}"
|
||
MinHeight="28" FontSize="11"
|
||
ToolTip="대소문자만 다른 줄을 같게 볼지"/>
|
||
<Button Content="{Binding LineFilterLabel}" Command="{Binding ToggleLineFilterCommand}"
|
||
MinHeight="28" FontSize="11" Margin="2,4,2,0"
|
||
ToolTip="설정에 적어 둔 정규식에 걸리는 줄을 차이에서 뺍니다"/>
|
||
<Button Content="{Binding WrapLabel}" Click="ToggleWrap_Click"
|
||
MinHeight="28" FontSize="11" Margin="2,4,2,0"
|
||
ToolTip="긴 줄을 접어서 보여줍니다 (가로 스크롤 대신)"/>
|
||
</UniformGrid>
|
||
<!-- C# 코드 스타일 맞춤(6차 추가). 중괄호 줄바꿈만 달라 차이가 많이 뜨는 것을 막는다. -->
|
||
<ComboBox ItemsSource="{Binding CSharpStyleNames}" SelectedIndex="{Binding CSharpStyleIndex}"
|
||
MinHeight="26" FontSize="11" Margin="2,4,2,0"
|
||
Visibility="{Binding IsRulesOpen, Converter={StaticResource BoolToVis}}"
|
||
ToolTip="C# 파일의 여는 중괄호 · else/catch/finally 줄바꿈을 이 스타일로 맞춘 뒤 비교합니다.
AURORA: 형식 · 메서드 중괄호만 새 줄, 나머지는 같은 줄, } else {
Allman: 모두 새 줄 (Visual Studio 기본값)
편집 칸 글이 바뀌면 저장할 때 그 스타일로 저장됩니다."/>
|
||
<Button Content="{Binding ReadOnlyLabel}" Click="ToggleReadOnly_Click"
|
||
MinHeight="28" FontSize="11" Margin="2,4,2,0"
|
||
Visibility="{Binding IsRulesOpen, Converter={StaticResource BoolToVis}}"
|
||
ToolTip="실수로 고치는 것을 막습니다"/>
|
||
</StackPanel>
|
||
</ScrollViewer>
|
||
</DockPanel>
|
||
</Border>
|
||
</Grid>
|
||
|
||
<!--
|
||
④ 상태바 — 창 아래 한 줄.
|
||
|
||
<b>왜 옮겼나</b> - 예전에는 세 군데에 흩어져 있었다.
|
||
BASE 바닥의 "총 43 라인 · 차이 10 라인", MERGED 바닥 첫 줄의 "1행 1열 | 차이 -/5 | UTF-8",
|
||
그 아래 줄의 "편집 0건 · 되돌리기 0건 · 남은 차이 10 라인". 같은 뜻의 숫자가 세 벌이라
|
||
어느 것을 봐야 할지 헷갈렸고, 패널마다 54px 를 먹었다.
|
||
|
||
<b>자리 규칙</b> - 왼쪽은 지금 어디에 있는지, 가운데는 얼마나 남았는지, 오른쪽은 이 파일이 무엇인지.
|
||
패널 밖으로 나오면서 두 패널의 코드 영역 높이가 저절로 같아진다.
|
||
-->
|
||
<Border Grid.Row="3" Padding="8,4" BorderThickness="1,1,1,1" Margin="0,2,0,0"
|
||
Background="{DynamicResource Ubisam.Brush.Sidebar.Background}"
|
||
BorderBrush="{DynamicResource Ubisam.Brush.Input.Border}">
|
||
<Grid>
|
||
<Grid.ColumnDefinitions>
|
||
<ColumnDefinition Width="Auto"/>
|
||
<ColumnDefinition Width="*"/>
|
||
<ColumnDefinition Width="Auto"/>
|
||
</Grid.ColumnDefinitions>
|
||
|
||
<!-- 왼쪽: 지금 어디 -->
|
||
<StackPanel Grid.Column="0" Orientation="Horizontal" VerticalAlignment="Center">
|
||
<TextBlock Text="{Binding CaretPosition}" Style="{StaticResource Mono}" FontSize="11"/>
|
||
<!-- 11차 F-5: 기본(12)이 아닐 때만 보인다. 누르면 기본으로(Ctrl+0 과 같음). -->
|
||
<TextBlock Text="{Binding CodeFontLabel}" FontSize="11" Margin="10,0,0,0" Cursor="Hand"
|
||
Style="{StaticResource Muted}" ToolTip="코드 글자 크기 - Ctrl+휠 · Ctrl++/- 로 바꾸고, 누르거나 Ctrl+0 이면 기본(12)">
|
||
<TextBlock.InputBindings>
|
||
<MouseBinding MouseAction="LeftClick" Command="{Binding FontResetCommand}"/>
|
||
</TextBlock.InputBindings>
|
||
</TextBlock>
|
||
<Border Width="1" Margin="10,1" Background="{DynamicResource Ubisam.Brush.Input.Border}"/>
|
||
<!--
|
||
차이 이동을 개수 바로 옆에 둔다(4차 C-5).
|
||
가장 자주 누르는 것인데 오른쪽 칸 끝에 있었고, 정작 "몇 번째인지"는 여기 있었다.
|
||
보는 자리와 누르는 자리가 갈려 있으면 눈과 손이 따로 움직인다.
|
||
오른쪽 칸의 큰 단추는 그대로 둔다 - 쓰던 사람 손을 빼앗지 않는다.
|
||
-->
|
||
<Button Content="◀" Command="{Binding PrevDiffCommand}"
|
||
Style="{StaticResource LegendButton}" FontSize="11" FontWeight="Bold" Margin="6,0,0,0"
|
||
ToolTip="이전 차이 (Alt+Up)"/>
|
||
<TextBlock Text="{Binding DiffPosition}" FontSize="11" FontWeight="Bold" Margin="2,0"
|
||
Foreground="{DynamicResource Ubisam.Brush.Accent}"/>
|
||
<Button Content="▶" Command="{Binding NextDiffCommand}"
|
||
Style="{StaticResource LegendButton}" FontSize="11" FontWeight="Bold"
|
||
ToolTip="다음 차이 (Alt+Down)"/>
|
||
</StackPanel>
|
||
|
||
<!-- 가운데: 얼마나 남았나 -->
|
||
<StackPanel Grid.Column="1" Orientation="Horizontal" VerticalAlignment="Center"
|
||
Margin="14,0,14,0">
|
||
<TextBlock Text="{Binding DiffSummary}" FontSize="12" VerticalAlignment="Center"/>
|
||
<TextBlock Text="·" Style="{StaticResource Muted}" FontSize="11" Margin="6,0"
|
||
Visibility="{Binding EditSummary, Converter={StaticResource TextToVis}}"/>
|
||
<TextBlock Text="{Binding EditSummary}" FontSize="12" VerticalAlignment="Center"/>
|
||
</StackPanel>
|
||
|
||
<!-- 오른쪽: 이 파일이 무엇인가 -->
|
||
<StackPanel Grid.Column="2" Orientation="Horizontal" VerticalAlignment="Center">
|
||
<TextBlock Text="{Binding FileEncoding}" Style="{StaticResource Muted}" FontSize="11"/>
|
||
<TextBlock Text="·" Style="{StaticResource Muted}" FontSize="11" Margin="5,0"/>
|
||
<TextBlock Text="{Binding FileNewLine}" Style="{StaticResource Muted}" FontSize="11"/>
|
||
<TextBlock Text="·" Style="{StaticResource Muted}" FontSize="11" Margin="5,0"/>
|
||
<TextBlock Text="{Binding LanguageName}" Style="{StaticResource Muted}" FontSize="11"
|
||
ToolTip="확장자로 고른 언어입니다. 색칠과 코드 검사가 이 값을 따릅니다"/>
|
||
|
||
<Border Width="1" Margin="10,1" Background="{DynamicResource Ubisam.Brush.Input.Border}"
|
||
Visibility="{Binding RulesSummary, Converter={StaticResource TextToVis}}"/>
|
||
<TextBlock Text="{Binding RulesSummary}" FontSize="11"
|
||
Foreground="{DynamicResource Ubisam.Brush.Muted}"
|
||
Visibility="{Binding RulesSummary, Converter={StaticResource TextToVis}}"/>
|
||
|
||
<Border Width="1" Margin="10,1" Background="{DynamicResource Ubisam.Brush.Input.Border}"/>
|
||
<TextBlock Text="코드 검사" Style="{StaticResource Muted}" FontSize="11" Margin="0,0,6,0"/>
|
||
<ToggleButton x:Name="ProblemToggle" Padding="6,1" FontSize="11" FontWeight="Bold"
|
||
MinHeight="22" BorderThickness="0" Background="Transparent"
|
||
IsEnabled="{Binding HasProblems}"
|
||
ToolTip="눌러서 확인이 필요한 줄을 봅니다">
|
||
<ToggleButton.Style>
|
||
<Style TargetType="ToggleButton">
|
||
<Setter Property="Foreground" Value="{DynamicResource Ubisam.Brush.Success}"/>
|
||
<Setter Property="Cursor" Value="Arrow"/>
|
||
<Style.Triggers>
|
||
<DataTrigger Binding="{Binding HasProblems}" Value="True">
|
||
<Setter Property="Foreground" Value="{DynamicResource Ubisam.Brush.Danger}"/>
|
||
<Setter Property="Cursor" Value="Hand"/>
|
||
</DataTrigger>
|
||
</Style.Triggers>
|
||
</Style>
|
||
</ToggleButton.Style>
|
||
<TextBlock Text="{Binding ProblemSummary}"/>
|
||
</ToggleButton>
|
||
|
||
<Popup IsOpen="{Binding IsChecked, ElementName=ProblemToggle}"
|
||
PlacementTarget="{Binding ElementName=ProblemToggle}"
|
||
Placement="Top" StaysOpen="False" AllowsTransparency="True"
|
||
HorizontalOffset="-8" VerticalOffset="-4">
|
||
<Border Background="{DynamicResource Ubisam.Brush.Input.Background}"
|
||
BorderBrush="{DynamicResource Ubisam.Brush.Danger}"
|
||
BorderThickness="1" Padding="4" MaxWidth="620" MaxHeight="240"
|
||
Effect="{DynamicResource Ubisam.Effect.Popup}">
|
||
<ScrollViewer VerticalScrollBarVisibility="Auto">
|
||
<ItemsControl ItemsSource="{Binding Problems}">
|
||
<ItemsControl.ItemTemplate>
|
||
<DataTemplate>
|
||
<Button Command="{Binding DataContext.GoToProblemCommand,
|
||
RelativeSource={RelativeSource AncestorType=UserControl}}"
|
||
CommandParameter="{Binding}"
|
||
HorizontalContentAlignment="Left"
|
||
Background="Transparent" BorderThickness="0"
|
||
Padding="6,3" Margin="0"
|
||
ToolTip="누르면 그 줄로 이동합니다">
|
||
<StackPanel Orientation="Horizontal">
|
||
<TextBlock Text="{Binding Where}" FontFamily="Consolas"
|
||
FontSize="11" FontWeight="Bold" MinWidth="46"
|
||
Foreground="{DynamicResource Ubisam.Brush.Danger}"/>
|
||
<TextBlock Text="{Binding Message}" FontSize="11"
|
||
TextWrapping="Wrap" Margin="6,0,0,0"/>
|
||
</StackPanel>
|
||
</Button>
|
||
</DataTemplate>
|
||
</ItemsControl.ItemTemplate>
|
||
</ItemsControl>
|
||
</ScrollViewer>
|
||
</Border>
|
||
</Popup>
|
||
</StackPanel>
|
||
</Grid>
|
||
</Border>
|
||
</Grid>
|
||
</DockPanel>
|
||
</UserControl>
|