Beispiel #1
0
    def on_item_save(self, item_id: str, event_kwargs: Dict[str, Any]) -> bool:
        """ update item specified by flow key using the new values/changes given in event_kwargs. """
        self.vpo(f"LiszApp.on_item_save('{item_id}', {event_kwargs})")

        add_item = (item_id == '')
        item_idx = -1 if add_item else self.find_item_index(item_id)

        action_or_err = self.edit_validate(item_idx, **event_kwargs)

        if action_or_err:
            if action_or_err.startswith('request_delete_confirmation'):
                self.change_flow(id_of_flow('confirm', 'item_deletion', item_id),
                                 popup_kwargs=dict(node_only=action_or_err.endswith('_for_node')))
            else:
                self.show_message(action_or_err,
                                  title=get_txt("error on adding new item '{item_id}'" if add_item else
                                                "error on editing item '{item_id}'"))

            return False

        if add_item:  # new list item added (with non-empty new_id) at index 0 of the current node
            item_idx = 0

        self.play_vibrate(LOVE_VIBRATE_PATTERN)
        event_kwargs['flow_id'] = id_of_flow('focus', 'item', self.current_node_items[item_idx]['id'])

        self.save_app_states()
        return True
    def on_focus(self, _self, focus: bool):
        """ change flow on text input change of focus.

        :param _self:
        :param focus:           True if this text input got focus, False on unfocus.
        """
        if focus:
            flow_id = self.focus_flow_id or id_of_flow('edit')
        else:
            flow_id = self.unfocus_flow_id or id_of_flow('close')
        App.get_running_app().main_app.change_flow(flow_id)
Beispiel #3
0
    def on_touch_up(self, touch: MotionEvent) -> bool:
        """ drop / finish drag """
        if touch.grab_current is not self:
            return super().on_touch_up(touch)
        if touch.ud[self] != 'drag':
            return False

        ma = self.main_app

        dst_node_path = None
        child_id = ''
        moved = False
        if self.dragging_to_parent_widget_instance or ma.placeholders_above or ma.placeholders_below:
            src_node = self.dragged_from_node
            assert src_node.index(self.item_data) == self.item_idx
            dst_item_id = ''
            if self.dragging_to_parent_widget_instance:
                dst_node_path = ma.flow_path[:-1]
            elif ma.placeholders_above and ma.placeholders_below:   # drop into node
                item_idx = list(ma.placeholders_below.keys())[0]
                child_id = src_node[item_idx]['id']
                dst_node_path = ma.flow_path + [id_of_flow('enter', 'item', child_id), ]
            else:
                if ma.placeholders_above:
                    item_idx = list(ma.placeholders_above.keys())[0]
                else:
                    item_idx = list(ma.placeholders_below.keys())[0] + 1
                dst_item_id = src_node[item_idx]['id'] if item_idx < len(src_node) else ''
            moved = ma.move_item(src_node, self.item_data['id'], dropped_path=dst_node_path, dropped_id=dst_item_id)

        self._restore_menu_bar()
        self.app_root.remove_widget(self)
        ma.cleanup_placeholder()

        ma.dragging_item_idx = None
        self.dragged_from_node = None
        touch.ungrab(self)

        if moved:
            ma.play_sound('edited')
            ma.save_app_states()
            moved = not child_id and dst_node_path is not None
        # refresh and maybe set/change focus; on_flow_id() with 'focus' flow action does also a full refresh/redraw
        if moved:
            ma.refresh_all()
        else:
            flow_id = id_of_flow('focus', 'item', child_id or self.item_data['id'])
            if flow_id == ma.flow_id:
                # remove focus from focused item - allowing clipboard item copies of current node (not current item)
                ma.change_app_state('flow_id', id_of_flow('', ''))    # using instead change_flow() recovers last focus
            else:
                ma.change_flow(flow_id)

        return True
