private EEGDataListener GetRawDataRecordingListener() { if (!this.Settings.SaveRawData) { return(null); } StreamWriter writer; try { writer = new StreamWriter( Path.Combine(this.Settings.OutputFolder, GetFileName(RAW_DATA_BASE_NAME, this.startTime, GUIUtils.Strings.CSV_EXTENSION)), false); } catch (Exception) { GUIUtils.Alert("Failed to save raw data to " + this.Settings.OutputFolder, MessageBoxIcon.Warning); return(null); } var invoker = new SingleThreadedInvoker(); return(new EEGDataListener(invoker, null, data => { try { writer.WriteLine(data.ConcatToString(Environment.NewLine)); } catch (Exception) { } }, null, () => { writer.Dispose(); invoker.Dispose(); })); }
/// <summary> /// The enumerator implementation /// </summary> public override IEnumerator <View> GetEnumerator() { IViewResult result; using (var logWriter = new StreamWriter(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "compexp_log_" + settings.SubjectName + DateTime.Now.ToString("MM dd yyyy H mm ss") + ".txt"))) using (var dataWriter = new StreamWriter(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "compexp_" + settings.SubjectName + DateTime.Now.ToString("MM dd yyyy H mm ss") + ".csv"))) { for (int i = 0; i < 2; i++) { yield return(new ChoiceView(new string[] { "Ready for Study Phase" }, out result)); //Present half the stimuli for study for (int j = 0 + i * (presentation.Count / 2); j < (presentation.Count / 2) * (i + 1); j++) { yield return(new TextView(presentation[j], this.settings.PresentationTime, GUIUtils.Constants.DISPLAY_FONT_LARGE)); yield return(new RestView(this.settings.RestTime)); } //Begin the practice phase yield return(new ChoiceView(new string[] { "Start EEG Recording" }, out result) { Text = "Click When Ready" }); var connected = true; // assume it's connected using (var invoker = new SingleThreadedInvoker()) using (var connectionListener = new EEGDataListener(invoker, s => connected = true, null, s => connected = false)) { // listen for a broken connection this.dataSource.AddListener(connectionListener); foreach (var view in this.GetViews(invoker, logWriter, dataWriter, i)) { if (connected) { yield return(view); } else { GUIUtils.Alert("Lost connection to headset!"); break; } } this.dataSource.RemoveListener(connectionListener); } } } }
private TextWriter LogExperimentAndGetLogger() { if (!this.Settings.LogExperiment) { return(null); } try { var writer = new StreamWriter( Path.Combine(this.Settings.OutputFolder, GetFileName(LOG_BASE_NAME, this.startTime, GUIUtils.Strings.TEXT_EXTENSION)), false); writer.WriteLine(string.Format(GUIUtils.Strings.LOGGING_TITLE_FORMAT, "General Settings")); writer.WriteLine(); writer.WriteLine(this.Settings); writer.WriteLine(); writer.WriteLine(string.Format(GUIUtils.Strings.LOGGING_TITLE_FORMAT, "First Stimulus Class")); writer.WriteLine(); writer.WriteLine(this.StimulusClass1); writer.WriteLine(); writer.WriteLine(string.Format(GUIUtils.Strings.LOGGING_TITLE_FORMAT, "Second Stimulus Class")); writer.WriteLine(); writer.WriteLine(this.StimulusClass2); writer.WriteLine(); writer.WriteLine(string.Format(GUIUtils.Strings.LOGGING_TITLE_FORMAT, "Classifiers")); writer.WriteLine(); foreach (var classifier in this.ClassificationSchemes) { writer.WriteLine(classifier); writer.WriteLine(); } writer.WriteLine(string.Format(GUIUtils.Strings.LOGGING_TITLE_FORMAT, "Artifact Detection")); writer.WriteLine(); writer.WriteLine(this.Settings.ArtifactDetectionSettings.UseArtifactDetection ? this.Settings.ArtifactDetectionSettings.PrettyPrint() : "Disabled"); writer.WriteLine(); writer.WriteLine(string.Format(GUIUtils.Strings.LOGGING_TITLE_FORMAT, "Beginning Experiment")); writer.WriteLine(); return(writer); } catch (Exception ex) { GUIUtils.Alert("Failed to log experiment to " + this.Settings.OutputFolder + ": " + ex.Message, MessageBoxIcon.Warning); return(null); } }
//A private method for reading in stimuli, using \n as an indicator of a newline private IArrayView <string> ReadCompetitionStimuli(string path) { try { var lines = File.ReadAllLines(path); var stimuli = lines.Select(s => s.Replace(@"\n", Environment.NewLine)) .ToIArray(); return(stimuli); } catch (Exception) { GUIUtils.Alert("Failed to Read File" + path); return(null); } }
/// <summary> /// Yields a sequence of views that implement the tool /// </summary> public override IEnumerator <View> GetEnumerator() { IViewResult result; // for each image, get the user's input var stimuli = this.stimulusClass.Stimuli.ToIArray(); for (int i = 0; i < stimuli.Count; i++) { yield return(new ClassifyView(stimuli[i], this.stimulusClass, out result)); if (BACK.Equals(result.Value)) { i = Math.Max(-1, i - 2); continue; } if (SKIP.Equals(result.Value)) { continue; } stimuli[i].Subclass = (bool?)result.Value; } // a brief break yield return(new RestView(500)); // offer to save yield return(new ChoiceView(new string[] { SAVE, "Don't Save" }, out result)); // save if (SAVE.Equals(result.Value)) { if (this.stimulusClass.TrySave()) { yield return(new TextView("Results saved to " + this.stimulusClass.SavePath, 2000)); } else { GUIUtils.Alert("Failed to save results to " + this.stimulusClass.SavePath, MessageBoxIcon.Error); } } }
private TextWriter GetTrialWriter() { if (!this.Settings.SaveTrialData) { return(null); } try { return(new StreamWriter( Path.Combine(this.Settings.OutputFolder, GetFileName(DATA_BASE_NAME, this.startTime, GUIUtils.Strings.CSV_EXTENSION)), false)); } catch (Exception) { GUIUtils.Alert("Failed to save trial data to " + this.Settings.OutputFolder, MessageBoxIcon.Warning); return(null); } }
/// <summary> /// Yields the experiment as a sequence of views /// </summary> public override IEnumerator <View> GetEnumerator() { // wait to begin yield return(new ChoiceView(new string[] { "Click anywhere to begin" })); var connected = new VolatileBool(true); // assume it's connected using (var invoker = new SingleThreadedInvoker()) using (var connectionListener = new EEGDataListener(invoker, s => connected.value = true, null, s => connected.value = false)) using (var logger = this.LogExperimentAndGetLogger()) // log the experiment using (var trialLogger = this.GetTrialWriter()) // logs each trial { // create the runtime var runtime = new Runtime(this) { Classifiers = this.ClassificationSchemes.Select(cs => new ClassifierManager(cs)).ToIArray(), Logger = logger, TrialLogger = trialLogger, }; // listen for a broken connection this.DataSource.AddListener(connectionListener); foreach (var view in this.GetViews(runtime)) { if (connected.value) { yield return(view); } else { GUIUtils.Alert(runtime.LogLine("Lost connection to headset!")); break; } } this.DataSource.RemoveListener(connectionListener); } }
private void BuildView(ClassificationScheme classificationScheme) { this.SuspendLayout(); this.Text = classificationScheme.Settings.Name; var table = GUIUtils.CreateTable(new double[] { .33, .33, .33 }, Direction.Horizontal); // classifier var classifierSettings = new DerivedTypeConfigurationPanel(typeof(IClassifier), classificationScheme.Classifier); this.getClassifier = () => (IClassifier)classifierSettings.GetConfiguredObject(); table.Controls.Add(classifierSettings, 0, 0); // general settings var generalSettings = new ConfigurationPanel(classificationScheme.Settings); table.Controls.Add(generalSettings, 1, 0); // bin selection var panel = new Panel() { Dock = DockStyle.Fill }; var binList = new CheckedListBox() { Dock = DockStyle.Fill, CheckOnClick = true }; binList.AddContextMenu(); this.ToolTip.SetToolTip(binList, "Select which time bins from each trial will be used to train the classifier"); var timeBins = GeneralClassifierSettings.MAX_BINS .CountTo() .Select(i => new TimeBin(i) { Checked = classificationScheme.Settings.SelectedBins.Contains(i) }) .ToIArray(); binList.ItemCheck += (sender, args) => ((TimeBin)binList.Items[args.Index]).Checked = (args.NewValue == CheckState.Checked); Action <int> refreshBinList = (binWidth) => { // ensure the right number of items int binCount = GeneralClassifierSettings.GetBinCount(binWidth); if (binList.Items.Count < binCount) { binList.Items.AddRange(timeBins.SubView(binList.Items.Count, binCount - binList.Items.Count).ToArray()); } else { for (int i = binList.Items.Count - 1; i >= binCount; i--) { binList.Items.RemoveAt(i); } } // ensure correct width and uncheck all TimeBin timeBin; for (int i = 0; i < binCount; i++) { timeBin = (TimeBin)binList.Items[i]; timeBin.BinWidth = binWidth; binList.SetItemChecked(i, timeBin.Checked); } binList.Invalidate(); }; refreshBinList(classificationScheme.Settings.BinWidthMillis); var binWidthProp = typeof(GeneralClassifierSettings).GetProperty("BinWidthMillis"); var nameProp = typeof(GeneralClassifierSettings).GetProperty("Name"); if (binWidthProp == null || nameProp == null) { throw new Exception("Failed to find properties!"); } generalSettings.PropertyChanged += args => { if (args.Property.Equals(binWidthProp)) { refreshBinList((int)args.Getter()); } else if (args.Property.Equals(nameProp)) { this.Text = args.Getter().ToString(); } }; this.getSettings = () => { var settings = (GeneralClassifierSettings)generalSettings.GetConfiguredObject(); settings.SelectedBins = binList.CheckedIndices.Cast <int>().ToIArray(); return(settings); }; panel.Controls.Add(binList); panel.Controls.Add("Time Bins".ToLabel()); var saveButton = GUIUtils.CreateFlatButton("Save", (b) => { this.saveDialog.FileName = this.Text; if (this.saveDialog.ShowDialog() != DialogResult.OK) { return; } bool saved = this.ClassificationScheme.TrySerializeToFile(this.saveDialog.FileName); GUIUtils.Alert((saved ? "Saved" : "Failed to save") + " classifier info to " + this.saveDialog.FileName, (saved ? MessageBoxIcon.Information : MessageBoxIcon.Error)); string directory = Path.GetDirectoryName(this.saveDialog.FileName); if (Directory.Exists(directory)) { this.saveDialog.InitialDirectory = directory; } }); saveButton.Dock = DockStyle.Bottom; panel.Controls.Add(saveButton); table.Controls.Add(panel, 2, 0); this.Controls.Add(table); this.ResumeLayout(false); }
/// <summary> /// The enumerator implementation /// </summary> public override IEnumerator <View> GetEnumerator() { IViewResult result; Random numgen = new Random(); RandomizedQueue <StudyTestPair> study = new RandomizedQueue <StudyTestPair>(); RandomizedQueue <StudyTestPair> quiz = new RandomizedQueue <StudyTestPair>(); RandomizedQueue <StudyTestPair> done = new RandomizedQueue <StudyTestPair>(); string filename = "adapt_data_" + settings.SubjectName + "_" + DateTime.Now.ToString("MM dd yyyy H mm ss") + ".csv"; using (var logWriter = new StreamWriter(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "adapt_log_" + settings.SubjectName + "_" + DateTime.Now.ToString("MM dd yyyy H mm ss") + ".txt"))) //If using MATLAB reference, the datawriter path must match the location of your MATLAB code using (var dataWriter = new StreamWriter(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), filename))) { yield return(new ChoiceView(new string[] { "Ready for Training Study Phase" }, out result)); //Present competition stimuli for study for (int j = 0; j < presentation.Count; j++) { yield return(new TextView(presentation[j], this.settings.PresentationTime, GUIUtils.Constants.DISPLAY_FONT_LARGE)); yield return(new RestView(this.settings.RestTime)); } //Begin the practice phase yield return(new ChoiceView(new string[] { "Start Training EEG Recording" }, out result) { Text = "Click When Ready" }); var compconnected = true; // assume it's connected using (var compinvoker = new SingleThreadedInvoker()) using (var compconnectionListener = new EEGDataListener(compinvoker, s => compconnected = true, null, s => compconnected = false)) { // listen for a broken connection this.dataSource.AddListener(compconnectionListener); foreach (var view in this.GetCompViews(compinvoker, logWriter, dataWriter)) { if (compconnected) { yield return(view); } else { GUIUtils.Alert("Lost connection to headset!"); break; } } this.dataSource.RemoveListener(compconnectionListener); } //Check that the person has sufficient training data if (numArt1 > 24 || numArt2 > 24) { yield return(new TextView("Error: Weeping Angel", settings.InstructionTime, GUIUtils.Constants.DISPLAY_FONT_LARGE)); } //MATLAB REFERENCE //matlab.Execute("cd c:\\Users\\Nicole\\Documents\\Matlab\\Thesis\\Adapt"); //matlab.Execute("classifier = wekacomptrain('"+ filename + "');"); yield return(new ChoiceView(new string[] { "Start Study Phase" }, out result) { Text = "Click When Ready" }); while (pres.Count > 0) { var stimulus = pres.RemoveRandom(); yield return(new TextView(stimulus.test + "\n" + stimulus.answer, this.settings.PresentationTime, GUIUtils.Constants.DISPLAY_FONT_LARGE)); yield return(new RestView(this.settings.RestTime)); quiz.Add(stimulus); } yield return(new ChoiceView(new string[] { "Start Test Phase" }, out result) { Text = "Click When Ready" }); var connected = true; // assume it's connected using (var invoker = new SingleThreadedInvoker()) using (var connectionListener = new EEGDataListener(invoker, s => connected = true, null, s => connected = false)) { // listen for a broken connection this.dataSource.AddListener(connectionListener); foreach (var view in this.GetViews(invoker, logWriter, dataWriter, study, quiz, done, numgen)) { if (connected) { yield return(view); } else { GUIUtils.Alert("Lost connection to headset!"); break; } } this.dataSource.RemoveListener(connectionListener); } } }
private void BuildView() { this.SuspendLayout(); var tabs = new CustomTabControl() { Dock = DockStyle.Fill }; tabs.DisplayStyleProvider = new TabStyleVisualStudioProvider(tabs) { ShowTabCloser = true }; tabs.TabClosing += (sender, args) => ((CustomTab)args.TabPage).RaiseClosingSafe(args); var startTab = new CustomTab() { Text = "Classifiers " }; // the ending space is necessary for some reason startTab.Closing += (sender, args) => { args.Cancel = true; if (GUIUtils.IsUserSure("Reset classifiers?")) { this.classifierTabs.Clear(); this.Controls.Remove(tabs); tabs.Dispose(); this.BuildView(); this.OnSizeChanged(EventArgs.Empty); } }; // classifier list var classifierList = new CheckedListBox() { Dock = DockStyle.Fill, CheckOnClick = true }; classifierList.AddContextMenu(); Action <ClassificationScheme> addClassifier = (scheme) => { // get unique name if necessary string baseName = string.IsNullOrWhiteSpace(scheme.Settings.Name) ? "new classifier" : scheme.Settings.Name; if (!this.classifierTabs.Select(ct => ct.Text).Contains(baseName)) { scheme.Settings.Name = baseName; } else { int i = 1; while (this.classifierTabs .Select(ct => ct.Text.ToLower()) .Contains(string.Format("{0} {1}", baseName, i))) { i++; } scheme.Settings.Name = string.Format("{0} {1}", baseName, i); } // create the tab var classifierTab = new ClassificationSchemeTab(scheme); classifierTab.TextChanged += (sender, args) => classifierList.Invalidate(); classifierTab.Closing += (sender, args) => { this.classifierTabs.Remove(classifierTab); classifierList.Items.Remove(classifierTab); }; this.classifierTabs.Add(classifierTab); tabs.TabPages.Add(classifierTab); classifierList.Items.Add(classifierTab, true); }; this.getSelectedClassifiers = () => classifierList.CheckedItems.Cast <ClassificationSchemeTab>().Select(cst => cst.ClassificationScheme).ToIArray(); // buttons var buttonTable = GUIUtils.CreateButtonTable(Direction.Horizontal, DockStyle.Bottom, GUIUtils.CreateFlatButton("New", (b) => { var classifier = classifierList.Items.Count > 0 ? ((ClassificationSchemeTab)(classifierList.SelectedItem ?? classifierList.Items[0])).ClassificationScheme : new ClassificationScheme(); classifier.Settings.Name = string.Empty; addClassifier(classifier); }, startTab.ToolTip, "Create a new classifier"), GUIUtils.CreateFlatButton("Load", (b) => { if (this.openDialog.ShowDialog() != DialogResult.OK) { return; } ClassificationScheme scheme; foreach (var path in this.openDialog.FileNames) { if (Utils.TryDeserializeFile(this.openDialog.FileName, out scheme)) { addClassifier(scheme); } else { GUIUtils.Alert("Failed to load classifier info from " + path, MessageBoxIcon.Error); } } }, startTab.ToolTip, "Load a previously saved classifier settings file")); // artifact detection config var artifactDetectionPanel = new ConfigurationPanel(this.artifactDetection); artifactDetectionPanel.PropertyChanged += args => this.artifactDetection.SetProperty(args.Property, args.Getter()); // artifact detection label var artifactDetectionLabel = new Label() { Dock = DockStyle.Bottom, TextAlign = ContentAlignment.MiddleCenter, Visible = false }; IEnumerable <EEGDataEntry> empty = new EEGDataEntry[0], entries = empty; var listener = new EEGDataListener(GUIUtils.GUIInvoker, source => artifactDetectionLabel.Visible = true, data => { if (!this.artifactDetection.UseArtifactDetection) { artifactDetectionLabel.Visible = false; entries = empty; return; } artifactDetectionLabel.Visible = true; entries = entries.Concat(data); if (data.LastItem().TimeStamp - entries.First().TimeStamp >= 500) { if (this.artifactDetection.HasMotionArtifact(entries)) { artifactDetectionLabel.Text = "Motion artifact detected!"; artifactDetectionLabel.BackColor = Color.Red; artifactDetectionLabel.ForeColor = Color.White; if (this.artifactDetection.Beep) { GUIUtils.GUIInvoker.BeginInvoke(SystemSounds.Beep.Play); } } else { artifactDetectionLabel.Text = "No artifacts detected"; artifactDetectionLabel.BackColor = Color.Green; artifactDetectionLabel.ForeColor = Color.Black; } entries = empty; } }, source => artifactDetectionLabel.Visible = false); // avoid using the gui invoker before the handle has been created this.HandleCreated += (sender, args) => EmotivDataSource.Instance.AddListener(listener); artifactDetectionLabel.Disposed += (sender, args) => { EmotivDataSource.Instance.RemoveListener(listener); listener.Dispose(); }; // right half var rightPanel = new Panel() { Dock = DockStyle.Fill }; rightPanel.Controls.Add(classifierList); rightPanel.Controls.Add(buttonTable); // left half var leftPanel = new Panel() { Dock = DockStyle.Fill }; leftPanel.Controls.Add(artifactDetectionPanel); leftPanel.Controls.Add(artifactDetectionLabel); var cols = GUIUtils.CreateTable(new double[] { .5, .5 }, Direction.Horizontal); cols.Controls.Add(rightPanel, 0, 0); cols.Controls.Add(leftPanel, 1, 0); startTab.Controls.Add(cols); tabs.TabPages.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); }
/// <summary> /// Builds the application view for the Adaptive Application /// </summary> public void BuildAdaptiveView() { this.SuspendLayout(); this.Text = GUIUtils.Strings.APP_NAME; this.Size = new System.Drawing.Size(1500, 750); //Settings panels var config = ConfigurationPanel.Create <AdaptiveSettings>(); //var artifactConfig = ConfigurationPanel.Create<ArtifactDetectionSettings>(); var stimulipanel = new AdaptiveSelectorPanel() { Dock = DockStyle.Fill }; // classifier settings var classifierPanel = new ClassificationSchemePanel() { Dock = DockStyle.Fill }; //Headset Connected? EmotivStatusCheckerPanel statusChecker = new EmotivStatusCheckerPanel() { Dock = DockStyle.Fill }; // start button var startButton = GUIUtils.CreateFlatButton("Start Experiment", b => { var settings = (AdaptiveSettings)config.GetConfiguredObject(); //settings.ArtifactDetectionSettings = (ArtifactDetectionSettings)artifactConfig.GetConfiguredObject(); settings.ArtifactDetectionSettings = (ArtifactDetectionSettings)classifierPanel.ArtifactDetectionSettings; var test = this.ReadAdaptStimuli(stimulipanel.TestFile); var ans = this.ReadAdaptStimuli(stimulipanel.AnsFile); var presentation = this.ReadCompetitionStimuli(stimulipanel.PresentationFile); var class1 = this.ReadCompetitionStimuli(stimulipanel.Class1File); var class2 = this.ReadCompetitionStimuli(stimulipanel.Class2File); //Make study-test pairs for practice phase RandomizedQueue <MCAEmotiv.GUI.Adaptive.StudyTestPair> stp = new RandomizedQueue <MCAEmotiv.GUI.Adaptive.StudyTestPair>(); for (int i = 0; i < test.Count; i++) { stp.Add(new MCAEmotiv.GUI.Adaptive.StudyTestPair(test[i], ans[i], i)); } //To Do: Add a dialog box so that the user knows whether the headset is connected IEEGDataSource dataSource; if (statusChecker.HeadsetConnected) { dataSource = EmotivDataSource.Instance; } else { dataSource = new MockEEGDataSource(); } var classifiers = classifierPanel.SelectedClassifiers; this.Animate(new AdaptiveProvider(stp, presentation, class1, class2, settings, dataSource, classifiers.Where(c => c.Settings.FeatureCount > 0).ToIArray())); }); //Dialog boxes for saving and loading experiment settings var saveDialog = new SaveFileDialog() { Title = "Save experiment settings", Filter = "Experiment settings files|*.adaptsettings", InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) }; var openDialog = new OpenFileDialog() { Title = "Select the saved experiment settings (.adaptsettings) file", Filter = "Experiment settings files|*.adaptsettings", InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), Multiselect = false }; // button table for saving and loading experiment settings var buttonTable = GUIUtils.CreateButtonTable(Direction.Horizontal, DockStyle.Fill, GUIUtils.CreateFlatButton("Save", b => { var settings = (AdaptiveSettings)config.GetConfiguredObject(); settings.TestFile = stimulipanel.TestFile; settings.AnsFile = stimulipanel.AnsFile; settings.PresentationFile = stimulipanel.PresentationFile; settings.Class1File = stimulipanel.Class1File; settings.Class2File = stimulipanel.Class2File; //settings.ArtifactDetectionSettings = (ArtifactDetectionSettings)artifactConfig.GetConfiguredObject(); settings.ArtifactDetectionSettings = (ArtifactDetectionSettings)classifierPanel.ArtifactDetectionSettings; //ISSUE HERE //settings.ClassificationSettings = (ClassificationScheme) classifierPanel saveDialog.FileName = string.IsNullOrWhiteSpace(settings.ExperimentName) ? "my experiment" : settings.ExperimentName; if (saveDialog.ShowDialog() != DialogResult.OK) { return; } bool saved = settings.TrySerializeToFile(saveDialog.FileName); GUIUtils.Alert((saved ? "Saved" : "Failed to save") + " experiment info to " + saveDialog.FileName, (saved ? MessageBoxIcon.Information : MessageBoxIcon.Error)); string directory = Path.GetDirectoryName(saveDialog.FileName); if (Directory.Exists(directory)) { saveDialog.InitialDirectory = directory; } }, null, "Save experiment configuration information"), GUIUtils.CreateFlatButton("Load", b => { if (openDialog.ShowDialog() != DialogResult.OK) { return; } AdaptiveSettings settings; if (Utils.TryDeserializeFile(openDialog.FileName, out settings)) { config.SetConfiguredObject(settings); stimulipanel.TestFile = settings.TestFile; stimulipanel.AnsFile = settings.AnsFile; stimulipanel.PresentationFile = settings.PresentationFile; stimulipanel.Class1File = settings.Class1File; stimulipanel.Class2File = settings.Class2File; //NEED TO DO EACH CLASSIFIERPANEL PROPERTY ONE BY ONE :( //artifactConfig.SetConfiguredObject(settings.ArtifactDetectionSettings); //classifierPanel.SetConfiguredObject(settings.ArtifactDetectionSettings); } else { GUIUtils.Alert("Failed to load experiment info from " + openDialog.FileName, MessageBoxIcon.Error); } }, null, "Load a previously saved experiment settings file")); //Put together the GUI var rows = GUIUtils.CreateTable(new[] { .5, .35, .15 }, Direction.Vertical); var col1 = GUIUtils.CreateTable(new[] { .5, .5 }, Direction.Horizontal); var col2 = GUIUtils.CreateTable(new[] { .5, .5 }, Direction.Horizontal); var col3 = GUIUtils.CreateTable(new[] { .5, .5 }, Direction.Horizontal); //col2.Controls.Add(artifactConfig, 1, 0); col1.Controls.Add(startButton, 1, 0); col1.Controls.Add(statusChecker, 0, 0); col2.Controls.Add(config, 0, 0); col2.Controls.Add(classifierPanel, 1, 0); col3.Controls.Add(stimulipanel, 1, 0); col3.Controls.Add(buttonTable, 0, 0); rows.Controls.Add(col3, 0, 1); rows.Controls.Add(col1, 0, 2); rows.Controls.Add(col2, 0, 0); this.Controls.Add(rows); this.ResumeLayout(false); }
/// <summary> /// Builds the application view for the competition experiment /// </summary> public void BuildCompetitionExperimenterView() { this.SuspendLayout(); this.Text = GUIUtils.Strings.APP_NAME; this.Size = new System.Drawing.Size(1500, 750); //Settings panel var config = ConfigurationPanel.Create <CompetitionExperimentSettings>(); var artifactConfig = ConfigurationPanel.Create <ArtifactDetectionSettings>(); var stimulipanel = new CompetitionClassSelectorPanel() { Dock = DockStyle.Fill }; //Headset Connected? EmotivStatusCheckerPanel statusChecker = new EmotivStatusCheckerPanel() { Dock = DockStyle.Fill }; // start button var startButton = GUIUtils.CreateFlatButton("Start Experiment", b => { var settings = (CompetitionExperimentSettings)config.GetConfiguredObject(); settings.ArtifactDetectionSettings = (ArtifactDetectionSettings)artifactConfig.GetConfiguredObject(); var presentation = this.ReadCompetitionStimuli(stimulipanel.PresentationFile); var class1 = this.ReadCompetitionStimuli(stimulipanel.Class1File); var class2 = this.ReadCompetitionStimuli(stimulipanel.Class2File); if (presentation == null) { return; } //To Do: Add a dialog box so that the user knows whether the headset is connected IEEGDataSource dataSource; if (statusChecker.HeadsetConnected) { dataSource = EmotivDataSource.Instance; } else { dataSource = new MockEEGDataSource(); } this.Animate(new CompetitionExperimentProvider(presentation, class1, class2, settings, dataSource)); }); //Dialog boxes for saving and loading experiment settings var saveDialog = new SaveFileDialog() { Title = "Save experiment settings", Filter = "Experiment settings files|*.compexpsettings", InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) }; var openDialog = new OpenFileDialog() { Title = "Select the saved experiment settings (.compexpsettings) file", Filter = "Experiment settings files|*.compexpsettings", InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), Multiselect = false }; // button table for saving and loading experiment settings var buttonTable = GUIUtils.CreateButtonTable(Direction.Horizontal, DockStyle.Fill, GUIUtils.CreateFlatButton("Save", b => { var settings = (CompetitionExperimentSettings)config.GetConfiguredObject(); settings.PresentationFile = stimulipanel.PresentationFile; settings.Class1File = stimulipanel.Class1File; settings.Class2File = stimulipanel.Class2File; settings.ArtifactDetectionSettings = (ArtifactDetectionSettings)artifactConfig.GetConfiguredObject(); saveDialog.FileName = string.IsNullOrWhiteSpace(settings.ExperimentName) ? "my experiment" : settings.ExperimentName; if (saveDialog.ShowDialog() != DialogResult.OK) { return; } bool saved = settings.TrySerializeToFile(saveDialog.FileName); GUIUtils.Alert((saved ? "Saved" : "Failed to save") + " experiment info to " + saveDialog.FileName, (saved ? MessageBoxIcon.Information : MessageBoxIcon.Error)); string directory = Path.GetDirectoryName(saveDialog.FileName); if (Directory.Exists(directory)) { saveDialog.InitialDirectory = directory; } }, null, "Save experiment configuration information"), GUIUtils.CreateFlatButton("Load", b => { if (openDialog.ShowDialog() != DialogResult.OK) { return; } CompetitionExperimentSettings settings; if (Utils.TryDeserializeFile(openDialog.FileName, out settings)) { config.SetConfiguredObject(settings); stimulipanel.PresentationFile = settings.PresentationFile; stimulipanel.Class1File = settings.Class1File; stimulipanel.Class2File = settings.Class2File; artifactConfig.SetConfiguredObject(settings.ArtifactDetectionSettings); } else { GUIUtils.Alert("Failed to load experiment info from " + openDialog.FileName, MessageBoxIcon.Error); } }, null, "Load a previously saved experiment settings file")); //Put together the GUI var rows = GUIUtils.CreateTable(new[] { .5, .2, .3 }, Direction.Vertical); var col1 = GUIUtils.CreateTable(new[] { .5, .5 }, Direction.Horizontal); var col2 = GUIUtils.CreateTable(new[] { .5, .5 }, Direction.Horizontal); var col3 = GUIUtils.CreateTable(new[] { .5, .5 }, Direction.Horizontal); col2.Controls.Add(artifactConfig, 1, 0); col1.Controls.Add(startButton, 1, 0); col1.Controls.Add(statusChecker, 0, 0); col2.Controls.Add(config, 0, 0); col3.Controls.Add(stimulipanel, 1, 0); col3.Controls.Add(buttonTable, 0, 0); rows.Controls.Add(col3, 0, 1); rows.Controls.Add(col1, 0, 2); rows.Controls.Add(col2, 0, 0); this.Controls.Add(rows); this.ResumeLayout(false); }
/// <summary> /// Builds the application view for the User Control Vocabulary Application /// </summary> public void BuildUserCtrlView() { this.SuspendLayout(); this.Text = GUIUtils.Strings.APP_NAME; this.Size = new System.Drawing.Size(1500, 750); //Settings panel var config = ConfigurationPanel.Create <UserCtrlSettings>(); var stimulipanel = new UserCtrlSelectorPanel() { Dock = DockStyle.Fill }; // start button var startButton = GUIUtils.CreateFlatButton("Start Experiment", b => { var settings = (UserCtrlSettings)config.GetConfiguredObject(); var presentation = this.ReadUserStimuli(stimulipanel.PresentationFile); var test = this.ReadUserStimuli(stimulipanel.TestFile); var ans = this.ReadUserStimuli(stimulipanel.AnsFile); var comp = this.ReadCompetitionStimuli(stimulipanel.CompFile); var class1 = this.ReadCompetitionStimuli(stimulipanel.Class1File); var class2 = this.ReadCompetitionStimuli(stimulipanel.Class2File); //Make study-test pairs for the practice phase RandomizedQueue <MCAEmotiv.GUI.UserControlVocab.StudyTestPair> stp = new RandomizedQueue <MCAEmotiv.GUI.UserControlVocab.StudyTestPair>(); for (int i = 0; i < test.Count; i++) { stp.Add(new MCAEmotiv.GUI.UserControlVocab.StudyTestPair(test[i], ans[i], i)); } if (presentation == null) { return; } this.Animate(new UserCtrlProvider(presentation, comp, class1, class2, stp, settings)); }); //Dialog boxes for saving and loading experiment settings var saveDialog = new SaveFileDialog() { Title = "Save experiment settings", Filter = "Experiment settings files|*.usersettings", InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) }; var openDialog = new OpenFileDialog() { Title = "Select the saved experiment settings (.usersettings) file", Filter = "Experiment settings files|*.usersettings", InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), Multiselect = false }; // button table for saving and loading experiment settings var buttonTable = GUIUtils.CreateButtonTable(Direction.Horizontal, DockStyle.Fill, GUIUtils.CreateFlatButton("Save", b => { var settings = (UserCtrlSettings)config.GetConfiguredObject(); settings.PresentationFile = stimulipanel.PresentationFile; settings.TestFile = stimulipanel.TestFile; settings.AnsFile = stimulipanel.AnsFile; settings.CompFile = stimulipanel.CompFile; settings.Class1File = stimulipanel.Class1File; settings.Class2File = stimulipanel.Class2File; saveDialog.FileName = string.IsNullOrWhiteSpace(settings.ExperimentName) ? "my experiment" : settings.ExperimentName; if (saveDialog.ShowDialog() != DialogResult.OK) { return; } bool saved = settings.TrySerializeToFile(saveDialog.FileName); GUIUtils.Alert((saved ? "Saved" : "Failed to save") + " experiment info to " + saveDialog.FileName, (saved ? MessageBoxIcon.Information : MessageBoxIcon.Error)); string directory = Path.GetDirectoryName(saveDialog.FileName); if (Directory.Exists(directory)) { saveDialog.InitialDirectory = directory; } }, null, "Save experiment configuration information"), GUIUtils.CreateFlatButton("Load", b => { if (openDialog.ShowDialog() != DialogResult.OK) { return; } UserCtrlSettings settings; if (Utils.TryDeserializeFile(openDialog.FileName, out settings)) { config.SetConfiguredObject(settings); stimulipanel.PresentationFile = settings.PresentationFile; stimulipanel.TestFile = settings.TestFile; stimulipanel.AnsFile = settings.AnsFile; stimulipanel.CompFile = settings.CompFile; stimulipanel.Class1File = settings.Class1File; stimulipanel.Class2File = settings.Class2File; } else { GUIUtils.Alert("Failed to load experiment info from " + openDialog.FileName, MessageBoxIcon.Error); } }, null, "Load a previously saved experiment settings file")); //Put together the GUI var rows = GUIUtils.CreateTable(new[] { .5, .35, .15 }, Direction.Vertical); var col3 = GUIUtils.CreateTable(new[] { .5, .5 }, Direction.Horizontal); col3.Controls.Add(stimulipanel, 1, 0); col3.Controls.Add(buttonTable, 0, 0); rows.Controls.Add(col3, 0, 1); rows.Controls.Add(startButton, 0, 2); rows.Controls.Add(config, 0, 0); this.Controls.Add(rows); this.ResumeLayout(false); }
/// <summary> /// Builds the application view for the False Adaptive Application /// </summary> public void BuildFAdaptView() { this.SuspendLayout(); this.Text = GUIUtils.Strings.APP_NAME; this.Size = new System.Drawing.Size(1500, 750); //Settings panels var config = ConfigurationPanel.Create <FalseAdaptSettings>(); var artifactConfig = ConfigurationPanel.Create <ArtifactDetectionSettings>(); var stimulipanel = new FalseAdaptSelectorPanel() { Dock = DockStyle.Fill }; //Headset Connected? EmotivStatusCheckerPanel statusChecker = new EmotivStatusCheckerPanel() { Dock = DockStyle.Fill }; // start button var startButton = GUIUtils.CreateFlatButton("Start Experiment", b => { var settings = (FalseAdaptSettings)config.GetConfiguredObject(); settings.ArtifactDetectionSettings = (ArtifactDetectionSettings)artifactConfig.GetConfiguredObject(); var presentation = this.ReadFAStimuli(stimulipanel.PresentationFile); var comp = this.ReadCompetitionStimuli(stimulipanel.CompFile); var class1 = this.ReadCompetitionStimuli(stimulipanel.Class1File); var class2 = this.ReadCompetitionStimuli(stimulipanel.Class2File); var study = this.ReadUserStimuli(stimulipanel.StudyFile); //Make study-test pairs for practice phase RandomizedQueue <StudyTestTuple> stt = new RandomizedQueue <StudyTestTuple>(); for (int i = 0; i < presentation.Count; i++) { if (presentation[i] == "5") { stt.Add(new StudyTestTuple(presentation[i + 1], presentation[i + 1], true)); } if (presentation[i] == "7") { stt.Add(new StudyTestTuple(presentation[i + 1], presentation[i + 2], false)); } } this.Animate(new FalseAdaptProvider(stt, comp, class1, class2, study, settings)); }); //Dialog boxes for saving and loading experiment settings var saveDialog = new SaveFileDialog() { Title = "Save experiment settings", Filter = "Experiment settings files|*.fasettings", InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) }; var openDialog = new OpenFileDialog() { Title = "Select the saved experiment settings (.fasettings) file", Filter = "Experiment settings files|*.fasettings", InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), Multiselect = false }; // button table for saving and loading experiment settings var buttonTable = GUIUtils.CreateButtonTable(Direction.Horizontal, DockStyle.Fill, GUIUtils.CreateFlatButton("Save", b => { var settings = (FalseAdaptSettings)config.GetConfiguredObject(); settings.PresentationFile = stimulipanel.PresentationFile; settings.StudyFile = stimulipanel.StudyFile; settings.CompFile = stimulipanel.CompFile; settings.Class1File = stimulipanel.Class1File; settings.Class2File = stimulipanel.Class2File; settings.ArtifactDetectionSettings = (ArtifactDetectionSettings)artifactConfig.GetConfiguredObject(); saveDialog.FileName = string.IsNullOrWhiteSpace(settings.ExperimentName) ? "my experiment" : settings.ExperimentName; if (saveDialog.ShowDialog() != DialogResult.OK) { return; } bool saved = settings.TrySerializeToFile(saveDialog.FileName); GUIUtils.Alert((saved ? "Saved" : "Failed to save") + " experiment info to " + saveDialog.FileName, (saved ? MessageBoxIcon.Information : MessageBoxIcon.Error)); string directory = Path.GetDirectoryName(saveDialog.FileName); if (Directory.Exists(directory)) { saveDialog.InitialDirectory = directory; } }, null, "Save experiment configuration information"), GUIUtils.CreateFlatButton("Load", b => { if (openDialog.ShowDialog() != DialogResult.OK) { return; } FalseAdaptSettings settings; if (Utils.TryDeserializeFile(openDialog.FileName, out settings)) { config.SetConfiguredObject(settings); stimulipanel.PresentationFile = settings.PresentationFile; stimulipanel.StudyFile = settings.StudyFile; stimulipanel.CompFile = settings.CompFile; stimulipanel.Class1File = settings.Class1File; stimulipanel.Class2File = settings.Class2File; artifactConfig.SetConfiguredObject(settings.ArtifactDetectionSettings); } else { GUIUtils.Alert("Failed to load experiment info from " + openDialog.FileName, MessageBoxIcon.Error); } }, null, "Load a previously saved experiment settings file")); //Put together the GUI var rows = GUIUtils.CreateTable(new[] { .5, .3, .2 }, Direction.Vertical); var col1 = GUIUtils.CreateTable(new[] { .5, .5 }, Direction.Horizontal); var col2 = GUIUtils.CreateTable(new[] { .5, .5 }, Direction.Horizontal); var col3 = GUIUtils.CreateTable(new[] { .5, .5 }, Direction.Horizontal); col2.Controls.Add(artifactConfig, 1, 0); col1.Controls.Add(startButton, 1, 0); col1.Controls.Add(statusChecker, 0, 0); col2.Controls.Add(config, 0, 0); col3.Controls.Add(stimulipanel, 1, 0); col3.Controls.Add(buttonTable, 0, 0); rows.Controls.Add(col3, 0, 1); rows.Controls.Add(col1, 0, 2); rows.Controls.Add(col2, 0, 0); this.Controls.Add(rows); this.ResumeLayout(false); }
/// <summary> /// The enumerator implementation /// </summary> public override IEnumerator <View> GetEnumerator() { IViewResult result; Random numgen = new Random(); int a, b; RandomizedQueue <string> pres = new RandomizedQueue <string>(); RandomizedQueue <string> usedPres = new RandomizedQueue <string>(); pres.AddRange(presentation); using (var logWriter = new StreamWriter(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "krmon_log_" + settings.SubjectName + "_" + DateTime.Now.ToString("MM dd yyyy H mm ss") + ".txt"))) using (var anslog = new StreamWriter(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "krmon_anslog_" + settings.SubjectName + "_" + DateTime.Now.ToString("MM dd yyyy H mm ss") + ".txt"))) using (var dataWriter = new StreamWriter(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "krmon_data_" + settings.SubjectName + "_" + DateTime.Now.ToString("MM dd yyyy H mm ss") + ".csv"))) { //Alternating Study and Test Phases for (int i = 0; i < settings.NumRounds; i++) { yield return(new ChoiceView(new string[] { "Start Study Phase" }, out result) { Text = "Click When Ready" }); while (pres.Count > 0) { var stimulus = pres.RemoveRandom(); yield return(new TextView(stimulus, this.settings.PresentationTime, GUIUtils.Constants.DISPLAY_FONT_LARGE)); yield return(new RestView(this.settings.RestTime)); usedPres.Add(stimulus); } pres.AddRange(usedPres); usedPres.Clear(); a = numgen.Next(4, 13); b = numgen.Next(4, 13); yield return(new VocabView(string.Format("{0} x {1} = {2}", a, b, a * b), "Verify", settings.DisplayTime, settings.DelayTime, true, anslog, out result)); yield return(new ChoiceView(new string[] { "Start Test Phase" }, out result) { Text = "Click When Ready" }); var connected = true; // assume it's connected using (var invoker = new SingleThreadedInvoker()) using (var connectionListener = new EEGDataListener(invoker, s => connected = true, null, s => connected = false)) { // listen for a broken connection this.dataSource.AddListener(connectionListener); foreach (var view in this.GetViews(invoker, anslog, logWriter, dataWriter, i, pres)) { if (connected) { yield return(view); } else { GUIUtils.Alert("Lost connection to headset!"); break; } } this.dataSource.RemoveListener(connectionListener); } } } }
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); }
/// <summary> /// Builds the application view /// </summary> public void BuildExperimenterView() { this.SuspendLayout(); this.Text = GUIUtils.Strings.APP_NAME; this.Size = new System.Drawing.Size(1500, 750); // experiment settings var experimentPanel = new ExperimentPanel() { Dock = DockStyle.Fill }; // classifier settings var classifierPanel = new ClassificationSchemePanel() { Dock = DockStyle.Fill }; // stimulus class settings var stimulusClassPanel = new StimulusClassPanel() { Dock = DockStyle.Fill }; // status checker var statusChecker = new EmotivStatusCheckerPanel() { Dock = DockStyle.Fill }; // start button var startButton = GUIUtils.CreateFlatButton("Start Experiment", b => { var experimentSettings = experimentPanel.ExperimentSettings; experimentSettings.ImageDisplaySettings = stimulusClassPanel.ImageDisplaySettings; experimentSettings.ArtifactDetectionSettings = classifierPanel.ArtifactDetectionSettings; // check stimulus classes if (stimulusClassPanel.StimulusClass1 == null || stimulusClassPanel.StimulusClass2 == null) { GUIUtils.Alert("Two stimulus classes must be selected", MessageBoxIcon.Error); return; } if (stimulusClassPanel.StimulusClass1.UsedStimuli(experimentSettings.QuestionMode).IsEmpty() || stimulusClassPanel.StimulusClass2.UsedStimuli(experimentSettings.QuestionMode).IsEmpty()) { GUIUtils.Alert("Each stimulus class must have at least one valid stimulus for the selected question mode", MessageBoxIcon.Error); return; } if (stimulusClassPanel.StimulusClass1.Settings.Marker == stimulusClassPanel.StimulusClass2.Settings.Marker) { GUIUtils.Alert("The two selected stimulus classes must have different marker values", MessageBoxIcon.Error); return; } // check classifiers var classifiers = classifierPanel.SelectedClassifiers; foreach (var classifier in classifiers) { if (classifier.Settings.FeatureCount <= 0 && !GUIUtils.IsUserSure("Classifier " + classifier.Settings.Name + " has no features. Continue without this classifier?")) { return; } } // check headset if (!statusChecker.HeadsetConnected && !GUIUtils.IsUserSure("The Emotiv headset is not connected: run experiment with mock headset (generates random data for testing purposes)?")) { return; } this.Animate(new ExperimentProvider(experimentSettings, stimulusClassPanel.StimulusClass1, stimulusClassPanel.StimulusClass2, classifiers.Where(c => c.Settings.FeatureCount > 0).ToIArray(), statusChecker.HeadsetConnected ? EmotivDataSource.Instance : this.mockDataSource ?? (this.mockDataSource = new MockEEGDataSource()))); }); // add all controls var rows = GUIUtils.CreateTable(new double[] { .5, .5 }, Direction.Vertical); // top row var topCols = GUIUtils.CreateTable(new double[] { .25, .75 }, Direction.Horizontal); topCols.Controls.Add(experimentPanel, 0, 0); topCols.Controls.Add(classifierPanel, 1, 0); rows.Controls.Add(topCols, 0, 0); // bottom row var bottomCols = GUIUtils.CreateTable(new double[] { .75, .25 }, Direction.Horizontal); bottomCols.Controls.Add(stimulusClassPanel, 0, 0); var bottomRightTable = GUIUtils.CreateTable(new double[] { .6, .4 }, Direction.Vertical); bottomRightTable.Controls.Add(statusChecker, 0, 0); bottomRightTable.Controls.Add(startButton, 0, 1); bottomCols.Controls.Add(bottomRightTable, 1, 0); rows.Controls.Add(bottomCols, 0, 1); this.Controls.Add(rows); this.ResumeLayout(false); }
private void BuildView() { // config panel var config = ConfigurationPanel.Create <ExperimentSettings>(); // output folder var outputLabel = "Data Output Folder".ToLabel(DockStyle.Bottom); var outputLink = new LinkLabel() { Text = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory), Dock = DockStyle.Bottom }; outputLink.Click += (sender, args) => { if (this.folderDialog.ShowDialog() != DialogResult.OK) { return; } outputLink.Text = this.folderDialog.SelectedPath; }; this.getExperimentSettings = () => { var settings = (ExperimentSettings)config.GetConfiguredObject(); settings.OutputFolder = outputLink.Text; return(settings); }; // button table var buttonTable = GUIUtils.CreateButtonTable(Direction.Horizontal, DockStyle.Bottom, GUIUtils.CreateFlatButton("Save", b => { var settings = this.ExperimentSettings; this.saveDialog.FileName = string.IsNullOrWhiteSpace(settings.ExperimentName) ? "my experiment" : settings.ExperimentName; if (this.saveDialog.ShowDialog() != DialogResult.OK) { return; } bool saved = settings.TrySerializeToFile(this.saveDialog.FileName); GUIUtils.Alert((saved ? "Saved" : "Failed to save") + " experiment info to " + this.saveDialog.FileName, (saved ? MessageBoxIcon.Information : MessageBoxIcon.Error)); string directory = Path.GetDirectoryName(this.saveDialog.FileName); if (Directory.Exists(directory)) { this.saveDialog.InitialDirectory = directory; } }, this.toolTip, "Save experiment configuration information"), GUIUtils.CreateFlatButton("Load", b => { if (this.openDialog.ShowDialog() != DialogResult.OK) { return; } ExperimentSettings settings; foreach (var path in this.openDialog.FileNames) { if (Utils.TryDeserializeFile(this.openDialog.FileName, out settings)) { config.SetConfiguredObject(settings); } else { GUIUtils.Alert("Failed to load experiment info from " + path, MessageBoxIcon.Error); } } }, this.toolTip, "Load a previously saved experiment settings file")); // add all controls this.Controls.Add(config); this.Controls.Add(outputLabel); this.Controls.Add(outputLink); this.Controls.Add(buttonTable); }