private void BuildView() { this.SuspendLayout(); this.Text = this.StimulusClass.Settings.Name; var cols = GUIUtils.CreateTable(new double[] { .33, .33, .33 }, Direction.Horizontal); // settings var settingsConfig = new ConfigurationPanel(this.StimulusClass.Settings) { Dock = DockStyle.Fill }; // image panel var imagePanel = new ImagePanel() { Dock = DockStyle.Fill }; // dropdown var dropDown = new ComboBox() { DropDownStyle = ComboBoxStyle.DropDownList, Dock = DockStyle.Bottom }; dropDown.MouseWheel += (sender, args) => ((HandledMouseEventArgs)args).Handled = true; dropDown.Items.Add(new DisplayPointer(() => this.StimulusClass.Settings.Answer1, true)); dropDown.Items.Add(new DisplayPointer(() => this.StimulusClass.Settings.Answer2, false)); dropDown.Items.Add(new DisplayPointer(GUIUtils.Strings.UNCLASSIFIED, null)); // source folder var sourceFolderLink = new LinkLabel() { AutoSize = true, Text = Path.GetFileName(this.StimulusClass.SourceFolder), Dock = DockStyle.Top }; sourceFolderLink.Click += (sender, args) => { try { System.Diagnostics.Process.Start("explorer.exe", this.StimulusClass.SourceFolder); } catch (Exception) { GUIUtils.Alert("Failed to open " + this.StimulusClass.SourceFolder); } }; this.ToolTip.SetToolTip(sourceFolderLink, "Open " + this.StimulusClass.SourceFolder); // image list var imageList = new CheckedListBox() { Dock = DockStyle.Fill }; imageList.AddContextMenu(); foreach (var stimulus in this.StimulusClass.Stimuli) { imageList.Items.Add(new StimulusItem(this.StimulusClass, stimulus), stimulus.Used); } EventHandler setImage = (sender, args) => { if (imageList.Items.Count > 0) { var stimulus = ((StimulusItem)(imageList.SelectedItem ?? imageList.Items[0])).Stimulus; imagePanel.ImagePath = stimulus.PathOrText; dropDown.Visible = true; switch (stimulus.Subclass) { case true: dropDown.SelectedIndex = 0; break; case false: dropDown.SelectedIndex = 1; break; case null: dropDown.SelectedIndex = 2; break; } } else { imagePanel.ImagePath = null; dropDown.Visible = false; } }; setImage(imageList, EventArgs.Empty); // first set imageList.SelectedIndexChanged += setImage; settingsConfig.PropertyChanged += args => { this.StimulusClass.Settings.SetProperty(args.Property, args.Getter()); this.Text = this.StimulusClass.Settings.Name; imageList.Invalidate(); // force a refresh int selectedIndex = dropDown.SelectedIndex; var items = dropDown.Items.Cast <DisplayPointer>().ToArray(); dropDown.Items.Clear(); dropDown.Items.AddRange(items); dropDown.SelectedIndex = selectedIndex; }; imageList.ItemCheck += (sender, args) => ((StimulusItem)imageList.Items[args.Index]).Stimulus.Used = (args.NewValue == CheckState.Checked); dropDown.SelectedIndexChanged += (sender, args) => { ((StimulusItem)(imageList.SelectedItem ?? imageList.Items[0])).Stimulus.Subclass = (bool?)((DisplayPointer)dropDown.SelectedItem).Key; imageList.Invalidate(); }; this.getSelectedStimulus = () => imageList.SelectedItem == null ? null : ((StimulusItem)imageList.SelectedItem).Stimulus; // selection info label var selectionInfoLabel = new Label() { Dock = DockStyle.Bottom, AutoSize = true }; PaintEventHandler updateSelectionInfoLabel = (sender, args) => { var items = imageList.Items.Cast <StimulusItem>(); selectionInfoLabel.Text = string.Format("{0}/{1} selected", items.Count(s => s.Stimulus.Used), imageList.Items.Count); if (!string.IsNullOrWhiteSpace(this.StimulusClass.Settings.Answer1) || !string.IsNullOrWhiteSpace(this.StimulusClass.Settings.Answer2)) { selectionInfoLabel.Text += string.Format(" ({0}/{1} {2}, {3}/{4} {5}, {6}/{7} {8})", items.Count(s => s.Stimulus.Subclass == true && s.Stimulus.Used), items.Count(s => s.Stimulus.Subclass == true), this.StimulusClass.Settings.Answer1, items.Count(s => s.Stimulus.Subclass == false && s.Stimulus.Used), items.Count(s => s.Stimulus.Subclass == false), this.StimulusClass.Settings.Answer2, items.Count(s => s.Stimulus.Subclass == null && s.Stimulus.Used), items.Count(s => s.Stimulus.Subclass == null), GUIUtils.Strings.UNCLASSIFIED); } }; imageList.Paint += updateSelectionInfoLabel; updateSelectionInfoLabel(null, null); // button table var buttonTable = GUIUtils.CreateButtonTable(Direction.Horizontal, DockStyle.Bottom, GUIUtils.CreateFlatButton("Classify", b => { MainForm.Instance.Animate(new StimulusClassSetupProvider(this.StimulusClass), this.Invalidate); }, this.ToolTip, "Launch a tool to quickly answer this class's question for all stimuli"), GUIUtils.CreateFlatButton("Refresh", b => { this.StimulusClass.RefreshStimuli(); this.Invalidate(); }, this.ToolTip, "Reload the stimuli from the file system"), GUIUtils.CreateFlatButton("Save", b => { bool saved = this.StimulusClass.TrySave(); GUIUtils.Alert((saved ? "Saved" : "Failed to save") + " stimulus class info to " + this.StimulusClass.SavePath, (saved ? MessageBoxIcon.Information : MessageBoxIcon.Error)); }, this.ToolTip, "Save configuration information to " + this.StimulusClass.SavePath)); // add all controls Panel panel; // left column panel = new Panel() { Dock = DockStyle.Fill }; panel.Controls.Add(settingsConfig); panel.Controls.Add(sourceFolderLink); panel.Controls.Add("Folder".ToLabel()); panel.Controls.Add(buttonTable); cols.Controls.Add(panel, 0, 0); // middle column panel = new Panel() { Dock = DockStyle.Fill }; panel.Controls.Add(imageList); panel.Controls.Add(selectionInfoLabel); panel.Controls.Add("Stimuli".ToLabel()); cols.Controls.Add(panel, 1, 0); // right column panel = new Panel() { Dock = DockStyle.Fill }; panel.Controls.Add(imagePanel); panel.Controls.Add(dropDown); cols.Controls.Add(panel, 2, 0); this.Controls.Add(cols); this.ResumeLayout(false); }
private void BuildView() { this.SuspendLayout(); this.StimulusClass1 = this.StimulusClass2 = null; // tab control var tabs = new CustomTabControl() { Dock = DockStyle.Fill }; tabs.DisplayStyleProvider = new TabStyleVisualStudioProvider(tabs) { ShowTabCloser = true }; tabs.TabClosing += (sender, args) => ((CustomTab)args.TabPage).RaiseClosingSafe(args); // start tab var startTab = new CustomTab() { Text = "Classes" }; // columns var cols = GUIUtils.CreateTable(new double[] { .33, .33, .33 }, Direction.Horizontal); // image config var imageConfig = ConfigurationPanel.Create <ImageDisplaySettings>(); // image panel var imagePanel = new ImagePanel() { Dock = DockStyle.Fill, UseNativeSize = false }; bool cycle = true; var rand = new Random(); Func <StimulusClass, string> getImageForClass = stimulusClass => { var tab = this.stimulusClassTabs.First(t => t.StimulusClass == stimulusClass); if (tab.StimulusClass.Stimuli.Count == 0) { return(null); } if (!((ImageDisplaySettings)imageConfig.GetConfiguredObject()).CycleThroughImages) { return((tab.SelectedStimulus ?? tab.StimulusClass.Stimuli.First()).PathOrText); } return(tab.StimulusClass.Stimuli.ElementAt(rand.Next(tab.StimulusClass.Stimuli.Count)).PathOrText); }; Action setImage = () => { imagePanel.ImagePath = this.StimulusClass1 == null ? null : getImageForClass(this.StimulusClass1); imagePanel.SecondaryImagePath = this.StimulusClass2 == null ? null : getImageForClass(this.StimulusClass2); }; setImage(); var timer = new Timer() { Interval = 2500, Enabled = true }; timer.Tick += (sender, args) => { // just return if we're not cycling to avoid flicker if (!cycle && !timer.Enabled) { return; } // if the form is valid, set a new image var activeTextBox = this.FindForm().ActiveControl as TextBox; if (activeTextBox == null || activeTextBox.IsValid()) { setImage(); } }; Action <ImageDisplaySettings> configurePanel = settings => { imagePanel.Configure(settings); if (settings.CycleThroughImages != cycle) { cycle = settings.CycleThroughImages; setImage(); } this.ImageDisplaySettings = settings; }; configurePanel((ImageDisplaySettings)imageConfig.GetConfiguredObject()); imageConfig.PropertyChanged += args => configurePanel((ImageDisplaySettings)imageConfig.GetConfiguredObject()); // class list var classList = new CheckedListBox() { Dock = DockStyle.Fill, AllowDrop = true, CheckOnClick = true }; classList.AddContextMenu(); ItemCheckEventHandler refreshSelectedClasses = (sender, args) => { // get the list of checked indices, including the possibly not-yet-changed item List <int> checkedIndices = classList.CheckedIndices.Cast <int>().ToList(); if (args != null) { if (args.NewValue == CheckState.Checked) { checkedIndices.Add(args.Index); checkedIndices.Sort(); } else { checkedIndices.Remove(args.Index); } } this.StimulusClass1 = this.StimulusClass2 = null; if (checkedIndices.Count > 0) { this.StimulusClass1 = ((StimulusClassTab)classList.Items[checkedIndices[0]]).StimulusClass; if (checkedIndices.Count > 1) { this.StimulusClass2 = ((StimulusClassTab)classList.Items[checkedIndices[1]]).StimulusClass; } } setImage(); }; Action <string> addClass = path => { StimulusClass stimulusClass; if (!StimulusClass.TryLoad(path, out stimulusClass)) { GUIUtils.Alert("Failed to load stimulus class from " + path, MessageBoxIcon.Error); } else if (this.stimulusClassTabs .Count(tp => tp.StimulusClass.SourceFolder.Equals(path, StringComparison.OrdinalIgnoreCase) || tp.StimulusClass.SavePath.Equals(path, StringComparison.OrdinalIgnoreCase)) > 0) { GUIUtils.Alert("A class from " + path + " is already loaded!", MessageBoxIcon.Exclamation); } else { // get a unique marker unless this was the load of a saved class if (!File.Exists(stimulusClass.SavePath)) { stimulusClass.Settings.Marker = this.stimulusClassTabs.Count == 0 ? 1 : this.stimulusClassTabs.Max(s => s.StimulusClass.Settings.Marker) + 1; } var classTab = new StimulusClassTab(stimulusClass); classTab.TextChanged += (sender, args) => classList.Invalidate(); classTab.Closing += (sender, args) => { this.stimulusClassTabs.Remove(classTab); classList.Items.Remove(classTab); refreshSelectedClasses(classList, null); }; this.stimulusClassTabs.Add(classTab); tabs.TabPages.Add(classTab); classList.Items.Add(classTab, true); refreshSelectedClasses(classList, null); } }; classList.ItemCheck += refreshSelectedClasses; classList.DragEnter += (sender, args) => { if (args.Data.GetDataPresent(DataFormats.FileDrop, false) && ((string[])args.Data.GetData(DataFormats.FileDrop)).Where(StimulusClass.IsValidLoadPath).Count() > 0) { args.Effect = DragDropEffects.All; } }; classList.DragDrop += (sender, args) => { // check that the form is in a valid state var activeTextBox = this.FindForm().ActiveControl as TextBox; if (activeTextBox != null && !activeTextBox.IsValid()) { GUIUtils.Alert("All entered data must be valid in order for drag and drop to be enabled", MessageBoxIcon.Error); return; } string[] data = (string[])args.Data.GetData(DataFormats.FileDrop); foreach (string path in data.Where(StimulusClass.IsValidLoadPath)) { addClass(path); } }; // button table var buttonTable = GUIUtils.CreateButtonTable(Direction.Horizontal, DockStyle.Bottom, GUIUtils.CreateFlatButton("New", b => { if (this.folderDialog.ShowDialog() == DialogResult.OK) { addClass(this.folderDialog.SelectedPath); } }, startTab.ToolTip, "Create a new stimulus class from a folder of images"), GUIUtils.CreateFlatButton("Load", b => { if (this.fileDialog.ShowDialog() == DialogResult.OK) { addClass(this.fileDialog.FileName); } }, startTab.ToolTip, "Load a previously saved stimulus class settings file")); startTab.Closing += (sender, args) => { args.Cancel = true; if (GUIUtils.IsUserSure("Reset stimulus classes?")) { this.stimulusClassTabs.Clear(); this.Controls.Remove(tabs); tabs.Dispose(); timer.Enabled = false; timer.Dispose(); this.BuildView(); this.OnSizeChanged(EventArgs.Empty); } }; // add all controls // left column var panel = new Panel() { Dock = DockStyle.Fill }; panel.Controls.Add(classList); panel.Controls.Add(buttonTable); cols.Controls.Add(panel, 0, 0); // middle column cols.Controls.Add(imageConfig, 1, 0); // right column cols.Controls.Add(imagePanel, 2, 0); startTab.Controls.Add(cols); tabs.Controls.Add(startTab); this.Controls.Add(tabs); this.ResumeLayout(false); }
private void BuildView() { this.SuspendLayout(); this.Text = this.StimulusClass.Settings.Name; var cols = GUIUtils.CreateTable(new double[] { .33, .33, .33 }, Direction.Horizontal); // settings var settingsConfig = new ConfigurationPanel(this.StimulusClass.Settings) { Dock = DockStyle.Fill }; // image panel var imagePanel = new ImagePanel() { Dock = DockStyle.Fill }; // dropdown var dropDown = new ComboBox() { DropDownStyle = ComboBoxStyle.DropDownList, Dock = DockStyle.Bottom }; dropDown.MouseWheel += (sender, args) => ((HandledMouseEventArgs)args).Handled = true; dropDown.Items.Add(new DisplayPointer(() => this.StimulusClass.Settings.Answer1, true)); dropDown.Items.Add(new DisplayPointer(() => this.StimulusClass.Settings.Answer2, false)); dropDown.Items.Add(new DisplayPointer(GUIUtils.Strings.UNCLASSIFIED, null)); // source folder var sourceFolderLink = new LinkLabel() { AutoSize = true, Text = Path.GetFileName(this.StimulusClass.SourceFolder), Dock = DockStyle.Top }; sourceFolderLink.Click += (sender, args) => { try { System.Diagnostics.Process.Start("explorer.exe", this.StimulusClass.SourceFolder); } catch (Exception) { GUIUtils.Alert("Failed to open " + this.StimulusClass.SourceFolder); } }; this.ToolTip.SetToolTip(sourceFolderLink, "Open " + this.StimulusClass.SourceFolder); // image list var imageList = new CheckedListBox() { Dock = DockStyle.Fill }; imageList.AddContextMenu(); foreach (var stimulus in this.StimulusClass.Stimuli) imageList.Items.Add(new StimulusItem(this.StimulusClass, stimulus), stimulus.Used); EventHandler setImage = (sender, args) => { if (imageList.Items.Count > 0) { var stimulus = ((StimulusItem)(imageList.SelectedItem ?? imageList.Items[0])).Stimulus; imagePanel.ImagePath = stimulus.PathOrText; dropDown.Visible = true; switch (stimulus.Subclass) { case true: dropDown.SelectedIndex = 0; break; case false: dropDown.SelectedIndex = 1; break; case null: dropDown.SelectedIndex = 2; break; } } else { imagePanel.ImagePath = null; dropDown.Visible = false; } }; setImage(imageList, EventArgs.Empty); // first set imageList.SelectedIndexChanged += setImage; settingsConfig.PropertyChanged += args => { this.StimulusClass.Settings.SetProperty(args.Property, args.Getter()); this.Text = this.StimulusClass.Settings.Name; imageList.Invalidate(); // force a refresh int selectedIndex = dropDown.SelectedIndex; var items = dropDown.Items.Cast<DisplayPointer>().ToArray(); dropDown.Items.Clear(); dropDown.Items.AddRange(items); dropDown.SelectedIndex = selectedIndex; }; imageList.ItemCheck += (sender, args) => ((StimulusItem)imageList.Items[args.Index]).Stimulus.Used = (args.NewValue == CheckState.Checked); dropDown.SelectedIndexChanged += (sender, args) => { ((StimulusItem)(imageList.SelectedItem ?? imageList.Items[0])).Stimulus.Subclass = (bool?)((DisplayPointer)dropDown.SelectedItem).Key; imageList.Invalidate(); }; this.getSelectedStimulus = () => imageList.SelectedItem == null ? null : ((StimulusItem)imageList.SelectedItem).Stimulus; // selection info label var selectionInfoLabel = new Label() { Dock = DockStyle.Bottom, AutoSize = true }; PaintEventHandler updateSelectionInfoLabel = (sender, args) => { var items = imageList.Items.Cast<StimulusItem>(); selectionInfoLabel.Text = string.Format("{0}/{1} selected", items.Count(s => s.Stimulus.Used), imageList.Items.Count); if (!string.IsNullOrWhiteSpace(this.StimulusClass.Settings.Answer1) || !string.IsNullOrWhiteSpace(this.StimulusClass.Settings.Answer2)) selectionInfoLabel.Text += string.Format(" ({0}/{1} {2}, {3}/{4} {5}, {6}/{7} {8})", items.Count(s => s.Stimulus.Subclass == true && s.Stimulus.Used), items.Count(s => s.Stimulus.Subclass == true), this.StimulusClass.Settings.Answer1, items.Count(s => s.Stimulus.Subclass == false && s.Stimulus.Used), items.Count(s => s.Stimulus.Subclass == false), this.StimulusClass.Settings.Answer2, items.Count(s => s.Stimulus.Subclass == null && s.Stimulus.Used), items.Count(s => s.Stimulus.Subclass == null), GUIUtils.Strings.UNCLASSIFIED); }; imageList.Paint += updateSelectionInfoLabel; updateSelectionInfoLabel(null, null); // button table var buttonTable = GUIUtils.CreateButtonTable(Direction.Horizontal, DockStyle.Bottom, GUIUtils.CreateFlatButton("Classify", b => { MainForm.Instance.Animate(new StimulusClassSetupProvider(this.StimulusClass), this.Invalidate); }, this.ToolTip, "Launch a tool to quickly answer this class's question for all stimuli"), GUIUtils.CreateFlatButton("Refresh", b => { this.StimulusClass.RefreshStimuli(); this.Invalidate(); }, this.ToolTip, "Reload the stimuli from the file system"), GUIUtils.CreateFlatButton("Save", b => { bool saved = this.StimulusClass.TrySave(); GUIUtils.Alert((saved ? "Saved" : "Failed to save") + " stimulus class info to " + this.StimulusClass.SavePath, (saved ? MessageBoxIcon.Information : MessageBoxIcon.Error)); }, this.ToolTip, "Save configuration information to " + this.StimulusClass.SavePath)); // add all controls Panel panel; // left column panel = new Panel() { Dock = DockStyle.Fill }; panel.Controls.Add(settingsConfig); panel.Controls.Add(sourceFolderLink); panel.Controls.Add("Folder".ToLabel()); panel.Controls.Add(buttonTable); cols.Controls.Add(panel, 0, 0); // middle column panel = new Panel() { Dock = DockStyle.Fill }; panel.Controls.Add(imageList); panel.Controls.Add(selectionInfoLabel); panel.Controls.Add("Stimuli".ToLabel()); cols.Controls.Add(panel, 1, 0); // right column panel = new Panel() { Dock = DockStyle.Fill }; panel.Controls.Add(imagePanel); panel.Controls.Add(dropDown); cols.Controls.Add(panel, 2, 0); this.Controls.Add(cols); this.ResumeLayout(false); }
private void BuildView() { this.SuspendLayout(); this.StimulusClass1 = this.StimulusClass2 = null; // tab control var tabs = new CustomTabControl() { Dock = DockStyle.Fill }; tabs.DisplayStyleProvider = new TabStyleVisualStudioProvider(tabs) { ShowTabCloser = true }; tabs.TabClosing += (sender, args) => ((CustomTab)args.TabPage).RaiseClosingSafe(args); // start tab var startTab = new CustomTab() { Text = "Classes" }; // columns var cols = GUIUtils.CreateTable(new double[] { .33, .33, .33 }, Direction.Horizontal); // image config var imageConfig = ConfigurationPanel.Create<ImageDisplaySettings>(); // image panel var imagePanel = new ImagePanel() { Dock = DockStyle.Fill, UseNativeSize = false }; bool cycle = true; var rand = new Random(); Func<StimulusClass, string> getImageForClass = stimulusClass => { var tab = this.stimulusClassTabs.First(t => t.StimulusClass == stimulusClass); if (tab.StimulusClass.Stimuli.Count == 0) return null; if (!((ImageDisplaySettings)imageConfig.GetConfiguredObject()).CycleThroughImages) return (tab.SelectedStimulus ?? tab.StimulusClass.Stimuli.First()).PathOrText; return tab.StimulusClass.Stimuli.ElementAt(rand.Next(tab.StimulusClass.Stimuli.Count)).PathOrText; }; Action setImage = () => { imagePanel.ImagePath = this.StimulusClass1 == null ? null : getImageForClass(this.StimulusClass1); imagePanel.SecondaryImagePath = this.StimulusClass2 == null ? null : getImageForClass(this.StimulusClass2); }; setImage(); var timer = new Timer() { Interval = 2500, Enabled = true }; timer.Tick += (sender, args) => { // just return if we're not cycling to avoid flicker if (!cycle && !timer.Enabled) return; // if the form is valid, set a new image var activeTextBox = this.FindForm().ActiveControl as TextBox; if (activeTextBox == null || activeTextBox.IsValid()) setImage(); }; Action<ImageDisplaySettings> configurePanel = settings => { imagePanel.Configure(settings); if (settings.CycleThroughImages != cycle) { cycle = settings.CycleThroughImages; setImage(); } this.ImageDisplaySettings = settings; }; configurePanel((ImageDisplaySettings)imageConfig.GetConfiguredObject()); imageConfig.PropertyChanged += args => configurePanel((ImageDisplaySettings)imageConfig.GetConfiguredObject()); // class list var classList = new CheckedListBox() { Dock = DockStyle.Fill, AllowDrop = true, CheckOnClick = true }; classList.AddContextMenu(); ItemCheckEventHandler refreshSelectedClasses = (sender, args) => { // get the list of checked indices, including the possibly not-yet-changed item List<int> checkedIndices = classList.CheckedIndices.Cast<int>().ToList(); if (args != null) { if (args.NewValue == CheckState.Checked) { checkedIndices.Add(args.Index); checkedIndices.Sort(); } else checkedIndices.Remove(args.Index); } this.StimulusClass1 = this.StimulusClass2 = null; if (checkedIndices.Count > 0) { this.StimulusClass1 = ((StimulusClassTab)classList.Items[checkedIndices[0]]).StimulusClass; if (checkedIndices.Count > 1) this.StimulusClass2 = ((StimulusClassTab)classList.Items[checkedIndices[1]]).StimulusClass; } setImage(); }; Action<string> addClass = path => { StimulusClass stimulusClass; if (!StimulusClass.TryLoad(path, out stimulusClass)) GUIUtils.Alert("Failed to load stimulus class from " + path, MessageBoxIcon.Error); else if (this.stimulusClassTabs .Count(tp => tp.StimulusClass.SourceFolder.Equals(path, StringComparison.OrdinalIgnoreCase) || tp.StimulusClass.SavePath.Equals(path, StringComparison.OrdinalIgnoreCase)) > 0) GUIUtils.Alert("A class from " + path + " is already loaded!", MessageBoxIcon.Exclamation); else { // get a unique marker unless this was the load of a saved class if (!File.Exists(stimulusClass.SavePath)) stimulusClass.Settings.Marker = this.stimulusClassTabs.Count == 0 ? 1 : this.stimulusClassTabs.Max(s => s.StimulusClass.Settings.Marker) + 1; var classTab = new StimulusClassTab(stimulusClass); classTab.TextChanged += (sender, args) => classList.Invalidate(); classTab.Closing += (sender, args) => { this.stimulusClassTabs.Remove(classTab); classList.Items.Remove(classTab); refreshSelectedClasses(classList, null); }; this.stimulusClassTabs.Add(classTab); tabs.TabPages.Add(classTab); classList.Items.Add(classTab, true); refreshSelectedClasses(classList, null); } }; classList.ItemCheck += refreshSelectedClasses; classList.DragEnter += (sender, args) => { if (args.Data.GetDataPresent(DataFormats.FileDrop, false) && ((string[])args.Data.GetData(DataFormats.FileDrop)).Where(StimulusClass.IsValidLoadPath).Count() > 0) args.Effect = DragDropEffects.All; }; classList.DragDrop += (sender, args) => { // check that the form is in a valid state var activeTextBox = this.FindForm().ActiveControl as TextBox; if (activeTextBox != null && !activeTextBox.IsValid()) { GUIUtils.Alert("All entered data must be valid in order for drag and drop to be enabled", MessageBoxIcon.Error); return; } string[] data = (string[])args.Data.GetData(DataFormats.FileDrop); foreach (string path in data.Where(StimulusClass.IsValidLoadPath)) addClass(path); }; // button table var buttonTable = GUIUtils.CreateButtonTable(Direction.Horizontal, DockStyle.Bottom, GUIUtils.CreateFlatButton("New", b => { if (this.folderDialog.ShowDialog() == DialogResult.OK) addClass(this.folderDialog.SelectedPath); }, startTab.ToolTip, "Create a new stimulus class from a folder of images"), GUIUtils.CreateFlatButton("Load", b => { if (this.fileDialog.ShowDialog() == DialogResult.OK) addClass(this.fileDialog.FileName); }, startTab.ToolTip, "Load a previously saved stimulus class settings file")); startTab.Closing += (sender, args) => { args.Cancel = true; if (GUIUtils.IsUserSure("Reset stimulus classes?")) { this.stimulusClassTabs.Clear(); this.Controls.Remove(tabs); tabs.Dispose(); timer.Enabled = false; timer.Dispose(); this.BuildView(); this.OnSizeChanged(EventArgs.Empty); } }; // add all controls // left column var panel = new Panel() { Dock = DockStyle.Fill }; panel.Controls.Add(classList); panel.Controls.Add(buttonTable); cols.Controls.Add(panel, 0, 0); // middle column cols.Controls.Add(imageConfig, 1, 0); // right column cols.Controls.Add(imagePanel, 2, 0); startTab.Controls.Add(cols); tabs.Controls.Add(startTab); this.Controls.Add(tabs); this.ResumeLayout(false); }