Example #1
0
def format_choices(choices, uniformat=True, si=None):
    """ Transform the given choices into an ordered list of (value, formatted value) tuples

    Args:
        choices (Iterable): The choices to be formatted or None
        uniformat (bool): If True, all the values will be formatted using the same SI prefix
        si (bool): si unit to format the choice values to.
          This argument takes precedence over the `uniformat` argument.

    Returns:
        ([(value, formatted value)], si prefix) or (None, None)

    """

    if choices:
        choices_si_prefix = None

        # choice_fmt is an iterable of tuples: (choice, formatted choice)
        if isinstance(choices, dict):
            # In this case we assume that the values are already formatted
            choices_formatted = choices.items()
        elif si is not None:
            fmt, choices_si_prefix = utun.si_scale_list(choices, si)
            choices_formatted = zip(choices, [u"%g" % c for c in fmt])
        elif len(choices) > 1 and all([isinstance(c, numbers.Real) for c in choices]):
            try:
                # TODO: does it matter? Can't we always do non-uniform?
                # Or just guess based on the magnitude between the lowest and biggest value?
                if uniformat:
                    fmt, choices_si_prefix = utun.si_scale_list(choices)
                    choices_formatted = zip(choices, [u"%g" % c for c in fmt])
                else:
                    fmt = []
                    for choice in choices:
                        fmt.append(to_string_si_prefix(choice))
                    return zip(choices, fmt), choices_si_prefix
            except Exception:
                logging.exception("Formatting error!")
                choices_formatted = [(c, choice_to_str(c)) for c in choices]
        else:
            choices_formatted = [(c, choice_to_str(c)) for c in choices]

        if not isinstance(choices, OrderedDict):
            choices_formatted = sorted(choices_formatted)

        return choices_formatted, choices_si_prefix

    else:
        return None, None
Example #2
0
def format_axis_choices(name, axis_def):
    """
    Transform the given choices for an axis into an user friendly display

    name (str): the name of the axis
    axis_def (Axis): the axis definition

    returns:
      choices_formatted (None or list of (value, str): axis value/user-friendly
         display name (including the unit). None if axis doesn't support choices.
    """

    try:
        choices = axis_def.choices
    except AttributeError:
        return None

    if not choices:
        return None

    unit = axis_def.unit

    if isinstance(choices, dict):
        choices_formatted = list(choices.items())
        # In this case, normally the values are already formatted, but for
        # wavelength band, the "formatted" value is still a band info (ie, two
        # values in m)
        if name == "band":

            def to_readable_band(v):
                if (isinstance(v, (tuple, list)) and len(v) > 1 and
                        all(isinstance(c, numbers.Real) for c in v)):
                    return fluo.to_readable_band(v)
                else:
                    return v

            choices_formatted = [(k, to_readable_band(v)) for k, v in choices_formatted]
    elif len(choices) > 1 and all(isinstance(c, numbers.Real) for c in choices):
        choices_formatted = None
        try:
            choices = sorted(choices)
            # Can we fit them (more or less) all with the same unit prefix?
            mn_non0 = min(c for c in choices if c != 0)
            if abs(choices[-1] / mn_non0) < 1000:
                fmt, choices_si_prefix = utun.si_scale_list(choices)
                fmt = [utun.to_string_pretty(c, 3, unit) for c in fmt]
                choices_formatted = list(zip(choices, fmt))
        except Exception:
            logging.exception("Formatting error for %s", choices)
        if choices_formatted is None:
            choices_formatted = [(c, readable_str(c, unit=unit, sig=3)) for c in choices]
    else:
        choices_formatted = [(c, u"%s %s" % (choice_to_str(c), unit)) for c in choices]

    if not isinstance(choices, OrderedDict):
        # sort 2-tuples = according to first value in tuple
        choices_formatted = sorted(choices_formatted)

    return choices_formatted
