class StoryTests(unittest.TestCase): def setUp(self): self.s = Story() def tearDown(self): del self.s def test_add_node(self): self.s.add_node('a') self.assertTrue('a' in self.s) self.s.add_node(1) self.assertFalse(1 in self.s) self.assertTrue('1' in self.s) l = ['b', 'c', 'd'] self.s.add_nodes_from(l) for c in l: self.assertTrue(c in self.s) self.assertTrue('a' in self.s) self.assertTrue('1' in self.s) def test_add_edge(self): self.s.add_node('a') self.s.add_node('b') self.s.add_edge('a', 'b') self.assertTrue('a' in self.s) self.assertTrue('b' in self.s) self.assertTrue('b' in self.s.neighbors('a')) self.assertFalse('a' in self.s.neighbors('b')) self.s.add_edge('c', 'd') self.assertTrue('c' in self.s) self.assertTrue('d' in self.s) self.assertTrue('d' in self.s.neighbors('c')) self.assertFalse('c' in self.s.neighbors('d')) ebunch = [('b', 'c'), ('d', 'e')] self.s.add_edges_from(ebunch) self.assertTrue('e' in self.s) def test_add_undir_edge(self): self.s.add_node('a') self.s.add_node('b') self.s.add_undirected_edge('a', 'b') self.assertTrue('a' in self.s) self.assertTrue('b' in self.s) self.assertTrue('b' in self.s.neighbors('a')) self.assertTrue('a' in self.s.neighbors('b')) self.s.add_undirected_edge('c', 'd') self.assertTrue('c' in self.s) self.assertTrue('d' in self.s) self.assertTrue('d' in self.s.neighbors('c')) self.assertTrue('c' in self.s.neighbors('d')) ebunch = [('b', 'c'), ('d', 'e')] self.s.add_undirected_edges_from(ebunch) self.assertTrue('e' in self.s) def test_set_current(self): with self.assertRaises(StoryError): self.s.current = 'a' self.s.add_node('a') self.s.current = 'a' self.assertTrue('a' in self.s.visited) self.assertTrue(self.s.current == 'a') def test_add_actions(self): self.s.add_node('a') s1 = 'This is a test message' self.s.add_say('a', message=s1) s2 = 'Fake message' self.s.add_say('a', message=s2) actions = self.s.node['a']['actions'] self.assertTrue(actions == [{'type': 'say', 'kwargs': {'message': s1}}, {'type': 'say', 'kwargs': {'message': s2}}]) def test_run_conditions1(self): l = ['a', 'b', 'c'] self.s.add_nodes_from(l) self.s.require_visit('b', 'a') self.s.require_visit('c', 'a', 'b') self.assertFalse('a' in self.s.visited) condition = self.s.run_conditions('b')[0] self.assertFalse(condition()) condition = self.s.run_conditions('c')[0] self.assertFalse(condition()) self.s.current = 'a' condition = self.s.run_conditions('b')[0] self.assertTrue(condition()) condition = self.s.run_conditions('c')[0] self.assertFalse(condition()) self.s.current = 'b' condition = self.s.run_conditions('c')[0] self.assertTrue(condition()) def test_run_conditions2(self): l = ['a', 'b', 'c', 'd'] self.s.add_nodes_from(l) self.s.context = {'apples': 5} self.s.check_context_for('b', 'apples') self.s.check_context_for('c', apples=6) self.s.check_context_for('d', 'oranges') condition = self.s.run_conditions('b')[0] self.assertTrue(condition()) condition = self.s.run_conditions('c')[0] self.assertFalse(condition()) condition = self.s.run_conditions('d')[0] self.assertFalse(condition()) updated_context = {'apples': 6, 'oranges': 0} self.s.update_context(updated_context) condition = self.s.run_conditions('b')[0] self.assertTrue(condition()) condition = self.s.run_conditions('c')[0] self.assertTrue(condition()) condition = self.s.run_conditions('d')[0] self.assertTrue(condition()) def test_context(self): d = {'a': 1, 'b': 2} self.s.context = d self.assertTrue(self.s.context == d) self.assertFalse(self.s.context is d) def test_run(self): # test empty self.s() l = ['a', 'b', 'c', 'd'] self.s.add_nodes_from(l) self.s.add_edge('a', 'b') self.s.add_edge('a', 'c') self.s.add_edge('c', 'd') self.s.current = 'a' path = ['c', 'd'] path_iter = iter(path) current = iter(path) dummy_input = lambda: next(path_iter) while not self.s.is_finished: self.s.input_fct = dummy_input self.s() self.assertTrue(self.s.current == next(current)) '''
class EditScreen(Screen): # dropdown_wid = ObjectProperty() dropdown_btn_wid = ObjectProperty() node_info_wid = ObjectProperty() refresh_btn = ObjectProperty() storyboard_wid = ObjectProperty() def __init__(self, **kwargs): super(EditScreen, self).__init__(**kwargs) self.d = None self.init_node_select_dropdown() self.story = Story() self.current_node = None self.refresh_btn.bind(on_release=self.refresh_graph) self.current_file = '' def init_node_select_dropdown(self): self.d = d = DropDown() b = Button(text='Add a node...', size_hint_y=None, height=dp(30)) b.bind(on_release=self.show_add_popup) d.add_widget(b) d.bind(on_select=lambda _, text: setattr(self.dropdown_btn_wid, 'text', text)) self.dropdown_btn_wid.bind(on_release=d.open) def show_file_browser(self, action): p = FileBrowserPopup() def update_current_file(instance, text): self.current_file = p.current_path + '/' + text.strip() if action == 'save as': p.filename_inp.bind(text=update_current_file) p.action_btn.text = 'Save' def save(button): self.save_current() p.dismiss() p.action_btn.bind(on_release=save) p.open() elif action == 'load': p.action_btn.text = 'Load' def load(button): path = p.selected_file self.load_story(path) p.dismiss() p.action_btn.bind(on_release=load) p.open() def save_current(self): if self.current_file: filename = self.current_file.strip() # check whether user has appended '.story' filename extension filename = filename.split('.') if len(filename) == 1 or filename[-1] != 'story': filename.append('story') filename = '.'.join(filename) print(filename) with open(filename, 'w') as f: pickle.dump(self.story, f) else: self.show_file_browser('save as') def load_story(self, path): # TODO: check whether current file is saved with open(path, 'r') as f: try: obj = pickle.load(f) except IOError as e: print(str(e)) return if isinstance(obj, Story): self.story = obj else: # TODO: display helpful message return for node in self.story: b = Button(text=node, size_hint_y=None, height=dp(30)) b.bind(on_release=self.show_info_callback) self.d.add_widget(b) self.refresh_graph() def check_current_file(self): board = self.ids['board'] if board.current_file: board.save_story(board.current_file) else: self.show_file_chooser() def refresh_graph(self, *args): g = self.story plt.clf() nx.draw_networkx(g, node_size=2000, font_size=dp(16), node_shape=',') curr_axes = plt.gca() curr_axes.axes.get_xaxis().set_visible(False) curr_axes.axes.get_yaxis().set_visible(False) buf = io.BytesIO() plt.savefig(buf, format='png') buf.seek(0) image = CoreImage(buf, ext='png') self.storyboard_wid.texture = image.texture def show_add_popup(self, button): # show the add popup p = AddNodePopup(attach_to=self) p.open() def add_callback(button): """Add the node to the story and update the dropdown menu """ self.d.dismiss() node_name = p.node_name self.story.add_node(node_name) print(self.story.nodes()) p.dismiss() # update the dropdown menu b = Button(text=node_name, size_hint_y=None, height=dp(30)) b.bind(on_release=self.show_info_callback) self.d.add_widget(b) p.submit_btn_wid.bind(on_release=add_callback) def show_info_callback(self, button): """Shows the node information in the sidebar """ self.current_node = button.text self.d.select(button.text) # p.dismiss() node_info = self.node_info_wid node_info.clear_widgets() node_info.add_widget(Label(text='name:')) # TODO: allow node renaming? node_info.add_widget(TextInput(text=button.text, multiline=False)) node_info.add_widget(Label(text='actions:')) actions_b = Button(text='edit...') actions_b.bind(on_release=self.show_add_action_popup) node_info.add_widget(actions_b) node_info.add_widget(Label(text='destinations:')) dest_b = Button(text='edit...') dest_b.bind(on_release=self.show_add_dest_popup) node_info.add_widget(dest_b) node_info.add_widget(Label(text='origins:')) orig_b = Button(text='edit...') orig_b.bind(on_release=self.show_add_origin_popup) node_info.add_widget(orig_b) def show_add_action_popup(self, button): p = AddActionPopup(existing_actions=self.story.get_actions(self.current_node), attach_to=self) p.open() def add_action_callback(button): a = Action() p.add_action(a) # p.actions_list_wid.add_widget(a) # p.actions_temp.append(a) def update_story(action): if action.action_type == 'say': self.story.add_say(self.current_node, **action.parameters) elif action.action_type == 'listen': self.story.add_listen(self.current_node, **action.parameters) elif action.action_type == 'play': self.story.add_play(self.current_node, **action.parameters) def save_callback(button): actions = p.actions_temp for action in actions: update_story(action) p.dismiss() p.add_action_btn_wid.bind(on_release=add_action_callback) p.save_btn.bind(on_release=save_callback) def show_add_dest_popup(self, button): p = AddEdgePopup(title='Add destinations') valid_dest = self.story.nodes() valid_dest.remove(self.current_node) for dest in valid_dest: b = ToggleButton(text=dest, size_hint_y=None, height=dp(30)) if dest in self.story.neighbors(self.current_node): b.state = 'down' p.node_list.add_widget(b) p.node_list.add_widget(Widget()) def save_callback(button): to_add = [] to_remove = [] for child in p.node_list.children: if isinstance(child, ToggleButton): node_name = child.text if child.state == 'down': to_add.append(node_name) else: to_remove.append(node_name) for node in to_add: if node not in self.story.neighbors(self.current_node): self.story.add_edge(self.current_node, node) for node in to_remove: if node in self.story.neighbors(self.current_node): self.story.remove_edge(self.current_node, node) p.dismiss() p.save_btn.bind(on_release=save_callback) p.open() def show_add_origin_popup(self, button): p = AddEdgePopup(title='Add origins') valid_orig = self.story.nodes() valid_orig.remove(self.current_node) for orig in valid_orig: b = ToggleButton(text=orig, size_hint_y=None, height=dp(30)) if orig in self.story.predecessors(self.current_node): b.state = 'down' p.node_list.add_widget(b) p.node_list.add_widget(Widget()) def save_callback(button): to_add = [] to_remove = [] for child in p.node_list.children: if isinstance(child, ToggleButton): node_name = child.text if child.state == 'down': to_add.append(node_name) else: to_remove.append(node_name) for node in to_add: if node not in self.story.predecessors(self.current_node): self.story.add_edge(node, self.current_node) for node in to_remove: if node in self.story.predecessors(self.current_node): self.story.remove_edge(node, self.current_node) p.dismiss() p.save_btn.bind(on_release=save_callback) p.open()