Beispiel #4
0
 def on_item_delete(self, item_id: str, event_kwargs: Dict[str, Any]) -> bool:
     """ delete item or node of this item """
     item_id = event_kwargs.get('item_id', item_id)
     assert item_id
     del_node = event_kwargs.get('del_node', False)
     self.delete_item(item_id, del_node)
     if not del_node:
         self.change_flow(id_of_flow('', ''))
     self.play_sound('deleted')
     self.refresh_all()
     return True
    def on_fb_ori_main_action(self, flow_id, event_kwargs):
        """ FBOri main tap """
        print("FBOri.on_fb_ori_main_action call", flow_id, event_kwargs)

        print("FBOri_main create new instance")
        wid = FlowButton(
            text="FBOri - Original FlowButton" +
            str(len(self.framework_root.children)),
            tap_flow_id=id_of_flow('action', 'fb_ori_main'),
            tap_kwargs=dict(
                kwarg1="FBOri tap_kwargs declared in on_fb_ori_main_action"))
        self.framework_root.add_widget(wid)
Beispiel #6
0
 def toggle_color_picker(self, wid, color_name='square_fill_ink'):
     """ show or hide color picker"""
     print("TOGGLE COLOR PICKER", getattr(wid, color_name),
           self.color_picker)
     is_open = self.color_dropdown and self.color_dropdown.attach_to
     if is_open:
         self.color_dropdown.dismiss()
     if self.color_dropdown:
         self.color_picker.unbind(color=wid.setter(color_name))
         self.color_picker = None
         self.color_dropdown = None
     if not is_open:
         self.color_dropdown = Factory.ColorPickerDD()
         self.change_flow(id_of_flow('suggest'))
         self.color_dropdown.open(wid)
         self.color_picker = self.color_dropdown.ids.col_pic
         self.color_picker.color = getattr(wid, color_name)
         self.color_picker.bind(color=wid.setter(color_name))
Beispiel #7
0
        def add_extract_options(node_flow_path: List[str], pre: str = ""):
            """ add extract options for the node specified by node_flow_path.

            :param node_flow_path:  flow path of node for to add extract options to the child_maps list.
            :param pre:             info button text prefix (for to mark the focused item).
            """
            node = self.flow_path_node(node_flow_path, strict=True)
            if not node or node_flow_path in added_nodes:
                return      # skip empty and already added nodes
            added_nodes.append(node_flow_path)
            parent_node_id = flow_key(self.flow_path[-1]) if self.flow_path else FLOW_PATH_ROOT_ID

            if child_maps:
                child_maps.append(dict(              # add separator widget
                    cls='Widget',
                    kwargs=dict(size_hint_y=None, height=self.font_size / 3)))

            copy_icon = id_of_flow('copy', 'node')
            image_size = (self.font_size * 1.29, self.font_size * 1.29)
            node_info = self.node_info(node,
                                       what=() if self.verbose else ('selected_leaf_count', 'unselected_leaf_count'))
            if parent_node_id:
                node_info['name'] = parent_node_id

            info_text = (f"{self.flow_path_text(node_flow_path, display_root=True)}"
                         f"   {node_info[('un' if sel_status is False else '') + 'selected_leaf_count']}"
                         f"/{node_info['selected_leaf_count'] + node_info['unselected_leaf_count']}")
            child_maps.append(dict(
                kwargs=dict(
                    text=pre + info_text,
                    tap_flow_id=id_of_flow('open', 'node_info', repr(node_flow_path)),
                    tap_kwargs=dict(popup_kwargs=dict(node_info=node_info)),
                    image_size=image_size,
                    circle_fill_color=self.flow_path_ink, circle_fill_size=image_size,
                    square_fill_color=self.flow_id_ink[:3] + (0.39, ))))

            attr_tpl = dict(tap_flow_id=id_of_flow('extract', 'node', repr(node_flow_path)),
                            tap_kwargs=dict(popups_to_close=('replace_with_data_map_container', ), extract_type=''),
                            icon_name=id_of_flow('export', 'node'), image_size=image_size)

            attrs = deepcopy(attr_tpl)
            attrs.update(text=get_txt("copy all node items"), icon_name=copy_icon)
            attrs['tap_kwargs']['extract_type'] = 'copy'
            child_maps.append(dict(kwargs=attrs))

            attrs = deepcopy(attr_tpl)
            attrs.update(text=get_txt("export all node items"))
            attrs['tap_kwargs']['extract_type'] = 'export'
            child_maps.append(dict(kwargs=attrs))

            if self.debug:
                attrs = deepcopy(attr_tpl)
                attrs.update(text=get_txt("cut all node items"), icon_name=id_of_flow('cut', 'node'))
                attrs['tap_kwargs']['extract_type'] = 'cut'
                child_maps.append(dict(kwargs=attrs))

                attrs = deepcopy(attr_tpl)
                attrs.update(text=get_txt("delete all node items"), icon_name=id_of_flow('delete', 'item'))
                attrs['tap_kwargs']['extract_type'] = 'delete'
                child_maps.append(dict(kwargs=attrs))

            if sel_status is not None:
                extract_filter = 'sel' if sel_status else 'unsel'
                ink = self.selected_item_ink if sel_status else self.unselected_item_ink

                attrs = deepcopy(attr_tpl)
                attrs.update(text=get_txt("copy {'' if sel_status else 'un'}selected node items"), icon_name=copy_icon,
                             circle_fill_color=ink, circle_fill_size=image_size)
                attrs['tap_kwargs']['extract_type'] = 'copy_' + extract_filter
                child_maps.append(dict(kwargs=attrs))

                attrs = deepcopy(attr_tpl)
                attrs.update(text=get_txt("export {'' if sel_status else 'un'}selected node items"),
                             circle_fill_color=ink, circle_fill_size=image_size)
                attrs['tap_kwargs']['extract_type'] = 'export_' + extract_filter
                child_maps.append(dict(kwargs=attrs))
