미리보기 툴바를 아이콘으로 — 버튼 여덟 개가 글자 벽이었다
인쇄… / 새로 고침 / 인쇄될 것만 / 환자 선택… / 환자 해제 / 데이터소스… / 누른 것 초기화 / - / 100% / + 가 전부 글자로 한 줄에 늘어서 있었다. 무엇이 명령이고 무엇이 상태인지 구분되지 않고, 이름이 긴 것들이 자리를 다 먹어 종이 위 툴바가 화면의 한 조각을 차지했다. 셸 제목줄의 아이콘 줄과 같은 규범으로 맞춘다 — 이름은 툴팁이 받는다. <b>글자로 남긴 것은 값과 상태뿐이다.</b> 고른 환자 이름과 배율 — 둘 다 아이콘으로 대신할 수 없는 정보다. ## 버튼 두 개를 하나로 합쳤다 '환자 선택'과 '환자 해제'가 나란히 있었다. 셸 제목줄은 같은 일을 아이콘 하나로 한다 — 안 골랐으면 바로 선택 창, 이미 골랐으면 바꾸기·해제 메뉴다. 늘 보이는 자리에서 '누르면 해제'로 두면 실수로 지운다는 것이 그 설계의 이유였고, 여기도 같은 자리다. 고른 상태는 아이콘 색으로 알린다. 안 고른 상태의 색을 <b>B.Muted 로 명시</b>했다 — null 을 넘기면 하드코딩 검정으로 칠해져 어두운 툴바에서 혼자 묻힌다(제목줄에서 실제로 겪은 결함이라 같은 실수를 반복하지 않는다). ## 아이콘은 실제로 있는 것만 골랐다 카탈로그에 없는 이름을 쓰면 조용히 대체 글리프로 떨어진다 — 쓰려던 refresh-cw · user-x · database · eraser 는 없어서 rotate-cw · table · undo-2 로 바꿨다(90종 중 실재하는 것만 확인해 썼다). '인쇄될 것만'은 토글이라 눌린 상태가 곧 '인쇄 기준'이라는 뜻이 된다 — 툴팁이 양쪽을 설명한다. ## 값을 치르는 것 글자가 사라져 처음 쓰는 사람은 툴팁을 한 번 훑어야 한다. 이 도구를 며칠에 한 번 쓰는 사용자에게는 실제 비용이다 — 다만 제목줄이 이미 같은 방식이라 규범이 하나로 모이는 쪽이 낫다고 봤다. ## 판정 - 단위 시험 388 · edit-smoke 405건 전건 통과 - --dialog-shots 69장 전건 통과 — 미리보기 툴바를 잘라 2배로 키워 다크·라이트 양쪽을 눈으로 확인 - --modal-check · --maxrect · --scale-budget 전건 통과 - --db-render P062 md5 8d683835f5d81e7bb41c79071d6bf954 불변 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
3e75bdc9b9
commit
592275fa97
@@ -1,55 +1,83 @@
|
|||||||
<Window x:Class="SheetMe.Designer.Views.PreviewWindow"
|
<Window x:Class="SheetMe.Designer.Views.PreviewWindow"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:ctl="clr-namespace:SheetMe.Designer.Controls"
|
||||||
Title="미리보기" Width="900" Height="1000"
|
Title="미리보기" Width="900" Height="1000"
|
||||||
WindowStartupLocation="CenterOwner" Background="{DynamicResource B.CanvasBg}"
|
WindowStartupLocation="CenterOwner" Background="{DynamicResource B.CanvasBg}"
|
||||||
Style="{StaticResource ThemedDialogWindow}">
|
Style="{StaticResource ThemedDialogWindow}">
|
||||||
|
<Window.Resources>
|
||||||
|
<ctl:IconNameToVisualConverter x:Key="IconName"/>
|
||||||
|
</Window.Resources>
|
||||||
<DockPanel>
|
<DockPanel>
|
||||||
<ToolBarTray DockPanel.Dock="Top">
|
<ToolBarTray DockPanel.Dock="Top">
|
||||||
<ToolBar>
|
<ToolBar>
|
||||||
<Button Content="인쇄..." Padding="10,3" Click="OnPrint"/>
|
<!--
|
||||||
<Button Content="새로 고침" Padding="10,3" Click="OnRefresh"
|
아이콘 버튼으로 둔다. 전에는 여덟 개가 전부 글자라 툴바가 글자 벽이었고,
|
||||||
ToolTip="구조 변경은 자동으로 따라오고, 창을 누르면 다시 그립니다"/>
|
무엇이 명령이고 무엇이 상태인지 구분되지 않았다.
|
||||||
|
글자로 남기는 것은 <b>값과 상태</b>뿐이다 — 고른 환자 이름과 배율.
|
||||||
|
이름은 툴팁이 받는다(셸 제목줄의 아이콘 줄과 같은 규범).
|
||||||
|
-->
|
||||||
|
<Button Style="{StaticResource Subtle}" Width="34" Height="28" Padding="0"
|
||||||
|
Click="OnPrint" ToolTip="인쇄..."
|
||||||
|
Content="{Binding Source=printer, Converter={StaticResource IconName}, ConverterParameter=16}"/>
|
||||||
|
<Button Style="{StaticResource Subtle}" Width="34" Height="28" Padding="0"
|
||||||
|
Click="OnRefresh"
|
||||||
|
ToolTip="다시 그리기 — 구조 변경은 자동으로 따라오고, 창을 누르면 다시 그립니다"
|
||||||
|
Content="{Binding Source=rotate-cw, Converter={StaticResource IconName}, ConverterParameter=16}"/>
|
||||||
<Separator/>
|
<Separator/>
|
||||||
<!--
|
<!--
|
||||||
레거시 미리보기와 레거시 인쇄가 서로 다르다 — 미리보기는 PrintOutPut=False 를
|
레거시 미리보기와 레거시 인쇄가 서로 다르다 — 미리보기는 PrintOutPut=False 를
|
||||||
그대로 보여 주고 인쇄는 뺀다. 둘 다 확인할 수 있어야 해서 보기를 가른다.
|
그대로 보여 주고 인쇄는 뺀다. 둘 다 확인할 수 있어야 해서 보기를 가른다.
|
||||||
기본은 인쇄 기준 — 저장 전에 확인하려는 것이 대개 종이 결과다.
|
기본은 인쇄 기준 — 저장 전에 확인하려는 것이 대개 종이 결과다.
|
||||||
|
토글은 눌린 상태가 곧 '인쇄 기준'이라는 뜻이다(툴팁이 양쪽을 설명한다).
|
||||||
-->
|
-->
|
||||||
<CheckBox x:Name="PrintViewToggle" Content="인쇄될 것만" IsChecked="True"
|
<ToggleButton x:Name="PrintViewToggle" IsChecked="True"
|
||||||
VerticalAlignment="Center" Margin="4,0"
|
Style="{StaticResource MiniToggle}" Width="34" Height="28" Padding="0"
|
||||||
Checked="OnViewToggled" Unchecked="OnViewToggled"
|
Checked="OnViewToggled" Unchecked="OnViewToggled"
|
||||||
ToolTip="끄면 화면에 보이는 대로 — 인쇄 출력을 끈 컨트롤도 보입니다(레거시 미리보기와 같음)"/>
|
ToolTip="인쇄될 것만 보기 — 끄면 화면에 보이는 대로(인쇄 출력을 끈 컨트롤도 보입니다)"
|
||||||
|
Content="{Binding Source=eye, Converter={StaticResource IconName}, ConverterParameter=16}"/>
|
||||||
<Separator/>
|
<Separator/>
|
||||||
<!--
|
<!--
|
||||||
실제 환자로 미리보기 — 태그가 값을 뽑는지 확인하는 유일한 방법이다.
|
실제 환자로 미리보기 — 태그가 값을 뽑는지 확인하는 유일한 방법이다.
|
||||||
고르지 않은 상태가 기본이다. 여는 순간 환자를 붙이면 미리보기를 열 때마다
|
고르지 않은 상태가 기본이다. 여는 순간 환자를 붙이면 미리보기를 열 때마다
|
||||||
환자 정보를 조회하게 되고, 그건 이 도구가 할 일이 아니다.
|
환자 정보를 조회하게 되고, 그건 이 도구가 할 일이 아니다.
|
||||||
|
|
||||||
|
선택·해제를 <b>한 버튼</b>으로 합쳤다 — 셸 제목줄의 환자 아이콘과 같은 방식이다.
|
||||||
|
안 골랐으면 바로 선택 창, 이미 골랐으면 바꾸기·해제 메뉴를 띄운다.
|
||||||
|
늘 보이는 자리에서 '누르면 해제'로 두면 실수로 지운다.
|
||||||
-->
|
-->
|
||||||
<Button x:Name="PatientButton" Content="환자 선택..." Padding="10,3" Click="OnPickPatient"
|
<Button x:Name="PatientButton" Style="{StaticResource Subtle}" Width="34" Height="28" Padding="0"
|
||||||
ToolTip="실제 환자·내원을 골라 태그에 값이 들어간 상태로 확인합니다"/>
|
Click="OnPickPatient"
|
||||||
<Button x:Name="PatientClearButton" Content="환자 해제" Padding="10,3" Click="OnClearPatient"
|
ToolTip="환자 선택 — 실제 환자·내원을 골라 태그에 값이 들어간 상태로 확인합니다"/>
|
||||||
IsEnabled="False" ToolTip="환자 없이 — 태그는 사유만 보입니다"/>
|
|
||||||
<!--
|
<!--
|
||||||
데이터소스 결과 — 종이에 값이 안 찍혔을 때 왜인지는 여기서만 알 수 있다.
|
데이터소스 결과 — 종이에 값이 안 찍혔을 때 왜인지는 여기서만 알 수 있다.
|
||||||
"[MDataTable1.ALGYON — 조회 결과가 0행입니다]" 한 줄로는 쿼리가 틀렸는지,
|
"[MDataTable1.ALGYON — 조회 결과가 0행입니다]" 한 줄로는 쿼리가 틀렸는지,
|
||||||
치환이 빈 값이 됐는지, 이 환자에게 정말 자료가 없는지 가릴 수 없다.
|
치환이 빈 값이 됐는지, 이 환자에게 정말 자료가 없는지 가릴 수 없다.
|
||||||
-->
|
-->
|
||||||
<Button x:Name="DataSourceButton" Content="데이터소스..." Padding="10,3" Click="OnShowDataSources"
|
<Button x:Name="DataSourceButton" Style="{StaticResource Subtle}" Width="34" Height="28" Padding="0"
|
||||||
IsEnabled="False" ToolTip="MDataTable 조회 결과와 치환을 마친 SQL 을 봅니다"/>
|
Click="OnShowDataSources" IsEnabled="False"
|
||||||
<TextBlock x:Name="PatientText" VerticalAlignment="Center" Margin="8,0"
|
ToolTip="데이터소스 결과 — MDataTable 조회 결과와 치환을 마친 SQL 을 봅니다"
|
||||||
MaxWidth="360" TextTrimming="CharacterEllipsis"
|
Content="{Binding Source=table, Converter={StaticResource IconName}, ConverterParameter=16}"/>
|
||||||
Foreground="{DynamicResource B.Muted}" Text="환자 없음"/>
|
|
||||||
<!--
|
<!--
|
||||||
미리보기에서 눌러 본 체크·라디오를 원래대로. 문서는 처음부터 안 건드리므로
|
미리보기에서 눌러 본 체크·라디오를 원래대로. 문서는 처음부터 안 건드리므로
|
||||||
되돌릴 것이 없고, 여기서 지우는 것은 "눌러 본 흔적"뿐이다.
|
되돌릴 것이 없고, 여기서 지우는 것은 "눌러 본 흔적"뿐이다.
|
||||||
-->
|
-->
|
||||||
<Button x:Name="ResetChecksButton" Content="누른 것 초기화" Padding="10,3" Click="OnResetChecks"
|
<Button x:Name="ResetChecksButton" Style="{StaticResource Subtle}" Width="34" Height="28" Padding="0"
|
||||||
IsEnabled="False" ToolTip="미리보기에서 눌러 본 체크·라디오를 서식의 기본 상태로 돌립니다"/>
|
Click="OnResetChecks" IsEnabled="False"
|
||||||
|
ToolTip="누른 것 초기화 — 미리보기에서 눌러 본 체크·라디오를 서식의 기본 상태로 돌립니다"
|
||||||
|
Content="{Binding Source=undo-2, Converter={StaticResource IconName}, ConverterParameter=16}"/>
|
||||||
|
<!-- 고른 환자는 <b>글자로</b> 남긴다 — 이름은 아이콘으로 대신할 수 없는 값이다 -->
|
||||||
|
<TextBlock x:Name="PatientText" VerticalAlignment="Center" Margin="8,0"
|
||||||
|
MaxWidth="360" TextTrimming="CharacterEllipsis"
|
||||||
|
Foreground="{DynamicResource B.Muted}" Text="환자 없음"/>
|
||||||
<Separator/>
|
<Separator/>
|
||||||
<Button Content="-" Padding="8,3" Click="OnZoomOut"/>
|
<Button Style="{StaticResource Subtle}" Width="30" Height="28" Padding="0"
|
||||||
|
Click="OnZoomOut" ToolTip="축소"
|
||||||
|
Content="{Binding Source=minus, Converter={StaticResource IconName}, ConverterParameter=14}"/>
|
||||||
<TextBlock x:Name="ZoomText" Text="100%" VerticalAlignment="Center" Margin="6,0" MinWidth="42" TextAlignment="Center"/>
|
<TextBlock x:Name="ZoomText" Text="100%" VerticalAlignment="Center" Margin="6,0" MinWidth="42" TextAlignment="Center"/>
|
||||||
<Button Content="+" Padding="8,3" Click="OnZoomIn"/>
|
<Button Style="{StaticResource Subtle}" Width="30" Height="28" Padding="0"
|
||||||
|
Click="OnZoomIn" ToolTip="확대"
|
||||||
|
Content="{Binding Source=plus, Converter={StaticResource IconName}, ConverterParameter=14}"/>
|
||||||
</ToolBar>
|
</ToolBar>
|
||||||
</ToolBarTray>
|
</ToolBarTray>
|
||||||
|
|
||||||
|
|||||||
@@ -303,21 +303,42 @@ public partial class PreviewWindow : Window
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void OnPickPatient(object sender, RoutedEventArgs e)
|
private void OnPickPatient(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
var picked = PatientPickerDialogView.Pick(this, out var label);
|
// 안 골랐으면 바로 선택 창. 이미 골랐으면 <b>메뉴</b>다 —
|
||||||
if (picked is null)
|
// 늘 보이는 아이콘에서 '누르면 해제'로 두면 실수로 지운다.
|
||||||
|
// 셸 제목줄의 환자 아이콘과 같은 규범이다(버튼 두 개를 하나로 합쳤다).
|
||||||
|
if (!PatientSession.HasPatient)
|
||||||
{
|
{
|
||||||
|
Pick();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 세션에만 쓴다 — 그러면 Changed 가 이 창을 포함한 <b>모든</b> 화면을 갱신한다.
|
var menu = new System.Windows.Controls.ContextMenu
|
||||||
// 여기서 직접 UsePatient 도 부르면 두 번 그리고, 더 나쁘게는
|
{
|
||||||
// 세션과 창이 어긋나는 경로가 하나 더 생긴다.
|
PlacementTarget = PatientButton,
|
||||||
PatientSession.Set(picked, label);
|
Placement = System.Windows.Controls.Primitives.PlacementMode.Bottom,
|
||||||
|
};
|
||||||
|
var header = new System.Windows.Controls.MenuItem { Header = PatientSession.Label, IsEnabled = false };
|
||||||
|
var change = new System.Windows.Controls.MenuItem { Header = "환자 바꾸기..." };
|
||||||
|
change.Click += (_, _) => Pick();
|
||||||
|
var clear = new System.Windows.Controls.MenuItem { Header = "환자 해제" };
|
||||||
|
clear.Click += (_, _) => PatientSession.Set(null, string.Empty);
|
||||||
|
menu.Items.Add(header);
|
||||||
|
menu.Items.Add(new System.Windows.Controls.Separator());
|
||||||
|
menu.Items.Add(change);
|
||||||
|
menu.Items.Add(clear);
|
||||||
|
menu.IsOpen = true;
|
||||||
|
|
||||||
|
void Pick()
|
||||||
|
{
|
||||||
|
// 권한 문·감사 기록·문맥 읽기는 전부 Pick 안에 있다 — 호출부마다 다시 확인하면 어긋난다.
|
||||||
|
// 세션에만 쓴다 — 그러면 Changed 가 이 창을 포함한 <b>모든</b> 화면을 갱신한다.
|
||||||
|
if (PatientPickerDialogView.Pick(this, out var label) is { } picked)
|
||||||
|
{
|
||||||
|
PatientSession.Set(picked, label);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>환자를 뗀다 — 종이에서 값이 사라지고 사유로 돌아가는 것까지 확인해야 한다</summary>
|
/// <summary>환자를 뗀다 — 종이에서 값이 사라지고 사유로 돌아가는 것까지 확인해야 한다</summary>
|
||||||
private void OnClearPatient(object sender, RoutedEventArgs e)
|
|
||||||
=> PatientSession.Set(null, string.Empty);
|
|
||||||
|
|
||||||
private void OnPatientSessionChanged(object? sender, EventArgs e)
|
private void OnPatientSessionChanged(object? sender, EventArgs e)
|
||||||
=> UsePatient(PatientSession.Current, PatientSession.Label);
|
=> UsePatient(PatientSession.Current, PatientSession.Label);
|
||||||
|
|
||||||
@@ -359,7 +380,11 @@ public partial class PreviewWindow : Window
|
|||||||
fields = new MDataTableRunner(designer.Document,
|
fields = new MDataTableRunner(designer.Document,
|
||||||
picked is null ? null : new PatientQueryVariableSource(picked, UserSession.Current.UidCod));
|
picked is null ? null : new PatientQueryVariableSource(picked, UserSession.Current.UidCod));
|
||||||
PatientText.Text = picked is null ? "환자 없음" : label;
|
PatientText.Text = picked is null ? "환자 없음" : label;
|
||||||
PatientClearButton.IsEnabled = picked is not null;
|
// 고른 상태는 <b>아이콘 색</b>으로 알린다 — 셸 제목줄과 같다.
|
||||||
|
// 안 고른 상태의 색은 B.Muted 여야 한다(null 을 넘기면 하드코딩 검정으로 칠해져
|
||||||
|
// 어두운 툴바에서 혼자 묻힌다 — 제목줄에서 실제로 겪은 결함이다).
|
||||||
|
PatientButton.Content = Controls.LucideIcons.Icon("user", 16,
|
||||||
|
picked is null ? "B.Muted" : "B.Accent");
|
||||||
DataSourceButton.IsEnabled = fields.Names.Count > 0;
|
DataSourceButton.IsEnabled = fields.Names.Count > 0;
|
||||||
BuildPages();
|
BuildPages();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user