コード例 #1
0
class LinksView(View):
    def __init__(self, parent):
        super().__init__(parent)
        self['text'] = 'Links'
        self.update_idletasks()
        h = self.parent.winfo_reqheight()
        w = self.parent.winfo_reqwidth()

        self._flow = None
        self._grid_rows_descr: List[Dict] = []
        self._possible_input: List[str] = []
        self._active_wd_idx = -1

        self.grid()
        self.rowconfigure(0, weight=1)
        self.rowconfigure(1, weight=1)

        self._infovar = StringVar()
        self._info_entry = Entry(self,
                                 name='flow_info',
                                 textvariable=self._infovar,
                                 width=35)
        self._info_entry.grid(row=0,
                              column=0,
                              padx=PADX,
                              pady=PADY,
                              sticky=N + W + E)
        self._info_desr = {
            'getter': self._infovar.get,
            'setter': self._infovar.set,
            'wd': self._info_entry
        }
        # Content will be scrolable
        self._content = ScrolledFrame(self,
                                      use_ttk=True,
                                      height=int(h / 5),
                                      width=int((w / 2)))
        self._content.grid(row=1,
                           column=0,
                           padx=PADX,
                           pady=PADY_S,
                           sticky=W + E)
        # Create the params frame within the ScrolledFrame
        self._links_view = self._content.display_widget(Frame)
        return

    @property
    def descriptors(self) -> List[Dict]:
        return self._grid_rows_descr

    @property
    def info_descr(self) -> str:
        return self._info_desr

    def get_active_item_link_descriptors(self) -> List[List[Widget]]:
        if self._active_wd_idx < 0:
            return None
        descriptors = self._grid_rows_descr[self._active_wd_idx]
        return descriptors

    def clear(self) -> None:
        self._infovar.set('')
        for child in self._links_view.winfo_children():
            child.grid_remove()
        self._grid_rows_descr.clear()
        self._content.scroll_to_top()
        self._possible_input.clear()
        self._active_wd_idx = -1
        return

    def build(self, flow: FlowModel) -> None:
        self._flow = flow
        self._infovar.set(flow.info)
        items = copy.deepcopy(flow.items)
        for i, item in enumerate(items):
            item_links_frame = self._create_item_links_container(i + 1, item)
            item_links_frame.grid(row=i + 1, column=0, padx=PADX, sticky=W + E)
            item_links_frame.columnconfigure(0, weight=1)
            item_links_frame.columnconfigure(1, weight=1)
            item_links_descr = self._create_item_links_widgets(
                item_links_frame, i, item)
            self._grid_rows_descr.append(item_links_descr)
        self._disable_all()
        self._active_wd_idx = 0
        self._hightlighte_active_wd(True)
        self._set_active_wd_state(True)
        return

    def _create_item_links_container(self, idx: int,
                                     item: FlowItemModel) -> Widget:
        i_n = item.name.replace('.', '-')
        name = f'--{idx}-{i_n}--'
        item_links_frame = LabelFrame(self._links_view, name=name)
        return item_links_frame

    def _create_item_links_widgets(self, container: LabelFrame, idx: int,
                                   item: FlowItemModel) -> Dict:
        item_links_descr = []
        title = f'{idx}-{item.name}'
        i_n = item.name.replace('.', '-')
        name = f'--{idx}-{i_n}--'
        item_label = Label(container, name=name, text=title)
        item_label.grid(row=0, column=0, padx=PADX_S, pady=PADY_S, sticky=W)
        item_links_descr.append({
            'name': item_label.winfo_name(),
            'getter': None,
            'setter': None,
            'wd': item_label
        })
        infovar = StringVar()
        infovar.set(item.title)
        info_entry = Entry(container, textvariable=infovar, width=38)
        info_entry.grid(row=0, column=1, padx=PADX_S, pady=PADY_S, sticky=E)
        item_links_descr.append({
            'name': info_entry.winfo_name(),
            'getter': infovar.get,
            'setter': None,
            'wd': info_entry
        })

        inrefs_def = item.inrefs_def
        outrefs_def = item.outrefs_def

        for i, outref_def in enumerate(outrefs_def):
            outref_name = outref_def.get('name')
            self._possible_input.append(f'{title}-{outref_name}')

        links = item.links
        if len(inrefs_def) > 0:
            for i, inref_def in enumerate(inrefs_def):
                inref_name = inref_def.get('name')
                getter, inref_lbl, inref_combo = self._create_link_widget(
                    container, inref_name, links)
                inref_lbl.grid(row=i + 1,
                               column=0,
                               padx=PADX_S,
                               pady=PADY_S,
                               sticky=W)
                inref_combo.grid(row=i + 1,
                                 column=1,
                                 columnspan=2,
                                 padx=PADX_S,
                                 pady=PADY_S,
                                 sticky=E)
                item_links_descr.append({
                    'name': inref_name,
                    'getter': getter,
                    'setter': None,
                    'wd': inref_combo
                })
        return item_links_descr

    def _create_link_widget(
            self, container: LabelFrame, inref_name: str,
            links: Dict[str, str]) -> Tuple[Callable, Widget, Widget]:
        def get():
            return inref_combo.get()

        text = f'{inref_name}:'
        inref_lbl = Label(container,
                          text=text,
                          anchor=W,
                          justify=LEFT,
                          width=10)
        var = StringVar()
        inref_combo = Combobox(container,
                               name=inref_name,
                               justify=LEFT,
                               width=35)
        inref_combo['values'] = copy.deepcopy(
            self._possible_input[:len(self._possible_input) - 2])
        # Assign current value
        if len(links) > 0:
            link = links.get(inref_name)
            if link is not None:
                inref_combo.set(link)
                inref_combo.textvariable = var
        return get, inref_lbl, inref_combo

    def set_active_wd(self, idx: int) -> None:
        self._hightlighte_active_wd()
        self._set_active_wd_state()
        self._active_wd_idx = idx
        self._hightlighte_active_wd(True)
        self._set_active_wd_state(True)
        return

    def _set_active_wd_state(self, active: bool = False) -> None:
        state = DISABLED
        if active:
            state = NORMAL
        descriptors = self._grid_rows_descr[self._active_wd_idx]
        for descr in descriptors:
            widget = descr.get('wd')
            widget['state'] = state
        return

    def _disable_all(self) -> None:
        for descriptors in self._grid_rows_descr:
            for descr in descriptors:
                widget = descr.get('wd')
                widget['state'] = DISABLED
        return

    # UI methods

    def _hightlighte_active_wd(self, active: bool = False) -> None:
        fg_color = 'black'
        bg_color = 'SystemButtonFace'
        if active:
            fg_color = 'white'
            bg_color = 'RoyalBlue'
        descriptors = self._grid_rows_descr[self._active_wd_idx]
        for descr in descriptors:
            widget = descr.get('wd')
            name = widget.winfo_name()
            if name.startswith('--'):
                widget['fg'] = fg_color
                widget['bg'] = bg_color
                break
        return
