Esempio n. 1
0
class ClrForm(object):
    def __init__(self, width=320, height=240, setup=None, teardown=None):
        """
		Creates a .NET Windows Form instance.
		
		:param width: Width of the window
		:param height: Height of the window
		:param setup: Function callback to call when the form has been created
		:param tearmdown: Function delegate to assign to the Form's Closing event
		"""

        from System.Windows.Forms import Application, Form
        from System.Drawing import Size
        self.form = Form(Text="muFAT Test",
                         Size=Size(width, height),
                         MinimizeBox=False,
                         MaximizeBox=False,
                         TopMost=True)
        self.hwnd = self.form.Handle
        if setup is not None:
            setup.__call__()
        if teardown is not None:
            self.form.Closing += teardown
        else:
            self.form.Closing += self.__exit__
        if hasattr(self, 'resized'):
            self.form.ResizeEnd += self.resized

    def __enter__(self):
        """
		Override this function to specify what happens when the form is initialized
		"""
        return self

    def __exit__(self, *args):
        """
		Override this function to specify what happens when the form is closed
		or closing.
		"""
        pass

    def show(self):
        self.form.ShowDialog()

    def close(self):
        self.form.Close()
class ConfirmationDialog():
    '''
    Dialog window for confirming changed stim settings.
    Used when clicking 'Save' on a stim dialog to confirm that
    the user wants to stop the currently-running stimulation.
    '''
    def ShowDialog(self, controller, title, text):
        # set controller
        self.controller = controller

        # create confirmation boolean -- True means the user wants to save
        # the stimulus settings and stop the currently running stimulation.
        self.confirmation = False

        # create the form
        self.dialog_window = Form()
        self.dialog_window.AutoSize = True
        self.dialog_window.Width = 400
        self.dialog_window.MaximumSize = Size(400, 225)
        self.dialog_window.StartPosition = FormStartPosition.CenterScreen
        self.dialog_window.Text = title
        self.dialog_window.FormBorderStyle = FormBorderStyle.FixedSingle

        # create the main panel
        self.panel = FlowLayoutPanel()
        self.panel.Parent = self.dialog_window
        self.panel.BackColor = DIALOG_COLOR
        self.panel.Dock = DockStyle.Top
        self.panel.Padding = Padding(10, 10, 0, 10)
        self.panel.FlowDirection = FlowDirection.TopDown
        self.panel.WrapContents = False
        self.panel.AutoSize = True
        self.panel.Font = BODY_FONT

        # add the dialog text
        dialog_label = Label()
        dialog_label.Parent = self.panel
        dialog_label.Text = text
        dialog_label.Width = self.panel.Width
        dialog_label.AutoSize = True
        dialog_label.Margin = Padding(0, 5, 0, 0)

        # add button panel
        self.add_button_panel()

        # show the dialog
        self.dialog_window.ShowDialog()

        # return the exp name
        return self.confirmation

    def add_button_panel(self):
        # create button panel
        self.button_panel = FlowLayoutPanel()
        self.button_panel.Parent = self.dialog_window
        self.button_panel.BackColor = BUTTON_PANEL_COLOR
        self.button_panel.Dock = DockStyle.Bottom
        self.button_panel.Padding = Padding(10, 0, 10, 10)
        self.button_panel.WrapContents = False
        self.button_panel.AutoSize = True
        self.button_panel.Font = BODY_FONT
        self.button_panel.FlowDirection = FlowDirection.LeftToRight

        # add yes button
        self.yes_button = Button()
        self.yes_button.Parent = self.button_panel
        self.yes_button.Text = "Yes, Stop the Stimulation"
        self.yes_button.Click += self.on_yes_button_click
        self.yes_button.BackColor = BUTTON_COLOR
        self.yes_button.AutoSize = True

        # add cancel button
        self.cancel_button = Button()
        self.cancel_button.Parent = self.button_panel
        self.cancel_button.Text = "Cancel"
        self.cancel_button.Click += self.on_cancel_button_click
        self.cancel_button.BackColor = BUTTON_COLOR
        self.cancel_button.Font = ERROR_FONT
        self.cancel_button.AutoSize = True

        # cancel button is activated when user presses Enter
        self.dialog_window.AcceptButton = self.cancel_button

    def on_yes_button_click(self, sender, event):
        self.confirmation = True

        # close the window
        self.dialog_window.Close()

    def on_cancel_button_click(self, sender, event):
        self.confirmation = False

        # close the window
        self.dialog_window.Close()
