def onInit(self): # pylint: disable=invalid-name self.set_info() self.prepare_progress_control() if get_setting_bool('stopAfterClose'): self.getControl(3013).setLabel(localize(30033)) # Stop else: self.getControl(3013).setLabel(localize(30034)) # Close
def open_menu(self, widget, event): if self.disabled: return if event.button in (1, 2, 3): # Clicked the popup menu indicator if self.__enable_popup and self.__popup_hover: self.__menu = Gtk.Menu() if self.__have_desktop_dir: # Can't do this without the desktop directory desktop_item = Gtk.MenuItem( utils.localize(STRINGS['popup_add_to_desktop'], self.__language)) desktop_item.connect( 'activate', lambda x: self.__special_operation( self.parent.add_program_to_desktop)) desktop_item.show() self.__menu.append(desktop_item) panel_item = Gtk.MenuItem( utils.localize(STRINGS['popup_add_to_panel'], self.__language)) panel_item.connect( 'activate', lambda x: self.__special_operation( self.parent.add_program_to_panel)) panel_item.show() self.__menu.append(panel_item) if self.is_fave: # special entry for fave buttons remove_fave = Gtk.MenuItem( utils.localize(STRINGS['popup_remove_from_faves'], self.__language)) remove_fave.connect( 'activate', lambda x: self.__special_operation( self.parent.remove_program_from_faves)) remove_fave.show() self.__menu.append(remove_fave) # Need to do things when the menu closes... self.__menu.connect('deactivate', self.__cancel_menu) # ...and if autohiding is enabled (like it usually is) we # must NOT hide the window when the menu opens! self.parent.disable_out_of_focus_hide() self.__popup_open = True self.__menu.popup(parent_menu_shell=None, parent_menu_item=None, func=None, data=None, button=event.button, activate_time=event.time) return True # Clicked on something else return False
def open_menu(self, widget, event): if self.disabled: return if event.button == 3: self.menu = Gtk.Menu() desktop_item = Gtk.MenuItem( localize(self.MENU_ITEMS['add_to_desktop'], self.parent.language)) desktop_item.connect( 'activate', lambda x: self.__special_operation( self.parent.add_program_to_desktop)) desktop_item.show() self.menu.append(desktop_item) panel_item = Gtk.MenuItem( localize(self.MENU_ITEMS['add_to_panel'], self.parent.language)) panel_item.connect( 'activate', lambda x: self.__special_operation( self.parent.add_program_to_panel)) panel_item.show() self.menu.append(panel_item) if self.is_fave: # special entry for fave buttons remove_fave = Gtk.MenuItem( localize(self.MENU_ITEMS['remove_from_faves'], self.parent.language)) remove_fave.connect( 'activate', lambda x: self.__special_operation( self.parent.remove_program_from_faves)) remove_fave.show() self.menu.append(remove_fave) # Need to do things when the menu closes... self.menu.connect('deactivate', self.__cancel_menu) # ...and if autohiding is enabled (like it usually is) we # must NOT hide the window when the menu opens! self.parent.disable_out_of_focus_hide() self.menu_open = True self.menu.popup(parent_menu_shell=None, parent_menu_item=None, func=None, data=None, button=event.button, activate_time=event.time)
def __create_button(self, y, data): button = buttons.SidebarButton( self, self.__settings, utils.localize(data['title'], self.__settings.language), self.__icons[data['icon']], utils.localize(data.get('description', ''), self.__settings.language), data['command']) button.connect('clicked', self.__clicked_sidebar_button) button.show() self.container.put(button, 0, y) # the next available Y coordinate return y + button.get_preferred_button_size()[1]
def __clicked_changelog(self, *unused): try: web_window( url=utils.expand_variables(get_changelog_url() + '&theme=$(user_theme)', self.__variables), title=utils.localize(STRINGS['sb_changelog_window_title'], self.__settings.language), width=1000, height=650, enable_js=True) # Markdown is used on the page, need JS except Exception as exception: logging.error(str(exception)) self.__parent.error_message( utils.localize(STRINGS['sb_changelog_link_failed'], self.__settings.language), str(exception)) self.__parent.autohide()
def __create_hostinfo(self): label_top = WINDOW_HEIGHT - MAIN_PADDING - HOSTINFO_LABEL_HEIGHT utils_gui.create_separator(container=self.container, x=0, y=label_top - MAIN_PADDING, w=SIDEBAR_WIDTH, h=1, orientation=Gtk.Orientation.HORIZONTAL) hostname_label = Gtk.Label() hostname_label.set_size_request(SIDEBAR_WIDTH, HOSTINFO_LABEL_HEIGHT) hostname_label.set_ellipsize(Pango.EllipsizeMode.END) hostname_label.set_justify(Gtk.Justification.CENTER) hostname_label.set_alignment(0.5, 0.5) hostname_label.set_use_markup(True) # FIXME: "big" and "small" are not good sizes, we need to be explicit hostname_label.set_markup( '<big>{0}</big>\n<small><a href="{3}" title="{4}">{1}</a> ({2})</small>' .format( utils.get_file_contents('/etc/puavo/hostname'), utils.get_file_contents('/etc/puavo-image/release'), utils.get_file_contents('/etc/puavo/hosttype'), '', utils.localize(STRINGS['sb_changelog_title'], self.__settings.language))) hostname_label.connect('activate-link', self.__clicked_changelog) hostname_label.show() self.container.put(hostname_label, 0, label_top)
def __show_empty_message(self, msg): if isinstance(msg, dict): msg = utils.localize(msg, self.__settings.language) self.__empty.set_markup( '<span color="#888" size="large"><i>{0}</i></span>'.format(msg)) self.__empty.show()
def __clicked_avatar_button(self, _): print('Clicked the user avatar button') try: web_window(url=utils.expand_variables( 'https://$(puavo_domain)/users/profile/edit?lang=$(user_language)', self.__variables), title=utils.localize(STRINGS['sb_avatar_hover'], self.__settings.language), width=1000, height=650, enable_js=True) # The profile editor needs JavaScript except Exception as exception: logging.error(str(exception)) self.__parent.error_message( utils.localize(STRINGS['sb_avatar_link_failed'], self.__settings.language), str(exception)) self.__parent.autohide()
def get_all_operations(self, broker_account_started_at: datetime) \ -> List[tinvest.schemas.Operation]: """Возвращает все операции в портфеле с указанной даты""" from_ = localize(broker_account_started_at) now = get_now() operations = (self._client.\ get_operations(broker_account_id=self._broker_account_id, from_=from_, to=now)\ .payload.operations) return operations
def handle_incoming_messages(): #Information data = request.json userid = data['entry'][0]['messaging'][0]['sender']['id'] timestamp = data['entry'][0]['messaging'][0]['timestamp'] msg = '' if 'text' in data['entry'][0]['messaging'][0]['message']: msg = data['entry'][0]['messaging'][0]['message']['text'] #/Information user = botutils.User(userid, 0) utils.localize(user) if msg.startswith('/'): command_task = threading.Thread(target=bot.runCommand, name='command_task', args=(user, msg)) command_task.start() else: if easter_slug.on_message(user, msg) == 0: chatting_slug.on_message(user, msg) return 'ok'
def _ret(s): r = requests.get(SETU_API).json() for img in r.get('data'): p = LOCAL_SERVER + localize(img.get('url')) send(s, target, [{ 'type': 'Plain', 'text': '色图time!' }, { 'type': 'Image', 'url': p }]) log.info('完成发送色图到{}, 色图: {}'.format(target, img.get('url')))
def add_program_to_panel(self, program): logging.info('Adding program "%s" (id="%s") to the bottom panel', program.name, program.name) try: utils_gui.create_panel_link(program) except Exception as exception: logging.error('Panel icon creation failed') logging.error(str(exception)) self.error_message( utils.localize(STRINGS['panel_link_failed'], self.__settings.language), str(exception))
def set_info(self): if self.item.get('rating') is None: rating = '' else: rating = str(round(float(self.item.get('rating')), 1)) self.setProperty( 'stop_close_label', utils.localize( constants.STOP_STRING_ID if self.stop_enable else constants.CLOSE_STRING_ID ) ) self.setProperty('shuffle_enable', str(self.shuffle is not None)) self.setProperty('shuffle_on', str(self.shuffle)) if self.item is not None: art = self.item.get('art') self.setProperty('fanart', art.get('tvshow.fanart', '')) self.setProperty('landscape', art.get('tvshow.landscape', '')) self.setProperty('clearart', art.get('tvshow.clearart', '')) self.setProperty('clearlogo', art.get('tvshow.clearlogo', '')) self.setProperty('poster', art.get('tvshow.poster', '')) self.setProperty('thumb', art.get('thumb', '')) self.setProperty('plot', self.item.get('plot', '')) self.setProperty('tvshowtitle', self.item.get('showtitle', '')) self.setProperty('title', self.item.get('title', '')) season = str(self.item.get('season', '')) self.setProperty('season', season) episode = str(self.item.get('episode', '')) self.setProperty('episode', episode) self.setProperty( 'seasonepisode', '{0}x{1}'.format(season, episode) if season else episode ) firstaired, firstaired_string = utils.localize_date( self.item.get('firstaired', '') ) self.setProperty('firstaired', firstaired_string) self.setProperty('premiered', firstaired_string) self.setProperty( 'year', str(firstaired.year) if firstaired else firstaired_string ) self.setProperty('rating', rating) self.setProperty('playcount', str(self.item.get('playcount', 0))) self.setProperty('runtime', str(self.item.get('runtime', '')))
def __create_avatar(self): self.__must_download_avatar = True default_avatar = path_join(self.__settings.res_dir, 'default_avatar.png') existing_avatar = path_join(self.__settings.user_dir, 'avatar.jpg') if self.__settings.is_guest or self.__settings.is_webkiosk: # Always use the default avatar for guests and webkiosk sessions logging.info('Not loading avatar for a guest/webkiosk session') avatar_image = default_avatar self.__must_download_avatar = False elif file_exists(existing_avatar): logging.info( 'A previously-downloaded user avatar file exists, using it') avatar_image = existing_avatar else: # We need to download this avatar image right away, use the # default avatar until the download is complete logging.info( 'Not a guest/webkiosk session and no previously-' 'downloaded avatar available, using the default image') avatar_image = default_avatar if self.__settings.is_guest or self.__settings.is_webkiosk: avatar_tooltip = None else: avatar_tooltip = \ utils.localize(STRINGS['sb_avatar_hover'], self.__settings.language) self.__avatar = buttons.AvatarButton(self, self.__settings, getuser(), avatar_image, avatar_tooltip) # No profile editing for guest users if self.__settings.is_guest or self.__settings.is_webkiosk: logging.info('Disabling the avatar button for guest user') self.__avatar.disable() else: self.__avatar.connect('clicked', self.__clicked_avatar_button) self.container.put(self.__avatar, 0, MAIN_PADDING) self.__avatar.show()
def _copy_episode_details(upnext_info): # If next episode information is not provided, fake it if not upnext_info.get('next_episode'): episode = upnext_info['current_episode'] episode['episodeid'] = constants.UNKNOWN_DATA episode['art'] = {} # Next provided episode may not be the next consecutive episode so we # can't assume that the episode can simply be incremented, instead set # title to indicate the next episode in the UpNext popup # episode['episode'] = utils.get_int(episode, 'episode') + 1 episode['title'] = utils.localize(constants.NEXT_STRING_ID) # Change season and episode info to empty string to avoid episode # formatting issues ("S-1E-1") in UpNext popup episode['season'] = '' episode['episode'] = '' episode['plot'] = '' episode['playcount'] = 0 episode['rating'] = 0 episode['firstaired'] = '' episode['runtime'] = 0 upnext_info['next_episode'] = episode # If current episode information is not provided, fake it elif not upnext_info.get('current_episode'): episode = upnext_info['next_episode'] episode['episodeid'] = constants.UNKNOWN_DATA episode['art'] = {} episode['title'] = '' episode['season'] = '' episode['episode'] = '' episode['plot'] = '' episode['playcount'] = 0 episode['rating'] = 0 episode['firstaired'] = '' episode['runtime'] = 0 upnext_info['current_episode'] = episode return upnext_info
def add_program_to_desktop(self, program): """Creates a desktop shortcut to a program.""" if not self.__settings.desktop_dir: return # Create the link file # TODO: use the *original* .desktop file if it exists name = os.path.join(self.__settings.desktop_dir, '{0}.desktop'.format(program.name)) logging.info('Adding program "%s" to the desktop, destination="%s"', program.name, name) try: utils_gui.create_desktop_link(name, program) except Exception as exception: logging.error('Desktop link creation failed:') logging.error(str(exception)) self.error_message( utils.localize(STRINGS['desktop_link_failed'], self.__settings.language), str(exception))
def clicked_program_button(self, button): program = button.data program.uses += 1 logging.info('Clicked program button "%s", usage counter is %d', program.menudata_id, program.uses) self.__faves.update(self.menudata.programs, self.__settings) if program.command is None: logging.error('No command defined for program "%s"', program.name) return # Try to launch the program. Use Gio's services, as Gio understands the # "Exec=" keys and we don't have to spawn shells with pipes and "sh". try: if self.__settings.prod_mode: # Spy the user and log what programs they use. This information # is then sent to various TLAs around the world and used in all # sorts of nefarious classified black operations. syslog.syslog( syslog.LOG_INFO, 'Launching program "{0}", command="{1}"'.format( program.menudata_id, program.command)) # Just kidding. The reason program starts are logged to syslog # is actually really simple: you can grep the log and count # which programs are actually used and how many times. # Of course this only logs programs that are started through # Puavomenu, but we decided to ignore this for now. logging.info('Executing "%s"', program.command) if program.program_type in (PROGRAM_TYPE_DESKTOP, PROGRAM_TYPE_CUSTOM): # Set the program name to empty string ('') to force some (KDE) # programs to use their default window titles. These programs # have command-line parameters like "-qwindowtitle" or "-caption" # and Gio, when launching the program, sets the "%c" argument # (in the Exec= key) to the program's name it takes from the # command (program.command). This is Wrong(TM), but during # testing I noticed that if we leave it empty (*NOT* None # because that triggers the unwanted behavior!) then these # programs will use their own default titles. Gio.AppInfo.create_from_commandline(program.command, '', 0).launch() elif program.program_type == PROGRAM_TYPE_WEB: Gio.AppInfo.launch_default_for_uri(program.command, None) else: raise RuntimeError('Unknown program type "{0}"'.format( program.program_type)) # Of course, we never check the return value here, so we # don't know if the command actually worked... self.autohide() if self.__settings.reset_view_after_start: # Go back to the default view self.reset_view() except Exception as exception: logging.error('Could not launch program "%s": %s', program.command, str(exception)) self.error_message( utils.localize(STRINGS['program_launching_failed'], self.__settings.language), str(exception)) return False
def __init__(self, settings): """This is where the magic happens.""" start_time = time.clock() super().__init__() self.__settings = settings # Ensure the window is not visible until it's ready self.set_visible(False) self.set_type_hint(Gtk.WindowType.TOPLEVEL) # ---------------------------------------------------------------------- # Set up a domain socket for show/hide messages from the panel # button shell extension. This is done early, because if it # fails, we simply exit. We can't do *anything* without it. # (The only other choice would be to always display the menu, # never allowing the user to hide it because without the socket # it cannot be reopened.) try: # Clean leftovers os.unlink(self.__settings.socket) except OSError: pass try: self.__socket = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM) self.__socket.bind(self.__settings.socket) except Exception as exception: # Oh dear... logging.error('Unable to create a domain socket for IPC!') logging.error('Reason: %s', str(exception)) logging.error('Socket name: "%s"', self.__settings.socket) logging.error('This is a fatal error, stopping here.') syslog.syslog(syslog.LOG_CRIT, 'PuavoMenu IPC socket "%s" creation failed: %s', self.__settings.socket, str(exception)) syslog.syslog(syslog.LOG_CRIT, 'PuavoMenu stops here. Contact Opinsys support.') exit(1) # Start listening the socket. Use glib's watch functions, then # we don't need to use threads (which work too, but are harder # to clean up and we'll run into problems with multihtreaded # xlib programs). # https://developer.gnome.org/pygobject/stable/glib-functions.html# # function-glib--io-add-watch GLib.io_add_watch(self.__socket, GLib.IO_IN, self.__socket_watcher) # ---------------------------------------------------------------------- # Exit stuff. By default the program cannot be exited normally. self.__exit_permitted = False self.connect('delete-event', self.__try_exit) # Program, menu and category data self.menudata = None # Current category (index to menudata.category_index) self.current_category = -1 # The current menu, if any (None if on category top-level) self.current_menu = None # The current menu/program buttons in the current # category and menu, if any self.__buttons = [] # Storage for 48x48 -pixel program and menu icons. Maintained # separately from the menu data. self.__icons = iconcache.IconCache(48, 48 * 20) # Background image for top-level menus try: if self.__settings.dark_theme: image_name = 'folder_dark.png' else: image_name = 'folder.png' # WARNING: Hardcoded image size! self.__menu_background = \ utils_gui.load_image_at_size(self.__settings.res_dir + image_name, 150, 110) except Exception as exception: logging.error("Can't load the menu background image: %s", str(exception)) self.__menu_background = None # ---------------------------------------------------------------------- # Create the window elements # Set window style if self.__settings.prod_mode: self.set_skip_taskbar_hint(True) self.set_skip_pager_hint(True) self.set_deletable(False) # no close button self.set_decorated(False) else: # makes developing slightly easier self.set_skip_taskbar_hint(False) self.set_skip_pager_hint(False) self.set_deletable(True) self.set_decorated(True) self.__exit_permitted = True # Don't mess with the real menu when running in development mode if self.__settings.prod_mode: self.set_title('PuavoMenuUniqueName') else: self.set_title('DevModePuavoMenu') self.set_resizable(False) self.set_size_request(WINDOW_WIDTH, WINDOW_HEIGHT) self.set_position(Gtk.WindowPosition.CENTER) # Top-level container for all widgets. This is needed, because # a window can contain only one child widget and we can have # dozens of them. Every widget has a fixed position and size, # because the menu isn't user-resizable. self.__main_container = Gtk.Fixed() self.__main_container.set_size_request(WINDOW_WIDTH, WINDOW_HEIGHT) if not self.__settings.prod_mode: # Create the devtools popup menu self.menu_signal = \ self.connect('button-press-event', self.__devtools_menu) # ---------------------------------------------------------------------- # Menus/programs list # TODO: Gtk.Notebook isn't the best choice for this # Category tabs self.__category_buttons = Gtk.Notebook() self.__category_buttons.set_size_request(CATEGORIES_WIDTH, -1) self.__category_buttons.connect('switch-page', self.__clicked_category) self.__main_container.put(self.__category_buttons, PROGRAMS_LEFT, MAIN_PADDING) # The back button self.__back_button = Gtk.Button() self.__back_button.set_label('<<') self.__back_button.connect('clicked', self.__clicked_back_button) self.__back_button.set_size_request(BACK_BUTTON_WIDTH, -1) self.__main_container.put(self.__back_button, BACK_BUTTON_X, BACK_BUTTON_Y) # The search box # filter unwanted characters from queries self.__translation_table = \ dict.fromkeys(map(ord, "*^?{[]}/\\_+=\"\'#%&()'`@$<>|~"), None) self.__search = Gtk.SearchEntry() self.__search.set_size_request(SEARCH_WIDTH, SEARCH_HEIGHT) self.__search.set_max_length(10) # you won't need more than this self.__search_changed_signal = \ self.__search.connect('changed', self.__do_search) self.__search_keypress_signal = \ self.__search.connect('key-press-event', self.__search_keypress) self.__search.set_placeholder_text( utils.localize(STRINGS['search_placeholder'], self.__settings.language)) self.__main_container.put( self.__search, PROGRAMS_LEFT + PROGRAMS_WIDTH - SEARCH_WIDTH - MAIN_PADDING, MAIN_PADDING) # Menu label and description self.__menu_title = Gtk.Label() self.__menu_title.set_size_request(PROGRAMS_WIDTH, -1) self.__menu_title.set_ellipsize(Pango.EllipsizeMode.END) self.__menu_title.set_justify(Gtk.Justification.CENTER) self.__menu_title.set_alignment(0.0, 0.0) self.__menu_title.set_use_markup(True) self.__main_container.put( self.__menu_title, BACK_BUTTON_X + BACK_BUTTON_WIDTH + MAIN_PADDING, BACK_BUTTON_Y + 3) # The main programs list self.__programs_container = Gtk.ScrolledWindow() self.__programs_container.set_size_request(PROGRAMS_WIDTH, PROGRAMS_HEIGHT) self.__programs_container.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) self.__programs_container.set_shadow_type(Gtk.ShadowType.NONE) self.__programs_icons = Gtk.Fixed() self.__programs_container.add_with_viewport(self.__programs_icons) self.__main_container.put(self.__programs_container, PROGRAMS_LEFT, PROGRAMS_TOP) # Placeholder for empty categories, menus and search results self.__empty = Gtk.Label() self.__empty.set_size_request(PROGRAMS_WIDTH, PROGRAMS_HEIGHT) self.__empty.set_use_markup(True) self.__empty.set_justify(Gtk.Justification.CENTER) self.__empty.set_alignment(0.5, 0.5) self.__main_container.put(self.__empty, PROGRAMS_LEFT, PROGRAMS_TOP) # Faves list self.__faves_sep = Gtk.Separator( orientation=Gtk.Orientation.HORIZONTAL) self.__faves_sep.set_size_request(PROGRAMS_WIDTH, 1) self.__main_container.put( self.__faves_sep, PROGRAMS_LEFT, PROGRAMS_TOP + PROGRAMS_HEIGHT + MAIN_PADDING) self.__faves = faves.FavesList(self, self.__settings) self.__faves.set_size_request(PROGRAMS_WIDTH, PROGRAM_BUTTON_HEIGHT + 2) self.__main_container.put(self.__faves, PROGRAMS_LEFT, FAVES_TOP) # ---------------------------------------------------------------------- # The sidebar: the user avatar, buttons, host infos utils_gui.create_separator(container=self.__main_container, x=SIDEBAR_LEFT - MAIN_PADDING, y=MAIN_PADDING, w=1, h=WINDOW_HEIGHT - (MAIN_PADDING * 2), orientation=Gtk.Orientation.VERTICAL) self.__sidebar = sidebar.Sidebar(self, self.__settings) self.__main_container.put(self.__sidebar.container, SIDEBAR_LEFT, SIDEBAR_TOP) # ---------------------------------------------------------------------- # Setup GTK signal handlers # Listen for Esc keypresses for manually hiding the window self.__main_keypress_signal = \ self.connect('key-press-event', self.__check_for_esc) self.__focus_signal = None if not self.__settings.autohide: # Keep the window on top of everything and show it self.set_visible(True) self.set_keep_above(True) else: # In auto-hide mode, hide the window when it loses focus self.enable_out_of_focus_hide() self.__search.connect('focus-out-event', self.__search_out) # ---------------------------------------------------------------------- # UI done self.add(self.__main_container) self.__main_container.show() # DO NOT CALL self.show_all() HERE, the window has hidden elements # that are shown/hidden on demand. And we don't even have any # menu data yet to show. end_time = time.clock() utils.log_elapsed_time('Window init time', start_time, end_time) # ---------------------------------------------------------------------- # Load menu data # Finally, load the menu data and show the UI self.load_menu_data() # This is a bad, bad situation that should never happen in production. # It will happen one day. if self.menudata is None or len(self.menudata.programs) == 0: if self.__settings.prod_mode: self.__show_empty_message(STRINGS['menu_no_data_at_all_prod']) else: self.__show_empty_message(STRINGS['menu_no_data_at_all_dev'])
def __init__(self, parent, settings, label, icon=None, tooltip=None, data=None, is_fave=False, is_installer=False, enable_popup=True): super().__init__(parent, settings, label, icon, tooltip, data) self.is_fave = is_fave # Need this for localize() self.__language = settings.language if settings.desktop_dir is None: self.__have_desktop_dir = False else: self.__have_desktop_dir = True # Setup the popup menu self.__enable_popup = enable_popup self.__popup_hover = False self.__popup_open = False self.__hover_signal = None # Setup "installer" buttons self.__is_installer = is_installer if self.__is_installer: # No popup menus for installers, they are not going to work # from the panel or the desktop... self.__enable_popup = False # UGLY UGLY UGLY color = '#888' if settings.dark_theme else '#444' markup = '{0}\n<span foreground="{1}"><i><small>[{2}]</small></i></span>' \ .format(label, color, utils.localize(STRINGS['button_puavopkg_installer_suffix'], settings.language)) self.label_layout.set_markup(markup) self.set_property('tooltip-text', utils.localize(STRINGS['button_puavopkg_installer_tooltip'], settings.language)) self.__menu = None self.__menu_signal = self.connect('button-press-event', self.open_menu) # We want mouse motion events self.set_events(self.get_events() | Gdk.EventMask.POINTER_MOTION_MASK) # Setup the popup indicator box. Compute its coordinates. self.__indicator_x1 = PROGRAM_BUTTON_WIDTH - self.INDICATOR_WIDTH - self.INDICATOR_EDGE self.__indicator_x2 = self.__indicator_x1 + self.INDICATOR_WIDTH self.__indicator_y1 = self.INDICATOR_EDGE self.__indicator_y2 = self.__indicator_y1 + self.INDICATOR_HEIGHT
def step(self, tick): # if self.target == self.master.ball.location: # self.master.ball.step(tick) # self.target = self.master.ball.location # if self.agent.team == 0: print(utils.steer(self.target, self.car), utils.angle2D(self.target, self.car), self.target.tuple, self.car.location.tuple) # self.controls.yaw = utils.steer(self.target, self.car) self.controls.throttle, self.controls.boost = utils.throttle( self.car, self.speed) turn_radius = utils.turn_radius(self.car, self.target) angle_to_target = utils.angle2D(self.target, self.car) point = utils.point_on_circle(self.car, utils.sign(angle_to_target) * math.pi / 2, turn_radius) #, self.car.rotation) circle = [] for i in range(0, 366, 6): n = utils.point_on_circle(point, math.radians(i), turn_radius) #, point.rotation) circle.append(n.tuple) self.agent.renderer.draw_polyline_3d(circle, self.agent.renderer.red()) # ball_prediction = self.agent.get_ball_prediction_struct() # if ball_prediction is not None: # # for i in range(0, ball_prediction.num_slices): # if self.target == self.master.ball.location: # self.target = structs.Vector3(ball_prediction.slices[10].physics.location) # turn_radius = utils.turn_radius(self.car, self.target) # goal_to_ball_uv = (self.agent.game_info.their_goal.location - self.agent.game_info.ball.location).normalize() # yaw = math.atan2(goal_to_ball_uv.x, goal_to_ball_uv.z) #math.atan((goal_to_ball_uv.x/(-goal_to_ball_uv.y)))# # pitch = 0#math.atan(math.hypot(goal_to_ball_uv.x, goal_to_ball_uv.y)/goal_to_ball_uv.z) # target_ang = structs.Rotator(pitch, yaw, 0) # circle_point = utils.point_on_circle(self.target, math.pi/2, turn_radius, target_ang) # circle = [] # for i in range(0, 366, 6): # n = utils.point_on_circle(circle_point, math.radians(i), turn_radius) # circle.append(n.tuple) # self.agent.renderer.draw_polyline_3d(circle, self.agent.renderer.black()) # x1 = point.x # y1 = point.y # x2 = circle_point.x # y2 = circle_point.y # gamma = -math.atan((y2-y1)/(x2-x1)) # beta = math.asin((turn_radius-turn_radius)/math.sqrt((x2-x1)**2 + (y2-y1)**2)) # alpha = gamma-beta # x3 = x1 - turn_radius*math.cos((math.pi/2)-alpha) # y3 = y1 - turn_radius*math.sin((math.pi/2)-alpha) # x4 = x2 + turn_radius*math.cos((math.pi/2)-alpha) # y4 = y2 + turn_radius*math.sin((math.pi/2)-alpha) # tang1 = structs.Vector3(x3, y3, 100) # tang2 = structs.Vector3(x4, y4, 100) # if self.last_target_ang != target_ang: # print('ye') # self.cur_hit = 0 # self.last_target_ang = target_ang # self.to_hit = [tang1, tang2, self.agent.game_info.ball.location] # self.agent.renderer.draw_rect_3d(self.to_hit[0].tuple, 20, 20, True, self.agent.renderer.black()) # self.agent.renderer.draw_rect_3d(self.to_hit[1].tuple, 20, 20, True, self.agent.renderer.black()) # point_to_target = utils.distance2D(self.target, point) # if point_to_target < turn_radius: # #inside circle # if abs(utils.angle2D(self.target, self.car)) < math.pi/2: # to_target = utils.localize(self.target, self.car).normalize(turn_radius) # self.target = self.car.location - to_target # self.controls.boost = 0 # self.controls.throttle = 0 # else: # to_target = utils.localize(self.target, self.car).normalize(turn_radius) # self.target = self.car.location - to_target # self.controls.boost = 0 # self.controls.handbrake = 1 # point2 = structs.Vector3(x,y,z) # self.agent.renderer.draw_rect_3d(point.tuple, 10, 10, True, self.agent.renderer.blue()) if isinstance(self.master, states.quickShoot): if self.path: if not self.path.on_path(self.car.location): # self.path = None print('yes') else: curvetarget = self.path.evaluate(0.1) curvetarget = structs.Vector3(curvetarget[0], curvetarget[1], 0) self.controls.steer = utils.steer(curvetarget, self.car) self.agent.renderer.draw_rect_3d( curvetarget.tuple, 10, 10, True, self.agent.renderer.blue()) if not self.path: b_prediction = self.agent.get_ball_prediction_struct() target = utils.find_point_on_line( self.agent.game_info.their_goal.location, self.target, -.05) self.path = structs.Path(self.agent, [ self.car.location, utils.point_on_circle(self.car, 0, 500), 'TP', target, self.target ], utils.sign(angle_to_target), self.car.rotation, self.car) angletotarget = utils.map( abs(utils.angle2D(self.target, self.car)), 0, math.pi, 0, math.pi) curvetarget = self.path.evaluate(0.1) curvetarget = structs.Vector3(curvetarget[0], curvetarget[1], 0) self.agent.renderer.draw_rect_3d(curvetarget.tuple, 10, 10, True, self.agent.renderer.blue()) self.controls.steer = utils.steer(curvetarget, self.car) elif utils.distance2D(point, self.target) < turn_radius: to_target = utils.localize(self.target, self.car).normalize(turn_radius) self.target = self.car.location - to_target self.controls.boost = False self.controls.steer = utils.steer(self.target, self.car) else: self.controls.steer = utils.steer(self.target, self.car) if self.path: # print(self.path.on_path(self.car.location)) self.agent.renderer.draw_polyline_3d( self.path.get_path_points(np.linspace(0, 1.0, 100)), self.agent.renderer.green()) self.agent.renderer.draw_rect_3d(self.target.tuple, 10, 10, True, self.agent.renderer.red()) self.agent.renderer.draw_line_3d(self.car.location.flatten().tuple, self.target.flatten().tuple, self.agent.renderer.green()) self.expired = True return self.controls
def __parse_yml_string(string, lang_id, conditions): """Loads menu data from YAML data stored in a string.""" import yaml programs = {} menus = {} categories = {} # use safe_load(), it does not attempt to construct Python classes data = yaml.safe_load(string) if data is None or not isinstance(data, dict): logger.warn('__parse_yml_string(): string produced no data, or the ' 'data is not a dict') return programs, menus, categories # data.get('xxx', []) will fail if the list following the key is # empty, returning None and crashing the program. if data.get('programs') is None: data['programs'] = [] if data.get('menus') is None: data['menus'] = [] if data.get('categories') is None: data['categories'] = [] # -------------------------------------------------------------------------- # Parse programs for i in data['programs']: status, name, params = __convert_yaml_node(i) if not status: continue if not __is_valid(name): logger.error('Program name "{0}" contains invalid characters, ' 'ignoring'.format(name)) continue if name in programs: logger.warn('Program "{0}" defined multiple times, ignoring ' 'duplicates'.format(name)) continue # "Reserve" the name so it's used even if we can't parse this # program definition, otherwise duplicate entries might slip # through programs[name] = None # Figure out the type prog_type = params.get('type', 'desktop') if prog_type not in ('desktop', 'custom', 'web'): logger.error('Unknown program type "{0}" for "{1}", ' 'ignoring definition'.format(prog_type, name)) continue p = Program() if prog_type == 'desktop': p.type = PROGRAM_TYPE_DESKTOP elif prog_type == 'custom': p.type = PROGRAM_TYPE_CUSTOM else: p.type = PROGRAM_TYPE_WEB p.name = name # Conditionally hidden? if 'condition' in params and \ __is_hidden(conditions, params['condition'], name): p.hidden = True programs[name] = p continue # Load common parameters if 'name' in params: p.title = localize(params['name'], lang_id) if __is_empty(p.title): logger.error('Empty name given for "{0}"'.format(name)) p.title = None if 'description' in params: p.description = localize(params['description'], lang_id) if __is_empty(p.description): logger.warn( 'Ignoring empty description for program "{0}"'.format( name)) p.description = None if 'icon' in params: p.icon = str(params['icon']) if __is_empty(p.icon): logger.warn('Ignoring empty icon for "{0}"'.format(name)) p.icon = None p.keywords = __parse_list(params.get('keywords', [])) # Some per-type additional checks if p.type in (PROGRAM_TYPE_CUSTOM, PROGRAM_TYPE_WEB): if p.title is None: logger.error('Custom program/web link "{0}" has no name at ' 'all, ignoring definition'.format(name)) continue if p.icon is None: # this isn't fatal, it just looks really ugly logger.warn('Custom program/web link "{0}" is missing an ' 'icon definition'.format(name)) # Load type-specific parameters if p.type == PROGRAM_TYPE_DESKTOP: if 'command' in params: # allow overriding of the "Exec" definition p.command = str(params['command']) if __is_empty(p.command): logger.warn('Ignoring empty command override for desktop ' 'program "{0}"'.format(name)) p.command = None elif p.type == PROGRAM_TYPE_CUSTOM: if 'command' not in params or __is_empty(params['command']): logger.error( 'Custom program "{0}" has no command defined' '(or it\'s empty), ignoring command definition'.format( name)) continue p.command = str(params['command']) elif p.type == PROGRAM_TYPE_WEB: if ('url' not in params) or __is_empty(params['url']): logger.error('Web link "{0}" has no URL defined (or it\'s ' 'empty), ignoring link definition'.format(name)) continue p.command = str(params['url']) # Actually use the reserved slot programs[name] = p # -------------------------------------------------------------------------- # Parse menus for i in data['menus']: status, name, params = __convert_yaml_node(i) if not status: continue if not __is_valid(name): logger.error('Menu name "{0}" contains invalid characters, ' 'ignoring'.format(name)) continue if name in menus: logger.error('Menu "{0}" defined multiple times, ignoring ' 'duplicates'.format(name)) continue # Like programs, reserve the name to prevent duplicates menus[name] = None m = Menu() m.name = name # Conditionally hidden? if 'condition' in params and \ __is_hidden(conditions, params['condition'], name): m.hidden = True menus[name] = m continue m.title = localize(params.get('name', ''), lang_id) if __is_empty(m.title): logger.error( 'Menu "{0}" has no name at all, menu ignored'.format(name)) continue if 'description' in params: m.description = localize(params['description'], lang_id) if __is_empty(m.description): logger.warn( 'Ignoring empty description for menu "{0}"'.format(name)) m.description = None if 'icon' in params: m.icon = str(params['icon']) if __is_empty(m.icon): logger.warn('Menu "{0}" has a missing/empty icon'.format(name)) m.icon = None m.programs = __parse_list(params.get('programs', [])) if __is_empty(m.programs): logger.warn( 'Menu "{0}" has no programs defined for it at all'.format( name)) m.programs = [] # Actually use the reserved slot menus[name] = m # -------------------------------------------------------------------------- # Parse categories for i in data['categories']: status, name, params = __convert_yaml_node(i) if not status: continue if not __is_valid(name): logger.error('Category name "{0}" contains invalid characters, ' 'ignoring'.format(name)) continue if name in categories: logger.error('Category "{0}" defined multiple times, ignoring ' 'duplicates'.format(name)) continue # Again reserve the name to prevent duplicates categories[name] = None c = Category() c.name = name if 'condition' in params and \ __is_hidden(conditions, params['condition'], name): c.hidden = True categories[name] = c continue c.title = localize(params.get('name', ''), lang_id) if __is_empty(c.title): logger.error('Category "{0}" has no name at all, ' 'category ignored'.format(name)) continue if 'position' in params: try: c.position = int(params['position']) except ValueError: logger.warn('Cannot interpret "{0}" as a position for ' 'category "{1}", defaulting to 0'.format( params["position"], name)) c.position = 0 c.menus = __parse_list(params.get('menus', [])) c.programs = __parse_list(params.get('programs', [])) if __is_empty(c.menus) and __is_empty(c.programs): logger.warn('Category "{0}" has no menus or programs defined ' 'for it at all'.format(name)) # Actually use the reserved slot categories[name] = c return programs, menus, categories
def __clicked_sidebar_button(self, button): try: command = button.data arguments = command.get('args', '') # Support plain strings and arrays of strings as arguments if isinstance(arguments, list): arguments = ' '.join(arguments).strip() if len(arguments) == 0: logging.error('Sidebar button without a command!') self.__parent.error_message( 'Nothing to do', 'This button has no commands associated with it.') return self.__parent.autohide() # Expand variables if command.get('have_vars', False): arguments = utils.expand_variables(arguments, self.__variables) logging.debug('Sidebar button arguments: "%s"', arguments) if command['type'] == 'command': logging.info('Executing a command') Gio.AppInfo.create_from_commandline(arguments, '', 0).launch() elif command['type'] == 'url': logging.info('Opening a URL') Gio.AppInfo.launch_default_for_uri(arguments, None) elif command['type'] == 'webwindow': logging.info('Creating a webwindow') # Default settings title = None width = None height = None enable_js = False # Allow the window to be customized if 'webwindow' in command: settings = command['webwindow'] width = settings.get('width', None) height = settings.get('height', None) title = settings.get('title', None) enable_js = settings.get('enable_js', False) if title: title = utils.localize(title, self.__settings.language) web_window(url=arguments, title=title, width=width, height=height, enable_js=enable_js) except Exception as exception: logging.error('Could not process a sidebar button click!') logging.error(str(exception)) self.__parent.error_message( utils.localize(STRINGS['sb_button_failed'], self.__settings.language), str(exception))
def build_menu_data(raw_programs, raw_menus, raw_categories, language): """Builds the actual menu data from raw menu data.""" programs = {} menus = {} categories = {} # Build programs for menudata_id, src_prog in raw_programs.items(): if not src_prog: continue if 'type' not in src_prog: logging.error( 'Program "%s" has no type specified. ' 'This really should not happen.', menudata_id) continue dst_prog = Program() # Type and menudata ID. Python, why did you have to reserve # common words as "type" and "id" and not let me use them? dst_prog.program_type = src_prog['type'] dst_prog.menudata_id = menudata_id # We can't actually remove hidden things. as they are referenced # to in menus and categories and if we remove them here, we'll # erroneously report them to be "broken". if 'hidden' in src_prog and src_prog['hidden']: dst_prog.hidden = True # Name (required) if 'name' in src_prog and src_prog['name']: dst_prog.name = utils.localize(src_prog['name'], language) if utils.is_empty(dst_prog.name): logging.error('Program "%s" has no name at all, skipping it', menudata_id) raw_programs[menudata_id] = None continue # Description (optional), accept ONLY a localized description if 'description' in src_prog and src_prog['description'] and \ language in src_prog['description']: dst_prog.description = \ utils.localize(src_prog['description'], language) # Keywords (optional) if 'keywords' in src_prog and language in src_prog['keywords']: dst_prog.keywords = list(src_prog['keywords'][language]) # Command (required) if 'command' in src_prog: dst_prog.command = src_prog['command'] if utils.is_empty(dst_prog.command): if dst_prog.program_type == PROGRAM_TYPE_WEB: logging.error( 'Web link "%s" has an empty or missing URL, ' 'link ignored', menudata_id) else: logging.error( 'Program "%s" has an empty or missing command, ' 'program ignored', menudata_id) raw_programs[menudata_id] = None continue # Icon if 'icon' in src_prog: dst_prog.icon_name = src_prog['icon'] if utils.is_empty(dst_prog.icon_name): logging.warning('Program "%s" has no icon defined for it', menudata_id) else: # Is the icon name a full path to an icon file, or just # a generic name? _, ext = os.path.splitext(dst_prog.icon_name) if (not utils.is_empty(ext)) and (ext in ICON_EXTENSIONS): dst_prog.icon_name_is_path = True programs[menudata_id] = dst_prog # Build menus and add programs to them for menudata_id, src_menu in raw_menus.items(): if not src_menu: continue dst_menu = Menu() dst_menu.menudata_id = menudata_id # Like programs, we only flag menus to be hidden if 'hidden' in src_menu and src_menu['hidden']: dst_menu.hidden = True # Name (required) if 'name' in src_menu and src_menu['name']: dst_menu.name = utils.localize(src_menu['name'], language) if utils.is_empty(dst_menu.name): logging.error('Menu "%s" has no name at all, skipping it', menudata_id) raw_menus[menudata_id] = None continue # Description (optional) if 'description' in src_menu and src_menu['description']: dst_menu.description = utils.localize(src_menu['description'], language) # Icon (required, but it's not fatal if it's missing) if 'icon' in src_menu and src_menu['icon']: dst_menu.icon_name = src_menu['icon'] if utils.is_empty(dst_menu.icon_name): logging.warning('Menu "%s" has no icon defined for it', menudata_id) # List of programs (required, but it's not fatal if it's empty/missing) had_something = False if 'programs' in src_menu: for p_name in src_menu['programs']: if p_name not in programs or programs[p_name] is None: logging.warning( 'Menu "%s" references to a non-existing program "%s"', menudata_id, p_name) continue # Don't whine about an empty menu if all of it's programs # are hidden had_something = True # Silently ignore hidden programs if programs[p_name].hidden: continue programs[p_name].used = True dst_menu.programs.append(programs[p_name]) if len(dst_menu.programs) == 0 and not had_something: logging.warning('Menu "%s" is completely empty', menudata_id) menus[menudata_id] = dst_menu # Build categories and add menus and programs to them for menudata_id, src_cat in raw_categories.items(): if not src_cat: continue if 'hidden' in src_cat and src_cat['hidden']: continue dst_cat = Category() dst_cat.menudata_id = menudata_id # Name (required) if 'name' in src_cat and src_cat['name']: dst_cat.name = utils.localize(src_cat['name'], language) if utils.is_empty(dst_cat.name): logging.error('Category "%s" has no name at all, skipping it', menudata_id) raw_categories[menudata_id] = None continue # Description (optional) if 'description' in src_cat and src_cat['description']: dst_cat.description = utils.localize(src_cat['description'], language) # List of menus and programs (technically you need at least one of # either, but it's not a fatal error to omit everything, it just # looks ugly) if 'menus' in src_cat: for m_name in src_cat['menus']: if m_name not in menus or menus[m_name] is None: logging.warning( 'Category "%s" references to a non-existing menu "%s"', menudata_id, m_name) continue # Silently ignore hidden menus if menus[m_name].hidden: continue menus[m_name].used = True dst_cat.menus.append(menus[m_name]) if 'programs' in src_cat: for p_name in src_cat['programs']: if p_name not in programs or programs[p_name] is None: logging.warning( 'Category "%s" references to a non-existing program "%s"', menudata_id, p_name) continue # Silently ignore hidden programs if programs[p_name].hidden: continue programs[p_name].used = True dst_cat.programs.append(programs[p_name]) # Position if 'position' in src_cat: try: dst_cat.position = int(src_cat['position']) except ValueError: logging.warning( 'Cannot interpret "%s" as a position for ' 'category "%s", defaulting to 0', src_cat['position'], menudata_id) dst_cat.position = 0 if len(dst_cat.menus) == 0 and len(dst_cat.programs) == 0: logging.warning('Category "%s" is completely empty', menudata_id) categories[menudata_id] = dst_cat return programs, menus, categories
def show(self): if self._demolabel is not None: return # FIXME: Using a different font does not seem to have much of an impact self._demolabel = ControlLabel(0, getScreenHeight() // 4, getScreenWidth(), 100, localize(30060) + '\n' + localize(30061), font='font36_title', textColor='0xddee9922', alignment=0x00000002) self.window.addControl(self._demolabel) self.log('show', 0)