1#!/usr/bin/env python3 2 3import re 4 5from asciimatics.effects import Julia, Clock 6from asciimatics.widgets import Frame, TextBox, Layout, Label, Divider, Text, \ 7 CheckBox, RadioButtons, Button, PopUpDialog 8from asciimatics.scene import Scene 9from asciimatics.screen import Screen 10from asciimatics.exceptions import ResizeScreenError, NextScene, StopApplication, \ 11 InvalidFields 12import sys 13 14# Initial data for the form 15form_data = { 16 "TA": ["Hello world!", "How are you?"], 17 "TB": "alphabet", 18 "TC": "123", 19 "TD": "a@b.com", 20 "Things": 2, 21 "CA": False, 22 "CB": True, 23 "CC": False, 24} 25 26 27class DemoFrame(Frame): 28 def __init__(self, screen): 29 super(DemoFrame, self).__init__(screen, 30 int(screen.height * 2 // 3), 31 int(screen.width * 2 // 3), 32 data=form_data, 33 has_shadow=True, 34 name="My Form") 35 layout = Layout([1, 18, 1]) 36 self.add_layout(layout) 37 self._reset_button = Button("Reset", self._reset) 38 layout.add_widget(Label("Group 1:"), 1) 39 layout.add_widget(TextBox(5, 40 label="My First Box:", 41 name="TA", 42 on_change=self._on_change), 1) 43 layout.add_widget( 44 Text(label="Alpha:", 45 name="TB", 46 on_change=self._on_change, 47 validator="^[a-zA-Z]*$"), 1) 48 layout.add_widget( 49 Text(label="Number:", 50 name="TC", 51 on_change=self._on_change, 52 validator="^[0-9]*$"), 1) 53 layout.add_widget( 54 Text(label="Email:", 55 name="TD", 56 on_change=self._on_change, 57 validator=self._check_email), 1) 58 layout.add_widget(Divider(height=2), 1) 59 layout.add_widget(Label("Group 2:"), 1) 60 layout.add_widget(RadioButtons([("Option 1", 1), 61 ("Option 2", 2), 62 ("Option 3", 3)], 63 label="A Longer Selection:", 64 name="Things", 65 on_change=self._on_change), 1) 66 layout.add_widget(CheckBox("Field 1", 67 label="A very silly long name for fields:", 68 name="CA", 69 on_change=self._on_change), 1) 70 layout.add_widget( 71 CheckBox("Field 2", name="CB", on_change=self._on_change), 1) 72 layout.add_widget( 73 CheckBox("Field 3", name="CC", on_change=self._on_change), 1) 74 layout.add_widget(Divider(height=3), 1) 75 layout2 = Layout([1, 1, 1]) 76 self.add_layout(layout2) 77 layout2.add_widget(self._reset_button, 0) 78 layout2.add_widget(Button("View Data", self._view), 1) 79 layout2.add_widget(Button("Quit", self._quit), 2) 80 self.fix() 81 82 def _on_change(self): 83 changed = False 84 self.save() 85 for key, value in self.data.items(): 86 if key not in form_data or form_data[key] != value: 87 changed = True 88 break 89 self._reset_button.disabled = not changed 90 91 def _reset(self): 92 self.reset() 93 raise NextScene() 94 95 def _view(self): 96 # Build result of this form and display it. 97 try: 98 self.save(validate=True) 99 message = "Values entered are:\n\n" 100 for key, value in self.data.items(): 101 message += "- {}: {}\n".format(key, value) 102 except InvalidFields as exc: 103 message = "The following fields are invalid:\n\n" 104 for field in exc.fields: 105 message += "- {}\n".format(field) 106 self._scene.add_effect( 107 PopUpDialog(self._screen, message, ["OK"])) 108 109 def _quit(self): 110 self._scene.add_effect( 111 PopUpDialog(self._screen, 112 "Are you sure?", 113 ["Yes", "No"], 114 on_close=self._quit_on_yes)) 115 116 @staticmethod 117 def _check_email(value): 118 m = re.match(r"^[a-zA-Z0-9_\-.]+@[a-zA-Z0-9_\-.]+\.[a-zA-Z0-9_\-.]+$", 119 value) 120 return len(value) == 0 or m is not None 121 122 @staticmethod 123 def _quit_on_yes(selected): 124 # Yes is the first button 125 if selected == 0: 126 raise StopApplication("User requested exit") 127 128 129class ClockFrame(Frame): 130 def __init__(self, screen, x, y): 131 super(ClockFrame, self).__init__(screen, 13, 26, 132 name="Clock", 133 has_shadow=True, 134 x=x, y=y) 135 self.add_effect(Clock(self._canvas, 13, 7, 7, Screen.COLOUR_BLUE)) 136 self.fix() 137 138 139def demo(screen, scene): 140 scenes = [] 141 effects = [ 142 Julia(screen), 143 ClockFrame(screen, 0, 0), 144 ClockFrame(screen, screen.width - 26, 0), 145 ClockFrame(screen, 0, screen.height - 13), 146 ClockFrame(screen, screen.width - 26, screen.height - 13), 147 DemoFrame(screen), 148 ] 149 scenes.append(Scene(effects, -1)) 150 151 screen.play(scenes, stop_on_resize=True, start_scene=scene) 152 153 154last_scene = None 155while True: 156 try: 157 Screen.wrapper(demo, catch_interrupt=False, arguments=[last_scene]) 158 sys.exit(0) 159 except ResizeScreenError as e: 160 last_scene = e.scene 161