Esempio n. 3
0
class StimDialog():
    '''
    Dialog window for setting stim parameters.
    Used when creating or editing a stimulus.
    '''

    def ShowDialog(self, controller, stim_index):
        # set controller
        self.controller = controller

        # initialize success bool
        self.success = False

        # initialize invalid params label
        self.invalid_params_label = None

        # create confirmation dialog
        self.confirmation_dialog = ConfirmationDialog()

        # create a dictionary to save stim parameters for different stim types
        # as the user changes parameters & types of stimuli in this dialog.
        # If the user switches from looming dot to moving dot and back,
        # the previous settings for the looming dot can be restored.
        self.saved_stim_parameters = {}

        if stim_index != None:
            # we are editing an existing stim; get the stim params
            self.i = stim_index
            self.stim_name = self.controller.config_params['stim_list'][self.i]
            self.stim_type = self.controller.config_params['types_list'][self.i]
            self.stim_duration = self.controller.config_params['durations_list'][self.i]
            self.stim_parameters = self.controller.config_params['parameters_list'][self.i]

        else:
            # we are creating a new stim; make new stim params
            self.i = len(self.controller.config_params['stim_list'])
            self.stim_type = 'Looming Dot'
            self.stim_name = self.stim_type
            self.stim_duration = self.controller.default_stim_duration()
            self.stim_parameters = self.controller.default_stim_params(self.stim_type)

            # add the stim to the config params
            self.controller.add_stim(self.stim_name, self.stim_type, self.stim_duration, self.stim_parameters)

        # save a copy of the initial stim params so we can restore them later
        self.saved_stim_parameters[self.stim_type] = self.controller.config_params['parameters_list'][self.i]

        # create the form
        self.dialog_window = Form()
        self.dialog_window.FormBorderStyle = FormBorderStyle.FixedSingle
        self.dialog_window.Text = "{} Parameters".format(self.stim_name)
        self.dialog_window.StartPosition = FormStartPosition.CenterScreen
        self.dialog_window.Width = 400

        # add & populate stim param panel
        self.add_stim_param_panel()
        self.populate_stim_param_panel()

        # add & populate stim choice panel
        self.add_stim_choice_panel()
        self.populate_stim_choice_panel()

        # add save button panel
        self.add_save_button_panel()

        # auto-size the window
        self.dialog_window.AutoSize = True

        # show the dialog
        self.dialog_window.ShowDialog()
        
        # return success boolean
        return self.success

    def add_stim_choice_panel(self):
        # create stim choice panel
        self.stim_choice_panel = FlowLayoutPanel()
        self.stim_choice_panel.Parent = self.dialog_window
        self.stim_choice_panel.BackColor = CHOICE_PANEL_COLOR
        self.stim_choice_panel.Dock = DockStyle.Top
        self.stim_choice_panel.Padding = Padding(10)
        self.stim_choice_panel.FlowDirection = FlowDirection.TopDown
        self.stim_choice_panel.WrapContents = False
        self.stim_choice_panel.AutoSize = True
        self.stim_choice_panel.Font = BODY_FONT

    def populate_stim_choice_panel(self):
        # empty stim choice panel
        list_of_controls = self.stim_choice_panel.Controls
        for control in list_of_controls:
            control.Dispose()
        self.stim_choice_panel.Controls.Clear()

        # add stim choice label
        stim_choice_label = Label()
        stim_choice_label.Parent = self.stim_choice_panel
        stim_choice_label.Text = "Stim:"
        stim_choice_label.AutoSize = True

        # add stim chooser
        self.stim_chooser = ComboBox()
        self.stim_chooser.DropDownStyle = ComboBoxStyle.DropDownList
        self.stim_chooser.Parent = self.stim_choice_panel
        self.stim_chooser.Items.AddRange(("Looming Dot", "Moving Dot", "Combined Dots", "Optomotor Grating", "Grating", "Broadband Grating", "Delay", "Black Flash", "White Flash"))  ##!! need to add option for OKR here
        self.stim_chooser.SelectionChangeCommitted += self.on_stim_choice
        self.stim_chooser.Text = self.stim_type
        self.stim_chooser.Width = self.dialog_window.Width - 40
        self.stim_chooser.AutoSize = True
        self.stim_chooser.Font = BODY_FONT

    def add_stim_param_panel(self):
        # create stim param panel
        self.stim_param_panel = FlowLayoutPanel()
        self.stim_param_panel.Parent = self.dialog_window
        self.stim_param_panel.BackColor = PARAM_PANEL_COLOR
        self.stim_param_panel.Dock = DockStyle.Top
        self.stim_param_panel.Padding = Padding(10)
        self.stim_param_panel.FlowDirection = FlowDirection.TopDown
        self.stim_param_panel.WrapContents = False
        self.stim_param_panel.AutoScroll = True
        self.stim_param_panel.Font = BODY_FONT
        self.stim_param_panel.AutoSize = True
        self.stim_param_panel.MaximumSize = Size(0, 500)

    def populate_stim_param_panel(self):
        # empty stim param panel
        list_of_controls = self.stim_param_panel.Controls
        for control in list_of_controls:
            control.Dispose()
        self.stim_param_panel.Controls.Clear()
        
        # initialize stim param text controls dict
        self.stim_param_textboxes = {}
        self.stim_param_checkboxes = {}

        # add name label & textbox
        add_param_label('Name:', self.stim_param_panel)
        self.name_textbox = TextBox()
        self.name_textbox.Parent = self.stim_param_panel
        self.name_textbox.Text = str(self.stim_name)
        self.name_textbox.AutoSize = True
        self.name_textbox.Width = 300
        self.name_textbox.BackColor = BUTTON_PANEL_COLOR
        self.name_textbox.Font = BODY_FONT

        # add duration label & textbox
        add_param_label('Duration (s):', self.stim_param_panel)
        self.duration_textbox = TextBox()
        self.duration_textbox.Parent = self.stim_param_panel
        self.duration_textbox.Text = str(self.stim_duration)
        self.duration_textbox.AutoSize = True
        self.duration_textbox.Width = 300
        self.duration_textbox.BackColor = BUTTON_PANEL_COLOR
        self.duration_textbox.Font = BODY_FONT

        # add parameters heading label
        if self.stim_type not in ("Delay", "Black Flash", "White Flash"):
            add_heading_label("{} Parameters".format(self.stim_type), self.stim_param_panel)

        # add param labels & textboxes
        if self.stim_type == "Looming Dot":
            self.add_stim_param_to_window('looming_dot_init_x_pos', 'Initial x position (deg)')
            self.add_stim_param_to_window('looming_dot_init_y_pos', 'Initial y position (deg)')
            self.add_stim_param_to_window('l_v', 'l/v (ms)')
            self.add_stim_param_to_window('looming_dot_brightness', 'Dot brightness (0 - 1)') #Will need to change to brightness ie moving dot
            self.add_stim_param_to_window('background_brightness', 'Background brightness (0 - 1)')     #here is the background_brightness problem
            self.add_stim_param_checkbox_to_window('checkered', 'Checkerboard pattern?')     #here is the background_brightness problem
            self.add_stim_param_to_window('num_squares', 'Number of squares in the checkerboard pattern')     #here is the background_brightness problem
            self.add_stim_param_checkbox_to_window('expand_checkered_pattern', 'Expanding checkerboard pattern?')     #here is the background_brightness problem
