Split the tenkey menu into separate control

hoping to re-use on the login screen, but also makes it easier to
override if needed
This commit is contained in:
Lance Edgar 2023-10-05 15:12:06 -05:00
parent 8f647a85b9
commit 734600817f
3 changed files with 262 additions and 168 deletions

View file

@ -26,6 +26,8 @@ WuttaPOS - custom controls (base class)
import flet as ft import flet as ft
from wuttapos.util import make_button
class WuttaControl(ft.UserControl): class WuttaControl(ft.UserControl):
@ -39,6 +41,9 @@ class WuttaControl(ft.UserControl):
def informed_refresh(self, **kwargs): def informed_refresh(self, **kwargs):
pass pass
def make_button(self, *args, **kwargs):
return make_button(*args, **kwargs)
def reset(self, e=None): def reset(self, e=None):
if self.on_reset: if self.on_reset:
self.on_reset(e=e) self.on_reset(e=e)

143
wuttapos/controls/tenkey.py Normal file
View file

@ -0,0 +1,143 @@
# -*- coding: utf-8; -*-
################################################################################
#
# WuttaPOS -- Pythonic Point of Sale System
# Copyright © 2023 Lance Edgar
#
# This file is part of WuttaPOS.
#
# WuttaPOS is free software: you can redistribute it and/or modify it under the
# terms of the GNU General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# WuttaPOS is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# WuttaPOS. If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
"""
WuttaPOS - ten-key control
"""
import flet as ft
from .base import WuttaControl
class WuttaTenkeyMenu(WuttaControl):
default_font_size = 40
default_button_size = 100
def __init__(self, *args, **kwargs):
self.on_char = kwargs.pop('on_char', None)
self.on_enter = kwargs.pop('on_enter', None)
self.on_up_click = kwargs.pop('on_up_click', None)
self.on_up_longpress = kwargs.pop('on_up_longpress', None)
self.on_down_click = kwargs.pop('on_down_click', None)
self.on_down_longpress = kwargs.pop('on_down_longpress', None)
super().__init__(*args, **kwargs)
def build(self):
return ft.Container(
content=ft.Column(
[
ft.Row(
[
self.make_tenkey_button("1"),
self.make_tenkey_button("2"),
self.make_tenkey_button("3"),
self.make_tenkey_button("@"),
],
spacing=0,
),
ft.Row(
[
self.make_tenkey_button("4"),
self.make_tenkey_button("5"),
self.make_tenkey_button("6"),
self.make_tenkey_button("", on_long_press=self.up_long_press),
],
spacing=0,
),
ft.Row(
[
self.make_tenkey_button("7"),
self.make_tenkey_button("8"),
self.make_tenkey_button("9"),
self.make_tenkey_button("", on_long_press=self.down_long_press),
],
spacing=0,
),
ft.Row(
[
self.make_tenkey_button("0"),
# self.make_tenkey_button("00"),
self.make_tenkey_button("."),
# TODO: should just specify 2x multiplier instead
self.make_tenkey_button("ENTER", width=self.default_button_size * 2),
],
alignment=ft.MainAxisAlignment.SPACE_BETWEEN,
spacing=0,
),
],
spacing=0,
),
)
def make_tenkey_button(
self,
text,
font_size=None,
bgcolor='green',
height=None,
width=None,
on_click=None,
on_long_press=None,
):
if not font_size:
font_size = self.default_font_size
if not height:
height = self.default_button_size
if not width:
width = self.default_button_size
if not on_click:
on_click = self.tenkey_click
return self.make_button(text, font_size=font_size, bgcolor=bgcolor,
height=height, width=width,
on_click=on_click,
on_long_press=on_long_press)
def tenkey_click(self, e):
value = e.control.content.value
if value == 'ENTER':
if self.on_enter:
self.on_enter(e)
elif value == '': # UP
if self.on_up_click:
self.on_up_click(e)
elif value == '': # DOWN
if self.on_down_click:
self.on_down_click(e)
else: # normal char key
if self.on_char:
self.on_char(value)
def up_long_press(self, e):
if self.on_up_longpress:
self.on_up_longpress(e)
def down_long_press(self, e):
if self.on_down_longpress:
self.on_down_longpress(e)

View file

