def __init__(self, master, pikax_handler): super().__init__(master, pikax_handler) self.grid_height = 10 self.grid_width = 1 # create buttons self.rank_button = self.make_button(text=texts.get('MENU_RANK')) self.search_button = self.make_button(text=texts.get('MENU_SEARCH')) self.illustration_button = self.make_button(text=texts.get('MENU_ID')) self.artist_button = self.make_button(text=texts.get('MENU_ARTIST')) self.back_button = self.make_button(text=texts.get('MENU_BACK')) self.rank_button_id = self.add_widget(widget=self.rank_button, row=2) self.search_button_id = self.add_widget(widget=self.search_button, row=3) self.illustration_button_id = self.add_widget( widget=self.illustration_button, row=4) self.artist_button_id = self.add_widget(widget=self.artist_button, row=5) self.back_button_id = self.add_widget(widget=self.back_button, row=7) self.buttons = [ self.rank_button, self.illustration_button, self.search_button, self.back_button ] self.config_buttons() self.grid(self.frame)
def __init__(self, master, pikax_handler): super().__init__(master, pikax_handler) self.grid_width = 20 self.grid_height = 18 self.id_or_url_text_id = self.add_text(text=texts.get('ILLUSTRATION_ID_OR_URL'), row=4, column=9, columnspan=2) self.id_or_url_input = self.make_text(height=10) self.id_or_url_input_id = self.add_widget(widget=self.id_or_url_input, row=8, column=9, columnspan=2) # buttons self.download_button = self.make_button(text=texts.get('ILLUSTRATION_DOWNLOAD')) self.download_button_id = self.add_widget(widget=self.download_button, row=13, column=11) self.back_button = self.make_button(text=texts.get('ILLUSTRATION_BACK')) self.back_button_id = self.add_widget(widget=self.back_button, row=13, column=8) self.output = self.make_download_output() self.output_id = self.add_text(text='', row=15, column=9, columnspan=2, font=self.output_font) self.redirect_output_to(self.output_id, text_widget=False) self.download_button.configure(command=self.download_clicked) self.back_button.configure(command=self.back_clicked) self.download_thread = None self.id_or_url_input.focus_set() self.restore_prev() self.grid(self.frame)
def get_canvas_location(self, row, column, rowspan, columnspan): if row < 0 or row > self.grid_height: raise ValueError( texts.get('MODELS_INVALID_ROW_ERROR').format( row=row, grid_height=self.grid_height)) if column < 0 or column > self.grid_width: raise ValueError( texts.get('MODELS_INVALID_COLUMN_ERROR').format( column=column, grid_width=self.grid_width)) if row + rowspan < 0 or row + rowspan > self.grid_height: raise ValueError( texts.get('MODELS_INVALID_ROWSPAN_ERROR').format( rowspan=rowspan, row=row, grid_height=self.grid_height)) if column + columnspan < 0 or column + columnspan > self.grid_width: raise ValueError( texts.get('MODELS_INVALID_COLUMNSPAN_ERROR').format( columnspan=columnspan, column=column, grid_width=self.grid_width)) row_height = self.height / self.grid_height column_width = self.width / self.grid_width row_start = row_height * row row_end = row_height * (row + rowspan) height = (row_end + row_start) / 2 column_start = column_width * column column_end = column_width * (column + columnspan) width = (column_start + column_end) / 2 return width, height
def print_done(self, msg=None): if msg: if self.is_first_print: log(f' [ {texts.get("DONE")} ] => {msg}', normal=True) else: log(' [ {done} ] => {0:.2f}{s} \n{msg}'.format( time.time() - self.start_time, msg=msg, s=texts.get('SECOND'), done=texts.get("DONE")), normal=True) else: if self.is_first_print: log(f' [ {texts.get("DONE")} ]', normal=True) else: log(' [ {done} ] => {0:.2f}{s}'.format(time.time() - self.start_time, s=texts.get('SECOND'), done=texts.get("DONE")), normal=True) self.is_first_print = True self.start_time = None self.last_percent = None self.last_percent_print_time = None self.last_percent_time_left = None self.last_printed_line = None self.est_time_lefts = [0, 0, 0]
def download_clicked(self, _=None): limit_input = self.limit_entry.get() date_input = self.date_entry.get() type_input = self.type_dropdown.get() content_input = self.content_dropdown.get() limit_type = self.limit_text_entry.get() folder = self.download_folder_entry.get() try: if folder: folder = str(folder) if folder != clean_filename(folder): raise ValueError(texts.get('RANK_INVALID_FOLDER_ERROR')) else: folder = None rank_params = self.check_input(limit=limit_input, date=date_input, rank_type=type_input, content=content_input, limit_type=limit_type) rank_params['folder'] = folder download(target=self.pikax_handler.rank, kwargs=rank_params) except ValueError as e: import sys sys.stdout.write( texts.get('RANK_ERROR_MESSAGE').format(error_message=str(e)))
def search_and_download_clicked(self, _=None): try: keyword = str(self.keyword_entry.get()) if not keyword: raise ValueError(texts.get('SEARCH_EMPTY_KEYWORD_ERROR')) folder_input = str(self.download_folder_entry.get()) if folder_input != clean_filename(folder_input): raise ValueError(texts.get('SEARCH_INVALID_FOLDER_ERROR')) folder = folder_input or None try: limit_input = int( self.limit_entry.get()) if self.limit_entry.get() else None except ValueError: raise ValueError(texts.get('SEARCH_LIMIT_ERROR')) match_input = str(self.match_dropdown.get()) sort_input = str(self.sort_dropdown.get()) popularity_input = str(self.popularity_dropdown.get()) limit_type_input = str(self.limit_text_entry.get()) params = self.check_inputs(limit_input=limit_input, match_input=match_input, sort_input=sort_input, popularity_input=popularity_input, limit_type_input=limit_type_input) except (TypeError, ValueError) as e: sys.stdout.write( texts.get('SEARCH_ERROR_MESSAGE').format(error_message=str(e))) return params['keyword'] = keyword params['folder'] = folder download(target=self.pikax_handler.search, kwargs=params)
def __init__(self, target, args=None, kwargs=None): if kwargs is None: kwargs = dict() import texts if kwargs: texts.LANG = kwargs['lang'] del kwargs['lang'] self.window = tk.Tk() self.width = settings.DOWNLOAD_WINDOW_WIDTH self.height = settings.DOWNLOAD_WINDOW_HEIGHT config_root(root=self.window, title=texts.get('FRAME_TITLE'), width=self.width, height=self.height) super().__init__(self.window, pikax_handler=None) self.grid_width = 3 # add using the old grid height so that report button and cancel button are on the same height self.cancel_button = self.make_button( text=texts.get('DOWNLOADER_CANCEL')) self.cancel_button_id = self.add_widget(widget=self.cancel_button, column=1, row=self.grid_height - 30) self.grid_height = 9 self.text_font = font.Font(family=settings.DEFAULT_FONT_FAMILY, size=settings.DEFAULT_FONT_SIZE - 2) self.display_area_height = 6 self.end_display_area_height = 14 self.display_area_width = 75 self.display_area = self.make_text() self.display_area_id = self.add_widget(widget=self.display_area, row=4, column=0, columnspan=3) # configure # remove language button, not in use self.language_button.destroy() self.config() self.grid(self.frame) self.window.grab_set() self.download_thread = DownloadThread( target=target, args=args, kwargs=kwargs, output_area=self.display_area, button=self.cancel_button, end_height=self.end_display_area_height) self.download_thread.start() self.window.mainloop()
def _get_ids(self, next_url, limit, id_type): import sys if limit: limit = int(limit) data_container_name = params.Type.get_response_container_name( id_type.value) ids_collected = [] while next_url is not None and (not limit or len(ids_collected) < limit): res_data = self.req(next_url).json() if id_type is params.Type.USER: ids_collected += [ item['user']['id'] for item in res_data[data_container_name] ] else: ids_collected += [ item['id'] for item in res_data[data_container_name] ] next_url = res_data['next_url'] ids_collected = list(set(ids_collected)) limit_str = "/ " + str(limit) if limit else "" sys.stdout.write( texts.get('API_ID_COLLECTED').format( ids_len=len(ids_collected), limit_str=limit_str)) if limit: ids_collected = util.trim_to_limit(ids_collected, limit) return ids_collected
def set(self, value): if value not in self.values: raise AttributeError( texts.get('MODELS_SWITCHBUTTON_INVALID_SET_VALUE').format( value=value, values=self.values)) self.curr_index = self.values.index(value) self.configure(text=value)
def login(self, username, password): status, client = LoginHandler().android_login(username, password) if status is LoginHandler.LoginStatus.ANDROID: self.pikax.logged_client = client self.logged = True else: raise PikaxException(texts.get('PIKAX_FAILED_LOGIN'))
def run(self): super().run() self.button.configure(text=texts.get('DOWNLOADER_DONE')) if isinstance(self.output_area, tk.Text): self.output_area.see(0.0) if self.end_height: self.output_area.configure(height=int(self.end_height))
def _get_params(self): artist_id_search = re.findall(r'\d+', str(self.id_or_url_input.get()), re.S) limit = self.limit_entry.get().strip() likes_more_than = self.likes_entry.get().strip() if not limit: limit = None else: limit = int(limit) if not likes_more_than: likes_more_than = None else: likes_more_than = int(likes_more_than) folder = self.download_folder_entry.get() if len(artist_id_search) < 1: raise ValueError(texts.get('ARTIST_NO_ID_FOUND')) elif len(artist_id_search) > 1: raise ValueError(texts.get('ARTIST_AMBIGUOUS_ID_FOUND')) else: # ['Illustrations', 'Mangas', 'Bookmarks'] content_input = self.content_switchbutton.get() if content_input == self.content_switch_values[0]: content = params.ContentType.ILLUST elif content_input == self.content_switch_values[1]: content = params.ContentType.MANGA else: content = params.ContentType.BOOKMARK artist_id = artist_id_search[0] return { 'artist_id': artist_id, 'folder': str(folder), 'limit': limit, 'content': content, 'likes': likes_more_than, # ['pages limit', 'artworks limit'] 'pages_limit': texts.get('LIMIT_CHOICES')[0] == self.limit_text_entry.get() }
def print_progress(self, curr, total, title=None, msg=None): curr_percent = math.floor(curr / total * 100) curr_time = time.time() if self.is_first_print: est_time_left = float("inf") self.is_first_print = False self.last_percent_time_left = est_time_left self.last_percent_print_time = curr_time self.start_time = time.time() elif self.last_percent == curr_percent: est_time_left = self.last_percent_time_left else: bad_est_time_left = (curr_time - self.last_percent_print_time) / ( curr_percent - self.last_percent) * (100 - curr_percent) self.est_time_lefts.append(bad_est_time_left) self.est_time_lefts = self.est_time_lefts[1:] percent_left = 100 - curr_percent percent_diff = curr_percent - self.last_percent chunk_left = round(percent_left / percent_diff) if chunk_left < len(self.est_time_lefts): est_time_left = sum(self.est_time_lefts[-chunk_left:] ) / chunk_left if chunk_left != 0 else 0.00 else: est_time_left = sum(self.est_time_lefts) / len( self.est_time_lefts) self.last_percent_time_left = est_time_left self.last_percent_print_time = curr_time self.last_percent = curr_percent if est_time_left != 0.0: progress_text = '{0} / {1} => {2}% | {3} {4:.2f}{5}'.format( curr, total, curr_percent, texts.get('TIME_LEFT_EST'), est_time_left, texts.get('SECOND')) else: progress_text = '{0} / {1} => {2}% '.format( curr, total, curr_percent) if msg: progress_text = progress_text + ' | ' + str(msg) progress_text = '\n'.join(progress_text.split('|')) if title: progress_text = title + '\n\n' + progress_text log(progress_text, end='', start=settings.CLEAR_LINE, inform=True) self.last_printed_line = progress_text
def download_by_illust_ids(self, illust_ids): try: artworks, fails = self.pikax.get_id_processor().process(ids=illust_ids, process_type=params.ProcessType.ILLUST) result = DefaultPikaxResult(artworks, download_type=params.DownloadType.ILLUST) self.pikax.download(result) except ArtworkError as e: sys.stdout.write(texts.get('PIKAX_ILLUST_ID_FAILED').format(error=e))
def load_from_local(file_path): try: with open(file_path, 'rb') as file: return pickle.load(file) except pickle.UnpicklingError as e: sys.stdout.write( texts.get('FILE_CORRUPTED').format(file=file_path, msg=str(e))) remove_local_file(file_path) return None
def main(): root = tk.Tk() config_root(root=root, title=texts.get('FRAME_TITLE'), width=settings.MAIN_WINDOW_WIDTH, height=settings.MAIN_WINDOW_HEIGHT) login_screen = LoginScreen(master=root, pikax_handler=PikaxHandler()) restore_data(login_screen) root.mainloop()
def download_clicked(self): self.canvas.itemconfigure(self.output_id, text='') user_input = self.id_or_url_input.get(0.0, tk.END) search_ids = re.findall(r'(?<!\d)\d{8}(?!\d)', user_input, re.S) if search_ids: params = {'illust_ids': search_ids} download(target=self.pikax_handler.download_by_illust_ids, kwargs=params) else: sys.stdout.write(texts.get('ILLUSTRATION_NO_ID_FOUND'))
def search(self, keyword, limit, sort, match, popularity, folder, pages_limit): try: old_limit = settings.MAX_PAGES_PER_ARTWORK if pages_limit: settings.MAX_PAGES_PER_ARTWORK = 1 result = self.pikax.search(keyword=keyword, limit=limit, sort=sort, match=match, popularity=popularity) self.pikax.download(result, folder) settings.MAX_PAGES_PER_ARTWORK = old_limit except PikaxException as e: import sys sys.stdout.write(texts.get('PIKAX_SEARCH_FAILED').format(error=e))
def rank(self, rank_type, limit, date, content, folder, pages_limit): try: old_limit = settings.MAX_PAGES_PER_ARTWORK if pages_limit: settings.MAX_PAGES_PER_ARTWORK = 1 result = self.pikax.rank(rank_type=rank_type, limit=limit, date=date, content=content) self.pikax.download(result, folder=folder) settings.MAX_PAGES_PER_ARTWORK = old_limit except PikaxException as e: import sys sys.stdout.write(texts.get('PIKAX_RANK_FAILED').format(error=e))
def check_input(self, limit, date, rank_type, content, limit_type): try: if limit: limit = int(limit) else: limit = None except ValueError: raise ValueError(texts.get('RANK_LIMIT_ERROR')) matcher = re.compile(r'^\d{8}$') if not matcher.match(date): raise ValueError(texts.get('RANK_DATE_ERROR')) # ['daily', 'weekly', 'monthly', 'rookie'] rank_types = texts.get('RANK_TYPES') if rank_type == rank_types[2]: rank_type = params.RankType.MONTHLY elif rank_type == rank_types[1]: rank_type = params.RankType.WEEKLY elif rank_type == rank_types[3]: rank_type = params.RankType.ROOKIE else: # daily rank_type = params.RankType.DAILY # ['illustration', 'manga'] content_types = texts.get('RANK_CONTENT_TYPES') if content == content_types[1]: content = params.Content.MANGA else: # illustration content = params.Content.ILLUST return { 'limit': limit, 'date': date, 'content': content, 'rank_type': rank_type, # ['pages limit', 'artworks limit'] 'pages_limit': limit_type == texts.get('LIMIT_CHOICES')[0] }
def render_commands(): commands_dict = texts.get() with open(COMMANDS_TEMPLATE) as f: template = jinja2.Template(f.read()) context = { 'commands': [command for command, args in commands_dict.items() if args], } code = template.render(context) with open(COMMANDS_OUTPUT, 'w') as f: f.write(code)
def __init__(self, master, pikax_handler): super().__init__(master, pikax_handler) # settings # sizes self.grid_height = 30 self.grid_width = 11 # text self.username_text = texts.get('LOGIN_USERNAME') self.password_text = texts.get('LOGIN_PASSWORD') self.login_button_text = texts.get('LOGIN_LOGIN_BUTTON') self.guest_button_text = texts.get('LOGIN_GUEST_BUTTON') self.register_text = texts.get('LOGIN_REGISTER_BUTTON') # make entries & button self.username_entry = self.make_entry() self.password_entry = self.make_entry() self.login_button = self.make_button(text=self.login_button_text) self.guest_button = self.make_button(text=self.guest_button_text) self.register_button = self.make_button(text=self.register_text) # add text self.canvas_username = self.add_text(text=self.username_text, row=9, column=4, columnspan=3) self.canvas_password = self.add_text(text=self.password_text, row=14, column=4, columnspan=3) # add entries & button to canvas self.username_entry_id = self.add_widget(widget=self.username_entry, row=11, column=4, columnspan=3) self.password_entry_id = self.add_widget(widget=self.password_entry, row=16, column=4, columnspan=3) self.guest_button_id = self.add_widget(widget=self.guest_button, row=20, column=3) self.login_button_id = self.add_widget(widget=self.login_button, row=20, column=5) self.register_button_id = self.add_widget(widget=self.register_button, row=20, column=7) self.output_id = self.add_text(text='', row=26, column=4, columnspan=3, font=self.output_font) # add checkbox self.remember_me_checkbox = self.make_checkbutton(text=texts.get('LOGIN_REMEMBER_TEXT')) self.remember_me_checkbox_id = self.add_widget(widget=self.remember_me_checkbox, row=24, column=5) self.config_buttons() self.config_output() self.config_entries() self.grid(self.frame) self.username_entry.focus_set() # # default operations # self.restore_previous()
def _rank(cls, rank_params, limit): import sys ids = [] page_num = 0 while True: page_num += 1 rank_params['p'] = page_num try: res = util.req(url=cls.url, params=rank_params).json() except ReqException as e: util.log(str(e), error=True, save=True) util.log('End of rank at page:', page_num, inform=True, save=True) break if 'error' in res: util.log('End of page while searching', str(rank_params) + '. Finished') break else: ids += [content['illust_id'] for content in res['contents']] limit_str = "/ " + str(limit) if limit else "" sys.stdout.write( texts.get('API_ID_COLLECTED').format(ids_len=len(ids), limit_str=limit_str)) # check if number of ids reached requirement if limit: num_of_ids_found = len(ids) if limit == num_of_ids_found: break elif limit < num_of_ids_found: ids = util.trim_to_limit(ids, limit) break return ids
def render_options(): commands_dict = texts.get() options_dict = {} for command, args in commands_dict.items(): if not args: continue options_dict[command] = options = [] serial = 0 group_keys = defaultdict(set) for group, arg in enumerate(args): text = fixers.regex_replace(arg, command) tmp = analyzers.parse(text) for order, o in enumerate(tmp): options += [{ **o, 'group': group, 'order': order, 'serial': serial }] serial += 1 group_keys[group].update(o['keys']) for option in options: invalid_serials = set() for group, keys in group_keys.items(): if not keys.issuperset(option['keys']): invalid_serials.update( {o['serial'] for o in options if o['group'] == group}) option['invalid_serials'] = invalid_serials with open(OPTIONS_TEMPLATE) as f: template = jinja2.Template(f.read()) context = {'options_dict': options_dict} code = template.render(context) with open(OPTIONS_OUTPUT, 'w') as f: f.write(code)
def check_inputs(self, limit_input, match_input, sort_input, popularity_input, limit_type_input): from pikax import params # ['exact', 'partial', 'any'] match choices # ['date ascending', 'date descending'] sort # ['any', '100', '500', '1000', '5000', '10000', '20000'] popularity if not limit_input or limit_input == self.match_choices[2]: limit = None else: limit = int(limit_input) if not match_input or match_input == self.match_choices[2]: match = params.Match.ANY elif match_input == self.match_choices[0]: match = params.Match.EXACT else: match = params.Match.PARTIAL if not sort_input or sort_input == self.sort_choices[1]: sort = params.Sort.DATE_DESC else: sort = params.Sort.DATE_ASC if not popularity_input or popularity_input == self.match_choices[2]: popularity = None else: popularity = int(popularity_input) return { 'limit': limit, 'sort': sort, 'match': match, 'popularity': popularity, # ['pages limit', 'artworks limit'] 'pages_limit': limit_type_input == texts.get('LIMIT_CHOICES')[0] }
def make_limit_text_entry(self): limit_choices = texts.get('LIMIT_CHOICES') limit_text_entry = self.make_switchbutton(limit_choices, default=limit_choices[0], width=PikaxButton.width) return limit_text_entry
def __init__(self, master, pikax_handler): super().__init__(master, pikax_handler) self.grid_width = 15 self.grid_height = 10 # texts self.date_text_id = self.add_text(text=texts.get('RANK_DATE'), row=2, column=5) self.limit_text_entry = self.make_limit_text_entry() self.limit_text_entry_id = self.add_widget( widget=self.limit_text_entry, row=3, column=5) self.type_text_id = self.add_text(text=texts.get('RANK_TYPE'), row=4, column=5) self.content_text_id = self.add_text(text=texts.get('RANK_CONTENT'), row=5, column=5) self.download_folder_text_id = self.add_text( text=texts.get('RANK_DOWNLOAD_FOLDER'), row=6, column=5) # create inputs self.date_entry = self.make_entry() self.date_entry.insert(0, format(date.today(), '%Y%m%d')) self.limit_entry = self.make_entry() self.rank_types = texts.get('RANK_TYPES') self.type_dropdown = self.make_dropdown(self.rank_types[0], self.rank_types) self.content_types = texts.get('RANK_CONTENT_TYPES') self.content_dropdown = self.make_dropdown(self.content_types[0], self.content_types) self.download_folder_entry = self.make_entry() # add inputs self.date_entry_id = self.add_widget(widget=self.date_entry, row=2, column=9) self.limit_entry_id = self.add_widget(widget=self.limit_entry, row=3, column=9) self.type_dropdown_id = self.add_widget(widget=self.type_dropdown, row=4, column=9) self.content_dropdown_id = self.add_widget( widget=self.content_dropdown, row=5, column=9) self.download_folder_entry_id = self.add_widget( widget=self.download_folder_entry, row=6, column=9) # create buttons self.back_button = self.make_button(text=texts.get('RANK_BACK')) self.download_button = self.make_button( text=texts.get('RANK_DOWNLOAD')) # add buttons self.back_button_id = self.add_widget(widget=self.back_button, row=7, column=5) self.download_button_id = self.add_widget(self.download_button, row=7, column=9) # output self.output_id = self.add_text(text='', row=8, column=5, columnspan=4, font=self.output_font) self.redirect_output_to(self.output_id, text_widget=False) # config self.config() self.restore_prev() self.grid(self.frame)
def set(self, value=False): self.checked = value text = texts.get( 'TICK') + ' ' + self.text if self.checked else texts.get( 'CROSS') + ' ' + self.text self.configure(text=text)
def download(self, pikax_result: PikaxResult, folder: str = ''): from common import concurrent_download if not folder: folder = pikax_result.folder folder = util.clean_filename(folder) if folder and not os.path.isdir(folder): os.mkdir(folder) download_function = self.download_type_to_function[ pikax_result.download_type] download_function = functools.partial(download_function, folder=folder) artworks = pikax_result.artworks total_pages = sum(len(artwork) for artwork in artworks) total_artworks = len(artworks) manager = mp.Manager() curr_artwork = manager.Value('i', 0) curr_page = manager.Value('i', 0) successes = manager.list() fails = manager.list() skips = manager.list() target = functools.partial( self.download_func, target=download_function, curr_artwork=curr_artwork, curr_page=curr_page, total_pages=total_pages, total_artworks=total_artworks, successes=successes, fails=fails, skips=skips, ) util.log(texts.get('DOWNLOAD_INITIALIZING').format( total_pages=total_pages, total_artworks=total_artworks), start=os.linesep, inform=True) concurrent_download(target=target, items=pikax_result.artworks) util.print_done() finish_msg = '' finish_msg += texts.get('DOWNLOAD_FINISHED_SUCCESS_PAGES').format( successes=len(successes)) finish_msg += texts.get('DOWNLOAD_FINISHED_SKIPPED_PAGES').format( skips=len(skips)) for index, skip_info in enumerate(skips): finish_msg += texts.get('DOWNLOAD_FINISHED_SKIPPED_INFO').format( counter=index + 1, skip_info=str(skip_info)) finish_msg += texts.get('DOWNLOAD_FINISHED_FAILED_PAGES').format( fails=len(fails)) for index, fail_info in enumerate(fails): finish_msg += texts.get('DOWNLOAD_FINISHED_FAILED_INFO').format( counter=index + 1, fail_info=str(fail_info)) download_path = os.path.abspath(folder) folder_msg = texts.get('DOWNLOAD_FINISHED_PATH_NOTICE').format( download_path=download_path) util.print_done(str(finish_msg + folder_msg))
def __init__(self, master, pikax_handler): self.master = master self.frame = self.make_frame(borderwidth=0, highlightthickness=0) if 'frames' not in master.__dict__: master.frames = dict() master.frames[self.__class__.__name__] = self.frame self.pikax_handler = pikax_handler # this update is important when opening another different window, else winfo width & height will return 1 self.master.update() # # settings # # colors self.title_color = '#51abc2' self.artist_name_color = '#1b5361' self.text_color = '#51abc2' # sizes self.width = self.master.winfo_width() self.height = self.master.winfo_height() self.grid_height = self.height self.grid_width = self.width self.title_font_size = 12 # texts self.issue_text = texts.get('MODELS_ISSUE_TEXT') self.title_text = texts.get('TITLE_TEXT') # font self.text_font = font.Font(family=settings.DEFAULT_FONT_FAMILY, size=settings.DEFAULT_FONT_SIZE, weight=font.BOLD) self.canvas_artist_font = font.Font(family='Courier', size=10) self.output_font = font.Font(family=settings.DEFAULT_FONT_FAMILY, size=settings.DEFAULT_FONT_SIZE - 4) # # default operations # # add canvas background self.canvas = self.set_canvas(image_path=get_background_file_path(), focus=tk.CENTER) # add title title_font = font.Font(family='Arial', size=self.title_font_size, weight=font.BOLD) self.canvas_title = self.add_text(text=self.title_text, font=title_font, row=20, column=60, columnspan=2, color=self.title_color) # add issue button self.issue_button = self.make_button(text=self.issue_text) self.issue_button_id = self.add_widget(widget=self.issue_button, row=self.grid_height - 30, column=self.grid_width - 75) self.issue_button.configure(command=self.issue_button_pressed) # add language button self.language_button = self.make_switchbutton(values=texts.LANGS, default=texts.LANG) self.language_button.configure(width=PikaxButton.width) self.language_button_id = self.add_widget(widget=self.language_button, row=self.grid_height - 30, column=self.grid_width - 250) self.language_button.bind('<Button-1>', self.language_button_clicked, add='+') # add background artist reference self.artist_reference = self.add_text( text=texts.get('MODELS_ARTIST_REFERENCE_TEXT').format( artist_name=settings.CANVAS_BACKGROUND_ARTIST_NAME), row=self.grid_height - 26, column=100, columnspan=2, font=self.canvas_artist_font, color=self.artist_name_color)