##            self.add_stim_param_to_window('background', ' Background (0-1)')##Will add option to change background
        elif self.stim_type == "Moving Dot":
            self.add_stim_param_to_window('radius', 'Radius (px)')
            self.add_stim_param_to_window('moving_dot_init_x_pos', 'Initial x position (deg)')
            self.add_stim_param_to_window('moving_dot_init_y_pos', 'Initial y position (deg)')
            self.add_stim_param_to_window('v_x', 'Horiz. velocity (deg/s)')
            self.add_stim_param_to_window('v_y', 'Vertical velocity (deg/s)')
            self.add_stim_param_to_window('moving_dot_brightness', 'Dot brightness (0 - 1)')
            self.add_stim_param_to_window('background_brightness', 'Background brightness (0 - 1)')
        elif self.stim_type == "Combined Dots":
##            ##Looming                     won't allow all of this, needs to fit window
            add_heading_label("Looming Dot Parameters", self.stim_param_panel)
            self.add_stim_param_to_window('looming_dot_init_x_pos', 'Initial x position (deg)')
            self.add_stim_param_to_window('looming_dot_init_y_pos', 'Initial y position (deg)')
            self.add_stim_param_to_window('l_v', 'l/v (ms)')
            self.add_stim_param_to_window('looming_dot_brightness', 'Contrast (0 - 1)') #changed brightness from contrast
            ##moving
            add_heading_label("Moving Dot Parameters", self.stim_param_panel)
            self.add_stim_param_to_window('radius', 'Radius (px)')
            self.add_stim_param_to_window('moving_dot_init_x_pos', 'Initial x position (deg)')
            self.add_stim_param_to_window('moving_dot_init_y_pos', 'Initial y position (deg)')
            self.add_stim_param_to_window('v_x', 'Horiz. velocity (deg/s)')
            self.add_stim_param_to_window('v_y', 'Vertical velocity (deg/s)')
            self.add_stim_param_to_window('moving_dot_brightness', 'Contrast (0 - 1)')
            self.add_stim_param_to_window('background_brightness', 'Background brightness (0-1)')
        elif self.stim_type == "Optomotor Grating":
            self.add_stim_param_to_window('frequency', 'Spatial frequency (1/deg)')
            self.add_stim_param_to_window('merging_pos', 'Converging position (x)')#will need to do something to get x
            self.add_stim_param_to_window('init_phase', 'Initial phase (deg)')
            self.add_stim_param_to_window('velocity', 'Velocity (deg/s)')
            self.add_stim_param_to_window('contrast', 'Contrast (0 - 1)')
            self.add_stim_param_to_window('brightness', 'Brightness (0 - 1)')
            self.add_stim_param_to_window('angle', 'Angle')
        elif self.stim_type in ["Grating", "Broadband Grating"]:
            self.add_stim_param_to_window('frequency', 'Spatial frequency (1/deg)')
            self.add_stim_param_to_window('init_phase', 'Initial phase (deg)')
            self.add_stim_param_to_window('velocity', 'Velocity (deg/s)')
            self.add_stim_param_to_window('contrast', 'Contrast (0 - 1)')
            self.add_stim_param_to_window('brightness', 'Brightness (0 - 1)')
            self.add_stim_param_to_window('angle', 'Angle')
        elif self.stim_type == "White Flash":
            self.add_stim_param_to_window('brightness', 'Brightness (0 - 1)')
        elif self.stim_type in ("Delay", "Black Flash"):
            pass

    def add_stim_param_to_window(self, name, label_text):
        # add param label
        add_param_label(label_text + ':', self.stim_param_panel)

        # add param textbox
        self.stim_param_textboxes[name] = TextBox()
        self.stim_param_textboxes[name].Parent = self.stim_param_panel
        self.stim_param_textboxes[name].Text = str(self.stim_parameters[name])
        self.stim_param_textboxes[name].AutoSize = True
        self.stim_param_textboxes[name].Width = 360
        self.stim_param_textboxes[name].BackColor = TEXTBOX_COLOR
        self.stim_param_textboxes[name].Font = BODY_FONT

    def add_stim_param_checkbox_to_window(self, name, label_text):
        # add param label
        add_param_label(label_text + ':', self.stim_param_panel)

        # add param textbox
        self.stim_param_checkboxes[name] = CheckBox()
        self.stim_param_checkboxes[name].Parent = self.stim_param_panel
        self.stim_param_checkboxes[name].Text = ""
        self.stim_param_checkboxes[name].Checked = self.stim_parameters[name]
        self.stim_param_checkboxes[name].AutoSize = True
        self.stim_param_checkboxes[name].Width = 360
        self.stim_param_checkboxes[name].BackColor = TEXTBOX_COLOR
        self.stim_param_checkboxes[name].Font = BODY_FONT

    def on_stim_choice(self, sender, event):
        # stop the dialog window from refreshing
        self.dialog_window.SuspendLayout()

        # save a copy of the current stim params for the currently selected stim type
        self.stim_param_textbox_values = {key: value.Text for (key, value) in self.stim_param_textboxes.items()}
        self.stim_param_checkbox_values = {key: value.Checked for (key, value) in self.stim_param_checkboxes.items()}
        self.saved_stim_parameters[self.stim_type] = dict({key: float(value) for (key, value) in self.stim_param_textbox_values.items()}.items() + {key: bool(value) for (key, value) in self.stim_param_checkbox_values.items()}.items())

        # get selected stim type
        new_stim_type = self.stim_chooser.SelectedItem.ToString()

        if new_stim_type != self.stim_type:
            # update stim type
            self.stim_type = new_stim_type
            self.stim_name = new_stim_type

            if new_stim_type in self.saved_stim_parameters:
                # we have previously set parameters for this stim type; restore these
                self.stim_parameters = self.saved_stim_parameters[self.stim_type]
            else:
                # create new default stim parameters
                self.stim_parameters = self.controller.default_stim_params(self.stim_type)

            # refresh panel
            self.stim_choice_panel.Refresh()

            self.stim_choice_panel.BackColor = stim_color(self.stim_type)

            # populate stim param panel
            self.populate_stim_param_panel()

            self.name_textbox.Text = self.stim_name

        # allow the dialog window to refresh
        self.dialog_window.ResumeLayout()

    def add_save_button_panel(self):
        # create save button panel
        self.save_button_panel = FlowLayoutPanel()
        self.save_button_panel.Parent = self.dialog_window
        self.save_button_panel.BackColor = BUTTON_PANEL_COLOR
        self.save_button_panel.Dock = DockStyle.Bottom
        self.save_button_panel.Padding = Padding(10)
        self.save_button_panel.WrapContents = False
        self.save_button_panel.AutoSize = True
        self.save_button_panel.Font = BODY_FONT

        # add save button
        self.save_button = Button()
        self.save_button.Parent = self.save_button_panel
        self.save_button.Text = "Save"
        self.save_button.Click += self.on_save_button_click
        self.save_button.BackColor = BUTTON_COLOR
        self.save_button.AutoSize = True

        # save button is activated when user presses Enter
        self.dialog_window.AcceptButton = self.save_button

        # add close button
        self.close_button = Button()
        self.close_button.Parent = self.save_button_panel
        self.close_button.Text = "Cancel"
        self.close_button.DialogResult = DialogResult.Cancel
        self.close_button.BackColor = BUTTON_COLOR
        self.close_button.AutoSize = True

    def on_save_button_click(self, sender, event):
        if self.controller.running_stim:
            confirmation = self.confirmation_dialog.ShowDialog(self.controller, "Stop Current Stimulation?", "Saving these settings will stop the currently-running stimulation. Continue?")
        else:
            confirmation = True

        if confirmation:
            # save stim params
            self.success = self.save_stim_params(sender, event)

            if self.success:
                # saving was successful; close the window
                self.dialog_window.Close()

    def save_stim_params(self, sender, event):
        # stop any running stim
        self.controller.stop_stim()

        # get contents of param textboxes
        self.stim_param_textbox_values = {key: value.Text for (key, value) in self.stim_param_textboxes.items()}
        self.stim_param_checkbox_values = {key: value.Checked for (key, value) in self.stim_param_checkboxes.items()}
        name = self.name_textbox.Text
        duration = self.duration_textbox.Text
        type = self.stim_chooser.SelectedItem.ToString()
        
        if self.are_valid_params(type, self.stim_param_textbox_values) and is_nonnegative_number(duration):
            # the params are valid

            # remove any invalid params text
            self.remove_invalid_params_text()
            
            # create new parameters dicts
            new_stim_params = dict({key: float(value) for (key, value) in self.stim_param_textbox_values.items()}.items() + {key: bool(value) for (key, value) in self.stim_param_checkbox_values.items()}.items())

            # update config params
            self.controller.config_params['stim_list'][self.i] = name
            self.controller.config_params['durations_list'][self.i] = float(duration)
            self.controller.config_params['types_list'][self.i] = type
            self.controller.config_params['parameters_list'][self.i] = new_stim_params

            # save config params
            self.controller.save_config_params()

            # update stim window's params
            if self.controller.stim_window:
                self.controller.stim_window.update_params()

            return True
        else:
            # the params are invalid; add invalid params text
            self.add_invalid_params_text()

            return False

    def are_valid_params(self, stim_type, stim_params):
        # check that all of the params are valid
        if stim_type == "Looming Dot":
            stim_params_are_valid = (is_number(stim_params['looming_dot_init_x_pos'])
                                     and is_number(stim_params['looming_dot_init_y_pos'])
                                     and is_positive_number(stim_params['l_v'])
                                     and is_number_between_0_and_1(stim_params['looming_dot_brightness'])
                                     and is_number_between_0_and_1(stim_params['background_brightness']))
        elif stim_type == "Moving Dot":
            stim_params_are_valid = (is_nonnegative_number(stim_params['radius'])
                                     and is_number(stim_params['moving_dot_init_x_pos'])
                                     and is_number(stim_params['moving_dot_init_y_pos'])
                                     and is_number(stim_params['v_x'])
                                     and is_number(stim_params['v_y'])
                                     and is_number_between_0_and_1(stim_params['moving_dot_brightness'])
                                     and is_number_between_0_and_1(stim_params['background_brightness']))
        elif stim_type == "Combined Dots":
            stim_params_are_valid = (is_nonnegative_number(stim_params['radius'])
                                     and is_number(stim_params['moving_dot_init_x_pos'])
                                     and is_number(stim_params['moving_dot_init_y_pos'])
                                     and is_number(stim_params['v_x'])
                                     and is_number(stim_params['v_y'])
                                     and is_number_between_0_and_1(stim_params['moving_dot_brightness']) 
                                     and is_number(stim_params['looming_dot_init_x_pos']) 
                                     and is_number(stim_params['looming_dot_init_y_pos'])
                                     and is_positive_number(stim_params['l_v'])
                                     and is_number_between_0_and_1(stim_params['looming_dot_brightness'])
                                     and is_number_between_0_and_1(stim_params['background_brightness']))                                    
        elif stim_type == "Optomotor Grating":
            stim_params_are_valid = (is_positive_number(stim_params['frequency'])
                                     and is_nonnegative_number(stim_params['merging_pos'])
                                     and is_number(stim_params['init_phase'])
                                     and is_number(stim_params['velocity'])
                                     and is_number_between_0_and_1(stim_params['contrast'])
                                     and is_number_between_0_and_1(stim_params['brightness'])
                                     and is_number(stim_params['angle']))
        elif stim_type in ["Grating", "Broadband Grating"]:
            stim_params_are_valid = (is_positive_number(stim_params['frequency'])
                                     and is_number(stim_params['init_phase'])
                                     and is_number(stim_params['velocity'])
                                     and is_number_between_0_and_1(stim_params['contrast'])
                                     and is_number_between_0_and_1(stim_params['brightness'])
                                     and is_number(stim_params['angle']))
        elif stim_type == "White Flash":
            stim_params_are_valid = is_number_between_0_and_1(stim_params['brightness'])
        elif stim_type in ("Delay", "Black Flash"):
            stim_params_are_valid = True

        return stim_params_are_valid

    def add_invalid_params_text(self):
        if not self.invalid_params_label:
            # add invalid params label
            self.invalid_params_label = Label()
            self.invalid_params_label.Parent = self.save_button_panel
            self.invalid_params_label.Font = ERROR_FONT
            self.invalid_params_label.Padding = Padding(5)
            self.invalid_params_label.ForeColor = Color.Red
            self.invalid_params_label.AutoSize = True

        # set invalid param label text
        self.invalid_params_label.Text = "Invalid parameters."

    def remove_invalid_params_text(self):
        if self.invalid_params_label:
            # clear invalid param label text
            self.invalid_params_label.Text = ""