Example #3
0
def format_axis_choices(name, axis_def):
    """
    Transform the given choices for an axis into an user friendly display

    name (str): the name of the axis
    axis_def (Axis): the axis definition

    returns:
      choices_formatted (None or list of (value, str): axis value/user-friendly
         display name (including the unit). None if axis doesn't support choices.
    """

    try:
        choices = axis_def.choices
    except AttributeError:
        return None

    if not choices:
        return None

    unit = axis_def.unit

    if isinstance(choices, dict):
        choices_formatted = choices.items()
        # In this case, normally the values are already formatted, but for
        # wavelength band, the "formatted" value is still a band info (ie, two
        # values in m)
        if name == "band":

            def to_readable_band(v):
                if (isinstance(v, (tuple, list)) and len(v) > 1 and
                        all(isinstance(c, numbers.Real) for c in v)):
                    return fluo.to_readable_band(v)
                else:
                    return v

            choices_formatted = [(k, to_readable_band(v)) for k, v in choices_formatted]
    elif len(choices) > 1 and all(isinstance(c, numbers.Real) for c in choices):
        choices_formatted = None
        try:
            choices = sorted(choices)
            # Can we fit them (more or less) all with the same unit prefix?
            mn_non0 = min(c for c in choices if c != 0)
            if abs(choices[-1] / mn_non0) < 1000:
                fmt, choices_si_prefix = utun.si_scale_list(choices)
                fmt = [utun.to_string_pretty(c, 3, unit) for c in fmt]
                choices_formatted = zip(choices, fmt)
        except Exception:
            logging.exception("Formatting error for %s", choices)
        if choices_formatted is None:
            choices_formatted = [(c, readable_str(c, unit=unit, sig=3)) for c in choices]
    else:
        choices_formatted = [(c, u"%s %s" % (choice_to_str(c), unit)) for c in choices]

    if not isinstance(choices, OrderedDict):
        # sort 2-tuples = according to first value in tuple
        choices_formatted = sorted(choices_formatted)

    return choices_formatted
Example #4
0
def format_choices(choices):
    """ Transform the given choices into an ordered list of (value, formatted value) tuples

    Args:
        choices (Iterable): The choices to be formatted or None

    Returns:
        ([(value, formatted value)], si prefix) or (None, None)

    """

    if choices:
        choices_si_prefix = None

        # choice_fmt is an iterable of tuples: (choice, formatted choice)
        if isinstance(choices, dict):
            # In this case we assume that the values are already formatted
            choices_formatted = choices.items()
        elif len(choices) > 1 and all(isinstance(c, numbers.Real) for c in choices):
            try:
                choices = sorted(choices)
                # Can we fit them (more or less) all with the same unit prefix?
                mn_non0 = min(c for c in choices if c != 0)
                if abs(choices[-1] / mn_non0) < 1000:
                    fmt, choices_si_prefix = utun.si_scale_list(choices)
                    fmt = [utun.to_string_pretty(c, 3) for c in fmt]
                    choices_formatted = zip(choices, fmt)
                else:
                    fmt = [to_string_si_prefix(c, sig=3) for c in choices]
                    return zip(choices, fmt), None
            except Exception:
                logging.exception("Formatting error for %s", choices)
                choices_formatted = [(c, choice_to_str(c)) for c in choices]
        else:
            choices_formatted = [(c, choice_to_str(c)) for c in choices]

        if not isinstance(choices, OrderedDict):
            choices_formatted = sorted(choices_formatted)

        return choices_formatted, choices_si_prefix

    else:
        return None, None
Example #5
0
def format_choices(choices):
    """ Transform the given choices into an ordered list of (value, formatted value) tuples

    Args:
        choices (Iterable): The choices to be formatted or None

    Returns:
        ([(value, formatted value)], si prefix) or (None, None)

    """

    if choices:
        choices_si_prefix = None

        # choice_fmt is an iterable of tuples: (choice, formatted choice)
        if isinstance(choices, dict):
            # In this case we assume that the values are already formatted
            choices_formatted = choices.items()
        elif len(choices) > 1 and all(isinstance(c, numbers.Real) for c in choices):
            try:
                choices = sorted(choices)
                # Can we fit them (more or less) all with the same unit prefix?
                mn_non0 = min(c for c in choices if c != 0)
                if abs(choices[-1] / mn_non0) < 1000:
                    fmt, choices_si_prefix = utun.si_scale_list(choices)
                    fmt = [utun.to_string_pretty(c, 3) for c in fmt]
                    choices_formatted = zip(choices, fmt)
                else:
                    fmt = [to_string_si_prefix(c, sig=3) for c in choices]
                    return zip(choices, fmt), None
            except Exception:
                logging.exception("Formatting error for %s", choices)
                choices_formatted = [(c, choice_to_str(c)) for c in choices]
        else:
            choices_formatted = [(c, choice_to_str(c)) for c in choices]

        if not isinstance(choices, OrderedDict):
            choices_formatted = sorted(choices_formatted)

        return choices_formatted, choices_si_prefix

    else:
        return None, None