コード例 #2
0
class DataView(View):
  def __init__(self, parent):
    super().__init__(parent)
    self['text'] = 'Data'
    # self['bg'] = 'green'

    h = self.parent.winfo_reqheight()
    w = self.parent.winfo_reqwidth()
    self.grid()
    # self.grid_propagate(False)

    self.rowconfigure(0, weight=1)
    self.rowconfigure(1, weight=1)
    # self.rowconfigure(2, weight=1)
    # self.columnconfigure(0, pad=15)
    self.columnconfigure(0, weight=1)

    # Last existing output
    self._data_last = Frame(self, height=int(h*0.3), highlightbackground='gray', highlightthickness=1)
    self._data_last.grid(row=0, column=0, padx=PADX, pady=PADY_S, sticky=W + E + N + S)
    self._data_last.columnconfigure(0, weight=1)
    self._data_last.rowconfigure(0, weight=1)
    self._data_last.grid_propagate(False)
    # self._last_view = Label(self._data_last, name='last image')

    # Setup canvas inside the frame
    # self._canvas_data_last = Canvas(self._data_last, bg='green')
    # self._canvas_data_last.grid(row=0, column=0, padx=PADX_S, pady=PADY_S, sticky=W + E + N + S)

    #Add PIL image to the Canvas
    # canvas.create_image(10,10,anchor=NW,image=img)

    # Preview content will be scrolable
    self.content = ScrolledFrame(self, height=int(h*0.3), use_ttk=True)
    # Bind the arrow keys and scroll wheel
    # self.content.bind_arrow_keys(self)
    # self.content.bind_scroll_wheel(self)
    self.content.grid(row=1, column=0, padx=PADX, pady=PADY_S, sticky=W + E + N + S)
    # Create the preview frame within the ScrolledFrame
    self.preview_view = self.content.display_widget(Frame)
    
    # self.data_actions = Frame(self, height=int(h*0.2), highlightbackground='gray', highlightthickness=1)
    # self.data_actions.grid(row=2, column=0, padx=PADX, pady=PADY_S, sticky=W + E + S)
    # self.data_actions.columnconfigure(0, weight=1)
    # self.data_actions.columnconfigure(1, weight=1)
    # self.data_actions.columnconfigure(2, weight=1)
    # self.data_actions.columnconfigure(3, weight=1)
    # self.data_actions.columnconfigure(4, weight=1)
    
    # self._preview_height = DEFAULT_VIEW_SIZE
    # self._preview_width = DEFAULT_VIEW_SIZE

    # self.scale_frame = LabelFrame(self.data_actions, text='Preview size:')
    # self.scale_frame.grid(row=0, column=0, columnspan=4, padx=PADX_S, pady=PADY_S, sticky=W+E)
    # self.scale_frame.columnconfigure(0, weight=1)
    # self.scale_frame.columnconfigure(1, weight=1)
    # self.scale_frame.columnconfigure(2, weight=1)
    # self.scale_frame.columnconfigure(3, weight=1)

    # self.var_h = IntVar()
    # self.var_h.set(self._preview_height)
    # self.scale_h = Scale(self.scale_frame, from_=50, to=500, resolution=50, variable=self.var_h, orient=HORIZONTAL, length=400)
    # self.scale_h.grid(row=0, column=0, columnspan=3, padx=PADX_S, pady=PADY_S, sticky=W+E)
    # self.scale_h.bind("<ButtonRelease-1>", self._set_h)

    # self.var_fixed_size = BooleanVar()
    # self.fixed_size = Checkbutton(self.scale_frame, variable=self.var_fixed_size, text='Fixed size', onvalue=True, offvalue=False, command=self._fix_size)
    # self.fixed_size.grid(row=0, column=3, padx=PADX_S, pady=PADY_S, sticky=W+E)

    # self.btn_save = Button(self.data_actions, text='Save', width=BTNW_S, command=self._save)
    # self.btn_save.grid(row=0, column=4, padx=PADX, pady=PADY)
    
    self._out = None
    self._idx_map :Dict = {}
    self._grid_rows: List[Widget] = []
    self._storage: FlowStorage = None
    self._last_view = None
    return

  @property
  def storage(self) -> FlowStorage:
    return self._storage
  
  @storage.setter
  def storage(self, storage) -> None:
    self._storage = storage
    return

  def clear_view(self) -> None:
    self._out = None
    self._idx_map = {}
    for row in self._grid_rows:
      row.grid_remove()  
    self._grid_rows.clear()
    self.content.scroll_to_top()
    if self._last_view is not None:
      self._last_view.grid_remove()
    return

  def default(self) -> None:
    # if self.var_fixed_size.get():
    #   return
    self._preview_height = DEFAULT_VIEW_SIZE
    self._preview_width = DEFAULT_VIEW_SIZE
    # self.var_h.set(self._preview_height)
    self._preview() 
    return

  def _preview_size(self, image) -> Tuple[int,int]:
    (h, w) = image.shape[:2]
    ratio = w/h
    if h > self._preview_height:
      h = self._preview_height
      w = int(h*ratio)
    elif w > self._preview_width:    
      w = self._preview_width
      h = int(w/ratio)
    elif h < self._preview_height and w < self._preview_width:
      h = self._preview_height
      w = int(h*ratio)
    else:
      pass
    return (w, h)

  def _fit_image(self, image):  
    dim = self._preview_size(image)
    image = cv2.resize(image, dim, interpolation=cv2.INTER_NEAREST)
    return image

  def _preview_image_list(self, parent, image: List[np.ndarray], name: str) -> Widget:
    image = cv2.hconcat(image)
    return self._preview_image(parent, image, name)

  def _preview_image(self, parent, image: np.ndarray, name: str) -> Widget:
    preview = self._fit_image(image)
    pil_image = Image.fromarray(preview)
    photo = ImageTk.PhotoImage(pil_image)
    view = Label(parent, name=name, image=photo)
    view.image = photo
    return view

  def _preview_object(self, parent, data: any, name: str) -> Widget:
    view = Label(parent, name=name, border=1)
    # text = json.dumps(data, indent = 3)
    # df = pd.DataFrame(data)
    view.config(text = data)
    return view

  def _get_preview(self, ref_type: FlowDataType) -> Callable:
    views = {
      FlowDataType.NP_ARRAY: self._preview_image,
      FlowDataType.LIST_NP_ARRAYS: self._preview_image_list
    }
    return views.get(ref_type, self._preview_object)

  def _clear_preview(self, idx: int) -> None:
    if len(self._grid_rows) > 0:
      self._out = None
      # map idx to preview idx
      row_idx = self._get_row_idx(f'{idx}')
      if row_idx == WITHOUT_PREVIEW_DATA:
        return
      row_idx = max(len(self._idx_map)-1, self._get_row_idx(f'{idx}'))
      try:
        # remove idx mapping for the idx
        self._idx_map.pop(f'{row_idx}')
        # remove existing preview item with the idx
        res = self._grid_rows.pop(row_idx)
        res.grid_remove()
      except IndexError:
        pass
    return
  
  def update_result(self, idx: int, state_id: str) -> None:
    self._show_last(state_id)
    self. _clear_preview(idx)
    return
 
  def _create_row_output_container(self, row_idx: int, title: str) -> Widget:
    state_frame = LabelFrame(self.preview_view, name=f'--{row_idx}--', text=title)
    state_frame.grid(row=row_idx, column=0, sticky=W)
    state_frame.rowconfigure(0, pad=15)
    state_frame.columnconfigure(0, weight=1)
    state_frame.columnconfigure(0, pad=15)
    # state_frame.columnconfigure(1, weight=1)
    # state_frame.columnconfigure(1, pad=15)
    return state_frame

  def _create_preview(self, row_idx, title, out_data, out_refs) -> None:
    preview_frame = self._create_row_output_container(row_idx, title)
    # previews for a state outputs 
    for i, ref in enumerate(out_refs):
      (ref_extr, ref_intr, ref_type) = ref
      data = out_data.get(ref_intr)
      if data is None:
        continue
      preview = self._get_preview(ref_type)
      # convert to a conventional format (without '.')
      name = ref_extr.replace('.', '-')
      widget = preview(preview_frame, data, name)
      widget.grid(row=i, column=0, sticky=W)
      widget.bind('<Button-1>', self._on_click)
    try:
      # remove existing item with the row_idx
      self._grid_rows.pop(row_idx)
    except IndexError:
      pass
    # set new one
    self._grid_rows.insert(row_idx, preview_frame)

    # Scroll view if need
    self.update_idletasks()
    h = preview_frame.winfo_height()
    self.content.focus_set()
    self.content.yview(SCROLL, h, UNITS)
    return

  def _get_row_idx(self, state_id: str) -> int:
    row_idx = self._idx_map.get(state_id, WITHOUT_PREVIEW_DATA)
    return row_idx

  @staticmethod
  def _parse_out_refs(refs) -> Tuple[str, str]:
    parts =refs[0][0].split('-')
    state_id = parts[0]
    title = '-'.join(parts[0:len(parts)-1])
    return state_id, title

  def _show_last(self, state_id: str) -> None:
    out_data = self._storage.get_state_output_data(state_id)
    refs = self._storage.get_state_output_refs(state_id)
    if out_data is None or refs is None:
      return
    out_refs = [(ref.ext_ref, ref.int_ref, ref.data_type) for ref in refs]  
    if len(out_refs) > 0:
      ref = out_refs[0]
      (ref_extr, ref_intr, ref_type) = ref
      data = out_data.get(ref_intr)
      if data.dtype == np.dtype('uint8'):
        pil_image = Image.fromarray(data)
        photo = ImageTk.PhotoImage(pil_image)
        self._last_view = Label(self._data_last, name='last image', image=photo)
        self._last_view.image = photo 
        self._last_view.grid(row=0, column=0, padx=PADX_S, pady=PADY_S, sticky=W + E + N + S)
      else:
        self._last_view.grid_remove()
      # self._canvas_data_last.create_image(x1=10, y1=10, anchor=NW, image=photo)
    return

  def _preview(self) -> None:   
    if self._out is None:
      return
    (out_refs, out_data) = self._out
    if len(out_refs) > 0:
      state_id, title = self._parse_out_refs(out_refs)
      row_idx = self._get_row_idx(state_id)
      self._create_preview(row_idx, title, out_data, out_refs)
    return

  def _map_idx_to_row_idx(self, idx: int) -> None:
    preview_row = len(self._idx_map)
    (out_refs, out_data) = self._out
    if len(out_refs) == 0 and len(out_data) == 0:
      # No data for preview
      self._idx_map[f'{idx}'] = WITHOUT_PREVIEW_DATA
      return
    # map idx to row_idx
    self._idx_map[f'{idx}'] = min(idx, preview_row)
    return

  def _show_preview(self, idx: int, state_id: str) -> None:
    out_data = self._storage.get_state_output_data(state_id)
    refs = self._storage.get_state_output_refs(state_id)
    if out_data is None or refs is None:
      return
    out_refs = [(ref.ext_ref, ref.int_ref, ref.data_type) for ref in refs]  
    self._out = (out_refs, out_data)
    self._map_idx_to_row_idx(idx)
    self._preview()
    return

  def show_result(self, idx: int, state_id: str) -> None:
    self._show_preview(idx, state_id)
    self._show_last(state_id)
    return
    
  def _on_click(self, event) -> None:
    event.widget.focus_set()
    active_widget_name = event.widget._name
    print(active_widget_name)
    for row in self._grid_rows:
      for child in row.children:
        if child == active_widget_name:
          self._plot(child)
    return

  def _plot(self, name: str) -> None:
    parts = name.split('-')
    state_id = parts[0] + '-' + parts[2]
    key = parts[3]
    data_dict = self._storage.get_state_output_data(state_id)
    data = data_dict.get(key)
    plot_dlg = PlotDialog(self, name, data)
    return

  def _set_h(self, event) -> None:
    self._preview_height = self.scale_h.get()
    self._preview()
    return

  def _fix_size(self) -> None:
    # self.scale_h['state'] = NORMAL
    # if self.var_fixed_size.get() == True:
    #   self.scale_h['state'] = DISABLED
    return

  def _save(self) -> None:
    print('save')
    return

  # TODO:
  # https://stackoverflow.com/questions/28005591/how-to-create-a-scrollable-canvas-that-scrolls-without-a-scroll-bar-in-python
  def _move(self, preview_frame):
    deltay = self._preview_height
    deltax = self._preview_width
    # make sure we don't move beyond our scrollable region
    (x0,y0,x1,y1) = self.content._canvas.coords()
    deltay = 0 if (deltay > 0 and y1 >= 400) else deltay
    deltay = 0 if (deltay < 0 and y0 <= -400) else deltay
    deltax = 0 if (deltax > 0 and x1 >= 400) else deltax
    deltax = 0 if (deltax < 0 and x0 <= -400) else deltax

    # move the item, then scroll it into view
    self.content._canvas.move(preview_frame, deltax, deltay)
    self._make_visible(preview_frame)    

  def _make_visible(self, preview_frame) -> None:
    # determine the bounding box of the visible area of the screen
    (cx0,cy0) = (self.content._canvas.canvasx(0), self.content._canvas.canvasy(0))
    (cx1,cy1) = (self.content._canvas.canvasx(self.content._canvas.cget("width")), 
                  self.content._canvas.canvasy(self.content._canvas.cget("height")))

    # determine the bounding box of the thing to be made visible
    (x0,y0,x1,y1) = self.content._canvas.coords(preview_frame)

    # determine how far off the screen the object is
    deltax = x0-cx0 if x0 <= cx0 else x1-cx1 if x1 >= cx1 else 0
    deltay = y0-cy0 if y0 <= cy0 else y1-cy1 if y1 >= cy1 else 0

    # scroll the canvas to make the item visible
    self.canvas.xview("scroll", int(deltax), "units")
    self.canvas.yview("scroll", int(deltay), "units")
    return