Esempio n. 4
0
class TTLDialog():
    '''
    Dialog window for setting TTL pulse parameters.
    '''
    def ShowDialog(self, controller):
        # set controller
        self.controller = controller

        # initialize success bool
        self.success = False

        # initialize invalid params label
        self.invalid_params_label = None

        # get current TTL params
        self.TTL_params = controller.config_params['TTL_params']

        # create the form
        self.dialog_window = Form()
        self.dialog_window.FormBorderStyle = FormBorderStyle.FixedSingle
        self.dialog_window.Text = "TTL Parameters"
        self.dialog_window.StartPosition = FormStartPosition.CenterScreen
        self.dialog_window.Width = 200

        # add & populate TTL param panel
        self.add_TTL_param_panel()
        self.populate_TTL_param_panel()

        # add save button panel
        self.add_save_button_panel()

        # auto-size the window
        self.dialog_window.AutoSize = True

        # show the dialog
        self.dialog_window.ShowDialog()

        # return success boolean
        return self.success

    def add_TTL_param_panel(self):
        # create TTL param panel
        self.TTL_param_panel = FlowLayoutPanel()
        self.TTL_param_panel.Parent = self.dialog_window
        self.TTL_param_panel.BackColor = PARAM_PANEL_COLOR
        self.TTL_param_panel.Dock = DockStyle.Bottom
        self.TTL_param_panel.Padding = Padding(10)
        self.TTL_param_panel.FlowDirection = FlowDirection.TopDown
        self.TTL_param_panel.WrapContents = False
        self.TTL_param_panel.AutoScroll = True
        self.TTL_param_panel.Font = BODY_FONT
        self.TTL_param_panel.AutoSize = True

    def populate_TTL_param_panel(self):
        # initialize TTL param text controls dict
        self.TTL_param_textboxes = {}

        # add heading label
        add_heading_label("TTL Parameters", self.TTL_param_panel)

        # add param labels & textboxes
        self.add_TTL_param_to_window('delay', 'Delay (ms)')
        self.add_TTL_param_to_window('frequency', 'Frequency (Hz)')
        self.add_TTL_param_to_window('pulse_width', 'Pulse width (ms)')
        self.add_TTL_param_to_window('duration', 'Duration (s)')

    def add_TTL_param_to_window(self, name, label_text):
        # add param label
        add_param_label(label_text + ':', self.TTL_param_panel)

        # add param textbox
        self.TTL_param_textboxes[name] = TextBox()
        self.TTL_param_textboxes[name].Parent = self.TTL_param_panel
        self.TTL_param_textboxes[name].Text = str(self.TTL_params[name])
        self.TTL_param_textboxes[name].Width = 150
        self.TTL_param_textboxes[name].BackColor = TEXTBOX_COLOR
        self.TTL_param_textboxes[name].AutoSize = True
        self.TTL_param_textboxes[name].Font = Font(BODY_FONT.FontFamily, 18)

    def add_save_button_panel(self):
        # create save button panel
        self.save_button_panel = FlowLayoutPanel()
        self.save_button_panel.Parent = self.dialog_window
        self.save_button_panel.BackColor = BUTTON_PANEL_COLOR
        self.save_button_panel.Dock = DockStyle.Bottom
        self.save_button_panel.Padding = Padding(10)
        self.save_button_panel.WrapContents = False
        self.save_button_panel.AutoSize = True
        self.save_button_panel.Font = BODY_FONT

        # add save button
        self.save_button = Button()
        self.save_button.Parent = self.save_button_panel
        self.save_button.Text = "Save"
        self.save_button.Click += self.on_save_button_click
        self.save_button.BackColor = BUTTON_COLOR
        self.save_button.AutoSize = True

        # save button is activated when user presses Enter
        self.dialog_window.AcceptButton = self.save_button

        # add close button
        self.close_button = Button()
        self.close_button.Parent = self.save_button_panel
        self.close_button.Text = "Close"
        self.close_button.DialogResult = DialogResult.Cancel
        self.close_button.BackColor = BUTTON_COLOR
        self.close_button.AutoSize = True

    def on_save_button_click(self, sender, event):
        # save TTL params
        self.success = self.save_TTL_params(sender, event)

        if self.success:
            # saving was successful; close the window
            self.dialog_window.Close()

    def save_TTL_params(self, sender, event):
        # get contents of param textboxes
        self.TTL_param_textbox_values = {
            key: value.Text
            for (key, value) in self.TTL_param_textboxes.items()
        }

        if self.are_valid_params(self.TTL_param_textbox_values):
            # the params are valid

            # remove any invalid params text
            self.remove_invalid_params_text()

            # create new parameters dicts
            new_TTL_params = {
                key: float(value)
                for (key, value) in self.TTL_param_textbox_values.items()
            }

            # update controller's TTL params
            self.controller.config_params['TTL_params'] = new_TTL_params

            # save TTL params
            self.controller.save_config_params()

            return True
        else:
            # the params are invalid; add invalid params text
            self.add_invalid_params_text()

            return False

    def are_valid_params(self, TTL_params):
        # check that all of the params are valid
        stim_params_are_valid = (
            is_nonnegative_number(TTL_params['delay'])
            and is_positive_number(TTL_params['frequency'])
            and is_positive_number(TTL_params['pulse_width'])
            and is_positive_number(TTL_params['duration']))

        return stim_params_are_valid

    def add_invalid_params_text(self):
        if not self.invalid_params_label:
            # add invalid params label
            self.invalid_params_label = Label()
            self.invalid_params_label.Parent = self.save_button_panel
            self.invalid_params_label.Font = ERROR_FONT
            self.invalid_params_label.Padding = Padding(5)
            self.invalid_params_label.ForeColor = Color.Red
            self.invalid_params_label.AutoSize = True

        # set invalid param label text
        self.invalid_params_label.Text = "Invalid parameters."

    def remove_invalid_params_text(self):
        if self.invalid_params_label:
            # clear invalid param label text
            self.invalid_params_label.Text = ""