Example #6
0
def create_axis_entry(container, name, comp, conf=None):
    # If no conf provided, set it to an empty dictionary
    conf = conf or {}

    # Format label
    label_text = conf.get('label', label_to_human(name))
    tooltip = conf.get('tooltip', "")

    logging.debug("Adding Axis control %s", label_text)

    ad = comp.axes[name]
    pos = comp.position.value[name]
    unit = ad.unit

    # If axis has .range (continuous) => slider
    # If axis has .choices (enumerated) => combo box
    if hasattr(ad, "range"):
        if "range" in conf:
            minv, maxv = conf["range"]
        else:
            minv, maxv = ad.range

        ctrl_conf = {
            'min_val': minv,
            'max_val': maxv,
            'unit': unit,
            'accuracy': conf.get('accuracy', 3),
        }

        lbl_ctrl, value_ctrl = container.add_float_slider(label_text, pos, ctrl_conf)

        # don't bind to wx.EVT_SLIDER, which happens as soon as the slider moves,
        # but to EVT_SCROLL_CHANGED, which happens when the user has made his
        # mind. This avoid too many unnecessary actuator moves and disabling the
        # widget too early.
        axis_entry = AxisSettingEntry(name, comp, lbl_ctrl=lbl_ctrl, value_ctrl=value_ctrl,
                                      events=wx.EVT_SCROLL_CHANGED)
    else:
        # FIXME: should be readonly, but it fails with GetInsertionPoint (wx.CB_READONLY)
        lbl_ctrl, value_ctrl = container.add_combobox_control(label_text)

        # format the choices
        choices = ad.choices

        if isinstance(choices, dict):
            # it's then already value -> string (user-friendly display)
            choices_fmt = choices.items()
            unit = None
        elif (unit and len(choices) > 1 and
              all([isinstance(c, numbers.Real) for c in choices])):
            # TODO: need same update as add_value
            fmt, prefix = utun.si_scale_list(choices)
            choices_fmt = zip(choices, [u"%g" % c for c in fmt])
            unit = prefix + unit
        else:
            choices_fmt = [(c, choice_to_str(c)) for c in choices]

        choices_fmt = sorted(choices_fmt) # sort 2-tuples = according to first value in tuple

        # FIXME: Is this still needed?
        def _eat_event(evt):
            """ Quick and dirty empty function used to 'eat' mouse wheel events """
            pass
        value_ctrl.Bind(wx.EVT_MOUSEWHEEL, _eat_event)

        # Set choices
        if unit is None:
            unit = ""
        for choice, formatted in choices_fmt:
            value_ctrl.Append(u"%s %s" % (formatted, unit), choice)

        # A small wrapper function makes sure that the value can
        # be set by passing the actual value (As opposed to the text label)
        def cb_set(value, ctrl=value_ctrl, unit=unit):
            for i in range(ctrl.Count):
                if ctrl.GetClientData(i) == value:
                    logging.debug("Setting ComboBox value to %s", ctrl.Items[i])
                    return ctrl.SetValue(ctrl.Items[i])
            else:
                logging.warning("No existing label found for value %s", value)
                return ctrl.GetValue()

        # equivalent wrapper function to retrieve the actual value
        def cb_get(ctrl=value_ctrl, name=name):
            value = ctrl.GetValue()
            # Try to use the predefined value if it's available
            for i in range(ctrl.Count):
                if ctrl.Items[i] == value:
                    logging.debug("Getting CB value %s", ctrl.GetClientData(i))
                    return ctrl.GetClientData(i)
            else:
                logging.error("Failed to find value %s for axis %s", value, name)

        axis_entry = AxisSettingEntry(name, comp, lbl_ctrl=lbl_ctrl, value_ctrl=value_ctrl,
                                      pos_2_ctrl=cb_set, ctrl_2_pos=cb_get,
                                      events=(wx.EVT_COMBOBOX, wx.EVT_TEXT_ENTER))

    value_ctrl.SetToolTipString(tooltip)
    lbl_ctrl.SetToolTipString(tooltip)

    return axis_entry
