usability tweaks.

implemented lookup of file names by typing its first letters.

'sort by' menu now works properly.
This commit is contained in:
morkt
2014-08-02 18:23:20 +04:00
parent 7492ea24ae
commit 931d76db04
2 changed files with 80 additions and 33 deletions

View File

@@ -27,6 +27,8 @@
<CollectionViewSource x:Key="ListViewSource" Source="{Binding}"/> <CollectionViewSource x:Key="ListViewSource" Source="{Binding}"/>
<local:BooleanToCollapsedVisibilityConverter x:Key="booleanToCollapsedVisibilityConverter" /> <local:BooleanToCollapsedVisibilityConverter x:Key="booleanToCollapsedVisibilityConverter" />
<local:EntryTypeConverter x:Key="entryTypeConverter"/> <local:EntryTypeConverter x:Key="entryTypeConverter"/>
<local:SortModeToBooleanConverter x:Key="sortModeToBooleanConverter" />
<Style x:Key="HeaderLeftAlign" TargetType="{x:Type GridViewColumnHeader}"> <Style x:Key="HeaderLeftAlign" TargetType="{x:Type GridViewColumnHeader}">
<Setter Property="HorizontalContentAlignment" Value="Left"></Setter> <Setter Property="HorizontalContentAlignment" Value="Left"></Setter>
</Style> </Style>
@@ -151,16 +153,16 @@
<Separator/> <Separator/>
<MenuItem Header="{x:Static s:guiStrings.CtxMenuSortBy}"> <MenuItem Header="{x:Static s:guiStrings.CtxMenuSortBy}">
<MenuItem Header="{x:Static s:guiStrings.CtxMenuSortByName}" IsCheckable="True" <MenuItem Header="{x:Static s:guiStrings.CtxMenuSortByName}" IsCheckable="True"
IsChecked="{Binding ElementName=AppWindow, Path=IsSortByName, Mode=OneWay}" IsChecked="{Binding ElementName=AppWindow, Path=SortMode, Mode=OneWay, Converter={StaticResource sortModeToBooleanConverter}, ConverterParameter=Name}"
Command="{x:Static local:Commands.SortBy}" CommandParameter="Name"/> Command="{x:Static local:Commands.SortBy}" CommandParameter="Name"/>
<MenuItem Header="{x:Static s:guiStrings.CtxMenuSortByType}" IsCheckable="True" <MenuItem Header="{x:Static s:guiStrings.CtxMenuSortByType}" IsCheckable="True"
IsChecked="{Binding ElementName=AppWindow, Path=IsSortByType, Mode=OneWay}" IsChecked="{Binding ElementName=AppWindow, Path=SortMode, Mode=OneWay, Converter={StaticResource sortModeToBooleanConverter}, ConverterParameter=Type}"
Command="{x:Static local:Commands.SortBy}" CommandParameter="Type"/> Command="{x:Static local:Commands.SortBy}" CommandParameter="Type"/>
<MenuItem Header="{x:Static s:guiStrings.CtxMenuSortBySize}" IsCheckable="True" <MenuItem Header="{x:Static s:guiStrings.CtxMenuSortBySize}" IsCheckable="True"
IsChecked="{Binding ElementName=AppWindow, Path=IsSortBySize, Mode=OneWay}" IsChecked="{Binding ElementName=AppWindow, Path=SortMode, Mode=OneWay, Converter={StaticResource sortModeToBooleanConverter}, ConverterParameter=Size}"
Command="{x:Static local:Commands.SortBy}" CommandParameter="Size"/> Command="{x:Static local:Commands.SortBy}" CommandParameter="Size"/>
<MenuItem Header="{x:Static s:guiStrings.CtxMenuUnsorted}" IsCheckable="True" <MenuItem Header="{x:Static s:guiStrings.CtxMenuUnsorted}" IsCheckable="True"
IsChecked="{Binding ElementName=AppWindow, Path=IsUnsorted, Mode=OneWay}" IsChecked="{Binding ElementName=AppWindow, Path=SortMode, Mode=OneWay, Converter={StaticResource sortModeToBooleanConverter}}"
Command="{x:Static local:Commands.SortBy}"/> Command="{x:Static local:Commands.SortBy}"/>
</MenuItem> </MenuItem>
</MenuItem> </MenuItem>

