예제 #1
0
class TagView(Group):

    nsViewClass = FGTagView
    tag = delegateProperty("_nsObject")
    state = delegateProperty("_nsObject")
    _callback = weakrefCallbackProperty()

    def __init__(self, posSize, tag, state, callback=None):
        super().__init__(posSize)
        self.tag = tag
        self.state = state
        self._callback = callback

    def _callCallback(self):
        callback = self._callback
        if callback is not None:
            callback(self)
예제 #2
0
class FeatureTagGroup(Group):

    _callback = weakrefCallbackProperty()

    def __init__(self, width, tagGroups, callback=None):
        posSize = (0, 0, width, 50)  # dummy height
        super().__init__(posSize)
        self._callback = callback
        self._state = {}
        self.setTags(tagGroups, {})

    def _breakCycles(self):
        del self._callback
        super()._breakCycles()

    def setTags(self, tagGroups, stylisticSetNames):
        # clear all subviews
        for attr, value in list(self.__dict__.items()):
            if isinstance(value, VanillaBaseObject):
                delattr(self, attr)
        self._titles = list(tagGroups)
        self._tagIdentifiers = defaultdict(list)
        margin = 10
        tagWidth = 60
        y = margin
        tagCounter = 0
        for title, tags in tagGroups.items():
            titleLabel = TextBox((margin, y, -margin, 20), title)
            setattr(self, f"label_{title}", titleLabel)
            y += 24
            for tag in sorted(tags):
                tagView = TagView((margin, y, tagWidth, 20),
                                  tag,
                                  None,
                                  callback=self._tagStateChanged)
                names = stylisticSetNames.get(tag)
                if names:
                    if len(names) == 1:
                        description = next(iter(names))
                    else:
                        description = "<multiple names>"
                else:
                    description = features.get(tag, ["<unknown>"])[0]
                friendlyName = TextBox(
                    (margin + tagWidth + 6, y + 1, -margin, 20), description)
                friendlyName._nsObject.cell().setLineBreakMode_(
                    AppKit.NSLineBreakByTruncatingTail)
                tagIdentifier = f"tag_{title}_{tag}"
                self._tagIdentifiers[tag].append(tagIdentifier)
                setattr(self, tagIdentifier, tagView)
                setattr(self, f"friendlyName_{title}_{tag}", friendlyName)
                tagCounter += 1
                y += 26
            y += 6
        posSize = (0, 0, self.getPosSize()[2], y)
        self.setPosSize(posSize)
        self._updateState()

    def _tagStateChanged(self, tagView):
        tag = tagView.tag
        state = tagView.state
        # if a tag occurs in more than one group, reflect the new state
        for tagIdentifier in self._tagIdentifiers[tag]:
            otherTagView = getattr(self, tagIdentifier)
            if otherTagView is not tagView:
                otherTagView.state = state
        if state is None:
            self._state.pop(tag, None)
        else:
            self._state[tag] = state
        callback = self._callback
        if callback is not None:
            callback(self)

    def get(self):
        return dict(self._state)

    def _updateState(self):
        for tag, value in self._state.items():
            for tagIdentifier in self._tagIdentifiers.get(tag, ()):
                tagView = getattr(self, tagIdentifier)
                tagView.state = value

    def set(self, state):
        for tag, tagIdentifiers in self._tagIdentifiers.items():
            for tagIdentifier in tagIdentifiers:
                tagView = getattr(self, tagIdentifier)
                tagView.state = state.get(tag)
        self._state = dict(state)
