Skip to content

Commit

Permalink
File status list tweaks (#5542)
Browse files Browse the repository at this point in the history
#5437 
* Auto resilze FileStatusList column
* more accurate Ctrl+A handling in FileStatusList
  • Loading branch information
NikolayXHD authored and RussKie committed Oct 13, 2018
1 parent 4d8370d commit 0655fc2
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 61 deletions.
10 changes: 10 additions & 0 deletions GitUI/UserControls/ExListView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,16 @@ public struct LVGROUP
}
#endregion

protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified)
{
// Prevent flickering horizontal scrollbar when control width is reduced,
// by preventing redrawing the control before column width is adjusted to new width in
// some event handler e.g. ClientSizeChanged.
BeginUpdate();
base.SetBoundsCore(x, y, width, height, specified);
EndUpdate();
}

private bool _isInWmPaintMsg;

protected override void WndProc(ref Message m)
Expand Down
19 changes: 10 additions & 9 deletions GitUI/UserControls/FileStatusList.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

157 changes: 105 additions & 52 deletions GitUI/UserControls/FileStatusList.cs
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,34 @@ int GetLastIndex()
}
}

private static (Image Image, string Text) GetDisplayElements(ListViewItem item, PathFormatter formatter, int itemWidth)
{
if (!(item?.Tag is GitItemStatus gitItemStatus))
{
return (default, default);
}

Image image = null;
if (item.ImageList != null && item.ImageIndex != -1)
{
image = item.ImageList.Images[item.ImageIndex];
}

var (_, textWidth) = GetHorizontalTextRange(item, image, itemWidth);
var text = formatter.FormatTextForDrawing(textWidth, gitItemStatus.Name, gitItemStatus.OldName);
text = AppendItemSubmoduleStatus(text, gitItemStatus);

return (image, text);
}

private static (int TextStartX, int TextWidth) GetHorizontalTextRange(ListViewItem item, Image image, int itemWidth)
{
var textStartX = item.Position.X + (image?.Width ?? 0);
var textWidth = itemWidth - textStartX;

return (textStartX, textWidth);
}

public void SelectAll()
{
try
Expand Down Expand Up @@ -738,8 +766,6 @@ private void UpdateFileStatusListView(bool updateCausedByFilter = false)
HandleVisibility_NoFilesLabel_FilterComboBox(filesPresent: true);
}

FileStatusListView.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent);

HashSet<GitItemStatus> previouslySelectedItems = null;

if (updateCausedByFilter)
Expand All @@ -757,7 +783,6 @@ private void UpdateFileStatusListView(bool updateCausedByFilter = false)
FileStatusListView.Items.Clear();

var truncateMethod = AppSettings.TruncatePathMethod;
var clientSizeWidth = truncateMethod == TruncatePathMethod.Compact || truncateMethod == TruncatePathMethod.TrimStart;
var fileNameOnlyMode = truncateMethod == TruncatePathMethod.FileNameOnly;

var list = new List<ListViewItem>();
Expand All @@ -784,37 +809,16 @@ private void UpdateFileStatusListView(bool updateCausedByFilter = false)
FileStatusListView.Groups.Add(group);
}

var pathFormatter = new PathFormatter(FileStatusListView.CreateGraphics(), FileStatusListView.Font);

foreach (var item in statuses)
{
if (!(_filter?.IsMatch(item.Name) ?? true))
{
continue;
}

string text;
if (clientSizeWidth)
{
// list-item has client width, so we don't need horizontal scrollbar (which is determined by this text width)
text = string.Empty;
}
else if (fileNameOnlyMode)
{
// we need to put filename in list-item text -> then horizontal scrollbar
// will have proper width (by the longest filename, and not all path)
text = PathFormatter.FormatTextForFileNameOnly(item.Name, item.OldName);
if (!(_filter?.IsMatch(text) ?? true))
{
continue;
}

text = AppendItemSubmoduleStatus(text, item);
}
else
{
text = item.Name;
}

var listItem = new ListViewItem(text, group)
var listItem = new ListViewItem(string.Empty, group)
{
ImageIndex = GetItemImageIndex(item)
};
Expand All @@ -840,6 +844,19 @@ private void UpdateFileStatusListView(bool updateCausedByFilter = false)
}

listItem.Tag = item;

var (image, text) = GetDisplayElements(listItem, pathFormatter, FileStatusListView.ClientSize.Width);
if (image == default && text == default)
{
continue;
}

if (fileNameOnlyMode && !(_filter?.IsMatch(text) ?? true))
{
continue;
}

listItem.Text = text;
list.Add(listItem);
}
}
Expand All @@ -856,9 +873,8 @@ private void UpdateFileStatusListView(bool updateCausedByFilter = false)
}
}

FileStatusListView.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize);
FileStatusListView.EndUpdate();