View File

@@ -25,6 +25,7 @@ using System;
using System.IO; using System.IO;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using System.Globalization;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Diagnostics; using System.Diagnostics;
@@ -108,7 +109,7 @@ namespace GARbro.GUI
{ {
if (null != m_lvSortByColumn) if (null != m_lvSortByColumn)
{ {
Settings.Default.lvSortColumn = m_lvSortByColumn.Tag.ToString(); Settings.Default.lvSortColumn = SortMode;
Settings.Default.lvSortDirection = m_lvSortDirection; Settings.Default.lvSortDirection = m_lvSortDirection;
} }
else else
@@ -165,7 +166,7 @@ namespace GARbro.GUI
return; return;
if (null == node) if (null == node)
{ {
while (MaxRecentFiles < m_recent_files.Count) while (MaxRecentFiles <= m_recent_files.Count)
m_recent_files.RemoveLast(); m_recent_files.RemoveLast();
m_recent_files.AddFirst (file); m_recent_files.AddFirst (file);
} }
@@ -200,10 +201,7 @@ namespace GARbro.GUI
if (value.IsArchive) if (value.IsArchive)
PushRecentFile (value.Path); PushRecentFile (value.Path);
if (m_lvSortByColumn != null) lv_Sort (SortMode, m_lvSortDirection);
lv_Sort (m_lvSortByColumn.Tag.ToString(), m_lvSortDirection);
else
lv_Sort (null, m_lvSortDirection);
if (!value.IsArchive && !string.IsNullOrEmpty (value.Path)) if (!value.IsArchive && !string.IsNullOrEmpty (value.Path))
{ {
Directory.SetCurrentDirectory (value.Path); Directory.SetCurrentDirectory (value.Path);
@@ -395,16 +393,14 @@ namespace GARbro.GUI
GridViewColumnHeader m_lvSortByColumn = null; GridViewColumnHeader m_lvSortByColumn = null;
ListSortDirection m_lvSortDirection = ListSortDirection.Ascending; ListSortDirection m_lvSortDirection = ListSortDirection.Ascending;
public bool IsSortByName { public string SortMode
get { return m_lvSortByColumn != null && "Name".Equals (m_lvSortByColumn.Tag); } {
get { return GetValue (SortModeProperty) as string; }
private set { SetValue (SortModeProperty, value); }
} }
public bool IsSortByType {
get { return m_lvSortByColumn != null && "Type".Equals (m_lvSortByColumn.Tag); } public static readonly DependencyProperty SortModeProperty =
} DependencyProperty.RegisterAttached ("SortMode", typeof(string), typeof(MainWindow), new UIPropertyMetadata());
public bool IsSortBySize {
get { return m_lvSortByColumn != null && "Size".Equals (m_lvSortByColumn.Tag); }
}
public bool IsUnsorted { get { return m_lvSortByColumn == null; } }
void lv_SetSortMode (string sortBy, ListSortDirection direction) void lv_SetSortMode (string sortBy, ListSortDirection direction)
{ {
@@ -427,6 +423,7 @@ namespace GARbro.GUI
column.HeaderTemplate = Resources["SortArrowNone"] as DataTemplate; column.HeaderTemplate = Resources["SortArrowNone"] as DataTemplate;
} }
} }
SortMode = sortBy;
} }
private void lv_Sort (string sortBy, ListSortDirection direction) private void lv_Sort (string sortBy, ListSortDirection direction)
@@ -457,6 +454,7 @@ namespace GARbro.GUI
string sortBy = headerClicked.Tag.ToString(); string sortBy = headerClicked.Tag.ToString();
lv_Sort (sortBy, direction); lv_Sort (sortBy, direction);
SortMode = sortBy;
// Remove arrow from previously sorted header // Remove arrow from previously sorted header
if (m_lvSortByColumn != null && m_lvSortByColumn != headerClicked) if (m_lvSortByColumn != null && m_lvSortByColumn != headerClicked)
@@ -488,20 +486,31 @@ namespace GARbro.GUI
} }
/// <summary> /// <summary>
/// Event handler for keys pressed in the right pane /// Event handler for keys pressed in the directory view pane
/// </summary> /// </summary>
private void lv_TextInput (object sender, TextCompositionEventArgs e) private void lv_TextInput (object sender, TextCompositionEventArgs e)
{ {
LookupItem (e.Text); LookupItem (e.Text, e.Timestamp);
e.Handled = true; e.Handled = true;
} }
class InputData
{
public int LastTime = 0;
public StringBuilder Phrase = new StringBuilder();
public bool Mismatch = false;
}
const int TextLookupTimeout = 1000; // milliseconds
InputData m_current_input = new InputData();
/// <summary> /// <summary>
/// Lookup item in listview pane by first letter. /// Lookup item in listview pane by first letters of name.
/// </summary> /// </summary>
private void LookupItem (string key) private void LookupItem (string key, int timestamp)
{ {
if (string.IsNullOrEmpty (key)) if (string.IsNullOrEmpty (key))
return; return;
@@ -509,20 +518,39 @@ namespace GARbro.GUI
if (source == null) if (source == null)
return; return;
var current = CurrentDirectory.SelectedItem as EntryViewModel; if (timestamp - m_current_input.LastTime > TextLookupTimeout)
int index = 0;
if (current != null && current.Name.StartsWith (key, StringIgnoreCase))
index = CurrentDirectory.SelectedIndex+1;
for (int i = index, count = source.Count; i < count; ++i)
{ {
var entry = source.GetItemAt (i) as EntryViewModel; m_current_input.Phrase.Clear();
if (entry != null && entry.Name.StartsWith (key, StringIgnoreCase)) m_current_input.Mismatch = false;
}
m_current_input.LastTime = timestamp;
if (m_current_input.Mismatch)
return;
if (1 == m_current_input.Phrase.Length && m_current_input.Phrase[0] == key[0])
{
// same key repeats, lookup by first letter only
int current = CurrentDirectory.SelectedIndex;
if (current != -1 && current+1 < source.Count)
{ {
lv_SelectItem (entry); var next_item = source.GetItemAt (current+1) as EntryViewModel;
break; if (next_item != null && next_item.Name.StartsWith (key, StringIgnoreCase))
{
lv_SelectItem (next_item);
return;
}
} }
} }
else
{
m_current_input.Phrase.Append (key);
}
string input = m_current_input.Phrase.ToString();
var matched = source.Cast<EntryViewModel>().Where (e => e.Name.StartsWith (input, StringIgnoreCase)).FirstOrDefault();
if (null != matched)
lv_SelectItem (matched);
else
m_current_input.Mismatch = true;
} }
private void acb_OnKeyDown (object sender, KeyEventArgs e) private void acb_OnKeyDown (object sender, KeyEventArgs e)
@@ -1087,6 +1115,23 @@ namespace GARbro.GUI
} }
} }
public class SortModeToBooleanConverter : IValueConverter
{
public object Convert (object value, Type targetType, object parameter, CultureInfo culture)
{
string actual_mode = value as string;
string check_mode = parameter as string;
if (string.IsNullOrEmpty (check_mode))
return string.IsNullOrEmpty (actual_mode);
return check_mode.Equals (actual_mode);
}
public object ConvertBack (object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
public class BooleanToCollapsedVisibilityConverter : IValueConverter public class BooleanToCollapsedVisibilityConverter : IValueConverter
{ {
#region IValueConverter Members #region IValueConverter Members