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}"/>
<local:BooleanToCollapsedVisibilityConverter x:Key="booleanToCollapsedVisibilityConverter" />
<local:EntryTypeConverter x:Key="entryTypeConverter"/>
<local:SortModeToBooleanConverter x:Key="sortModeToBooleanConverter" />
<Style x:Key="HeaderLeftAlign" TargetType="{x:Type GridViewColumnHeader}">
<Setter Property="HorizontalContentAlignment" Value="Left"></Setter>
</Style>
@ -151,16 +153,16 @@
<Separator/>
<MenuItem Header="{x:Static s:guiStrings.CtxMenuSortBy}">
<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"/>
<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"/>
<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"/>
<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}"/>
</MenuItem>
</MenuItem>

View File

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