コード例 #3
0
class ParamsView(View):
    def __init__(self, parent):
        super().__init__(parent)
        self['text'] = 'Parameters'
        self._factory = ParamWidgetFactory()

        self.update_idletasks()
        h = self.parent.winfo_reqheight()

        self._flow = None
        self._grid_rows_descr: List[Dict] = []
        self._active_wd_idx = -1

        self.grid()
        self.rowconfigure(0, weight=1)
        self.rowconfigure(1, weight=1)

        # Content will be scrolable
        self._content = ScrolledFrame(self, use_ttk=True, height=int(h * 0.65))
        self._content.grid(row=0,
                           column=0,
                           padx=PADX,
                           pady=PADY_S,
                           sticky=N + S + W + E)
        # Create the params frame within the ScrolledFrame
        self._params_view = self._content.display_widget(Frame)

        # Setup param actions view
        self._params_actions_frame = Frame(self,
                                           highlightbackground='gray',
                                           highlightthickness=1)
        self.btn_params_reset = Button(self._params_actions_frame,
                                       text='Reset',
                                       width=BTNW_S)
        self.btn_params_default = Button(self._params_actions_frame,
                                         text='Default',
                                         width=BTNW_S)
        self.btn_params_io = Button(self._params_actions_frame,
                                    text='I/O',
                                    width=BTNW_S)
        self.btn_params_reset.grid(row=0,
                                   column=0,
                                   padx=PADX,
                                   pady=PADY_S,
                                   sticky=W + N)
        self.btn_params_default.grid(row=0,
                                     column=1,
                                     padx=PADX,
                                     pady=PADY_S,
                                     sticky=W + N)
        self.btn_params_io.grid(row=0,
                                column=2,
                                padx=PADX,
                                pady=PADY_S,
                                sticky=W + N)
        self._params_actions_frame.grid(row=1,
                                        column=0,
                                        padx=PADX,
                                        pady=PADY_S,
                                        sticky=W + E + S)

        self._activate_params_buttons()
        return

