Beispiel #1
0
 def __init__(self, device_bank_registry=None, banking_info=None, delete_handler=None, track_list_component=None, *a, **k):
     assert banking_info is not None
     assert device_bank_registry is not None
     assert track_list_component is not None
     self._flattened_chain = FlattenedDeviceChain(collect_devices)
     self._track_decorator = DecoratorFactory()
     self._modes = NullModes()
     self.move_device = None
     super(DeviceNavigationComponent, self).__init__(item_provider=self._flattened_chain, *a, **k)
     self._delete_handler = delete_handler
     self.chain_selection = ChainSelectionComponent(parent=self, is_enabled=False)
     self.bank_selection = BankSelectionComponent(bank_registry=device_bank_registry, banking_info=banking_info, device_options_provider=self._device_component, is_enabled=False, parent=self)
     self.move_device = MoveDeviceComponent(parent=self, is_enabled=False)
     self._last_pressed_button_index = -1
     self._selected_on_previous_press = None
     self._modes = ModesComponent(parent=self)
     self._modes.add_mode('default', [
      partial(self.chain_selection.set_parent, None),
      partial(self.bank_selection.set_device, None)])
     self._modes.add_mode('chain_selection', [self.chain_selection])
     self._modes.add_mode('bank_selection', [self.bank_selection])
     self._modes.selected_mode = 'default'
     self.register_disconnectable(self._flattened_chain)
     self.__on_items_changed.subject = self
     self.__on_bank_selection_closed.subject = self.bank_selection
     self._update_selected_track()
     self._track_list = track_list_component
     watcher = self.register_disconnectable(DeviceChainStateWatcher(device_navigation=self))
     self.__on_device_item_state_changed.subject = watcher
     self._update_device()
     self._update_button_colors()
     return