Example #7
0
def create_axis_entry(container, name, comp, conf=None):
    # If no conf provided, set it to an empty dictionary
    conf = conf or {}

    # Format label
    label_text = conf.get('label', label_to_human(name))
    tooltip = conf.get('tooltip', "")

    logging.debug("Adding Axis control %s", label_text)

    ad = comp.axes[name]
    pos = comp.position.value[name]
    unit = ad.unit

    # Determine control type
    try:
        control_type = conf['control_type']
    except KeyError:
        # If axis has .range (continuous) => slider
        # If axis has .choices (enumerated) => combo box
        if hasattr(ad, "range"):
            control_type = odemis.gui.CONTROL_SLIDER
        else:
            control_type = odemis.gui.CONTROL_COMBO

    if callable(control_type):
        control_type = control_type(comp, name, conf)

    if control_type == odemis.gui.CONTROL_SLIDER:
        if "range" in conf:
            minv, maxv = conf["range"]
        else:
            minv, maxv = ad.range

        ctrl_conf = {
            'min_val': minv,
            'max_val': maxv,
            'unit': unit,
            'accuracy': conf.get('accuracy', 3),
        }

        lbl_ctrl, value_ctrl = container.add_float_slider(label_text, pos, ctrl_conf)

        # don't bind to wx.EVT_SLIDER, which happens as soon as the slider moves,
        # but to EVT_SCROLL_CHANGED, which happens when the user has made his
        # mind. This avoid too many unnecessary actuator moves and disabling the
        # widget too early.
        axis_entry = AxisSettingEntry(name, comp, lbl_ctrl=lbl_ctrl, value_ctrl=value_ctrl,
                                      events=wx.EVT_SCROLL_CHANGED)
    elif control_type == odemis.gui.CONTROL_FLT:
        if "range" in conf:
            minv, maxv = conf["range"]
        else:
            minv, maxv = ad.range

        ctrl_conf = {
            'min_val': minv,
            'max_val': maxv,
            'unit': unit,
            'accuracy': conf.get('accuracy', 3),
        }

        lbl_ctrl, value_ctrl = container.add_float_field(label_text, conf=ctrl_conf)
        axis_entry = AxisSettingEntry(name, comp, lbl_ctrl=lbl_ctrl, value_ctrl=value_ctrl,
                                      events=wx.EVT_COMMAND_ENTER)

    elif control_type == odemis.gui.CONTROL_COMBO:
        # FIXME: should be readonly, but it fails with GetInsertionPoint (wx.CB_READONLY)
        lbl_ctrl, value_ctrl = container.add_combobox_control(label_text)

        # format the choices
        choices = ad.choices

        if isinstance(choices, dict):
            # it's then already value -> string (user-friendly display)
            choices_fmt = choices.items()
            unit = None
        elif (unit and len(choices) > 1 and
              all([isinstance(c, numbers.Real) for c in choices])):
            # TODO: need same update as add_value
            fmt, prefix = utun.si_scale_list(choices)
            choices_fmt = zip(choices, [u"%g" % c for c in fmt])
            unit = prefix + unit
        else:
            choices_fmt = [(c, choice_to_str(c)) for c in choices]

        choices_fmt = sorted(choices_fmt) # sort 2-tuples = according to first value in tuple

        # Set choices
        if unit is None:
            unit = ""
        for choice, formatted in choices_fmt:
            value_ctrl.Append(u"%s %s" % (formatted, unit), choice)

        # A small wrapper function makes sure that the value can
        # be set by passing the actual value (As opposed to the text label)
        def cb_set(value, ctrl=value_ctrl, unit=unit):
            for i in range(ctrl.Count):
                if ((isinstance(value, float) and util.almost_equal(ctrl.GetClientData(i), value)) or
                    ctrl.GetClientData(i) == value):
                    logging.debug("Setting ComboBox value to %s", ctrl.Items[i])
                    ctrl.SetSelection(i)
                    break
            else:
                logging.warning("No existing label found for value %s", value)
                # entering value as free text
                txt = readable_str(value, unit)
                ctrl.SetValue(txt)

        # equivalent wrapper function to retrieve the actual value
        def cb_get(ctrl=value_ctrl, name=name):
            value = ctrl.GetValue()
            # Try to use the predefined value if it's available
            i = ctrl.GetSelection()

            # Warning: if the text contains an unknown value, GetSelection will
            # not return wx.NOT_FOUND (as expected), but the last selection value
            if i != wx.NOT_FOUND and ctrl.Items[i] == value:
                logging.debug("Getting item value %s from combobox control",
                              ctrl.GetClientData(i))
                return ctrl.GetClientData(i)
            else:
                logging.error("Failed to find value %s for axis %s", value, name)

        axis_entry = AxisSettingEntry(name, comp, lbl_ctrl=lbl_ctrl, value_ctrl=value_ctrl,
                                      pos_2_ctrl=cb_set, ctrl_2_pos=cb_get,
                                      events=(wx.EVT_COMBOBOX, wx.EVT_TEXT_ENTER))
    else:
        logging.error("Unknown control type %s", control_type)

    value_ctrl.SetToolTipString(tooltip)
    lbl_ctrl.SetToolTipString(tooltip)

    return axis_entry