Beispiel #8
0
    def show_extract_options(self, widget: Widget, flow_path_text: str = '',
                             item: Optional[LiszItem] = None, sel_status: Optional[bool] = None) -> bool:
        """ open context menu with the available extract actions of the current context/flow/app-status (focus, debug).

        :param widget:          widget to show extract options for.
        :param flow_path_text:  flow path text for to identify the node to extract (def=self.flow_path).
        :param item:            data dict of the item represented by :paramref:`~show_extract_options.widget`.
        :param sel_status:      pass True / False to add option for to export selected / unselected items.
        :return:                True if extract options are available and got displayed else False.
        """
        def add_extract_options(node_flow_path: List[str], pre: str = ""):
            """ add extract options for the node specified by node_flow_path.

            :param node_flow_path:  flow path of node for to add extract options to the child_maps list.
            :param pre:             info button text prefix (for to mark the focused item).
            """
            node = self.flow_path_node(node_flow_path, strict=True)
            if not node or node_flow_path in added_nodes:
                return      # skip empty and already added nodes
            added_nodes.append(node_flow_path)
            parent_node_id = flow_key(self.flow_path[-1]) if self.flow_path else FLOW_PATH_ROOT_ID

            if child_maps:
                child_maps.append(dict(              # add separator widget
                    cls='Widget',
                    kwargs=dict(size_hint_y=None, height=self.font_size / 3)))

            copy_icon = id_of_flow('copy', 'node')
            image_size = (self.font_size * 1.29, self.font_size * 1.29)
            node_info = self.node_info(node,
                                       what=() if self.verbose else ('selected_leaf_count', 'unselected_leaf_count'))
            if parent_node_id:
                node_info['name'] = parent_node_id

            info_text = (f"{self.flow_path_text(node_flow_path, display_root=True)}"
                         f"   {node_info[('un' if sel_status is False else '') + 'selected_leaf_count']}"
                         f"/{node_info['selected_leaf_count'] + node_info['unselected_leaf_count']}")
            child_maps.append(dict(
                kwargs=dict(
                    text=pre + info_text,
                    tap_flow_id=id_of_flow('open', 'node_info', repr(node_flow_path)),
                    tap_kwargs=dict(popup_kwargs=dict(node_info=node_info)),
                    image_size=image_size,
                    circle_fill_color=self.flow_path_ink, circle_fill_size=image_size,
                    square_fill_color=self.flow_id_ink[:3] + (0.39, ))))

            attr_tpl = dict(tap_flow_id=id_of_flow('extract', 'node', repr(node_flow_path)),
                            tap_kwargs=dict(popups_to_close=('replace_with_data_map_container', ), extract_type=''),
                            icon_name=id_of_flow('export', 'node'), image_size=image_size)

            attrs = deepcopy(attr_tpl)
            attrs.update(text=get_txt("copy all node items"), icon_name=copy_icon)
            attrs['tap_kwargs']['extract_type'] = 'copy'
            child_maps.append(dict(kwargs=attrs))

            attrs = deepcopy(attr_tpl)
            attrs.update(text=get_txt("export all node items"))
            attrs['tap_kwargs']['extract_type'] = 'export'
            child_maps.append(dict(kwargs=attrs))

            if self.debug:
                attrs = deepcopy(attr_tpl)
                attrs.update(text=get_txt("cut all node items"), icon_name=id_of_flow('cut', 'node'))
                attrs['tap_kwargs']['extract_type'] = 'cut'
                child_maps.append(dict(kwargs=attrs))

                attrs = deepcopy(attr_tpl)
                attrs.update(text=get_txt("delete all node items"), icon_name=id_of_flow('delete', 'item'))
                attrs['tap_kwargs']['extract_type'] = 'delete'
                child_maps.append(dict(kwargs=attrs))

            if sel_status is not None:
                extract_filter = 'sel' if sel_status else 'unsel'
                ink = self.selected_item_ink if sel_status else self.unselected_item_ink

                attrs = deepcopy(attr_tpl)
                attrs.update(text=get_txt("copy {'' if sel_status else 'un'}selected node items"), icon_name=copy_icon,
                             circle_fill_color=ink, circle_fill_size=image_size)
                attrs['tap_kwargs']['extract_type'] = 'copy_' + extract_filter
                child_maps.append(dict(kwargs=attrs))

                attrs = deepcopy(attr_tpl)
                attrs.update(text=get_txt("export {'' if sel_status else 'un'}selected node items"),
                             circle_fill_color=ink, circle_fill_size=image_size)
                attrs['tap_kwargs']['extract_type'] = 'export_' + extract_filter
                child_maps.append(dict(kwargs=attrs))

        self.vpo(f"LiszApp.show_extract_options({widget}, {flow_path_text}, {item}, {sel_status})")
        flow_path = self.flow_path_from_text(flow_path_text) if flow_path_text else self.flow_path
        has_focus = flow_action(self.flow_id) == 'focus'
        flo_key = flow_key(self.flow_id)
        child_maps = list()
        added_nodes = list()

        node_id = item['id'] if item else ''
        if node_id and 'node' in item:
            add_extract_options(flow_path + [id_of_flow('enter', 'item', node_id)],
                                pre=FOCUS_FLOW_PREFIX if has_focus and node_id == flo_key else "")

        add_extract_options(flow_path)

        if has_focus and flo_key != node_id:
            item = self.item_by_id(flo_key)
            if 'node' in item:
                add_extract_options(flow_path + [id_of_flow('enter', 'item', flo_key)], pre=FOCUS_FLOW_PREFIX)

        if not child_maps:
            self.show_message(get_txt("no extract options available for this item/node"))
            return False

        popup_kwargs = dict(parent=widget, child_data_maps=child_maps, auto_width_child_padding=self.font_size * 3)
        return self.change_flow(id_of_flow('open', 'extract'), popup_kwargs=popup_kwargs)
