|
@@ -68,6 +68,13 @@ def extract_values(x: Union[List[AutoCompleteFloatEdit], List[FloatEdit]]) -> It
|
|
|
def to_named_value(name: str) -> Callable[[str], Tuple[str,str]]:
|
|
|
return lambda e: (f'{name}#{e[0]}', e[1])
|
|
|
|
|
|
+def blank_ingredients_row(idx: int) -> Tuple[AutoCompleteEdit, FloatEdit, AutoCompleteEdit]:
|
|
|
+ return (
|
|
|
+ AutoCompleteEdit(('bg', f'product#{idx}')),
|
|
|
+ FloatEdit(('bg', f'')),
|
|
|
+ AutoCompleteEdit(('bg', f'unit#{idx}'))
|
|
|
+ )
|
|
|
+
|
|
|
class RecipeEditor(FocusWidget):
|
|
|
|
|
|
def keypress(self, size, key):
|
|
@@ -135,6 +142,13 @@ class RecipeEditor(FocusWidget):
|
|
|
w.set_edit_text(v)
|
|
|
if k == 'organic':
|
|
|
self.organic.set_state(v)
|
|
|
+ @property
|
|
|
+ def components(self):
|
|
|
+ return self._components
|
|
|
+
|
|
|
+ @components.setter
|
|
|
+ def components(self, _data: dict):
|
|
|
+ self._components = _data
|
|
|
|
|
|
def clear(self):
|
|
|
for ef in self.ingredients:
|
|
@@ -145,6 +159,53 @@ class RecipeEditor(FocusWidget):
|
|
|
self.instructions.set_edit_text('')
|
|
|
return self.update()
|
|
|
|
|
|
+ def add_ingredient(self):
|
|
|
+ self.ingredients.append(
|
|
|
+ blank_ingredients_row(len(self.ingredients))
|
|
|
+ )
|
|
|
+ l = LineBox(AttrMap(
|
|
|
+ AutoCompletePopUp(
|
|
|
+ self.ingredients[-1][0],
|
|
|
+ self.apply_choice,
|
|
|
+ lambda: self.activity_manager.show(self.update())
|
|
|
+ ), 'streak'), title=f'Product', title_align='left'
|
|
|
+ )
|
|
|
+ m = LineBox(
|
|
|
+ self.ingredients[-1][1], title=f'Quantity', title_align='left'
|
|
|
+ )
|
|
|
+ r = LineBox(AttrMap(
|
|
|
+ AutoCompletePopUp(
|
|
|
+ self.ingredients[-1][2],
|
|
|
+ self.apply_choice,
|
|
|
+ lambda: self.activity_manager.show(self.update())
|
|
|
+ ), 'streak'), title=f'Unit', title_align='left'
|
|
|
+ )
|
|
|
+ self.components['left_pane'].contents.append((l,('weight',1)))
|
|
|
+ self.components['middle_pane'][1].contents.append((m,('weight',1)))
|
|
|
+ self.components['right_pane'][1].contents.append((r,('weight',1)))
|
|
|
+ self.components['gutter'][1].contents = [
|
|
|
+ *[ (Divider(),('weight',1)) for _ in range(3) ],
|
|
|
+ *self.components['gutter'][1].contents,
|
|
|
+ ]
|
|
|
+ for idx, widget in enumerate(self.ingredients):
|
|
|
+ connect_signal(widget[0], 'postchange', lambda _,v: self.update())
|
|
|
+ connect_signal(widget[0], 'apply', lambda w, name: self.autocomplete_callback(
|
|
|
+ w, self.autocomplete_options(name, dict(map(
|
|
|
+ to_unnumbered_field,
|
|
|
+ filter(in_same_row(name), map(to_numbered_field, self.data.items())
|
|
|
+ ))))
|
|
|
+ ))
|
|
|
+ connect_signal(widget[1], 'postchange', lambda _,v: self.update())
|
|
|
+ connect_signal(widget[2], 'postchange', lambda _,v: self.update())
|
|
|
+ connect_signal(widget[2], 'apply', lambda w, name: self.autocomplete_callback(
|
|
|
+ w, self.autocomplete_options(name, dict(map(
|
|
|
+ to_unnumbered_field,
|
|
|
+ filter(in_same_row(name), map(to_numbered_field, self.data.items())
|
|
|
+ ))))
|
|
|
+ ))
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
def update(self):
|
|
|
data = self.data
|
|
|
organic = None if data['organic'] == 'mixed' else data['organic']
|
|
@@ -159,7 +220,7 @@ class RecipeEditor(FocusWidget):
|
|
|
except InvalidOperation:
|
|
|
quantity = None
|
|
|
|
|
|
- if None in (sort, product, unit):
|
|
|
+ if None in (sort, product, unit, quantity):
|
|
|
not_found = '>'
|
|
|
continue
|
|
|
|
|
@@ -187,6 +248,7 @@ class RecipeEditor(FocusWidget):
|
|
|
query_manager: QueryManager,
|
|
|
recipe,
|
|
|
):
|
|
|
+ self.components = dict()
|
|
|
self.buttons = {
|
|
|
'clear': Button(('streak', 'Clear')),
|
|
|
'exit': Button(('streak', 'Exit')),
|
|
@@ -198,13 +260,8 @@ class RecipeEditor(FocusWidget):
|
|
|
FloatEdit(('bg', f''), default=ingredient[1]),
|
|
|
AutoCompleteEdit(('bg', f'unit#{idx}'), edit_text=ingredient[2]),
|
|
|
) for idx, ingredient in enumerate(recipe['ingredients'])
|
|
|
- ] if len(recipe['ingredients']) else [
|
|
|
- (
|
|
|
- AutoCompleteEdit(('bg', 'product#0')),
|
|
|
- FloatEdit(('bg', f'')),
|
|
|
- AutoCompleteEdit(('bg', 'unit#0'))
|
|
|
- ),
|
|
|
- ]
|
|
|
+ ] if len(recipe['ingredients']) else [ ]
|
|
|
+
|
|
|
self.organic = NoTabCheckBox(('bg', "Organic"), state='mixed')
|
|
|
self.instructions = Edit('', edit_text=recipe['instructions'] or u'', multiline=True, allow_tab=True)
|
|
|
self.feeds = Text(f"Feeds: {recipe['feeds'] or ''}")
|
|
@@ -216,32 +273,15 @@ class RecipeEditor(FocusWidget):
|
|
|
self.feeds,
|
|
|
self.price,
|
|
|
]
|
|
|
-
|
|
|
+ self.activity_manager = activity_manager
|
|
|
self.query_manager = query_manager
|
|
|
self.autocomplete_options = lambda name, data: self.query_manager.unique_suggestions(name.split('#', 1)[0], **data)
|
|
|
self.autocomplete_callback = lambda widget, options: len(options) > 0 and widget._emit('open', options)
|
|
|
connect_signal(self.organic, 'postchange', lambda _,v: self.update())
|
|
|
|
|
|
- # todo: call this when adding new ingredient
|
|
|
- for idx, widget in enumerate(self.ingredients):
|
|
|
- connect_signal(widget[0], 'postchange', lambda _,v: self.update())
|
|
|
- connect_signal(widget[0], 'apply', lambda w, name: self.autocomplete_callback(
|
|
|
- w, self.autocomplete_options(name, dict(map(
|
|
|
- to_unnumbered_field,
|
|
|
- filter(in_same_row(name), map(to_numbered_field, self.data.items())
|
|
|
- ))))
|
|
|
- ))
|
|
|
- connect_signal(widget[1], 'postchange', lambda _,v: self.update())
|
|
|
- connect_signal(widget[2], 'postchange', lambda _,v: self.update())
|
|
|
- connect_signal(widget[2], 'apply', lambda w, name: self.autocomplete_callback(
|
|
|
- w, self.autocomplete_options(name, dict(map(
|
|
|
- to_unnumbered_field,
|
|
|
- filter(in_same_row(name), map(to_numbered_field, self.data.items())
|
|
|
- ))))
|
|
|
- ))
|
|
|
-
|
|
|
- connect_signal(self.buttons['clear'], 'click', lambda x: self.clear().update())
|
|
|
- connect_signal(self.buttons['exit'], 'click', lambda x: show_or_exit('esc'))
|
|
|
+ connect_signal(self.buttons['add'], 'click', lambda _: self.add_ingredient())
|
|
|
+ connect_signal(self.buttons['clear'], 'click', lambda _: self.clear().update())
|
|
|
+ connect_signal(self.buttons['exit'], 'click', lambda _: show_or_exit('esc'))
|
|
|
connect_signal(self.instructions, 'postchange', lambda _,v: self.update())
|
|
|
|
|
|
header = Text(u'Recipe Editor', 'center')
|
|
@@ -253,13 +293,12 @@ class RecipeEditor(FocusWidget):
|
|
|
])
|
|
|
banner = AttrMap(banner, 'banner')
|
|
|
|
|
|
- # todo: call this when adding new ingredient
|
|
|
left_pane = [
|
|
|
LineBox(AttrMap(
|
|
|
AutoCompletePopUp(
|
|
|
ingredient[0],
|
|
|
self.apply_choice,
|
|
|
- lambda: activity_manager.show(self.update())
|
|
|
+ lambda: self.activity_manager.show(self.update())
|
|
|
), 'streak'), title=f'Product', title_align='left'
|
|
|
) for idx, ingredient in enumerate(self.ingredients)
|
|
|
]
|
|
@@ -273,7 +312,7 @@ class RecipeEditor(FocusWidget):
|
|
|
AutoCompletePopUp(
|
|
|
ingredient[2],
|
|
|
self.apply_choice,
|
|
|
- lambda: activity_manager.show(self.update())
|
|
|
+ lambda: self.activity_manager.show(self.update())
|
|
|
), 'streak'), title=f'Unit', title_align='left'
|
|
|
) for idx, ingredient in enumerate(self.ingredients)
|
|
|
]
|
|
@@ -287,7 +326,7 @@ class RecipeEditor(FocusWidget):
|
|
|
]
|
|
|
|
|
|
|
|
|
- components = {
|
|
|
+ self.components = {
|
|
|
'top_pane': Columns([
|
|
|
(9, Pile([
|
|
|
Divider(),
|
|
@@ -307,19 +346,20 @@ class RecipeEditor(FocusWidget):
|
|
|
'left_pane': Pile(left_pane),
|
|
|
'gutter': (8, Pile(gutter))
|
|
|
}
|
|
|
+ self.add_ingredient()
|
|
|
|
|
|
widget = Pile([
|
|
|
banner,
|
|
|
Divider(),
|
|
|
- components['top_pane'],
|
|
|
- Columns((
|
|
|
- components['left_pane'],
|
|
|
- components['middle_pane'],
|
|
|
- components['right_pane'],
|
|
|
- #(1,Divider()),
|
|
|
- #components['gutter'],
|
|
|
- ), dividechars=0),
|
|
|
- components['bottom_pane'],
|
|
|
+ self.components['top_pane'],
|
|
|
+ Columns([
|
|
|
+ self.components['left_pane'],
|
|
|
+ self.components['middle_pane'],
|
|
|
+ self.components['right_pane'],
|
|
|
+ (1,Divider()),
|
|
|
+ self.components['gutter'],
|
|
|
+ ], dividechars=0),
|
|
|
+ self.components['bottom_pane'],
|
|
|
])
|
|
|
widget = Filler(widget, 'top')
|
|
|
widget = AttrMap(widget, 'bg')
|