UpdateColumnWidth();
return;

void EnsureSelectedIndexChangeSubscription()
Expand Down Expand Up @@ -948,6 +964,29 @@ string GetDescriptionForRevision(ObjectId objectId)
}
}

private void UpdateColumnWidth()
{
FileStatusListView.BeginUpdate();
columnHeader.AutoResize(ColumnHeaderAutoResizeStyle.ColumnContent);
var minWidth = FileStatusListView.ClientSize.Width;
if (columnHeader.Width < minWidth)
{
columnHeader.Width = minWidth;
}

ThreadHelper.JoinableTaskFactory.RunAsync(async () =>
{
// by postponing ListView redraw we workaround the bug
// that renders ListView unusable if column Width is set within any
// event handler like SizeChanged, ClientSizeChanged, Layout and etc.
// https://github.com/gitextensions/gitextensions/issues/5437
await Task.Delay(TimeSpan.FromMilliseconds(10));
await this.SwitchToMainThreadAsync();
FileStatusListView.EndUpdate();
}).FileAndForget();
}

private void HandleVisibility_NoFilesLabel_FilterComboBox(bool filesPresent)
{
NoFiles.Visible = !filesPresent;
Expand All @@ -959,6 +998,26 @@ private void HandleVisibility_NoFilesLabel_FilterComboBox(bool filesPresent)

// Event handlers

private void FileStatusListView_ClientSizeChanged(object sender, EventArgs e)
{
if (!FileStatusListView.IsHandleCreated)
{
return;
}

var formatter = new PathFormatter(FileStatusListView.CreateGraphics(), FileStatusListView.Font);
foreach (ListViewItem item in FileStatusListView.Items)
{
var (_, text) = GetDisplayElements(item, formatter, FileStatusListView.ClientSize.Width);

// let FileStatusListView know the actual displayed text
// in order to properly display horizontal scroll
item.Text = text;
}

UpdateColumnWidth();
}

private void FileStatusListView_ContextMenu_Opening(object sender, CancelEventArgs e)
{
var cm = (ContextMenuStrip)sender;
Expand Down Expand Up @@ -1001,31 +1060,24 @@ private void FileStatusListView_DoubleClick(object sender, EventArgs e)

private void FileStatusListView_DrawSubItem(object sender, DrawListViewSubItemEventArgs e)
{
if (!(e.Item?.Tag is GitItemStatus gitItemStatus))
var item = e.Item;
var formatter = new PathFormatter(e.Graphics, FileStatusListView.Font);

var (image, text) = GetDisplayElements(item, formatter, item.Bounds.Width);
if (image == default && text == default)
{
return;
}

var imageWidth = 0;
if (e.Item.ImageList != null && e.Item.ImageIndex != -1)
if (image != null)
{
var image = e.Item.ImageList.Images[e.Item.ImageIndex];
imageWidth = image.Width;
e.Graphics.DrawImageUnscaled(image, e.Item.Position.X, e.Item.Position.Y);
e.Graphics.DrawImageUnscaled(image, item.Position.X, item.Position.Y);
}

var font = FileStatusListView.Font;
var textStartX = e.Item.Position.X + imageWidth;
var textSpace = e.Item.Bounds.Width - textStartX;
var formatter = new PathFormatter(e.Graphics, font);

var text = formatter.FormatTextForDrawing(textSpace, gitItemStatus.Name, gitItemStatus.OldName);

text = AppendItemSubmoduleStatus(text, gitItemStatus);

var slashIndex = text.LastIndexOf('/');

var textRect = new Rectangle(textStartX, e.Item.Bounds.Top, textSpace, e.Item.Bounds.Height);
var (textStartX, textWidth) = GetHorizontalTextRange(item, image, item.Bounds.Width);
var textRect = new Rectangle(textStartX, item.Bounds.Top, textWidth, item.Bounds.Height);

if (slashIndex == -1 || slashIndex >= text.Length - 1)
{
Expand Down Expand Up @@ -1064,15 +1116,10 @@ private void FileStatusListView_GroupMouseDown(object sender, ListViewGroupMouse

private void FileStatusListView_KeyDown(object sender, KeyEventArgs e)
{
switch (e.KeyCode)
switch (e.KeyData)
{
case Keys.A:
case Keys.Control | Keys.A:
{
if (!e.Control)
{
break;
}

FileStatusListView.BeginUpdate();
try
{
Expand Down Expand Up @@ -1322,6 +1369,12 @@ private void FilterWatermarkLabel_Click(object sender, EventArgs e)
FilterComboBox.Focus();
}

private void FilterComboBox_SizeChanged(object sender, EventArgs e)
{
// strangely it does not invalidate itself on resize so its look becomes distorted
FilterComboBox.Invalidate();
}

#endregion
}
}

0 comments on commit 0655fc2

Please sign in to comment.