@ -34,6 +34,7 @@ from .base import WuttaView
from wuttapos.controls.custlookup import WuttaCustomerLookup from wuttapos.controls.custlookup import WuttaCustomerLookup
from wuttapos.controls.itemlookup import WuttaProductLookup from wuttapos.controls.itemlookup import WuttaProductLookup
from wuttapos.controls.txnitem import WuttaTxnItem from wuttapos.controls.txnitem import WuttaTxnItem
from wuttapos.controls.tenkey import WuttaTenkeyMenu
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -479,64 +480,9 @@ class POSView(WuttaView):
# no value provided, so do lookup # no value provided, so do lookup
self.customer_lookup() self.customer_lookup()
def build_controls(self): def tenkey_char(self, key):
session = self.app.make_session() if key == '@':
handler = self.get_batch_handler()
self.tender_cash = handler.get_tender(session, 'cash')
self.tender_check = handler.get_tender(session, 'check')
session.expunge_all()
session.close()
self.main_input = ft.TextField(on_submit=self.main_submit,
text_size=24,
text_style=ft.TextStyle(weight=ft.FontWeight.BOLD),
autofocus=True)
self.selected_item = None
self.items = ft.ListView(
item_extent=50,
height=800,
)
self.txn_total = ft.Text("", size=40)
self.items_column = ft.Column(
controls=[
ft.Container(
content=self.items,
padding=ft.padding.only(10, 0, 10, 0)),
ft.Row([self.txn_total],
alignment=ft.MainAxisAlignment.END),
],
expand=1,
)
def tenkey_click(e):
value = e.control.content.value
if value == 'ENTER':
self.main_submit()
elif value == '': # backspace
if self.main_input.value:
self.main_input.value = self.main_input.value[:-1]
self.main_input.focus()
self.page.update()
elif value == 'CE': # clear entry
if self.main_input.value:
self.main_input.value = ""
elif self.set_quantity.data is not None:
self.set_quantity.data = None
self.set_quantity.value = None
elif self.selected_item:
self.selected_item.bgcolor = 'white'
self.selected_item = None
self.main_input.focus()
self.page.update()
elif value == '@':
quantity = self.main_input.value quantity = self.main_input.value
valid = False valid = False
@ -574,7 +520,15 @@ class POSView(WuttaView):
self.page.update() self.page.update()
elif value == '': # UP else: # normal char
self.main_input.value = f"{self.main_input.value or ''}{key}"
self.main_input.focus()
self.page.update()
def tenkey_enter(self, e):
self.main_submit()
def tenkey_up_click(self, e):
# select previous item, if selection in progress # select previous item, if selection in progress
if self.selected_item: if self.selected_item:
@ -587,7 +541,11 @@ class POSView(WuttaView):
self.items.scroll_to(delta=-50, duration=100) self.items.scroll_to(delta=-50, duration=100)
self.page.update() self.page.update()
elif value == '': def tenkey_up_longpress(self, e):
self.items.scroll_to(delta=-500, duration=100)
self.page.update()
def tenkey_down_click(self, e):
# select next item, if selection in progress # select next item, if selection in progress
if self.selected_item: if self.selected_item:
@ -600,88 +558,72 @@ class POSView(WuttaView):
self.items.scroll_to(delta=50, duration=100) self.items.scroll_to(delta=50, duration=100)
self.page.update() self.page.update()
else: def tenkey_down_longpress(self, e):
self.main_input.value = f"{self.main_input.value or ''}{value}"
self.main_input.focus()
self.page.update()
def up_long_press(e):
self.items.scroll_to(delta=-500, duration=100)
self.page.update()
def down_long_press(e):
self.items.scroll_to(delta=500, duration=100) self.items.scroll_to(delta=500, duration=100)
self.page.update() self.page.update()
tenkey_button_size = self.default_button_size def build_controls(self):
tenkey_font_size = self.default_font_size
def tenkey_button(text, session = self.app.make_session()
bgcolor='green', handler = self.get_batch_handler()
height=tenkey_button_size, self.tender_cash = handler.get_tender(session, 'cash')
width=tenkey_button_size, self.tender_check = handler.get_tender(session, 'check')
on_click=tenkey_click, session.expunge_all()
on_long_press=None, session.close()
):
return ft.Container(content=ft.Text(text, size=tenkey_font_size,
weight=ft.FontWeight.BOLD),
height=height,
width=width,
on_click=on_click,
on_long_press=on_long_press,
alignment=ft.alignment.center,
border=ft.border.all(1, 'black'),
border_radius=ft.border_radius.all(5),
bgcolor=bgcolor)
self.tenkey_menu = ft.Container( self.main_input = ft.TextField(on_submit=self.main_submit,
content=ft.Column( text_size=24,
[ text_style=ft.TextStyle(weight=ft.FontWeight.BOLD),
ft.Row( autofocus=True)
[
tenkey_button("1"),
tenkey_button("2"),
tenkey_button("3"),
tenkey_button("@"),
],
spacing=0,
),
ft.Row(
[
tenkey_button("4"),
tenkey_button("5"),
tenkey_button("6"),
tenkey_button("", on_long_press=up_long_press),
],
spacing=0,
),
ft.Row(
[
tenkey_button("7"),
tenkey_button("8"),
tenkey_button("9"),
tenkey_button("", on_long_press=down_long_press),
],
spacing=0,
),
ft.Row(
[
tenkey_button("0"),
# tenkey_button("00"),
tenkey_button("."),
tenkey_button("ENTER", width=tenkey_button_size * 2),
],
alignment=ft.MainAxisAlignment.SPACE_BETWEEN,
spacing=0,
),
],
spacing=0,
),
expand=0)
meta_button_height = tenkey_button_size self.selected_item = None
self.items = ft.ListView(
item_extent=50,
height=800,
)
self.txn_total = ft.Text("", size=40)
self.items_column = ft.Column(
controls=[
ft.Container(
content=self.items,
padding=ft.padding.only(10, 0, 10, 0)),
ft.Row([self.txn_total],
alignment=ft.MainAxisAlignment.END),
],
expand=1,
)
def backspace_click(e):
if self.main_input.value:
self.main_input.value = self.main_input.value[:-1]
self.main_input.focus()
self.page.update()
def clear_entry_click(e):
if self.main_input.value:
self.main_input.value = ""
elif self.set_quantity.data is not None:
self.set_quantity.data = None
self.set_quantity.value = None
elif self.selected_item:
self.selected_item.bgcolor = 'white'
self.selected_item = None
self.main_input.focus()
self.page.update()
self.tenkey_menu = WuttaTenkeyMenu(self.config,
on_char=self.tenkey_char,
on_enter=self.tenkey_enter,
on_up_click=self.tenkey_up_click,
on_up_longpress=self.tenkey_up_longpress,
on_down_click=self.tenkey_down_click,
on_down_longpress=self.tenkey_down_longpress)
meta_button_height = self.default_button_size
meta_button_width = meta_button_height * 2 meta_button_width = meta_button_height * 2
meta_font_size = tenkey_font_size meta_font_size = self.default_font_size
def meta_button(text, on_click=None, bgcolor='blue', data=None, def meta_button(text, on_click=None, bgcolor='blue', data=None,
font_size=None): font_size=None):
@ -733,9 +675,9 @@ class POSView(WuttaView):
), ),
expand=0) expand=0)
context_button_height = tenkey_button_size context_button_height = self.default_button_size
context_button_width = context_button_height * 2 context_button_width = context_button_height * 2
context_font_size = tenkey_font_size context_font_size = self.default_font_size
def context_button(text, on_click=None, data=None): def context_button(text, on_click=None, data=None):
return ft.Container(content=ft.Text(text, size=context_font_size, return ft.Container(content=ft.Text(text, size=context_font_size,
@ -776,8 +718,12 @@ class POSView(WuttaView):
[ [
self.set_quantity, self.set_quantity,
self.main_input, self.main_input,
tenkey_button("", height=70, width=70), self.make_button("", font_size=40, bgcolor='green',
tenkey_button("CE", height=70, width=70), height=70, width=70,
on_click=backspace_click),
self.make_button("CE", font_size=40, bgcolor='green',
height=70, width=70,
on_click=clear_entry_click),
], ],
alignment=ft.MainAxisAlignment.CENTER, alignment=ft.MainAxisAlignment.CENTER,
expand=True, expand=True,