text: """
  pygame-menu
  https://github.com/ppizarror/pygame-menu
  
  EXAMPLE - CALCULATOR
  Simple calculator app.
  """
  
  __all__ = ['main']
  
  import pygame
  import pygame_menu
  from pygame_menu.examples import create_example_window
  
  from typing import Union, List
  
  
  class CalculatorApp(object):
      """
      Simple calculator app.
      """
      op: str  # Operation
      prev: str  # Prev value
      curr: str  # Current value
      menu: 'pygame_menu.Menu'
      screen: 'pygame_menu.widgets.Label'
      surface: 'pygame.Surface'
  
      # noinspection PyArgumentEqualDefault
      def __init__(self) -> None:
          self.surface = create_example_window('Example - Calculator', (320, 480))
  
          # Configure theme
          theme = pygame_menu.Theme()
  
          theme.background_color = (43, 43, 43)
          theme.title_background_color = (43, 43, 43)
          theme.title_bar_style = pygame_menu.widgets.MENUBAR_STYLE_SIMPLE
          theme.title_close_button_cursor = pygame_menu.locals.CURSOR_HAND
          theme.title_font_size = 35
          theme.widget_alignment = pygame_menu.locals.ALIGN_LEFT
          theme.widget_background_color = None
          theme.widget_font = pygame_menu.font.FONT_DIGITAL
          theme.widget_font_color = (255, 255, 255)
          theme.widget_font_size = 40
          theme.widget_padding = 0
          theme.widget_selection_effect = \
              pygame_menu.widgets.HighlightSelection(1, 0, 0).set_color((120, 120, 120))
  
          self.menu = pygame_menu.Menu('', 320, 480,
                                       center_content=False,
                                       mouse_motion_selection=True,
                                       onclose=pygame_menu.events.EXIT,
                                       overflow=False,
                                       theme=theme,
                                       )
          menu_deco = self.menu.get_scrollarea().get_decorator()
  
          # Add the layout
          self.menu.add.vertical_margin(40)
          menu_deco.add_rectangle(10, 88, 300, 55, (60, 63, 65), use_center_positioning=False)
          self.screen = self.menu.add.label('0', background_color=None, margin=(10, 0),
                                            selectable=True, selection_effect=None)
          self.menu.add.vertical_margin(20)
  
          cursor = pygame_menu.locals.CURSOR_HAND
  
          # Add horizontal frames
          f1 = self.menu.add.frame_h(299, 54, margin=(10, 0))
          b1 = f1.pack(self.menu.add.button('1', lambda: self._press(1), cursor=cursor))
          b2 = f1.pack(self.menu.add.button('2', lambda: self._press(2), cursor=cursor),
                       align=pygame_menu.locals.ALIGN_CENTER)
          b3 = f1.pack(self.menu.add.button('3', lambda: self._press(3), cursor=cursor),
                       align=pygame_menu.locals.ALIGN_RIGHT)
          self.menu.add.vertical_margin(10)
  
          f2 = self.menu.add.frame_h(299, 54, margin=(10, 0))
          b4 = f2.pack(self.menu.add.button('4', lambda: self._press(4), cursor=cursor))
          b5 = f2.pack(self.menu.add.button('5', lambda: self._press(5), cursor=cursor),
                       align=pygame_menu.locals.ALIGN_CENTER)
          b6 = f2.pack(self.menu.add.button('6', lambda: self._press(6), cursor=cursor),
                       align=pygame_menu.locals.ALIGN_RIGHT)
          self.menu.add.vertical_margin(10)
  
          f3 = self.menu.add.frame_h(299, 54, margin=(10, 0))
          b7 = f3.pack(self.menu.add.button('7', lambda: self._press(7), cursor=cursor))
          b8 = f3.pack(self.menu.add.button('8', lambda: self._press(8), cursor=cursor),
                       align=pygame_menu.locals.ALIGN_CENTER)
          b9 = f3.pack(self.menu.add.button('9', lambda: self._press(9), cursor=cursor),
                       align=pygame_menu.locals.ALIGN_RIGHT)
          self.menu.add.vertical_margin(10)
  
          f4 = self.menu.add.frame_h(299, 54, margin=(10, 0))
          b0 = f4.pack(self.menu.add.button('0', lambda: self._press(0), cursor=cursor))
          b_plus = f4.pack(self.menu.add.button('+', lambda: self._press('+'), cursor=cursor),
                           align=pygame_menu.locals.ALIGN_CENTER)
          b_minus = f4.pack(self.menu.add.button('-', lambda: self._press('-'), cursor=cursor),
                            align=pygame_menu.locals.ALIGN_RIGHT)
          self.menu.add.vertical_margin(10)
  
          f5 = self.menu.add.frame_h(299, 54, margin=(10, 0))
          b_times = f5.pack(self.menu.add.button('x', lambda: self._press('x'), cursor=cursor))
          b_div = f5.pack(self.menu.add.button('/', lambda: self._press('/'), cursor=cursor),
                          align=pygame_menu.locals.ALIGN_CENTER)
          beq = f5.pack(self.menu.add.button('=', lambda: self._press('='), cursor=cursor),
                        align=pygame_menu.locals.ALIGN_RIGHT)
  
          # Add decorator for each object
          for widget in (b1, b2, b3, b4, b5, b6, b7, b8, b9, b0, beq, b_plus,
                         b_minus, b_times, b_div):
              w_deco = widget.get_decorator()
              if widget != beq:
                  w_deco.add_rectangle(-37, -27, 74, 54, (15, 15, 15))
                  on_layer = w_deco.add_rectangle(-37, -27, 74, 54, (84, 84, 84))
              else:
                  w_deco.add_rectangle(-37, -27, 74, 54, (38, 96, 103))
                  on_layer = w_deco.add_rectangle(-37, -27, 74, 54, (40, 171, 187))
              w_deco.disable(on_layer)
              widget.set_attribute('on_layer', on_layer)
  
              def widget_select(sel: bool, wid: 'pygame_menu.widgets.Widget', _):
                  """
                  Function triggered if widget is selected
                  """
                  lay = wid.get_attribute('on_layer')
                  if sel:
                      wid.get_decorator().enable(lay)
                  else:
                      wid.get_decorator().disable(lay)
  
              widget.set_onselect(widget_select)
              widget.set_padding((2, 19, 0, 23))
              widget._keyboard_enabled = False
  
          self.prev = ''
          self.curr = ''
          self.op = ''
  
          self.menu.set_onupdate(self.process_events)
          self.menu.set_onwindowmouseleave(lambda m: self.screen.select(update_menu=True))
  
      def process_events(self, events: List['pygame.event.Event'], _=None) -> None:
          """
          Process events from user.
          """
          for event in events:
              if event.type == pygame.KEYDOWN:
                  # noinspection PyUnresolvedReferences
                  if event.key == pygame.K_0:
                      self._press(0)
                  elif event.key == pygame.K_1:
                      self._press(1)
                  elif event.key == pygame.K_2:
                      self._press(2)
                  elif event.key == pygame.K_3:
                      self._press(3)
                  elif event.key == pygame.K_4:
                      self._press(4)
                  elif event.key == pygame.K_5:
                      self._press(5)
                  elif event.key == pygame.K_6:
                      self._press(6)
                  elif event.key == pygame.K_7:
                      self._press(7)
                  elif event.key == pygame.K_8:
                      self._press(8)
                  elif event.key == pygame.K_9:
                      self._press(9)
                  elif event.key == pygame.K_PLUS:
                      self._press('+')
                  elif event.key == pygame.K_MINUS:
                      self._press('-')
                  elif event.key == pygame.K_SLASH or \
                          (hasattr(pygame, 'K_PERCENT') and event.key == pygame.K_PERCENT):
                      self._press('/')
                  elif event.key == pygame.K_ASTERISK or event.key == pygame.K_x:
                      self._press('x')
                  elif event.key == pygame.K_EQUALS or event.key == pygame.K_RETURN:
                      self._press('=')
                  elif event.key == pygame.K_BACKSPACE:
                      self._press('=')
                      self._press('=')
  
      def _operate(self) -> Union[int, float]:
          """
          Operate current and previous values.
  
          :return: Operation result
          """
          a = 0 if self.curr == '' else float(self.curr)
          b = 0 if self.prev == '' else float(self.prev)
          c = 0
          if self.op == '+':
              c = a + b
          elif self.op == '-':
              c = b - a
          elif self.op == 'x':
              c = a * b
          elif self.op == '/':
              if a != 0:
                  c = b / a
              else:
                  self.screen.set_title('Error')
          return int(c)
  
      def _press(self, digit: Union[int, str]) -> None:
          """
          Press calculator digit.
  
          :param digit: Number or symbol
          """
          if digit in ('+', '-', 'x', '/'):
              if self.curr != '':
                  if self.op != '':
                      self.prev = str(self._operate())
                  else:
                      self.prev = self.curr
                  self.curr = ''
              self.op = digit
              if len(self.prev) <= 8:
                  self.screen.set_title(self.prev + self.op)
              else:
                  self.screen.set_title('Ans' + self.op)
          elif digit == '=':
              if self.prev == '':
                  self.curr = ''
                  self.screen.set_title('0')
                  return
              c = self._operate()
              self.screen.set_title(str(c))
              if len(str(c)) > 8:
                  c = 0
                  self.screen.set_title('Overflow')
              self.prev = ''
              self.curr = str(c)
              self.op = ''
          else:
              if self.op == '':
                  if len(self.prev) <= 7:
                      self.prev += str(digit)
                      self.prev = self._format(self.prev)
                  self.screen.set_title(self.prev)
              else:
                  if len(self.curr) <= 7:
                      self.curr += str(digit)
                      self.curr = self._format(self.curr)
                  self.screen.set_title(self.curr)
  
      @staticmethod
      def _format(x: str) -> str:
          """
          Format number.
  
          :param x: Number
          :return: Str
          """
          try:
              if int(x) == float(x):
                  return str(int(x))
          except ValueError:
              pass
          try:
              x = float(x)
          except ValueError:
              pass
  
          return str(round(int(x), 0))
  
      def mainloop(self, test: bool) -> None:
          """
          App mainloop.
  
          :param test: Test status
          """
          self.menu.mainloop(self.surface, disable_loop=test)
  
  
  def main(test: bool = False) -> 'CalculatorApp':
      """
      Main function.
  
      :param test: Indicate function is being tested
      :return: App object
      """
      app = CalculatorApp()
      app.mainloop(test)
      return app
  
  
  if __name__ == '__main__':
      main()
  