class FileBrowser(BoxLayout): def __init__(self, name): super().__init__() self.orientation = "vertical" self.size_hint = (1, 1) self.scroll_body = ScrollView() self.add_widget(self.scroll_body) self.body = StackLayout(orientation="lr-tb", size_hint_y=None) self.scroll_body.add_widget(self.body) ##Settings## self.body.bind(minimum_height=self.body.setter('height')) self.draw() self.bind(pos=self.update_rectangles, size=self.update_rectangles) self.populate("placeholderforsource") def draw(self): self.canvas.before.clear() with self.canvas.before: Color(0.8, 1, 1, 1) self.rectangle = Rectangle(pos=self.pos, size=self.size) def update_rectangles(self, *args): self.rectangle.pos = self.pos self.rectangle.size = self.size def populate(self, source): # a means of setting source for i in range(0, 10): self.body.add_widget(SpecialImage("placeholderfordirentry"))
def _create_popup(self, instance): content = GridLayout(cols=1, spacing='10dp') scrollview = ScrollView(do_scroll_x=False, size_hint=(1, 0.85)) scrollcontent = StackLayout(size_hint=(1, None), spacing='5dp') scrollcontent.bind(minimum_height=scrollcontent.setter('height')) self.popup = popup = Popup(content=content, title=self.title, size_hint=(0.5, 0.9), auto_dismiss=False) popup.open() content.add_widget(Widget(size_hint_y=None, height=dp(2))) 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, height=dp(50), size_hint=(1, None)) btn.bind(on_release=self._set_option) scrollcontent.add_widget(btn) scrollview.add_widget(scrollcontent) content.add_widget(scrollview) btn = Button(text='Cancel', height=dp(50), size_hint=(1, None)) btn.bind(on_release=popup.dismiss) content.add_widget(btn)
def fetchData(self, tab): tab.clear_widgets() cur.execute("SELECT id,name,due,amount FROM RECORDS") rows = cur.fetchall() rows.insert(0, ["Inv No", "Name", "Due Date", "Amount"]) temp = ScrollView() root1 = StackLayout(size_hint_y=None, spacing=0, orientation="lr-tb") root1.bind(minimum_height=root1.setter('height')) i = 0 for row in rows: for col in row: if i == 0: root1.add_widget( MDLabel(text=str(col), height=30, size_hint_x=1 / 4, size_hint_y=None, halign="center", font_style="Body1")) else: root1.add_widget( MDLabel(text=str(col), height=30, size_hint_x=1 / 4, size_hint_y=None, halign="center", font_style="Body2")) if i == 0: root1.add_widget(MDSeparator()) i = i + 1 temp.add_widget(root1) tab.add_widget(temp)
def display(self): scrolllist = [] displist = [] searchBar = TextInput(size_hint=(.75, .1), multiline=False) searchBar.bind( on_text_validate=lambda x: self.processQuery(searchBar.text)) displist.append(searchBar) back = ColorButton("Go", (.125, .1), darkblue) back.bind(on_release=lambda x: self.processQuery(searchBar.text)) displist.append(back) back = ColorButton("Back", (.125, .1), darkblue) back.bind(on_release=lambda x: self.switcher.switch("login")) displist.append(back) teamList = ScrollView(size_hint=(1, None), size=(Window.width, Window.height - searchBar.height)) displist.append(teamList) teamListLayout = StackLayout(size_hint_y=None) teamListLayout.bind(minimum_height=teamListLayout.setter('height')) teamList.add_widget(teamListLayout) database = sqlite3.connect("scoutingdatabase.db") cursor = database.cursor() cursor.execute("SELECT * FROM pitscoutingdata " + self.query) for teamData in cursor.fetchall(): teamNumber = teamData[0] button = ColorButton(str(teamNumber), (.875, None), fairBlue, height=40) button.bind(on_release=self.pitScouterMainSwitch) scrolllist.append(button) hasBeenScouted = "scouted" if teamData[1] else "NOT SCOUTED" labelBackground = green if teamData[1] else red label = ColorLabel(hasBeenScouted, (.125, None), labelBackground, height=40) scrolllist.append(label) database.close() addTeam = ColorButton("add team", (.5, None), darkblue, height=40) addTeam.bind(on_release=lambda x: self.addPitRobot(addText.text)) scrolllist.append(addTeam) addText = TextInput(text=str(""), multiline=False, size_hint=(.5, None), height=40) addText.bind(on_validate_text=lambda x: self.addPitRobot(addText.text)) scrolllist.append(addText) for widget in scrolllist: teamListLayout.add_widget(widget) self.clear_widgets() for widget in displist: self.add_widget(widget)
class LogBox(ScrollView): _current_selection = 0 def __init__(self, root): super(LogBox, self).__init__() self.root = root self.size_hint = (1, None) self.height = 150 self.stack = StackLayout() self.stack.orientation = 'lr-tb' self.stack.size_hint = (1, None) self.stack.bind(minimum_height=self.stack.setter('height')) self.add_widget(self.stack) def add(self, note): self.stack.add_widget(LogEntry(note)) def get_entry(self, at): if at == 0: return None if at > len(self.stack.children): return None return self.stack.children[len(self.stack.children)-at] def get_current_entry(self): return self.get_entry(self.current_selection) @property def current_selection(self): return self._current_selection @current_selection.setter def current_selection(self, value): for child in self.stack.children: child.color = [1,1,1,1] if value > len(self.stack.children): self._current_selection = 0 return self._current_selection = value self.stack.children[len(self.stack.children)-value].color = [1,0,0,1] # We send a KEY ON signal for each note # only if we are on play mode. # Reset done status for each note. if self.root.app.playing: for note in self.get_current_entry().notes: note['done'] = False arduino.send(str.format("+{0}", note['note']))
def createStack(self): """Works out how to display the league matches. Layout depends on the number of matches found. """ matches = self.leagueobject.LeagueMatches x = len(matches) # Single column, no scrolling if x <= 10: self.spacer = True w = 1 scroll = False self.h = 42 * x # Dual columns, no scrolling elif x <= 20: self.spacer = False w = 0.5 scroll = False self.h = round(x/2.0) * 42 # Dual columns, scrolling else: self.spacer = False w = 0.5 scroll = True self.h = round(x/2.0) * 42 # Create a stack layout stack = StackLayout(orientation="tb-lr", size_hint_y=None, height=self.h) stack.bind(minimum_height=stack.setter('height')) # Add the league matches to it. for l in matches: lg = LeagueGame(match=l, size_hint=(w, None)) stack.add_widget(lg) # Create a scroll view scroll = ScrollView(size_hint=(1, 1)) scroll.add_widget(stack) return scroll
class LivikitLines(ScrollView): def __init__(self, **kwargs): super(LivikitLines, self).__init__(**kwargs) self.do_scroll_y = True self.layout = StackLayout(orientation='lr-tb', size_hint_y=None) self.layout.bind(minimum_height=self.layout.setter('height')) self.add_widget(self.layout) self.add_info('Time', 'Text') def add_info(self, text1, text2): line = BoxLayout(size_hint_y=None, height=35) line.add_widget(Label(text=text1, size_hint_x=None, width=210)) line.add_widget(Label(text=text2)) self.layout.add_widget(line) def add_item(self, begin, end, text): line = BoxLayout(size_hint_y=None, height=63) time_part = BoxLayout(orientation='vertical') time_part.size_hint_x = None time_part.width = 210 time_part.add_widget(self.new_label_time('begin', begin)) time_part.add_widget(self.new_label_time(' end', end)) line.add_widget(time_part) line.add_widget(TextInput(text=text, font_name=FONT_NAME)) self.layout.add_widget(line) def new_label_time(self, label, text): pair = BoxLayout() pair.add_widget(Label(text=label, size_hint_x=None, width=49)) pair.add_widget(TextInput(text=text, multiline=False, halign='center')) return pair
class MP3k(Widget): playlist_width = NumericProperty() def __init__(self, **kwargs): Globals.CONFIG = App.get_running_app().config Globals.TESTING = Globals.CONFIG.get('Development', 'test_mode') self.playlist_width = int( Globals.CONFIG.get('Playlist', 'playlist_width')) Globals.API = GoogleMusicApi() self.login_failed_popup = None self.google_music_api_login() self.formatter = Formatter() self.player = Player() self.player.set_streaming_quality( Globals.CONFIG.get('Google Play Music', 'quality').split(':')[0]) self.playlist = Playlist() self.librarymanager = LibraryManager() # self.librarymanager.load_library() self.history = History() self.playlist.queue = self.history.playlist_history self.updating_progress = False self.playlist_hidden = False super().__init__(**kwargs) self.player.bind(playing=self.update_play_button_state) self.player.bind(progress_percent=self.update_progress_slider) # Add search result views # Songs self.songlist = SongViewer() # Stations # self.stationlist = StationViewer() self.stationscroll = ScrollView(size_hint=(1, 1)) self.stationscroll.do_scroll_x = False self.stationlist = StackLayout(size_hint_y=None, spacing=10) self.stationlist.bind(minimum_height=self.stationlist.setter('height')) self.stationscroll.add_widget(self.stationlist) # Albums self.albumlist = AlbumViewer() # Create and init screen manager self.sm = ScreenManager() self.init_screens() # Listen for Keyboard events self._keyboard = Window.request_keyboard(None, self, 'text') self._keyboard.bind(on_key_down=self._pressed_key) self.searchbar.focus = True def google_music_api_login(self): if Globals.API.login( Globals.CONFIG.get('Google Play Music', 'login'), Globals.CONFIG.get('Google Play Music', 'password'), Globals.CONFIG.get('Google Play Music', 'device_id')): Logger.debug('Google Music: Login successful') if self.login_failed_popup: self.login_failed_popup.dismiss() self.login_failed_popup = None else: Logger.warning("Google Music: Login Failed") if not self.login_failed_popup: popup = Popup(title='Google Play Music™ login', content=LoginCredentials(), auto_dismiss=False, size_hint=(1, 1)) self.login_failed_popup = popup if Globals.STARTED: # login failed after configuration change self.login_failed_popup.open( ) # open popup because MP3k is completely rendered App.get_running_app().close_settings() else: # login failed on start pass # wait with popup until MP3k is completely rendered (MP3kApp opens the popup in on_start()) def try_login_step_1(self, instance, google_login, google_password): # Credentials login without device ID if Globals.API.login(google_login, google_password, ''): # login successful Globals.CONFIG.set('Google Play Music', 'login', google_login) Globals.CONFIG.set('Google Play Music', 'password', google_password) Globals.CONFIG.write() self.show_device_login() else: instance.login_failed_label.color = (1, 0, 0, 1) def try_login_step_2(self, button_container): # look for selected device for button in button_container.children: if button.state == 'down': # got it Globals.CONFIG.set('Google Play Music', 'device_id', button.device_id) Globals.CONFIG.write() # set device id in config if Globals.API.relogin( Globals.CONFIG.get( 'Google Play Music', 'login'), # re-login with valid device_id Globals.CONFIG.get('Google Play Music', 'password'), Globals.CONFIG.get('Google Play Music', 'device_id')): self.login_failed_popup.dismiss() break else: Logger.error('LOGIN: You have to select a device!') def show_device_login(self): self.login_failed_popup.dismiss() self.login_failed_popup = Popup(title='Google Play Music™ login', content=self.build_devices_login(), auto_dismiss=False, size_hint=(1, 1)) self.login_failed_popup.open() @staticmethod def build_devices_login(): devices = Globals.API.get_registered_mobile_devices( ) # get registered mobile devices login_devices = LoginDevices() # add buttons for devices for device in devices: btn = DeviceButton(text='{} (ID: {})'.format( device['name'], device['id']), device_id=device['id'], size_hint_y=None, height=30, group='devices') login_devices.device_button_container.add_widget(btn) return login_devices def init_screens(self): # Create screens screen_songs = Screen(name='Songs', size_hint=(1, 1)) screen_stations = Screen(name='Stations', size_hint=(1, 1)) screen_albums = Screen(name='Albums', size_hint=(1, 1)) # Add content to screens screen_songs.add_widget(self.songlist) # screen_stations.add_widget(self.stationlist) screen_stations.add_widget(self.stationscroll) screen_albums.add_widget(self.albumlist) # Add screens self.sm.add_widget(screen_songs) self.sm.add_widget(screen_stations) self.sm.add_widget(screen_albums) # Add screen manager and playlist self.screenmanagercontainer.add_widget(self.sm) def _pressed_key(self, keyboard, keycode, text, modifiers): if not self.searchbar.focus: if keycode[1] == 'spacebar' or keycode[0] == 1073742085: Logger.debug('Keyboard: Pressed spacebar/play-pause-media-key') self.playbutton_callback() elif keycode[0] == 1073742083: # 'previous track' media key Logger.debug("Keyboard: Pressed 'previous track' media key") self.previousbutton_callback() elif keycode[0] == 1073742082: # 'next track' media key Logger.debug("Keyboard: Pressed 'next track' media key") self.nextbutton_callback() #else: # print(keycode) def update_play_button_state(self, instance, value): if value: self.playbutton.icon = '../res/icons/glyphicons-175-pause_white.png' else: self.playbutton.icon = '../res/icons/glyphicons-174-play_white.png' def update_progress_slider(self, instance, value): self.progress_slider.value = value def update_playlist_position(self, window, width, height): self.playlist_view.pos_hint = {'x': .3, 'y': 90.0 / height} def update_playlist_view(self, instance, value): print('Updating playlist..') print('data_queue before: ' + str(len(self.playlist_view.data_queue))) # self.playlist_view.data_queue = self.playlist.queue # ListView should be updated if we do it like this.. self.playlist_view.children[0].adapter.data.clear( ) # ..but it isn't, so we do this self.playlist_view.children[0].adapter.data.extend( self.playlist.queue) # and then this # self.playlist_view.content.listview.adapter.data = self.playlist.queue # never do this, it replaces the # ObservableList and breaks kivy functionality print('data_queue after: ' + str(len(self.playlist_view.data_queue))) def _update_progress_interval(self, delta_time): if not self.updating_progress: self.updating_progress = True if self.player.current_track and self.player.playback_started and self.player.playing: # time_played_ms = pygame.mixer.music.get_pos() # duration_ms = int(self.musicmanager.current_track['duration_ms']) # progress = time_played_ms / (duration_ms / 100) progress_percent = self.player.send_cmd_to_mplayer( 'get_percent_pos', 'ANS_PERCENT_POSITION') if progress_percent is not False and progress_percent is not None: old_progress_percent = self.player.progress_percent self.player.progress_percent = interpolate( old_progress_percent, int(progress_percent)) Logger.trace('Progress: ' + str(self.player.progress_percent)) elif progress_percent is False: Logger.debug('_update_progress_interval: Received ' + str(progress_percent) + ' as progress') self.player.playback_finished() self.play_next_track() else: Logger.debug('_update_progress_interval: Received ' + str(progress_percent) + ' as progress') # remove schedule if no track selected elif not self.player.playback_started and not self.player.playing: Logger.debug( 'No song playing, removing slider update interval..') self.updating_progress = False return False self.updating_progress = False def on_config_changed(self, section, key, value): Logger.debug('Config: Config changed') if key == 'playlist_width': self.playlist_width = int(value) elif section == 'Google Play Music': Globals.API.logout() self.google_music_api_login() elif section == 'Development': if key == 'test_mode': Globals.TESTING = True if value == '1' else False def fix_scrolling_workaround(self): self.playlist_view.listview._reset_spopulate() def playbutton_state(self): Logger.debug('Playbuttonstate: ' + self.playbutton.state) return 'down' if self.player.playing else 'normal' def mark_playing_track(self): # track_item = self.playlist_view.get_track(0) # track_item.update_image('../res/icons/equalizer.gif') playing_text = '{} - {}'.format(self.player.current_track['title'], self.player.current_track['artist']) self.playinglabel.text = playing_text App.get_running_app().title = playing_text def restart_track(self): Logger.info('Restarting track..') self.play_track(self.player.current_track) def play_previous_track(self): Logger.info('Playing previous track') track = self.playlist.get_previous_track() if track: self.play_track(track) def play_next_track(self): Logger.info('Playing next track') track = self.playlist.get_next_track() if track: self.play_track(track) else: App.get_running_app( ).title = 'MusicPlayer 3000 for Google Play Music™' def switch_screen_callback(self, screen_title): self.sm.current = screen_title def play_callback(self, track, index): Logger.debug('Playing from songlist (left): Index ' + str(index)) self.playlist.add_track_and_set_current(track) self.fix_scrolling_workaround() self.play_track(track) def play_album_callback(self, album_id): index = len(self.playlist.queue) self.add_album_to_playlist_callback(album_id) idx, track = self.playlist.set_current_track(index) self.play_track(track) def play_from_playlist_callback(self, track, index): Logger.debug('Playing from playlist (right): Index ' + str(index)) self.playlist.set_current_track(index) self.play_track(track) def play_track(self, track): Logger.info('Playing track: ' + track['title']) self.player.play_track_from_id(track) self.mark_playing_track() # self.set_playing_icon() # unschedule possible previous intervals Clock.unschedule(self._update_progress_interval) # start interval for updating the progress slider Clock.schedule_interval(self._update_progress_interval, .1) def set_playing_icon(self): index, current_track = self.playlist.get_current_track() # self.playlist_view.children[0].adapter.data[index] def playbutton_callback(self): if self.player.current_track: # we have a track selected if self.player.playback_started and self.player.playing: # pause track self.player.pause_current_track() elif self.player.playback_started and not self.player.playing: # resume track self.player.resume_current_track() else: # playback has finished, restart track self.restart_track() else: # No track selected but maybe we have elements in the playlist Logger.debug('No current track set!') track = self.playlist.get_start() if track: self.play_track(track) else: # do nothing if no track selected #self.librarymanager.synchronize_library() pass def nextbutton_callback(self): if self.player.current_track: # we have a track selected self.play_next_track() else: # No track selected but maybe we have some in the playlist Logger.debug('No current track set!') track = self.playlist.get_start() if track: self.play_track(track) else: # do nothing if no track selected pass def previousbutton_callback(self): if self.player.current_track: # we have a track selected self.play_previous_track() else: # No track selected but maybe we have some in the playlist Logger.debug('No current track set!') track = self.playlist.get_start() if track: self.play_track(track) else: # do nothing if no track selected pass def shufflebutton_callback(self): if self.playlist.shuffle: Logger.info("I won't shuffle anymore..") self.playlist.shuffle = False self.shufflebutton.source = self.shufflebutton.source_img_alt else: Logger.info("Everyday I'm shuffling..") self.playlist.shuffle = True self.shufflebutton.source = self.shufflebutton.source_img def skip_callback(self, touch_pos): width = self.progress_slider.width touch_pos_x = touch_pos[0] position = touch_pos_x / (width / 100) if self.player.current_track: # we need a track to skip into if not self.player.playback_started: # song is not playing, restart song self.restart_track() self.player.skip_track_to(position) # skip to position else: # self.progress_slider.value = 0 # keep slider position at 0 # TODO: Look into slider implementation to keep slider at 0 pass def add_to_playlist_callback(self, track): self.playlist.add_track(QueryDict(track)) self.fix_scrolling_workaround() def remove_from_playlist_callback(self, index): self.playlist.remove_track(index) def add_album_to_playlist_callback(self, album_id): album = Globals.API.get_album_info(album_id) album_tracks = album['tracks'] if album_tracks: album_tracks = self.formatter.format_tracks_list(album_tracks) for track in album_tracks: self.playlist.add_track(QueryDict(track)) self.fix_scrolling_workaround() def play_station_callback(self, title, seed): tracks = Globals.API.get_station_tracks(title, seed) if tracks: tracks = self.formatter.format_tracks_list(tracks) self.playlist.clear() for track in tracks: self.playlist.add_track(track) self.fix_scrolling_workaround() # self.playlist.set_current_track(0) #self.playbutton_callback() track = self.playlist.get_start() if track: self.play_track(track) else: # do nothing if no track selected pass def playlist_button_callback(self): if self.playlist_hidden: self.playlist_container.width = self.playlist_width self.playlist_hidden = False else: self.playlist_container.width = 0 self.playlist_hidden = True def clear_playlist_callback(self): Logger.info('Clearing playlist') self.playlist.clear() # self.playlist.set_current_track(0) def search(self, text): if len(text) >= 3: try: search_results = Globals.API.search(text) # with open('search_test.json', 'w') as outfile: # json.dump(search_results, outfile) self.display_search_results(search_results) except CallFailure: Logger.warning("Search: No All Access for this account!") # TODO: Show login popup # TODO: Remove try..except block when gmusicapi 9.0.1 is stable else: with open('search_test.json') as outfile: search_results = json.load(outfile) self.display_search_results(search_results) def display_search_results(self, search_results): Logger.info("Displaying results..") Logger.debug("Displaying song results") tracks = [] for entry in search_results['song_hits']: tracks.append(entry['track']) # songs_sorted = sorted(songs, key=self.get_song_key) tracks_formatted = self.formatter.format_tracks_list(tracks) # self.ids['list_songs'].data_songs = tracks_formatted self.songlist.data_songs = tracks_formatted Logger.debug("Displaying station results") stations = [] for entry in search_results['station_hits']: stations.append(entry['station']) stations_formatted = self.formatter.format_stations_list(stations) # add station list items # self.stationlist.data_stations = stations_formatted # add station panels self.stationlist.clear_widgets() for station in stations_formatted: self.stationlist.add_widget(StationPanelItem(station)) Logger.debug("Displaying album results") albums = [] for entry in search_results['album_hits']: albums.append(entry['album']) albums_formatted = self.formatter.format_albums_list(albums) self.albumlist.data_albums = albums_formatted
class Catalog(BoxLayout): def __init__(self,**kwargs): super(Catalog, self).__init__(**kwargs) #self.orientation = 'vertical' self.search_bar = BoxLayout(size_hint=(1.0,0.05)) self.search_bar.add_widget(Label(text='Search',size_hint=(0.25,1.0))) self.search_text = (TextInput(multiline=False)) self.search_bar.add_widget(self.search_text) self.filter_bar = BoxLayout(size_hint=(1.0,0.05)) self.AHSE = ToggleButton(text='AHSE',size_hint=(0.25,1.0)) self.ENGR = ToggleButton(text='ENGR',size_hint=(0.25,1.0)) self.MTH = ToggleButton(text='MTH',size_hint=(0.25,1.0)) self.SCI = ToggleButton(text='SCI',size_hint=(0.25,1.0)) self.filter_bar.add_widget(self.AHSE) self.filter_bar.add_widget(self.ENGR) self.filter_bar.add_widget(self.MTH) self.filter_bar.add_widget(self.SCI) self.scrollview = ScrollView(size_hint=(1.0,0.9),size=(400,400)) self.courses = StackLayout(spacing=5,size_hint_y=None) self.courses.bind(minimum_height=self.courses.setter('height')) for course_object in catalog: course_item = Course_Item(course=course_object,size_hint=(0.245,None),height=200) self.courses.add_widget(course_item) self.scrollview.add_widget(self.courses) self.add_widget(self.search_bar) self.add_widget(self.filter_bar) self.add_widget(self.scrollview) Clock.schedule_interval(self.update_favorites,0.1) Clock.schedule_interval(self.search_function,0.1) def search_function(self,instance): query = self.search_text.text.lower() searched_items = [] filtered_items = [] #fills up the temp list the first time it runs if len(search_temp_list) == 0: for course_item in self.courses.children: search_temp_list.append(course_item) #if the query is not empty, do term search if query != "": for course_item in search_temp_list: if query == course_item.course.name.lower() or query == course_item.course.code or query == course_item.course.prof.lower(): searched_items.append(course_item) for keyword in course_item.course.keywords: if query == keyword.lower(): searched_items.append(course_item) else: searched_items = search_temp_list if self.AHSE.state == 'normal' and self.ENGR.state == 'normal' and self.MTH.state == 'normal' and self.SCI.state == 'normal': filtered_items = searched_items else: if self.AHSE.state == 'down': for course_item in searched_items: if course_item.course.credits['AHSE'] > 0: filtered_items.append(course_item) if self.ENGR.state == 'down': for course_item in searched_items: if course_item.course.credits['ENGR'] > 0 and course_item not in filtered_items: filtered_items.append(course_item) if self.MTH.state == 'down': for course_item in searched_items: if course_item.course.credits['MTH'] > 0 and course_item not in filtered_items: filtered_items.append(course_item) if self.SCI.state == 'down': for course_item in searched_items: if course_item.course.credits['SCI'] > 0 and course_item not in filtered_items: filtered_items.append(course_item) if len(self.courses.children) != len(filtered_items): self.courses.clear_widgets() for course_item in filtered_items: self.courses.add_widget(course_item) def update_favorites(self,instance): for course_item in self.courses.children: if course_item.favorite.state == 'normal' and course_item.course in favorite_courses: favorite_courses.remove(course_item.course) if course_item.favorite.state == 'down' and course_item.course not in favorite_courses: favorite_courses.append(course_item.course)
class EventListbox(StackLayout): def __init__(self, **kwargs): super(EventListbox, self).__init__(**kwargs) self.is_updating = False self.orientation = 'lr-tb' self.items = [] self.bind(pos=self.draw, size=self.draw) self.data_bindings = dict() self.selected_view = None self.selected_item = None # content self.content = StackLayout(orientation = 'lr-tb') self.content.size_hint_y = None #for scrollviewer self.content.bind(minimum_height=self.content.setter('height')) self.scrollview = ScrollView(size_hint=[1, 1]) self.scrollview.do_scroll_x = False self.scrollview.add_widget(self.content) self.add_widget(self.scrollview) def begin_update(self): self.is_updating = True def end_update(self): self.is_updating = False self.draw() def add_item(self, item): self.items.append(item) if not self.is_updating: self.draw() def clear_items(self): del self.items[:] self.clear_selection() self.draw() def clear_selection(self): self.selected_view = None self.selected_item = None def draw(self, *args): self.content.clear_widgets() self.data_bindings.clear() n = len(self.items) i = 0 while i < n: item_wgt = EventWidget(self.items[i]) item_wgt.height = self.height/4 item_wgt.size_hint = [1, None] #for scrollviewer parent item_wgt.bind(on_touch_down=self.selection_change) self.content.add_widget(item_wgt) self.data_bindings[item_wgt] = self.items[i] i += 1 # self.draw_background() def selection_change(self, instance, touch): for item_wgt in self.content.children: if item_wgt.collide_point(touch.x, touch.y): self.selected_view = item_wgt self.selected_item = self.data_bindings[item_wgt]
class HistToolApp(App): autosave_file_name = 'last_settings.hst' def __init__(self): super().__init__() self.models = [] self.histLayout = None self.scrollView = None self.usedIDs = [] self.all_settings = defaultdict(int) self.currID = self.loadSettings() self.initLayoutHeight = 10 Window.bind(on_resize=self._on_resize) def saveSettings(self, fname=autosave_file_name): saved_settings = [ self.all_settings[key] for key in self.all_settings if self.all_settings[key] != 0 ] #print(saved_settings) with open(fname, 'w') as f: for item in saved_settings: f.write("%s\n" % item) def loadSettings(self, fname=autosave_file_name): idx = 0 self.all_settings = defaultdict(int) with open(fname, 'r') as f: for line in f: self.all_settings[idx] = (eval(line)) idx += 1 return idx def build(self): if self.root is not None: self.root.clear_widgets() add_hist_button = Button(text='Add Histogram', font_size=14, on_press=self.addHistogram) create_hists_button = Button(text='Create Graphs', font_size=14, on_press=self.createHistograms) save_hists_button = Button(text='Save Histograms', font_size=14, on_press=self._save_button) load_hists_button = Button(text='Load Histograms', font_size=14, on_press=self._load_button) save_and_load = BoxLayout(orientation='vertical') save_and_load.add_widget(save_hists_button) save_and_load.add_widget(load_hists_button) btnLayout = BoxLayout(size_hint=(1, None), height=50) btnLayout.add_widget(add_hist_button) btnLayout.add_widget(create_hists_button) btnLayout.add_widget(save_and_load) self.scrollView = ScrollView(size_hint=(1, 1)) self.scrollView.do_scroll_x = False self.histLayout = StackLayout(orientation='tb-lr') self.histLayout.size_hint = (1, None) self.histLayout.height = self.initLayoutHeight self.histLayout.bind(minimum_height=self.histLayout.setter('height')) self.scrollView.add_widget(self.histLayout) self.root = BoxLayout(orientation='vertical') self.root.add_widget(self.scrollView) self.root.add_widget(btnLayout) self.updateHistList() return self.root def _load_button(self, instance): filename = askopenfilename( ) # show an "Open" dialog box and return the path to the selected file if filename == '': return self.idx = self.loadSettings(filename) self.updateHistList() def _save_button(self, instance): filename = asksaveasfilename( ) # show an "Open" dialog box and return the path to the selected file if filename == '': return self.saveSettings(filename) self.updateHistList() def updateModels(self): self.models = [] for key in self.all_settings: if self.all_settings[key] != 0: model = self.createModel(self.all_settings[key]) self.models.append(model) def parseEvalString(self, string): varSt = 0 varEnd = 0 varReplacements = [ 'x', 'y', 'z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k' ] vars = [] remainingBrackets = True while remainingBrackets == True: remainingBrackets = False for idx, c in enumerate(string): if c == "{": remainingBrackets = True varSt = idx elif c == "}": varEnd = idx retVar = string[varSt + 1:varEnd] if retVar in vars: inserted = varReplacements[vars.index(retVar)] else: vars.append(retVar) inserted = varReplacements[len(vars) - 1] string = string[:varSt] + inserted + string[varEnd + 1:] break if string == "": return None return (vars, "lambda " + ",".join(varReplacements[:len(vars)]) + " : " + string) def createModel(self, settings): eval_params1 = self.parseEvalString(settings[3]) eval_params2 = self.parseEvalString(settings[5]) if eval_params1 is None or eval_params2 is None: print("No evaluation parameters found. Histogram cancelled.") return #print(eval_params1) #print(eval_params2) model = hist_model() model.addTargetQuantity(settings[1]) model.addParameter(0, eval_params1[0], eval(eval_params1[1])) model.addParameter(1, eval_params2[0], eval(eval_params2[1])) model.changeLog(settings[6]) model.changeTitle(settings[0]) model.changeLabels((settings[2], settings[4])) return model def addHistogram(self, instance): settings = histogram_screen() if settings == None: return elif None in settings or "" in settings: print("Error: at least one field was left blank.") return #['title', 'ID', 'label1', 'boolean1', 'label2', 'boolean2', True] #0 1 2 3 4 5 6 self.all_settings[self.currID] = settings #displayed_settings[self.currID] = False self.currID += 1 self.updateHistList() def createHistograms(self, instance): self.updateModels() hstats = hist_stats("results_with_data.csv") for model in self.models: hstats.addHistObject(model) hstats.execute() def editHist(self, key): setting = self.all_settings[key] new_setting = histogram_screen(*setting) if new_setting == None: new_setting = setting elif None in new_setting or "" in new_setting: print("Error: at least one field was left blank.") new_setting = setting self.all_settings[key] = new_setting #displayed_settings[key] = False self.updateHistList() def duplicateHist(self, key): print("CurrID: " + str(self.currID)) self.all_settings[self.currID] = self.all_settings[key] self.currID += 1 self.updateHistList() def updateHistList(self): #for widget in self.histLayout.children: # print(widget.setting_id) #self.histLayout.remove_widget(widget) self.histLayout.clear_widgets() for key in range(self.currID + 1): if key in self.all_settings and self.all_settings[key] != 0: self.histLayout.add_widget( HistDescriptor(self.all_settings[key][0], self, key, size_hint=(None, None))) self.histLayout.height = self.initLayoutHeight for child in self.histLayout.children: self.histLayout.height += child.height self.histLayout.bind(minimum_height=self.histLayout.setter('height')) self.saveSettings() print("HistLayout height: " + str(self.histLayout.height)) def _on_resize(self, instance, w, h): self.root.size = (w, h) self.updateHistList()
def create(self, screen_manager): top_layout = AnchorLayout(size_hint=(1, 0.4), anchor_x='center', anchor_y='top') top = self.Top(size_hint=(1, 1), anchor_x='center', anchor_y='bottom') top.create() button_layout = AnchorLayout(size_hint=(1, 1), padding=(dp(20), dp(20), dp(20), dp(20)), anchor_x='left', anchor_y='top', opacity=0.5) back_button = BackButton() back_button.bind(on_release=lambda instance: setattr(screen_manager, 'current', 'RV')) button_layout.add_widget(back_button) top.add_widget(button_layout) top_layout.add_widget(top) self.float_layout.bind(images=lambda instance, value: top.insert_images(instance, value)) background = AnchorLayout(size_hint=(1, 1), anchor_x='center', anchor_y='center') vertical_scroll_view = ScrollView(do_scroll=(False, True), size_hint=(1, 1), bar_inactive_color=(0, 0, 0, 0), bar_color=(0, 0, 0, 0)) vertical_grid_layout = GridLayout(cols=1, size_hint=(1, None), padding=(dp(20), dp(20), dp(20), dp(20))) vertical_grid_layout.bind(minimum_height=vertical_grid_layout.setter('height')) details_layout = StackLayout(size_hint=(1, None), spacing=dp(20), padding=(dp(0), dp(20), dp(0), dp(0))) details_layout.bind(minimum_height=details_layout.setter('height')) author = CustomLabel(type='Author', txt=str(self.float_layout.author)) self.float_layout.bind(author=lambda instance, value: setattr(author, 'txt', value)) age = CustomLabel(type='Age', txt=str(self.float_layout.age)) self.float_layout.bind(age=lambda instance, value: setattr(age, 'txt', value)) breed = CustomLabel(type='Breed', txt=str(self.float_layout.breed)) self.float_layout.bind(breed=lambda instance, value: setattr(breed, 'txt', value)) location = CustomLabel(type='Location', txt=str(self.float_layout.location)) self.float_layout.bind(location=lambda instance, value: setattr(location, 'txt', value)) color = CustomLabel(type='Color', txt=str(self.float_layout.color)) self.float_layout.bind(color=lambda instance, value: setattr(color, 'txt', value)) date = CustomLabel(type='Date', txt=str(self.float_layout.date)) self.float_layout.bind(date=lambda instance, value: setattr(date, 'txt', value)) gender = CustomLabel(type='Gender', txt=str(self.float_layout.gender)) self.float_layout.bind(gender=lambda instance, value: setattr(gender, 'txt', value)) #petid = CustomLabel(type='Pet ID', txt=str(self.float_layout.petid)) #self.float_layout.bind(petid=lambda instance, value: setattr(petid, 'txt', value)) size = CustomLabel(type='Size', txt=str(self.float_layout.pet_size)) self.float_layout.bind(pet_size=lambda instance, value: setattr(size, 'txt', value)) status = CustomLabel(type='Status', txt=str(self.float_layout.status)) self.float_layout.bind(status=lambda instance, value: setattr(status, 'txt', value.title())) zip = CustomLabel(type='Zip', txt=str(self.float_layout.zip)) self.float_layout.bind(zip=lambda instance, value: setattr(zip, 'txt', value)) details_layout.add_widget(author) details_layout.add_widget(age) details_layout.add_widget(breed) details_layout.add_widget(location) details_layout.add_widget(color) details_layout.add_widget(date) details_layout.add_widget(gender) #details_layout.add_widget(petid) details_layout.add_widget(size) details_layout.add_widget(status) details_layout.add_widget(zip) name_layout = AnchorLayout(size_hint=(1, None), height=dp(30), anchor_x='center', anchor_y='center') pet_name = CustomName(name=str(self.float_layout.name)) self.float_layout.bind(name=lambda instance, value: setattr(pet_name, 'name', value)) pet_name.bind(size=pet_name.setter('text_size')) name_layout.add_widget(pet_name) summary_layout = AnchorLayout(size_hint=(1, None), height=dp(42), anchor_x='center', anchor_y='center', padding=(dp(0), dp(0), dp(0), dp(20))) summary = Label(halign='left', valign='center', color=get_color_from_hex('#6e7c97'), font_size=dp(16), font_name='assets/Inter-SemiBold.ttf', text='Summary') summary.bind(size=summary.setter('text_size')) summary_layout.add_widget(summary) vertical_grid_layout.add_widget(name_layout) vertical_grid_layout.add_widget(details_layout) vertical_grid_layout.add_widget(summary_layout) summary_label = SummaryLabel() vertical_grid_layout.add_widget(summary_label) self.float_layout.bind(summary=lambda instance, value: setattr(summary_label, 'text', value)) vertical_scroll_view.add_widget(vertical_grid_layout) background.add_widget(vertical_scroll_view) bottom_layout = AnchorLayout(size_hint=(1, 0.5), anchor_x='center', anchor_y='bottom') bottom_layout.add_widget(background) pin_and_message_layout = BoxLayout(size_hint=(1, None), height=dp(65), orientation='horizontal') message_button = MessageButton(icon='', text='Message', color=get_color_from_hex('#023b80'), padding=(dp(20), dp(20), dp(20), dp(0))) message_button.on_release = lambda: self.message_callback(self.root_sm) pin_and_message_layout.add_widget(message_button) self.float_layout.add_widget(top_layout) self.float_layout.add_widget(bottom_layout) self.float_layout.add_widget(pin_and_message_layout) return self.float_layout
class Catalog(BoxLayout): """Tab that displays available courses and allows user to search for, see details about, and add courses to planner tab""" def __init__(self,sm,**kwargs): super(Catalog,self).__init__(**kwargs) self.orientation = 'vertical' self.sm = sm ## Search Bar ## self.search_bar = BoxLayout(size_hint=(1.0,0.05)) self.search_text = TextInput(multiline=False,size_hint =(0.6,1.0)) self.create_course_popup = Build_Course(self.sm) self.create_course_button = Button(text='Create a Course',size_hint=(0.2,1.0),on_press=self.create_course_popup.open_pop_up) self.search_bar.add_widget(Label(text='Search',size_hint=(0.2,1.0))) self.search_bar.add_widget(self.search_text) self.search_bar.add_widget(self.create_course_button) ## Filter Buttons ## self.filter_bar = BoxLayout(size_hint=(1.0,0.05)) self.AHSE = ToggleButton(text='AHSE',size_hint=(0.25,1.0)) self.ENGR = ToggleButton(text='ENGR',size_hint=(0.25,1.0)) self.MTH = ToggleButton(text='MTH',size_hint=(0.25,1.0)) self.SCI = ToggleButton(text='SCI',size_hint=(0.25,1.0)) self.filter_bar.add_widget(self.AHSE) self.filter_bar.add_widget(self.ENGR) self.filter_bar.add_widget(self.MTH) self.filter_bar.add_widget(self.SCI) ## Scrollview of Courses ## self.scrollview = ScrollView(size_hint=(1.0,0.9),size=(400,400),scroll_timeout=5) self.courses = StackLayout(spacing=5,size_hint_y=None) self.courses.bind(minimum_height=self.courses.setter('height')) self.scrollview.add_widget(self.courses) ## Add Widgets to Tab ## self.add_widget(self.search_bar) self.add_widget(self.filter_bar) self.add_widget(self.scrollview) Clock.schedule_interval(self.search_function,0.1) def search_function(self,instance): """Allows user to search for courses by name, keyword, professor, or course code and filter courses by type""" query = self.search_text.text.lower() searched_items = [] filtered_items = [] #fills up the temp list the first time the function is called (copy of list of all courses) if len(search_temp_list) == 0: for course_item in self.courses.children: search_temp_list.append(course_item) #if the query is not empty, does term search first if query != "": for course_item in search_temp_list: if query == course_item.course.name.lower() or query == course_item.course.code or query == course_item.course.prof.lower(): searched_items.append(course_item) for keyword in course_item.course.keywords: if query == keyword.lower(): searched_items.append(course_item) #if the query is empty, searched courses = all courses else: searched_items = search_temp_list #if none of the buttons are down, keep all searched courses if self.AHSE.state == 'normal' and self.ENGR.state == 'normal' and self.MTH.state == 'normal' and self.SCI.state == 'normal': filtered_items = searched_items #if a button is down, shows only courses in that category (holding multiple buttons shows more courses) else: if self.AHSE.state == 'down': for course_item in searched_items: if course_item.course.credits['AHSE'] > 0: filtered_items.append(course_item) if self.ENGR.state == 'down': for course_item in searched_items: if course_item.course.credits['ENGR'] > 0 and course_item not in filtered_items: filtered_items.append(course_item) if self.MTH.state == 'down': for course_item in searched_items: if course_item.course.credits['MTH'] > 0 and course_item not in filtered_items: filtered_items.append(course_item) if self.SCI.state == 'down': for course_item in searched_items: if course_item.course.credits['SCI'] > 0 and course_item not in filtered_items: filtered_items.append(course_item) if len(self.courses.children) != len(filtered_items): self.courses.clear_widgets() for course_item in filtered_items: self.courses.add_widget(course_item)
class DragTab(BoxLayout): def __init__(self,**kwargs): super(DragTab,self).__init__(**kwargs) #Base Layer is a BoxLayout #right-hand column is StackLayout, lefthand is a vertical box layout self.scrollview = ScrollView(size=(400,400),size_hint=(0.3,1)) self.courses = StackLayout(spacing=5,size_hint_y=None,orientation='tb-rl') self.courses.bind(minimum_height=self.courses.setter('height')) self.scrollview.add_widget(self.courses) self.lefthand=BoxLayout(orientation='vertical', size_hint=(.7,1)) self.Planner=GridLayout(size_hint=(1,.9),rows=2, cols=4, spacing=3) self.slot1=Semester(text="Fall "+ str(all_globals.user.grad_year-4)) self.Planner.add_widget(self.slot1) self.slot2=Semester(text="Fall "+ str(all_globals.user.grad_year-3)) self.Planner.add_widget(self.slot2) self.slot3=Semester(text="Fall "+ str(all_globals.user.grad_year-2)) self.Planner.add_widget(self.slot3) self.slot4=Semester(text="Fall "+ str(all_globals.user.grad_year-1)) self.Planner.add_widget(self.slot4) self.slot5=Semester(text="Spring "+ str(all_globals.user.grad_year-3)) self.Planner.add_widget(self.slot5) self.slot6=Semester(text="Spring "+ str(all_globals.user.grad_year-2)) self.Planner.add_widget(self.slot6) self.slot7=Semester(text="Spring "+ str(all_globals.user.grad_year-1)) self.Planner.add_widget(self.slot7) self.slot8=Semester(text="Spring "+ str(all_globals.user.grad_year)) self.Planner.add_widget(self.slot8) self.lefthand.add_widget(self.Planner) self.stats_widget=BoxLayout(size_hint=(1, .1)) self.recycle=Button(size_hint=(.25, 1), text= 'Recycle \n Course') self.stats=Label(size_hint=(.75,1),color=(1,1,1,.3)) self.stats_widget.add_widget(self.recycle) self.stats_widget.add_widget(self.stats) self.lefthand.add_widget(self.stats_widget) #Now stuff it all in self.add_widget(self.lefthand) self.add_widget(self.scrollview) # if len(self.lefthand.children)>=2: Clock.schedule_interval(self.update_stats_widget, .1) def add_Icon(self,course): Icon=DragableButton(course=course,text=course.keywords[0],height=100,size_hint_y=None, droppable_zone_objects=[], bound_zone_objects=[], kill_zone_objects=[], drag_opacity=.5, remove_on_drag=True) # Icon.text_size=self.size Icon.bound_zone_objects.append(self.Planner) Icon.bound_zone_objects.append(self.scrollview) Icon.bound_zone_objects.append(self.recycle) Icon.droppable_zone_objects.append(self.slot1.coursehouse) Icon.droppable_zone_objects.append(self.slot2.coursehouse) Icon.droppable_zone_objects.append(self.slot3.coursehouse) Icon.droppable_zone_objects.append(self.slot4.coursehouse) Icon.droppable_zone_objects.append(self.slot5.coursehouse) Icon.droppable_zone_objects.append(self.slot6.coursehouse) Icon.droppable_zone_objects.append(self.slot7.coursehouse) Icon.droppable_zone_objects.append(self.slot8.coursehouse) Icon.droppable_zone_objects.append(self.courses) Icon.kill_zone_objects.append(self.recycle) self.courses.add_widget(Icon) print Icon.droppable_zone_objects def update_stats_widget(self, dt): ##DON'T REWRITE OVER THE USER INFORMATION WITH THE DUMMY DATA!!!!!! Fixed=False all_globals.user.credits['AHSE'] = 0#course.course.pre_credits['AHSE'] all_globals.user.credits['ENGR'] = 0#course.course.pre_credits['ENGR'] all_globals.user.credits['MTH'] = 0#course.course.pre_credits['MTH'] all_globals.user.credits['SCI'] = 0#course.course.pre_credits['SCI'] for child in self.lefthand.children[:]: if child.height> 300: for semester_block in child.children[:]: for semester_element in semester_block.children[:]: if semester_element.height>100: for course in semester_element.children[:]: all_globals.user.credits['AHSE'] += course.course.credits['AHSE'] all_globals.user.credits['ENGR'] += course.course.credits['ENGR'] all_globals.user.credits['MTH'] += course.course.credits['MTH'] all_globals.user.credits['SCI'] += course.course.credits['SCI'] for child in self.lefthand.children[:]: if child.height>300: Fixed=True if Fixed: for child in self.lefthand.children[:]: if child.height< 300: for grandchild in child.children[:]: if grandchild.width> 300: child.remove_widget(grandchild) stats=Label(size_hint=(1,1),text='AHSE: '+str(all_globals.user.credits['AHSE'])+' '+'ENGR: '+str(all_globals.user.credits['ENGR'])+' '+'MTH: '+str(all_globals.user.credits['MTH'])+' '+'SCI: '+str(all_globals.user.credits['SCI'])+' ',color=(1,1,1,1)) child.add_widget(stats)
class Form: def __init__(self): self._states = None self._zip_codes = None self._cities = None self._selected_city = None self._selected_zip_code = None self._name = None self._gender = None self._age = None self._breed = None self._color = None self._size = None self._status = None self._date = None self._state = None self._summary = None self._zip = None self._city = None self._images = [] self._image_upload = None self._images_grid_layout = None self._files = None self._button_submit = None self.raw_images = [] def get_states(self): list = [ 'AL', 'AK', 'AZ', 'AR', 'CA', 'CO', 'CT', 'DE', 'FL', 'GA', 'HI', 'ID', 'IL', 'IN', 'IA', 'KS', 'KY', 'LA', 'ME', 'MD', 'MA', 'MI', 'MN', 'MS', 'MO', 'MT', 'NE', 'NV', 'NH', 'NJ', 'NM', 'NY', 'NC', 'ND', 'OH', 'OK', 'OR', 'PA', 'RI', 'SC', 'SD', 'TN', 'TX', 'UT', 'VT', 'VA', 'WA', 'WV', 'WI', 'WY' ] return list def get_date(self, date): self._date.ids.category.text = datetime.strptime( str(date), '%Y-%m-%d').strftime('%B %d, %Y') self._date.ids.category.color = get_color_from_hex('#023b80') self._date.ids.icon.color = get_color_from_hex('#023b80') def date_picker(self): date_dialog = MDDatePicker(callback=self.get_date) date_dialog.open() def load_files(self): try: from jnius import autoclass PythonActivity = autoclass('org.kivy.android.PythonActivity') self._files = MDFileManager(exit_manager=self.exit_manager, select_path=self.select_path, previous=True, ext=['png', 'jpg', 'jpeg']) self._files.show(PythonActivity.storagePath) except: self._files = MDFileManager(exit_manager=self.exit_manager, select_path=self.select_path, previous=True, ext=['png', 'jpg', 'jpeg']) self._files.show('/') def remove_image(self, instance, path=None): self._images_grid_layout.remove_widget(instance.parent.parent) self._images.remove(path) def select_path(self, path): self._image_upload.ids.svg.color = get_color_from_hex('#023b80') self._image_upload.ids.icon.color = get_color_from_hex('#023b80') self.exit_manager(path) self._images.append(path) anchor_layout = CustomAnchorLayout(size_hint=(None, None), size=(dp(95), dp(85))) layout = CustomStencilView() layout.add_widget( CustomImageUpload(size_hint=(None, None), pos_hint={ 'center_x': 0.5, 'center_y': 0.5 }, keep_ratio=True, allow_stretch=True, source=path)) anchor_layout.add_widget(layout) cancel_layout = AnchorLayout(anchor_x='right', anchor_y='top', padding=(dp(-5), dp(-5))) cancel_image = CancelImage() cancel_image.ids.cancel.text = '' cancel_layout.add_widget(cancel_image) anchor_layout.add_widget(cancel_layout) holder = AnchorLayout(size_hint=(None, None), size=(dp(95), dp(85))) holder.add_widget(anchor_layout) copy_cancel_layout = AnchorLayout(anchor_x='right', anchor_y='top', padding=(dp(-5), dp(-5))) copy_cancel_image = CancelImage() copy_cancel_image.ids.cancel.text = '' copy_cancel_image.fbind('on_release', self.remove_image, path=path) copy_cancel_layout.add_widget(copy_cancel_image) holder.add_widget(copy_cancel_layout) self._images_grid_layout.add_widget(holder) def exit_manager(self, path): self._files.close() def on_deselect(self, instance, icon=None, border=None): border.rgb = get_color_from_hex('#c9d0dc') if border.ids.category.text == border.type: icon.color = get_color_from_hex('#c9d0dc') def create_drop_down(self, button, list=None, icon=None, border=None): border.rgb = get_color_from_hex('#023b80') icon.color = get_color_from_hex('#023b80') drop_down = DropDown() drop_down.fbind('on_dismiss', self.on_deselect, icon=icon, border=border) drop_down.bind(on_select=lambda instance, x: (setattr(button.ids.category, 'text', x), setattr(button.ids.category, 'color', get_color_from_hex('#023b80')), setattr(button.ids.icon, 'color', get_color_from_hex('#023b80')))) for text in list: new_item = CustomMenu(size_hint=(1, None), height=dp(45), text=text) new_item.bind( on_release=lambda item: drop_down.select(item.text)) drop_down.add_widget(new_item) drop_down.open(button) def on_change_text(self, instance, value): for state, list in self._states.items(): if state == value: self._zip_codes = [] self._cities = [] for item in list: self._zip_codes.append(item['zip']) self._cities.append(item['city']) self._cities.sort() def on_summary_focus(self, instance, value, icon=None, border=None): if value: border.rgb = get_color_from_hex('#023b80') else: border.rgb = get_color_from_hex('#c9d0dc') if instance.text == '': if value: icon.color = get_color_from_hex('#023b80') else: icon.color = get_color_from_hex('#c9d0dc') else: instance.text = instance.text def on_focus(self, instance, value, icon=None, border=None): if value: border.rgb = get_color_from_hex('#023b80') else: border.rgb = get_color_from_hex('#c9d0dc') if instance.text == '': if value: icon.color = get_color_from_hex('#023b80') else: icon.color = get_color_from_hex('#c9d0dc') else: instance.text = instance.text.title() def on_focus_city(self, instance, value, icon=None, border=None): if self._state.ids.category.text == 'State': instance.is_focusable = False Snackbar(text='Please select a state first!').show() instance.is_focusable = True else: if value: border.rgb = get_color_from_hex('#023b80') else: border.rgb = get_color_from_hex('#c9d0dc') if instance.text == '': if value: icon.color = get_color_from_hex('#023b80') else: icon.color = get_color_from_hex('#c9d0dc') else: instance.text = self._selected_city def on_focus_zip(self, instance, value, icon=None, border=None): if self._state.ids.category.text == 'State': instance.is_focusable = False Snackbar(text='Please select a state first!').show() instance.is_focusable = True else: if value: border.rgb = get_color_from_hex('#023b80') else: border.rgb = get_color_from_hex('#c9d0dc') if instance.text == '': if value: icon.color = get_color_from_hex('#023b80') else: icon.color = get_color_from_hex('#c9d0dc') else: instance.text = self._selected_zip_code def on_cities(self, instance, value): try: for city in self._cities: if city.lower().startswith(value.lower()): diff = re.split(value, city, flags=re.IGNORECASE)[1] if diff != '': self._city.ids.category.suggestion_text = diff self._selected_city = city break except: pass def on_zip_codes(self, instance, value): try: for zip in self._zip_codes: if zip.startswith(value): diff = re.split(value, zip)[1] if diff != '': self._zip.ids.category.suggestion_text = diff self._selected_zip_code = zip break except: pass def submit_data(self): name = self._name.ids.category.text.replace('Name', '') gender = self._gender.ids.category.text.replace('Gender', '') age = self._age.ids.category.text.replace('Age', '') breed = self._breed.ids.category.text.replace('Breed', '') color = self._color.ids.category.text.replace('Color', '') size = self._size.ids.category.text.replace('Size', '') status = self._status.ids.category.text.replace('Status', '') date = self._date.ids.category.text.replace('Date', '') state = self._state.ids.category.text.replace('State', '') summary = self._summary.ids.category.text.replace('Summary', '') zip = self._zip.ids.category.text.replace('Zip', '') city = self._city.ids.category.text.replace('City', '') images = self._images id = uuid.uuid4() dict = { 'name': name.strip(), 'gender': gender.strip(), 'age': age.strip(), 'breed': breed.strip(), 'color': color.strip(), 'size': size.strip(), 'status': status.strip(), 'date': date.strip(), 'state': state.strip(), 'zip': zip.strip(), 'city': city.strip(), 'summary': summary, 'petid': id } for key, value in dict.items(): if value == '': Snackbar(text=key.title() + ' is missing.').show() return if not images: Snackbar(text='Image is missing.').show() return Snackbar(text='Attempting to send requested pet...').show() print('All fields satisfied.') self._button_submit.disabled = True self._button_submit.text = 'SENDING' for image in images: tuple = (image, open(image, 'rb')) self.raw_images.append(tuple) #pool = Pool(1) #pool.apply_async(requests.post, args=['https://fur-finder.herokuapp.com/api/pets//'], kwds={'data': dict, 'files': self.raw_images}, callback=self.on_success, error_callback=self.on_error) th = Thread(target=self.post, args=(dict, )) th.setDaemon(True) th.start() def post(self, data): s = requests.Session() s.hooks['response'].append(self.callback) headers = {'Authorization': 'Token ' + LoginView.token} #pet_list_size = requests.get(url='https://fur-finder.herokuapp.com/api/pets//', headers=headers).json() #data['petid'] = len(pet_list_size) - 1 resp = s.post('http://fur-finder.herokuapp.com/api/pets//', data=data, files=self.raw_images, headers=headers) if resp.ok: pass else: print(resp.text) def callback(self, r, **kwargs): print(r.text) for raw_image in self.raw_images: raw_image[1].close() if r.ok: Snackbar(text='Successfully reported pet.').show() print('POST successful.') else: Snackbar(text='Could not report pet. Try different pictures.' ).show() print('POST failed.') self._button_submit.disabled = False self._button_submit.text = 'SUBMIT' self.raw_images.clear() def create(self): with open(os.path.join(os.path.dirname(__file__), '../states.json')) as file: self._states = json.load(file) main_grid_layout = GridLayout(size_hint=(1, None), cols=1, spacing=dp(20), padding=(dp(20), dp(0), dp(20), dp(0))) main_grid_layout.bind( minimum_height=main_grid_layout.setter('height')) self._name = FormInput(size_hint=(1, None), height=dp(45), icon='', type='Name', input_type='text', input_filter=None) self._name.ids.category.fbind('focus', self.on_focus, icon=self._name.ids.icon, border=self._name) self._breed = FormInput(size_hint=(1, None), height=dp(45), icon='', type='Breed', input_type='text', input_filter=None) self._breed.ids.category.fbind('focus', self.on_focus, icon=self._breed.ids.icon, border=self._breed) self._city = FormInput(size_hint=(1, None), height=dp(45), icon='', type='City', input_type='text', input_filter=None) self._city.ids.category.fbind('focus', self.on_focus_city, icon=self._city.ids.icon, border=self._city) self._city.ids.category.fbind('text', self.on_cities) self._zip = FormInput(size_hint=(1, None), height=dp(45), icon='', type='Zip', input_type='number', input_filter='int') self._zip.ids.category.fbind('focus', self.on_focus_zip, icon=self._zip.ids.icon, border=self._zip) self._zip.ids.category.fbind('text', self.on_zip_codes) self._date = FormLabel(size_hint=(1, None), height=dp(45), icon='', type='Date', chevron='') self._date.on_release = lambda: self.date_picker() self._gender = FormLabel(size_hint=(1, None), height=dp(45), icon='', type='Gender') self._gender.fbind('on_release', self.create_drop_down, list=['Male', 'Female'], icon=self._gender.ids.icon, border=self._gender) self._age = FormLabel(size_hint=(1, None), height=dp(45), icon='', type='Age') self._age.fbind('on_release', self.create_drop_down, list=['Puppy', 'Kitten', 'Adult', 'Senior'], icon=self._age.ids.icon, border=self._age) self._color = FormLabel(size_hint=(1, None), height=dp(45), icon='', type='Color') self._color.fbind('on_release', self.create_drop_down, list=[ 'Black', 'Blue', 'Brown', 'Cream', 'Fawn', 'Gold', 'Grey', 'Multicolor', 'Orange', 'Red', 'Tan', 'White' ], icon=self._color.ids.icon, border=self._color) self._size = FormLabel(size_hint=(1, None), height=dp(45), icon='', type='Size') self._size.fbind('on_release', self.create_drop_down, list=['Small', 'Medium', 'Large'], icon=self._size.ids.icon, border=self._size) self._status = FormLabel(size_hint=(1, None), height=dp(45), icon='', type='Status') self._status.fbind('on_release', self.create_drop_down, list=['Lost', 'Found'], icon=self._status.ids.icon, border=self._status) self._state = FormLabel(size_hint=(1, None), height=dp(45), icon='', type='State') self._state.fbind('on_release', self.create_drop_down, list=self.get_states(), icon=self._state.ids.icon, border=self._state) self._state.ids.category.fbind('text', self.on_change_text) self._summary = SummaryInput(size_hint=(1, None), height=dp(135), icon='', type='Summary', input_type='text', input_filter=None) self._summary.ids.category.fbind('focus', self.on_summary_focus, icon=self._summary.ids.icon, border=self._summary) self._button_submit = Button( text='SUBMIT', background_normal='', background_color=get_color_from_hex('#023b80'), font_size=dp(16), font_name='assets/Inter-Medium.ttf', size_hint=(None, None), size=(dp(100), dp(50))) self._button_submit.on_release = lambda: self.submit_data() gender_and_age_grid_layout = GridLayout(size_hint=(1, None), cols=2, spacing=dp(20)) gender_and_age_grid_layout.bind( minimum_height=gender_and_age_grid_layout.setter('height')) gender_and_age_grid_layout.add_widget(self._gender) gender_and_age_grid_layout.add_widget(self._age) color_and_size_grid_layout = GridLayout(size_hint=(1, None), cols=2, spacing=dp(20)) color_and_size_grid_layout.bind( minimum_height=color_and_size_grid_layout.setter('height')) color_and_size_grid_layout.add_widget(self._color) color_and_size_grid_layout.add_widget(self._size) state_and_zip_grid_layout = GridLayout(size_hint=(1, None), cols=2, spacing=dp(20)) state_and_zip_grid_layout.bind( minimum_height=state_and_zip_grid_layout.setter('height')) state_and_zip_grid_layout.add_widget(self._state) state_and_zip_grid_layout.add_widget(self._zip) status_and_date_grid_layout = GridLayout(size_hint=(1, None), cols=2, spacing=dp(20)) status_and_date_grid_layout.bind( minimum_height=status_and_date_grid_layout.setter('height')) status_and_date_grid_layout.add_widget(self._status) status_and_date_grid_layout.add_widget(self._date) self._image_upload = FormImage(size_hint=(None, None), size=(dp(95), dp(85))) self._image_upload.ids.svg.text = '' self._image_upload.ids.icon.text = '' self._image_upload.on_release = lambda: self.load_files() self._images_grid_layout = StackLayout(size_hint=(1, None), spacing=dp(20)) self._images_grid_layout.bind( minimum_height=self._images_grid_layout.setter('height')) self._images_grid_layout.add_widget(self._image_upload) main_grid_layout.add_widget(self._name) main_grid_layout.add_widget(gender_and_age_grid_layout) main_grid_layout.add_widget(self._breed) main_grid_layout.add_widget(color_and_size_grid_layout) main_grid_layout.add_widget(status_and_date_grid_layout) main_grid_layout.add_widget(state_and_zip_grid_layout) main_grid_layout.add_widget(self._city) main_grid_layout.add_widget(self._summary) main_grid_layout.add_widget(self._images_grid_layout) main_grid_layout.add_widget(self._button_submit) scroll_view = ScrollView(size_hint=(1, 0.9), effect_cls=ScrollEffect, bar_inactive_color=(0, 0, 0, 0), bar_color=(0, 0, 0, 0)) scroll_view.add_widget(main_grid_layout) return scroll_view
class FileBrowser(BoxLayout): def __init__(self, name, **kwargs): super().__init__(**kwargs) self.orientation = "vertical" # the below is now handled #self.size_hint = (None, None) #it would be nice if this could be optionally passed in with kwargs #self.size = (width, height) self.source = "" self.show_file_names = True self.selected_image = SpecialImage(None) self.image_width_hint = 1 # big one self.bind( size=partial(self.set_image_width_hint) ) # will need size or just height, depending on what's being used in the function Window.bind(mouse_pos=self._mouse_move) self.hover_count = None # set this during populate self.menu_bar = MenuBar(name, almost_black, light_grey, light_blue) self.add_widget(self.menu_bar) self.scroll_body = ScrollView(bar_width='12dp', scroll_wheel_distance='20dp', scroll_type=['bars', 'content'], bar_inactive_color=[.7, .7, .7, .2 ]) ### add settings self.add_widget(self.scroll_body) self.scroll_body.bind(on_scroll_stop=self.on_scroll_stop_function) self.body = StackLayout( orientation="lr-tb", size_hint_x=0.99, size_hint_y=None, spacing=[1, 5] ) # the horizontal spacing isn't like the website, but they didn't have background colours like I do self.scroll_body.add_widget(self.body) self.body.bind(minimum_height=self.body.setter('height')) self.body.bind(height=self.scroll_test_function) self.bottom_bar = BottomBar(size_hint=(1, None), height='17dp', font_size='13dp', bold=True) self.add_widget(self.bottom_bar) self.draw() self.bind(pos=self.update_rectangles, size=self.update_rectangles) self.bind(size=self.test_function) self.size = self.size self.test_function() def scroll_test_function(self, *args): self.scroll_body.scroll_wheel_distance = kivy.metrics.dp(20) * math.log( self.body.height ) / 4 #< I think I stumbled across a combination here hat's quite effective (it goes between 35-45 depending on number of items, maybe more maybe less) def test_function(self, *args): self.body.padding = [3, 5, kivy.metrics.dp(12), 0] #self.body.padding = [(self.width - (self.width * 0.99)), 5, kivy.metrics.dp(12), 0] # def draw(self): self.canvas.before.clear() with self.canvas.before: Color(1, 1, 1, 1) self.rectangle = Rectangle(pos=self.pos, size=self.size) def update_rectangles(self, *args): self.rectangle.pos = self.pos self.rectangle.size = self.size def populate(self, source): # a means of setting source self.source = source if self.body.children != []: self.body.clear_widgets() if source != "": direntry_iterator = os.scandir(self.source) for direntry in direntry_iterator: if direntry.is_file( ) == True: # Could also check if they are images (.png, .jpg) a_special_image = SpecialImage(direntry) self.body.add_widget(a_special_image) a_special_image.be_within = self a_special_image.be_not_within = self.menu_bar a_special_image.be_not_within_two = self.bottom_bar # set sizes of specialimage. This might be a dumb way to do it, they only need to be called once, you see. a_special_image.update_height() a_special_image.update_image_height() a_special_image.update_boxlayout() a_special_image.update_text_textboxes() def set_selected(self, a_special_image): if a_special_image != self.selected_image: if self.selected_image != None: self.selected_image.selected = False self.selected_image.set_deselected() self.selected_image = a_special_image a_special_image.set_selected() self.bottom_bar.update_text(self.selected_image.file_name + " selected") def set_image_width_hint(self, *args): pass def _mouse_move(self, *args): if not self.get_root_window(): return is_collide = self.collide_point(*self.to_widget(*args[1])) hovered = False for child in self.body.children: if child.hover == True and child.selected == False: # since until you on_exit a special image, and it's selected, hover will be true (and we don't want to have a hand cursor) hovered = True break if is_collide == True and hovered == True: Window.set_system_cursor("hand") elif is_collide == False: pass else: Window.set_system_cursor("arrow") def on_scroll_stop_function(self, *args): for child in self.body.children: # i.e. when on_scroll_stop is called for scroll_body, iterate through the special images and get them to check if they should be on_hovered or exits (this wouldn't be done otherwise: because a scroll isn't a mouse move) child._mouse_move( "hifdidl", Window.mouse_pos ) # THANK F**K THAT THIS WORKS. My doubt was that it would pass some bull shit Window.mouse_pos.
class DecksMenu(RelativeLayout): def __init__(self, cards, setts, username, **kwargs): super().__init__(**kwargs) self.username = username self.acc_decks = [cards[card] for card in cards] self.acc_decks = [Deck(deck) for deck in self.acc_decks] self.acc_settings = setts self.cardWidth = 100 self.spacingSize = 10 self.paddingSize = 50 Window.clearcolor = colors.GRAY self.scroll = ScrollView() self.scroll.size = (Window.width, Window.height) self.scroll.bar_color = colors.WHITE self.scroll.bar_width = dp(12) self.scroll.scroll_distance = dp(80) # * default oreintation is horizontal self.load() self.add_widget(self.scroll) self.bottom_buttons = BoxLayout() self.new_deck_button = Button() self.new_deck_button.text = "New Deck" self.new_deck_button.size_hint = (1, None) self.new_deck_button.height = dp(50) self.new_deck_button.on_press = self.goto_deck_adding self.stats_button = Button() self.stats_button.text = "Stats" self.stats_button.size_hint = (1, None) self.stats_button.height = dp(50) self.stats_button.on_press = self.goto_stats self.manage_button = Button() self.manage_button.text = "Manage" self.manage_button.size_hint = (1, None) self.manage_button.height = dp(50) self.bottom_buttons.add_widget(self.new_deck_button) self.bottom_buttons.add_widget(self.stats_button) self.bottom_buttons.add_widget(self.manage_button) self.add_widget(self.bottom_buttons) self.top_loc = StackLayout() self.top_loc.orientation = "rl-tb" self.top_buttons = BoxLayout() self.settings_button = Button() self.settings_button.text = "Settings" self.settings_button.size_hint = (None, None) self.settings_button.size = (dp(100), dp(50)) self.settings_button.on_press = self.goto_settings self.search_button = Button() self.search_button.text = "Search" self.search_button.size_hint = (None, None) self.search_button.size = (dp(100), dp(50)) self.top_bar = TextInput() self.top_bar.multiline = False self.top_bar.hint_text = "Search Query" self.top_bar.size_hint = (None, None) self.top_bar.height = dp(50) self.top_bar.width = dp(500) self.top_bar.background_normal = '' self.top_bar.background_color = colors.GRAY self.top_bar.foreground_color = colors.WHITE self.top_bar.font_name = "Comfortaa" self.top_bar.font_size = 40 self.top_loc.add_widget(self.top_bar) self.top_loc.add_widget(self.search_button) self.top_loc.add_widget(self.settings_button) # self.top_loc.add_widget(self.top_buttons) self.add_widget(self.top_loc) def goto_settings(self): self.add_widget(SettingsPage()) def goto_deck_adding(self): self.add_widget(DeckAddPage()) def goto_stats(self): self.add_widget(StatsPage()) def load(self): try: for deck in self.acc_decks[:-1]: self.boxes.remove_widget(deck.cardview) except AttributeError: pass try: self.scroll.remove_widget(self.boxes) except AttributeError: pass self.init_boxes() for deck in self.acc_decks: deck.cardview.size_hint = (None, None) deck.cardview.size = (dp(self.cardWidth), dp(self.cardWidth * 1.5)) self.boxes.add_widget(deck.cardview) def init_boxes(self): self.boxes = StackLayout() self.boxes.bind(minimum_height=self.boxes.setter('height')) self.boxes.padding = dp(self.paddingSize) self.boxes.size_hint = (1, None) self.boxes.orientation = "lr-tb" self.boxes.spacing = dp(self.spacingSize) self.boxes.background_color = colors.PGREEN self.scroll.add_widget(self.boxes)
def build(self): alloc_data = budget_backend.get_allocations_by_period(self.year, self.month) trans_data = budget_backend.get_trans_summ_by_period(self.year, self.month) root = ScrollView(size_hint=(1,None), size=(Window.height, Window.width)) main_grid_layout = GridLayout(cols=7, spacing=10, size_hint_y=None, height=500) main_grid_layout.bind(minimum_height=main_grid_layout.setter('height')) main_box_layout = BoxLayout(orientation='vertical', size_hint_y=None) main_box_layout.bind(minimum_height=main_box_layout.setter('height')) top_stack_layout = StackLayout(size_hint_y=None, height=40) top_stack_layout.bind(minimum_height=top_stack_layout.setter('height')) back_btn = Button(text='Back', size_hint=(.1,None), height=40) back_btn.bind(on_press=lambda x: self.move_time_backward()) top_stack_layout.add_widget(back_btn) self.widget_dict['Time'] = Label(text='[b]' + self.month_name + ' ' + str(self.year) + '[/b]', size_hint=(.1,None), height=40, markup=True) top_stack_layout.add_widget(self.widget_dict['Time']) forward_btn = Button(text='Next', size_hint=(.1,None), height=40) forward_btn.bind(on_press=lambda x: self.move_time_forward()) top_stack_layout.add_widget(forward_btn) self.widget_dict['Status'] = Label(text='', size_hint=(0.15,None), height=40) top_stack_layout.add_widget(self.widget_dict['Status']) # status_bar = FloatLayout() # self.widget_dict['Status'] = Label(text='TEST', size_hint=(None,None), height=40, pos_hint={'right':1, 'center_y':0.5}) # status_bar.add_widget(self.widget_dict['Status']) # top_stack_layout.add_widget(status_bar) main_grid_layout.add_widget(Label(text='[b]Section[/b]', size_hint_y=None, height=80, font_size='20sp', markup=True)) main_grid_layout.add_widget(Label(text='[b]Category[/b]', size_hint_y=None, height=80, font_size='20sp', markup=True)) main_grid_layout.add_widget(Label(text='[b]Allocated[/b]', size_hint_y=None, height=80, font_size='20sp', markup=True)) main_grid_layout.add_widget(Label(text='[b]Spent[/b]', size_hint_y=None, height=80, font_size='20sp', markup=True)) main_grid_layout.add_widget(Label(text='', size_hint_y=None, height=80, font_size='20sp', markup=True)) main_grid_layout.add_widget(Label(text='', size_hint_y=None, height=80, font_size='20sp', markup=True)) main_grid_layout.add_widget(Label(text='', size_hint_y=None, height=80, font_size='20sp', markup=True)) for row in alloc_data.itertuples(): try: sum_trans_amt = trans_data.loc[trans_data['Category'] == row.Category, 'SumAmount'].iloc[0] except IndexError: sum_trans_amt = 0 if (row.Amount < sum_trans_amt): color_tag = '[color=#FF0040]' #red elif (row.Amount > sum_trans_amt): color_tag = '[color=#F7FE2E]' #yellow else: color_tag = '[color=#FFFFFF]' #white self.widget_dict['Section_' + row.Category] = Label(text=row.Section, size_hint_y=None, height=40) main_grid_layout.add_widget(self.widget_dict['Section_' + row.Category]) self.widget_dict['Label_' + row.Category] = Label(text=row.Category, size_hint_y=None, height=40) main_grid_layout.add_widget(self.widget_dict['Label_' + row.Category]) self.widget_dict['Alloc_' + row.Category] = Label(text=color_tag + str(row.Amount) + '[/color]', size_hint_y=None, height=40, markup=True) main_grid_layout.add_widget(self.widget_dict['Alloc_' + row.Category]) self.widget_dict['Trans_' + row.Category] = Label(text=color_tag + str(sum_trans_amt) + '[/color]', size_hint_y=None, height=40, markup=True) main_grid_layout.add_widget(self.widget_dict['Trans_' + row.Category]) self.widget_dict['Input_' + row.Category] = AllocationTextInput( size_hint_y=None, height=40, multiline=False, category=row.Category) self.widget_dict['Input_' + row.Category].bind(text=partial(update_btn_values, parent=self)) main_grid_layout.add_widget(self.widget_dict['Input_' + row.Category]) self.widget_dict['SetBtn_' + row.Category] = AllocationButton( text='Set', size_hint_y=None, height=40, category=row.Category) self.widget_dict['SetBtn_' + row.Category].bind( on_press=partial(change_allocation, arg_alloc_type='set', top_layout=self)) main_grid_layout.add_widget(self.widget_dict['SetBtn_' + row.Category]) self.widget_dict['AddBtn_' + row.Category] = AllocationButton( text='Add', size_hint_y=None, height=40, category=row.Category) self.widget_dict['AddBtn_' + row.Category].bind( on_press=partial(change_allocation, arg_alloc_type='add', top_layout=self)) main_grid_layout.add_widget(self.widget_dict['AddBtn_' + row.Category]) main_box_layout.add_widget(top_stack_layout) main_box_layout.add_widget(main_grid_layout) root.add_widget(main_box_layout) return root
def __init__(self, **kwargs): super(BookmarkList, self).__init__(**kwargs) scrollBox = ScrollView( do_scroll_x=False, ) self.add_widget(scrollBox) stack = StackLayout(size_hint=(1, None)) stack.bind( minimum_height=stack.setter('height') ) scrollBox.add_widget(stack) bookmarks = sorted(glob(f'{self.dataDir}/bookmarks/*.json'), key = os.path.getmtime)[::-1] for filename in bookmarks: bookmark = filename[len(f'{self.dataDir}/bookmarks/'):-5] label = LongpressButton( text = bookmark, height = self.settings['itemSize'], background_color = self.settings['sectionColor'], size_hint = (1, None), on_long_press = lambda w: edit(w), on_short_press = lambda w: choose(w) ) label.selected = False stack.add_widget(label) buttonBar = BoxLayout() self.add_widget(buttonBar) cancelBtn = ImageButton( source = 'data/delete.png', color_normal = self.settings['inactiveColor'], size_hint = (1, None), height = self.settings['headerSize'], on_release = lambda w: self.parent.parent.parent.dismiss(), ) deleteBtn = ImageButton( source = 'data/trash.png', color_normal = self.settings['inactiveColor'], size_hint = (1, None), height = self.settings['headerSize'], on_release = lambda w: deleteSelected(), ) buttonBar.add_widget(deleteBtn) buttonBar.add_widget(cancelBtn) def choose(item): selection = False for sibling in item.parent.children: if sibling.selected: selection = True break if selection: if item.selected: deselect(item) else: select(item) else: self.chosen = item.text self.parent.parent.parent.dismiss() def edit(w): editBox = BoxLayout( height = self.settings['itemSize'], size_hint = (1, None), ) entry = TextInput( text = w.text, multiline = False, on_text_validate = lambda w: updateItem(w), ) delete = ImageButton( size_hint_x = None, width = self.settings['itemSize'], source = 'data/trash.png', color_normal = self.settings['actionColor'], on_release = lambda w: selectItem(entry), ) ok = ImageButton( size_hint_x = None, width = self.settings['itemSize'], source = 'data/ok.png', color_normal = [0, .5, 0, 1], on_release = lambda w: updateItem(entry), ) editBox.add_widget(delete) editBox.add_widget(entry) editBox.add_widget(ok) entry.index = stack.children.index(w) entry.orig = w stack.add_widget(editBox, entry.index) stack.remove_widget(w) def remove_widgets(entry): for item in entry.children: entry.remove_widget(item) entry.parent.remove_widget(entry) def updateItem(entry): reservedChars = '[?:"*|/\\\<>]' entry.text = re.sub(reservedChars, '-', entry.text) os.rename(f'{self.dataDir}/bookmarks/{entry.orig.text}.json', f'{self.dataDir}/bookmarks/{entry.text}.json') entry.orig.text = entry.text stack.add_widget(entry.orig, entry.index) remove_widgets(entry.parent) def selectItem(entry): stack.add_widget(entry.orig, entry.index) select(entry.orig) remove_widgets(entry.parent) deleteBtn.color = self.settings['redColor'] def select(item): item.selected = True item.background_color = self.settings['actionColor'] def deselect(item): item.selected = False item.background_color = self.settings['sectionColor'] def deleteSelected(): for item in stack.children[:]: if item.selected: os.remove(f'{self.dataDir}/bookmarks/{item.text}.json') stack.remove_widget(item)
class FilePane(BoxLayout): tiles = None mainlayout = None slider = None startPath = None main = None count2 = 0 count = 0 total_size = 0 images = ['.jpeg', '.png', '.jpeg', '.bmp', '.dpx', '.exr', '.gif', '.ico', '.jpg2000', '.jpg', '.jls', '.pam', '.pbm', '.pcx', '.pgm', '.pgmyuv', '.pic', '.ppm', '.ptx', '.sgi', '.ras', '.tga', '.tiff', '.webp', '.xbm', '.xface', '.xwd'] def __init__(self, width, height, foldername, mainlayout): super(FilePane, self).__init__() # Add Option bar to top of right panel ----- #topOptionBar = RelativeLayout(size = (width, resY *.04), size_hint_y = None) self.size = (width, height) self.size_hint = (None,None) self.startPath = foldername self.auto_bring_to_front = False self.mainlayout = mainlayout self.orientation = 'horizontal' self.tiles = StackLayout(size = (width*.9, height), size_hint_x = None, padding=10, spacing=10) #print self.tiles.size #print self.tiles.minimum_height self.tiles.bind(minimum_height = self.tiles.setter('height')) self.add_widget(self.tiles) r = RelativeLayout(height = self.height) scrollbar = Slider(orientation = 'vertical') r.add_widget(scrollbar) self.add_widget(r) print self.tiles.height try: dirs = os.listdir( foldername ) # This would print all the files and directories for file in dirs: if(self.isImage(file)): self.addFile(self.startPath+ "\\" + file, file) except OSError: print OSError print "FilePane: no files found" print self.tiles.height scrollbar.range = (0, self.tiles.height) scrollbar.bind(value = self.updatePos) def updatePos(self, instance, value): self.tiles.y = value def on_touch_down(self, touch): if super(FilePane, self).on_touch_down(touch): return False if not self.collide_point(touch.x, touch.y): return False touch.grab(self) touch.ud[self] = True return False def isImage(self, file): for i in self.images: if(file.endswith(i)): return True def addFile(self, path, name): r = RelativeLayout(size_hint =(None,None)) file = FileWidget(path, name, self, r) r.add_widget(file) r.size = file.size self.total_size += r.size[1] self.tiles.height = self.total_size - self.height self.tiles.add_widget(r) def getMain(self): return self.mainlayout; def getRoot(self): return self.tiles
class DragTab(BoxLayout): def __init__(self,**kwargs): super(DragTab,self).__init__(**kwargs) #Base Layer is a BoxLayout #right-hand column is StackLayout, lefthand is a vertical box layout FreshColor=[0.2,0.65,0.8,0.85] SophColor=[0.2,0.65,0.8,0.75] JuniColor=[0.2,0.65,0.8,0.6] SeniColor=[0.2,0.65,0.8,0.45] self.scrollview = ScrollView(size=(400,400),size_hint=(0.3,1.0),scroll_timeout=10) self.courses = StackLayout(spacing=5,size_hint_y=None,orientation='rl-tb') self.courses.bind(minimum_height=self.courses.setter('height')) self.scrollview.add_widget(self.courses) self.lefthand=BoxLayout(orientation='vertical', size_hint=(.7,1)) self.Planner=GridLayout(size_hint=(1,.85),rows=2, cols=4, spacing=3) self.slot1=Semester(text="Fall "+ str(all_globals.user.grad_year-4), color=FreshColor) self.slot2=Semester(text="Fall "+ str(all_globals.user.grad_year-3), color=SophColor) self.slot3=Semester(text="Fall "+ str(all_globals.user.grad_year-2), color=JuniColor) self.slot4=Semester(text="Fall "+ str(all_globals.user.grad_year-1), color=SeniColor) self.slot5=Semester(text="Spring "+ str(all_globals.user.grad_year-3), color=FreshColor) self.slot6=Semester(text="Spring "+ str(all_globals.user.grad_year-2), color=SophColor) self.slot7=Semester(text="Spring "+ str(all_globals.user.grad_year-1), color=JuniColor) self.slot8=Semester(text="Spring "+ str(all_globals.user.grad_year), color=SeniColor) self.slots=[self.slot1, self.slot2, self.slot3, self.slot4, self.slot5, self.slot6, self.slot7, self.slot8] for sem_obj in self.slots: self.Planner.add_widget(sem_obj) self.lefthand.add_widget(self.Planner) self.stats_widget=BoxLayout(size_hint=(1, .15)) self.recycle=Button(size_hint=(.2, 1),background_normal='recycle.png',background_down='recycle.png')#,text= 'Recycle \n Course') self.stats=Label(size_hint=(1,1),color=(1,1,1,.3)) self.stats_widget.add_widget(self.recycle) self.stats_widget.add_widget(self.stats) self.lefthand.add_widget(self.stats_widget) #Now stuff it all in self.add_widget(self.lefthand) self.add_widget(self.scrollview) Clock.schedule_interval(self.update_stats_widget, .1) def add_Icon(self,course): Icon=DragableButton(course=course,text=course.keywords[0],height=100,size_hint_y=None, droppable_zone_objects=[], bound_zone_objects=[], kill_zone_objects=[], drag_opacity=.5, remove_on_drag=True) Icon.bound_zone_objects.append(self.Planner) Icon.bound_zone_objects.append(self.scrollview) Icon.bound_zone_objects.append(self.courses) Icon.bound_zone_objects.append(self.recycle) for sem in self.slots: Icon.add_droppable_zone(sem.coursehouse) Icon.droppable_zone_objects.append(self.scrollview) Icon.droppable_zone_objects.append(self.courses) Icon.kill_zone_objects.append(self.recycle) self.courses.add_widget(Icon) def update_stats_widget(self, dt): # When the user gets pre-credits as an attribute, we can stop writing over # Fixed=False all_globals.user.credits['AHSE'] = 0#course.course.pre_credits['AHSE'] all_globals.user.credits['ENGR'] = 0#course.course.pre_credits['ENGR'] all_globals.user.credits['MTH'] = 0#course.course.pre_credits['MTH'] all_globals.user.credits['SCI'] = 0#course.course.pre_credits['SCI'] all_globals.user.courses=[] for semester_obj in self.slots: for icon in semester_obj.coursehouse.children[:]: all_globals.user.courses.append(icon.course.code) all_globals.user.credits['AHSE'] += icon.course.credits['AHSE'] all_globals.user.credits['ENGR'] += icon.course.credits['ENGR'] all_globals.user.credits['MTH'] += icon.course.credits['MTH'] all_globals.user.credits['SCI'] += icon.course.credits['SCI'] self.stats_widget.remove_widget(self.stats) self.stats=Label(size_hint=(1,1),text='AHSE: '+str(all_globals.user.credits['AHSE'])+' '+'ENGR: '+str(all_globals.user.credits['ENGR'])+' '+'MTH: '+str(all_globals.user.credits['MTH'])+' '+'SCI: '+str(all_globals.user.credits['SCI'])+' ',color=(1,1,1,1)) print all_globals.user.courses self.stats_widget.add_widget(self.stats) for sem in self.slots: sem.Me.clear_widgets() adjust=4 for sem in self.slots[0:4]: sem.Me.add_widget(Label(text="Fall "+ str(all_globals.user.grad_year-adjust))) adjust-=1 adjust=3 for sem in self.slots[4:]: sem.Me.add_widget(Label(text="Spring "+ str(all_globals.user.grad_year-adjust))) adjust-=1
def __init__(self, **kwargs): super(CheckList, self).__init__(**kwargs) if platform == "android": from android.storage import primary_external_storage_path from android.permissions import request_permissions, check_permission, Permission sdcard = primary_external_storage_path() dataDir = sdcard + '/plocka' if not os.path.exists(dataDir): request_permissions([ Permission.READ_EXTERNAL_STORAGE, Permission.WRITE_EXTERNAL_STORAGE ]) while not check_permission(Permission.WRITE_EXTERNAL_STORAGE): time.sleep(1) else: dataDir = os.environ['HOME'] + '/.config/Plocka' os.makedirs(dataDir, exist_ok=True) scriptDir = os.path.dirname(os.path.realpath(__file__)) global shoppingList try: with open(dataDir + '/Plocka.json') as fd: shoppingList = json.load(fd) except: shoppingList = [{ "section": "Section 1", "items": [{ "item": "Item 1", "done": False }, { "item": "Item 2", "done": True }, { "item": "Item 3", "done": True }] }, { "section": "Section 2", "items": [{ "item": "Item 1", "done": True }, { "item": "Item 2", "done": False }, { "item": "Item 3", "done": False }, { "item": "Item 4", "done": True }] }, { "section": "Section 3", "items": [{ "item": "Item 1", "done": True }, { "item": "Item 2", "done": True }, { "item": "Item 3", "done": False }] }] defaultSettings = { 'headerSize': '40sp', 'sectionSize': '20sp', 'sectionColor': [0.1, 0.2, 0.2, 1], 'sectionTextSize': '10sp', 'itemSize': '30sp', 'itemColor': [0.20, 0.25, 0.29, 1], 'doneColor': [0.24, 0.30, 0.35, 1], 'actionColor': [.2, .7, .9, 1], 'activeColor': [1, 1, 1, 1], 'inactiveColor': [1, 1, 1, 0.5], 'redColor': [1, 0, 0, 0.5], 'greenColor': [0, 1, 0, 0.5], 'backupsToKeep': 10, 'maxBackupAge': 1, 'showSections': 'maybe', } try: with open(dataDir + '/settings.json') as fd: settings = json.load(fd) for key in defaultSettings: if not key in settings: settings[key] = defaultSettings[key] except: settings = defaultSettings backups = sorted(glob(f'{dataDir}/Plocka-*.json')) cutoff = ( datetime.now() - timedelta(days=settings['maxBackupAge'])).strftime("%Y%m%d%H%M%S") for backup in backups[:-settings['backupsToKeep']]: if backup < f'{dataDir}/Plocka-{cutoff}.json': print('deleting backup file ' + backup) os.remove(backup) def hide(widget): if widget.height: widget.restore = widget.height widget.height = 0 widget.opacity = 0 widget.disabled = True def unhide(widget): if widget.disabled: widget.height = widget.restore widget.opacity = 1 widget.disabled = False def checkSection(stack, current): for item in stack.children[::-1]: if item.type == 'section': section = item if item == current: break index = stack.children.index(section) for item in stack.children[index - 1::-1]: if item.type == 'item' and item.check.state == 'normal': return if item.type == 'section': break hide(section) self.writeDeferred = False def writeFile(dt): if dt and not self.writeDeferred: return self.writeDeferred = False activeList = [] for item in stack.children[::-1]: if item.type == 'item': entry = { "item": item.text, "done": item.check.state == 'down' } section["items"].append(entry) elif item.type == 'section': section = {"section": item.origText, "items": []} activeList.append(section) shoppingList['lists'][shoppingList['active']]['name'] = title.text shoppingList['lists'][shoppingList['active']]['list'] = activeList now = datetime.now().strftime("%Y%m%d%H%M%S") if os.path.exists(f'{dataDir}/Plocka.json'): os.rename(f'{dataDir}/Plocka.json', f'{dataDir}/Plocka-{now}.json') with open(f'{dataDir}/Plocka.json', 'w', encoding='utf8') as fd: json.dump(shoppingList, fd, indent=2, ensure_ascii=False) saveBtn.color = settings['greenColor'] def undo(instance): global shoppingList try: last = sorted(glob(f'{dataDir}/Plocka-*.json'))[-1] os.rename(last, f'{dataDir}/Plocka.json') with open(dataDir + '/Plocka.json') as fd: shoppingList = json.load(fd) populate() hideUnHide(hideBtn) except: pass def toggle(instance): if instance.check.state == 'down': instance.background_color = settings['itemColor'] instance.color = settings['activeColor'] instance.check.state = 'normal' else: instance.background_color = settings['doneColor'] instance.color = settings['inactiveColor'] instance.check.state = 'down' if not self.writeDeferred: self.writeDeferred = True saveBtn.color = settings['actionColor'] Clock.schedule_once(writeFile, 10) if hideBtn.state == 'down' and instance.check.state == 'down': hide(instance.check) hide(instance) checkSection(stack, instance) def hideUnHide(instance): if hideBtn.state != "down" and not searchInput.text: for item in stack.children[:]: unhide(item) elif searchInput.text == searchInput.text.upper( ) and searchInput.text != searchInput.text.lower(): activeSection = False for item in stack.children[::-1]: if item.type == 'section': if re.search(searchInput.text, item.text): activeSection = True else: activeSection = False if activeSection and ( hideBtn.state != 'down' or item.type != 'item' and item.type != 'check' or hideBtn.state == 'down' and item.type == 'check' and item.state != 'down' or hideBtn.state == 'down' and item.type == 'item' and item.check.state != 'down'): unhide(item) else: hide(item) else: hasChildren = False regexp = searchInput.text if searchInput.text else '.' for item in stack.children[:]: if item.type == 'item': if hideBtn.state == "down" and item.check.state == 'down' or not re.search( regexp, item.text, re.IGNORECASE): hide(item.check) hide(item) else: unhide(item.check) unhide(item) hasChildren = True elif item.type == 'section': if hasChildren and settings['showSections'] == 'always': unhide(item) hasChildren = False else: hide(item) def crossCheck(instance): toggle(instance.label) def edit(instance): entry = TextInput( text=instance.text, size_hint=(0.5, None), height=settings['itemSize'], multiline=False, on_text_validate=lambda w: updateItem(w), ) if instance.type == 'section': entry.text = instance.origText relative = ImageButton( source='data/left.png' if instance.type == 'item' else 'data/right.png', color_normal=[1, 1, 1, .7], height=settings['itemSize'], size_hint=(0.1, None), on_release=lambda w: updateItem(entry), ) before = ImageButton( source='data/up.png', color_normal=[1, 1, 1, .7], height=settings['itemSize'], size_hint=(0.1, None), on_release=lambda w: updateItem(entry), ) replace = ImageButton( source='data/ok.png', color_normal=[0, .5, 0, 1], height=settings['itemSize'], size_hint=(0.1, None), on_release=lambda w: updateItem(entry), ) after = ImageButton( source='data/down.png', color_normal=[1, 1, 1, .7], height=settings['itemSize'], size_hint=(0.1, None), on_release=lambda w: updateItem(entry), ) delete = ImageButton( source='data/delete.png', color_normal=[.5, 0, 0, 1], height=settings['itemSize'], size_hint=(0.1, None), on_release=lambda w: updateItem(entry), ) entry.orig = instance entry.relative = relative entry.before = before entry.replace = replace entry.after = after entry.delete = delete entry.type = 'entry' relative.type = 'relative' before.type = 'before' replace.type = 'replace' after.type = 'after' delete.type = 'delete' hide(instance) if instance.type == 'item': hide(instance.check) index = stack.children.index(instance) stack.add_widget(delete, index) stack.add_widget(entry, index) stack.add_widget(relative, index) stack.add_widget(before, index) stack.add_widget(replace, index) stack.add_widget(after, index) entry.select_all() Clock.schedule_once(lambda dt: reselect(entry), 0.5) def reselect(entry): # repeat select_all after half a second to avoid losing focus on release entry.focused = True entry.select_all() def updateItem(entry): todo = 'replace' if entry.delete.state == 'down': todo = 'delete' elif entry.before.state == 'down': todo = 'before' elif entry.after.state == 'down': todo = 'after' elif entry.relative.state == 'down': if entry.orig.type == 'section': todo = 'item' else: todo = 'section' orig = entry.orig text = entry.text stack.remove_widget(entry.relative) stack.remove_widget(entry.before) stack.remove_widget(entry.replace) stack.remove_widget(entry.after) stack.remove_widget(entry.delete) stack.remove_widget(entry) if todo == 'delete': stack.remove_widget(orig) if orig.type == 'item': stack.remove_widget(orig.check) else: unhide(orig) if orig.type == 'item': unhide(orig.check) if todo == 'replace': if orig.type == 'section': orig.origText = text orig.text = text.upper() else: orig.text = text else: if orig.type == 'section' and todo != 'item' or todo == 'section': label = sectionButton(text) else: label = itemButtonPair(text, False) index = stack.children.index(orig) if todo == 'before' or todo == 'section': index += 1 if orig.type == 'item': if todo == 'before' or todo == 'section': index += 1 if label.type == 'item': stack.add_widget(label.check, index) stack.add_widget(label, index) edit(label) writeFile(0) self.searchDeferred = False def doSearch(text, undo): if not self.searchDeferred: self.searchDeferred = True Clock.schedule_once(filterOut, 1) return text def filterOut(dt): self.searchDeferred = False hideUnHide(hideBtn) def setBookmark(): now = datetime.now().strftime("%Y-%m-%dT%H-%M-%S") os.makedirs(f'{dataDir}/bookmarks', exist_ok=True) print(f"set bookmark '{dataDir}/bookmarks/{now}.json'") shutil.copy(f'{dataDir}/Plocka.json', f'{dataDir}/bookmarks/{now}.json') bookmark = '' def getBookmark(): popup = Popup( title="Bookmarks", content=BookmarkList( dataDir=dataDir, settings=settings, orientation='vertical', ), size_hint=(0.9, 0.9), ) popup.bind(on_pre_dismiss=useBookmark) popup.open() def useBookmark(w): global shoppingList bookmark = w.content.chosen if not bookmark: print('no bookmark chosen') return writeFile(0) shutil.copy(f'{dataDir}/bookmarks/{bookmark}.json', f'{dataDir}/Plocka.json') with open(f'{dataDir}/Plocka.json') as fd: shoppingList = json.load(fd) populate() def selectList(w): global shoppingList dropdown = DropDown( on_select=lambda instance, selected: setActive(selected), ) index = -1 for item in shoppingList['lists']: index += 1 if index == shoppingList['active']: continue btn = Button( text=item['name'], size_hint_y=None, background_color=settings['sectionColor'], height=settings['itemSize'], ) btn.index = index btn.bind(on_release=lambda btn: dropdown.select(btn.index)) dropdown.add_widget(btn) about = Button( text="About Plocka", size_hint_y=None, background_color=settings['sectionColor'], height=settings['itemSize'], ) about.bind(on_release=lambda about: dropdown.select(-1)) dropdown.add_widget(about) dropdown.open(w) def setActive(selected): if selected > -1: global shoppingList shoppingList['active'] = selected populate() writeFile(0) else: with open(scriptDir + '/ABOUT.rst') as fd: about = fd.read() with open(scriptDir + '/LICENSE') as fd: license = fd.read() aboutText = RstDocument(text=about + '\n\nLicense\n-------\n\n' + license, ) popup = Popup( title="Plocka " + __version__, content=aboutText, ) popup.open() def editList(w): buttonBox = BoxLayout() top.add_widget(buttonBox) delete = ImageButton( source='data/delete.png', color_normal=[.5, 0, 0, 1], size_hint_x=None, width=settings['headerSize'], on_release=lambda w: deleteList(w), ) buttonBox.add_widget(delete) entry = TextInput( text=w.text, height=settings['headerSize'], multiline=False, on_text_validate=lambda w: setListName(w), ) buttonBox.add_widget(entry) saveBtn = ImageButton( source="data/ok.png", color_normal=settings['greenColor'], size_hint_x=None, width=settings['headerSize'], on_release=lambda x: setListName(entry), ) buttonBox.add_widget(saveBtn) copy = ImageButton( source='data/copy.png', color_normal=[1, 1, 1, .7], size_hint_x=None, width=settings['headerSize'], on_release=lambda w: copyList(w), ) buttonBox.add_widget(copy) new = ImageButton( source='data/new.png', color_normal=settings['greenColor'], size_hint_x=None, width=settings['headerSize'], on_release=lambda w: createList(entry), ) buttonBox.add_widget(new) top.remove_widget(title) top.remove_widget(searchBtn) entry.focused = True def closeEditor(w): top.add_widget(title) top.add_widget(searchBtn) top.remove_widget(w.parent) def setListName(w): title.text = w.text closeEditor(w) writeFile(0) def createList(w): global shoppingList new = { 'name': 'New list', 'list': [{ 'section': 'Section', 'items': [] }] } at = shoppingList['active'] + 1 shoppingList['lists'].insert(at, new) setActive(at) closeEditor(w) def copyList(w): global shoppingList at = shoppingList['active'] new = json.loads(json.dumps(shoppingList['lists'][at])) new['name'] += ' 2' at += 1 shoppingList['lists'].insert(at, new) setActive(at) closeEditor(w) def deleteList(w): at = shoppingList['active'] del (shoppingList['lists'][at]) if at >= len(shoppingList['lists']): at = at - 1 setActive(at) closeEditor(w) # Widgets def sectionButton(text): label = LongpressButton( text=text.upper(), font_size=settings['sectionTextSize'], height=settings['sectionSize'], background_color=settings['sectionColor'], size_hint=(1, None), on_long_press=lambda w: edit(w), ) label.origText = text label.type = 'section' return label def itemButtonPair(text, done): label = LongpressButton( text=text, height=settings['itemSize'], background_color=settings['itemColor'], size_hint=(0.95, None), on_short_press=lambda w: toggle(w), on_long_press=lambda w: edit(w), ) label.type = 'item' check = CheckBox( height=settings['itemSize'], size_hint=(0.05, None), on_release=lambda w: crossCheck(w), ) if done: label.background_color = settings['doneColor'] label.color = settings['inactiveColor'] check.state = 'down' check.type = 'check' check.label = label label.check = check return label def populate(): global shoppingList if not 'lists' in shoppingList: shoppingList = { 'lists': [{ 'name': 'Plocka', 'list': shoppingList }] } if not 'active' in shoppingList: shoppingList['active'] = 0 title.text = shoppingList['lists'][shoppingList['active']]['name'] stack.clear_widgets() for section in shoppingList['lists'][ shoppingList['active']]['list']: if settings['showSections'] != 'never': sectionLabel = sectionButton(section['section']) stack.add_widget(sectionLabel) for item in section['items']: label = itemButtonPair(item['item'], item['done']) stack.add_widget(label.check) stack.add_widget(label) def toggleSearch(widget): if searchInput.disabled: top.add_widget(searchInput, 1) searchInput.disabled = False searchInput.focused = True else: searchInput.text = '' searchInput.disabled = True top.remove_widget(searchInput) hideUnHide(hideBtn) # MAIN top = BoxLayout( size_hint=(1, None), height=settings['headerSize'], ) self.add_widget(top) title = LongpressButton( text='Unknown', background_color=settings['sectionColor'], on_short_press=selectList, on_long_press=editList, ) top.add_widget(title) searchBtn = ImageButton( source='data/search.png', width=settings['headerSize'], color_normal=[1, 1, 1, .6], on_release=toggleSearch, size_hint_x=None, ) top.add_widget(searchBtn) searchInput = TextInput( disabled=True, multiline=False, input_filter=doSearch, on_text_validate=lambda w: hideUnHide(hideBtn), ) scrollBox = ScrollView( size_hint=(1, .9), do_scroll_x=False, ) self.add_widget(scrollBox) stack = StackLayout(size_hint=(1, None)) stack.bind(minimum_height=stack.setter('height')) scrollBox.add_widget(stack) populate() buttons = BoxLayout( size_hint=(1, None), height=settings['headerSize'], ) self.add_widget(buttons) saveBtn = ImageButton( source="data/ok.png", color_normal=settings['greenColor'], on_release=lambda x: writeFile(0), ) buttons.add_widget(saveBtn) hideBtn = ToggleImageButton( image_down="data/show.png", image_normal="data/hide.png", color_down=[1, 1, 1, .9], color_normal=[1, 1, 1, .6], on_release=hideUnHide, ) buttons.add_widget(hideBtn) undoBtn = ImageButton( source='data/undo.png', color_normal=settings['redColor'], on_release=undo, ) buttons.add_widget(undoBtn) bookmarkBtn = LongpressImageButton( source='data/bookmark.png', color_normal=settings['greenColor'], on_short_press=lambda w: setBookmark(), on_long_press=lambda w: getBookmark(), ) buttons.add_widget(bookmarkBtn)