def __init__(self, json_device, *args, **kwargs): super(DeviceBox, self).__init__(*args, **kwargs) self.app = App.get_running_app() print 'building device box' print json_device print '\n' self.maj_id = json_device['id'] self.model = json_device['device_key'] self.name = json_device['name'] self.orientation = 'vertical' self.add_widget(Label(text = self.name, text_size = (self.width-dp(10), 35))) if self.model in self.nexa_controllers: self.switches = [] for switch in json_device['switches']: if switch['state'] != None: state = switch['state'] else: state = False new_switch = Switch(id = switch['id'], active = state, disabled = True) self.switches.append(new_switch) self.add_widget(new_switch) elif self.model in self.nexa_sensors: self.last_activated = Label(text = json_device['last_activated'], size_hint = (None, 1), text_size = (self.width-dp(10), 100), pos_hint = {'center_x': 0.5}) self.add_widget(self.last_activated) elif self.model in self.nexa_devices: self.switch = Switch(id = json_device['id']) self.switch.bind(active = self.user_action) self.add_widget(self.switch)
def _create_popup(self, instance): # create the popup content = BoxLayout(orientation='vertical', spacing='5dp') popup_width = min(0.95 * Window.width, dp(500)) self.popup = popup = Popup( content=content, title=self.title, size_hint=(None, None), size=(popup_width, '400dp')) popup.height = len(self.options) * dp(55) + dp(150) # add all the options content.add_widget(Widget(size_hint_y=None, height=1)) uid = str(self.uid) for option in self.options: state = 'down' if option == self.value else 'normal' btn = ToggleButton(text=option, state=state, group=uid) btn.bind(on_release=self._set_option) content.add_widget(btn) # finally, add a cancel button to return on the previous panel content.add_widget(SettingSpacer()) btn = Button(text='Cancel', size_hint_y=None, height=dp(50)) btn.bind(on_release=popup.dismiss) content.add_widget(btn) # and open the popup ! popup.open()
def on_touch_down(self, touch): #when touch count = 2, the canvas is cleared, getting rid of the lines and angle if self.touch_down_count == 2: self.canvas.clear() return #when touch count is greater than 2, we reset the count to zero to allow for new lines to be drawn and measured if self.touch_down_count > 2: self.touch_down_count = 0 #Record the touch coordinates in x and y as variables x1 = touch.x y1 = touch.y #create a label on touch and store it in the user dictionary to be accessed later by an update function touch.ud['label'] = Label(size_hint=(None, None)) #when the touch count is 0 or 1, we will record the touch coordinates and draw a crosshair at the touch location if self.touch_down_count <= 1: #add a label widget self.add_widget(touch.ud['label']) with self.canvas: #save the touch points to the user dictionary touch.ud['x1'] = x1 touch.ud['y1'] = y1 #set parameters for crosshair display Color(1, 0, 0) l = dp(40) w = dp(3) #draw crosshair Rectangle(pos=(touch.ud['x1'] - w / 2, touch.ud['y1'] - l / 2), size=(w, l)) Rectangle(pos=(touch.ud['x1'] - l / 2, touch.ud['y1'] - w / 2), size=(l, w))
def __init__(self, **kwargs): # The starting vertical scroll position self._start_y = None super(ScrollContainer, self).__init__(**kwargs) self.scroll_type = ['bars', 'content'] self.scroll_wheel_distance = dp(114) self.bar_width = dp(20)
def on_touch_down(self, touch): #Record the touch coordinates in x and y as variables x1 = touch.x y1 = touch.y #when the touch count is 0 or 1, we will record the touch coordinates and draw a crosshair at the touch location if self.touch_down_count > 1: return with self.canvas: touch.ud['label'] = TextInput() self.initiate_touch_label(touch.ud['label'], touch) self.add_widget(touch.ud['label']) #save the touch points to the user dictionary touch.ud['x1'] = x1 touch.ud['y1'] = y1 #set parameters for crosshair display Color(1, 0, 0) l = dp(25) w = dp(1) #draw crosshair Rectangle(pos=(touch.ud['x1'] - w / 2, touch.ud['y1'] - l / 2), size=(w, l)) Rectangle(pos=(touch.ud['x1'] - l / 2, touch.ud['y1'] - w / 2), size=(l, w)) #Initialize the vector v1 if self.touch_down_count == 0: #Record the touch coordinates to variables x2 = touch.x y2 = touch.y #Save touch coordinates to the user dictionary touch.ud['x2'] = x2 touch.ud['y2'] = y2 #When the touch count is zero (first touch), we define a vector v1 based on the touch positions in ud v1 = (touch.ud['x2'] - touch.ud['x1'], touch.ud['y2'] - touch.ud['y1']) self.v1 = v1
def on_volts(self, mapBin, instance): value = instance.text.strip() if value == '' or value == "." or value == "-": value = 0 instance.text = str(value) try: value = float(value) if self.scaling_map: self.scaling_map.setVolts(mapBin, value) self.dispatch('on_map_updated') self.regen_plot() except ScalingMapException as e: warn = CenteredBubble() warn.add_widget(WarnLabel(text=str(e))) warn.auto_dismiss_timeout(WARN_DISMISS_TIMEOUT) warn.background_color = (1, 0, 0, 1.0) warn.size = (dp(200), dp(50)) warn.size_hint = (None,None) self.get_root_window().add_widget(warn) warn.center_on(instance) original_value = self.scaling_map.getVolts(mapBin) self.set_volts_cell(instance, original_value) Clock.schedule_once(lambda dt: self._refocus(instance)) except Exception as e: alertPopup('Scaling Map', str(e)) original_value = self.scaling_map.getVolts(mapBin) self.set_volts_cell(instance, original_value)
def Start(self,uTitle,aOptions,fktCallBack): ''' starts selection ''' self.fktCallBack=fktCallBack # create the popup content = GridLayout(cols=1, spacing='5dp') scrollview = ScrollView( do_scroll_x=False, bar_width='10dp',scroll_type=['bars'] ) scrollcontent = GridLayout(cols=1, spacing='5dp', size_hint=(None, None)) scrollcontent.bind(minimum_height=scrollcontent.setter('height')) self.oPopup = popup = Popup(content=content, title=ReplaceVars(uTitle), size_hint=(0.5, 0.9), auto_dismiss=False) #we need to open the popup first to get the metrics popup.open() #Add some space on top content.add_widget(Widget(size_hint_y=None, height=dp(2))) # add all the options for option in aOptions: if hasattr(option,"Name"): name=option.Name else: name=option.Type btn = Button(text=name, size=(popup.width, dp(30)), size_hint=(None, None)) btn.bind(on_release=self.On_Value) btn.oDBRef=option scrollcontent.add_widget(btn) # finally, add a cancel button scrollview.add_widget(scrollcontent) content.add_widget(scrollview) content.add_widget(SettingSpacer()) btn = Button(text=ReplaceVars('$lvar(5009)'), size=(popup.width, dp(50)),size_hint=(0.9, None)) btn.bind(on_release=popup.dismiss) content.add_widget(btn)
def on_edit(self): channel = self.channel popup = Popup(title='Edit System Channel' if channel.systemChannel else 'Edit Channel', content=ChannelEditor(channel=channel), size_hint=(None, None), size=(dp(500), dp(180))) popup.open() popup.bind(on_dismiss=self.on_edited)
def card(content, title=None, background_color=None, size=(.7, .5)): '''Вывод диалоговых окон с кастомным контентом.''' if not background_color: background_color = [1.0, 1.0, 1.0, 1] card = MDCard(size_hint=(1, 1), padding=5) #, background_color=background_color) if title: box = BoxLayout(orientation='vertical', padding=dp(8)) box.add_widget( MDLabel( text=title, theme_text_color='Secondary', font_style="Title", size_hint_y=None, height=dp(36) ) ) box.add_widget(MDSeparator(height=dp(1))) box.add_widget(content) card.add_widget(box) else: card.add_widget(content) dialog = ModalView(size_hint=size, background_color=[0, 0, 0, .2]) dialog.add_widget(card) #dialog.open() return dialog
def on_touch_up(self, touch): if touch == self.current_touch: self.current_touch = None if self.app.editor.delete.collide_point( *self.to_window(*touch.pos)): for f in [frog for frog in self.parent.children if type(frog) == FrogPH]: if f.place == self.id: self.app.editor.level.remove_widget(f) self.app.editor.level.remove_widget(self) return True x = int(round(self.center_x / dp(100), 0)) y = int(round(self.y / dp(100), 0)) x = x if x > 0 else 1 y = y if y > 0 else 1 center_x = dp(100) * x y = dp(100) * y # Loop until a free place was found loop = True while loop: for child in self.parent.children: if child.center_x == center_x and\ y == child.y and child != self: x += 1 center_x = dp(100) * x break else: loop = False self.center_x = center_x self.y = y self.app.editor.select.center = self.to_window( *self.center) return True return super(PHScatter, self).on_touch_up(touch)
def export_level(self, path): out = "level boats={} flys={} energy={} ".format( self.sidebar.level_settings.boats_count.text, self.sidebar.level_settings.flys_count.text, self.sidebar.level_settings.energy_count.text) # get level size max_x = 0 max_y = 0 children = self.level.children for c in children: x = int(round(c.center_x / dp(100), 0)) if x > max_x: max_x = x y = int(round(c.y / dp(100), 0)) if y > max_y: max_y = y out += "size={},{}\n".format(max_x + 1, max_y + 1) # add the objects for c in self.level.children: extra_opts = " " if type(c) == WaterLilyPH: tp = "waterlily" elif type(c) == StoneLilyPH: tp = "stonelily" elif type(c) == SwitchLilyPH: if c.options.controlled: tp = "switchlily" extra_opts += "controlled={}".format( c.options.controlled.id) else: tp = "stonelily" elif type(c) == ExercisePH: tp = c.options.tp.lower() extra_opts += "count={} orientation={} ".format( c.options.count, c.options.orientation.lower()) elif type(c) == StartPH: tp = "start" elif type(c) == EndPH: tp = "end" else: continue x = int(round(c.center_x / dp(100), 0)) y = int(round(c.y / dp(100), 0)) c_id = c.id s = "{} pos={},{} id={}".format(tp, x, y, c_id) out += s + extra_opts + "\n" # Add the player frog out += "frog id=player jump_img={} sit_img={}"\ .format( self.level.start.frog.jump_img, self.level.start.frog.sit_img) +\ " player=True place=start\n" # Add the other frogs for frog in [c for c in self.level.children if type(c) == FrogPH]: out += "frog jump_img={} sit_img={} place={}\n".format( frog.jump_img, frog.sit_img, frog.place) f = open(path, "w") f.write(out) f.close()
def _update_shadow(self, *args): if self.elevation > 0: width = self.width * 2 height = self.height * 2 x = self.center_x - width / 2 self._soft_shadow_size = (width, height) self._hard_shadow_size = (width, height) y = self.center_y - height / 2 - dp(.1 * 1.5 ** self.elevation) self._soft_shadow_pos = (x, y) self._soft_shadow_a = 0.1 * 1.1 ** self.elevation self._soft_shadow_texture = self._shadow.textures[ str(int(round(self.elevation)))] y = self.center_y - height / 2 - dp(.5 * 1.18 ** self.elevation) self._hard_shadow_pos = (x, y) self._hard_shadow_a = .4 * .9 ** self.elevation self._hard_shadow_texture = self._shadow.textures[ str(int(round(self.elevation - 1)))] else: self._soft_shadow_a = 0 self._hard_shadow_a = 0
def on_touch_up(self, touch): if touch == self.current_touch: self.current_touch = None if self.app.editor.delete.collide_point(*touch.pos): self.app.editor.level.remove_widget(self) return True x = int(round(self.center_x / dp(100), 0)) y = int(round(self.y / dp(100), 0)) center_x = dp(100) * x y = dp(100) * y for child in self.parent.children: if child.center_x == center_x and\ y == child.y and child != self and\ type(child) != FrogPH and\ type(child) != StartPH: for frog in [c for c in self.parent.children if type(c) == FrogPH]: if frog.place == child.id and frog != self: break else: child.bind(pos=self.on_parent_pos) self.center = child.center self.app.editor.select.center = self.to_window( *self.center) self.place = child.id break else: self.parent.remove_widget(self) return True return super(PHScatter, self).on_touch_up(touch)
def build(self): # create root widget root_widget = FloatLayout() box = BoxLayout(orientation='vertical', size_hint=(None, None), size=(400, 200), spacing=dp(20), padding=dp(20), pos_hint={'center_x': .5, 'center_y':.5}) # create the labels and the textinputs lbl_user = Label(text='User Name:') lbl_password = Label(text='Password') ti_user = TextInput() ti_password = TextInput(password=True) # create the containers for the labels and textinputs grid_user_pass = GridLayout(rows=2, cols=2, spacing=dp(20)) # create the ok button my_but_is_ok = Button(text='OK') my_but_is_ok.bind(on_release=lambda *args: self.check_user(ti_user.text, ti_password.text)) # add the labels and input fields to the container grid_user_pass.add_widget(lbl_user) grid_user_pass.add_widget(ti_user) grid_user_pass.add_widget(lbl_password) grid_user_pass.add_widget(ti_password) # add the grid_container into it's container box.add_widget(grid_user_pass) root_widget.add_widget(box) # add the ok button at the bottom of the grid box.add_widget(my_but_is_ok) return root_widget
def __init__(self, **kwargs): super(GameRecorder, self).__init__(**kwargs) self.orientation = 'vertical' if self.height > self.width else 'horizontal' self.bind(size=self.on_size, orientation=self.on_orientation) self.game = Game() side_box = BoxLayout(orientation='vertical') b = BoxLayout(size_hint_y=None, height=dp(50)) back_button = CustomButton(text='<< Games') undo_button = CustomButton(text='Reset') undo_button.bind(on_release=self.reset) back_button.bind(on_release=self.go_back) b.add_widget(back_button) b.add_widget(undo_button) save_button = CustomButton(text='Save game', size_hint_y=None, height=dp(50)) save_button.bind(on_release=self.save_popup) side_box.add_widget(b) side_box.add_widget(save_button) moves_scroll = ScrollView() self.moves_table=MovesGrid(padding=dp(10), spacing=dp(10)) for move in self.game.move_history: self.moves_table.add_widget(MoveButton(text=move)) side = self.height if self.orientation == 'horizontal' else self.width self.board = ChessboardUI(game=self.game, size_hint=(None,None), height=side, width=side) self.board.bind(move_made=self.change_moves) self.add_widget(self.board) moves_scroll.add_widget(self.moves_table) side_box.add_widget(moves_scroll) self.add_widget(side_box)
def _create_subpopup(self, instance): ''' shows the sub popup ''' # create the popup content = GridLayout(cols=1, spacing='5dp') scrollview = ScrollView( do_scroll_x=False) scrollcontent = GridLayout(cols=1, spacing='5dp', size_hint=(None, None)) scrollcontent.bind(minimum_height=scrollcontent.setter('height')) self.subpopup = popup = Popup(content=content, title=self.uOption, size_hint=(0.5, 0.9), auto_dismiss=False) #we need to open the popup first to get the metrics popup.open() #Add some space on top content.add_widget(Widget(size_hint_y=None, height=dp(2))) # add all the options uid = str(self.uid) for option in self.aSubOption: state = 'down' if option == self.value else 'normal' oTbtn = ToggleButton(text=option, state=state, group=uid, size=(popup.width, dp(55)), size_hint=(None, None)) oTbtn.bind(on_release=self._set_suboption) scrollcontent.add_widget(oTbtn) # finally, add a cancel button to return on the previous panel scrollview.add_widget(scrollcontent) content.add_widget(scrollview) content.add_widget(SettingSpacer()) oMbtn = cMultiLineButton(text=ReplaceVars('$lvar(5009)'), size=(popup.width, dp(50)),size_hint=(0.9, None), halign='center', valign='middle') oMbtn.bind(on_release=popup.dismiss) content.add_widget(oMbtn)
def change_ctx(self, text, *args): popup = self.parent.parent.parent.parent.parent container = self.ids.cols_container amount = self.ids.amount if not self._old_height: self._old_height = self.height if text == 'Columns': # hide amount amount.size_hint_x = 0 amount.width = 0 amount.background_color = (0, 0, 0, 0) # add layout for columns container.add_widget(AppendColsLayout()) self.height = self.height + dp(90) container.height = dp(90) else: # show amount amount.size_hint_x = 1 amount.background_color = (1, 1, 1, 1) self.height = self._old_height container.height = 0 if container.children: container.clear_widgets() popup.recalc_height(popup.ids.taskbody, self.parent)
def init_tracks_list(self): if self.track_manager and self.trackDb: matchedTracks = [] for track in self.trackDb.tracks: matchedTrack = self.track_manager.find_track_by_short_id(track.trackId) if matchedTrack: matchedTracks.append(matchedTrack) grid = kvFind(self, 'rcid', 'tracksgrid') grid.clear_widgets() if len(matchedTracks) == 0: grid.add_widget(EmptyTrackDbView()) self.tracksGrid.height = dp(self.TRACK_ITEM_MIN_HEIGHT) else: self.tracksGrid.height = dp(self.TRACK_ITEM_MIN_HEIGHT) * (len(matchedTracks) + 1) index = 0 for track in matchedTracks: trackDbView = TrackDbItemView(track=track, index=index) trackDbView.bind(on_remove_track=self.on_remove_track) trackDbView.size_hint_y = None trackDbView.height = dp(self.TRACK_ITEM_MIN_HEIGHT) grid.add_widget(trackDbView) index += 1 self.disableView(False)
def move(self): if self.dead: if self.image.pos[0] > resources.rocket['width'] * -1 and\ self.image.pos[1] > resources.rocket['height'] * -1: self.image.pos = (self.image.pos[0] - dp(20), self.image.pos[1] - dp(20)) self.image.size = (self.image.size[0] - dp(25), self.image.size[1] - dp(10)) return if self.force: self.image.source = resources.rocket['sprite1'] self.image.reload() # if self.image.pos[1] < (Window.height - self.default_y - 150): # self.die() self.image.pos = (self.image.pos[0], self.image.pos[1] + Sizer.get_rocket_speed()) self.pos = (self.image.pos[0], self.image.pos[1] + Sizer.get_rocket_speed()) else: self.image.source = resources.rocket['sprite2'] self.image.reload() self.image.pos = (self.image.pos[0], self.image.pos[1] - Sizer.get_rocket_speed()) self.pos = (self.image.pos[0], self.image.pos[1] - Sizer.get_rocket_speed()) if ( self.image.pos[1] < (self.image.size[1] / 2) * -1 or self.image.pos[1] > Window.height + self.image.size[1] ): self.die()
def _create_popup(self, instance): """Modified from SettingString's popup.""" # create popup layout self.popup = SliderPopup(title=self.title, setting=self, value=float(self.value), size=(min(0.95 * Window.width, dp(500)), dp(250))) self.popup.open()
def __init__(self, username, userid, name): """ """ self.name = name self.username = username self.userid = userid super(LevelSelect, self).__init__() conn = sqlite3.connect(filehome + 'database.db') # Opens the connection to the database. c = conn.cursor() levels = c.execute('''SELECT levelid, levelname, leveldesc FROM level''') # Gets the levels from the database box = BoxLayout(orientation = 'vertical') box.add_widget(Banner(False, 2, self.userid)) # Adds the top banner, as this is the main menu we need a logout button and not a back button. lvlAccordion = Accordion(orientation = 'vertical', min_space = dp(25), anim_duration = 1) for i in levels: item = AccordionItem(title = i[1], min_space = dp(25), background_normal='images/blue32025.png', background_selected='images/orange32025.png') boxa = BoxLayout(orientation = 'vertical') lbl = Label(text = i[2], text_size = (300, None)) boxa.add_widget(lbl) btn = Button(text = 'Go', id = str(i[0])+','+i[1], on_press = self.selectlevel, background_normal = 'images/orange32030.png', background_down = 'images/blue32025.png', size_hint_y = None, height = dp(30)) boxa.add_widget(btn) item.add_widget(boxa) lvlAccordion.add_widget(item) box.add_widget(lvlAccordion) # Adds the Accordion to the box self.add_widget(box) # Adds the box widget to the screen conn.close()
def __init__(self, **kwargs): super(MyScreen, self).__init__(**kwargs) scrollView = ScrollView() self.add_widget(scrollView) boxLayout = BoxLayout(orientation='vertical', height=dp(1000), padding=dp(48)) scrollView.add_widget(boxLayout) textField = SingleLineTextField(id='text_filed', size_hint=(0.8, None), height=dp(48)) textField.hint_text='This is a pretty text filed' boxLayout.add_widget(textField) buttonContainer = BoxLayout(orientation='horizontal', height=dp(48)) flatButton = MDFlatButton(text='FlatButton') # size is not working somehow # flatButton.size = (3*dp(48), dp(48)) buttonContainer.add_widget(flatButton) raiseButton = MDRaisedButton(text='RaiseButton') # raiseButton.size = (3*dp(48), dp(48)) buttonContainer.add_widget(raiseButton) boxLayout.add_widget(buttonContainer) switchContainer = BoxLayout(orientation='horizontal') checkbox1 = MDCheckbox(group='test') # checkbox1.size=(dp(48), dp(48)) switchContainer.add_widget(checkbox1) checkbox2 = MDCheckbox(group='test') # checkbox2.size=(dp(48), dp(48)) switchContainer.add_widget(checkbox2) boxLayout.add_widget(switchContainer)
def ShowList(self): ''' Shows the discover results ''' # create the popup oContent = GridLayout(cols=1, spacing='5dp') oScrollview = ScrollView( do_scroll_x=False) self.oScrollContent = StackLayout(size_hint=(None, None)) self.oPopup = oPopup = Popup(content=oContent, title=ReplaceVars('$lvar(5028)'), size_hint=(0.9, 0.9), auto_dismiss=False) #we need to open the popup first to get the metrics oPopup.open() #Add some space on top oContent.add_widget(Widget(size_hint_y=None, height=dp(2))) aDiscoverScripts=oORCA.oScripts.GetScriptListForScriptType("DEVICE_DISCOVER") aScrollContent=[] for uDiscoverScriptName in aDiscoverScripts: oScrollContentSingle = GridLayout(size_hint=(None, None)) aScrollContent.append(oScrollContentSingle) oScrollContentSingle.bind(minimum_height=oScrollContentSingle.setter('height')) oORCA.oScripts.RunScript(uDiscoverScriptName,{'createlist':1,'oGrid':oScrollContentSingle}) self.oScrollContent.add_widget(cLabel(text=oORCA.oScripts.aScripts[uDiscoverScriptName].uSubType, background_color=[0.2, 0.2, 0.2, 1.0], color=[0.9, 0.9, 0.9, 1.0], size=(oPopup.width, dp(30)),size_hint=(None, None), halign='center')) self.oScrollContent.add_widget(oScrollContentSingle) self.oScrollContent.add_widget(SettingSpacer()) # finally, add a cancel button to return on the previous panel oScrollview.add_widget(self.oScrollContent) oContent.add_widget(oScrollview) oContent.add_widget(SettingSpacer()) oBtn = Button(text=ReplaceVars('$lvar(5000)'), size=(oPopup.width, dp(50)),size_hint=(1, None)) oBtn.bind(on_release=self.On_Cancel) oContent.add_widget(oBtn) #resize the Scrollcontent to fit to all Childs. Needs to be done, after the popup has been shown Clock.schedule_once(self.SetScrollSize, 0)
def __init__(self, **kwargs): # ID of the command being executed self._cmd_id = None # List of the "completed" statuses. # The first status should be "Done" self._completed = [] # If True - sends a request to retrieve a command status self._wait_completion = False # requested command self._command = (0, '') super(RemoteControlUI, self).__init__( orientation='vertical', spacing=2, padding=3, **kwargs) # Control buttons panel pnl_controls = BoxLayout(size_hint_y=None, height=metrics.dp(35)) pnl_controls.add_widget( Button(text='Refresh', on_release=self._get_commands)) pnl_controls.add_widget( Button(text='Close', on_release=App.get_running_app().stop)) self.add_widget(pnl_controls) # Command buttons panel self._pnl_commands = BoxLayout(orientation='vertical') self.add_widget(self._pnl_commands) # Info panel lbl_info = Label( text=self.info_text, size_hint_y=None, height=metrics.dp(35)) self.bind(info_text=lbl_info.setter('text')) self.add_widget(lbl_info)
def on_pos(self, *args): self.hint_anim_in = Animation(_hint_y=dp(34), _hint_lbl_font_size=sp(12), duration=.2, t='out_quad') self.hint_anim_out = Animation(_hint_y=dp(10), _hint_lbl_font_size=sp(16), duration=.2, t='out_quad')
def __init__(self, **kwargs): super(Collide, self).__init__(**kwargs) self.remove_width = dp(280) self.remove_height = dp(120) if self.debug: with self.canvas: Color(1, 0, 0) self.rect = Rectangle()
def on_bt_configure(self, instance, value): if not self._bt_popup: content = AdvancedBluetoothConfigView(self.config.connectivityConfig) popup = editor_popup(title="Configure Bluetooth", content=content, answerCallback=self.on_bluetooth_popup_answer, size=(dp(600), dp(300))) self._bt_popup = popup self._bt_config_view = content
def _get_standard_increment(self): if DEVICE_TYPE == "mobile": if self.device_orientation == "landscape": return dp(48) else: return dp(56) else: return dp(64)
def set_background(self): texture = GameContext.resources['textures']['toolbar_bg'] th, tw = texture.size th, tw = dp(th), dp(tw) with self.canvas.before: Color(1, 1, 1, 1) for i in xrange(50): Rectangle(pos=(i*tw, 0) , size=(tw, th), texture=texture)
def on_text(self, *args): #get text field text text_input_value = self.header_textinput.text #once user has type 3 letters and more, start substring search if len(text_input_value)>2: #if previous listview exists, remove it self.closeListView() #start search, put the response data in a list adapter suggestions = app.datamall_bus_stop.busnamesubstringSearch(text_input_value) #ListitemButton Behaviour args_converter = lambda row_index, rec: { 'text':rec['text'], 'size_hint':(None,None), 'height': '50dp', 'width': self.header_textinput.width } suggestion_listadapter = ListAdapter( data=suggestions, args_converter=args_converter, selection_mode='multiple', selection_limit=1, allow_empty_selection=True, cls=ListItemButton ) #binds each listview button to the autofill function suggestion_listadapter.bind(on_selection_change=self.selection_change) #Logger.info("heightheight"+str(dp(60))) #Logger.info("heightheight"+str(float(dp(50)*len(suggestions)/self.height))) self.suggestion_listview = ListView( adapter=suggestion_listadapter, size_hint_y=(float(dp(50)*len(suggestions)/self.height)) if (float(dp(50)*len(suggestions)/self.height))<0.4 else 0.4, width=self.header_textinput.width, pos_hint={"top":(self.height-self.header_textinput.height*1.3)/self.height}, x=self.header_textinput.x ) #The container is a GridLayout widget held within a ScrollView widget. #So we are giving the ScrollViewParent a custom scroll effect #ListView >> ScrollView >> GridLayout #effect_cls is an ObjectProperty and defaults to DampedScrollEffect. self.suggestion_listview.container.parent.effect_cls = self.scrolleffect #Timeout allowed to trigger the scroll_distance, in milliseconds. If the user has not moved scroll_distance within the timeout, the scrolling will be disabled, and the touch event will go to the children. self.suggestion_listview.container.parent.scroll_distance = 10 self.suggestion_listview.container.parent.scroll_timeout = 1000 self.listview_widget_collector.append(self.suggestion_listview) self.ids['searchbusscreen_floatlayout'].add_widget(self.suggestion_listview) else: #User is deleting his input, so naturally, we shall close the listview (if it exists) self.closeListView()
class MDBottomNavigationHeader(ThemableBehavior, ButtonBehavior, MDAnchorLayout): panel_color = ColorProperty([1, 1, 1, 0]) """ Panel color of bottom navigation. :attr:`panel_color` is an :class:`~kivy.properties.ColorProperty` and defaults to `[1, 1, 1, 0]`. """ tab = ObjectProperty() """ :attr:`tab` is an :class:`~MDBottomNavigationItem` and defaults to `None`. """ panel = ObjectProperty() """ :attr:`panel` is an :class:`~MDBottomNavigation` and defaults to `None`. """ active = BooleanProperty(False) text = StringProperty() """ :attr:`text` is an :class:`~MDTab.text` and defaults to `''`. """ text_color_normal = ColorProperty([1, 1, 1, 1]) """ Text color of the label when it is not selected. :attr:`text_color_normal` is an :class:`~kivy.properties.ColorProperty` and defaults to `[1, 1, 1, 1]`. """ text_color_active = ColorProperty([1, 1, 1, 1]) """ Text color of the label when it is selected. :attr:`text_color_active` is an :class:`~kivy.properties.ColorProperty` and defaults to `[1, 1, 1, 1]`. """ selected_color_background = ColorProperty(None) """ The background color of the highlighted item when using Material Design v3. .. versionadded:: 1.0.0 :attr:`selected_color_background` is an :class:`~kivy.properties.ColorProperty` and defaults to `None`. """ opposite_colors = BooleanProperty(True) _label = ObjectProperty() _label_font_size = NumericProperty("12sp") _text_color_normal = ColorProperty([1, 1, 1, 1]) _text_color_active = ColorProperty([1, 1, 1, 1]) _selected_region_width = NumericProperty(dp(64)) def __init__(self, panel, tab): self.panel = panel self.tab = tab super().__init__() self._text_color_normal = (self.theme_cls.disabled_hint_text_color if self.text_color_normal == [1, 1, 1, 1] else self.text_color_normal) self._label = self.ids._label self._label_font_size = sp(12) self.theme_cls.bind(disabled_hint_text_color=self._update_theme_style) self.active = False def on_press(self) -> None: """Called when clicking on a panel item.""" if self.theme_cls.material_style == "M2": Animation(_label_font_size=sp(14), d=0.1).start(self) elif self.theme_cls.material_style == "M3": Animation( _selected_region_width=dp(64), t="in_out_sine", d=0, ).start(self) Animation( _text_color_normal=self.theme_cls.primary_color if self.text_color_active == [1, 1, 1, 1] else self.text_color_active, d=0.1, ).start(self) def _update_theme_style(self, instance_theme_manager: ThemeManager, color: list): """Called when the application theme style changes (White/Black).""" if not self.active: self._text_color_normal = (color if self.text_color_normal == [ 1, 1, 1, 1 ] else self.text_color_normal)
def _update_ticks(self, size): # re-compute the positions of the bounding rectangle mesh = self._mesh_rect vert = mesh.vertices if self.draw_border: s0, s1, s2, s3 = size vert[0] = s0 vert[1] = s1 vert[4] = s2 vert[5] = s1 vert[8] = s2 vert[9] = s3 vert[12] = s0 vert[13] = s3 vert[16] = s0 vert[17] = s1 else: vert[0:18] = [0 for k in range(18)] mesh.vertices = vert # re-compute the positions of the x/y axis ticks mesh = self._mesh_ticks vert = mesh.vertices start = 0 xpoints = self._ticks_majorx ypoints = self._ticks_majory xpoints2 = self._ticks_minorx ypoints2 = self._ticks_minory ylog = self.ylog xlog = self.xlog xmin = self.xmin xmax = self.xmax if xlog: xmin = log10(xmin) xmax = log10(xmax) ymin = self.ymin ymax = self.ymax if ylog: xmin = log10(ymin) ymax = log10(ymax) if len(xpoints): top = size[3] if self.x_grid else metrics.dp(12) + size[1] ratio = (size[2] - size[0]) / float(xmax - xmin) for k in range(start, len(xpoints) + start): vert[k * 8] = size[0] + (xpoints[k - start] - xmin) * ratio vert[k * 8 + 1] = size[1] vert[k * 8 + 4] = vert[k * 8] vert[k * 8 + 5] = top start += len(xpoints) if len(xpoints2): top = metrics.dp(8) + size[1] ratio = (size[2] - size[0]) / float(xmax - xmin) for k in range(start, len(xpoints2) + start): vert[k * 8] = size[0] + (xpoints2[k - start] - xmin) * ratio vert[k * 8 + 1] = size[1] vert[k * 8 + 4] = vert[k * 8] vert[k * 8 + 5] = top start += len(xpoints2) if len(ypoints): top = size[2] if self.y_grid else metrics.dp(12) + size[0] ratio = (size[3] - size[1]) / float(ymax - ymin) for k in range(start, len(ypoints) + start): vert[k * 8 + 1] = size[1] + (ypoints[k - start] - ymin) * ratio vert[k * 8 + 5] = vert[k * 8 + 1] vert[k * 8] = size[0] vert[k * 8 + 4] = top start += len(ypoints) if len(ypoints2): top = metrics.dp(8) + size[0] ratio = (size[3] - size[1]) / float(ymax - ymin) for k in range(start, len(ypoints2) + start): vert[k * 8 + 1] = size[1] + (ypoints2[k - start] - ymin) * ratio vert[k * 8 + 5] = vert[k * 8 + 1] vert[k * 8] = size[0] vert[k * 8 + 4] = top mesh.vertices = vert
def show_floating_labels(self): i = 0 for lbl in self.lbl_list: i += 0.3 pos_x = Window.width / 2 - (lbl.width + dp(23)) Animation(x=pos_x, d=i, t="out_elastic").start(lbl)
def animateLightningBoltIcon(self): Anim = Animation(lightningBoltPosX=dp(10), t='out_quad', d=0.02) + Animation(lightningBoltPosX=dp(0), t='out_elastic', d=0.5) Anim.start(self)
def on_progress(*args): self._line_blank_space_right_point = ( self._hint_lbl.width + dp(5))
class Button_Item(ThemableBehavior, ButtonBehavior, BoxLayout): transition = StringProperty('out_quad') duration = NumericProperty(0.3) button_bg_color = ListProperty(None) button_width = NumericProperty(dp(120)) text_size = NumericProperty(dp(13)) text_color = ListProperty(None) button_height = NumericProperty(dp(40)) icon_size = NumericProperty(dp(20)) icon_color = ListProperty(None) text = StringProperty() icon = StringProperty() mode = OptionProperty('color_on_normal', options=['color_on_normal', 'color_on_active']) # ================ badgeitem_size = NumericProperty(dp(20)) badge_bg_color = ListProperty() badgeitem_padding = NumericProperty(dp(3)) badgeitem_color = ListProperty() badge_position = StringProperty('right') badge_text = StringProperty('') badge_bold = BooleanProperty(False) badge_offset = NumericProperty(0.4) badge_disabled = BooleanProperty(False) _bg_opacity = NumericProperty(1) def __init__(self, **kwargs): super().__init__(**kwargs) def on_release(self): for button in self.parent.children: if button == self: continue button._button_shrink() self._button_expand() return super().on_release() def _button_expand(self): label_anim = Animation(opacity=1, transition=self.transition, duration=self.duration) label_anim.start(self.ids._label) anim = Animation(width=self.button_width, _bg_opacity=1, t=self.transition, duration=self.duration) anim.start(self) def _button_shrink(self): if self.mode == 'color_on_active': opacity = 0 else: opacity = 1 label_anim = Animation(opacity=0, transition=self.transition, duration=self.duration) label_anim.start(self.ids._label) but_anim = Animation(width=self.height, _bg_opacity=opacity, t=self.transition, duration=self.duration) but_anim.start(self)
def __init__(self, **kwargs): super().__init__(**kwargs) self.height = dp(72)
def _update_action_buttons(self, *args): self._action_area.clear_widgets() for btn in self._action_buttons: btn.content.texture_update() btn.width = btn.content.texture_size[0] + dp(16) self._action_area.add_widget(btn)
def show_menu_list_animation(self): Animation(y=dp(60), d=0.6, t="out_elastic").start(self.ids.menu_dialog) self.menu_open = True
def back_animation(self): Animation( size=(dp(250), dp(250)), d=0.5, ).start(self.ids.helmet_img) Animation( y=-self.ids.shadow_planet_img.height, d=1.2, ).start(self.ids.shadow_planet_img) Animation( opacity=0, d=1.2, ).start(self.ids.box_name_planet) Animation( opacity=0, size=(0, 0), d=0.7, ).start(self.ids.earth_img) Animation( opacity=0, d=1.2, ).start(self.ids.light_img) Animation( opacity=0, d=0.7, t="in_sine", ).start(self.ids.bg_img) Animation( angle=45, size=(dp(100), dp(100)), pos_hint={"center_y": 0.5}, d=1, t="in_back", ).start(self.ids.planet_img) Animation( color=(0, 0, 0, 1), d=1, ).start(self.ids.toolbar) Animation(opacity=1, d=0.5).start(self.ids.box_carousel) Animation( opacity=0, y=-self.ids.planet_lbl.height, d=0.9, t="in_out_back", ).start(self.ids.planet_lbl) Animation( opacity=0, y=-self.ids.info_lbl.height, d=1.0, t="in_out_back", ).start(self.ids.info_lbl) Animation( opacity=0, y=-self.ids.more_lbl.height, d=1.1, t="in_out_back", ).start(self.ids.more_lbl) Animation( opacity=0, y=self.ids.sep.height, d=1.2, t="in_out_back", ).start(self.ids.sep) self.animation_back = False
class MDSelectionList(MDList): """ :Events: `on_selected` Called when a list item is selected. `on_unselected` Called when a list item is unselected. """ selected_mode = BooleanProperty(False) """ List item selection mode. If `True` when clicking on a list item, it will be selected. :attr:`selected_mode` is an :class:`~kivy.properties.BooleanProperty` and defaults to `False`. """ icon = StringProperty("check") """ Name of the icon with which the selected list item will be marked. :attr:`icon` is an :class:`~kivy.properties.StringProperty` and defaults to `'check'`. """ icon_pos = ListProperty() """ The position of the icon that will mark the selected list item. :attr:`icon_pos` is an :class:`~kivy.properties.ListProperty` and defaults to `[]`. """ icon_bg_color = ColorProperty([1, 1, 1, 1]) """ Background color of the icon that will mark the selected list item. :attr:`icon_bg_color` is an :class:`~kivy.properties.ColorProperty` and defaults to `[1, 1, 1, 1]`. """ icon_check_color = ColorProperty([0, 0, 0, 1]) """ Color of the icon that will mark the selected list item. :attr:`icon_check_color` is an :class:`~kivy.properties.ColorProperty` and defaults to `[1, 1, 1, 1]`. """ overlay_color = ColorProperty([0, 0, 0, 0.2]) """ The overlay color of the selected list item.. :attr:`overlay_color` is an :class:`~kivy.properties.ColorProperty` and defaults to `[0, 0, 0, 0.2]]`. """ progress_round_size = NumericProperty(dp(46)) """ Size of the spinner for switching of `selected_mode` mode. :attr:`progress_round_size` is an :class:`~kivy.properties.NumericProperty` and defaults to `dp(46)`. """ progress_round_color = ColorProperty(None) """ Color of the spinner for switching of `selected_mode` mode. :attr:`progress_round_color` is an :class:`~kivy.properties.NumericProperty` and defaults to `None`. """ def __init__(self, **kwargs): super().__init__(**kwargs) self.register_event_type("on_selected") self.register_event_type("on_unselected") def add_widget(self, widget, index=0, canvas=None): selection_icon = SelectionIconCheck( icon=self.icon, md_bg_color=self.icon_bg_color, icon_check_color=self.icon_check_color, ) container = SelectionItem( size_hint=(1, None), height=widget.height, instance_item=widget, instance_icon=selection_icon, overlay_color=self.overlay_color, progress_round_size=self.progress_round_size, progress_round_color=self.progress_round_color, owner=self, ) container.add_widget(widget) if not self.icon_pos: pos = ( dp(12), container.height / 2 - selection_icon.height / 2, ) else: pos = self.icon_pos selection_icon.pos = pos container.add_widget(selection_icon) return super().add_widget(container, index, canvas) def get_selected(self) -> bool: """Returns ``True`` if at least one item in the list is checked.""" selected = False for item in self.children: if item.selected: selected = True break return selected def get_selected_list_items(self) -> list: """ Returns a list of marked objects: [<kivymd.uix.selection.SelectionItem object>, ...] """ selected_list_items = [] for item in self.children: if item.selected: selected_list_items.append(item) return selected_list_items def unselected_all(self) -> None: for item in self.children: item.do_unselected_item() self.selected_mode = False def selected_all(self) -> None: for item in self.children: item.do_selected_item() self.selected_mode = True def on_selected(self, *args): """Called when a list item is selected.""" if not self.selected_mode: self.selected_mode = True def on_unselected(self, *args): """Called when a list item is unselected.""" self.selected_mode = self.get_selected()
class SelectionItem(ThemableBehavior, MDRelativeLayout, TouchBehavior): selected = BooleanProperty(False) """ Whether or not an item is checked. :attr:`selected` is an :class:`~kivy.properties.BooleanProperty` and defaults to `False`. """ owner = ObjectProperty() """ Instance of :class:`~kivymd.uix.selection.MDSelectionList` class. :attr:`owner` is an :class:`~kivy.properties.ObjectProperty` and defaults to `None`. """ instance_item = ObjectProperty() """ User item. Must be a Kivy or KivyMD widget. :attr:`instance_item` is an :class:`~kivy.properties.ObjectProperty` and defaults to `None`. """ instance_icon = ObjectProperty() """ Instance of :class:`~kivymd.uix.selection.SelectionIconCheck` class. :attr:`instance_icon` is an :class:`~kivy.properties.ObjectProperty` and defaults to `None`. """ overlay_color = ColorProperty([0, 0, 0, 0.2]) """See :attr:`~MDSelectionList.overlay_color`.""" progress_round_size = NumericProperty(dp(46)) """See :attr:`~MDSelectionList.progress_round_size`.""" progress_round_color = ColorProperty(None) """See :attr:`~MDSelectionList.progress_round_color`.""" _progress_round = NumericProperty(0) _progress_line_end = NumericProperty(0) _progress_animation = BooleanProperty(False) _touch_long = BooleanProperty(False) _instance_progress_inner_circle_color = ObjectProperty() _instance_progress_inner_circle_ellipse = ObjectProperty() _instance_progress_inner_outer_color = ObjectProperty() _instance_progress_inner_outer_line = ObjectProperty() _instance_overlay_color = ObjectProperty() _instance_overlay_rounded_rec = ObjectProperty() def __init__(self, **kwargs): super().__init__(**kwargs) Clock.schedule_once(self.set_progress_round) def set_progress_round(self, interval: Union[int, float]) -> None: with self.canvas.after: self._instance_progress_inner_circle_color = Color(rgba=(0, 0, 0, 0)) self._instance_progress_inner_circle_ellipse = Ellipse( size=self.get_progress_round_size(), pos=self.get_progress_round_pos(), ) self.bind( pos=self.update_progress_inner_circle_ellipse, size=self.update_progress_inner_circle_ellipse, ) # FIXME: Radius value is not displayed. self._instance_overlay_color = Color(rgba=(0, 0, 0, 0)) self._instance_overlay_rounded_rec = RoundedRectangle( size=self.size, pos=self.pos, radius=self.instance_item.radius if hasattr( self.instance_item, "radius") else [ 0, ], ) self.bind( pos=self.update_overlay_rounded_rec, size=self.update_overlay_rounded_rec, ) self._instance_progress_inner_outer_color = Color(rgba=(0, 0, 0, 0)) self._instance_progress_inner_outer_line = SmoothLine( width=dp(4), circle=[ self.center_x, self.center_y, self.progress_round_size * 0.58, 0, 0, ], ) def do_selected_item(self, *args) -> None: Animation(scale=1, d=0.2).start(self.instance_icon) self.selected = True self._progress_animation = False self._instance_overlay_color.rgba = self.get_overlay_color() self.owner.dispatch("on_selected", self) def do_unselected_item(self) -> None: Animation(scale=0, d=0.2).start(self.instance_icon) self.selected = False self._instance_overlay_color.rgba = self.get_overlay_color() self.owner.dispatch("on_unselected", self) def do_animation_progress_line(self, animation: Animation, instance_selection_item, value: float) -> None: self._instance_progress_inner_outer_line.circle = ( self.center_x, self.center_y, self.progress_round_size * 0.58, 0, 360 * value, ) def update_overlay_rounded_rec(self, *args) -> None: self._instance_overlay_rounded_rec.size = self.size self._instance_overlay_rounded_rec.pos = self.pos def update_progress_inner_circle_ellipse(self, *args) -> None: self._instance_progress_inner_circle_ellipse.size = ( self.get_progress_round_size()) self._instance_progress_inner_circle_ellipse.pos = ( self.get_progress_round_pos()) def reset_progress_animation(self) -> None: Animation.cancel_all(self) self._progress_animation = False self._instance_progress_inner_circle_color.rgba = (0, 0, 0, 0) self._instance_progress_inner_outer_color.rgba = (0, 0, 0, 0) self._instance_progress_inner_outer_line.circle = [ self.center_x, self.center_y, self.progress_round_size * 0.58, 0, 0, ] self._progress_line_end = 0 def get_overlay_color(self) -> list: return self.overlay_color if self.selected else (0, 0, 0, 0) def get_progress_round_pos(self) -> tuple: return ( self.center_x - self.progress_round_size / 2, self.center_y - self.progress_round_size / 2, ) def get_progress_round_size(self) -> tuple: return self.progress_round_size, self.progress_round_size def get_progress_round_color(self) -> tuple: return (self.theme_cls.primary_color if not self.progress_round_color else self.progress_round_color) def get_progress_line_color(self) -> tuple: return (self.theme_cls.primary_color[:-1] + [0.5] if not self.progress_round_color else self.progress_round_color[:-1] + [0.5]) def on_long_touch(self, *args) -> None: if not self.owner.get_selected(): self._touch_long = True self._progress_animation = True def on_touch_up(self, touch): if self.collide_point(*touch.pos): if self._touch_long: self._touch_long = False return super().on_touch_up(touch) def on_touch_down(self, touch): if self.collide_point(*touch.pos): if self.selected: self.do_unselected_item() else: if self.owner.selected_mode: self.do_selected_item() return super().on_touch_down(touch) def on__touch_long(self, instance_selection_tem, touch_value: bool) -> None: if not touch_value: self.reset_progress_animation() def on__progress_animation(self, instance_selection_tem, touch_value: bool) -> None: if touch_value: anim = Animation(_progress_line_end=360, d=1, t="in_out_quad") anim.bind( on_progress=self.do_animation_progress_line, on_complete=self.do_selected_item, ) anim.start(self) self._instance_progress_inner_outer_color.rgba = ( self.get_progress_line_color()) self._instance_progress_inner_circle_color.rgba = ( self.get_progress_round_color()) else: self.reset_progress_animation()
class ThreeLineIconListItem(ContainerSupport, ThreeLineListItem): _txt_left_pad = NumericProperty(dp(72))
def __init__(self, **kwargs): super().__init__(**kwargs) self._txt_right_pad = dp(40) + m_res.HORIZ_MARGINS
def __init__(self, **kwargs): super().__init__(**kwargs) self.height = dp(72) if not self._height else self._height
def __init__(self): super(HohenGame, self).__init__() self.textinput = TextInput(hint_text='Your commands here..', x=metrics.dp(10), y=metrics.dp(48), multiline=False, width=metrics.dp(470), height=metrics.dp(38)) self.cmd = Label(text="Welcome to Hohenheim!", x=metrics.dp(196), y=metrics.dp(130), text_size=(metrics.dp(460), metrics.dp(160)), markup=True) self.textinput.bind(on_text_validate=self.on_enter) self.giant = Sprite(source='images/giant.png', x=metrics.dp(620), y=metrics.dp(330)) self.depo = Sprite(source='images/deposit.png', x=metrics.dp(220), y=metrics.dp(470)) self.axe = Sprite(source='images/axe.png', x=metrics.dp(1220), y=metrics.dp(470)) self.invaxe = Image(source='images/axe.png', x=metrics.dp(self.invx('axe')), y=metrics.dp(self.invy('axe')), width=metrics.dp(30)) self.invdepo = Image(source='images/deposit.png', x=metrics.dp(self.invx('depo')), y=metrics.dp(self.invy('depo')), width=metrics.dp(30)) self.background = Sprite(source='images/background_nobridge.jpg') self.bridge = Sprite(source='images/bridge.jpg', x=metrics.dp(500), y=metrics.dp(260)) self.bridge_active = Sprite(source='images/bridge_active.jpg', x=metrics.dp(500), y=metrics.dp(260)) self.takehelp = {'axe': self.axe, 'depo': self.depo} self.gmhelp = { 'giant': self.giant, 'bridge': self.bridge, 'bridge_active': self.bridge_active } self.invhelp = {'axe': self.invaxe, 'depo': self.invdepo} self.add_widget(self.background) self.add_widget(self.textinput) self.add_widget(self.cmd) self.addobjects()
def on_focus(self, *args): disabled_hint_text_color = self.theme_cls.disabled_hint_text_color Animation.cancel_all(self, "_line_width", "_hint_y", "_hint_lbl_font_size") self._set_text_len_error() if self.focus: _fill_color = self.fill_color _fill_color[3] = self.fill_color[3] - 0.1 if not self._get_has_error(): def on_progress(*args): self._line_blank_space_right_point = ( self._hint_lbl.width + dp(5)) animation = Animation( _line_blank_space_left_point=self._hint_lbl.x - dp(5), _current_hint_text_color=self.line_color_focus, fill_color=_fill_color, duration=0.2, t="out_quad", ) animation.bind(on_progress=on_progress) animation.start(self) self.has_had_text = True Animation.cancel_all(self, "_line_width", "_hint_y", "_hint_lbl_font_size") if not self.text: self._anim_lbl_font_size(dp(14), sp(12)) Animation( _line_width=self.width, duration=(0.2 if self.line_anim else 0), t="out_quad", ).start(self) if self._get_has_error(): self._anim_current_error_color(self.error_color) if self.helper_text_mode == "on_error" and ( self.error or self._text_len_error): self._anim_current_error_color(self.error_color) elif (self.helper_text_mode == "on_error" and not self.error and not self._text_len_error): self._anim_current_error_color((0, 0, 0, 0)) elif self.helper_text_mode in ("persistent", "on_focus"): self._anim_current_error_color(disabled_hint_text_color) else: self._anim_current_right_lbl_color(disabled_hint_text_color) Animation( duration=0.2, _current_hint_text_color=self.line_color_focus).start(self) if self.helper_text_mode == "on_error": self._anim_current_error_color((0, 0, 0, 0)) if self.helper_text_mode in ("persistent", "on_focus"): self._anim_current_error_color(disabled_hint_text_color) else: _fill_color = self.fill_color _fill_color[3] = self.fill_color[3] + 0.1 Animation(fill_color=_fill_color, duration=0.2, t="out_quad").start(self) if not self.text: self._anim_lbl_font_size(dp(38), sp(16)) Animation( _line_blank_space_right_point=0, _line_blank_space_left_point=0, duration=0.2, t="out_quad", ).start(self) if self._get_has_error(): self._anim_get_has_error_color(self.error_color) if self.helper_text_mode == "on_error" and ( self.error or self._text_len_error): self._anim_current_error_color(self.error_color) elif (self.helper_text_mode == "on_error" and not self.error and not self._text_len_error): self._anim_current_error_color((0, 0, 0, 0)) elif self.helper_text_mode == "persistent": self._anim_current_error_color(disabled_hint_text_color) elif self.helper_text_mode == "on_focus": self._anim_current_error_color((0, 0, 0, 0)) else: Animation(duration=0.2, color=(1, 1, 1, 1)).start(self._hint_lbl) self._anim_get_has_error_color() if self.helper_text_mode == "on_error": self._anim_current_error_color((0, 0, 0, 0)) elif self.helper_text_mode == "persistent": self._anim_current_error_color(disabled_hint_text_color) elif self.helper_text_mode == "on_focus": self._anim_current_error_color((0, 0, 0, 0)) Animation( _line_width=0, duration=(0.2 if self.line_anim else 0), t="out_quad", ).start(self)
def build(self): Game = Widget() Game.add_widget(HohenGame()) Window.size = int(metrics.dp(1366)), int(metrics.dp(768)) #Window.fullscreen = True return Game
def __init__(self, **kwargs): super(MultiLineListItem, self).__init__(**kwargs) self._num_lines = ceil(len(self.text) / 120.0) self.height = dp(37 + 20 * (self._num_lines - 1)) self.text_size = self.width, None self.__post_init__(kwargs)
def get_normal_height(self): return ((Window.height * 80 / 100) - self._spacer_top - dp(52) - self.ids.container.padding[1] - self.ids.container.padding[-1] - 100)
class MaterialList(ThemeBehaviour, BoxLayout): title = StringProperty('') tile_rows = BoundedNumericProperty(1, min=1, max=3) list_type = OptionProperty('text', options=('text', 'icon_text', 'avatar_text', 'avatar_text_icon')) text_color = ListProperty() text_color_selected = ListProperty() background_color_selected = ListProperty() background_color_disabled = ListProperty() divider_color = ListProperty([1, 1, 1, 0]) selection_mode = OptionProperty('single', options=('none', 'single', 'multiple')) allow_empty_selection = BooleanProperty(False) selection_limit = NumericProperty(-1) list_data = ListProperty() selection = ListProperty([]) _tile_height = NumericProperty(dp(48)) _list_view = ObjectProperty() def __init__(self, **kwargs): super(MaterialList, self).__init__(**kwargs) self.register_event_type('on_selection') self.text_color = self._theme_cls.primary_text_color() self.text_color_selected = self._theme_cls.accent_color self.background_color_selected = get_rgba_color( [self._theme_cls.theme_style, 'FlatButtonDown']) self.background_color_disabled = self._theme_cls.disabled_bg_color() self.bind(tile_rows=self._set_tile_height, list_data=self._get_adapter) def on_selection(self, *args): pass def _get_adapter(self, *args): if self.list_type == 'text': converter = lambda row_index, rec: { 'text': rec['text'], 'secondary_text': rec['secondary_text'] if 'secondary_text' in rec else '', 'tile_rows': self.tile_rows, 'text_color_selected': self.text_color_selected, 'background_color_selected': self.background_color_selected, 'background_color_disabled': self.background_color_disabled, 'divider_color': self.divider_color, 'size_hint_y': None, 'height': self._tile_height, 'callback': rec['callback'] if 'callback' in rec else None } adapter = ListAdapter(data=self.list_data, args_converter=converter, cls=TextTile) adapter.bind(selection=self.setter('selection')) self._list_view.adapter = adapter self._list_view.adapter.selection_mode = self.selection_mode self._list_view.adapter.selection_limit = self.selection_limit self._list_view.adapter.allow_empty_selection = self.allow_empty_selection if self.list_type == 'icon_text': converter = lambda row_index, rec: { 'icon': rec['icon'], 'text': rec['text'], 'secondary_text': rec['secondary_text'] if 'secondary_text' in rec else '', 'tile_rows': self.tile_rows, 'text_color_selected': self.text_color_selected, 'background_color_selected': self.background_color_selected, 'background_color_disabled': self.background_color_disabled, 'divider_color': self.divider_color, 'size_hint_y': None, 'height': self._tile_height, 'callback': rec['callback'] if 'callback' in rec else None } adapter = ListAdapter(data=self.list_data, args_converter=converter, cls=IconTextTile) adapter.bind(selection=self.setter('selection')) self._list_view.adapter = adapter self._list_view.adapter.selection_mode = self.selection_mode self._list_view.adapter.selection_limit = self.selection_limit self._list_view.adapter.allow_empty_selection = self.allow_empty_selection if self.list_type == 'avatar_text': converter = lambda row_index, rec: { 'avatar': rec['avatar'], 'text': rec['text'], 'secondary_text': rec['secondary_text'] if 'secondary_text' in rec else '', 'tile_rows': self.tile_rows, 'text_color_selected': self.text_color_selected, 'background_color_selected': self.background_color_selected, 'background_color_disabled': self.background_color_disabled, 'divider_color': self.divider_color, 'size_hint_y': None, 'height': self._tile_height, 'callback': rec['callback'] if 'callback' in rec else None } adapter = ListAdapter(data=self.list_data, args_converter=converter, cls=AvatarTextTile) adapter.bind(selection=self.setter('selection')) self._list_view.adapter = adapter self._list_view.adapter.selection_mode = self.selection_mode self._list_view.adapter.selection_limit = self.selection_limit self._list_view.adapter.allow_empty_selection = self.allow_empty_selection def _set_tile_height(self, *args): if self.tile_rows == 1: if self.tile_type == 'text' or self.tile_type == 'icon_text': self._tile_height = dp(48) else: self._tile_height = dp(56) elif self.tile_rows == 2: self._tile_height = dp(72) else: self._tile_height = dp(88)
def update_height(self, *_): self._spacer_top = self.content_cls.height + dp(24)
def _get_horizontal_margins(self): if DEVICE_TYPE == "mobile": return dp(16) else: return dp(24)
class ThreeLineAvatarIconListItem(ThreeLineAvatarListItem): # dp(40) = dp(16) + dp(24): _txt_right_pad = NumericProperty(dp(40) + m_res.HORIZ_MARGINS)
def set_content(self, instance_content_dialog): def _events_callback(result_press): self.dismiss() if result_press: self.events_callback(result_press, self) if self.device_ios: # create buttons for iOS self.background = self._background if instance_content_dialog.__class__ is ContentInputDialog: self.text_field = TextInput( size_hint=(1, None), multiline=False, height=dp(33), cursor_color=self.theme_cls.primary_color, hint_text=instance_content_dialog.hint_text, background_normal='{}ios_entr_ti.png'.format(images_path), background_active='{}ios_entr_ti.png'.format(images_path)) instance_content_dialog.ids.box_input.height = dp(33) instance_content_dialog.ids.box_input.add_widget( self.text_field) if self.text_button_cancel != '': anchor = 'left' else: anchor = 'center' box_button_ok = AnchorLayout(anchor_x=anchor) box_button_ok.add_widget( MDTextButton( text=self.text_button_ok, font_size='18sp', on_release=lambda x: _events_callback( self.text_button_ok))) instance_content_dialog.ids.box_buttons.add_widget(box_button_ok) if self.text_button_cancel != '': box_button_ok.anchor_x = 'left' box_button_cancel = AnchorLayout(anchor_x='right') box_button_cancel.add_widget( MDTextButton( text=self.text_button_cancel, font_size='18sp', on_release=lambda x: _events_callback( self.text_button_cancel))) instance_content_dialog.ids.box_buttons.add_widget( box_button_cancel) else: # create buttons for Android if instance_content_dialog.__class__ is ContentInputDialog: self.text_field = MDTextField( size_hint=(1, None), height=dp(48), hint_text=instance_content_dialog.hint_text) instance_content_dialog.ids.box_input.height = dp(48) instance_content_dialog.ids.box_input.add_widget( self.text_field) instance_content_dialog.ids.box_buttons.remove_widget( instance_content_dialog.ids.sep) box_buttons = AnchorLayout( anchor_x='right', size_hint_y=None, height=dp(30)) box = BoxLayout(size_hint_x=None, spacing=dp(5)) box.bind(minimum_width=box.setter('width')) button_ok = MDRaisedButton( text=self.text_button_ok, on_release=lambda x: _events_callback(self.text_button_ok)) box.add_widget(button_ok) if self.text_button_cancel != '': button_cancel = MDFlatButton( text=self.text_button_cancel, theme_text_color='Custom', text_color=self.theme_cls.primary_color, on_release=lambda x: _events_callback( self.text_button_cancel)) box.add_widget(button_cancel) box_buttons.add_widget(box) instance_content_dialog.ids.box_buttons.add_widget(box_buttons) instance_content_dialog.ids.box_buttons.height = button_ok.height instance_content_dialog.remove_widget( instance_content_dialog.ids.sep)
class ThreeLineRightIconListItem(ContainerSupport, ThreeLineListItem): # dp(40) = dp(16) + dp(24): _txt_right_pad = NumericProperty(dp(40) + m_res.HORIZ_MARGINS)
def _update_tabs(self, *l): self_content = self.content if not self_content: return # cache variables for faster access tab_pos = self.tab_pos tab_layout = self._tab_layout tab_layout.clear_widgets() scrl_v = ScrollView(size_hint=(None, 1)) tabs = self._tab_strip parent = tabs.parent if parent: parent.remove_widget(tabs) scrl_v.add_widget(tabs) scrl_v.pos = (0, 0) self_update_scrollview = self._update_scrollview # update scrlv width when tab width changes depends on tab_pos if self._partial_update_scrollview is not None: tabs.unbind(width=self._partial_update_scrollview) self._partial_update_scrollview = partial(self_update_scrollview, scrl_v) tabs.bind(width=self._partial_update_scrollview) # remove all widgets from the tab_strip self.clear_widgets(do_super=True) tab_height = self.tab_height widget_list = [] tab_list = [] pos_letter = tab_pos[0] if pos_letter == 'b' or pos_letter == 't': # bottom or top positions # one col containing the tab_strip and the content self.cols = 1 self.rows = 2 # tab_layout contains the scrollview containing tabs and two blank # dummy widgets for spacing tab_layout.rows = 1 tab_layout.cols = 3 tab_layout.size_hint = (1, None) tab_layout.height = (tab_height + tab_layout.padding[1] + tab_layout.padding[3] + dp(2)) self_update_scrollview(scrl_v) if pos_letter == 'b': # bottom if tab_pos == 'bottom_mid': tab_list = (Widget(), scrl_v, Widget()) widget_list = (self_content, tab_layout) else: if tab_pos == 'bottom_left': tab_list = (scrl_v, Widget(), Widget()) elif tab_pos == 'bottom_right': # add two dummy widgets tab_list = (Widget(), Widget(), scrl_v) widget_list = (self_content, tab_layout) else: # top if tab_pos == 'top_mid': tab_list = (Widget(), scrl_v, Widget()) elif tab_pos == 'top_left': tab_list = (scrl_v, Widget(), Widget()) elif tab_pos == 'top_right': tab_list = (Widget(), Widget(), scrl_v) widget_list = (tab_layout, self_content) elif pos_letter == 'l' or pos_letter == 'r': # left ot right positions # one row containing the tab_strip and the content self.cols = 2 self.rows = 1 # tab_layout contains two blank dummy widgets for spacing # "vertically" and the scatter containing scrollview # containing tabs tab_layout.rows = 3 tab_layout.cols = 1 tab_layout.size_hint = (None, 1) tab_layout.width = tab_height scrl_v.height = tab_height self_update_scrollview(scrl_v) # rotate the scatter for vertical positions rotation = 90 if tab_pos[0] == 'l' else -90 sctr = Scatter(do_translation=False, rotation=rotation, do_rotation=False, do_scale=False, size_hint=(None, None), auto_bring_to_front=False, size=scrl_v.size) sctr.add_widget(scrl_v) lentab_pos = len(tab_pos) # Update scatter's top when it's pos changes. # Needed for repositioning scatter to the correct place after its # added to the parent. Use clock_schedule_once to ensure top is # calculated after the parent's pos on canvas has been calculated. # This is needed for when tab_pos changes to correctly position # scatter. Without clock.schedule_once the positions would look # fine but touch won't translate to the correct position if tab_pos[lentab_pos - 4:] == '_top': # on positions 'left_top' and 'right_top' sctr.bind(pos=partial(self._update_top, sctr, 'top', None)) tab_list = (sctr, ) elif tab_pos[lentab_pos - 4:] == '_mid': # calculate top of scatter sctr.bind( pos=partial(self._update_top, sctr, 'mid', scrl_v.width)) tab_list = (Widget(), sctr, Widget()) elif tab_pos[lentab_pos - 7:] == '_bottom': tab_list = (Widget(), Widget(), sctr) if pos_letter == 'l': widget_list = (tab_layout, self_content) else: widget_list = (self_content, tab_layout) # add widgets to tab_layout add = tab_layout.add_widget for widg in tab_list: add(widg) # add widgets to self add = self.add_widget for widg in widget_list: add(widg)
def back_to_previous_screen(self, *args): if self.menu_open: self.menu_open = False self.hide_menu_list_animation() App.get_running_app().main_widget.ids.scr_mngr.current = "previous" App.get_running_app().main_widget.ids.toolbar.height = dp(56)
def set_shadow(self, *args): self.action_button._hard_shadow_size = (dp(112), dp(112)) self.action_button._soft_shadow_size = (dp(112), dp(112))
class MDTapTargetView(ThemableBehavior, EventDispatcher): """Rough try to mimic the working of Android's TapTargetView. :Events: :attr:`on_open` Called at the time of the start of the widget opening animation. :attr:`on_close` Called at the time of the start of the widget closed animation. """ widget = ObjectProperty() """ Widget to add ``TapTargetView`` upon. :attr:`widget` is an :class:`~kivy.properties.ObjectProperty` and defaults to `None`. """ outer_radius = NumericProperty(dp(200)) """ Radius for outer circle. .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/tap-target-view-widget-outer-radius.png :align: center :attr:`outer_radius` is an :class:`~kivy.properties.NumericProperty` and defaults to `dp(200)`. """ outer_circle_color = ListProperty() """ Color for the outer circle in ``rgb`` format. .. code-block:: python self.tap_target_view = MDTapTargetView( ... outer_circle_color=(1, 0, 0) ) .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/tap-target-view-widget-outer-circle-color.png :align: center :attr:`outer_circle_color` is an :class:`~kivy.properties.ListProperty` and defaults to ``theme_cls.primary_color``. """ outer_circle_alpha = NumericProperty(0.96) """ Alpha value for outer circle. :attr:`outer_circle_alpha` is an :class:`~kivy.properties.NumericProperty` and defaults to `0.96`. """ target_radius = NumericProperty(dp(45)) """ Radius for target circle. .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/tap-target-view-widget-target-radius.png :align: center :attr:`target_radius` is an :class:`~kivy.properties.NumericProperty` and defaults to `dp(45)`. """ target_circle_color = ListProperty([1, 1, 1]) """ Color for target circle in ``rgb`` format. .. code-block:: python self.tap_target_view = MDTapTargetView( ... target_circle_color=(1, 0, 0) ) .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/tap-target-view-widget-target-circle-color.png :align: center :attr:`target_circle_color` is an :class:`~kivy.properties.ListProperty` and defaults to `[1, 1, 1]`. """ title_text = StringProperty() """ Title to be shown on the view. :attr:`title_text` is an :class:`~kivy.properties.StringProperty` and defaults to `''`. """ title_text_size = NumericProperty(dp(25)) """ Text size for title. :attr:`title_text_size` is an :class:`~kivy.properties.NumericProperty` and defaults to `dp(25)`. """ title_text_color = ListProperty([1, 1, 1, 1]) """ Text color for title. :attr:`title_text_color` is an :class:`~kivy.properties.ListProperty` and defaults to `[1, 1, 1, 1]`. """ title_text_bold = BooleanProperty(True) """ Whether title should be bold. :attr:`title_text_bold` is an :class:`~kivy.properties.BooleanProperty` and defaults to `True`. """ description_text = StringProperty() """ Description to be shown below the title (keep it short). :attr:`description_text` is an :class:`~kivy.properties.StringProperty` and defaults to `''`. """ description_text_size = NumericProperty(dp(20)) """ Text size for description text. :attr:`description_text_size` is an :class:`~kivy.properties.NumericProperty` and defaults to `dp(20)`. """ description_text_color = ListProperty([0.9, 0.9, 0.9, 1]) """ Text size for description text. :attr:`description_text_color` is an :class:`~kivy.properties.ListProperty` and defaults to `[0.9, 0.9, 0.9, 1]`. """ description_text_bold = BooleanProperty(False) """ Whether description should be bold. :attr:`description_text_bold` is an :class:`~kivy.properties.BooleanProperty` and defaults to `False`. """ draw_shadow = BooleanProperty(False) """ Whether to show shadow. :attr:`draw_shadow` is an :class:`~kivy.properties.BooleanProperty` and defaults to `False`. """ cancelable = BooleanProperty(False) """ Whether clicking outside the outer circle dismisses the view. :attr:`cancelable` is an :class:`~kivy.properties.BooleanProperty` and defaults to `False`. """ widget_position = OptionProperty( "left", options=[ "left", "right", "top", "bottom", "left_top", "right_top", "left_bottom", "right_bottom", "center", ], ) """ Sets the position of the widget on the :attr:`~outer_circle`. Available options are `'left`', `'right`', `'top`', `'bottom`', `'left_top`', `'right_top`', `'left_bottom`', `'right_bottom`', `'center`'. :attr:`widget_position` is an :class:`~kivy.properties.OptionProperty` and defaults to `'left'`. """ title_position = OptionProperty( "auto", options=[ "auto", "left", "right", "top", "bottom", "left_top", "right_top", "left_bottom", "right_bottom", ], ) """ Sets the position of :attr`~title_text` on the outer circle. Only works if :attr`~widget_position` is set to `'center'`. In all other cases, it calculates the :attr`~title_position` itself. Must be set to other than `'auto`' when :attr`~widget_position` is set to `'center`'. Available options are `'auto'`, `'left`', `'right`', `'top`', `'bottom`', `'left_top`', `'right_top`', `'left_bottom`', `'right_bottom`', `'center`'. :attr:`title_position` is an :class:`~kivy.properties.OptionProperty` and defaults to `'auto'`. """ stop_on_outer_touch = BooleanProperty(False) """ Whether clicking on outer circle stops the animation. :attr:`stop_on_outer_touch` is an :class:`~kivy.properties.BooleanProperty` and defaults to `False`. """ stop_on_target_touch = BooleanProperty(True) """ Whether clicking on target circle should stop the animation. :attr:`stop_on_target_touch` is an :class:`~kivy.properties.BooleanProperty` and defaults to `True`. """ state = OptionProperty("close", options=["close", "open"]) """ State of :class:`~MDTapTargetView`. :attr:`state` is an :class:`~kivy.properties.OptionProperty` and defaults to `'close'`. """ _outer_radius = NumericProperty(0) _target_radius = NumericProperty(0) def __init__(self, **kwargs): self.ripple_max_dist = dp(90) self.on_outer_radius(self, self.outer_radius) self.on_target_radius(self, self.target_radius) self.core_title_text = Label( markup=True, size_hint=(None, None), bold=self.title_text_bold ) self.core_title_text.bind(texture_size=self.core_title_text.setter("size")) self.core_description_text = Label(markup=True, size_hint=(None, None)) self.core_description_text.bind( texture_size=self.core_description_text.setter("size") ) super().__init__(**kwargs) self.register_event_type("on_outer_touch") self.register_event_type("on_target_touch") self.register_event_type("on_outside_click") self.register_event_type("on_open") self.register_event_type("on_close") if not self.outer_circle_color: self.outer_circle_color = self.theme_cls.primary_color[:-1] def _initialize(self): setattr(self.widget, "_outer_radius", 0) setattr(self.widget, "_target_radius", 0) setattr(self.widget, "target_ripple_radius", 0) setattr(self.widget, "target_ripple_alpha", 0) # Bind some function on widget event when this function is called # instead of when the class itself is initialized to prevent all # widgets of all instances to get bind at once and start messing up. self.widget.bind(on_touch_down=self._some_func) def _draw_canvas(self): _pos = self._ttv_pos() self.widget.canvas.before.clear() with self.widget.canvas.before: # Outer circle. Color( *self.outer_circle_color, self.outer_circle_alpha, group="ttv_group", ) _rad1 = self.widget._outer_radius Ellipse(size=(_rad1, _rad1), pos=_pos[0], group="ttv_group") # Title text. Color(*self.title_text_color, group="ttv_group") Rectangle( size=self.core_title_text.texture.size, texture=self.core_title_text.texture, pos=_pos[1], group="ttv_group", ) # Description text. Color(*self.description_text_color, group="ttv_group") Rectangle( size=self.core_description_text.texture.size, texture=self.core_description_text.texture, pos=( _pos[1][0], _pos[1][1] - self.core_description_text.size[1] - 5, ), group="ttv_group", ) # Target circle. Color(*self.target_circle_color, group="ttv_group") _rad2 = self.widget._target_radius Ellipse( size=(_rad2, _rad2), pos=( self.widget.x - (_rad2 / 2 - self.widget.size[0] / 2), self.widget.y - (_rad2 / 2 - self.widget.size[0] / 2), ), group="ttv_group", ) # Target ripple. Color( *self.target_circle_color, self.widget.target_ripple_alpha, group="ttv_group", ) _rad3 = self.widget.target_ripple_radius Ellipse( size=(_rad3, _rad3), pos=( self.widget.x - (_rad3 / 2 - self.widget.size[0] / 2), self.widget.y - (_rad3 / 2 - self.widget.size[0] / 2), ), group="ttv_group", ) def stop(self, *args): """Starts widget close animation.""" # It needs a better implementation. self.anim_ripple.unbind(on_complete=self._repeat_ripple) self.core_title_text.opacity = 0 self.core_description_text.opacity = 0 anim = Animation( d=0.15, t="in_cubic", **dict( zip( ["_outer_radius", "_target_radius", "target_ripple_radius"], [0, 0, 0], ) ), ) anim.bind(on_complete=self._after_stop) anim.start(self.widget) def _after_stop(self, *args): self.widget.canvas.before.remove_group("ttv_group") args[0].stop_all(self.widget) elev = getattr(self.widget, "elevation", None) if elev: self._fix_elev() self.dispatch("on_close") # Don't forget to unbind the function or it'll mess # up with other next bindings. self.widget.unbind(on_touch_down=self._some_func) self.state = "close" def _fix_elev(self): with self.widget.canvas.before: Color(a=self.widget._soft_shadow_a) Rectangle( texture=self.widget._soft_shadow_texture, size=self.widget._soft_shadow_size, pos=self.widget._soft_shadow_pos, ) Color(a=self.widget._hard_shadow_a) Rectangle( texture=self.widget._hard_shadow_texture, size=self.widget._hard_shadow_size, pos=self.widget._hard_shadow_pos, ) Color(a=1) def start(self, *args): """Starts widget opening animation.""" self._initialize() self._animate_outer() self.state = "open" self.core_title_text.opacity = 1 self.core_description_text.opacity = 1 self.dispatch("on_open") def _animate_outer(self): anim = Animation( d=0.2, t="out_cubic", **dict( zip( ["_outer_radius", "_target_radius"], [self._outer_radius, self._target_radius], ) ), ) anim.cancel_all(self.widget) anim.bind(on_progress=lambda x, y, z: self._draw_canvas()) anim.bind(on_complete=self._animate_ripple) anim.start(self.widget) setattr(self.widget, "target_ripple_radius", self._target_radius) setattr(self.widget, "target_ripple_alpha", 1) def _animate_ripple(self, *args): self.anim_ripple = Animation( d=1, t="in_cubic", target_ripple_radius=self._target_radius + self.ripple_max_dist, target_ripple_alpha=0, ) self.anim_ripple.stop_all(self.widget) self.anim_ripple.bind(on_progress=lambda x, y, z: self._draw_canvas()) self.anim_ripple.bind(on_complete=self._repeat_ripple) self.anim_ripple.start(self.widget) def _repeat_ripple(self, *args): setattr(self.widget, "target_ripple_radius", self._target_radius) setattr(self.widget, "target_ripple_alpha", 1) self._animate_ripple() def on_open(self, *args): """Called at the time of the start of the widget opening animation.""" def on_close(self, *args): """Called at the time of the start of the widget closed animation.""" def on_draw_shadow(self, instance, value): Logger.warning( "The shadow adding method will be implemented in future versions" ) def on_description_text(self, instance, value): self.core_description_text.text = value def on_description_text_size(self, instance, value): self.core_description_text.font_size = value def on_description_text_bold(self, instance, value): self.core_description_text.bold = value def on_title_text(self, instance, value): self.core_title_text.text = value def on_title_text_size(self, instance, value): self.core_title_text.font_size = value def on_title_text_bold(self, instance, value): self.core_title_text.bold = value def on_outer_radius(self, instance, value): self._outer_radius = self.outer_radius * 2 def on_target_radius(self, instance, value): self._target_radius = self.target_radius * 2 def on_target_touch(self): if self.stop_on_target_touch: self.stop() def on_outer_touch(self): if self.stop_on_outer_touch: self.stop() def on_outside_click(self): if self.cancelable: self.stop() def _some_func(self, wid, touch): """ This function decides which one to dispatch based on the touch position. """ if self._check_pos_target(touch.pos): self.dispatch("on_target_touch") elif self._check_pos_outer(touch.pos): self.dispatch("on_outer_touch") else: self.dispatch("on_outside_click") def _check_pos_outer(self, pos): """ Checks if a given `pos` coordinate is within the :attr:`~outer_radius`. """ cx = self.circ_pos[0] + self._outer_radius / 2 cy = self.circ_pos[1] + self._outer_radius / 2 r = self._outer_radius / 2 h, k = pos lhs = (cx - h) ** 2 + (cy - k) ** 2 rhs = r ** 2 if lhs <= rhs: return True return False def _check_pos_target(self, pos): """ Checks if a given `pos` coordinate is within the :attr:`~target_radius`. """ cx = self.widget.pos[0] + self.widget.width / 2 cy = self.widget.pos[1] + self.widget.height / 2 r = self._target_radius / 2 h, k = pos lhs = (cx - h) ** 2 + (cy - k) ** 2 rhs = r ** 2 if lhs <= rhs: return True return False def _ttv_pos(self): """ Calculates the `pos` value for outer circle and text based on the position provided. :returns: A tuple containing pos for the circle and text. """ _rad1 = self.widget._outer_radius _center_x = self.widget.x - (_rad1 / 2 - self.widget.size[0] / 2) _center_y = self.widget.y - (_rad1 / 2 - self.widget.size[0] / 2) if self.widget_position == "left": circ_pos = (_center_x + _rad1 / 3, _center_y) title_pos = (_center_x + _rad1 / 1.4, _center_y + _rad1 / 1.4) elif self.widget_position == "right": circ_pos = (_center_x - _rad1 / 3, _center_y) title_pos = (_center_x - _rad1 / 10, _center_y + _rad1 / 1.4) elif self.widget_position == "top": circ_pos = (_center_x, _center_y - _rad1 / 3) title_pos = (_center_x + _rad1 / 4, _center_y + _rad1 / 4) elif self.widget_position == "bottom": circ_pos = (_center_x, _center_y + _rad1 / 3) title_pos = (_center_x + _rad1 / 4, _center_y + _rad1 / 1.2) # Corner ones need to be at a little smaller distance # than edge ones that's why _rad1/4. elif self.widget_position == "left_top": circ_pos = (_center_x + _rad1 / 4, _center_y - _rad1 / 4) title_pos = (_center_x + _rad1 / 2, _center_y + _rad1 / 4) elif self.widget_position == "right_top": circ_pos = (_center_x - _rad1 / 4, _center_y - _rad1 / 4) title_pos = (_center_x - _rad1 / 10, _center_y + _rad1 / 4) elif self.widget_position == "left_bottom": circ_pos = (_center_x + _rad1 / 4, _center_y + _rad1 / 4) title_pos = (_center_x + _rad1 / 2, _center_y + _rad1 / 1.2) elif self.widget_position == "right_bottom": circ_pos = (_center_x - _rad1 / 4, _center_y + _rad1 / 4) title_pos = (_center_x, _center_y + _rad1 / 1.2) else: # Center. circ_pos = (_center_x, _center_y) if self.title_position == "auto": raise ValueError( "widget_position='center' requires title_position to be set." ) elif self.title_position == "left": title_pos = (_center_x + _rad1 / 10, _center_y + _rad1 / 2) elif self.title_position == "right": title_pos = (_center_x + _rad1 / 1.6, _center_y + _rad1 / 2) elif self.title_position == "top": title_pos = (_center_x + _rad1 / 2.5, _center_y + _rad1 / 1.3) elif self.title_position == "bottom": title_pos = (_center_x + _rad1 / 2.5, _center_y + _rad1 / 4) elif self.title_position == "left_top": title_pos = (_center_x + _rad1 / 8, _center_y + _rad1 / 1.4) elif self.title_position == "right_top": title_pos = (_center_x + _rad1 / 2, _center_y + _rad1 / 1.3) elif self.title_position == "left_bottom": title_pos = (_center_x + _rad1 / 8, _center_y + _rad1 / 4) elif self.title_position == "right_bottom": title_pos = (_center_x + _rad1 / 2, _center_y + _rad1 / 3.5) else: raise ValueError( f"'{self.title_position}'" f"is not a valid value for title_position" ) self.circ_pos = circ_pos return circ_pos, title_pos