# API

    @property
    def descriptors(self) -> List[Dict]:
        return self._grid_rows_descr

    def get_active_item_params_widgets(self) -> List[Widget]:
        if self._active_wd_idx < 0:
            return None
        descriptors = self._grid_rows_descr[self._active_wd_idx]
        widgets = []
        for descr in descriptors:
            widget = descr.get('wd')
            widgets.append(widget)
        return widgets

    def get_item_name(self, idx: int) -> str:
        descriptors = self._grid_rows_descr[idx]
        widget_0 = descriptors[0].get('wd')
        parent_name = widget_0.winfo_parent()
        idx_s = parent_name.index('--')
        p_n: str = parent_name[idx_s + 2:len(parent_name) - 2]
        idx_point = p_n.find('-', 3)
        p_n = p_n[:idx_point] + '.' + p_n[idx_point + 1:]
        return p_n

    def get_item_params(self, idx: int) -> Dict:
        params = {}
        descriptors = self._grid_rows_descr[idx]
        for descr in descriptors:
            widget = descr.get('wd')
            name = widget.winfo_name()
            if name.startswith('--'):
                continue
            getter = descr.get('getter')
            value = getter()
            params[name] = value
        return params

    def set_item_params(self, idx: int, params) -> None:
        if self._active_wd_idx < 0:
            return None
        descriptors = self._grid_rows_descr[idx]
        for descr in descriptors:
            widget = descr.get('wd')
            name = widget.winfo_name()
            if name.startswith('--'):
                continue
            setter = descr.get('setter')
            setter(params.get(name))
        return

    def clear(self) -> None:
        for child in self._params_view.winfo_children():
            child.grid_remove()
        self._grid_rows_descr.clear()
        self._content.scroll_to_top()
        self._active_wd_idx = -1
        self._activate_params_buttons()
        return