Beispiel #9
0
        def add_import_options(info_text: str):
            """ add menu options for the current node. """
            info = self.node_info(node, what=() if self.verbose else ('selected_leaf_count', 'unselected_leaf_count'))
            if len(node) == 1:
                info['content'] = node[0]['id']
            info_text = str(info['selected_leaf_count'] + info['unselected_leaf_count']) + " items from " + info_text
            if node_id:
                info['name'] = node_id
                info_text = get_txt("node '{node_id}' with ") + info_text
            info_text += " to"
            child_maps.append(dict(kwargs=dict(
                text=info_text, tap_flow_id=id_of_flow('open', 'node_info'),
                tap_kwargs=dict(popup_kwargs=dict(node_info=info)),
                image_size=image_size, circle_fill_color=self.flow_path_ink, circle_fill_size=image_size,
                square_fill_color=self.flow_id_ink[:3] + (0.39,))))

            args_tpl: Dict[str, Any] = dict(
                tap_flow_id=id_of_flow('import', 'node'),
                tap_kwargs=dict(node_to_import=node, popups_to_close=('replace_with_data_map_container',)),
                image_size=image_size)

            if self.flow_path:
                kwargs = deepcopy(args_tpl)
                kwargs['text'] = get_txt("current list begin")
                if node_id:
                    kwargs['tap_kwargs']['add_node_id'] = node_id
                child_maps.append(dict(kwargs=kwargs))

                item_index = len(self.current_node_items)
                if item_index:
                    kwargs = deepcopy(args_tpl)
                    kwargs['text'] = get_txt("current list end")
                    kwargs['tap_kwargs']['import_items_index'] = item_index
                    if node_id:
                        kwargs['tap_kwargs']['add_node_id'] = node_id
                    child_maps.append(dict(kwargs=kwargs))

            kwargs = deepcopy(args_tpl)
            kwargs['text'] = get_txt("{FLOW_PATH_ROOT_ID} list begin")
            kwargs['tap_kwargs']['import_items_node'] = self.root_node
            if node_id:
                kwargs['tap_kwargs']['add_node_id'] = node_id
            child_maps.append(dict(kwargs=kwargs))

            item_index = len(self.root_node)
            if item_index:
                kwargs = deepcopy(args_tpl)
                kwargs['text'] = get_txt("{FLOW_PATH_ROOT_ID} list end")
                kwargs['tap_kwargs']['import_items_node'] = self.root_node
                kwargs['tap_kwargs']['import_items_index'] = item_index
                if node_id:
                    kwargs['tap_kwargs']['add_node_id'] = node_id
                child_maps.append(dict(kwargs=kwargs))

            if focused_id:
                item_index = self.find_item_index(focused_id)

                kwargs = deepcopy(args_tpl)
                kwargs['text'] = get_txt("before focused item '{focused_id}'")
                kwargs['tap_kwargs']['import_items_index'] = item_index
                if node_id:
                    kwargs['tap_kwargs']['add_node_id'] = node_id
                child_maps.append(dict(kwargs=kwargs))

                focused_item = self.item_by_id(focused_id)
                if 'node' in focused_item:
                    kwargs = deepcopy(args_tpl)
                    kwargs['text'] = get_txt("into focused sub-list '{focused_id}'")
                    kwargs['tap_kwargs']['import_items_node'] = focused_item['node']
                    if node_id:
                        kwargs['tap_kwargs']['add_node_id'] = node_id
                    child_maps.append(dict(kwargs=kwargs))

                kwargs = deepcopy(args_tpl)
                kwargs['text'] = get_txt("after focused '{focused_id}'")
                kwargs['tap_kwargs']['import_items_index'] = item_index + 1
                if node_id:
                    kwargs['tap_kwargs']['add_node_id'] = node_id
                child_maps.append(dict(kwargs=kwargs))