예제 #3
0
class SliderPlus(Group):

    _callback = weakrefCallbackProperty()

    def __init__(self,
                 posSize,
                 label,
                 minValue,
                 value,
                 maxValue,
                 continuous=True,
                 callback=None):
        super().__init__(posSize)
        self._callback = callback
        self.label = TextBox((0, 0, 0, 20), label)
        self.slider = Slider((0, 18, -60, 20),
                             value=minValue,
                             minValue=minValue,
                             maxValue=maxValue,
                             continuous=continuous,
                             callback=self._sliderCallback)
        self.editField = EditText((-50, 16, 0, 24),
                                  "",
                                  continuous=False,
                                  callback=self._editFieldCallback)
        self.editField._nsObject.setAlignment_(AppKit.NSRightTextAlignment)
        self._setSliderFromValue(value)
        self._setEditFieldFromValue(value)

    def _breakCycles(self):
        self._callback = None
        super()._breakCycles()

    def _sliderCallback(self, sender):
        value = sender.get()
        self._setEditFieldFromValue(value)
        callCallback(self._callback, self)

    def _editFieldCallback(self, sender):
        value = sender.get()
        if not value:
            # self._setSliderFromValue(None)
            callCallback(self._callback, self)
            return
        value = value.replace(",", ".")
        try:
            f = float(value)
        except ValueError:
            pass
        else:
            self.slider.set(f)
            sliderValue = self.slider.get()
            if sliderValue != f:
                self._setEditFieldFromValue(sliderValue)
            callCallback(self._callback, self)

    def _setSliderFromValue(self, value):
        if isinstance(value, set):
            value = sum(value) / len(value)
        elif value is None:
            minValue = self.slider._nsObject.minValue()
            maxValue = self.slider._nsObject.maxValue()
            value = (minValue + maxValue) / 2
        self.slider.set(value)

    def _setEditFieldFromValue(self, value):
        if isinstance(value, set):
            if len(value) == 1:
                value = next(iter(value))
            else:
                value = None
        if value is None:
            s = ""
        else:
            if int(value) == value:
                s = str(int(value))
            else:
                s = f"{value:.1f}"
        self.editField.set(s)

    def get(self):
        if not self.editField.get():
            return None
        else:
            return self.slider.get()

    def set(self, value):
        self._setSliderFromValue(value)
        self._setEditFieldFromValue(value)
예제 #4
0
class SliderGroup(Group):

    _callback = weakrefCallbackProperty()

    def __init__(self, width, sliderInfo, continuous=True, callback=None):
        super().__init__((0, 0, width, 0))
        self._callback = callback
        self._continuous = continuous
        self._tags = []
        self.setSliderInfo(sliderInfo)

    def _breakCycles(self):
        self._callback = None
        super()._breakCycles()

    def setSliderInfo(self, sliderInfo):
        savedState = self.get()
        # clear all subviews
        for attr, value in list(self.__dict__.items()):
            if isinstance(value, VanillaBaseObject):
                delattr(self, attr)
        margin = 10
        y = margin
        self._tags = []
        self._defaultValues = {}
        for tag, (label, minValue, defaultValue,
                  maxValue) in sliderInfo.items():
            self._tags.append(tag)
            self._defaultValues[tag] = defaultValue
            attrName = f"slider_{tag}"
            slider = SliderPlus((margin, y, -margin, 40),
                                label,
                                minValue,
                                defaultValue,
                                maxValue,
                                continuous=self._continuous,
                                callback=self._sliderChanged)
            setattr(self, attrName, slider)
            y += 50

        self.resetAllButton = Button((10, y, 120, 25), "Reset all axes",
                                     self._resetAllButtonCallback)
        self.resetAllButton.enable(False)
        y += 35

        posSize = (0, 0, self.getPosSize()[2], y)
        self.setPosSize(posSize)
        self._updateState(savedState)

    def _sliderChanged(self, sender):
        self.resetAllButton.enable(True)
        callCallback(self._callback, self)

    def _resetAllButtonCallback(self, sender):
        self.resetAllButton.enable(False)
        for tag in self._tags:
            attrName = f"slider_{tag}"
            slider = getattr(self, attrName)
            slider.set(self._defaultValues[tag])
        callCallback(self._callback, self)

    def get(self):
        state = {}
        for tag in self._tags:
            attrName = f"slider_{tag}"
            slider = getattr(self, attrName)
            value = slider.get()
            if value is not None:
                if len(self._defaultValues[tag]
                       ) != 1 or value not in self._defaultValues[tag]:
                    state[tag] = value
        return state

    def _updateState(self, state):
        for tag, value in state.items():
            attrName = f"slider_{tag}"
            slider = getattr(self, attrName, None)
            if slider is not None:
                slider.set(value)

    def set(self, state):
        if state:
            self.resetAllButton.enable(True)
        for tag in self._tags:
            attrName = f"slider_{tag}"
            slider = getattr(self, attrName)
            value = state.get(tag)
            if value is None:
                value = self._defaultValues[tag]
            slider.set(value)