feature<ContextMenu>: highlight branch/commit/tag name in ContextMenuItem

This commit is contained in:
leo 2024-02-06 19:07:17 +08:00
parent 98e65c0f11
commit e310cfd84f
5 changed files with 176 additions and 170 deletions

View file

@ -181,17 +181,17 @@
<sys:String x:Key="Text.RepoCM.Open">Open</sys:String>
<sys:String x:Key="Text.RepoCM.Explore">Explore in File Manager</sys:String>
<sys:String x:Key="Text.BranchCM.Push">Push '{0}'</sys:String>
<sys:String x:Key="Text.BranchCM.Push">Push ${0}$</sys:String>
<sys:String x:Key="Text.BranchCM.DiscardAll">Discard all changes</sys:String>
<sys:String x:Key="Text.BranchCM.FastForward">Fast-Forward to '{0}'</sys:String>
<sys:String x:Key="Text.BranchCM.Pull">Pull '{0}'</sys:String>
<sys:String x:Key="Text.BranchCM.PullInto">Pull '{0}' into '{1}'</sys:String>
<sys:String x:Key="Text.BranchCM.Checkout">Checkout '{0}'</sys:String>
<sys:String x:Key="Text.BranchCM.Merge">Merge '{0}' into '{1}'</sys:String>
<sys:String x:Key="Text.BranchCM.Rebase">Rebase '{0}' on '{1}'</sys:String>
<sys:String x:Key="Text.BranchCM.Finish">Git Flow - Finish '{0}'</sys:String>
<sys:String x:Key="Text.BranchCM.Rename">Rename '{0}'</sys:String>
<sys:String x:Key="Text.BranchCM.Delete">Delete '{0}'</sys:String>
<sys:String x:Key="Text.BranchCM.FastForward">Fast-Forward to ${0}$</sys:String>
<sys:String x:Key="Text.BranchCM.Pull">Pull ${0}$</sys:String>
<sys:String x:Key="Text.BranchCM.PullInto">Pull ${0}$ into ${1}$</sys:String>
<sys:String x:Key="Text.BranchCM.Checkout">Checkout ${0}$</sys:String>
<sys:String x:Key="Text.BranchCM.Merge">Merge ${0}$ into ${1}$</sys:String>
<sys:String x:Key="Text.BranchCM.Rebase">Rebase ${0}$ on ${1}$</sys:String>
<sys:String x:Key="Text.BranchCM.Finish">Git Flow - Finish ${0}$</sys:String>
<sys:String x:Key="Text.BranchCM.Rename">Rename ${0}$</sys:String>
<sys:String x:Key="Text.BranchCM.Delete">Delete ${0}$</sys:String>
<sys:String x:Key="Text.BranchCM.Tracking">Tracking ...</sys:String>
<sys:String x:Key="Text.BranchCM.CopyName">Copy Branch Name</sys:String>
<sys:String x:Key="Text.BranchCM.UnsetUpstream">Unset Upstream</sys:String>
@ -203,8 +203,8 @@
<sys:String x:Key="Text.RemoteCM.Delete">Delete ...</sys:String>
<sys:String x:Key="Text.RemoteCM.CopyURL">Copy URL</sys:String>
<sys:String x:Key="Text.CommitCM.Reset">Reset '{0}' to Here</sys:String>
<sys:String x:Key="Text.CommitCM.Rebase">Rebase '{0}' to Here</sys:String>
<sys:String x:Key="Text.CommitCM.Reset">Reset ${0}$ to Here</sys:String>
<sys:String x:Key="Text.CommitCM.Rebase">Rebase ${0}$ to Here</sys:String>
<sys:String x:Key="Text.CommitCM.CherryPick">Cherry-Pick This Commit</sys:String>
<sys:String x:Key="Text.CommitCM.Reword">Reword</sys:String>
<sys:String x:Key="Text.CommitCM.Squash">Squash Into Parent</sys:String>
@ -212,8 +212,8 @@
<sys:String x:Key="Text.CommitCM.SaveAsPatch">Save as Patch ...</sys:String>
<sys:String x:Key="Text.CommitCM.CopySHA">Copy SHA</sys:String>
<sys:String x:Key="Text.TagCM.Push">Push '{0}'</sys:String>
<sys:String x:Key="Text.TagCM.Delete">Delete '{0}'</sys:String>
<sys:String x:Key="Text.TagCM.Push">Push ${0}$</sys:String>
<sys:String x:Key="Text.TagCM.Delete">Delete ${0}$</sys:String>
<sys:String x:Key="Text.TagCM.Copy">Copy Tag Name</sys:String>
<sys:String x:Key="Text.StashCM.Apply">Apply</sys:String>
@ -458,66 +458,12 @@
<sys:String x:Key="Text.Squash.To">To :</sys:String>
<sys:String x:Key="Text.Squash.Message">Reword :</sys:String>
<sys:String x:Key="Text.Statistics">Statistics</sys:String>
<sys:String x:Key="Text.Statistics.ThisWeek">WEEK</sys:String>
<sys:String x:Key="Text.Statistics.ThisMonth">MONTH</sys:String>
<sys:String x:Key="Text.Statistics.ThisYear">YEAR</sys:String>
<sys:String x:Key="Text.Statistics.TotalCommitterCount">Total Committers: {0}</sys:String>
<sys:String x:Key="Text.Statistics.TotalCommitsCount">Total Commits{0}</sys:String>
<sys:String x:Key="Text.Statistics.CommitterName">COMMITTER</sys:String>
<sys:String x:Key="Text.Statistics.CommitAmount">COMMITS</sys:String>
<sys:String x:Key="Text.AssumeUnchanged">FILES ASSUME UNCHANGED</sys:String>
<sys:String x:Key="Text.AssumeUnchanged.Remove">REMOVE</sys:String>
<sys:String x:Key="Text.AssumeUnchanged.Empty">NO FILES ASSUMED AS UNCHANGED</sys:String>
<sys:String x:Key="Text.Weekday.0">SUN</sys:String>
<sys:String x:Key="Text.Weekday.1">MON</sys:String>
<sys:String x:Key="Text.Weekday.2">TUE</sys:String>
<sys:String x:Key="Text.Weekday.3">WED</sys:String>
<sys:String x:Key="Text.Weekday.4">THU</sys:String>
<sys:String x:Key="Text.Weekday.5">FRI</sys:String>
<sys:String x:Key="Text.Weekday.6">SAT</sys:String>
<sys:String x:Key="Text.Month.1">Jan</sys:String>
<sys:String x:Key="Text.Month.2">Feb</sys:String>
<sys:String x:Key="Text.Month.3">Mar</sys:String>
<sys:String x:Key="Text.Month.4">Apr</sys:String>
<sys:String x:Key="Text.Month.5">May</sys:String>
<sys:String x:Key="Text.Month.6">Jun</sys:String>
<sys:String x:Key="Text.Month.7">Jul</sys:String>
<sys:String x:Key="Text.Month.8">Aug</sys:String>
<sys:String x:Key="Text.Month.9">Sep</sys:String>
<sys:String x:Key="Text.Month.10">Oct</sys:String>
<sys:String x:Key="Text.Month.11">Nov</sys:String>
<sys:String x:Key="Text.Month.12">Dec</sys:String>
<sys:String x:Key="Text.Sort.Name">By Name</sys:String>
<sys:String x:Key="Text.Sort.RecentlyOpened">By Recently Opened</sys:String>
<sys:String x:Key="Text.Sort.Bookmark">By Bookmark Color</sys:String>
<sys:String x:Key="Text.NotConfigured">Git has NOT been configured. Please to go [Preference] and configure it first.</sys:String>
<sys:String x:Key="Text.PathNotFound">Path[{0}] not exists!</sys:String>
<sys:String x:Key="Text.MissingBash">Can NOT locate bash.exe. Make sure bash.exe exists under the same folder with git.exe</sys:String>
<sys:String x:Key="Text.BinaryNotSupported">BINARY FILE NOT SUPPORTED!!!</sys:String>
<sys:String x:Key="Text.BlameTypeNotSupported">BLAME ON THIS FILE IS NOT SUPPORTED!!!</sys:String>
<sys:String x:Key="Text.GitDirNotFound">GIT_DIR for this repository NOT FOUND!</sys:String>
<sys:String x:Key="Text.InitGitFlowFailed">Initialize Git-flow failed!</sys:String>
<sys:String x:Key="Text.BadGitFlowType">Bad git-flow branch type!</sys:String>
<sys:String x:Key="Text.BadCloneFolder">EXISTS and FULL ACCESS CONTROL needed</sys:String>
<sys:String x:Key="Text.BadRemoteUri">Remote git URL not supported</sys:String>
<sys:String x:Key="Text.BadLocalName">Bad local repository name</sys:String>
<sys:String x:Key="Text.EmptyRemoteName">Remote name can NOT be null</sys:String>
<sys:String x:Key="Text.BadRemoteName">Bad name for remote. Regex: ^[\\w\\-\\.]+$</sys:String>
<sys:String x:Key="Text.DuplicatedRemoteName">Duplicated remote name!</sys:String>
<sys:String x:Key="Text.EmptyBranchName">Branch name can NOT be null</sys:String>
<sys:String x:Key="Text.BadBranchName">Bad name for branch. Regex: ^[\\w\\-/\\.]+$</sys:String>
<sys:String x:Key="Text.DuplicatedBranchName">Duplicated branch name!</sys:String>
<sys:String x:Key="Text.EmptyCommitMessage">Commit message can NOT be empty</sys:String>
<sys:String x:Key="Text.BadPatchFile">Invalid path for patch file</sys:String>
<sys:String x:Key="Text.BadRelativePath">Invalid relative path</sys:String>
<sys:String x:Key="Text.BadArchiveFile">Invalid path for archive file</sys:String>
<sys:String x:Key="Text.Required">This field is required</sys:String>
<sys:String x:Key="Text.ConfirmRemoveRepo">You are removing repository '{0}'. Are you sure to continue?</sys:String>
<sys:String x:Key="Text.SaveAsPatchSuccess">Patch has been saved successfully!</sys:String>
</ResourceDictionary>

