class StatBox(BoxLayout): '''box for getting and displaying stats about rolls. parent app is what's called for dice actions and info updates. all calls are self.parent_app.request_something(*args).''' view_model = ObjectProperty(mvm.StatBox(mvm.DiceTableManager())) def __init__(self, **kwargs): super(StatBox, self).__init__(**kwargs) def display_stats(self, stat_text, vals): '''takes a stat title and two values, and displays them.''' self.ids['stat_text'].title = stat_text self.ids['slider_1'].value = vals[0] self.ids['slider_2'].value = vals[1] def update(self): '''called when dice list changes.''' val_1 = int(self.ids['slider_1'].value) val_2 = int(self.ids['slider_2'].value) info_text, stat_text, vals, min_max = self.view_model.display(val_1, val_2) self.ids['info_text'].title = info_text self.ids['slider_1'].max = self.ids['slider_2'].max = min_max[1] self.ids['slider_1'].min = self.ids['slider_2'].min = min_max[0] self.display_stats(stat_text, vals) def assign_text_value(self): '''called by text_input to assign that value to sliders and show stats''' val_1 = int(self.ids['slider_1_text'].title.replace(',', '')) val_2 = int(self.ids['slider_2_text'].title.replace(',', '')) self.ids['slider_1'].value = val_1 self.ids['slider_2'].value = val_2 def assign_slider_value(self): '''the main function. displays stats of current slider values.''' val_1 = int(self.ids['slider_1'].value) val_2 = int(self.ids['slider_2'].value) self.display_stats(*self.view_model.display_stats(val_1, val_2))
def setUp(self): self.DTM = mvm.DiceTableManager() self.ST = mvm.SavedTables() self.interface = mvm.CurrentAndSavedInterface(self.DTM, self.ST) self.GB = mvm.GraphBox(self.DTM, self.ST, True) self.CB = mvm.ChangeBox(self.DTM) self.SB = mvm.StatBox(self.DTM) self.AB = mvm.AddBox(self.DTM) self.IB = mvm.InfoBox(self.DTM)
class ChangeBox(GridLayout): '''displays current dice and allows to change. parent app is what's called for dice actions and info updates. all calls are self.parent_app.request_something(*args).''' view_model = ObjectProperty(mvm.ChangeBox(mvm.DiceTableManager())) def __init__(self, **kwargs): super(ChangeBox, self).__init__(**kwargs) self.cols = 1 self.old_dice = [] def add_rm(self, btn): '''uses die stored in button and btn title to request add or rm''' self.view_model.add_rm(int(btn.title), btn.die) self.parent.parent.do_update() def reset(self, btn): '''resets current table back to empty and display instructions''' self.view_model.reset() self.parent.parent.do_update() self.clear_widgets() self.add_widget(Label(text=INTRO_TEXT, text_size=self.size, valign='top', halign='center')) def update(self): '''updates the current dice after add, rm or clear''' new_dice = [] button_list = self.view_model.display() self.clear_widgets() max_height = self.height/10 reset = Button(text='reset table', on_press=self.reset, size_hint=(1, None), height=0.75*max_height) self.add_widget(reset) if button_list: new_height = min((self.height - reset.height) / len(button_list), max_height) for labels, die_ in button_list: temp = labels[:] labels = [] for label in temp: if '50' not in label or 'D' in label: labels.append(label) box = BoxLayout(size_hint=(0.8, None), height=new_height, orientation='horizontal') self.add_widget(box) x_hint = round(1./(len(labels) + 2), 2) for label in labels: if label[0] == '-' or label[0] == '+': btn = FlashButton( text=label, size_hint=(x_hint, 1), die=die_, on_press=lambda btn: btn.delay(self.add_rm, btn) ) box.add_widget(btn) else: flash = FlashLabel(text=label, size_hint=(3 * x_hint, 1)) box.add_widget(flash) new_dice.append(label) if label not in self.old_dice: Clock.schedule_once(flash.flash_it, 0.01) self.old_dice = new_dice
def __init__(self, master): self.frame = tk.Frame(master) self.frame.columnconfigure(0, minsize=300, weight=1) self.frame.rowconfigure(0, weight=1) self.frame.rowconfigure(0, weight=1) self.frame.pack() table = mvm.DiceTableManager() history = mvm.SavedTables() # reloads history file. if corrupted, notifies and writes an empty hist hist_msg = history.reload_from_file() if 'ok' not in hist_msg and hist_msg != 'error: no file': msgbox.showinfo('Error', 'Error loading history:\n' + hist_msg) history.write_to_file() change = mvm.ChangeBox(table) add = mvm.AddBox(table) stat = mvm.StatBox(table) self.menus = GraphMenu(self, mvm.GraphBox(table, history, True)) self.info = mvm.InfoBox(table) self.change_box = ChangeBox(self) self.change_box.view_model = change self.add_box = AddBox(self) self.add_box.view_model = add self.stat_box = StatBox(self, stat) # self.stat_box.view_model = stat self.change_box.frame.grid(row=0, column=0, rowspan=2, sticky=tk.NSEW) self.change_box.frame.config(borderwidth=5, relief=tk.GROOVE) self.add_box.frame.grid(row=0, column=1, sticky=tk.NSEW) self.add_box.frame.config(borderwidth=5, relief=tk.GROOVE) self.stat_box.frame.grid(row=1, column=1, sticky=tk.NSEW) self.stat_box.frame.config(borderwidth=5, relief=tk.GROOVE) # the info frame info_frame = tk.Frame(self.frame, borderwidth=5, relief=tk.GROOVE) info_frame.grid(row=0, column=3, rowspan=2, sticky=tk.NSEW) label_btn = tk.Frame(info_frame) label_btn.pack(fill=tk.X) info_lbl = tk.Label(label_btn, fg='white', bg='blue', text='here are all the rolls\nand their frequency') info_lbl.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) tk.Button(label_btn, text='Weights\ninfo', bg='light yellow', command=self.weight_info).pack(side=tk.LEFT, padx=5, pady=5) text_scrollbar = tk.Scrollbar(info_frame) text_scrollbar.pack(side=tk.RIGHT, fill=tk.Y) self.info_text = tk.Text(info_frame, yscrollcommand=text_scrollbar.set, width=20) self.info_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) text_scrollbar.config(command=self.info_text.yview) self.frame.columnconfigure(0, minsize=300, weight=1) self.do_update()
def __init__(self, **kwargs): super(DicePlatform, self).__init__(**kwargs) table = mvm.DiceTableManager() history = mvm.SavedTables() self._read_hist_msg = history.reload_from_file() change = mvm.ChangeBox(table) add = mvm.AddBox(table) stat = mvm.StatBox(table) graph = mvm.GraphBox(table, history, False) info = mvm.InfoBox(table) self.ids['change_box'].view_model = change self.ids['add_box'].view_model = add self.ids['stat_box'].view_model = stat self.ids['graph_box'].view_model = graph self.ids['info_box'].view_model = info self.initializer()
class InfoBox(BoxLayout): '''displays basic info about the die.''' view_model = ObjectProperty(mvm.InfoBox(mvm.DiceTableManager())) def __init__(self, **kwargs): super(InfoBox, self).__init__(**kwargs) def initialize(self): '''called at main app init. workaround for kv file loading after py''' self.ids['full_text'].set_title( 'here are all the rolls and their frequency' ) self.ids['full_text'].ids['page_box_title'].font_size *= 0.75 self.ids['weights_info'].reset_sizes([0.1, 0.1, 0.80]) self.ids['weights_info'].set_title('full weight info') def choose(self, slider, key): '''chooses a page for pagebox with key=string-which box to display in. value=int-page number.''' lines = self.ids[key].get_lines_number() #reversing the slider page = int(slider.max) + int(slider.min) - int(slider.value) self.ids[key].set_text(*self.view_model.display_chosen_page(page, key)) def previous(self, key): '''displays previous page and updates view for pagebox[key=string]''' lines = self.ids[key].get_lines_number() self.ids[key].set_text(*self.view_model.display_previous_page(key)) def next(self, key): '''displays next page and updates view for pagebox[key=string]''' lines = self.ids[key].get_lines_number() self.ids[key].set_text(*self.view_model.display_next_page(key)) def update(self): '''updates views for all parts of the box.''' all_info = self.view_model.display_paged( self.ids['weights_info'].get_lines_number(), self.ids['full_text'].get_lines_number() ) self.ids['general_info'].title = all_info[0] self.ids['table_str'].title = all_info[1] self.ids['weights_info'].set_text(*all_info[2]) self.ids['full_text'].set_text(*all_info[3])
def __init__(self, master): """master is an object that has master.frame.""" self.master = master self.frame = tk.Frame(master.frame) self.view_model = mvm.ChangeBox(mvm.DiceTableManager())
def __init__(self, master): """master is an object that has master.frame.""" self.master = master self.frame = tk.Frame(master.frame) self.frame.grid_columnconfigure(0, pad=20) self.frame.grid_columnconfigure(1, pad=20) self.frame.grid_columnconfigure(2, pad=20) self.frame.grid_columnconfigure(3, pad=20) self.view_model = mvm.AddBox(mvm.DiceTableManager()) self.current = tk.StringVar() self.current.set('\n\n\n\n') tk.Label(self.frame, textvariable=self.current).grid( column=0, row=0, sticky=tk.W + tk.E + tk.S + tk.N, columnspan=4) any_size_lbl = tk.Label(self.frame, text='may input\nany size') any_size_lbl.grid(column=0, row=1) ToolTip(any_size_lbl, 'type in a die size between 2 and 200 and press enter.', 250) weights = tk.Button(self.frame, text='make\nweights', bg='thistle1', command=self.add_weights) weights.grid(column=1, row=1, rowspan=2) weights_text = ('A two-sided die with weights 1:4, 2:1 means that it ' + 'rolls a one 4 times as often as a 2') ToolTip(weights, weights_text, 200) strength_lbl = tk.Label(self.frame, text='strength') strength_lbl.grid(column=2, row=1) strength_text = 'A three-sided die X4 rolls 4, 8, 12 instead of 1, 2, 3' ToolTip(strength_lbl, strength_text, 200) mod_label = tk.Label(self.frame, text='die\nmodifier') mod_label.grid(column=3, row=1) ToolTip(mod_label, 'D3+2 rolls 3, 4, 5 instead of 1, 2, 3', 200) self.any_size = NumberInput(self.frame, width=10, bg='thistle1') self.any_size.bind('<Return>', self.assign_size_text) self.any_size.grid(column=0, row=2) multiplier = tk.StringVar() multiplier.set('X1') multiplier.trace('w', partial(self.assign_multiplier, multiplier)) strength = tk.OptionMenu(self.frame, multiplier, *['X{}'.format(num) for num in range(1, 11)]) strength.config(bg='thistle1', activebackground='thistle1') strength.grid(column=2, row=2) mod = tk.Scale(self.frame, from_=5, to=-5, command=self.assign_mod, bg='thistle1', activebackground='thistle1') mod.grid(column=3, row=2, rowspan=2) preset = tk.Frame(self.frame) for index, preset_text in enumerate(self.view_model.presets): btn = tk.Button(preset, text=preset_text, bg='thistle1', command=partial(self.assign_size_btn, preset_text)) row_, col_ = divmod(index, 4) btn.grid(row=row_, column=col_, padx=5) preset.grid(column=0, row=3, sticky=tk.NSEW, columnspan=3) instruct = tk.Label(self.frame, text=50 * '-', bg='PaleTurquoise1') instruct.grid(column=0, row=4, sticky=tk.NSEW, columnspan=4) instructions = ('Use buttons above to create the die you want. ' + 'Then use the "+" buttons below to add it to the table') ToolTip(instruct, instructions, 200) self.adder = tk.Frame(self.frame) self.adder.grid(column=0, row=5, sticky=tk.NSEW, columnspan=4) self.display_die()
class GraphBox(BoxLayout): '''buttons for making graphs. parent app is what's called for dice actions and info updates. all calls are self.parent_app.request_something(*args).''' view_model = ObjectProperty(mvm.GraphBox(mvm.DiceTableManager(), mvm.SavedTables(), True)) def __init__(self, **kwargs): super(GraphBox, self).__init__(**kwargs) self.confirm = Popup(title='Delete everything?', content=BoxLayout(), size_hint=(0.8, 0.4), title_align='center', title_size=75) self.confirm.content.add_widget(Button(text='EVERY\nTHING!!!', on_press=self.clear_all, texture_size=self.size)) self.confirm.content.add_widget(Button(text='never\nmind', on_press=self.confirm.dismiss)) def initialize(self): '''called at main app init. workaround for kv file loading after py''' self.ids['graph_space'].add_widget(PlotCheckBox(size_hint=(1, 0.5), parent_obj=self)) self.update() def update(self): '''updates the current window to display new graph history and current table to graph''' current, history = self.view_model.display() #sz_hint for 'past graphs' label to take up all the space #base_y make sure other widgets fit rows = len(history) + 3 base_y = .99/rows if base_y > 0.1: base_y = 0.1 sz_hint = (1, 1 - (rows - 1) * base_y) self.ids['graph_space'].clear_widgets() self.ids['graph_space'].add_widget(Label(text='past graphs', halign='center', size_hint=sz_hint)) for text_, tuple_list_ in history: check = PlotCheckBox(size_hint=(0.79, base_y), active=False, tuple_list=tuple_list_) reload_ = FlashButton( size_hint=(0.2, base_y), lst=[text_, tuple_list_], max_lines=1, text='reload_saved_dice_table', valign='middle', halign='center', on_press=lambda btn: btn.delay(self.reload, btn) ) self.ids['graph_space'].add_widget(check) self.ids['graph_space'].add_widget(reload_) check.text = text_ self.ids['graph_space'].add_widget(Label(text='new table', size_hint=(1, base_y))) check = PlotCheckBox(size_hint=(1, base_y), active=True, tuple_list=current[1]) self.ids['graph_space'].add_widget(check) check.text = current[0] Clock.schedule_once(lambda dt: check.ids['label'].flash_it(), 0.01) def reload(self, btn): '''reloads from history to current table''' self.view_model.reload_saved_dice_table(btn.lst[0], btn.lst[1]) self.parent.parent.do_update() def graph_it(self): '''prepares plot and calls PlotPopup''' to_plot = [] for item in self.ids['graph_space'].children[:]: if isinstance(item, PlotCheckBox): if item.active: to_plot.append((item.text, item.tuple_list)) plots = self.view_model.get_requested_graphs(to_plot) self.update() if plots[2]: plotter = PlotPopup(*plots) plotter.open() def clear_all(self, btn): '''clear graph history''' self.confirm.dismiss() self.view_model.delete_all() self.update() def clear_selected(self): '''clear selected checked items from graph history''' to_clear = [] for item in self.ids['graph_space'].children[1:]: if isinstance(item, PlotCheckBox): if item.active: to_clear.append((item.text, item.tuple_list)) self.view_model.delete_requested(to_clear) self.update()
class AddBox(BoxLayout): '''box for adding new dice. parent app is what's called for dice actions and info updates. all calls are self.parent_app.request_something(*args).''' view_model = ObjectProperty(mvm.AddBox(mvm.DiceTableManager())) def __init__(self, **kwargs): super(AddBox, self).__init__(**kwargs) def initialize(self): '''called at main app init. workaround for kv file loading after py''' for preset_text in self.view_model.presets: btn = Button(text=preset_text, on_press=self.assign_size_btn) self.ids['presets'].add_widget(btn) self.ids['multiplier'].bind(text=self.assign_multiplier) self.display_die() def update(self): '''called by main app at dice change''' self.ids['current'].title = (self.view_model.display_current_table()) def assign_size_btn(self, btn): '''assigns the die size and die when a preset btn is pushed''' die_size = int(btn.title[1:]) self.view_model.set_size(die_size) self.display_die() def assign_size_text(self, text): '''asigns the die size and die when title is entered''' top = 200 bottom = 2 int_string = text if int_string: die_size = int(text) die_size = min(top, max(bottom, die_size)) if text != str(die_size): self.ids['custom_input'].title = str(die_size) self.view_model.set_size(die_size) self.display_die() def assign_mod(self): '''assigns a die modifier and new die when slider is moved''' mod = int(self.ids['modifier'].value) self.view_model.set_mod(mod) self.display_die() def assign_multiplier(self, spinner, text): '''assigns a die multiplier and new_die based on spinner's title.''' multiplier = int(text[1:]) self.view_model.set_multiplier(multiplier) self.display_die() def display_die(self): '''all changes to size, mod and weight call this function''' self.ids['add_it'].clear_widgets() to_add = self.view_model.display_die() x_hint = round(1./(len(to_add) + 1), 2) flash = FlashLabel(text=to_add[0], size_hint=(2*x_hint, 1)) self.ids['add_it'].add_widget(flash) flash.flash_it() for add_val in to_add[1:]: btn = FlashButton(text=add_val, size_hint=(x_hint, 1), on_press=lambda btn: btn.delay(self.add, btn)) self.ids['add_it'].add_widget(btn) def add(self, btn): '''uses btn title and die stored in view_model to add to current table''' self.view_model.add(int(btn.title)) self.parent.parent.do_update() def record_weights(self, text_val_lst): '''takes a list of [('weight for <roll>', int=the_weight)...] and makes a weighted die with it.''' self.view_model.record_weights_text(text_val_lst) self.display_die() def add_weights(self): '''opens the weightpopup and sizes accordingly''' popup = WeightsPopup(self, self.view_model.get_weights_text()) popup.open()