/// <summary> /// Introduce an action by an animation and complete it with another animation/action /// </summary> /// <param name="board">Key of the storyboard to be played prior to the action.</param> /// <param name="action">Action to be executed after the board animation has been played. The board_Leave animation is played right after this action is completed.</param> /// <param name="closingBoard">Key of the storyboard to be played after the action has completed.</param> /// <param name="closingAction">Action to be executed after the closingBoard animation has been played.</param> public static void Do(string board, Action action, string closingBoard = null, Action closingAction = null) { if (!EnableAnimations || _Storyboard_Completed_Action != null || board == null || IsAnimated) { // re-entrant LimeMsg.Debug("AnimateAction bypassed: {0}, EnableAnimations: {1}, IsAnimated: {2}", board, EnableAnimations, IsAnimated); action(); closingAction?.Invoke(); return; } LimeMsg.Debug("AnimateAction: {0}", board); IsAnimated = true; _Storyboard_Completed_board = board; _Storyboard_Completed_Action = action; _Storyboard_Closing_board = closingBoard; _Storyboard_Closing_Action = closingAction; if (Commands.MainWindow.TryFindResource(_Storyboard_Completed_board) is Storyboard sb) { var winscope = _Storyboard_Completed_board.StartsWith("wxPanel"); _Storyboard_board = sb.Clone(); _Storyboard_board.Completed += _Storyboard_Completed; _Storyboard_board.Begin(winscope ? (FrameworkElement)Commands.MainWindow.Browser : Commands.MainWindow); } else { IsAnimated = false; var doit = _Storyboard_Completed_Action; _Storyboard_Completed_Action = null; doit(); } }
private void Popup_Opened(object sender, EventArgs e) { LimeMsg.Debug("Popup_Opened"); // Subscribe to every parent scrollviewers to detect scrolling there (and close the DropDown) if (_ScrollChangedEventHandler == null) { _ScrollChangedEventHandler = new ScrollChangedEventHandler(ScrollViewer_ScrollChanged); foreach (var scrollViewer in GetParentScrollViewers()) { scrollViewer.ScrollChanged += _ScrollChangedEventHandler; } } // Autosize if (wxPopup.Placement == PlacementMode.Bottom || wxPopup.Placement == PlacementMode.Top) { wxPopupBorder.MinWidth = wxMain.ActualWidth; wxPopup.HorizontalOffset = wxMain.Margin.Left; } var item = WPF.FindFirstChild <TextBox>(wxPicker); if (item != null) { Keyboard.Focus(item); } }
/// <summary> /// Set focus on the first valid focusable element in the control /// </summary> public void SetFocus(object dataContext = null) { UIElement focus = null; if (IsEnabled && Focusable) { focus = this; } else { if (dataContext != null) { focus = WPF.FindFirstChild <FrameworkElement>(this, (wx) => wx.IsVisible && wx.IsEnabled && wx.Focusable && wx.DataContext == dataContext ); } if (focus == null) { focus = WPF.FindFirstChild <UIElement>(this, (wx) => wx.IsVisible && wx.IsEnabled && wx.Focusable ); } } LimeMsg.Debug("LimeControl SetFocus: {0}", focus); if (focus != null) { Keyboard.Focus(focus); } }
/// <summary> /// Show the application dialog and return selection /// </summary> /// <param name="enableDirectory">Enable to create new direcoty.</param> /// <returns>selected application, null if cancel/fail</returns> private static string AppDialog(bool enableDirectory = true) { FolderBrowser fb = new FolderBrowser { Description = Global.Properties["ItemAddApp"].Desc, IncludeFiles = true, ShowNewFolderButton = enableDirectory }; // Retrieve the Application Folder if (LimeLib.IsWindows8) { ShellShortcut link = new ShellShortcut(ConfigLocal.AppsFolderPath); IntPtr pidl = link.PIDL; LimeMsg.Debug("AppDialog: AppsFolder PIDL: {0}", pidl.ToInt32()); fb.RootPIDL = pidl; fb.InitialDirectory = String.Format(":{0}", pidl.ToInt32()); } else { fb.RootFolderID = FolderBrowser.FolderID.StartMenu; LimeMsg.Debug("AppDialog: AppsFolder FolderID: {0}", fb.RootFolderID); } // Show the dialog if (fb.ShowDialog() == System.Windows.Forms.DialogResult.OK) { return(fb.SelectedPath); } return(null); }
private static void GlobalPropertyCollectionChanged(object sender, PropertyChangedEventArgs e) { LimeMsg.Debug("GlobalPropertyCollectionChanged: {0}", e.PropertyName); if (e.PropertyName == "ReqAdmin") { Properties[nameof(Commands.ConfigSave)].ReqAdmin = Properties.ReqAdmin; } else if (e.PropertyName == "Item" && e is LimePropertyChangedEventArgs ev) { try { if (User.DevMode) { var prop = Properties.Get(ev.ItemPath); if (prop != null && prop.Visible) { LimeMsg.Dev("{0}={1}", ev.ItemPath, prop.Value); } } } catch { } } }
/// <summary> /// Refresh the list of found items /// </summary> public void Refresh() { LimeMsg.Debug("MetadataSearchPanel: Refresh"); if (DataContext is LimeMetadata meta && meta.Search != null && Visibility == Visibility.Visible && IsEnabled) { // Trigger a Search value change event to update the search result LimeTextBox_TextValidated(this, new LimeControlEventArgs(this, meta.Search, meta.Search.Value)); }
// -------------------------------------------------------------------------------------------------- #region Callbacks /// <summary> /// Detect changes affecting the Icon sizes to update the LimeItem Icon size /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void IconSizePropertyChanged(object sender = null, PropertyChangedEventArgs e = null) { LimeMsg.Debug("Skin IconSizePropertyChanged: {0}", Name); Global.Root.Tree.ImgSrcSmallSize = (uint)((_IconSmallSize.Content as DoubleScaled).Scaled * Global.Local.ScreenDPI); Global.Root.Tree.ImgSrcBigSize = (uint)((_IconBigSize.Content as DoubleScaled).Scaled * Global.Local.ScreenDPI); IconWrapTrigger = 5.0 + Global.Root.Tree.ImgSrcBigSize + 2 * Global.Root.Tree.ImgSrcSmallSize < IconButtonWidth; }
/// <summary> /// Handle the busy state /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void wxInfoEditPanelBorder_IsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e) { var busy = !(bool)e.NewValue; LimeMsg.Debug("wxInfoEditPanelBorder_IsEnabledChanged: {0}", busy); this.Cursor = busy ? Cursors.Wait : null; wxInfoEditWait.IsEnabled = busy; }
/// <summary> /// Track loaded ItemsControls /// </summary> /// <param name="sender">ItemsControl</param> /// <param name="e"></param> private static void OnLoaded(object sender, RoutedEventArgs e) { LimeMsg.Debug("DataVirtualization OnLoaded"); if (sender == null) { return; } var wxthis = (ItemsControl)sender; }
private void ListBox_PreviewKeyDown(object sender, KeyEventArgs e) { LimeMsg.Debug("ListBox_PreviewKeyDown: {0}", e.Key); var wxobj = e.OriginalSource as ListBoxItem; if (wxobj == null) { return; } if (Keyboard.Modifiers != 0) { return; } bool close = false; switch (e.Key) { case Key.Enter: var wxcheck = WPF.FindFirstChild <CheckBox>(wxobj); if (wxcheck != null) { wxcheck.IsChecked = !wxcheck.IsChecked; e.Handled = true; } else { close = true; } break; case Key.Escape: var prop = wxMain.DataContext as LimeProperty; Cache = prop.Value; close = true; break; case Key.Up: close = wxMenu.SelectedIndex == 0; break; case Key.Right: case Key.Left: close = true; break; } if (close) { wxPopup.IsOpen = false; wxMain.IsChecked = false; Keyboard.Focus(wxMain); e.Handled = true; } }
/// <summary> /// Delegate for <see cref="_Watch"/> /// </summary> /// <param name="source"></param> /// <param name="e"></param> private static void OnXamlFileChanged(object source, FileSystemEventArgs e) { if (Global.User.SkinAutoRefresh && Global.User.DevMode) { LimeMsg.Debug("Skin OnXamlFileChanged: {0} : {1}", e?.ChangeType, e.FullPath); if (e.ChangeType == WatcherChangeTypes.Changed) { // Thread safe call Global.Root.Tree?.UIElement.Dispatcher.Invoke(() => Commands.SkinReload.Execute()); } } }
private void Button_IsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e) { var wxobj = sender as ButtonBase; LimeMsg.Debug("LimeButton Button_IsEnabledChanged: {0}, {1}", wxobj.IsEnabled, wxobj.IsFocused); if (!wxobj.IsEnabled && wxobj.IsFocused) { LimeMsg.Debug("LimeButton Button_IsEnabledChanged: Fix focus"); TraversalRequest tRequest = new TraversalRequest(FocusNavigationDirection.Next); wxobj.MoveFocus(tRequest); } }
/// <summary> /// React on Binding change /// </summary> /// <param name="d"></param> /// <param name="e"></param> private static void OnBoundDataContextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var wxobj = d as MetadataSearchPanel; if (e.NewValue is LimeMetadata meta) { LimeMsg.Debug("MetadataSearchPanel: BoundDataContext: {0}", meta.Search?.Value); if (meta.Search == null) { wxobj.Refresh(); } } }
/// <summary> /// Load the list of available skins into <see cref="Global.User.SkinList"/>. /// </summary> public void LoadSkinList() { string path = About.SkinsPath; FileSystemInfo[] fInfos = null; try { DirectoryInfo dInfo; dInfo = new DirectoryInfo(path); fInfos = dInfo.GetFileSystemInfos(); if (fInfos == null) { LimeMsg.Error("UnableOpenDir", path); } } catch { LimeMsg.Error("UnableOpenDir", path); } if (fInfos != null) { Array.Sort(fInfos, (x, y) => StringComparer.InvariantCultureIgnoreCase.Compare(x.Name, y.Name)); var dirs = new List <string>(fInfos.Length); foreach (var info in fInfos) { if ((info.Attributes & FileAttributes.Directory) != 0) { dirs.Add(info.Name); } } Global.User.SkinList = dirs.ToArray(); // Parameter cleanup if (Global.User.SkinParams != null) { string[] keys = Global.User.SkinParams.Keys.ToArray(); foreach (string key in keys) { if (!dirs.Contains(key)) { LimeMsg.Debug("Skin: Parameter cleanup: {0}", key); Global.User.SkinParams.Remove(key); } } } } }
/// <summary> /// Track unloaded ItemsControls /// </summary> /// <param name="sender">ItemsControl</param> /// <param name="e"></param> private static void OnUnloaded(object sender, RoutedEventArgs e) { LimeMsg.Debug("DataVirtualization OnUnloaded"); if (sender == null) { return; } var wxthis = (ItemsControl)sender; if (GetTarget(wxthis) is IItemsRangeInfo rinfo) { rinfo.Close(); } }
// -------------------------------------------------------------------------------------------------- #region Methods /// <summary> /// Retrieve the Skin Parameter matching a property identifier (key). /// </summary> /// <param name="identifier">key-name of the Skin Parameter (case-insensitive)</param> /// <returns>The found SkinParam, or null if not found</returns> public SkinParam Get(string identifier) { identifier = identifier.ToLower(); foreach (var param in Parameters) { if (param.Ident.ToLower() == identifier) { return(param); } } LimeMsg.Debug("LimeProperty.Get: not found: {0}", identifier); return(null); }
void ScrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e) { // Ignore Extend changes if (e.OriginalSource != sender) { return; } if (wxPopup.IsOpen && (e.VerticalChange != 0 || e.HorizontalChange != 0 || e.ViewportHeightChange != 0 || e.ViewportWidthChange != 0)) { LimeMsg.Debug("LimeColorPicker ScrollViewer_ScrollChanged: {0}", e.OriginalSource); wxPopup.IsOpen = false; wxMain.IsChecked = false; Keyboard.Focus(wxMain); } }
private void TextBox_PreviewKeyDown(object sender, KeyEventArgs e) { var wxobj = e.OriginalSource as TextBox; if (wxobj == null) { return; } if (Keyboard.Modifiers != 0) { return; } // Avoid bubbling keys up LimeMsg.Debug("LimeColorPicker TextBlock_PreviewKeyDown: {0}", e.Key); //e.Handled = true; TraversalRequest tRequest = null; switch (e.Key) { case Key.Up: tRequest = new TraversalRequest(FocusNavigationDirection.Up); break; case Key.Down: tRequest = new TraversalRequest(FocusNavigationDirection.Down); break; case Key.Enter: case Key.Escape: if (e.Key == Key.Escape) { BindingExpression be = wxobj.GetBindingExpression(TextBox.TextProperty); if (be != null) { be.UpdateTarget(); } } wxPopup.IsOpen = false; wxMain.IsChecked = false; Keyboard.Focus(wxMain); e.Handled = true; break; } if (tRequest != null) { wxobj.MoveFocus(tRequest); e.Handled = true; } }
/// <summary> /// Detect a change in any of the Skin Parameters /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void SkinParamPropertyChanged(object sender = null, PropertyChangedEventArgs e = null) { LimeMsg.Debug("Skin SkinParamPropertyChanged: {0} <- {1}", (sender as SkinParam)?.Ident, e.PropertyName); if (Global.User.Modified) { return; } if (string.IsNullOrEmpty(e.PropertyName) || e.PropertyName == "Content" || e.PropertyName == "Item") { Global.User.Modified = true; // Force Save Button to activate System.Windows.Input.CommandManager.InvalidateRequerySuggested(); } }
/// <summary> /// Save the Settings of LimeLauncher to an XML file. /// </summary> /// <param name="path">File to save the settings to.</param> /// <param name="apply">Apply pending changes to system (registry).</param> /// <returns>true if successful, false otherwise.</returns> public bool Save(string path = null, bool apply = true) { // Apply System changes if (StartWithWindowsModified) { LimeMsg.Debug("ConfigLocal: Set StartWithWindows: {0}", Global.Local.StartWithWindows); SystemRegistry.SetAutoRun(About.name, Global.Local.StartWithWindows ? About.ApplicationPath : null); StartWithWindowsModified = false; } if (String.IsNullOrEmpty(path)) { path = SettingsPath; } return(Save(path, this)); }
private void Popup_Opened(object sender, EventArgs e) { LimeMsg.Debug("Popup_Opened"); // Subscribe to every parent scrollviewers to detect scrolling there (and close the DropDown) if (_ScrollChangedEventHandler == null) { _ScrollChangedEventHandler = new ScrollChangedEventHandler(ScrollViewer_ScrollChanged); foreach (var scrollViewer in GetParentScrollViewers()) { LimeMsg.Debug("LimeDropDown Popup_Opened: subscribe _ScrollChangedEventHandler: {0}", scrollViewer); scrollViewer.ScrollChanged += _ScrollChangedEventHandler; } } // Autosize if (wxPopup.Placement == PlacementMode.Bottom || wxPopup.Placement == PlacementMode.Top) { wxMenu.MinWidth = wxMain.ActualWidth; wxPopup.HorizontalOffset = wxMain.Margin.Left; } // Readjust value if not yet selected if (wxMenu.ItemsSource != null && Cache != null) { wxMenu.SelectedValue = Cache; } ListBoxItem item = null; if (wxMenu.SelectedItem != null) { item = wxMenu.ItemContainerGenerator.ContainerFromItem(wxMenu.SelectedItem) as ListBoxItem; } if (item == null) { item = WPF.FindFirstChild <ListBoxItem>(wxMenu); } if (item != null) { Keyboard.Focus(item); } }
/// <summary> /// React on Binding change /// </summary> /// <param name="d"></param> /// <param name="e"></param> private static void OnBoundDataContextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var wxThis = d as InfoPanel; if (e.OldValue is LimeItem old) { old.PropertyChangedWeak -= wxThis.Item_PropertyChanged; } if (e.NewValue is LimeItem item) { LimeMsg.Debug("InfoPanel: BoundDataContext: {0}", item.Name); LimeLib.LifeCheck(); item.PropertyChangedWeak += wxThis.Item_PropertyChanged; wxThis.Item_PropertyChanged(item, null); } }
private void Popup_Closed(object sender, EventArgs e) { LimeMsg.Debug("Popup_Closed"); wxMain.IsChecked = wxMain.IsFocused && wxMain.IsChecked == true; var prop = wxMain.DataContext as LimeProperty; prop.Value = Cache.ToString(); // Unsubscribe to every parent scrollviewers if (_ScrollChangedEventHandler != null) { foreach (var scrollViewer in GetParentScrollViewers()) { scrollViewer.ScrollChanged -= _ScrollChangedEventHandler; } _ScrollChangedEventHandler = null; } }
private static void _Storyboard_Completed(object sender, EventArgs e) { // Animation completed: remve callback _Storyboard_board.Completed -= _Storyboard_Completed; if (_Storyboard_Completed_Action != null) { Storyboard sbo = null; if (_Storyboard_Closing_board != null) { sbo = Commands.MainWindow.TryFindResource(_Storyboard_Closing_board) as Storyboard; } IsAnimated = sbo != null; var doit = _Storyboard_Completed_Action; _Storyboard_Completed_Action = null; doit(); if (sbo != null) { var winscope = _Storyboard_Closing_board.StartsWith("wxPanel"); _Storyboard_board = sbo.Clone(); LimeMsg.Debug("AnimateAction animate: {0}", IsAnimated); _Storyboard_board.Completed += _Storyboard_Completed; _Storyboard_board.Begin(winscope ? (FrameworkElement)Commands.MainWindow.Browser : Commands.MainWindow); } else { IsAnimated = false; var redoit = _Storyboard_Closing_Action; _Storyboard_Closing_Action = null; redoit?.Invoke(); } } else { IsAnimated = false; LimeMsg.Debug("AnimateAction Completed: {0}", IsAnimated); var redoit = _Storyboard_Closing_Action; _Storyboard_Closing_Action = null; redoit?.Invoke(); } }
/// <summary> /// Schedule the virtualization update to avoid too expensive CPU access during UI operation /// </summary> /// <param name="sender">ScrollViewer</param> /// <param name="e"></param> private static void OnScrollChanged(object sender, ScrollChangedEventArgs e) { LimeMsg.Debug("DataVirtualization OnScrollChanged"); var wxthis = (UIElement)sender; Timer.Stop(); // Complete previous operation if (Timer.Tag != null && wxthis != Timer.Tag) { OnTimerElapsed(); } // Schedule new Timer operation var delay = GetDelay(wxthis); Timer.Tag = wxthis; Timer.Interval = delay; Timer.Start(); }
/// <summary> /// Use the LimeProperty CanConvertFrom method to validate the data content /// </summary> /// <param name="value"></param> /// <param name="cultureInfo"></param> /// <returns></returns> public override ValidationResult Validate(object value, CultureInfo cultureInfo) { var prop = Source; if (prop != null && !prop.CanConvertFrom(value)) { if (prop.AllowEmpty && value is string str && str == "") { return(ValidationResult.ValidResult); } LimeMsg.Debug("LimePropertyValidationRule: Parameter Error from {0} to {1}", value, prop.Ident); return(new ValidationResult(false, "Parameter error")); } // Check Range if (prop != null && prop.Maximum > prop.Minimum && value is string) { // Handle percents if (double.TryParse(value as string, out double val)) { var min = prop.Minimum; var max = prop.Maximum; if (prop.Percentage) { min *= 100; max *= 100; } if (val < min || val > max) { LimeMsg.Debug("LimePropertyValidationRule: Range Error from {0} to {1} (range {2}..{3})", value, prop.Ident, min, max); return(new ValidationResult(false, "Range error")); } } } return(ValidationResult.ValidResult); }
/// <summary> /// Function called back when the application starts: Initialize the application /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void App_Startup(object sender, StartupEventArgs e) { // Initialize Logger #if TRACE LimeMsg.Handlers += LimeMsg.DebugLog; #endif //LimeMsg.Handlers += LimeMsg.WinLog; LimeMsg.Handlers += LimeMsg.WinDialog; // Display version LimeMsg.Debug("{0} version {1}", About.name, About.version); LimeMsg.Debug("ApplicationPath: {0}", About.ApplicationPath); // Initialize/Load LimeLauncher data-structures Global.Load(); // Initialize GUI new MainWindow(); // Parse command arguments CommandLineInterface(true, e.Args); }
private void Popup_Closed(object sender, EventArgs e) { LimeMsg.Debug("Popup_Closed"); wxMain.IsChecked = wxMain.IsFocused && wxMain.IsChecked == true; var prop = wxMain.DataContext as LimeProperty; if (Cache != null) { ValidateValue(set: true); } // Unsubscribe to every parent scrollviewers if (_ScrollChangedEventHandler != null) { foreach (var scrollViewer in GetParentScrollViewers()) { LimeMsg.Debug("LimeDropDown Popup_Closed: unsubscribe _ScrollChangedEventHandler: {0}", scrollViewer); scrollViewer.ScrollChanged -= _ScrollChangedEventHandler; } _ScrollChangedEventHandler = null; } }
/// <summary> /// Validate the value /// </summary> /// <param name="sender">Callback from DispatcherTimer</param> /// <param name="e">Callback from DispatcherTimer</param> private void ValidateValue(object sender = null, EventArgs e = null) { if (Timer != null) { Timer.Stop(); Timer = null; } // Handle percents string txt = wxTextBox.Text.Trim(); if (txt.EndsWith("%")) { txt = txt.Substring(0, txt.Length - 1); } LimeMsg.Debug("LimeNumBox ValidateValue: {0}", txt); if (double.TryParse(txt, out double val) || txt == "" && wxMain.DataContext is LimeProperty lp && lp.AllowEmpty) { // Trigger Validation if (wxMain.DataContext is LimeProperty prop) { if (prop.Percentage) { val /= 100; } if (prop.CanConvertFrom(val.ToString())) { prop.Value = val.ToString(); } } // Required in case it is called from timer, it seems CommandManager.InvalidateRequerySuggested(); } }
/// <summary> /// React on Binding change /// </summary> /// <param name="d"></param> /// <param name="e"></param> private static void OnBoundDataContextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var wxThis = d as InfoEditPanel; if (e.NewValue is LimeItem item) { LimeMsg.Debug("InfoEditPanel: BoundDataContext: {0}", item.Name); LimeLib.LifeCheck(); var meta = item.Metadata; if (meta != null && meta.Search == null) { if (meta.Type == MediaType.Video) { var path = meta["Path"].Value; var repl = Global.User.PathToSearchMovie.Replace(path); meta.Search = new LimeProperty("Search", repl); } } } #if TRACE wxThis.StopWatch.Restart(); #endif }