View file

@ -180,17 +180,17 @@
<sys:String x:Key="Text.RepoCM.Open">打开</sys:String>
<sys:String x:Key="Text.RepoCM.Explore">在浏览器中查看</sys:String>
<sys:String x:Key="Text.BranchCM.Push">推送 '{0}'</sys:String>
<sys:String x:Key="Text.BranchCM.Push">推送 ${0}$</sys:String>
<sys:String x:Key="Text.BranchCM.DiscardAll">放弃所有更改</sys:String>
<sys:String x:Key="Text.BranchCM.FastForward">快进到 '{0}'</sys:String>
<sys:String x:Key="Text.BranchCM.Pull">拉回 '{0}'</sys:String>
<sys:String x:Key="Text.BranchCM.PullInto">拉回 '{0}' 内容至 '{1}'</sys:String>
<sys:String x:Key="Text.BranchCM.Checkout">检出 '{0}'</sys:String>
<sys:String x:Key="Text.BranchCM.Merge">合并 '{0}' 到 '{1}'</sys:String>
<sys:String x:Key="Text.BranchCM.Rebase">变基 '{0}' 分支至 '{1}'</sys:String>
<sys:String x:Key="Text.BranchCM.Finish">GIT工作流 - 完成 '{0}'</sys:String>
<sys:String x:Key="Text.BranchCM.Rename">重命名 '{0}'</sys:String>
<sys:String x:Key="Text.BranchCM.Delete">删除 '{0}'</sys:String>
<sys:String x:Key="Text.BranchCM.FastForward">快进到 ${0}$</sys:String>
<sys:String x:Key="Text.BranchCM.Pull">拉回 ${0}$</sys:String>
<sys:String x:Key="Text.BranchCM.PullInto">拉回 ${0}$ 内容至 ${1}$</sys:String>
<sys:String x:Key="Text.BranchCM.Checkout">检出 ${0}$</sys:String>
<sys:String x:Key="Text.BranchCM.Merge">合并 ${0}$ 到 ${1}$</sys:String>
<sys:String x:Key="Text.BranchCM.Rebase">变基 ${0}$ 分支至 ${1}$</sys:String>
<sys:String x:Key="Text.BranchCM.Finish">GIT工作流 - 完成 ${0}$</sys:String>
<sys:String x:Key="Text.BranchCM.Rename">重命名 ${0}$</sys:String>
<sys:String x:Key="Text.BranchCM.Delete">删除 ${0}$</sys:String>
<sys:String x:Key="Text.BranchCM.Tracking">切换上游分支...</sys:String>
<sys:String x:Key="Text.BranchCM.CopyName">复制分支名</sys:String>
<sys:String x:Key="Text.BranchCM.UnsetUpstream">取消追踪</sys:String>
@ -202,8 +202,8 @@
<sys:String x:Key="Text.RemoteCM.Delete">删除 ...</sys:String>
<sys:String x:Key="Text.RemoteCM.CopyURL">复制远程地址</sys:String>
<sys:String x:Key="Text.CommitCM.Reset">重置 '{0}' 到此处</sys:String>
<sys:String x:Key="Text.CommitCM.Rebase">变基 '{0}' 到此处</sys:String>
<sys:String x:Key="Text.CommitCM.Reset">重置 ${0}$ 到此处</sys:String>
<sys:String x:Key="Text.CommitCM.Rebase">变基 ${0}$ 到此处</sys:String>
<sys:String x:Key="Text.CommitCM.CherryPick">挑选此提交</sys:String>
<sys:String x:Key="Text.CommitCM.Reword">编辑提交信息</sys:String>
<sys:String x:Key="Text.CommitCM.Squash">合并此提交到上一个提交</sys:String>
@ -211,8 +211,8 @@
<sys:String x:Key="Text.CommitCM.SaveAsPatch">另存为补丁 ...</sys:String>
<sys:String x:Key="Text.CommitCM.CopySHA">复制提交指纹</sys:String>
<sys:String x:Key="Text.TagCM.Push">推送 '{0}'</sys:String>
<sys:String x:Key="Text.TagCM.Delete">删除 '{0}'</sys:String>
<sys:String x:Key="Text.TagCM.Push">推送 ${0}$</sys:String>
<sys:String x:Key="Text.TagCM.Delete">删除 ${0}$</sys:String>
<sys:String x:Key="Text.TagCM.Copy">复制标签名</sys:String>
<sys:String x:Key="Text.StashCM.Apply">应用</sys:String>
@ -457,66 +457,12 @@
<sys:String x:Key="Text.Squash.To">合并到 :</sys:String>
<sys:String x:Key="Text.Squash.Message">修改提交信息:</sys:String>
<sys:String x:Key="Text.Statistics">提交统计</sys:String>
<sys:String x:Key="Text.Statistics.ThisWeek">本周</sys:String>
<sys:String x:Key="Text.Statistics.ThisMonth">本月</sys:String>
<sys:String x:Key="Text.Statistics.ThisYear">本年</sys:String>
<sys:String x:Key="Text.Statistics.TotalCommitterCount">提交者人数:{0}</sys:String>
<sys:String x:Key="Text.Statistics.TotalCommitsCount">总计提交次数:{0}</sys:String>
<sys:String x:Key="Text.Statistics.CommitterName">提交者</sys:String>
<sys:String x:Key="Text.Statistics.CommitAmount">提交次数</sys:String>
<sys:String x:Key="Text.AssumeUnchanged">不跟踪更改的文件</sys:String>
<sys:String x:Key="Text.AssumeUnchanged.Remove">移除</sys:String>
<sys:String x:Key="Text.AssumeUnchanged.Empty">没有不跟踪更改的文件</sys:String>
<sys:String x:Key="Text.Weekday.0">星期日</sys:String>
<sys:String x:Key="Text.Weekday.1">星期一</sys:String>
<sys:String x:Key="Text.Weekday.2">星期二</sys:String>
<sys:String x:Key="Text.Weekday.3">星期三</sys:String>
<sys:String x:Key="Text.Weekday.4">星期四</sys:String>
<sys:String x:Key="Text.Weekday.5">星期五</sys:String>
<sys:String x:Key="Text.Weekday.6">星期六</sys:String>
<sys:String x:Key="Text.Month.1">1月</sys:String>
<sys:String x:Key="Text.Month.2">2月</sys:String>
<sys:String x:Key="Text.Month.3">3月</sys:String>
<sys:String x:Key="Text.Month.4">4月</sys:String>
<sys:String x:Key="Text.Month.5">5月</sys:String>
<sys:String x:Key="Text.Month.6">6月</sys:String>
<sys:String x:Key="Text.Month.7">7月</sys:String>
<sys:String x:Key="Text.Month.8">8月</sys:String>
<sys:String x:Key="Text.Month.9">9月</sys:String>
<sys:String x:Key="Text.Month.10">10月</sys:String>
<sys:String x:Key="Text.Month.11">11月</sys:String>
<sys:String x:Key="Text.Month.12">12月</sys:String>
<sys:String x:Key="Text.Sort.Name">按名称升序</sys:String>
<sys:String x:Key="Text.Sort.RecentlyOpened">按最近访问</sys:String>
<sys:String x:Key="Text.Sort.Bookmark">按书签颜色</sys:String>
<sys:String x:Key="Text.NotConfigured">GIT尚未配置。请打开【偏好设置】配置GIT路径。</sys:String>
<sys:String x:Key="Text.PathNotFound">路径({0})不存在或不可读取!</sys:String>
<sys:String x:Key="Text.MissingBash">无法找到bash.exe请确保其在git.exe同目录中</sys:String>
<sys:String x:Key="Text.BinaryNotSupported">二进制文件不支持该操作!!!</sys:String>
<sys:String x:Key="Text.BlameTypeNotSupported">选中文件不支持该操作!!!</sys:String>
<sys:String x:Key="Text.GitDirNotFound">获取仓库GIT_DIR失败!</sys:String>
<sys:String x:Key="Text.InitGitFlowFailed">初始化GIT FLOW失败!</sys:String>
<sys:String x:Key="Text.BadGitFlowType">不支持的GIT FLOW分支!</sys:String>
<sys:String x:Key="Text.BadCloneFolder">目录不存在或不可写!!!</sys:String>
<sys:String x:Key="Text.BadRemoteUri">非法的远程仓库地址!</sys:String>
<sys:String x:Key="Text.BadLocalName">非法的本地仓库地址!</sys:String>
<sys:String x:Key="Text.EmptyRemoteName">远程仓库地址不可为空</sys:String>
<sys:String x:Key="Text.BadRemoteName">远程仓库地址包含非法字符!仅支持字母、数字、下划线、横线或英文点号!</sys:String>
<sys:String x:Key="Text.DuplicatedRemoteName">远程仓库名已存在!</sys:String>
<sys:String x:Key="Text.EmptyBranchName">分支名不可为空</sys:String>
<sys:String x:Key="Text.BadBranchName">分支名包含非法字符!仅支持字母、数字、下划线、横线或英文点号!</sys:String>
<sys:String x:Key="Text.DuplicatedBranchName">分支名已存在!</sys:String>
<sys:String x:Key="Text.EmptyCommitMessage">提交信息未填写!</sys:String>
<sys:String x:Key="Text.BadPatchFile">补丁文件不存在或不可访问!</sys:String>
<sys:String x:Key="Text.BadRelativePath">非法的子路径!</sys:String>
<sys:String x:Key="Text.BadArchiveFile">非法的存档文件路径!</sys:String>
<sys:String x:Key="Text.Required">内容未填写!</sys:String>
<sys:String x:Key="Text.ConfirmRemoveRepo">正在将 '{0}' 从列表中移除,是否要继续?</sys:String>
<sys:String x:Key="Text.SaveAsPatchSuccess">补丁已成功保存!</sys:String>
</ResourceDictionary>

