class ROISelector(BoxLayout): def __init__(self, **kwargs): super(ROISelector, self).__init__(**kwargs) self.dropdown = DropDown() self.dropdown.bind(on_select=lambda obj, x: setattr( self.ids.mainbutton_id, 'text', "ROI {0}".format(x))) self.roi_list = App.get_running_app().roi_list self.roi_list.bind(on_roi_added=self.add_roi_button) self.roi_list.bind(on_roi_selected=lambda obj, index: self.dropdown. select(obj.values[index])) self.roi_list.bind(on_roi_removed=self.remove_roi_button) add_roi_btn = Button(text="Add new ROI…", size_hint_y=None, height=44) add_roi_btn.bind(on_release=lambda obj: self.roi_list.add() or self. roi_list.select(len(self.roi_list.values) - 1)) self.dropdown.add_widget(add_roi_btn) self.roi_buttons = [] def add_roi_button(self, obj, new_value): color = roi_colors[new_value % len(roi_colors)] btn = Button(text="ROI {0}".format(new_value), size_hint_y=None, height=44, background_color=color) btn.bind(on_release=lambda instance: self.roi_list.select( self.roi_buttons.index(btn))) self.dropdown.add_widget(btn) self.roi_buttons.append(btn) def remove_roi_button(self, obj, index): self.dropdown.remove_widget(self.roi_buttons[index]) del self.roi_buttons[index] self.ids.mainbutton_id.text = "Select ROI…"
class DropDownInput(TextInput): def __init__(self, preload=None, preload_attr=None, preload_clean=True, **kwargs): self.multiline = False self.drop_down = DropDown() self.drop_down.bind(on_select=self.on_select) self.bind(on_text_validate=self.add_text) self.preload = preload self.preload_attr = preload_attr self.preload_clean = preload_clean self.not_preloaded = set() super(DropDownInput, self).__init__(**kwargs) self.add_widget(self.drop_down) def add_text(self, *args): if args[0].text not in [ btn.text for btn in self.drop_down.children[0].children if hasattr(btn, "text") ]: btn = Button(text=args[0].text, size_hint_y=None, height=44) self.drop_down.add_widget(btn) btn.bind(on_release=lambda btn: self.drop_down.select(btn.text)) if "preload" not in args: self.not_preloaded.add(btn) def on_select(self, *args): self.text = args[1] if args[1] not in [ btn.text for btn in self.drop_down.children[0].children if hasattr(btn, "text") ]: self.drop_down.append(Button(text=args[1])) # call on_text_validate after selection # to avoid having to select textinput and press enter self.dispatch("on_text_validate") def on_touch_down(self, touch): preloaded = set() if self.preload: for thing in self.preload: if self.preload_attr: # use operator to allow dot access of attributes thing_string = str( operator.attrgetter(self.preload_attr)(thing)) else: thing_string = str(thing) self.add_text(Button(text=thing_string), "preload") preloaded.add(thing_string) # preload_clean removes entries that # are not in the preload source anymore if self.preload_clean is True: added_through_widget = [ btn.text for btn in self.not_preloaded if hasattr(btn, "text") ] for btn in self.drop_down.children[0].children: try: if (btn.text not in preloaded and btn.text not in added_through_widget): self.drop_down.remove_widget(btn) except Exception as ex: pass return super(DropDownInput, self).on_touch_down(touch) def on_touch_up(self, touch): if touch.grab_current == self: self.drop_down.open(self) return super(DropDownInput, self).on_touch_up(touch)
class ClassSummary(CustomBoxLayout): def __init__(self, *args, **kwargs): super(ClassSummary, self).__init__(*args, **kwargs) # The first item in this panel should be a dropdown containing # all of the contours in the current image. self.contour_select_dropdown = DropDown() self.contour_select_dropdown.auto_dismiss = False self.editor_box = CustomBoxLayout(orientation='vertical', padding=[8, 8, 8, 8], spacing=5) self.class_select_dropdown = DropDown() self.class_select_dropdown.auto_dismiss = False self.class_select_button = Button(text='Select Class', size_hint_y=None, height=30) self.class_select_button.bind(on_press=self._class_select_pressed) self.name_input = TextInput(text='Item Name', multiline=False, size_hint_y=None, height=30) self.comment_input = TextInput(text='Comments', multiline=True, size_hint_y=None, height=120) self.name_input.bind(text=self._name_text_changed) self.comment_input.bind(text=self._comment_text_changed) self.editor_box.add_widget(self.class_select_button) self.editor_box.add_widget(self.name_input) self.editor_box.add_widget(self.comment_input) self.dropdown_activator = DropDownContourItem( class_color=hex_color('#000000'), index=-1, class_name='none') self.dropdown_activator.bind(on_press=self._activator_pressed) self.add_widget(self.dropdown_activator) self.add_widget(self.editor_box) self.dropdown_open = False self.current_entry = None self.dataset = None self.contours = [] self.contour_dropdown_items = [] self.current_contour = None self.class_names = [] self.class_buttons = [] def _name_text_changed(self, inst, val): self.current_contour['name'] = val def _comment_text_changed(self, inst, val): self.current_contour['comment'] = val def writeChangesToMemory(self): if self.current_entry is None: raise Exception("Nothing is currently being edited.") entry = self.dataset.meta_structure['entries'][self.current_key] for idx, contour in enumerate(self.contours): entry[idx]['class_idx'] = contour['class_idx'] entry[idx]['name'] = contour['name'] entry[idx]['comment'] = contour['comment'] def clearCurrentEntry(self): if self.current_entry is not None: for item in self.contour_dropdown_items: self.contour_select_dropdown.remove_widget(item) self.contours = [] self.contour_dropdown_items = [] def addContour(self, contour): item_class_idx = contour['class_idx'] item_class_color = self.dataset.meta_structure['classes'][ item_class_idx]['color'] item_class_name = self.dataset.meta_structure['classes'][ item_class_idx]['name'] proper_name = item_class_name if contour['name'] != '': if not contour['name'].isspace(): proper_name = self.current_contour['name'] dropdown_item = DropDownContourItem(class_color=item_class_color, index=item_class_idx, class_name=proper_name) self.contour_select_dropdown.add_widget(dropdown_item) dropdown_item.bind(on_press=self._item_selected) self.contours.append(contour) self.contour_dropdown_items.append(dropdown_item) def setCurrentContour(self, contour): self.current_contour = contour item_class_idx = contour['class_idx'] item_class_color = self.dataset.meta_structure['classes'][ item_class_idx]['color'] item_class_name = self.dataset.meta_structure['classes'][ item_class_idx]['name'] proper_name = item_class_name if self.current_contour['name'] != '': if not self.current_contour['name'].isspace(): proper_name = self.current_contour['name'] self.dropdown_activator.setProperties(item_class_color, item_class_idx, proper_name) self.name_input.text = contour['name'] self.comment_input.text = contour['comment'] self.class_select_button.text = item_class_name self.contour_select_dropdown.dismiss() self.dropdown_open = False def populateClassDropdown(self): for button in self.class_buttons: self.class_select_dropdown.remove_widget(button) self.class_names = [] self.class_buttons = [] for _class in self.dataset.meta_structure['classes']: self.class_names.append(_class['name']) button = Button(text=_class['name'], size_hint_y=None, height=30) self.class_buttons.append(button) self.class_select_dropdown.add_widget(button) button.bind(on_press=self._class_selected) def setCurrentEntry(self, key, dataset): if self.current_entry is not None: self.clearCurrentEntry() self.dataset = dataset self.current_entry = self.dataset.meta_structure['entries'][key] self.current_key = key self.populateClassDropdown() # Add each of these to the internal structure, and therefore the # image display. for contour in self.current_entry: self.addContour(contour) if len(self.current_entry) > 0: self.setCurrentContour(self.current_entry[0]) def _activator_pressed(self, inst): if not self.dropdown_open: self.contour_select_dropdown.open(inst) self.dropdown_open = True else: self.dropdown_open = False self.contour_select_dropdown.dismiss() def _class_select_pressed(self, inst): self.class_select_dropdown.open(inst) def _class_selected(self, inst): self.class_select_button.text = inst.text self.current_contour['class_idx'] = self.class_names.index(inst.text) self.class_select_dropdown.dismiss() # We need to change the item in the dropdown list of contours to match. class_idx = self.class_names.index(inst.text) contour_idx = self.contours.index(self.current_contour) item_class_color = self.dataset.meta_structure['classes'][class_idx][ 'color'] item_class_name = self.dataset.meta_structure['classes'][class_idx][ 'name'] proper_name = item_class_name if self.current_contour['name'] != '': if not self.current_contour['name'].isspace(): proper_name = self.current_contour['name'] self.contour_dropdown_items[contour_idx].setProperties( item_class_color, self.class_names.index(inst.text), proper_name) self.dropdown_activator.setProperties( item_class_color, self.class_names.index(inst.text), proper_name) self.parent.display.image_display.setContourColor( contour_idx, item_class_color) def _item_selected(self, inst): idx = self.contour_dropdown_items.index(inst) contour = self.contours[idx] self.setCurrentContour(contour)
class GeneScreen(Screen): def __init__(self, **kwargs): super(GeneScreen, self).__init__(**kwargs) # Widget Container screen_container = BoxLayout(orientation='vertical', padding=[1]) # *Logo---------------------------------------------------------------- self.logo = HomeButton() screen_container.add_widget(self.logo) # *Gene Selection Title------------------------------------------------ screen_container.add_widget(Label(text='Gene Selection', size_hint=(1, .1), color=(0, .1, .25, .75))) # *Drop Down Menu------------------------------------------------------ self.dropdown = DropDown() self.dropdown.bind(on_select=self.set_gene) self.dd_btns = [] # A list of drop down buttons for easy deletion # Populate when top button hit self.mainbutton = CustomButton(text='Select a gene', size_hint=(1, .2)) self.mainbutton.bind(on_release=self.load_genes) # Populate dropdown self.dropdown.bind(on_select=lambda instance, x: setattr(self.mainbutton, 'text', x)) # Place on screen screen_container.add_widget(self.mainbutton) # *Gene Buttons-------------------------------------------------------- # Declarations self.button_holder = BoxLayout(orientation='horizontal') # Edit Button self.edit_btn = CustomButton(text="Edit", size_hint=(.3, .3)) self.edit_btn.bind(on_release=self.switch_screen) # New Button self.new_btn = CustomButton(text="New", size_hint=(.3, .3)) self.new_btn.bind(on_release=self.switch_screen) # Delete Button self.delete_btn = CustomButton(text="Delete", size_hint=(.3, .3)) self.delete_btn.bind(on_release=self.delete) # Placement self.button_holder.add_widget(self.edit_btn) self.button_holder.add_widget(self.new_btn) self.button_holder.add_widget(self.delete_btn) screen_container.add_widget(self.button_holder) # Place Container # Pack all widgets self.add_widget(screen_container) # Reset drop down when screen is loaded self.bind(on_enter=self.reset_menu) def load_genes(self, *args): """Called when drop down is opened""" self.dropdown.clear_widgets() # Clear any packaged buttons del self.dd_btns[:] # Clear drop down button list # Grab relevant genes genes = global_data.groups[global_data.active_group] for gene in genes: btn = CustomButton(text=gene.name, size_hint_y=None, height=self.height/9) btn.bind(on_release=lambda button: self.dropdown.select(button.text)) self.dropdown.add_widget(btn) # Add button to menu self.dd_btns.append(btn) # Store button in delety-list self.dropdown.open(args[0]) def set_gene(self, *args): # Storing which group is selected for use in gene screen global_data.active_gene = args[1] # args[1] - Name of gene def delete(self, *args): def delete_gene(): group = global_data.active_group # Get active group gene = global_data.active_gene # Get active gene # Iterate through genes because we need to check the name of each for index, _gene in enumerate(global_data.groups[group]): if _gene.name == gene: # Delete the gene del global_data.groups[group][index] # Remove from drop down self.dropdown.remove_widget(self.dd_btns[index]) log(f"Gene {gene} deleted.") break group_mngr.save_groups(global_data.groups) # Save the groups global_data.active_gene = '' # No active gene self.dropdown.select('Select a gene') popup.dismiss() if global_data.active_gene != '': # *Deletion Confirmation------------------------------------------- content = BoxLayout(orientation='vertical') content.add_widget(Label(text=f"Delete " f"{global_data.active_gene}?")) # *Confirmation Buttons-------------------------------------------- options = BoxLayout(orientation='horizontal', spacing=2) confirm_btn = CustomButton(text="Delete", # Confirm button size_hint=(.3, .3)) cancel_btn = CustomButton(text="Cancel", # Cancel button size_hint=(.3, .3)) # Add Widgets to container options.add_widget(confirm_btn) options.add_widget(cancel_btn) content.add_widget(options) # *Popup Settings-------------------------------------------------- popup = Popup(title="Delete?", content=content, size_hint=(None, None), size=(400, 400), separator_color=[1., 1., 1., 1.]) confirm_btn.bind(on_press=delete_gene) cancel_btn.bind(on_press=popup.dismiss) popup.open() def switch_screen(*args): if args[1].text == "New": sm.current = 'editgene' elif args[1].text == "Edit": if global_data.active_gene != '': sm.current = 'editgene' def reset_menu(self, *args): # Need to make sure the menu text is defaulted when screen is entered self.dropdown.select('Select a gene') global_data.active_gene = ''
class GroupScreen(Screen): def __init__(self, **kwargs): super(GroupScreen, self).__init__(**kwargs) # Hold the widgets in a container screen_container = BoxLayout(orientation='vertical', padding=[1]) # *Empowered Logo------------------------------------------------------ self.logo = HomeButton() screen_container.add_widget(self.logo) # *Group Selection Title----------------------------------------------- screen_container.add_widget(Label(text='Group Selection', size_hint=(1, .1), color=(0, .1, .25, .75))) # *Dropdown Menu------------------------------------------------------- self.dropdown = DropDown() self.dropdown.bind(on_select=self.set_active_group) # On load, no group is active. global_data.active_group = '' # Store the drop down buttons for easy manipulation self.current_groups = {} # Populate when top button hit self.mainbutton = CustomButton(text='Select a group', size_hint=(1, .2)) # Populate drop down on select self.mainbutton.bind(on_release=self.load_groups) self.dropdown.bind(on_select=lambda instance, x: setattr(self.mainbutton, 'text', x)) # Place on screen screen_container.add_widget(self.mainbutton) # *Group Actions Title------------------------------------------------- # Declarations self.button_container = BoxLayout(orientation='horizontal') # Edit Button self.edit_btn = CustomButton(text="Edit", size_hint=(.3, .3)) self.edit_btn.bind(on_press=self.switch_screen) # New Button self.new_btn = CustomButton(text="New", size_hint=(.3, .3)) self.new_btn.bind(on_press=self.switch_screen) # Delete Button self.delete_btn = CustomButton(text="Delete", size_hint=(.3, .3)) self.delete_btn.bind(on_press=self.delete) # Put buttons in container self.button_container.add_widget(self.edit_btn) self.button_container.add_widget(self.new_btn) self.button_container.add_widget(self.delete_btn) # Add container to screen container screen_container.add_widget(self.button_container) # Package screen container self.add_widget(screen_container) # Make sure drop down menu gets reset self.bind(on_enter=self.reset_menu) def set_active_group(self, *args): # args = (<DropDown obj>, 'Methylation Pathway') # Storing which group is selected for use in gene screen and deletion global_data.active_group = args[1] def switch_screen(self, *args): # Switch screens if args[0].text == "Edit" and global_data.active_group != '': sm.current = 'gene' elif args[0].text == "New": sm.current = 'newgroup' def delete(self, *args): def delete_group(*args): # Get the selected group active_group = global_data.active_group # Delete it from the group dictionary del global_data.groups[active_group] log(f"Group {active_group} deleted.") # Overwrite the existing groups with the modified group dictionary group_mngr.save_groups(global_data.groups) # Clear the selected group global_data.active_group = '' # Remove it from the drop down menu self.dropdown.remove_widget(self.current_groups[active_group]) # Set drop down menu to default self.dropdown.select('Select a group') popup.dismiss() # If a group is selected and delete button hit, confirm deletion if global_data.active_group != '': # *Confirmation Popup---------------------------------------------- content = BoxLayout(orientation='vertical') content.add_widget(Label(text= f"Delete {global_data.active_group}?")) # *Popup buttons--------------------------------------------------- options = BoxLayout(orientation='horizontal', spacing=2) confirm_btn = CustomButton(text="Delete", # Confirm delete button size_hint=(.3, .3)) cancel_btn = CustomButton(text="Cancel", # Cancel delete button size_hint=(.3, .3)) options.add_widget(confirm_btn) options.add_widget(cancel_btn) content.add_widget(options) # *Popup Attributes------------------------------------------------ popup = Popup(title="Delete?", content=content, size_hint=(None, None), size=(400, 400), separator_color=[1., 1., 1., 1.]) confirm_btn.bind(on_press=delete_group) cancel_btn.bind(on_press=popup.dismiss) popup.open() def load_groups(self, *args): self.dropdown.clear_widgets() # Clear any packaged buttons self.current_groups = {} # Clear drop down button list groups = global_data.groups for group in groups: # Iterating through groups and adding a button btn = CustomButton(text=group, # Create button size_hint_y=None, height=44) btn.bind(on_release=lambda button: self.dropdown.select(button.text)) # Bind drop down functionality self.current_groups[group] = btn self.dropdown.add_widget(btn) # Put in drop down menu self.dropdown.open(args[0]) # Called on clicking the default button def reset_menu(self, *args): # Need to make sure the menu text is defaulted when screen is entered self.dropdown.select('Select a group') global_data.active_group = '' global_data.active_gene = ''
class BuyHousesPop(Popup): def __init__(self, **kwargs): # Obtain root reference self.root = kwargs.pop('root') self.btns = {} self.entries = {} self.total_money = 0 super().__init__(**kwargs) self.selected_square_properties = [] self.ids.accept_btn.disabled = True Clock.schedule_once(self.create_dropdown, 0) def create_dropdown(self, *args): self.dropdown_list = DropDown() for player in self.root.players: player_name = player.name.upper() # button for dropdown list 1 btn = Button( text=f'[b][color=#ffffff]{player_name}[/b][/color]', size_hint_y=None, height=self.width // 25, markup=True ) # Storing the btn references into a list self.btns[player_name] = btn # Create the binding function btn.bind(on_release=lambda btn: self.dropdown_list.select(btn.text)) # Add the widget to the dropdown window self.dropdown_list.add_widget(btn) # Bind the select name btns to opening the dropdown window self.ids.select_name_btn.bind(on_release=self.dropdown_list.open) # Binding the select name btns to also update their text values self.dropdown_list.bind( on_select=functools.partial(self.select_player, self.ids.select_name_btn) ) def select_player(self, btn, instance, button_text): # Obtain the true value in the text previous_player_name = btn.text.split(']')[2].split('[')[0] player_name = button_text.split(']')[2].split('[')[0] # If the selection change from not the default value if previous_player_name != 'SELECT PLAYER NAME': self.dropdown_list.add_widget(self.btns[previous_player_name]) # Removing the corresponding button from # right dropdown window self.dropdown_list.remove_widget(self.btns[player_name]) # Update text to given x btn.text = button_text # Find the matching player given the player_name selected_player = None for player in self.root.players: if player.name.upper() == player_name: selected_player = player break # Storing the selected player self.player = selected_player # Update the player_current_money label self.ids.player_current_money.text = f"[b][color=#000000]Player Current Money: ${self.player.money}[/b][/color]" # Update the property container with the selected player self.update_property_container(selected_player) if selected_player is not None: self.ids.accept_btn.disabled = False def update_property_container(self, selected_player): # Clean property container self.ids.property_container.clear_widgets() # Fill the property container given the properties of the # selected player for square_property in selected_player.property_own: # If the property is not part of a full set, then ignore it if not isinstance(square_property, PropertySquare) or (square_property.full_set is False): continue # Create button for property entry = BuyHousesEntry( square_property=square_property, initial_houses=square_property.number_of_houses, total_houses=square_property.number_of_houses ) # Add it to the entries of the popup if entry.square_property.property_set not in self.entries.keys(): self.entries[entry.square_property.property_set] = [entry] else: self.entries[entry.square_property.property_set].append(entry) # Place property name entry.ids.property_name.text = f'[b][color=#000000]{entry.square_property.full_name}[/b][/color]' # Updateing the entry's text self.update_house_numbers(entry) # Update the button status self.update_button_status() # Bind the property button to function # entry.bind(on_release=functools.partial(self.property_button_press)) entry.ids.buy_houses.bind(on_release=functools.partial(self.buy_houses, entry)) entry.ids.sell_houses.bind(on_release=functools.partial(self.sell_houses, entry)) # Add button to the property container self.ids.property_container.add_widget(entry) # Update the money values self.update_money_values() def update_button_status(self): for set_name in self.entries.keys(): # Checking all the other entries within the same set number_of_total_houses = list(map(lambda x: x.total_houses, self.entries[set_name])) # Determine the min and max min_val, max_val = min(number_of_total_houses), max(number_of_total_houses) for entry in self.entries[set_name]: # Determine if the entry's specific buttons are enabled or disabled if min_val == max_val: if min_val == 0: entry.ids.buy_houses.disabled = False entry.ids.sell_houses.disabled = True elif max_val == 5: entry.ids.buy_houses.disabled = True entry.ids.sell_houses.disabled = False else: entry.ids.buy_houses.disabled = False entry.ids.sell_houses.disabled = False elif entry.total_houses == min_val: entry.ids.buy_houses.disabled = False entry.ids.sell_houses.disabled = True elif entry.total_houses == max_val: entry.ids.sell_houses.disabled = False entry.ids.buy_houses.disabled = True # No matter what, if you have a mortgage property, you cannot buy/sell houses if entry.square_property.mortgage: entry.ids.buy_houses.disabled = True entry.ids.sell_houses.disabled = True def update_money_values(self): self.total_money = 0 for set_name in self.entries.keys(): # Determine the cost of the house for the set cost_of_house = self.entries[set_name][0].square_property.buy_house_cost # Determine the houses bought and the houses sold houses_bought = 0 houses_sold = 0 for entry in self.entries[set_name]: houses_diff = entry.total_houses - entry.initial_houses if houses_diff > 0: houses_bought += houses_diff else: houses_sold -= houses_diff # Calculate the total cost self.total_money += int(houses_sold * (cost_of_house / 2)) self.total_money -= int(houses_bought * cost_of_house) # Update the buy_sell money and the player's total money if self.total_money >= 0: self.ids.buy_sell_money.text = f"[b][color=#000000]Property Money: ${self.total_money}[/b][/color]" else: self.ids.buy_sell_money.text = f"[b][color=#000000]Property Money: -${abs(self.total_money)}[/b][/color]" # Update the total money of the player after the transaciton self.total_money += self.player.money self.ids.total_money.text = f"[b][color=#000000]Total Money: ${self.total_money}[/b][/color]" # Disable buttons if the player does not have enough money to pay for the houses/hotel self.cannot_pay() def update_house_numbers(self, entry): # Updateing the entry's text if entry.total_houses == 5: entry.ids.houses_numbers.text = "[b][color=#000000]1[/b][/color]" entry.ids.house.color = [1, 0, 0, 1] else: entry.ids.houses_numbers.text = f"[b][color=#000000]{entry.total_houses}[/b][/color]" entry.ids.house.color = [0, 1, 0, 1] def cannot_pay(self): # Disable buttons based on not enough money for set_name in self.entries.keys(): # Determine the cost of the house for the set cost_of_house = self.entries[set_name][0].square_property.buy_house_cost # If they don't have enough money to buy houses in this set if cost_of_house > self.total_money: for entry in self.entries[set_name]: entry.ids.buy_houses.disabled = True def buy_houses(self, entry, btn_instance): # Increase the entry's total houses entry.total_houses += 1 # Updateing the entry's text self.update_house_numbers(entry) # Place the houses/hotel number self.update_button_status() # Update money values self.update_money_values() if self.total_money != self.player.money: self.ids.select_name_btn.disabled = True else: self.ids.select_name_btn.disabled = False def sell_houses(self, entry, btn_instance): # Increase the entry's total houses entry.total_houses -= 1 # Updateing the entry's text self.update_house_numbers(entry) # Update total houses number displayed self.update_button_status() # Update money values self.update_money_values() if self.total_money != self.player.money: self.ids.select_name_btn.disabled = True else: self.ids.select_name_btn.disabled = False def accept(self): # Update the houses visible after buying/selling houses/hotel for set_name in self.entries.keys(): for entry in self.entries[set_name]: # Change the attributes of the property to the new number of houses entry.square_property.number_of_houses = entry.total_houses # Update the visibility of the house markers depending on the number # of houses. entry.square_property.update_house_markers() # Modify the player's money given the mortgage_unmortgage money self.player.money = self.total_money # Inform root to update property ownership and update player's money self.root.parent.parent.update_players_to_frame() # Log buy/sell houses bought_text = [] sold_text = [] for set_name in self.entries.keys(): for entry in self.entries[set_name]: house_diff = entry.total_houses - entry.initial_houses if entry.total_houses != 5 and entry.initial_houses != 5: if house_diff > 0: bought_text.append(f"{house_diff} house(s) for {entry.square_property.full_name}") elif house_diff < 0: sold_text.append(f'{-house_diff} house(s) for {entry.square_property.full_name}') elif entry.total_houses == 5 and entry.initial_houses != 5: bought_text.append(f"an hotel for {entry.square_property.full_name}") elif entry.initial_houses == 5 and entry.total_houses != 5: sold_text.append(f"an hotel for {entry.square_property.full_name}") bought_text = ",".join(bought_text) if bought_text else "no houses/hotel" sold_text = ",".join(sold_text) if sold_text else "no houses/hotel" log_text = f"{self.player.name.upper()} bought {bought_text} and sold {sold_text}" self.root.parent.parent.add_history_log_entry(log_text) # Dismiss the popup self.dismiss()
class MortgagePop(Popup): def __init__(self, **kwargs): # Obtain root reference self.root = kwargs.pop('root') self.btns = {} self.mortgage_unmortgage_money = 0 self.total_money = 0 if 'dismiss_binding_fn' in kwargs.keys(): self.dismiss_binding_fn = kwargs.pop('dismiss_binding_fn') else: self.dismiss_binding_fn = None super().__init__(**kwargs) self.selected_square_properties = [] self.ids.accept_btn.disabled = True Clock.schedule_once(self.create_dropdown, 0) def create_dropdown(self, *args): self.dropdown_list = DropDown() for player in self.root.players: player_name = player.name.upper() # button for dropdown list 1 btn = Button( text=f'[b][color=#ffffff]{player_name}[/b][/color]', size_hint_y=None, height=self.width // 25, markup=True ) # Storing the btn references into a list self.btns[player_name] = btn # Create the binding function btn.bind(on_release=lambda btn: self.dropdown_list.select(btn.text)) # Add the widget to the dropdown window self.dropdown_list.add_widget(btn) # Bind the select name btns to opening the dropdown window self.ids.select_name_btn.bind(on_release=self.dropdown_list.open) # Binding the select name btns to also update their text values self.dropdown_list.bind( on_select=functools.partial(self.select_player, self.ids.select_name_btn) ) def select_player(self, btn, instance, button_text): # Obtain the true value in the text previous_player_name = btn.text.split(']')[2].split('[')[0] player_name = button_text.split(']')[2].split('[')[0] # If the selection change from not the default value if previous_player_name != 'SELECT PLAYER NAME': self.dropdown_list.add_widget(self.btns[previous_player_name]) # Removing the corresponding button from # right dropdown window self.dropdown_list.remove_widget(self.btns[player_name]) # Update text to given x btn.text = button_text # Find the matching player given the player_name selected_player = None for player in self.root.players: if player.name.upper() == player_name: selected_player = player break # Storing the selected player self.player = selected_player # Update the player_current_money label self.ids.player_current_money.text = f"[b][color=#000000]Player Current Money: ${self.player.money}[/b][/color]" # Update the property container with the selected player self.update_property_container(selected_player) if selected_player is not None: self.ids.accept_btn.disabled = False def update_property_container(self, selected_player): # Clean property container self.ids.property_container.clear_widgets() # Fill the property container given the properties of the # selected player for square_property in selected_player.property_own: # If the property has houses, then it cannot be mortgaged if isinstance(square_property, PropertySquare) and (square_property.number_of_houses != 0): continue # Determine color of property property_color = "assets/buttons/red.png" if square_property.mortgage is False else "assets/buttons/light_grey.jpg" # Create button for property property_btn = PropertyButton( text=f'[b][color=#000000]{square_property.full_name}[/b][/color]', markup=True, background_normal=property_color, square_property=square_property ) # Bind the property button to function property_btn.bind(on_release=functools.partial(self.property_button_press)) # Add button to the property container self.ids.property_container.add_widget(property_btn) def property_button_press(self, btn_instance): # If the property is already selected, deselect it by: if btn_instance.square_property in self.selected_square_properties: # Remove from the list self.selected_square_properties.remove(btn_instance.square_property) # Change the color of the button back to white if btn_instance.square_property.mortgage is True: btn_instance.background_normal = "assets/buttons/light_grey.jpg" self.mortgage_unmortgage_money += btn_instance.square_property.unmortgage_value else: btn_instance.background_normal = "assets/buttons/red.png" self.mortgage_unmortgage_money -= btn_instance.square_property.mortgage_value else: # Append to the list self.selected_square_properties.append(btn_instance.square_property) # Change the color of the button to be highlighted if btn_instance.square_property.mortgage is True: btn_instance.background_normal = "assets/buttons/red.png" self.mortgage_unmortgage_money -= btn_instance.square_property.unmortgage_value else: btn_instance.background_normal = "assets/buttons/light_grey.jpg" self.mortgage_unmortgage_money += btn_instance.square_property.mortgage_value # Update the property_money if self.mortgage_unmortgage_money < 0: self.ids.mortgage_unmortgage_money.text = f"[b][color=#000000]Property Money: -${abs(self.mortgage_unmortgage_money)}[/b][/color]" else: self.ids.mortgage_unmortgage_money.text = f"[b][color=#000000]Property Money: ${abs(self.mortgage_unmortgage_money)}[/b][/color]" # Update the total_money self.total_money = self.player.money + self.mortgage_unmortgage_money self.ids.total_money.text = f"[b][color=#000000]Total Money: ${self.total_money}[/b][/color]" # if self.total_money != self.player.money: # self.ids.select_name_btn.disabled = True # else: # self.ids.select_name_btn.disabled = False if self.mortgage_unmortgage_money: self.ids.select_name_btn.disabled = True else: self.ids.select_name_btn.disabled = False def accept(self): # The properties that were selected must be mortgage/unmortgage for square_property in self.selected_square_properties: # Update the mortgage boolean square_property.mortgage = not square_property.mortgage # Call the gameboard to make the properties look mortgage or unmortgage square_property.update_player_icon() # Modify the player's money given the mortgage_unmortgage money self.player.money = self.total_money # Inform root to update property ownership and update player's money self.root.parent.parent.update_players_to_frame() # Log mortgage event mortgaged_property = ",".join( [square_property.full_name for square_property in self.selected_square_properties if square_property.mortgage is True]) unmortgaged_property = ",".join( [square_property.full_name for square_property in self.selected_square_properties if square_property.mortgage is False]) mortgaged_property = mortgaged_property if mortgaged_property else "no property" unmortgaged_property = unmortgaged_property if unmortgaged_property else "no property" log_text = f"{self.player.name.upper()} mortgaged {mortgaged_property} and unmortgage {unmortgaged_property}" self.root.parent.parent.add_history_log_entry(log_text) # Dismiss the popup self.dismiss() def dismiss(self): if self.dismiss_binding_fn: self.dismiss_binding_fn() super().dismiss()
class TradePop(Popup): def __init__(self, **kwargs): # Obtain root reference self.root = kwargs.pop('root') super().__init__(**kwargs) # Btns list of players self.left_btns = {} self.right_btns = {} # Selected players self.left_player = None self.right_player = None # Properties selected containers self.left_square_properties = [] self.right_square_properties = [] # Disable the accept button self.ids.accept_btn.disabled = True Clock.schedule_once(self.create_dropdown, 0) def create_dropdown(self, *args): self.dropdown_list_left = DropDown() self.dropdown_list_right = DropDown() for player in self.root.players: player_name = player.name.upper() # button for dropdown list 1 btn_left = Button( text=f'[b][color=#ffffff]{player_name}[/b][/color]', size_hint_y=None, height=self.width // 25, markup=True ) # button for dropdown list 2 btn_right = Button( text=f'[b][color=#ffffff]{player_name}[/b][/color]', size_hint_y=None, height=self.width // 25, markup=True ) # Storing the btn references into a list self.left_btns[player_name] = btn_left self.right_btns[player_name] = btn_right # Create the binding function btn_left.bind(on_release=lambda btn_left: self.dropdown_list_left.select(btn_left.text)) btn_right.bind(on_release=lambda btn_right: self.dropdown_list_right.select(btn_right.text)) # Add the widget to the dropdown window self.dropdown_list_left.add_widget(btn_left) self.dropdown_list_right.add_widget(btn_right) # Bind the select name btns to opening the dropdown window self.ids.select_name_btn_left.bind(on_release=self.dropdown_list_left.open) self.ids.select_name_btn_right.bind(on_release=self.dropdown_list_right.open) # Binding the select name btns to also update their text values self.dropdown_list_left.bind( on_select=functools.partial(self.select_player, self.ids.select_name_btn_left, 'left') ) self.dropdown_list_right.bind( on_select=functools.partial(self.select_player, self.ids.select_name_btn_right, 'right') ) def select_player(self, btn, side, instance, button_text): # Obtain the true value in the text previous_player_name = btn.text.split(']')[2].split('[')[0] player_name = button_text.split(']')[2].split('[')[0] # If the selection change from not the default value if previous_player_name != 'SELECT PLAYER NAME': self.dropdown_list_right.add_widget(self.right_btns[previous_player_name]) self.dropdown_list_left.add_widget(self.left_btns[previous_player_name]) # Removing the corresponding button from # right dropdown window self.dropdown_list_left.remove_widget(self.left_btns[player_name]) self.dropdown_list_right.remove_widget(self.right_btns[player_name]) # Update text to given x btn.text = button_text # Find the matching player given the player_name selected_player = None for player in self.root.players: if player.name.upper() == player_name: selected_player = player break # Store the selected player if side == 'left': self.left_player = selected_player self.ids.left_slider.max = self.left_player.money elif side == 'right': self.right_player = selected_player self.ids.right_slider.max = self.right_player.money # Update the property container with the selected player self.update_property_container(selected_player, side) if (self.left_player is not None) and (self.right_player is not None): self.ids.accept_btn.disabled = False def update_property_container(self, selected_player, side): # Clean property container if side == 'left': self.ids.left_property_container.clear_widgets() elif side == 'right': self.ids.right_property_container.clear_widgets() # Fill the property container given the properties of the # selected player for square_property in selected_player.property_own: # Create button for property property_btn = PropertyButton( text=f'[b][color=#000000]{square_property.full_name}[/b][/color]', markup=True, background_normal="", square_property=square_property ) # Bind the property button to function property_btn.bind(on_release=functools.partial(self.property_button_press, side)) # Add button to the property container if side == 'left': self.ids.left_property_container.add_widget(property_btn) elif side == 'right': self.ids.right_property_container.add_widget(property_btn) def property_button_press(self, side, btn_instance): square_property_container = self.left_square_properties if side == 'left' else self.right_square_properties # If the property is already selected, deselect it by: if btn_instance.square_property in square_property_container: # Remove from the list square_property_container.remove(btn_instance.square_property) # Change the color of the button back to white btn_instance.background_normal = "" else: # Append to the list square_property_container.append(btn_instance.square_property) # Change the color of the button to be highlighted btn_instance.background_normal = "assets/buttons/red.png" def accept(self): # Exchange properties # Left player gets the right properties for traded_square_property in self.left_square_properties: # Remove left's ownership self.left_player.property_own.remove(traded_square_property) # Add right's ownership self.root.buy_property(self.right_player, traded_square_property, cost=0) # Right player gets the left properties for traded_square_property in self.right_square_properties: # Remove right's ownership self.right_player.property_own.remove(traded_square_property) # Add left's ownership self.root.buy_property(self.left_player, traded_square_property, cost=0) # Exchange money left_slider_value = int(self.ids.left_slider.value) right_slider_value = int(self.ids.right_slider.value) self.left_player.money -= left_slider_value self.right_player.money += left_slider_value self.left_player.money += right_slider_value self.right_player.money -= right_slider_value # Inform root to update property ownership and update player's money self.root.parent.parent.update_players_to_frame() # Trade event log left_property = ",".join([sq.full_name for sq in self.left_square_properties]) right_property = ",".join([sq.full_name for sq in self.right_square_properties]) left_property = left_property if left_property else "no property" right_property = right_property if right_property else "no property" log_text = f"{self.left_player.name.upper()} traded {left_property} and ${left_slider_value} for {self.right_player.name.upper()}'s {right_property} and ${right_slider_value}" self.root.parent.parent.add_history_log_entry(log_text) # Dismiss the popup self.dismiss()