Beispiel #10
0
    def show_add_options(self, widget: Widget) -> bool:
        """ open context menu with all available actions for to add/import new node/item(s).

        :param widget:          FlowButton to open this context menu.
        :return:                True if any add options are available and got displayed else False.
        """
        def add_import_options(info_text: str):
            """ add menu options for the current node. """
            info = self.node_info(node, what=() if self.verbose else ('selected_leaf_count', 'unselected_leaf_count'))
            if len(node) == 1:
                info['content'] = node[0]['id']
            info_text = str(info['selected_leaf_count'] + info['unselected_leaf_count']) + " items from " + info_text
            if node_id:
                info['name'] = node_id
                info_text = get_txt("node '{node_id}' with ") + info_text
            info_text += " to"
            child_maps.append(dict(kwargs=dict(
                text=info_text, tap_flow_id=id_of_flow('open', 'node_info'),
                tap_kwargs=dict(popup_kwargs=dict(node_info=info)),
                image_size=image_size, circle_fill_color=self.flow_path_ink, circle_fill_size=image_size,
                square_fill_color=self.flow_id_ink[:3] + (0.39,))))

            args_tpl: Dict[str, Any] = dict(
                tap_flow_id=id_of_flow('import', 'node'),
                tap_kwargs=dict(node_to_import=node, popups_to_close=('replace_with_data_map_container',)),
                image_size=image_size)

            if self.flow_path:
                kwargs = deepcopy(args_tpl)
                kwargs['text'] = get_txt("current list begin")
                if node_id:
                    kwargs['tap_kwargs']['add_node_id'] = node_id
                child_maps.append(dict(kwargs=kwargs))

                item_index = len(self.current_node_items)
                if item_index:
                    kwargs = deepcopy(args_tpl)
                    kwargs['text'] = get_txt("current list end")
                    kwargs['tap_kwargs']['import_items_index'] = item_index
                    if node_id:
                        kwargs['tap_kwargs']['add_node_id'] = node_id
                    child_maps.append(dict(kwargs=kwargs))

            kwargs = deepcopy(args_tpl)
            kwargs['text'] = get_txt("{FLOW_PATH_ROOT_ID} list begin")
            kwargs['tap_kwargs']['import_items_node'] = self.root_node
            if node_id:
                kwargs['tap_kwargs']['add_node_id'] = node_id
            child_maps.append(dict(kwargs=kwargs))

            item_index = len(self.root_node)
            if item_index:
                kwargs = deepcopy(args_tpl)
                kwargs['text'] = get_txt("{FLOW_PATH_ROOT_ID} list end")
                kwargs['tap_kwargs']['import_items_node'] = self.root_node
                kwargs['tap_kwargs']['import_items_index'] = item_index
                if node_id:
                    kwargs['tap_kwargs']['add_node_id'] = node_id
                child_maps.append(dict(kwargs=kwargs))

            if focused_id:
                item_index = self.find_item_index(focused_id)

                kwargs = deepcopy(args_tpl)
                kwargs['text'] = get_txt("before focused item '{focused_id}'")
                kwargs['tap_kwargs']['import_items_index'] = item_index
                if node_id:
                    kwargs['tap_kwargs']['add_node_id'] = node_id
                child_maps.append(dict(kwargs=kwargs))

                focused_item = self.item_by_id(focused_id)
                if 'node' in focused_item:
                    kwargs = deepcopy(args_tpl)
                    kwargs['text'] = get_txt("into focused sub-list '{focused_id}'")
                    kwargs['tap_kwargs']['import_items_node'] = focused_item['node']
                    if node_id:
                        kwargs['tap_kwargs']['add_node_id'] = node_id
                    child_maps.append(dict(kwargs=kwargs))

                kwargs = deepcopy(args_tpl)
                kwargs['text'] = get_txt("after focused '{focused_id}'")
                kwargs['tap_kwargs']['import_items_index'] = item_index + 1
                if node_id:
                    kwargs['tap_kwargs']['add_node_id'] = node_id
                child_maps.append(dict(kwargs=kwargs))

        self.vpo(f"LiszApp.show_add_options({widget})")
        image_size = (self.font_size * 1.35, self.font_size * 1.35)
        focused_id = flow_key(self.flow_id) if flow_action(self.flow_id) == 'focus' else ''
        child_maps = list()

        node = node_from_literal(Clipboard.paste())
        if node:
            node_id = ''
            add_import_options(get_txt("clipboard"))

        node_files = self.importable_node_files(folder_path=self.documents_root_path)
        for node_file_info in node_files:
            if child_maps:                      # add separator widget
                child_maps.append(dict(cls='Widget', kwargs=dict(size_hint_y=None, height=self.font_size / 3)))

            node_id, node, file_path, err_msg = node_file_info
            if not err_msg:
                add_import_options(get_txt("export file"))

                child_maps.append(dict(cls='Widget', kwargs=dict(size_hint_y=None, height=self.font_size / 3)))
                node_id = ''
                add_import_options(get_txt("export file"))

            elif self.verbose:
                child_maps.append(dict(kwargs=dict(
                    cls='ImageLabel',
                    text=node_id + " error: " + err_msg,
                    square_fill_color=(1, 0, 0, 0.39,))))

        if not child_maps:
            self.show_message(get_txt("neither clipboard nor '{self.documents_root_path}' contains items to import"),
                              title=get_txt("import error(s)", count=1))
            return False

        popup_kwargs = dict(parent=widget, child_data_maps=child_maps, auto_width_child_padding=self.font_size * 3)
        return self.change_flow(id_of_flow('open', 'alt_add'), popup_kwargs=popup_kwargs)
Beispiel #11
0
 def edit_item_finished(self, old_id: str, new_id: str, state: str):
     """ finished list add/edit callback from on_dismiss event of ItemEditor """
     self.vpo(f"LiszApp.edit_item_finished('{old_id}', '{new_id}', {state})")
     self.change_flow(id_of_flow('save', 'item', old_id), new_id=new_id, want_node=state == 'down')