View file

@ -131,7 +131,7 @@ namespace SourceGit.ViewModels {
if (current.Head != commit.SHA) {
var reset = new MenuItem();
reset.Header = App.Text("CommitCM.Reset", current.Name);
reset.Header = CreateHighlightLabel("CommitCM.Reset", current.Name);
reset.Icon = CreateMenuIcon("Icons.Reset");
reset.Click += (o, e) => {
if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new Reset(_repo, current, commit));
@ -165,7 +165,7 @@ namespace SourceGit.ViewModels {
if (!commit.IsMerged) {
var rebase = new MenuItem();
rebase.Header = App.Text("CommitCM.Rebase", current.Name);
rebase.Header = CreateHighlightLabel("CommitCM.Rebase", current.Name);
rebase.Icon = CreateMenuIcon("Icons.Rebase");
rebase.Click += (o, e) => {
if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new Rebase(_repo, current, commit));
@ -262,7 +262,7 @@ namespace SourceGit.ViewModels {
var upstream = current.Upstream.Substring(13);
var fastForward = new MenuItem();
fastForward.Header = App.Text("BranchCM.FastForward", upstream);
fastForward.Header = CreateHighlightLabel("BranchCM.FastForward", upstream);
fastForward.Icon = CreateMenuIcon("Icons.FastForward");
fastForward.IsEnabled = dirty;
fastForward.Click += (o, e) => {
@ -272,7 +272,7 @@ namespace SourceGit.ViewModels {
submenu.Items.Add(fastForward);
var pull = new MenuItem();
pull.Header = App.Text("BranchCM.Pull", upstream);
pull.Header = CreateHighlightLabel("BranchCM.Pull", upstream);
pull.Icon = CreateMenuIcon("Icons.Pull");
pull.IsEnabled = dirty;
pull.Click += (o, e) => {
@ -283,7 +283,7 @@ namespace SourceGit.ViewModels {
}
var push = new MenuItem();
push.Header = App.Text("BranchCM.Push", current.Name);
push.Header = CreateHighlightLabel("BranchCM.Push", current.Name);
push.Icon = CreateMenuIcon("Icons.Push");
push.IsEnabled = _repo.Remotes.Count > 0 && dirty;
push.Click += (o, e) => {
@ -296,7 +296,7 @@ namespace SourceGit.ViewModels {
var type = _repo.GitFlow.GetBranchType(current.Name);
if (type != Models.GitFlowBranchType.None) {
var finish = new MenuItem();
finish.Header = App.Text("BranchCM.Finish", current.Name);
finish.Header = CreateHighlightLabel("BranchCM.Finish", current.Name);
finish.Icon = CreateMenuIcon("Icons.Flow");
finish.Click += (o, e) => {
if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new GitFlowFinish(_repo, current, type));
@ -307,7 +307,7 @@ namespace SourceGit.ViewModels {
}
var rename = new MenuItem();
rename.Header = App.Text("BranchCM.Rename", current.Name);
rename.Header = CreateHighlightLabel("BranchCM.Rename", current.Name);
rename.Icon = CreateMenuIcon("Icons.Rename");
rename.Click += (o, e) => {
if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new RenameBranch(_repo, current));
@ -324,7 +324,7 @@ namespace SourceGit.ViewModels {
submenu.Header = branch.Name;
var checkout = new MenuItem();
checkout.Header = App.Text("BranchCM.Checkout", branch.Name);
checkout.Header = CreateHighlightLabel("BranchCM.Checkout", branch.Name);
checkout.Icon = CreateMenuIcon("Icons.Check");
checkout.Click += (o, e) => {
if (PopupHost.CanCreatePopup()) PopupHost.ShowAndStartPopup(new Checkout(_repo, branch.Name));
@ -333,7 +333,7 @@ namespace SourceGit.ViewModels {
submenu.Items.Add(checkout);
var merge = new MenuItem();
merge.Header = App.Text("BranchCM.Merge", branch.Name, current.Name);
merge.Header = CreateHighlightLabel("BranchCM.Merge", branch.Name, current.Name);
merge.Icon = CreateMenuIcon("Icons.Merge");
merge.IsEnabled = !merged;
merge.Click += (o, e) => {
@ -346,7 +346,7 @@ namespace SourceGit.ViewModels {
var type = _repo.GitFlow.GetBranchType(branch.Name);
if (type != Models.GitFlowBranchType.None) {
var finish = new MenuItem();
finish.Header = App.Text("BranchCM.Finish", branch.Name);
finish.Header = CreateHighlightLabel("BranchCM.Finish", branch.Name);
finish.Icon = CreateMenuIcon("Icons.Flow");
finish.Click += (o, e) => {
if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new GitFlowFinish(_repo, branch, type));
@ -357,7 +357,7 @@ namespace SourceGit.ViewModels {
}
var rename = new MenuItem();
rename.Header = App.Text("BranchCM.Rename", branch.Name);
rename.Header = CreateHighlightLabel("BranchCM.Rename", branch.Name);
rename.Icon = CreateMenuIcon("Icons.Rename");
rename.Click += (o, e) => {
if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new RenameBranch(_repo, branch));
@ -366,7 +366,7 @@ namespace SourceGit.ViewModels {
submenu.Items.Add(rename);
var delete = new MenuItem();
delete.Header = App.Text("BranchCM.Delete", branch.Name);
delete.Header = CreateHighlightLabel("BranchCM.Delete", branch.Name);
delete.Icon = CreateMenuIcon("Icons.Clear");
delete.Click += (o, e) => {
if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new DeleteBranch(_repo, branch));
@ -385,7 +385,7 @@ namespace SourceGit.ViewModels {
submenu.Header = name;
var checkout = new MenuItem();
checkout.Header = App.Text("BranchCM.Checkout", name);
checkout.Header = CreateHighlightLabel("BranchCM.Checkout", name);
checkout.Icon = CreateMenuIcon("Icons.Check");
checkout.Click += (o, e) => {
foreach (var b in _repo.Branches) {
@ -402,7 +402,7 @@ namespace SourceGit.ViewModels {
submenu.Items.Add(checkout);
var merge = new MenuItem();
merge.Header = App.Text("BranchCM.Merge", name, current.Name);
merge.Header = CreateHighlightLabel("BranchCM.Merge", name, current.Name);
merge.Icon = CreateMenuIcon("Icons.Merge");
merge.IsEnabled = !merged;
merge.Click += (o, e) => {
@ -414,7 +414,7 @@ namespace SourceGit.ViewModels {
submenu.Items.Add(new MenuItem() { Header = "-" });
var delete = new MenuItem();
delete.Header = App.Text("BranchCM.Delete", name);
delete.Header = CreateHighlightLabel("BranchCM.Delete", name);
delete.Icon = CreateMenuIcon("Icons.Clear");
delete.Click += (o, e) => {
if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new DeleteBranch(_repo, branch));
@ -432,7 +432,7 @@ namespace SourceGit.ViewModels {
submenu.MinWidth = 200;
var push = new MenuItem();
push.Header = App.Text("TagCM.Push", tag.Name);
push.Header = CreateHighlightLabel("TagCM.Push", tag.Name);
push.Icon = CreateMenuIcon("Icons.Push");
push.IsEnabled = _repo.Remotes.Count > 0;
push.Click += (o, e) => {
@ -442,7 +442,7 @@ namespace SourceGit.ViewModels {
submenu.Items.Add(push);
var delete = new MenuItem();
delete.Header = App.Text("TagCM.Delete", tag.Name);
delete.Header = CreateHighlightLabel("TagCM.Delete", tag.Name);
delete.Icon = CreateMenuIcon("Icons.Clear");
delete.Click += (o, e) => {
if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new DeleteTag(_repo, tag));
@ -453,6 +453,13 @@ namespace SourceGit.ViewModels {
menu.Items.Add(submenu);
}
private object CreateHighlightLabel(string key, params object[] args) {
var label = new Views.NameHighlightedTextBlock();
label.Text = App.Text(key, args);
label.VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center;
return label;
}
private Avalonia.Controls.Shapes.Path CreateMenuIcon(string key) {
var icon = new Avalonia.Controls.Shapes.Path();
icon.Width = 12;

View file

@ -578,7 +578,7 @@ namespace SourceGit.ViewModels {
var menu = new ContextMenu();
var push = new MenuItem();
push.Header = App.Text("BranchCM.Push", branch.Name);
push.Header = CreateHighlightLabel("BranchCM.Push", branch.Name);
push.Icon = CreateMenuIcon("Icons.Push");
push.IsEnabled = Remotes.Count > 0;
push.Click += (_, e) => {
@ -601,7 +601,7 @@ namespace SourceGit.ViewModels {
if (!string.IsNullOrEmpty(branch.Upstream)) {
var upstream = branch.Upstream.Substring(13);
var fastForward = new MenuItem();
fastForward.Header = App.Text("BranchCM.FastForward", upstream);
fastForward.Header = CreateHighlightLabel("BranchCM.FastForward", upstream);
fastForward.Icon = CreateMenuIcon("Icons.FastForward");
fastForward.IsEnabled = !string.IsNullOrEmpty(branch.UpstreamTrackStatus) && branch.UpstreamTrackStatus.IndexOf('↑') < 0;
fastForward.Click += (o, e) => {
@ -610,7 +610,7 @@ namespace SourceGit.ViewModels {
};
var pull = new MenuItem();
pull.Header = App.Text("BranchCM.Pull", upstream);
pull.Header = CreateHighlightLabel("BranchCM.Pull", upstream);
pull.Icon = CreateMenuIcon("Icons.Pull");
pull.IsEnabled = !string.IsNullOrEmpty(branch.UpstreamTrackStatus);
pull.Click += (o, e) => {
@ -627,7 +627,7 @@ namespace SourceGit.ViewModels {
var current = Branches.Find(x => x.IsCurrent);
var checkout = new MenuItem();
checkout.Header = App.Text("BranchCM.Checkout", branch.Name);
checkout.Header = CreateHighlightLabel("BranchCM.Checkout", branch.Name);
checkout.Icon = CreateMenuIcon("Icons.Check");
checkout.Click += (o, e) => {
if (PopupHost.CanCreatePopup()) PopupHost.ShowAndStartPopup(new Checkout(this, branch.Name));
@ -638,7 +638,7 @@ namespace SourceGit.ViewModels {
var upstream = Branches.Find(x => x.FullName == branch.Upstream);
if (upstream != null) {
var fastForward = new MenuItem();
fastForward.Header = App.Text("BranchCM.FastForward", $"{upstream.Remote}/{upstream.Name}");
fastForward.Header = CreateHighlightLabel("BranchCM.FastForward", $"{upstream.Remote}/{upstream.Name}");
fastForward.Icon = CreateMenuIcon("Icons.FastForward");
fastForward.IsEnabled = !string.IsNullOrEmpty(branch.UpstreamTrackStatus) && branch.UpstreamTrackStatus.IndexOf('↑') < 0;
fastForward.Click += (o, e) => {
@ -654,7 +654,7 @@ namespace SourceGit.ViewModels {
menu.Items.Add(push);
var merge = new MenuItem();
merge.Header = App.Text("BranchCM.Merge", branch.Name, current.Name);
merge.Header = CreateHighlightLabel("BranchCM.Merge", branch.Name, current.Name);
merge.Icon = CreateMenuIcon("Icons.Merge");
merge.Click += (o, e) => {
if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new Merge(this, branch.Name, current.Name));
@ -662,7 +662,7 @@ namespace SourceGit.ViewModels {
};
var rebase = new MenuItem();
rebase.Header = App.Text("BranchCM.Rebase", current.Name, branch.Name);
rebase.Header = CreateHighlightLabel("BranchCM.Rebase", current.Name, branch.Name);
rebase.Icon = CreateMenuIcon("Icons.Rebase");
rebase.Click += (o, e) => {
if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new Rebase(this, current, branch));
@ -676,7 +676,7 @@ namespace SourceGit.ViewModels {
var type = GitFlow.GetBranchType(branch.Name);
if (type != Models.GitFlowBranchType.None) {
var finish = new MenuItem();
finish.Header = App.Text("BranchCM.Finish", branch.Name);
finish.Header = CreateHighlightLabel("BranchCM.Finish", branch.Name);
finish.Icon = CreateMenuIcon("Icons.Flow");
finish.Click += (o, e) => {
if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new GitFlowFinish(this, branch, type));
@ -687,7 +687,7 @@ namespace SourceGit.ViewModels {
}
var rename = new MenuItem();
rename.Header = App.Text("BranchCM.Rename", branch.Name);
rename.Header = CreateHighlightLabel("BranchCM.Rename", branch.Name);
rename.Icon = CreateMenuIcon("Icons.Rename");
rename.Click += (o, e) => {
if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new RenameBranch(this, branch));
@ -695,7 +695,7 @@ namespace SourceGit.ViewModels {
};
var delete = new MenuItem();
delete.Header = App.Text("BranchCM.Delete", branch.Name);
delete.Header = CreateHighlightLabel("BranchCM.Delete", branch.Name);
delete.Icon = CreateMenuIcon("Icons.Clear");
delete.IsEnabled = !branch.IsCurrent;
delete.Click += (o, e) => {
@ -847,7 +847,7 @@ namespace SourceGit.ViewModels {
var current = Branches.Find(x => x.IsCurrent);
var checkout = new MenuItem();
checkout.Header = App.Text("BranchCM.Checkout", $"{branch.Remote}/{branch.Name}");
checkout.Header = CreateHighlightLabel("BranchCM.Checkout", $"{branch.Remote}/{branch.Name}");
checkout.Icon = CreateMenuIcon("Icons.Check");
checkout.Click += (o, e) => {
foreach (var b in Branches) {
@ -866,7 +866,7 @@ namespace SourceGit.ViewModels {
if (current != null) {
var pull = new MenuItem();
pull.Header = App.Text("BranchCM.PullInto", $"{branch.Remote}/{branch.Name}", current.Name);
pull.Header = CreateHighlightLabel("BranchCM.PullInto", $"{branch.Remote}/{branch.Name}", current.Name);
pull.Icon = CreateMenuIcon("Icons.Pull");
pull.Click += (o, e) => {
if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new Pull(this, branch));
@ -874,7 +874,7 @@ namespace SourceGit.ViewModels {
};
var merge = new MenuItem();
merge.Header = App.Text("BranchCM.Merge", $"{branch.Remote}/{branch.Name}", current.Name);
merge.Header = CreateHighlightLabel("BranchCM.Merge", $"{branch.Remote}/{branch.Name}", current.Name);
merge.Icon = CreateMenuIcon("Icons.Merge");
merge.Click += (o, e) => {
if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new Merge(this, $"{branch.Remote}/{branch.Name}", current.Name));
@ -882,7 +882,7 @@ namespace SourceGit.ViewModels {
};
var rebase = new MenuItem();
rebase.Header = App.Text("BranchCM.Rebase", current.Name, $"{branch.Remote}/{branch.Name}");
rebase.Header = CreateHighlightLabel("BranchCM.Rebase", current.Name, $"{branch.Remote}/{branch.Name}");
rebase.Icon = CreateMenuIcon("Icons.Rebase");
rebase.Click += (o, e) => {
if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new Rebase(this, current, branch));
@ -896,7 +896,7 @@ namespace SourceGit.ViewModels {
}
var delete = new MenuItem();
delete.Header = App.Text("BranchCM.Delete", $"{branch.Remote}/{branch.Name}");
delete.Header = CreateHighlightLabel("BranchCM.Delete", $"{branch.Remote}/{branch.Name}");
delete.Icon = CreateMenuIcon("Icons.Clear");
delete.Click += (o, e) => {
if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new DeleteBranch(this, branch));
@ -956,7 +956,7 @@ namespace SourceGit.ViewModels {
};
var pushTag = new MenuItem();
pushTag.Header = App.Text("TagCM.Push", tag.Name);
pushTag.Header = CreateHighlightLabel("TagCM.Push", tag.Name);
pushTag.Icon = CreateMenuIcon("Icons.Push");
pushTag.IsEnabled = Remotes.Count > 0;
pushTag.Click += (o, ev) => {
@ -965,7 +965,7 @@ namespace SourceGit.ViewModels {
};
var deleteTag = new MenuItem();
deleteTag.Header = App.Text("TagCM.Delete", tag.Name);
deleteTag.Header = CreateHighlightLabel("TagCM.Delete", tag.Name);
deleteTag.Icon = CreateMenuIcon("Icons.Clear");
deleteTag.Click += (o, ev) => {
if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new DeleteTag(this, tag));
@ -1046,6 +1046,13 @@ namespace SourceGit.ViewModels {
return menu;
}
private object CreateHighlightLabel(string key, params object[] args) {
var label = new Views.NameHighlightedTextBlock();
label.Text = App.Text(key, args);
label.VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center;
return label;
}
private Avalonia.Controls.Shapes.Path CreateMenuIcon(string key) {
var icon = new Avalonia.Controls.Shapes.Path();
icon.Width = 12;

View file

@ -0,0 +1,100 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Media;
using System;
using System.Globalization;
namespace SourceGit.Views {
public class NameHighlightedTextBlock : Control {
public static readonly StyledProperty<string> TextProperty =
AvaloniaProperty.Register<NameHighlightedTextBlock, string>(nameof(Text));
public string Text {
get => GetValue(TextProperty);
set => SetValue(TextProperty, value);
}
public static readonly StyledProperty<FontFamily> FontFamilyProperty =
TextBlock.FontFamilyProperty.AddOwner<NameHighlightedTextBlock>();
public FontFamily FontFamily {
get => GetValue(FontFamilyProperty);
set => SetValue(FontFamilyProperty, value);
}
public static readonly StyledProperty<double> FontSizeProperty =
TextBlock.FontSizeProperty.AddOwner<NameHighlightedTextBlock>();
public double FontSize {
get => GetValue(FontSizeProperty);
set => SetValue(FontSizeProperty, value);
}
public static readonly StyledProperty<IBrush> ForegroundProperty =
TextBlock.ForegroundProperty.AddOwner<NameHighlightedTextBlock>();
public IBrush Foreground {
get => GetValue(ForegroundProperty);
set => SetValue(ForegroundProperty, value);
}
static NameHighlightedTextBlock() {
AffectsMeasure<NameHighlightedTextBlock>(TextProperty);
}
protected override Size MeasureOverride(Size availableSize) {
var text = Text;
if (string.IsNullOrEmpty(text)) return base.MeasureOverride(availableSize);
var typeface = new Typeface(FontFamily, FontStyle.Normal, FontWeight.Normal, FontStretch.Normal);
var formatted = new FormattedText(
Text,
CultureInfo.CurrentCulture,
FlowDirection.LeftToRight,
typeface,
FontSize,
Foreground);
return new Size(formatted.Width, formatted.Height);
}
public override void Render(DrawingContext context) {
var text = Text;
if (string.IsNullOrEmpty(text)) return;
var normalTypeface = new Typeface(FontFamily, FontStyle.Normal, FontWeight.Normal, FontStretch.Normal);
var highlightTypeface = new Typeface(FontFamily, FontStyle.Normal, FontWeight.Bold, FontStretch.Normal);
var underlinePen = new Pen(Foreground, 1);
var offsetX = 0.0;
var parts = text.Split('$', StringSplitOptions.None);
var isName = false;
foreach (var part in parts) {
if (string.IsNullOrEmpty(part)) {
isName = !isName;
continue;
}
var formatted = new FormattedText(
part,
CultureInfo.CurrentCulture,
FlowDirection.LeftToRight,
isName ? highlightTypeface : normalTypeface,
FontSize,
Foreground);
context.DrawText(formatted, new Point(offsetX, 0));
if (isName) {
var lineY = formatted.Baseline + 2;
context.DrawLine(underlinePen, new Point(offsetX, lineY), new Point(offsetX + formatted.Width, lineY));
offsetX += formatted.Width;
} else {
offsetX += formatted.Width + 4;
}
isName = !isName;
}
}
}
}