# Build

    def build(self, flow: FlowModel) -> None:
        self._flow = flow
        items = copy.deepcopy(flow.items)
        for i, item in enumerate(items):
            item_params_frame = self._create_item_params_container(i, item)
            item_params_frame.grid(row=i, column=0, padx=PADX, sticky=W + E)
            self._factory.container = item_params_frame
            item_params_descr = self._create_item_params_widgets(i, item)
            self._grid_rows_descr.append(item_params_descr)
        self._disable_all()
        self._active_wd_idx = 0
        self._hightlighte_active_wd(True)
        self._set_active_wd_state(True)
        self._activate_params_buttons(True)
        return

    def _create_item_params_container(self, idx: int,
                                      item: FlowItemModel) -> Widget:
        i_n = item.name.replace('.', '-')
        name = f'--{idx}-{i_n}--'
        item_params_frame = LabelFrame(self._params_view, name=name)
        return item_params_frame

    def _create_item_params_widgets(self, idx: int,
                                    item: FlowItemModel) -> Dict:
        item_params_descr = []
        title = f'{idx}-{item.name}'
        i_n = item.name.replace('.', '-')
        name = f'--{idx}-{i_n}--'
        item_label = Label(self._factory.container, name=name, text=title)
        item_label.grid(row=0,
                        column=0,
                        columnspan=3,
                        padx=PADX_S,
                        pady=PADY_S,
                        sticky=W)
        item_params_descr.append({
            'name': item_label.winfo_name(),
            'getter': None,
            'setter': None,
            'wd': item_label
        })
        params, params_def = self._merge_curent_params_with_params_ws(item)
        for i, param_def in enumerate(params_def):
            name = param_def.get('name')
            comment = param_def.get('comment')
            pvalue = params.get(name, None)
            if pvalue is not None:
                param_def['default'] = pvalue
            getter, setter, param_widget = self._factory.create(param_def)
            param_widget.grid(row=i + 1,
                              column=1,
                              padx=PADX_S,
                              pady=PADY_S,
                              sticky=W)
            param_label = Label(self._factory.container, text=f'{name}')
            param_label.grid(row=i + 1,
                             column=0,
                             padx=PADX_S,
                             pady=PADY_S,
                             sticky=W)
            param_descr = Label(self._factory.container, text=f'{comment}')
            param_descr.grid(row=i + 1,
                             column=2,
                             padx=PADX_S,
                             pady=PADY_S,
                             sticky=W)
            item_params_descr.append({
                'name': param_widget.winfo_name(),
                'getter': getter,
                'setter': setter,
                'wd': param_widget
            })
        return item_params_descr

    @staticmethod
    def _merge_curent_params_with_params_ws(
            item: FlowItemModel) -> Tuple[Dict, Dict]:
        # merge curent params with params_ws
        params = item.params  # Dict
        params_ws = item.params_ws  # Dict
        params_def = item.params_def  # List[Dict]
        for k in params_ws.keys():
            if k in params:
                continue
            params[k] = params_ws.ket(k)
        return params, params_def

    def set_active_wd(self, idx: int) -> None:
        self._hightlighte_active_wd()
        if self._active_wd_idx > idx:
            # disable, when move backward
            self._set_active_wd_state()
        self._active_wd_idx = idx
        self._hightlighte_active_wd(True)
        self._set_active_wd_state(True)
        self._set_button_io_state(idx)
        return

    def _set_active_wd_state(self, active: bool = False) -> None:
        state = DISABLED
        if active:
            state = NORMAL
        descriptors = self._grid_rows_descr[self._active_wd_idx]
        for descr in descriptors:
            widget = descr.get('wd')
            widget['state'] = state
        return

    def _disable_all(self) -> None:
        for descriptors in self._grid_rows_descr:
            for descr in descriptors:
                widget = descr.get('wd')
                widget['state'] = DISABLED
        return

    # UI methods
    def _hightlighte_active_wd(self, active: bool = False) -> None:
        fg_color = 'black'
        bg_color = 'SystemButtonFace'
        if active:
            fg_color = 'white'
            bg_color = 'RoyalBlue'
        descriptors = self._grid_rows_descr[self._active_wd_idx]
        for descr in descriptors:
            widget = descr.get('wd')
            name = widget.winfo_name()
            if name.startswith('--'):
                widget['fg'] = fg_color
                widget['bg'] = bg_color
                break
        return

    def _activate_params_buttons(self, activate=False) -> None:
        state = DISABLED
        if activate:
            state = NORMAL
        self.btn_params_reset['state'] = state
        self.btn_params_default['state'] = state
        self.btn_params_io['state'] = state
        return

    def _set_button_io_state(self, idx: int) -> None:
        flow_item = self._flow.get_item(idx)
        params_def = flow_item.params_def
        self.btn_params_io['state'] = DISABLED
        for param_def in params_def:
            if param_def.get('name') == 'path':
                self.btn_params_io['state'] = NORMAL
                break
        return