Beispiel #2
0
class DeviceNavigationComponent(DeviceNavigationComponentBase):
    __events__ = ('drum_pad_selection',
                  'mute_solo_stop_cancel_action_performed')

    def __init__(self,
                 device_bank_registry=None,
                 banking_info=None,
                 delete_handler=None,
                 track_list_component=None,
                 *a,
                 **k):
        self._flattened_chain = FlattenedDeviceChain(
            partial(collect_devices, self))
        self._track_decorator = DecoratorFactory()
        self._modes = NullModes()
        self.move_device = None
        (super(DeviceNavigationComponent,
               self).__init__)(a, item_provider=self._flattened_chain, **k)
        self._delete_handler = delete_handler
        self.chain_selection = ChainSelectionComponent(parent=self,
                                                       is_enabled=False)
        self.bank_selection = BankSelectionComponent(
            bank_registry=device_bank_registry,
            banking_info=banking_info,
            device_options_provider=(self._device_component),
            is_enabled=False,
            parent=self)
        self.move_device = MoveDeviceComponent(parent=self, is_enabled=False)
        self._last_pressed_button_index = -1
        self._selected_on_previous_press = None
        self._modes = ModesComponent(parent=self)
        self._modes.add_mode('default', [
            partial(self.chain_selection.set_parent, None),
            partial(self.bank_selection.set_device, None)
        ])
        self._modes.add_mode('chain_selection', [self.chain_selection])
        self._modes.add_mode('bank_selection', [self.bank_selection])
        self._modes.selected_mode = 'default'
        self.register_disconnectable(self._flattened_chain)
        self._DeviceNavigationComponent__on_items_changed.subject = self
        self._DeviceNavigationComponent__on_bank_selection_closed.subject = self.bank_selection
        self._update_selected_track()
        self._track_list = track_list_component
        watcher = self.register_disconnectable(
            DeviceChainStateWatcher(device_navigation=self))
        self._DeviceNavigationComponent__on_device_item_state_changed.subject = watcher
        self._update_device()
        self._update_button_colors()

    @property
    def modes(self):
        return self._modes

    def _in_device_enabling_mode(self):
        return self._track_list.selected_mode == 'mute'

    def _on_select_button_pressed(self, button):
        device_or_pad = self.items[button.index].item
        if self._in_device_enabling_mode():
            self._toggle_device(device_or_pad)
            self.notify_mute_solo_stop_cancel_action_performed()
        else:
            self._last_pressed_button_index = button.index
            if not (self._delete_handler and self._delete_handler.is_deleting):
                self._selected_on_previous_press = device_or_pad if self.selected_object != device_or_pad else None
                self._select_item(device_or_pad)

    def _on_select_button_released_immediately(self, button):
        if not self._in_device_enabling_mode():
            self._last_pressed_button_index = -1
            device_or_pad = self.items[button.index].item
            if self._delete_handler and self._delete_handler.is_deleting:
                self._delete_item(device_or_pad)
            elif self.selected_object == device_or_pad:
                if device_or_pad != self._selected_on_previous_press:
                    self._on_reselecting_object(device_or_pad)
            self._selected_on_previous_press = None

    def _on_select_button_pressed_delayed(self, button):
        if not self._in_device_enabling_mode():
            self._on_pressed_delayed(self.items[button.index].item)

    def _on_select_button_released(self, button):
        if button.index == self._last_pressed_button_index:
            self._modes.selected_mode = 'default'
            self._last_pressed_button_index = -1
            self._end_move_device()

    @singledispatchmethod
    def _toggle_device(self, device):
        if liveobj_valid(device):
            if device.parameters[0].is_enabled:
                set_enabled(device, not is_on(device))

    @_toggle_device.register(Live.DrumPad.DrumPad)
    def _(self, drum_pad):
        if liveobj_valid(drum_pad):
            drum_pad.mute = not drum_pad.mute

    @listens('state')
    def __on_device_item_state_changed(self):
        self._update_button_colors()

    @listens('items')
    def __on_items_changed(self):
        new_items = [x.item for x in self.items]
        selected_item = self._flattened_chain.selected_item
        lost_selection = selected_item not in new_items
        if lost_selection:
            if isinstance(selected_item, RackBank2Device):
                for item in new_items:
                    if isinstance(item, RackBank2Device):
                        if item.rack_device == selected_item.rack_device:
                            self._select_item(item)
                            break

        lost_selection_on_empty_pad = new_items and is_drum_pad(
            new_items[(-1)]) and lost_selection
        if self._should_select_drum_pad() or (lost_selection_on_empty_pad):
            self._select_item(self._current_drum_pad())
        if self.moving:
            self._show_selected_item()
        self.notify_drum_pad_selection()

    def _create_slot(self, index, item, nesting_level):
        items = self._item_provider.items[self.item_offset:]
        num_slots = min(self._num_visible_items, len(items))
        slot = None
        if index == 0 and self.can_scroll_left():
            slot = IconItemSlot(icon='page_left.svg')
            slot.is_scrolling_indicator = True
        elif index == num_slots - 1 and self.can_scroll_right():
            slot = IconItemSlot(icon='page_right.svg')
            slot.is_scrolling_indicator = True
        else:
            slot = ItemSlot(item=item, nesting_level=nesting_level)
            slot.is_scrolling_indicator = False
        return slot

    @listenable_property
    def moving(self):
        return self.move_device.is_enabled()

    @property
    def device_selection_update_allowed(self):
        return not self._should_select_drum_pad()

    def _color_for_button(self, button_index, is_selected):
        item = self.items[button_index]
        device_or_pad = item.item
        is_active = liveobj_valid(device_or_pad) and is_active_element(
            device_or_pad)
        chain = find_chain_or_track(device_or_pad)
        if not is_active:
            return 'DefaultButton.Off'
        if is_selected:
            return 'ItemNavigation.ItemSelected'
        if liveobj_valid(chain):
            return IndexedColor.from_live_index(chain.color_index,
                                                DISPLAY_BUTTON_SHADE_LEVEL)
        return 'ItemNavigation.ItemNotSelected'

    def _begin_move_device(self, device):
        if not self.move_device.is_enabled():
            if device.type != Live.Device.DeviceType.instrument:
                self.move_device.set_device(device)
                self.move_device.set_enabled(True)
                self._scroll_overlay.set_enabled(False)
                self.notify_moving()

    def _end_move_device(self):
        if self.move_device:
            if self.move_device.is_enabled():
                self.move_device.set_device(None)
                self.move_device.set_enabled(False)
                self._scroll_overlay.set_enabled(True)
                self.notify_moving()

    def request_drum_pad_selection(self):
        self._current_track().drum_pad_selected = True

    def unfold_current_drum_pad(self):
        self._current_track().drum_pad_selected = False
        self._current_drum_pad(
        ).canonical_parent.view.is_showing_chain_devices = True

    def sync_selection_to_selected_device(self):
        self._update_item_provider(
            self.song.view.selected_track.view.selected_device)

    @property
    def is_drum_pad_selected(self):
        return is_drum_pad(self._flattened_chain.selected_item)

    @property
    def is_drum_pad_unfolded(self):
        selection = self._flattened_chain.selected_item
        return drum_rack_for_pad(selection).view.is_showing_chain_devices

    def _current_track(self):
        return self._track_decorator.decorate(
            (self.song.view.selected_track),
            additional_properties={'drum_pad_selected': False})

    def _should_select_drum_pad(self):
        return self._current_track().drum_pad_selected

    def _current_drum_pad(self):
        return find_drum_pad(self.items)

    def _update_selected_track(self):
        self._selected_track = self.song.view.selected_track
        selected_track = self._current_track()
        self.reset_offset()
        self._flattened_chain.set_device_parent(selected_track)
        self._device_selection_in_track_changed.subject = selected_track.view
        self._modes.selected_mode = 'default'
        self._end_move_device()
        self._restore_selection(selected_track)

    def _restore_selection(self, selected_track):
        to_select = None
        if self._should_select_drum_pad():
            to_select = self._current_drum_pad()
        if to_select == None:
            to_select = selected_track.view.selected_device
        self._select_item(to_select)

    def back_to_top(self):
        pass

    @property
    def selected_object(self):
        selected_item = self.item_provider.selected_item
        return getattr(selected_item, 'proxied_object', selected_item)

    @singledispatchmethod
    def _do_select_item(self, device):
        self._current_track().drum_pad_selected = False
        appointed_device = device_to_appoint(device)
        self._appoint_device(appointed_device)
        self.song.view.select_device(device, False)
        self.song.appointed_device = appointed_device

    @_do_select_item.register(RackBank2Device)
    def _(self, bank_2_device):
        self._current_track().drum_pad_selected = False
        self._appoint_device(bank_2_device)

    @_do_select_item.register(Live.DrumPad.DrumPad)
    def _(self, pad):
        self._current_track().drum_pad_selected = True
        device = self._first_device_on_pad(pad)
        self._appoint_device(device)

    def _first_device_on_pad(self, drum_pad):
        chain = drum_rack_for_pad(drum_pad).view.selected_chain
        if chain:
            if chain.devices:
                return first(chain.devices)

    def _appoint_device(self, device):
        if self._device_component.device_changed(device):
            self._device_component.set_device(device)

    @singledispatchmethod
    def _on_reselecting_object(self, device):
        if liveobj_valid(device) and device.can_have_chains:
            if not device.can_have_drum_pads:
                self._toggle(device)
        else:
            self.bank_selection.set_device(device)
            self._modes.selected_mode = 'bank_selection'

    @_on_reselecting_object.register(RackBank2Device)
    def _(self, bank_2_device):
        device = bank_2_device.rack_device
        if liveobj_valid(device):
            if device.can_have_chains:
                if not device.can_have_drum_pads:
                    self._toggle(device)

    @_on_reselecting_object.register(Live.DrumPad.DrumPad)
    def _(self, drum_pad):
        rack = drum_rack_for_pad(drum_pad)
        self._toggle(rack)
        if rack.view.is_showing_chain_devices:
            first_device = self._first_device_on_pad(drum_pad)
            if first_device:
                self._select_item(first_device)
        self.notify_drum_pad_selection()

    @singledispatchmethod
    def _on_pressed_delayed(self, device):
        self._show_chains(device)
        self._begin_move_device(device)

    @_on_pressed_delayed.register(RackBank2Device)
    def _(self, bank_2_device):
        device = bank_2_device.rack_device
        self._show_chains(device)
        self._begin_move_device(device)

    @_on_pressed_delayed.register(Live.DrumPad.DrumPad)
    def _(self, _):
        pass

    @singledispatchmethod
    def _delete_item(self, device):
        delete_device(device)

    @_delete_item.register(Live.DrumPad.DrumPad)
    def _(self, pad):
        pass

    def _show_chains(self, device):
        if device.can_have_chains:
            self.chain_selection.set_parent(device)
            self._modes.selected_mode = 'chain_selection'

    @listens('back')
    def __on_bank_selection_closed(self):
        self._modes.selected_mode = 'default'

    def _update_device(self):
        if not self._should_select_drum_pad():
            if not self._is_drum_rack_selected():
                self._modes.selected_mode = 'default'
                self._update_item_provider(self._device_component.device())

    def _is_drum_rack_selected(self):
        selected_item = self._flattened_chain.selected_item
        instrument = self._find_top_level_instrument()
        return liveobj_valid(selected_item) and isinstance(
            selected_item, Live.RackDevice.RackDevice
        ) and selected_item.can_have_drum_pads and not liveobj_changed(
            selected_item, instrument)

    def _find_top_level_instrument(self):
        return find_if(
            lambda device: device.type == Live.Device.DeviceType.instrument,
            self._current_track().devices)

    @listens('selected_device')
    def _device_selection_in_track_changed(self):
        new_selection = self.song.view.selected_track.view.selected_device
        if self._can_update_device_selection(new_selection):
            self._modes.selected_mode = 'default'
            self._update_item_provider(new_selection)

    def _toggle(self, item):
        view = item.view
        if view.is_collapsed:
            view.is_collapsed = False
            view.is_showing_chain_devices = True
        else:
            view.is_showing_chain_devices = not view.is_showing_chain_devices

    def _can_update_device_selection(self, new_selection):
        can_update = liveobj_valid(new_selection)
        drum_pad_selected_or_requested = self.is_drum_pad_selected or self._should_select_drum_pad(
        )
        if can_update and drum_pad_selected_or_requested:
            if is_empty_rack(new_selection):
                can_update = False
            if not can_update or self.is_drum_pad_selected:
                can_update = not is_first_device_on_pad(
                    new_selection, self._flattened_chain.selected_item)
        else:
            pass
        if not can_update:
            if not drum_pad_selected_or_requested:
                can_update = True
            return can_update

    def _update_item_provider(self, selection):
        self._flattened_chain.selected_item = selection
        if not is_drum_pad(selection):
            self._current_track().drum_pad_selected = False
        self.notify_drum_pad_selection()