Esempio n. 5
0
class ConfigNameDialog():
    '''
    Dialog window for inputting a configuration name.
    Used when creating or renaming a configuration.
    '''
    def ShowDialog(self, controller, title, text, default_input, config_index):
        # set controller
        self.controller = controller

        # set exp index
        self.config_index = config_index

        # initialize exp name variable
        self.config_name = None

        # initialize invalid name label
        self.invalid_name_label = None

        # create the form
        self.dialog_window = Form()
        self.dialog_window.AutoSize = True
        self.dialog_window.Width = 400
        self.dialog_window.StartPosition = FormStartPosition.CenterScreen
        self.dialog_window.Text = title
        self.dialog_window.MaximumSize = Size(400, 160)
        self.dialog_window.FormBorderStyle = FormBorderStyle.FixedSingle

        # create the main panel
        self.panel = FlowLayoutPanel()
        self.panel.Parent = self.dialog_window
        self.panel.BackColor = DIALOG_COLOR
        self.panel.Dock = DockStyle.Top
        self.panel.Padding = Padding(10, 10, 0, 10)
        self.panel.FlowDirection = FlowDirection.TopDown
        self.panel.WrapContents = False
        self.panel.AutoSize = True
        self.panel.Font = BODY_FONT

        # add the dialog text
        config_name_label = Label()
        config_name_label.Parent = self.panel
        config_name_label.Text = text
        config_name_label.Width = self.panel.Width
        config_name_label.AutoSize = True
        config_name_label.Margin = Padding(0, 5, 0, 0)

        # add the textbox
        self.config_name_box = TextBox()
        self.config_name_box.Text = default_input
        self.config_name_box.Parent = self.panel
        self.config_name_box.Width = self.dialog_window.Width - 30
        self.config_name_box.AutoSize = True
        self.config_name_box.BackColor = BUTTON_PANEL_COLOR
        self.config_name_box.Font = Font(BODY_FONT.FontFamily, 9)

        # add save button panel
        self.add_save_button_panel()

        # show the dialog
        self.dialog_window.ShowDialog()

        # return the config name
        return self.config_name

    def add_save_button_panel(self):
        # create save button panel
        self.save_button_panel = FlowLayoutPanel()
        self.save_button_panel.Parent = self.dialog_window
        self.save_button_panel.BackColor = BUTTON_PANEL_COLOR
        self.save_button_panel.Dock = DockStyle.Bottom
        self.save_button_panel.Padding = Padding(10, 0, 10, 10)
        self.save_button_panel.WrapContents = False
        # self.save_button_panel.Height = 40
        self.save_button_panel.Font = BODY_FONT
        self.save_button_panel.FlowDirection = FlowDirection.LeftToRight
        self.save_button_panel.AutoSize = True

        # add save button
        self.save_button = Button()
        self.save_button.Parent = self.save_button_panel
        self.save_button.Text = "Save"
        self.save_button.Click += self.on_save_button_click
        self.save_button.BackColor = BUTTON_COLOR
        self.save_button.AutoSize = True

        # save button is activated when user presses Enter
        self.dialog_window.AcceptButton = self.save_button

    def on_save_button_click(self, sender, event):
        # get what's in the text box
        config_name = self.config_name_box.Text

        if self.config_index == None:
            # we are creating a new config; check if none of the existing configs have the same name
            success = not (config_name
                           in self.controller.configs['configs_list'])
        else:
            # we are renaming an config; check if none of the other configs have the same name
            other_configs = [
                exp for exp in self.controller.configs['configs_list']
                if not exp == "config_name"
            ]
            success = not (config_name in other_configs)

        if success:
            # the exp name is valid; set exp name & close the window
            self.config_name = config_name
            self.dialog_window.Close()
        else:
            # the exp name is invalid; add invalid name text
            self.add_invalid_name_text()

    def add_invalid_name_text(self):
        if not self.invalid_name_label:
            # add invalid name label
            self.invalid_name_label = Label()
            self.invalid_name_label.Parent = self.save_button_panel
            self.invalid_name_label.Font = ERROR_FONT
            self.invalid_name_label.Padding = Padding(5)
            self.invalid_name_label.ForeColor = Color.Red
            self.invalid_name_label.AutoSize = True

        # set invalid name label text
        self.invalid_name_label.Text = "Config name is taken."

    def remove_invalid_name_text(self):
        if self.invalid_name_label:
            # clear invalid name label text
            self.invalid_name_label.Text = ""