def main(): global screen print("Nerd Tabu") # Parse command line parser = argparse.ArgumentParser() parser.add_argument('quizfile', type=argparse.FileType('r'), help='Name of the quiz file') parser.add_argument('teamA', nargs='?', metavar='teamname_A', default='Team A', help='Name of team A') parser.add_argument('teamB', nargs='?', metavar='teamname_B', default='Team B', help='Name of team B') parser.add_argument('-d', '--datadir', default='.', help='Resource directory') parser.add_argument('-f', '--fullscreen', help='Run fullscreen', action='store_true') args = parser.parse_args() # Update settings settings = Settings(args.quizfile, args.datadir) settings.teams = [ args.teamA, args.teamB ] theme = Theme(args.datadir) # Initial game data cards = settings.get_random_cards() current_team = 0 # Main game loop pygame.init() if args.fullscreen: # screen = pygame.display.set_mode(theme.screen_size, pygame.FULLSCREEN) screen = pygame.display.set_mode(theme.screen_size, pygame.RESIZABLE | pygame.NOFRAME) else: screen = pygame.display.set_mode(theme.screen_size) theme.load_data() while len(cards)>0: team_get_ready(theme, settings, current_team) play_round(theme, settings, current_team, cards) current_team = (current_team + 1) % len(settings.teams) show_final_scores(theme, settings) pygame.quit()
def read_config(self, path): """parse alot's config file from path""" spec = os.path.join(DEFAULTSPATH, 'alot.rc.spec') newconfig = read_config(path, spec, checks={'mail_container': mail_container, 'force_list': force_list, 'align': align_mode, 'attrtriple': attr_triple, 'gpg_key_hint': gpg_key}) self._config.merge(newconfig) hooks_path = os.path.expanduser(self._config.get('hooksfile')) try: self.hooks = imp.load_source('hooks', hooks_path) except: logging.debug('unable to load hooks file:%s' % hooks_path) if 'bindings' in newconfig: newbindings = newconfig['bindings'] if isinstance(newbindings, Section): self._bindings.merge(newbindings) # themes themestring = newconfig['theme'] themes_dir = self._config.get('themes_dir') if themes_dir: themes_dir = os.path.expanduser(themes_dir) else: configdir = os.environ.get('XDG_CONFIG_HOME', os.path.expanduser('~/.config')) themes_dir = os.path.join(configdir, 'alot', 'themes') logging.debug(themes_dir) # if config contains theme string use that if themestring: if not os.path.isdir(themes_dir): err_msg = 'cannot find theme %s: themes_dir %s is missing' raise ConfigError(err_msg % (themestring, themes_dir)) else: theme_path = os.path.join(themes_dir, themestring) try: self._theme = Theme(theme_path) except ConfigError as e: err_msg = 'Theme file %s failed validation:\n' raise ConfigError((err_msg % themestring) + e.message) # if still no theme is set, resort to default if self._theme is None: theme_path = os.path.join(DEFAULTSPATH, 'default.theme') self._theme = Theme(theme_path) self._accounts = self._parse_accounts(self._config) self._accountmap = self._account_table(self._accounts)
def __init__(self, group, class_group=None, desktop_entry=None, identifier=None): self.dockbar_r = weakref.ref(group.dockbar_r()) self.theme = Theme() self.globals = Globals() connect(self.globals, "color-changed", self.reset_surfaces) self.desktop_entry = desktop_entry self.identifier = identifier self.class_group = class_group # Setting size to something other than zero to # avoid crashes if surface_update() is runned # before the size is set. self.size = 15 self.icon = None self.surfaces = {} self.average_color = None self.max_win_nr = self.theme.get_windows_cnt() self.types_in_theme = 0 for type in self.theme.get_types(): if not type in self.TYPE_DICT: continue self.types_in_theme = self.types_in_theme | self.TYPE_DICT[type]
def __init__(self): """ Attributes ---------- metadata: dict presentation metadata; each element of the dictionary if a dict with ['value', 'user'] items: value contains the metadata value and user indicates if the value comes from user (if True) or from defaults (if False). """ self.reset() self.metadata = {'title': Metadata(name='title', value=''), 'subtitle': Metadata(name='subtitle', value=''), 'authors': Metadata(name='authors', value=[]), 'authors_short': Metadata(name='authors_short', value=[]), 'emails': Metadata(name='emails', value=[]), 'affiliations': Metadata(name='affiliations', value=[]), 'affiliations_short': Metadata(name='affiliations_short', value=[]), 'logo': Metadata(name='logo', value=''), 'timer': Metadata(name='timer', value=''), 'location': Metadata(name='location', value=''), 'location_short': Metadata(name='location_short', value=''), 'date': Metadata(name='date', value=''), 'conference': Metadata(name='conference', value=''), 'conference_short': Metadata(name='conference_short', value=''), 'session': Metadata(name='session', value=''), 'session_short': Metadata(name='session_short', value=''), 'max_time': Metadata(name='max_time', value='25'), 'total_slides_number': Metadata(name='total_slides_number', value=''), 'dirs_to_copy': Metadata(name='dirs_to_copy', value=[]), 'toc': Metadata(name='toc', value=OrderedDict()), 'toc_depth': Metadata(name='toc_depth', value='2'), 'chaptertitle': Metadata(name='chaptertitle', value=''), 'chapternumber': Metadata(name='chapternumber', value=''), 'sectiontitle': Metadata(name='sectiontitle', value=''), 'sectionnumber': Metadata(name='sectionnumber', value=''), 'subsectiontitle': Metadata(name='subsectiontitle', value=''), 'subsectionnumber': Metadata(name='subsectionnumber', value=''), 'slidetitle': Metadata(name='slidetitle', value=''), 'slidenumber': Metadata(name='slidenumber', value=''), 'css_overtheme': Metadata(name='css_overtheme', value=[]), 'custom': Metadata(name='custom-[0-9]*', value='')} self.theme = Theme() self.parser = Parser() self.chapters = [] self.position = Position() return
def __init__(self, number, position=None, title=None, contents=None): """" Paramters --------- number: int slide global numeration position: dict position dictionary containing {'x': posx, 'y': posy, 'z': posz, 'rotx': rotx, 'roty': roty, 'rotz': rotz, 'scale': scaling} title: str contents: str """ self.number = number self.position = None self.set_position(position) self.title = title self.contents = contents self.overtheme = Theme() return
def __init__(self, liststore): self.liststore = liststore self.gui = gui = Gtk.Builder() gui.add_from_file(SHARED_DATA_FILE("gfeedline.glade")) self.window = window = gui.get_object("main_window") self.column = MultiColumnDict(gui) # multi-columns for Notebooks self.theme = Theme() self.font = FontSet() self.notification = StatusNotification(liststore) dnd_list = [Gtk.TargetEntry.new("text/uri-list", 0, 1), Gtk.TargetEntry.new("text/x-moz-url", 0, 4)] window.drag_dest_set(Gtk.DestDefaults.ALL, dnd_list, Gdk.DragAction.COPY) target = Gtk.TargetList.new([]) target.add(Gdk.Atom.intern("text/x-moz-url", False), 0, 4) target.add(Gdk.Atom.intern("text/uri-list", False), 0, 1) window.drag_dest_set_target_list(target) window.connect("drag-data-received", self.on_drag_data_received) SETTINGS.connect("changed::window-sticky", self.on_settings_sticky_change) self.on_settings_sticky_change(SETTINGS, "window-sticky") SETTINGS_VIEW.connect("changed::theme", self.on_settings_theme_change) self.on_settings_theme_change(SETTINGS_VIEW, "theme") is_multi_column = SETTINGS_VIEW.get_boolean("multi-column") menuitem_multicolumn = gui.get_object("menuitem_multicolumn") menuitem_multicolumn.set_active(is_multi_column) menuitem_update = MenuItemUpdate(gui, liststore) x, y, w, h = self._get_geometry_from_settings() # window.show() # for wrong position when auto-start if x >= 0 and y >= 0: window.move(x, y) window.resize(w, h) window.show() gui.connect_signals(self)
def __init__(self, parent, connection): BasePane.__init__( self, parent, connection, style=wx.TE_AUTO_URL | wx.TE_READONLY | wx.TE_NOHIDESEL | wx.TE_MULTILINE ) # state toggles for ANSI processing self.intensity = "" self.inverse = False self.theme = Theme() # TODO - this probably should be a preference, but for now, this is the # least-bad default behavior. self.Bind(wx.EVT_SIZE, self.on_size) self.Bind(wx.EVT_SET_FOCUS, self.focus_input) self.Bind(wx.EVT_TEXT_URL, self.process_url_click) self.Bind(wx.EVT_MIDDLE_DOWN, self.connection.input_pane.paste_from_selection) self.Bind(rtc.EVT_RICHTEXT_SELECTION_CHANGED, self.copy_from_selection) self.Bind(EVT_ROW_COL_CHANGED, self.on_row_col_changed)
def __init__(self, alot_rc=None, notmuch_rc=None, theme=None): """ :param alot_rc: path to alot's config file :type alot_rc: str :param notmuch_rc: path to notmuch's config file :type notmuch_rc: str :theme: path to initially used theme file :type theme: str """ self.hooks = None self._mailcaps = mailcap.getcaps() theme_path = theme or os.path.join(DEFAULTSPATH, 'default.theme') self._theme = Theme(theme_path) bindings_path = os.path.join(DEFAULTSPATH, 'default.bindings') self._bindings = ConfigObj(bindings_path) self._config = ConfigObj() self._accounts = None self._accountmap = None self.read_config(alot_rc) self.read_notmuch_config(notmuch_rc)
def _get_viewers ( self ): from theme import Theme from image_slice_viewer import ImageSliceViewer slicer = self.slicer theme = Theme.decode_image_slice( slicer.encoded, slicer.image ) result = [ ImageSliceViewer( name = name, image_slice = info.image_slice ) for name, info in ( ( ( 'Bottom Label', 'Top Label' )[ theme.on_top ], theme.horizontal ), ( ( 'Right Label', 'Left Label' )[ theme.on_left ], theme.vertical ), ( 'Body', theme.body ) ) if info is not None ] result.insert( 0, ImageSliceViewer( name = 'Original', image = slicer.image ) ) return result
def __init__(self, parent=None): super(MyElement, self).__init__() self.setObjectName('mainObject') self._users = [] self._index = 0 self._myTheme = Theme() self._myColor = self._myTheme.getTheme() self.mainProc = QProcess() self.secondProc = QProcess() self.mainProc.finished.connect(self.finishProc) self.mainProc.started.connect(self.startProc) self.secondProc.finished.connect(self.secondFinishProc) self.secondProc.started.connect(self.startProc) self.auth = Auth() self._isiPesan = "" self._judulPesan = "Error" self._overlay = "" self._isLock = False self._hasRegister = False self._hasLogin = False self._hasError = False self._userListData = UserItemModel() self._userListData.addRootElement() self.addNewUser()
class Presentation(object): """ Presentation object. Attributes ---------- chapters_number: int """ chapters_number = 0 @classmethod def reset(cls): """Reset to default state.""" cls.chapters_number = 0 Theme.reset() Chapter.reset() def __init__(self): """ Attributes ---------- metadata: dict presentation metadata; each element of the dictionary if a dict with ['value', 'user'] items: value contains the metadata value and user indicates if the value comes from user (if True) or from defaults (if False). """ self.reset() self.metadata = { 'title': Metadata(name='title', value=''), 'subtitle': Metadata(name='subtitle', value=''), 'authors': Metadata(name='authors', value=[]), 'authors_short': Metadata(name='authors_short', value=[]), 'emails': Metadata(name='emails', value=[]), 'affiliations': Metadata(name='affiliations', value=[]), 'affiliations_short': Metadata(name='affiliations_short', value=[]), 'logo': Metadata(name='logo', value=''), 'timer': Metadata(name='timer', value=''), 'location': Metadata(name='location', value=''), 'location_short': Metadata(name='location_short', value=''), 'date': Metadata(name='date', value=''), 'conference': Metadata(name='conference', value=''), 'conference_short': Metadata(name='conference_short', value=''), 'session': Metadata(name='session', value=''), 'session_short': Metadata(name='session_short', value=''), 'max_time': Metadata(name='max_time', value='25'), 'total_slides_number': Metadata(name='total_slides_number', value=''), 'dirs_to_copy': Metadata(name='dirs_to_copy', value=[]), 'toc': Metadata(name='toc', value=OrderedDict()), 'toc_depth': Metadata(name='toc_depth', value='2'), 'chaptertitle': Metadata(name='chaptertitle', value=''), 'chapternumber': Metadata(name='chapternumber', value=''), 'sectiontitle': Metadata(name='sectiontitle', value=''), 'sectionnumber': Metadata(name='sectionnumber', value=''), 'subsectiontitle': Metadata(name='subsectiontitle', value=''), 'subsectionnumber': Metadata(name='subsectionnumber', value=''), 'slidetitle': Metadata(name='slidetitle', value=''), 'slidenumber': Metadata(name='slidenumber', value=''), 'css_overtheme': Metadata(name='css_overtheme', value=[]), 'custom': Metadata(name='custom-[0-9]*', value='') } self.theme = Theme() self.parser = Parser() self.chapters = [] self.position = Position() return def __str__(self): strings = ['Chapters number ' + str(Presentation.chapters_number)] strings.append('Sections number ' + str(Chapter.sections_number)) strings.append('Subsections number ' + str(Section.subsections_number)) strings.append('Slides number ' + str(Subsection.slides_number)) for chapter in self.chapters: strings.append(str(chapter)) return '\n'.join(strings) def __update_toc(self): """Update TOC after a new chapter (the last one) has been added.""" self.metadata['toc'].value[ self.chapters[-1].title] = self.chapters[-1].toc def __get_metadata(self, source): """ Get metadata from source stream. Parameters ---------- source: str """ codeblocks = self.parser.tokenizer( source=source, re_search=self.parser.regexs['codeblock']) yamlblocks = self.parser.tokenizer( source=source, re_search=self.parser.regexs['yamlblock'], exclude=codeblocks) try: for block in yamlblocks: for data in load_all(block['match'].group().strip('---')): if 'metadata' in data: for element in data['metadata']: for key in element: if key in self.metadata: self.metadata[key].update_value( value=element[key]) except YAMLError: print('No valid definition of metadata has been found') def __get_theme(self, source): """ Get theme from source stream. Parameters ---------- source: str """ codeblocks = self.parser.tokenizer( source=source, re_search=self.parser.regexs['codeblock']) yamlblocks = self.parser.tokenizer( source=source, re_search=self.parser.regexs['yamlblock'], exclude=codeblocks) self.theme.get(''.join( [block['match'].group().strip('---') for block in yamlblocks])) def __add_chapter(self, chapter): """ Add a chapter to the pesentation. Parameters ---------- chapter: Chapter """ Presentation.chapters_number += 1 self.chapters.append(chapter) self.__update_toc() return def __check_bad_sectioning(self, tokens): """Check if the presentation has a bad sectioning. Parameters ---------- tokens: Parser.tokens source: str """ if '$titlepage' not in tokens['slides'][0]['match'].group().lower(): if tokens['slides'][0]['start'] < tokens['subsections'][0][ 'start'] or tokens['slides'][0]['start'] < tokens[ 'sections'][0]['start'] or tokens['slides'][0][ 'start'] < tokens['chapters'][0]['start']: print('Warning: found bad presentation sectioning!') print('The slide definition:') print(tokens['slides'][0]['match'].group() + "\n") print( 'is placed before the first defined chapter/section/subsection.' ) print( 'All contents before the first defined chapter/section/subsection is omitted!' ) print() return def __put_html_tag_head(self, doc, tag, text, config): """Put head tag into html doc. Parameters ---------- doc: Doc() tag: Tag() config : MatisseConfig MaTiSSe configuration """ with tag('head'): doc.stag('meta', charset='utf-8') doc.stag('meta', author=' and '.join(self.metadata['authors'].value)) with tag('title'): text(self.metadata['title'].value) doc.stag('meta', subtitle=self.metadata['subtitle'].value) doc.stag('link', rel='stylesheet', href='css/normalize.css') doc.stag('link', rel='stylesheet', href='css/matisse_defaults.css') doc.stag('link', rel='stylesheet', href='css/matisse_defaults_printing.css') if config.highlight: doc.stag('link', rel='stylesheet', href='js/highlight/styles/' + config.highlight_style) doc.stag('link', rel='stylesheet', href='css/theme.css') for css in self.metadata['css_overtheme'].value: doc.stag('link', rel='stylesheet', href=css) for chapter in self.chapters: for section in chapter.sections: for subsection in section.subsections: for slide in subsection.slides: if slide.overtheme.custom: doc.stag('link', rel='stylesheet', href='css/slide-' + str(slide.number) + '-overtheme.css') def __put_html_tags_scripts(self, doc, tag, config): """Put final tags for scripts into html doc. Parameters ---------- doc: Doc() tag: Tag() config : MatisseConfig MaTiSSe configuration """ with tag('script'): doc.attr(src='js/countDown.js') with tag('script'): doc.attr(src='js/impress.js') if not config.pdf: with tag('script'): doc.asis('impress().init();') if config.online_mathjax: with tag('script'): doc.attr(('type', 'text/javascript')) doc.attr( src= 'http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML' ) else: with tag('script'): doc.attr(('type', 'text/x-mathjax-config')) doc.text(""" MathJax.Hub.Config({ extensions: ["tex2jax.js"], jax: ["input/TeX", "output/HTML-CSS"], tex2jax: { inlineMath: [ ['$','$'] ], displayMath: [ ['$$','$$'] ], processEscapes: true }, "HTML-CSS": { availableFonts: ["Neo-Euler"] } }); """) with tag('script'): doc.attr(('type', 'text/javascript')) doc.attr(src='js/MathJax/MathJax.js') if config.highlight: with tag('script'): doc.attr(src='js/highlight/highlight.pack.js') with tag('script'): doc.text("""hljs.initHighlightingOnLoad();""") def __put_html_slide_decorators(self, tag, doc, decorator, position=None, overtheme=None, current=None): """Put html data of headers, footers and sidebars. Parameters ---------- doc: Doc tag: tag decorator: {header, footer, sidebar} position: {'L','R'} sidebars position, L => left, R => right current: list """ if overtheme is not None and overtheme.custom: theme = overtheme else: theme = self.theme # decorators = getattr(self.theme, 'slide_' + decorator) decorators = getattr(theme, 'slide_' + decorator) for decor in sorted(decorators): insert = True # position check for sidebars if decorator == 'sidebar' and position is not None: for css in decorators[decor]: for key in css: if 'position' in key.lower(): pos = css[key] break insert = pos.lower() == position.lower() # active check for css in decorators[decor]: for key in css: if 'active' in key.lower(): insert = insert and css[key].lower() == 'yes' if insert: # placeholders = self.theme.get_slide_decorators_metadata(decorator=decorator, name=decor) placeholders = theme.get_slide_decorators_metadata( decorator=decorator, name=decor) for metadata in self.metadata: placeholders = self.metadata[metadata].parse( parser=self.parser, source=placeholders, toc_depth=self.metadata['toc_depth'].value, max_time=self.metadata['max_time'].value, current=current) with tag('div', klass='slide-' + decor): doc.asis(placeholders) def parse(self, config, source): """Parse presentation from source stream. Parameters ---------- config : MatisseConfig MaTiSSe configuration source: str """ complete_source = self.parser.includes(source=source) self.__get_metadata(source=complete_source) self.__get_theme(source=complete_source) new_theme = Theme() new_theme.set_from(other=self.theme) tokens = self.parser.tokenize(source=complete_source) self.__check_bad_sectioning(tokens=tokens) chapters_number = 0 sections_number = 0 subsections_number = 0 slides_number = 0 titlepage_inserted = False for chap in tokens['chapters']: chapters_number += 1 slide_local_numbers = [0, 0, 0] if chap['match'].group('expr'): chapter = Chapter(number=chapters_number, title=chap['match'].group('expr')) else: chapter = Chapter(number=chapters_number, title='') for sec in tokens['sections']: if sec['start'] >= chap['start'] and sec['start'] <= chap[ 'end_next']: sections_number += 1 slide_local_numbers[1] = 0 slide_local_numbers[2] = 0 section = Section(number=sections_number, title=sec['match'].group('expr')) for subsec in tokens['subsections']: if subsec['start'] >= sec['start'] and subsec[ 'start'] <= sec['end_next']: subsections_number += 1 slide_local_numbers[2] = 0 subsection = Subsection( number=subsections_number, title=subsec['match'].group('expr')) for sld in tokens['slides']: if '$titlepage' in sld['match'].group().lower( ) and not titlepage_inserted: slide = Slide( number=0, title='titlepage', contents=complete_source[ sld['end']:sld['end_next']]) slide.get_overtheme(parser=self.parser) if slide.overtheme.copy_from_theme is not None and slide.overtheme.copy_from_theme: slide.overtheme.copy_from( other=self.theme) self.position.update_position( presentation_theme=self.theme, overtheme=slide.overtheme) slide.set_position( position=self.position.position) subsection.add_slide(slide=slide) titlepage_inserted = True else: if sld['start'] >= subsec['start'] and sld[ 'start'] <= subsec['end_next']: slide_local_numbers[0] += 1 slide_local_numbers[1] += 1 slide_local_numbers[2] += 1 if slide_local_numbers[ 0] == 1 and config.toc_at_chap_beginning is not None: slides_number += 1 self.position.update_position( presentation_theme=self.theme) subsection.add_slide(slide=Slide( number=slides_number, position=self.position. position, title='Table of Contents', contents='$toc[depth:' + str(config. toc_at_chap_beginning) + ']')) if slide_local_numbers[ 1] == 1 and config.toc_at_sec_beginning is not None: slides_number += 1 self.position.update_position( presentation_theme=self.theme) subsection.add_slide(slide=Slide( number=slides_number, position=self.position. position, title='Table of Contents', contents='$toc[depth:' + str(config.toc_at_sec_beginning ) + ']')) if slide_local_numbers[ 2] == 1 and config.toc_at_subsec_beginning is not None: slides_number += 1 self.position.update_position( presentation_theme=self.theme) subsection.add_slide(slide=Slide( number=slides_number, position=self.position. position, title='Table of Contents', contents='$toc[depth:' + str(config. toc_at_subsec_beginning) + ']')) slides_number += 1 slide = Slide( number=slides_number, title=sld['match'].group('expr'), contents=complete_source[ sld['end']:sld['end_next']]) slide.get_overtheme(parser=self.parser) if slide.overtheme.copy_from_theme is not None and slide.overtheme.copy_from_theme: slide.overtheme.copy_from( other=self.theme) self.position.update_position( presentation_theme=self.theme, overtheme=slide.overtheme) slide.set_position( position=self.position.position) subsection.add_slide(slide=slide) section.add_subsection(subsection=subsection) chapter.add_section(section=section) self.__add_chapter(chapter=chapter) self.metadata['total_slides_number'].update_value( value=str(Subsection.slides_number)) def to_html(self, config): """Generate a html stream of the whole presentation. Parameters ---------- config : MatisseConfig MaTiSSe configuration """ doc, tag, text = Doc().tagtext() doc.asis('<!DOCTYPE html>') with tag('html'): # doc.attr(title=self.metadata['title'].value) self.__put_html_tag_head(doc=doc, tag=tag, text=text, config=config) with tag('body', onload="resetCountdown(" + str(self.metadata['max_time'].value) + ");"): doc.attr(klass='impress-not-supported') with tag('div', id='impress'): # numbering: [local_chap, local_sec, local_subsec, local_slide] current = [0, 0, 0, 0] for chapter in self.chapters: current[0] += 1 current[1] = 0 current[2] = 0 current[3] = 0 self.metadata['chaptertitle'].update_value( value=chapter.title) self.metadata['chapternumber'].update_value( value=chapter.number) for section in chapter.sections: current[1] += 1 current[2] = 0 current[3] = 0 self.metadata['sectiontitle'].update_value( value=section.title) self.metadata['sectionnumber'].update_value( value=section.number) for subsection in section.subsections: current[2] += 1 current[3] = 0 self.metadata['subsectiontitle'].update_value( value=subsection.title) self.metadata['subsectionnumber'].update_value( value=subsection.number) for slide in subsection.slides: current[3] += 1 self.metadata['slidetitle'].update_value( value=slide.title) self.metadata['slidenumber'].update_value( value=slide.number) with doc.tag('div'): chapter.put_html_attributes(doc=doc) section.put_html_attributes(doc=doc) subsection.put_html_attributes(doc=doc) slide.put_html_attributes(doc=doc) self.__put_html_slide_decorators( tag=tag, doc=doc, decorator='header', current=current, overtheme=slide.overtheme) self.__put_html_slide_decorators( tag=tag, doc=doc, decorator='sidebar', position='L', current=current, overtheme=slide.overtheme) slide.to_html(doc=doc, parser=self.parser, metadata=self.metadata, theme=self.theme, current=current) self.__put_html_slide_decorators( tag=tag, doc=doc, decorator='sidebar', position='R', current=current, overtheme=slide.overtheme) self.__put_html_slide_decorators( tag=tag, doc=doc, decorator='footer', current=current, overtheme=slide.overtheme) self.__put_html_tags_scripts(doc=doc, tag=tag, config=config) # source = re.sub(r"<li>(?P<item>.*)</li>", r"<li><span>\g<item></span></li>", source) html = indent(doc.getvalue()) return html def save(self, config, output): """Save the html form of presentation into external file. Parameters ---------- config : MatisseConfig MaTiSSe configuration output : str output path """ if not os.path.exists(output): os.makedirs(output) with open(os.path.join(output, 'index.html'), 'w') as html: html.write(self.to_html(config=config)) # copy user defined directories if set if len(self.metadata['dirs_to_copy'].value) > 0: for data in self.metadata['dirs_to_copy'].value: sync_logger = logging.getLogger('sync_logger') sync(data, os.path.join(output, data), 'sync', create=True, logger=sync_logger) # css files with open(os.path.join(output, 'css/theme.css'), 'w') as css_theme: css_theme.writelines(self.theme.css) for chapter in self.chapters: for section in chapter.sections: for subsection in section.subsections: for slide in subsection.slides: if slide.overtheme.custom: with open( os.path.join( output, 'css/slide-' + str(slide.number) + '-overtheme.css'), 'w') as css_theme: css_theme.writelines(slide.overtheme.css) return
class Presentation(object): """ Presentation object. Attributes ---------- chapters_number: int """ chapters_number = 0 @classmethod def reset(cls): """Reset to default state.""" cls.chapters_number = 0 Theme.reset() Chapter.reset() def __init__(self): """ Attributes ---------- metadata: dict presentation metadata; each element of the dictionary if a dict with ['value', 'user'] items: value contains the metadata value and user indicates if the value comes from user (if True) or from defaults (if False). """ self.reset() self.metadata = {'title': Metadata(name='title', value=''), 'subtitle': Metadata(name='subtitle', value=''), 'authors': Metadata(name='authors', value=[]), 'authors_short': Metadata(name='authors_short', value=[]), 'emails': Metadata(name='emails', value=[]), 'affiliations': Metadata(name='affiliations', value=[]), 'affiliations_short': Metadata(name='affiliations_short', value=[]), 'logo': Metadata(name='logo', value=''), 'timer': Metadata(name='timer', value=''), 'location': Metadata(name='location', value=''), 'location_short': Metadata(name='location_short', value=''), 'date': Metadata(name='date', value=''), 'conference': Metadata(name='conference', value=''), 'conference_short': Metadata(name='conference_short', value=''), 'session': Metadata(name='session', value=''), 'session_short': Metadata(name='session_short', value=''), 'max_time': Metadata(name='max_time', value='25'), 'total_slides_number': Metadata(name='total_slides_number', value=''), 'dirs_to_copy': Metadata(name='dirs_to_copy', value=[]), 'toc': Metadata(name='toc', value=OrderedDict()), 'toc_depth': Metadata(name='toc_depth', value='2'), 'chaptertitle': Metadata(name='chaptertitle', value=''), 'chapternumber': Metadata(name='chapternumber', value=''), 'sectiontitle': Metadata(name='sectiontitle', value=''), 'sectionnumber': Metadata(name='sectionnumber', value=''), 'subsectiontitle': Metadata(name='subsectiontitle', value=''), 'subsectionnumber': Metadata(name='subsectionnumber', value=''), 'slidetitle': Metadata(name='slidetitle', value=''), 'slidenumber': Metadata(name='slidenumber', value=''), 'css_overtheme': Metadata(name='css_overtheme', value=[]), 'custom': Metadata(name='custom-[0-9]*', value='')} self.theme = Theme() self.parser = Parser() self.chapters = [] self.position = Position() return def __str__(self): strings = ['Chapters number ' + str(Presentation.chapters_number)] strings.append('Sections number ' + str(Chapter.sections_number)) strings.append('Subsections number ' + str(Section.subsections_number)) strings.append('Slides number ' + str(Subsection.slides_number)) for chapter in self.chapters: strings.append(str(chapter)) return '\n'.join(strings) def __update_toc(self): """Update TOC after a new chapter (the last one) has been added.""" self.metadata['toc'].value[self.chapters[-1].title] = self.chapters[-1].toc def __get_metadata(self, source): """ Get metadata from source stream. Parameters ---------- source: str """ codeblocks = self.parser.tokenizer(source=source, re_search=self.parser.regexs['codeblock']) yamlblocks = self.parser.tokenizer(source=source, re_search=self.parser.regexs['yamlblock'], exclude=codeblocks) try: for block in yamlblocks: for data in load_all(block['match'].group().strip('---')): if 'metadata' in data: for element in data['metadata']: for key in element: if key in self.metadata: self.metadata[key].update_value(value=element[key]) except YAMLError: print('No valid definition of metadata has been found') def __get_theme(self, source): """ Get theme from source stream. Parameters ---------- source: str """ codeblocks = self.parser.tokenizer(source=source, re_search=self.parser.regexs['codeblock']) yamlblocks = self.parser.tokenizer(source=source, re_search=self.parser.regexs['yamlblock'], exclude=codeblocks) self.theme.get(''.join([block['match'].group().strip('---') for block in yamlblocks])) def __add_chapter(self, chapter): """ Add a chapter to the pesentation. Parameters ---------- chapter: Chapter """ Presentation.chapters_number += 1 self.chapters.append(chapter) self.__update_toc() return def __check_bad_sectioning(self, tokens): """Check if the presentation has a bad sectioning. Parameters ---------- tokens: Parser.tokens source: str """ if '$titlepage' not in tokens['slides'][0]['match'].group().lower(): if tokens['slides'][0]['start'] < tokens['subsections'][0]['start'] or tokens['slides'][0]['start'] < tokens['sections'][0]['start'] or tokens['slides'][0]['start'] < tokens['chapters'][0]['start']: print('Warning: found bad presentation sectioning!') print('The slide definition:') print(tokens['slides'][0]['match'].group() + "\n") print('is placed before the first defined chapter/section/subsection.') print('All contents before the first defined chapter/section/subsection is omitted!') print() return def __put_html_tag_head(self, doc, tag, text, config): """Put head tag into html doc. Parameters ---------- doc: Doc() tag: Tag() config : MatisseConfig MaTiSSe configuration """ with tag('head'): doc.stag('meta', charset='utf-8') doc.stag('meta', author=' and '.join(self.metadata['authors'].value)) with tag('title'): text(self.metadata['title'].value) doc.stag('meta', subtitle=self.metadata['subtitle'].value) doc.stag('link', rel='stylesheet', href='css/normalize.css') doc.stag('link', rel='stylesheet', href='css/matisse_defaults.css') doc.stag('link', rel='stylesheet', href='css/matisse_defaults_printing.css') if config.highlight: doc.stag('link', rel='stylesheet', href='js/highlight/styles/' + config.highlight_style) doc.stag('link', rel='stylesheet', href='css/theme.css') for css in self.metadata['css_overtheme'].value: doc.stag('link', rel='stylesheet', href=css) for chapter in self.chapters: for section in chapter.sections: for subsection in section.subsections: for slide in subsection.slides: if slide.overtheme.custom: doc.stag('link', rel='stylesheet', href='css/slide-' + str(slide.number) + '-overtheme.css') def __put_html_tags_scripts(self, doc, tag, config): """Put final tags for scripts into html doc. Parameters ---------- doc: Doc() tag: Tag() config : MatisseConfig MaTiSSe configuration """ with tag('script'): doc.attr(src='js/countDown.js') with tag('script'): doc.attr(src='js/impress.js') if not config.pdf: with tag('script'): doc.asis('impress().init();') if config.online_mathjax: with tag('script'): doc.attr(('type', 'text/javascript')) doc.attr(src='http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML') else: with tag('script'): doc.attr(('type', 'text/x-mathjax-config')) doc.text(""" MathJax.Hub.Config({ extensions: ["tex2jax.js"], jax: ["input/TeX", "output/HTML-CSS"], tex2jax: { inlineMath: [ ['$','$'] ], displayMath: [ ['$$','$$'] ], processEscapes: true }, "HTML-CSS": { availableFonts: ["Neo-Euler"] } }); """) with tag('script'): doc.attr(('type', 'text/javascript')) doc.attr(src='js/MathJax/MathJax.js') if config.highlight: with tag('script'): doc.attr(src='js/highlight/highlight.pack.js') with tag('script'): doc.text("""hljs.initHighlightingOnLoad();""") def __put_html_slide_decorators(self, tag, doc, decorator, position=None, overtheme=None, current=None): """Put html data of headers, footers and sidebars. Parameters ---------- doc: Doc tag: tag decorator: {header, footer, sidebar} position: {'L','R'} sidebars position, L => left, R => right current: list """ if overtheme is not None and overtheme.custom: theme = overtheme else: theme = self.theme # decorators = getattr(self.theme, 'slide_' + decorator) decorators = getattr(theme, 'slide_' + decorator) for decor in sorted(decorators): insert = True # position check for sidebars if decorator == 'sidebar' and position is not None: for css in decorators[decor]: for key in css: if 'position' in key.lower(): pos = css[key] break insert = pos.lower() == position.lower() # active check for css in decorators[decor]: for key in css: if 'active' in key.lower(): insert = insert and css[key].lower() == 'yes' if insert: # placeholders = self.theme.get_slide_decorators_metadata(decorator=decorator, name=decor) placeholders = theme.get_slide_decorators_metadata(decorator=decorator, name=decor) for metadata in self.metadata: placeholders = self.metadata[metadata].parse(parser=self.parser, source=placeholders, toc_depth=self.metadata['toc_depth'].value, max_time=self.metadata['max_time'].value, current=current) with tag('div', klass='slide-' + decor): doc.asis(placeholders) def parse(self, config, source): """Parse presentation from source stream. Parameters ---------- config : MatisseConfig MaTiSSe configuration source: str """ complete_source = self.parser.includes(source=source) self.__get_metadata(source=complete_source) self.__get_theme(source=complete_source) new_theme = Theme() new_theme.set_from(other=self.theme) tokens = self.parser.tokenize(source=complete_source) self.__check_bad_sectioning(tokens=tokens) chapters_number = 0 sections_number = 0 subsections_number = 0 slides_number = 0 titlepage_inserted = False for chap in tokens['chapters']: chapters_number += 1 slide_local_numbers = [0, 0, 0] if chap['match'].group('expr'): chapter = Chapter(number=chapters_number, title=chap['match'].group('expr')) else: chapter = Chapter(number=chapters_number, title='') for sec in tokens['sections']: if sec['start'] >= chap['start'] and sec['start'] <= chap['end_next']: sections_number += 1 slide_local_numbers[1] = 0 slide_local_numbers[2] = 0 section = Section(number=sections_number, title=sec['match'].group('expr')) for subsec in tokens['subsections']: if subsec['start'] >= sec['start'] and subsec['start'] <= sec['end_next']: subsections_number += 1 slide_local_numbers[2] = 0 subsection = Subsection(number=subsections_number, title=subsec['match'].group('expr')) for sld in tokens['slides']: if '$titlepage' in sld['match'].group().lower() and not titlepage_inserted: slide = Slide(number=0, title='titlepage', contents=complete_source[sld['end']:sld['end_next']]) slide.get_overtheme(parser=self.parser) if slide.overtheme.copy_from_theme is not None and slide.overtheme.copy_from_theme: slide.overtheme.copy_from(other=self.theme) self.position.update_position(presentation_theme=self.theme, overtheme=slide.overtheme) slide.set_position(position=self.position.position) subsection.add_slide(slide=slide) titlepage_inserted = True else: if sld['start'] >= subsec['start'] and sld['start'] <= subsec['end_next']: slide_local_numbers[0] += 1 slide_local_numbers[1] += 1 slide_local_numbers[2] += 1 if slide_local_numbers[0] == 1 and config.toc_at_chap_beginning is not None: slides_number += 1 self.position.update_position(presentation_theme=self.theme) subsection.add_slide(slide=Slide(number=slides_number, position=self.position.position, title='Table of Contents', contents='$toc[depth:' + str(config.toc_at_chap_beginning) + ']')) if slide_local_numbers[1] == 1 and config.toc_at_sec_beginning is not None: slides_number += 1 self.position.update_position(presentation_theme=self.theme) subsection.add_slide(slide=Slide(number=slides_number, position=self.position.position, title='Table of Contents', contents='$toc[depth:' + str(config.toc_at_sec_beginning) + ']')) if slide_local_numbers[2] == 1 and config.toc_at_subsec_beginning is not None: slides_number += 1 self.position.update_position(presentation_theme=self.theme) subsection.add_slide(slide=Slide(number=slides_number, position=self.position.position, title='Table of Contents', contents='$toc[depth:' + str(config.toc_at_subsec_beginning) + ']')) slides_number += 1 slide = Slide(number=slides_number, title=sld['match'].group('expr'), contents=complete_source[sld['end']:sld['end_next']]) slide.get_overtheme(parser=self.parser) if slide.overtheme.copy_from_theme is not None and slide.overtheme.copy_from_theme: slide.overtheme.copy_from(other=self.theme) self.position.update_position(presentation_theme=self.theme, overtheme=slide.overtheme) slide.set_position(position=self.position.position) subsection.add_slide(slide=slide) section.add_subsection(subsection=subsection) chapter.add_section(section=section) self.__add_chapter(chapter=chapter) self.metadata['total_slides_number'].update_value(value=str(Subsection.slides_number)) def to_html(self, config): """Generate a html stream of the whole presentation. Parameters ---------- config : MatisseConfig MaTiSSe configuration """ doc, tag, text = Doc().tagtext() doc.asis('<!DOCTYPE html>') with tag('html'): # doc.attr(title=self.metadata['title'].value) self.__put_html_tag_head(doc=doc, tag=tag, text=text, config=config) with tag('body', onload="resetCountdown(" + str(self.metadata['max_time'].value) + ");"): doc.attr(klass='impress-not-supported') with tag('div', id='impress'): # numbering: [local_chap, local_sec, local_subsec, local_slide] current = [0, 0, 0, 0] for chapter in self.chapters: current[0] += 1 current[1] = 0 current[2] = 0 current[3] = 0 self.metadata['chaptertitle'].update_value(value=chapter.title) self.metadata['chapternumber'].update_value(value=chapter.number) for section in chapter.sections: current[1] += 1 current[2] = 0 current[3] = 0 self.metadata['sectiontitle'].update_value(value=section.title) self.metadata['sectionnumber'].update_value(value=section.number) for subsection in section.subsections: current[2] += 1 current[3] = 0 self.metadata['subsectiontitle'].update_value(value=subsection.title) self.metadata['subsectionnumber'].update_value(value=subsection.number) for slide in subsection.slides: current[3] += 1 self.metadata['slidetitle'].update_value(value=slide.title) self.metadata['slidenumber'].update_value(value=slide.number) with doc.tag('div'): chapter.put_html_attributes(doc=doc) section.put_html_attributes(doc=doc) subsection.put_html_attributes(doc=doc) slide.put_html_attributes(doc=doc) self.__put_html_slide_decorators(tag=tag, doc=doc, decorator='header', current=current, overtheme=slide.overtheme) self.__put_html_slide_decorators(tag=tag, doc=doc, decorator='sidebar', position='L', current=current, overtheme=slide.overtheme) slide.to_html(doc=doc, parser=self.parser, metadata=self.metadata, theme=self.theme, current=current) self.__put_html_slide_decorators(tag=tag, doc=doc, decorator='sidebar', position='R', current=current, overtheme=slide.overtheme) self.__put_html_slide_decorators(tag=tag, doc=doc, decorator='footer', current=current, overtheme=slide.overtheme) self.__put_html_tags_scripts(doc=doc, tag=tag, config=config) # source = re.sub(r"<li>(?P<item>.*)</li>", r"<li><span>\g<item></span></li>", source) html = indent(doc.getvalue()) return html def save(self, config, output): """Save the html form of presentation into external file. Parameters ---------- config : MatisseConfig MaTiSSe configuration output : str output path """ if not os.path.exists(output): os.makedirs(output) with open(os.path.join(output, 'index.html'), 'w') as html: html.write(self.to_html(config=config)) # copy user defined directories if set if len(self.metadata['dirs_to_copy'].value) > 0: for data in self.metadata['dirs_to_copy'].value: sync_logger = logging.getLogger('sync_logger') sync(data, os.path.join(output, data), 'sync', create=True, logger=sync_logger) # css files with open(os.path.join(output, 'css/theme.css'), 'w') as css_theme: css_theme.writelines(self.theme.css) for chapter in self.chapters: for section in chapter.sections: for subsection in section.subsections: for slide in subsection.slides: if slide.overtheme.custom: with open(os.path.join(output, 'css/slide-' + str(slide.number) + '-overtheme.css'), 'w') as css_theme: css_theme.writelines(slide.overtheme.css) return
def reset(cls): """Reset to default state.""" cls.chapters_number = 0 Theme.reset() Chapter.reset()
class IconFactory(): """IconFactory takes care of finding the right icon for a program and prepares the cairo surface.""" icon_theme = gtk.icon_theme_get_default() # Constants # Icon types SOME_MINIMIZED = 1<<4 ALL_MINIMIZED = 1<<5 LAUNCHER = 1<<6 # Icon effects MOUSE_OVER = 1<<7 MOUSE_BUTTON_DOWN = 1<<8 NEEDS_ATTENTION = 1<<9 BLINK = 1<<10 # ACTIVE_WINDOW ACTIVE = 1<<11 LAUNCH_EFFECT = 1<<12 # Double width/height icons for drag and drop situations. DRAG_DROPP = 1<<13 TYPE_DICT = {'some_minimized':SOME_MINIMIZED, 'all_minimized':ALL_MINIMIZED, 'launcher':LAUNCHER, 'mouse_over':MOUSE_OVER, 'needs_attention':NEEDS_ATTENTION, 'blink':BLINK, 'active':ACTIVE, 'launching':LAUNCH_EFFECT, 'mouse_button_down':MOUSE_BUTTON_DOWN} def __init__(self, class_group=None, desktop_entry=None, identifier=None): self.theme = Theme() self.globals = Globals() self.globals.connect('color-changed', self.reset_surfaces) self.desktop_entry = desktop_entry self.identifier = identifier self.class_group = class_group # Setting size to something other than zero to # avoid crashes if surface_update() is runned # before the size is set. self.size = 15 self.icon = None self.surfaces = {} self.average_color = None self.max_win_nr = self.theme.get_windows_cnt() self.types_in_theme = 0 for type in self.theme.get_types(): if not type in self.TYPE_DICT: continue self.types_in_theme = self.types_in_theme | self.TYPE_DICT[type] def remove(self): del self.desktop_entry del self.class_group del self.icon del self.surfaces del self.theme def set_desktop_entry(self, desktop_entry): self.desktop_entry = desktop_entry self.surfaces = {} del self.icon self.icon = None def set_class_group(self, class_group): if not self.desktop_entry and not self.class_group: self.surfaces = {} del self.icon self.icon = None self.class_group = class_group def set_size(self, size): if size <= 0: # To avoid chrashes. size = 15 self.size = size self.surfaces = {} self.average_color = None def get_size(self): return self.size def reset_surfaces(self, arg=None): self.surfaces = {} self.average_color = None def surface_update(self, type = 0): # Checks if the requested pixbuf is already # drawn and returns it if it is. # Othervice the surface is drawn, saved and returned. #The first four bits of type is for telling the number of windows self.win_nr = min(type & 15, self.max_win_nr) # Remove all types that are not used by the theme (saves memory) dnd = type & self.DRAG_DROPP type = type & self.types_in_theme type += self.win_nr if type in self.surfaces: surface = self.surfaces[type] else: self.temp = {} surface = None commands = self.theme.get_icon_dict() self.ar = self.theme.get_aspect_ratio() self.type = type for command, args in commands.items(): try: f = getattr(self,"command_%s"%command) except: raise else: surface = f(surface, **args) # Todo: add size correction. self.surfaces[type] = surface del self.temp gc.collect() if dnd: surface = self.dd_highlight(surface, self.globals.orient) gc.collect() return surface def dd_highlight(self, surface, direction = 'h'): w = surface.get_width() h = surface.get_height() # Make a background almost twice as wide or high # as the surface depending on panel orientation. if direction == 'v': h = h + 4 else: w = w + 4 bg = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) ctx = cairo.Context(bg) # Put arrow pointing to the empty part on it. if direction == 'v': ctx.move_to(1, h - 1.5) ctx.line_to(w - 1, h - 1.5) ctx.set_source_rgba(1, 1, 1, 0.2) ctx.set_line_width(2) ctx.stroke() ctx.move_to(2, h - 1.5) ctx.line_to(w - 2, h - 1.5) ctx.set_source_rgba(0, 0, 0, 0.7) ctx.set_line_width(1) ctx.stroke() else: ctx.move_to(w - 1.5, 1) ctx.line_to(w - 1.5, h - 1) ctx.set_source_rgba(1, 1, 1, 0.2) ctx.set_line_width(2) ctx.stroke() ctx.move_to(w - 1.5, 2) ctx.line_to(w - 1.5, h - 2) ctx.set_source_rgba(0, 0, 0, 0.7) ctx.set_line_width(1) ctx.stroke() # And put the surface on the left/upper half of it. ctx.set_source_surface(surface, 0, 0) ctx.paint() return bg def get_color(self, color): if color == "active_color": color = 'color5' if color in ['color%s'%i for i in range(1, 9)]: color = self.globals.colors[color] if color == "icon_average": color = self.get_average_color() else: try: if len(color) != 7: raise ValueError('The string has the wrong lenght') t = int(color[1:], 16) except: print "Theme error: the color attribute for a theme command"+ \ " should be a six digit hex string eg. \"#FFFFFF\" or"+ \ " the a dockbarx color (\"color1\"-\"color8\")." color = "#000000" return color def get_alpha(self, alpha): # Transparency if alpha == "active_opacity": # For backwards compability alpha = "color5" for i in range(1, 9): if alpha in ('color%s'%i, 'opacity%s'%i): if self.globals.colors.has_key('color%s_alpha'%i): a = float(self.globals.colors['color%s_alpha'%i])/255 else: print "Theme error: The theme has no" + \ " opacity option for color%s."%i a = 1.0 break else: try: a = float(alpha)/100 if a > 1.0 or a < 0: raise except: print 'Theme error: The opacity attribute of a theme ' + \ 'command should be a number between "0" ' + \ ' and "100" or "color1" to "color8".' a = 1.0 return a def get_average_color(self): if self.average_color is not None: return self.average_color r = 0 b = 0 g = 0 i = 0 pb = self.surface2pixbuf(self.icon) for row in pb.get_pixels_array(): for pix in row: if pix[3] > 30: i += 1 r += pix[0] g += pix[1] b += pix[2] if i > 0: r = int(float(r) / i + 0.5) g = int(float(g) / i + 0.5) b = int(float(b) / i + 0.5) r = ("0%s"%hex(r)[2:])[-2:] g = ("0%s"%hex(g)[2:])[-2:] b = ("0%s"%hex(b)[2:])[-2:] self.average_color = "#"+r+g+b del pb return self.average_color #### Flow commands def command_if(self, surface, type=None, windows=None, size=None, content=None): if content is None: return surface # TODO: complete this ## l = [] ## splits = ['!', '(', ')', '&', '|'] ## for c in type: ## if c in splits: ## l.append(c) ## elif l[-1] in splits: ## l.append(c) ## elif not l: ## l.append(c) ## else: ## l[-1] += c # Check if the type condition is satisfied if type is not None: negation = False if type[0] == "!" : type = type[1:] negation = True is_type = bool(type in self.TYPE_DICT \ and self.type & self.TYPE_DICT[type]) if not (is_type ^ negation): return surface #Check if the window number condition is satisfied if windows is not None: arg = windows negation = False if arg[0] == "!" : arg = windows[1:] negation = True if arg[0] == ":": arg = "0" + arg elif arg[-1] == ":": arg = arg +"15" l = arg.split(":", 1) try: l = [int(n) for n in l] except ValueError: print 'Theme Error: The windows attribute of ' + \ 'an <if> statement can\'t look like this:' + \ ' "%s". See Theming HOWTO for more information'%windows return surface if len(l) == 1: if not ((l[0] == self.win_nr) ^ negation): return surface else: if not ((l[0]<=self.win_nr and self.win_nr<=l[1]) ^ negation): return surface #Check if the icon size condition is satisfied if size is not None: arg = size negation = False if arg[0] == "!" : arg = size[1:] negation = True if arg[0] == ":": arg = "0" + arg elif arg[-1] == ":": arg = arg +"200" l = arg.split(":", 1) try: l = [int(n) for n in l] except ValueError: print 'Theme Error: The size attribute of ' + \ 'an <if> statement can\'t look like this:' + \ ' "%s". See Theming HOWTO for more information'%size return surface if len(l) == 1: if not ((l[0] == self.win_nr) ^ negation): return surface else: if not ((l[0]<=self.size and self.size<=l[1]) ^ negation): return surface # All tests passed, proceed. for command, args in content.items(): try: f = getattr(self,"command_%s"%command) except: raise else: surface = f(surface, **args) return surface def command_pixmap_from_self(self, surface, name, content=None): if not name: print "Theme Error: no name given for pixmap_from_self" raise Exeption w = int(surface.get_width()) h = int(surface.get_height()) self.temp[name] = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) ctx = cairo.Context(self.temp[name]) ctx.set_source_surface(surface) ctx.paint() if content is None: return surface for command,args in content.items(): try: f = getattr(self,"command_%s"%command) except: raise else: self.temp[name] = f(self.temp[name], **args) return surface def command_pixmap(self, surface, name, content=None, size=None): if size is not None: # TODO: Fix for different height and width w = h = self.size + int(size) elif surface is None: w = h = self.size else: w = surface.get_width() h = surface.get_height() self.temp[name] = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) if content is None: return surface for command,args in content.items(): try: f = getattr(self,"command_%s"%command) except: raise else: self.temp[name] = f(self.temp[name], **args) return surface #### Get icon def command_get_icon(self,surface=None, size=0): size = int(size) size = self.size + size if size <= 0: # To avoid chrashes. size = 15 if self.icon \ and self.icon.get_width() == size \ and self.icon.get_height() == size: return self.icon del self.icon self.icon = None pb = self.find_icon_pixbuf(size) if pb.get_width() != pb.get_height(): if pb.get_width() < pb.get_height(): h = size w = pb.get_width() * size/pb.get_height() elif pb.get_width() > pb.get_height(): w = size h = pb.get_height() * size/pb.get_width() self.icon = cairo.ImageSurface(cairo.FORMAT_ARGB32, size, size) ctx = gtk.gdk.CairoContext(cairo.Context(self.icon)) pbs = pb.scale_simple(w, h, gtk.gdk.INTERP_BILINEAR) woffset = int(float(size - w) / 2 + 0.5) hoffset = int(float(size - h) / 2 + 0.5) ctx.set_source_pixbuf(pb, woffset, hoffset) ctx.paint() del pb del pbs elif pb.get_width() != size: pbs = pb.scale_simple(size, size, gtk.gdk.INTERP_BILINEAR) self.icon = self.pixbuf2surface(pbs) del pb del pbs else: self.icon = self.pixbuf2surface(pb) del pb return self.icon def find_icon_pixbuf(self, size): # Returns the icon pixbuf for the program. Uses the following metods: # 1) If it is a launcher, return the icon from the # launcher's desktopfile # 2) Get the icon from the gio app # 3) Check if the res_class fits an themed icon. # 4) Search in path after a icon matching reclass. # 5) Use the mini icon for the class pixbuf = None icon_name = None if self.desktop_entry: icon_name = self.desktop_entry.getIcon() if os.path.isfile(icon_name): pixbuf = self.icon_from_file_name(icon_name, size) if pixbuf is not None: return pixbuf if not icon_name: if self.identifier: icon_name = self.identifier.lower() elif self.class_group: icon_name = self.class_group.get_res_class().lower() else: icon_name = "" # Special cases if icon_name.startswith('openoffice'): # Makes sure openoffice gets a themed icon icon_name = "ooo-writer" if self.icon_theme.has_icon(icon_name): return self.icon_theme.load_icon(icon_name,size,0) if icon_name[-4:] in (".svg", ".png", ".xpm"): if self.icon_theme.has_icon(icon_name[:-4]): pixbuf = self.icon_theme.load_icon(icon_name[:-4],size,0) if pixbuf is not None: return pixbuf pixbuf = self.icon_search_in_data_path(icon_name, size) if pixbuf is not None: return pixbuf if self.class_group: return self.class_group.get_icon().copy() # If no pixbuf has been found (can only happen for an unlaunched # launcher), make an empty pixbuf and show a warning. if self.icon_theme.has_icon('application-default-icon'): pixbuf = self.icon_theme.load_icon('application-default-icon', size, 0) else: pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8, size,size) pixbuf.fill(0x00000000) if self.desktop_entry: name = self.desktop_entry.getName() else: name = None ## dialog = gtk.MessageDialog( ## parent=None, ## flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, ## type=gtk.MESSAGE_WARNING, ## buttons=gtk.BUTTONS_OK, ## message_format= (_("Cannot load icon for %s")%name)) ## dialog.set_title('DockBarX') ## dialog.run() ## dialog.destroy() return pixbuf def icon_from_file_name(self, icon_name, icon_size = -1): if os.path.isfile(icon_name): try: return gtk.gdk.pixbuf_new_from_file_at_size(icon_name, -1, icon_size) except: pass return None def icon_search_in_data_path(self, icon_name, icon_size): data_folders = None if os.environ.has_key("XDG_DATA_DIRS"): data_folders = os.environ["XDG_DATA_DIRS"] if not data_folders: data_folders = "/usr/local/share/:/usr/share/" for data_folder in data_folders.split(':'): #The line below line used datafolders instead of datafolder. #I changed it because I suspect it was a bug. paths = (os.path.join(data_folder, "pixmaps", icon_name), os.path.join(data_folder, "icons", icon_name)) for path in paths: if os.path.isfile(path): icon = self.icon_from_file_name(path, icon_size) if icon: return icon return None #### Other commands def command_get_pixmap(self, surface, name, size=0): if surface is None: if self.globals.orient == 'h': width = int(self.size * ar) height = self.size else: width = self.size height = int(self.size * ar) else: width = surface.get_width() height = surface.get_height() if self.theme.has_surface(name): surface = self.resize_surface(self.theme.get_surface(name), width, height) else: print "theme error: pixmap %s not found"%name return surface def command_fill(self, surface, color, opacity=100): w = surface.get_width() h = surface.get_height() new = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) ctx = cairo.Context(new) ctx.set_source_surface(surface) ctx.paint() alpha = self.get_alpha(opacity) c = self.get_color(color) r = float(int(c[1:3], 16))/255 g = float(int(c[3:5], 16))/255 b = float(int(c[5:7], 16))/255 ctx.set_source_rgba(r, g, b) ctx.set_operator(cairo.OPERATOR_SOURCE) ctx.paint_with_alpha(alpha) return new def command_combine(self, surface, pix1, pix2, degrees=90): # Combines left half of surface with right half of surface2. # The transition between the two halves are soft. w = surface.get_width() h = surface.get_height() if pix1=="self": p1 = surface elif pix1 in self.temp: p1 = self.temp[pix1] elif self.theme.has_surface(pix1): w = surface.get_width() h = surface.get_height() p1 = self.resize_surface(self.theme.get_surface(bg), w, h) else: print "theme error: pixmap %s not found"%pix1 if pix2=="self": p2 = surface elif pix2 in self.temp: p2 = self.temp[pix2] elif self.theme.has_surface(pix2): w = surface.get_width() h = surface.get_height() p2 = self.resize_surface(self.theme.get_surface(bg), w, h) else: print "theme error: pixmap %s not found"%pix2 surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, p1.get_width(), p1.get_height()) ctx = cairo.Context(surface) linear = cairo.LinearGradient(0, 0, p1.get_width(), 0) linear.add_color_stop_rgba(0.4, 0, 0, 0, 0.5) linear.add_color_stop_rgba(0.6, 0, 0, 0, 1) ctx.set_source_surface(p2, 0, 0) #ctx.mask(linear) ctx.paint() linear = cairo.LinearGradient(0, 0, p1.get_width(), 0) linear.add_color_stop_rgba(0.4, 0, 0, 0, 1) linear.add_color_stop_rgba(0.6, 0, 0, 0, 0) ctx.set_source_surface(p1, 0, 0) ctx.mask(linear) try: del pb del pbs except: pass return surface def command_transp_sat(self, surface, opacity=100, saturation=100): # Makes the icon desaturized and/or transparent. w = surface.get_width() h = surface.get_height() new = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) ctx = gtk.gdk.CairoContext(cairo.Context(new)) alpha = self.get_alpha(opacity) # Todo: Add error check for saturation if int(saturation) < 100: sio = StringIO() surface.write_to_png(sio) sio.seek(0) loader = gtk.gdk.PixbufLoader() loader.write(sio.getvalue()) loader.close() sio.close() pixbuf = loader.get_pixbuf() saturation = min(1.0, float(saturation)/100) pixbuf.saturate_and_pixelate(pixbuf, saturation, False) ctx.set_source_pixbuf(pixbuf, 0, 0) ctx.paint_with_alpha(alpha) del loader del sio del pixbuf gc.collect() else: ctx.set_source_surface(surface) ctx.paint_with_alpha(alpha) return new def command_composite(self, surface, bg, fg, opacity=100, xoffset=0, yoffset=0): if fg=="self": foreground = surface elif fg in self.temp: foreground = self.temp[fg] elif self.theme.has_surface(fg): w = surface.get_width() h = surface.get_height() foreground = self.resize_surface(self.theme.get_surface(fg), w, h) else: print "theme error: pixmap %s not found"%fg return surface if bg=="self": background = surface elif bg in self.temp: w = self.temp[bg].get_width() h = self.temp[bg].get_height() background = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) ctx = cairo.Context(background) ctx.set_source_surface(self.temp[bg]) ctx.paint() elif self.theme.has_surface(bg): w = surface.get_width() h = surface.get_height() background = self.resize_surface(self.theme.get_surface(bg), w, h) else: print "theme error: pixmap %s not found"%bg return surface opacity = self.get_alpha(opacity) xoffset = float(xoffset) yoffset = float(yoffset) ctx = cairo.Context(background) ctx.set_source_surface(foreground, xoffset, yoffset) ctx.paint_with_alpha(opacity) return background def command_shrink(self, surface, percent=0, pixels=0): w0 = surface.get_width() h0 = surface.get_height() new = cairo.ImageSurface(cairo.FORMAT_ARGB32, w0, h0) ctx = cairo.Context(new) w = int(((100-int(percent)) * w0)/100)-int(pixels) h = int(((100-int(percent)) * h0)/100)-int(pixels) shrinked = self.resize_surface(surface, w, h) x = int(float(w0 - w) / 2 + 0.5) y = int(float(h0 - h) / 2 + 0.5) ctx.set_source_surface(shrinked, x, y) ctx.paint() del shrinked return new def command_correct_size(self, surface): if surface is None: return if self.globals.orient == 'v': width = self.size height = int(self.size * self.ar) else: width = int(self.size * self.ar) height = self.size if surface.get_width() == width and surface.get_height() == height: return surface woffset = int(float(width - surface.get_width()) / 2 + 0.5) hoffset = int(float(height - surface.get_height()) / 2 + 0.5) new = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height) ctx = cairo.Context(new) ctx.set_source_surface(surface, woffset, hoffset) ctx.paint() return new def command_glow(self, surface, color, opacity=100): # Adds a glow around the parts of the surface # that isn't completely transparent. alpha = self.get_alpha(opacity) # Thickness (pixels) tk = 1.5 # Prepare the glow that should be put behind the icon cs = self.command_colorize(surface, color) w = surface.get_width() h = surface.get_height() glow = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) ctx = cairo.Context(glow) tk1 = tk/2.0 for x, y in ((-tk1,-tk1), (-tk1,tk1), (tk1,-tk1), (tk1,tk1)): ctx.set_source_surface(cs, x, y) ctx.paint_with_alpha(0.66) for x, y in ((-tk,-tk), (-tk,tk), (tk,-tk), (tk,tk)): ctx.set_source_surface(cs, x, y) ctx.paint_with_alpha(0.27) # Add glow and icon to a new canvas new = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) ctx = cairo.Context(new) ctx.set_source_surface(glow) ctx.paint_with_alpha(alpha) ctx.set_source_surface(surface) ctx.paint() return new def command_colorize(self, surface, color): # Changes the color of all pixels to color. # The pixels alpha values are unchanged. # Convert color hex-string (format '#FFFFFF')to int r, g, b color = self.get_color(color) r = int(color[1:3], 16)/255.0 g = int(color[3:5], 16)/255.0 b = int(color[5:7], 16)/255.0 w = surface.get_width() h = surface.get_height() new = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) ctx = cairo.Context(new) ctx.set_source_rgba(r,g,b,1.0) ctx.mask_surface(surface) return new def command_bright(self, surface, strength = None, strenght = None): if strength is None and strenght is not None: # For compability with older themes. strength = strenght alpha = self.get_alpha(strength) w = surface.get_width() h = surface.get_height() # Colorize white white = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) ctx = cairo.Context(white) ctx.set_source_rgba(1.0, 1.0, 1.0, 1.0) ctx.mask_surface(surface) # Apply the white version over the icon # with the chosen alpha value new = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) ctx = cairo.Context(new) ctx.set_source_surface(surface) ctx.paint() ctx.set_source_surface(white) ctx.paint_with_alpha(alpha) return new def command_alpha_mask(self, surface, mask): if mask in self.temp: mask = self.temp[mask] elif self.theme.has_surface(mask): m = self.surface2pixbuf(self.theme.get_surface(mask)) m = m.scale_simple(surface.get_width(), surface.get_height(), gtk.gdk.INTERP_BILINEAR) mask = self.pixbuf2surface(m) w = surface.get_width() h = surface.get_height() new = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) ctx = cairo.Context(new) ctx.set_source_surface(surface) ctx.mask_surface(mask) return new #### Format conversions def pixbuf2surface(self, pixbuf): if pixbuf is None: return None w = pixbuf.get_width() h = pixbuf.get_height() surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) ctx = gtk.gdk.CairoContext(cairo.Context(surface)) ctx.set_source_pixbuf(pixbuf, 0, 0) ctx.paint() del pixbuf return surface def surface2pixbuf(self, surface): if surface is None: return None sio = StringIO() surface.write_to_png(sio) sio.seek(0) loader = gtk.gdk.PixbufLoader() loader.write(sio.getvalue()) loader.close() sio.close() pixbuf = loader.get_pixbuf() return pixbuf def surface2pil(self, surface): w = surface.get_width() h = surface.get_height() return Image.frombuffer("RGBA", (w, h), surface.get_data(), "raw", "RGBA", 0,1) def pil2surface(self, im): imgd = im.tostring("raw","RGBA",0,1) a = array.array('B',imgd) w = im.size[0] h = im.size[1] stride = im.size[0] * 4 surface = cairo.ImageSurface.create_for_data (a, cairo.FORMAT_ARGB32, w, h, stride) return surface def resize_surface(self, surface, w, h): im = self.surface2pil(surface) im = im.resize((w, h), Image.ANTIALIAS) return self.pil2surface(im)
def get_context_data(self, **kwargs): context = super(HomeView, self).get_context_data(**kwargs) theme = Theme.get_random_theme() context['banner_class'] = theme.css_class context['iama_form'] = IamaForm(initial={'weapon':theme.weapon, 'gender':theme.gender}) return context
class Slide(object): """ Slide object. """ @classmethod def reset(cls): """Reset to default state.""" return def __init__(self, number, position=None, title=None, contents=None): """" Paramters --------- number: int slide global numeration position: dict position dictionary containing {'x': posx, 'y': posy, 'z': posz, 'rotx': rotx, 'roty': roty, 'rotz': rotz, 'scale': scaling} title: str contents: str """ self.number = number self.position = None self.set_position(position) self.title = title self.contents = contents self.overtheme = Theme() return def __str__(self): strings = [str(self.title)] strings.append(str(self.contents)) return ''.join(strings) def get_overtheme(self, parser): """Get eventaul overtheme definition. Parameters ---------- parser: Parser """ codeblocks = parser.tokenizer(source=self.contents, re_search=parser.regexs['codeblock']) yamlblocks = parser.tokenizer(source=self.contents, re_search=parser.regexs['yamlblock'], exclude=codeblocks) if len(yamlblocks) > 0: self.overtheme.get(source=''.join([block['match'].group().strip('---') for block in yamlblocks]), name='overtheme', div_id='slide-' + str(self.number)) purged_contents = self.contents[:yamlblocks[0]['start']] for b, yamlblock in enumerate(yamlblocks[:-1]): purged_contents += self.contents[yamlblock['end']:yamlblocks[b + 1]['start']] purged_contents += self.contents[yamlblocks[-1]['end']:] self.contents = purged_contents def set_position(self, position): """Set slide position. Parameters ---------- position: dict position dictionary containing {'x': posx, 'y': posy, 'z': posz, 'rotx': rotx, 'roty': roty, 'rotz': rotz, 'scale': scaling} """ if position is not None: self.position = {} for key in position: self.position[key] = position[key] def put_html_attributes(self, doc): """Put html attibutes of the slide. Parameters ---------- doc: Doc """ doc.attr(('id', 'slide-' + str(self.number))) # doc.attr(('title', str(self.title))) doc.attr(('class', 'step slide')) doc.attr(('data-x', str(self.position['x']))) doc.attr(('data-y', str(self.position['y']))) doc.attr(('data-z', str(self.position['z']))) doc.attr(('data-scale', str(self.position['scale']))) doc.attr(('data-rotate-x', str(self.position['rotx']))) doc.attr(('data-rotate-y', str(self.position['roty']))) doc.attr(('data-rotate-z', str(self.position['rotz']))) return def to_html(self, doc, parser, metadata, theme, current): """Generate html from self. Parameters ---------- doc: Doc parser: Parser metatadata: dict presentation metadata theme: Theme() presentation theme current: list """ def _parse_env(Env, re_search, source): codeblocks = parser.tokenizer(source=source, re_search=parser.regexs['codeblock']) codes = parser.tokenizer(source=source, re_search=parser.regexs['code'], exclude=codeblocks) yamlblocks = parser.tokenizer(source=source, re_search=parser.regexs['yamlblock'], exclude=codeblocks + codes) envs = parser.tokenizer(source=source, re_search=re_search, exclude=codeblocks + yamlblocks + codes) if len(envs) > 0: parsed_source = source[:envs[0]['start']] for e, env in enumerate(envs[:-1]): current = Env(source=env['match'].group()) parsed_source += current.to_html() + source[env['end']:envs[e + 1]['start']] if Env is Video: if self.overtheme.custom: current = Env(source=envs[-1]['match'].group(), theme=self.overtheme) else: current = Env(source=envs[-1]['match'].group(), theme=theme) else: current = Env(source=envs[-1]['match'].group()) parsed_source += current.to_html() + source[envs[-1]['end']:] return parsed_source return source html = self.contents for meta in metadata: html = metadata[meta].parse(parser=parser, source=html, toc_depth=metadata['toc_depth'].value, max_time=metadata['max_time'].value, current=current) html = _parse_env(Env=Box, re_search=Box.regexs['box'], source=html) html = _parse_env(Env=Note, re_search=Note.regexs['note'], source=html) html = _parse_env(Env=Figure, re_search=Figure.regexs['figure'], source=html) html = _parse_env(Env=Table, re_search=Table.regexs['table'], source=html) html = _parse_env(Env=Video, re_search=Video.regexs['video'], source=html) html = _parse_env(Env=Columns, re_search=Columns.regexs['columns'], source=html) with doc.tag('div', klass='slide-content'): doc.asis(markdown2html(source=html)) return
class SettingsManager(object): """Organizes user settings""" def __init__(self, alot_rc=None, notmuch_rc=None): """ :param alot_rc: path to alot's config file :type alot_rc: str :param notmuch_rc: path to notmuch's config file :type notmuch_rc: str :theme: path to initially used theme file :type theme: str """ self.hooks = None self._mailcaps = mailcap.getcaps() self._config = ConfigObj() self._notmuchconfig = None self._theme = None self._accounts = None self._accountmap = None bindings_path = os.path.join(DEFAULTSPATH, 'default.bindings') self._bindings = ConfigObj(bindings_path) if alot_rc is not None: self.read_config(alot_rc) if notmuch_rc is not None: self.read_notmuch_config(notmuch_rc) def read_notmuch_config(self, path): """parse notmuch's config file from path""" spec = os.path.join(DEFAULTSPATH, 'notmuch.rc.spec') self._notmuchconfig = read_config(path, spec) def read_config(self, path): """parse alot's config file from path""" spec = os.path.join(DEFAULTSPATH, 'alot.rc.spec') newconfig = read_config(path, spec, checks={'mail_container': mail_container, 'force_list': force_list, 'align': align_mode, 'attrtriple': attr_triple, 'gpg_key_hint': gpg_key}) self._config.merge(newconfig) hooks_path = os.path.expanduser(self._config.get('hooksfile')) try: self.hooks = imp.load_source('hooks', hooks_path) except: logging.debug('unable to load hooks file:%s' % hooks_path) if 'bindings' in newconfig: newbindings = newconfig['bindings'] if isinstance(newbindings, Section): self._bindings.merge(newbindings) # themes themestring = newconfig['theme'] themes_dir = self._config.get('themes_dir') if themes_dir: themes_dir = os.path.expanduser(themes_dir) else: configdir = os.environ.get('XDG_CONFIG_HOME', os.path.expanduser('~/.config')) themes_dir = os.path.join(configdir, 'alot', 'themes') logging.debug(themes_dir) # if config contains theme string use that if themestring: if not os.path.isdir(themes_dir): err_msg = 'cannot find theme %s: themes_dir %s is missing' raise ConfigError(err_msg % (themestring, themes_dir)) else: theme_path = os.path.join(themes_dir, themestring) try: self._theme = Theme(theme_path) except ConfigError as e: err_msg = 'Theme file %s failed validation:\n' raise ConfigError((err_msg % themestring) + e.message) # if still no theme is set, resort to default if self._theme is None: theme_path = os.path.join(DEFAULTSPATH, 'default.theme') self._theme = Theme(theme_path) self._accounts = self._parse_accounts(self._config) self._accountmap = self._account_table(self._accounts) def _parse_accounts(self, config): """ read accounts information from config :param config: valit alot config :type config: `configobj.ConfigObj` :returns: list of accounts """ accounts = [] if 'accounts' in config: for acc in config['accounts'].sections: accsec = config['accounts'][acc] args = dict(config['accounts'][acc]) # create abook for this account abook = accsec['abook'] logging.debug('abook defined: %s' % abook) if abook['type'] == 'shellcommand': cmd = abook['command'] regexp = abook['regexp'] if cmd is not None and regexp is not None: args['abook'] = MatchSdtoutAddressbook(cmd, match=regexp) else: msg = 'underspecified abook of type \'shellcommand\':' msg += '\ncommand: %s\nregexp:%s' % (cmd, regexp) raise ConfigError(msg) elif abook['type'] == 'abook': contacts_path = abook['abook_contacts_file'] args['abook'] = AbookAddressBook(contacts_path, ignorecase=abook['ignorecase']) else: del(args['abook']) cmd = args['sendmail_command'] del(args['sendmail_command']) newacc = SendmailAccount(cmd, **args) accounts.append(newacc) return accounts def _account_table(self, accounts): """ creates a lookup table (emailaddress -> account) for a given list of accounts :param accounts: list of accounts :type accounts: list of `alot.account.Account` :returns: hashtable :rvalue: dict (str -> `alot.account.Account`) """ accountmap = {} for acc in accounts: accountmap[acc.address] = acc for alias in acc.aliases: accountmap[alias] = acc return accountmap def get(self, key, fallback=None): """ look up global config values from alot's config :param key: key to look up :type key: str :param fallback: fallback returned if key is not present :type fallback: str :returns: config value with type as specified in the spec-file """ value = None if key in self._config: value = self._config[key] if isinstance(value, Section): value = None if value is None: value = fallback return value def set(self, key, value): """ setter for global config values :param key: config option identifise :type key: str :param value: option to set :type value: depends on the specfile :file:`alot.rc.spec` """ self._config[key] = value def get_notmuch_setting(self, section, key, fallback=None): """ look up config values from notmuch's config :param section: key is in :type section: str :param key: key to look up :type key: str :param fallback: fallback returned if key is not present :type fallback: str :returns: config value with type as specified in the spec-file """ value = None if section in self._notmuchconfig: if key in self._notmuchconfig[section]: value = self._notmuchconfig[section][key] if value is None: value = fallback return value def get_theming_attribute(self, mode, name, part=None): """ looks up theming attribute :param mode: ui-mode (e.g. `search`,`thread`...) :type mode: str :param name: identifier of the atttribute :type name: str :rtype: urwid.AttrSpec """ colours = int(self._config.get('colourmode')) return self._theme.get_attribute(colours, mode, name, part) def get_threadline_theming(self, thread): """ looks up theming info a threadline displaying a given thread. This wraps around :meth:`~alot.settings.theme.Theme.get_threadline_theming`, filling in the current colour mode. :param thread: thread to theme :type thread: alot.db.thread.Thread """ colours = int(self._config.get('colourmode')) return self._theme.get_threadline_theming(thread, colours) def get_tagstring_representation(self, tag, onebelow_normal=None, onebelow_focus=None): """ looks up user's preferred way to represent a given tagstring. :param tag: tagstring :type tag: str :param onebelow_normal: attribute that shines through if unfocussed :type onebelow_normal: urwid.AttrSpec :param onebelow_focus: attribute that shines through if focussed :type onebelow_focus: urwid.AttrSpec If `onebelow_normal` or `onebelow_focus` is given these attributes will be used as fallbacks for fg/bg values '' and 'default'. This returns a dictionary mapping :normal: to :class:`urwid.AttrSpec` used if unfocussed :focussed: to :class:`urwid.AttrSpec` used if focussed :translated: to an alternative string representation """ colourmode = int(self._config.get('colourmode')) theme = self._theme cfg = self._config colours = [1, 16, 256] def colourpick(triple): """ pick attribute from triple (mono,16c,256c) according to current colourmode""" if triple is None: return None return triple[colours.index(colourmode)] # global default attributes for tagstrings. # These could contain values '' and 'default' which we interpret as # "use the values from the widget below" default_normal = theme.get_attribute(colourmode, 'global', 'tag') default_focus = theme.get_attribute(colourmode, 'global', 'tag_focus') # local defaults for tagstring attributes. depend on next lower widget fallback_normal = resolve_att(onebelow_normal, default_normal) fallback_focus = resolve_att(onebelow_focus, default_focus) for sec in cfg['tags'].sections: if re.match('^' + sec + '$', tag): normal = resolve_att(colourpick(cfg['tags'][sec]['normal']), fallback_normal) focus = resolve_att(colourpick(cfg['tags'][sec]['focus']), fallback_focus) translated = cfg['tags'][sec]['translated'] if translated is None: translated = tag translation = cfg['tags'][sec]['translation'] if translation: translated = re.sub(translation[0], translation[1], tag) break else: normal = fallback_normal focus = fallback_focus translated = tag return {'normal': normal, 'focussed': focus, 'translated': translated} def get_hook(self, key): """return hook (`callable`) identified by `key`""" if self.hooks: if key in self.hooks.__dict__: return self.hooks.__dict__[key] return None def get_mapped_input_keysequences(self, mode=None, prefix=u''): candidates = self._bindings.scalars if mode is not None: candidates = candidates + self._bindings[mode].scalars return [s for s in candidates if s.startswith(prefix)] def get_keybinding(self, mode, key): """look up keybinding from `MODE-maps` sections :param mode: mode identifier :type mode: str :param key: urwid-style key identifier :type key: str :returns: a command line to be applied upon keypress :rtype: str """ cmdline = None bindings = self._bindings if key in bindings.scalars: cmdline = bindings[key] if mode in bindings.sections: if key in bindings[mode].scalars: value = bindings[mode][key] if value: cmdline = value # Workaround for ConfigObj misbehaviour. cf issue #500 # this ensures that we get at least strings only as commandlines if isinstance(cmdline, list): cmdline = ','.join(cmdline) return cmdline def get_accounts(self): """ returns known accounts :rtype: list of :class:`Account` """ return self._accounts def get_account_by_address(self, address): """ returns :class:`Account` for a given email address (str) :param address: address to look up :type address: string :rtype: :class:`Account` or None """ for myad in self.get_addresses(): if myad in address: return self._accountmap[myad] return None def get_main_addresses(self): """returns addresses of known accounts without its aliases""" return [a.address for a in self._accounts] def get_addresses(self): """returns addresses of known accounts including all their aliases""" return self._accountmap.keys() def get_addressbooks(self, order=[], append_remaining=True): """returns list of all defined :class:`AddressBook` objects""" abooks = [] for a in order: if a: if a.abook: abooks.append(a.abook) if append_remaining: for a in self._accounts: if a.abook and a.abook not in abooks: abooks.append(a.abook) return abooks def mailcap_find_match(self, *args, **kwargs): """ Propagates :func:`mailcap.find_match` but caches the mailcap (first argument) """ return mailcap.findmatch(self._mailcaps, *args, **kwargs) def represent_datetime(self, d): """ turns a given datetime obj into a unicode string representation. This will: 1) look if a fixed 'timestamp_format' is given in the config 2) check if a 'timestamp_format' hook is defined 3) use :func:`~alot.helper.pretty_datetime` as fallback """ fixed_format = self.get('timestamp_format') if fixed_format: rep = string_decode(d.strftime(fixed_format), 'UTF-8') else: format_hook = self.get_hook('timestamp_format') if format_hook: rep = string_decode(format_hook(d), 'UTF-8') else: rep = pretty_datetime(d) return rep
def __init__(self): Theme.__init__(self)
def setupTheme(self): Theme.setupTheme(self)
class DockBar(): def __init__(self, applet=None, as_awn_applet=False): print "Dockbarx init" self.applet = applet self.groups = None self.windows = None self.container = None self.theme = None self.gkeys = { 'gkeys_select_next_group': None, 'gkeys_select_previous_group': None, 'gkeys_select_next_window': None, 'gkeys_select_previous_window': None } wnck.set_client_type(wnck.CLIENT_TYPE_PAGER) self.screen = wnck.screen_get_default() self.root_xid = int(gtk.gdk.screen_get_default().get_root_window().xid) self.screen.force_update() self.globals = Globals() self.globals.connect('theme-changed', self.reload) #--- Applet / Window container if self.applet is not None: self.applet.set_applet_flags( gnomeapplet.HAS_HANDLE|gnomeapplet.EXPAND_MINOR) if self.applet.get_orient() == gnomeapplet.ORIENT_DOWN \ or applet.get_orient() == gnomeapplet.ORIENT_UP: self.globals.orient = "h" self.container = gtk.HBox() else: self.globals.orient = "v" self.container = gtk.VBox() self.applet.add(self.container) self.pp_menu_xml = """ <popup name="button3"> <menuitem name="About Item" verb="About" stockid="gtk-about" /> <menuitem name="Preferences" verb="Pref" stockid="gtk-properties" /> <menuitem name="Reload" verb="Reload" stockid="gtk-refresh" /> </popup> """ self.pp_menu_verbs = [("About", self.on_ppm_about), ("Pref", self.on_ppm_pref), ("Reload", self.reload)] self.applet.setup_menu(self.pp_menu_xml, self.pp_menu_verbs,None) self.applet_origin_x = -1000 self.applet_origin_y = -1000 # background bug workaround self.applet.set_background_widget(applet) self.applet.show_all() else: self.container = gtk.HBox() self.globals.orient = "h" # Wait until the container is realized before adding anything to it. if not as_awn_applet: gobject.timeout_add(10, self.reload_on_realized) if self.applet is not None: self.applet.connect("size-allocate",self.on_applet_size_alloc) self.applet.connect("change_background", self.on_change_background) self.applet.connect("change-orient",self.on_change_orient) self.applet.connect("delete-event",self.cleanup) self.on_gkeys_changed(dialog=False) self.globals.connect('gkey-changed', self.on_gkeys_changed) def reload_on_realized(self): if self.container.window is None: return True self.reload() return False def reload(self, event=None, data=None): # Remove all old groupbuttons from container. for child in self.container.get_children(): self.container.remove(child) if self.windows: # Removes windows and unpinned group buttons for win in self.screen.get_windows(): self.on_window_closed(None, win) if self.groups is not None: # Removes pinned group buttons for group in self.groups: group.hide_list() group.icon_factory.remove() del self.groups del self.windows if self.theme: self.theme.remove() gc.collect() print "Dockbarx reload" self.groups = GroupList() self.windows = {} # Get the monitor on which dockbarx is. gdk_screen = gtk.gdk.screen_get_default() win = self.container.window if win is not None: self.monitor = gdk_screen.get_monitor_at_window(win) #--- Generate Gio apps self.apps_by_id = {} self.app_ids_by_exec = {} self.app_ids_by_name = {} self.app_ids_by_longname = {} self.wine_app_ids_by_program = {} for app in gio.app_info_get_all(): id = app.get_id() id = id[:id.rfind('.')].lower() name = u""+app.get_name().lower() exe = app.get_executable() if exe: self.apps_by_id[id] = app if id[:5] == 'wine-': try: cmd = u""+app.get_commandline().lower() except AttributeError: # Older versions of gio doesn't have get_comandline. cmd = u"" if cmd.find('.exe') > 0: program = cmd[:cmd.rfind('.exe')+4] program = program[program.rfind('\\')+1:] self.wine_app_ids_by_program[program] = id if name.find(' ')>-1: self.app_ids_by_longname[name] = id else: self.app_ids_by_name[name] = id if exe not in ('sudo','gksudo', 'java','mono', 'ruby','python'): if exe[0] == '/': exe = exe[exe.rfind('/')+1:] self.app_ids_by_exec[exe] = id else: self.app_ids_by_exec[exe] = id try: if self.theme is None: self.theme = Theme() else: self.theme.on_theme_changed() except NoThemesError, details: print details sys.exit(1) self.container.set_spacing(self.theme.get_gap()) self.container.show() #--- Initiate launchers self.desktop_entry_by_id = {} self.d_e_ids_by_exec = {} self.d_e_ids_by_name = {} self.d_e_ids_by_longname = {} self.d_e_ids_by_wine_program = {} gconf_pinned_apps = self.globals.get_pinned_apps_from_gconf() # Initiate launcher group buttons for launcher in gconf_pinned_apps: identifier, path = launcher.split(';') # Fix for launchers made in previous version of dockbarx identifier = identifier.lower() if identifier == '': identifier = None self.add_launcher(identifier, path) # Update pinned_apps list to remove any pinned_app that are faulty. self.update_pinned_apps_list() #--- Initiate windows # Initiate group buttons with windows for window in self.screen.get_windows(): self.on_window_opened(self.screen, window) self.screen.connect("window-opened", self.on_window_opened) self.screen.connect("window-closed", self.on_window_closed) self.screen.connect("active-window-changed", self.on_active_window_changed) self.screen.connect("viewports-changed", self.on_desktop_changed) self.screen.connect("active-workspace-changed", self.on_desktop_changed) self.on_active_window_changed(self.screen, None)
from PyQt5.QtWebEngineWidgets import QWebEngineView from ui.settings import Settings from ui.about import About from ui.notes_project import CreateNotesProject from config import Config from utils import basedir from theme import Theme from components.editor import CodeEditor from components.HTMLPreview import HTMLPreview from components.markdown_preview import MarkdownPreview from components.note_graph import NotesGraph from components.statusbar import Statusbar app = QApplication(sys.argv) config = Config(os.path.expanduser('~/.kettle/'), 'config.ini') themes = Theme(app, config) class Kettle(QMainWindow): def __init__(self): super().__init__() self.init_ui() self.filename = "untitled" def save_file(self): name = self.filename if not self.filename or self.filename == "untitled": name = QFileDialog.getSaveFileName(self, 'Save File')[0] file = open(name, 'wt') save_text = self.current_editor.toPlainText() file.write(save_text)
class Game: def __init__(self): self.ss = Size() self.theme = Theme() ### CRAZY COULD BE: # 0 - Boring. Very boring. Classical pong # 1 - Better than prev. Buffs appeared 1 time a 30*250 ms # 2 - If you don't know what to choose, use it. Buffs appeared 1 time a 30*100 ms # 3 - <del>CRAZIEST</del> FUNNIEST CHOICE EVER. BUFFS APEARED 1 TIME A 0.3 S # 4 - epileptic self.CRAZY = PositionList(("Classic", "Soft", "Normal", "Best", "Hard"), 2) # root window self.root = Tk() self.root.title("FPong") self.root.geometry("+0+0") self.root.iconphoto(False, PhotoImage(file="./images/window_icon.png")) self.root.resizable(False, False) # Create Canvas wit elements on it self.__init_canva() self.root.mainloop() def run(self, vs_bot): self.vs_bot = vs_bot self.left_pad.bot = vs_bot self._stop_cont_game() self.cur_menu = self.stop_menu self.main() def main(self): if not self.game_stopped: self.ball.move() self.right_pad.move(speed_up=self.buffs.r_pad_speed_up) self.buffs.update(self.ball.id) if self.vs_bot: self.left_pad.move(self.c.get_y_center(self.ball.id), \ self.buffs.l_pad_speed_up) else: self.left_pad.move(speed_up=self.buffs.l_pad_speed_up) # recall himself every 30 ms self.after_id = self.root.after(30, self.main) def win(self): self._increase_score(self.player.id) self.ball.respawn_ball() def loose(self): self._increase_score(self.player.other.id) def _increase_score(self, player): if player == Player.LEFT: self.player.l_player.score += 1 self.c.itemconfig(self.pl_l_text, text=self.player.l_player.score) else: self.player.r_player.score += 1 self.c.itemconfig(self.pl_r_text, text=self.player.r_player.score) def _key_pressed(self, event): if not self.game_stopped: # If ball and pads can move self.left_pad.button_press(event.keysym) self.right_pad.button_press(event.keysym) if event.keysym == "Escape": # Show/Hide menu window and stop/start game self._stop_cont_game() else: # Send this key to menu widget self.cur_menu.check_keys(event.keysym) def _key_released(self, event): if not self.game_stopped: self.left_pad.button_release(event.keysym) self.right_pad.button_release(event.keysym) def show_options_menu(self, hide=False): self.c.itemconfig(self.cur_menu.id, state=HIDDEN) if not hide: self.cur_menu = self.options_menu else: self.cur_menu = self.start_menu self.c.itemconfig(self.cur_menu.id, state=NORMAL) def update_size(self): new_w, new_h = self.ss.SCREEN_SIZES.get() xscale = new_w / self.ss.WIDTH yscale = new_h / self.ss.HEIGHT self._resize(xscale, yscale) def _resize(self, xscale, yscale): self.c.config(width=self.ss.WIDTH*xscale, height=self.ss.HEIGHT*yscale) self.c.scale(ALL, 0, 0, xscale, yscale) self.ss.scale(xscale, yscale) def update_crazy(self): self.buffs.init_buffs() def update_theme(self): if not self.theme.randomed: self.theme.choose_theme() self.rotate_colors() def rotate_colors(self): self.start_menu.rotate_colors() self.stop_menu.rotate_colors() self.options_menu.rotate_colors() self.theme.rotate_colors() def move_screen(self): left = 0 right = self.root.winfo_screenwidth() - int(self.ss.WIDTH) top = 0 bottom = self.root.winfo_screenheight() - int(self.ss.HEIGHT) new_x = randint(left, right) new_y = randint(top, bottom) self.root.geometry(f"+{new_x}+{new_y}") def _stop_cont_game(self): if self.game_stopped: self.c.itemconfig(self.cur_menu.id, state=HIDDEN) else: self.c.itemconfig(self.cur_menu.id, state=NORMAL) self.game_stopped = not self.game_stopped # Used for testing, shoud be changed def print_help(self): # TODO!! Print it on main window print("Welkome to the F(unny)Pong") print() print("Controls: left player - W/S, right - key Up/Down") print("When playing against bot you are on the right") print("At the time of game you could press Esc to go to the menu") print() print("There are 5 modes: Classic, Soft, Normal, Best, Hard") print("\tClassic - Without buffs") print("\tSoft - Sometimes minor buffs appear(Speed_up, Slow_down, Enlarge, Shrink)(all about pad)") print("\tNormal - Buffs pops up more frequently, and to previous list added (Small_ball, Big_ball, Random)") print("\tBest - Frequency increases, added (Rotate, Die)") print("\t\t\tMaybe I played this game so many times(while debugging) so that all the previous modes became boring") print("\t\t\t<Best> is the best - In My Humble Oppinion") print("\tHard - Added (Teleport, Splash, Move)") print() print("Note: in most cases buffs affect the player who touched the ball last") print("Except some general (Small_ball, Big_ball, Teleport, Move)") print() print("Some non-intuitive buffs:") print("\tRandom - (question mark) execute random buff") print("\tRotate - change pad control keys (when you press Up, it moves down) and color to dark-green") print("\tTeleport - change balls position") print("\tSplash - (white, green, red, black stripes) Cause blinking in your area") print("\tMove - (four arrows) Screen moves several times") def reinit(self): self.__init_canva() def __init_canva(self): # Canvas object self.c = ExCanvas(self.root, width=self.ss.WIDTH, height=self.ss.HEIGHT, background=self.theme["bg"]) self.c.pack()#expand=True) # central line self.c.create_line(self.ss.WIDTH//2, 0, self.ss.WIDTH//2, self.ss.HEIGHT, fill=self.theme["line"], tag="line") self.c.create_ball(self.ss.WIDTH//2, self.ss.HEIGHT//2, self.ss.BALL_RADIUS/2, fill=self.theme["line"], width=0, tag="line") self.__init_players_score() # Work with Pads left_pad_id = self.c.create_rectangle(0, 0, self.ss.PAD_W, self.ss.PAD_H, width=1, fill=self.theme["l_pad"], tag="l_pad") right_pad_id = self.c.create_rectangle(self.ss.WIDTH-self.ss.PAD_W, 0, self.ss.WIDTH, self.ss.PAD_H, width=1, fill=self.theme["r_pad"], tag="r_pad") self.left_pad = Pad(left_pad_id, self.c, self.ss, ("w", "s"), Player.LEFT) self.right_pad = Pad(right_pad_id, self.c, self.ss, ("Up", "Down"), Player.RIGHT) self.player = Player(self.left_pad, self.right_pad) self.ball = Ball(self.c, self.player, self, self.ss, self.theme["ball"]) self.buffs = Buffs(self.ss, self) # Menu creating stop_menu_id = self.c.create_window((self.ss.WIDTH/2, self.ss.HEIGHT/2)) self.stop_menu = StopMenu(stop_menu_id, self) self.c.itemconfig(stop_menu_id, window=self.stop_menu, state=HIDDEN) options_menu_id = self.c.create_window((self.ss.WIDTH/2, self.ss.HEIGHT/2)) self.options_menu = OptionMenu(options_menu_id, self) self.c.itemconfig(options_menu_id, window=self.options_menu, state=HIDDEN) start_menu_id = self.c.create_window((self.ss.WIDTH/2, self.ss.HEIGHT/2)) self.start_menu = StartMenu(start_menu_id, self) self.c.itemconfig(start_menu_id, window=self.start_menu) self.cur_menu = self.start_menu self.c.focus_set() self.theme.set_canvas(self.c) self.c.bind("<KeyPress>", self._key_pressed) self.c.bind("<KeyRelease>", self._key_released) self.game_stopped = True def __init_players_score(self): # Show players score self.pl_r_text = self.c.create_text(self.ss.WIDTH*4/5, self.ss.PAD_H/3, text=0, fill="white", font="Colibri 25", tag="text") self.pl_l_text = self.c.create_text(self.ss.WIDTH/5, self.ss.PAD_H/3, text=0, fill="white", font="Colibri 25", tag="text")
Clock.schedule_once(lambda *__: Factory.UpdateRestartPopup().open(), 0) def _restart_for_update(self): # Dismiss popup and run update utility if hasattr(self, 'update_notif'): self.update_notif.dismiss() self.update_client.run_util() self.stop() def open_settings(self): self.root.goto_page(3) Logger.info('Reading theme..') theme = Theme(name=Config.get('theme', 'default')) if __name__ == '__main__': Logger.info(f'System = {platform.system()}') Logger.info(f'Release = {platform.release()}') Window.clearcolor = theme.dark app = XtremeUpdaterApp() # set attributes required by the .kv file app.Config = Config app.version = __version__ app.theme = theme app.as_admin = IS_ADMIN
def reload(self, event=None, data=None): # Remove all old groupbuttons from container. for child in self.container.get_children(): self.container.remove(child) if self.windows: # Removes windows and unpinned group buttons for win in self.screen.get_windows(): self.on_window_closed(None, win) if self.groups is not None: # Removes pinned group buttons for group in self.groups: group.hide_list() group.icon_factory.remove() del self.groups del self.windows if self.theme: self.theme.remove() gc.collect() print "Dockbarx reload" self.groups = GroupList() self.windows = {} # Get the monitor on which dockbarx is. gdk_screen = gtk.gdk.screen_get_default() win = self.container.window if win is not None: self.monitor = gdk_screen.get_monitor_at_window(win) #--- Generate Gio apps self.apps_by_id = {} self.app_ids_by_exec = {} self.app_ids_by_name = {} self.app_ids_by_longname = {} self.wine_app_ids_by_program = {} for app in gio.app_info_get_all(): id = app.get_id() id = id[:id.rfind('.')].lower() name = u""+app.get_name().lower() exe = app.get_executable() if exe: self.apps_by_id[id] = app if id[:5] == 'wine-': try: cmd = u""+app.get_commandline().lower() except AttributeError: # Older versions of gio doesn't have get_comandline. cmd = u"" if cmd.find('.exe') > 0: program = cmd[:cmd.rfind('.exe')+4] program = program[program.rfind('\\')+1:] self.wine_app_ids_by_program[program] = id if name.find(' ')>-1: self.app_ids_by_longname[name] = id else: self.app_ids_by_name[name] = id if exe not in ('sudo','gksudo', 'java','mono', 'ruby','python'): if exe[0] == '/': exe = exe[exe.rfind('/')+1:] self.app_ids_by_exec[exe] = id else: self.app_ids_by_exec[exe] = id try: if self.theme is None: self.theme = Theme() else: self.theme.on_theme_changed() except NoThemesError, details: print details sys.exit(1)
def parse(self, config, source): """Parse presentation from source stream. Parameters ---------- config : MatisseConfig MaTiSSe configuration source: str """ complete_source = self.parser.includes(source=source) self.__get_metadata(source=complete_source) self.__get_theme(source=complete_source) new_theme = Theme() new_theme.set_from(other=self.theme) tokens = self.parser.tokenize(source=complete_source) self.__check_bad_sectioning(tokens=tokens) chapters_number = 0 sections_number = 0 subsections_number = 0 slides_number = 0 titlepage_inserted = False for chap in tokens['chapters']: chapters_number += 1 slide_local_numbers = [0, 0, 0] if chap['match'].group('expr'): chapter = Chapter(number=chapters_number, title=chap['match'].group('expr')) else: chapter = Chapter(number=chapters_number, title='') for sec in tokens['sections']: if sec['start'] >= chap['start'] and sec['start'] <= chap[ 'end_next']: sections_number += 1 slide_local_numbers[1] = 0 slide_local_numbers[2] = 0 section = Section(number=sections_number, title=sec['match'].group('expr')) for subsec in tokens['subsections']: if subsec['start'] >= sec['start'] and subsec[ 'start'] <= sec['end_next']: subsections_number += 1 slide_local_numbers[2] = 0 subsection = Subsection( number=subsections_number, title=subsec['match'].group('expr')) for sld in tokens['slides']: if '$titlepage' in sld['match'].group().lower( ) and not titlepage_inserted: slide = Slide( number=0, title='titlepage', contents=complete_source[ sld['end']:sld['end_next']]) slide.get_overtheme(parser=self.parser) if slide.overtheme.copy_from_theme is not None and slide.overtheme.copy_from_theme: slide.overtheme.copy_from( other=self.theme) self.position.update_position( presentation_theme=self.theme, overtheme=slide.overtheme) slide.set_position( position=self.position.position) subsection.add_slide(slide=slide) titlepage_inserted = True else: if sld['start'] >= subsec['start'] and sld[ 'start'] <= subsec['end_next']: slide_local_numbers[0] += 1 slide_local_numbers[1] += 1 slide_local_numbers[2] += 1 if slide_local_numbers[ 0] == 1 and config.toc_at_chap_beginning is not None: slides_number += 1 self.position.update_position( presentation_theme=self.theme) subsection.add_slide(slide=Slide( number=slides_number, position=self.position. position, title='Table of Contents', contents='$toc[depth:' + str(config. toc_at_chap_beginning) + ']')) if slide_local_numbers[ 1] == 1 and config.toc_at_sec_beginning is not None: slides_number += 1 self.position.update_position( presentation_theme=self.theme) subsection.add_slide(slide=Slide( number=slides_number, position=self.position. position, title='Table of Contents', contents='$toc[depth:' + str(config.toc_at_sec_beginning ) + ']')) if slide_local_numbers[ 2] == 1 and config.toc_at_subsec_beginning is not None: slides_number += 1 self.position.update_position( presentation_theme=self.theme) subsection.add_slide(slide=Slide( number=slides_number, position=self.position. position, title='Table of Contents', contents='$toc[depth:' + str(config. toc_at_subsec_beginning) + ']')) slides_number += 1 slide = Slide( number=slides_number, title=sld['match'].group('expr'), contents=complete_source[ sld['end']:sld['end_next']]) slide.get_overtheme(parser=self.parser) if slide.overtheme.copy_from_theme is not None and slide.overtheme.copy_from_theme: slide.overtheme.copy_from( other=self.theme) self.position.update_position( presentation_theme=self.theme, overtheme=slide.overtheme) slide.set_position( position=self.position.position) subsection.add_slide(slide=slide) section.add_subsection(subsection=subsection) chapter.add_section(section=section) self.__add_chapter(chapter=chapter) self.metadata['total_slides_number'].update_value( value=str(Subsection.slides_number))
class Slide(object): """ Slide object. """ @classmethod def reset(cls): """Reset to default state.""" return def __init__(self, number, position=None, title=None, contents=None): """" Paramters --------- number: int slide global numeration position: dict position dictionary containing {'x': posx, 'y': posy, 'z': posz, 'rotx': rotx, 'roty': roty, 'rotz': rotz, 'scale': scaling} title: str contents: str """ self.number = number self.position = None self.set_position(position) self.title = title self.contents = contents self.overtheme = Theme() return def __str__(self): strings = [str(self.title)] strings.append(str(self.contents)) return ''.join(strings) def get_overtheme(self, parser): """Get eventaul overtheme definition. Parameters ---------- parser: Parser """ codeblocks = parser.tokenizer(source=self.contents, re_search=parser.regexs['codeblock']) yamlblocks = parser.tokenizer(source=self.contents, re_search=parser.regexs['yamlblock'], exclude=codeblocks) if len(yamlblocks) > 0: self.overtheme.get(source=''.join( [block['match'].group().strip('---') for block in yamlblocks]), name='overtheme', div_id='slide-' + str(self.number)) purged_contents = self.contents[:yamlblocks[0]['start']] for b, yamlblock in enumerate(yamlblocks[:-1]): purged_contents += self.contents[ yamlblock['end']:yamlblocks[b + 1]['start']] purged_contents += self.contents[yamlblocks[-1]['end']:] self.contents = purged_contents def set_position(self, position): """Set slide position. Parameters ---------- position: dict position dictionary containing {'x': posx, 'y': posy, 'z': posz, 'rotx': rotx, 'roty': roty, 'rotz': rotz, 'scale': scaling} """ if position is not None: self.position = {} for key in position: self.position[key] = position[key] def put_html_attributes(self, doc): """Put html attibutes of the slide. Parameters ---------- doc: Doc """ doc.attr(('id', 'slide-' + str(self.number))) # doc.attr(('title', str(self.title))) doc.attr(('class', 'step slide')) doc.attr(('data-x', str(self.position['x']))) doc.attr(('data-y', str(self.position['y']))) doc.attr(('data-z', str(self.position['z']))) doc.attr(('data-scale', str(self.position['scale']))) doc.attr(('data-rotate-x', str(self.position['rotx']))) doc.attr(('data-rotate-y', str(self.position['roty']))) doc.attr(('data-rotate-z', str(self.position['rotz']))) return def to_html(self, doc, parser, metadata, theme, current): """Generate html from self. Parameters ---------- doc: Doc parser: Parser metatadata: dict presentation metadata theme: Theme() presentation theme current: list """ def _parse_env(Env, re_search, source): codeblocks = parser.tokenizer(source=source, re_search=parser.regexs['codeblock']) codes = parser.tokenizer(source=source, re_search=parser.regexs['code'], exclude=codeblocks) yamlblocks = parser.tokenizer(source=source, re_search=parser.regexs['yamlblock'], exclude=codeblocks + codes) envs = parser.tokenizer(source=source, re_search=re_search, exclude=codeblocks + yamlblocks + codes) if len(envs) > 0: parsed_source = source[:envs[0]['start']] for e, env in enumerate(envs[:-1]): current = Env(source=env['match'].group()) parsed_source += current.to_html( ) + source[env['end']:envs[e + 1]['start']] if Env is Video: if self.overtheme.custom: current = Env(source=envs[-1]['match'].group(), theme=self.overtheme) else: current = Env(source=envs[-1]['match'].group(), theme=theme) else: current = Env(source=envs[-1]['match'].group()) parsed_source += current.to_html() + source[envs[-1]['end']:] return parsed_source return source html = self.contents for meta in metadata: html = metadata[meta].parse(parser=parser, source=html, toc_depth=metadata['toc_depth'].value, max_time=metadata['max_time'].value, current=current) html = _parse_env(Env=Box, re_search=Box.regexs['box'], source=html) html = _parse_env(Env=Note, re_search=Note.regexs['note'], source=html) html = _parse_env(Env=Figure, re_search=Figure.regexs['figure'], source=html) html = _parse_env(Env=Table, re_search=Table.regexs['table'], source=html) html = _parse_env(Env=Video, re_search=Video.regexs['video'], source=html) html = _parse_env(Env=Columns, re_search=Columns.regexs['columns'], source=html) with doc.tag('div', klass='slide-content'): doc.asis(markdown2html(source=html)) return
class IconFactory(): """IconFactory finds the icon for a program and prepares the cairo surface.""" icon_theme = gtk.icon_theme_get_default() # Constants # Icon types SOME_MINIMIZED = 1<<4 ALL_MINIMIZED = 1<<5 LAUNCHER = 1<<6 # Icon effects MOUSE_OVER = 1<<7 MOUSE_BUTTON_DOWN = 1<<8 NEEDS_ATTENTION = 1<<9 BLINK = 1<<10 # ACTIVE_WINDOW ACTIVE = 1<<11 LAUNCH_EFFECT = 1<<12 # Double width/height icons for drag and drop situations. DRAG_DROPP_START = 1<<13 DRAG_DROPP_END = 1<<14 TYPE_DICT = {"some_minimized":SOME_MINIMIZED, "all_minimized":ALL_MINIMIZED, "launcher":LAUNCHER, "mouse_over":MOUSE_OVER, "needs_attention":NEEDS_ATTENTION, "blink":BLINK, "active":ACTIVE, "launching":LAUNCH_EFFECT, "mouse_button_down":MOUSE_BUTTON_DOWN} def __init__(self, group, class_group=None, desktop_entry=None, identifier=None): self.dockbar_r = weakref.ref(group.dockbar_r()) self.theme = Theme() self.globals = Globals() connect(self.globals, "color-changed", self.reset_surfaces) self.desktop_entry = desktop_entry self.identifier = identifier self.class_group = class_group # Setting size to something other than zero to # avoid crashes if surface_update() is runned # before the size is set. self.size = 15 self.icon = None self.surfaces = {} self.average_color = None self.max_win_nr = self.theme.get_windows_cnt() self.types_in_theme = 0 for type in self.theme.get_types(): if not type in self.TYPE_DICT: continue self.types_in_theme = self.types_in_theme | self.TYPE_DICT[type] def remove(self): del self.desktop_entry del self.class_group del self.icon del self.surfaces del self.theme def set_desktop_entry(self, desktop_entry): self.desktop_entry = desktop_entry self.surfaces = {} del self.icon self.icon = None def set_class_group(self, class_group): if not self.desktop_entry and not self.class_group: self.surfaces = {} del self.icon self.icon = None self.class_group = class_group def set_size(self, size): if size <= 0: # To avoid chrashes. size = 15 self.size = size self.surfaces = {} self.average_color = None def get_size(self): return self.size def get_icon(self, size): return self.__find_icon_pixbuf(size) def reset_icon(self): self.icon = None def reset_surfaces(self, arg=None): self.surfaces = {} self.average_color = None def surface_update(self, type = 0): # Checks if the requested pixbuf is already # drawn and returns it if it is. # Othervice the surface is drawn, saved and returned. #The first four bits of type is for telling the number of windows self.win_nr = min(type & 15, self.max_win_nr) # Remove all types that are not used by the theme (saves memory) dnd = (type & self.DRAG_DROPP_START and "start") or \ (type & self.DRAG_DROPP_END and "end") type = type & self.types_in_theme type += self.win_nr self.orient = self.dockbar_r().orient is_vertical = self.orient in ("left", "right") if type in self.surfaces: surface = self.surfaces[type] else: self.temp = {} surface = None commands = self.theme.get_icon_dict() self.ar = self.theme.get_aspect_ratio(is_vertical) self.type = type for command, args in commands.items(): try: f = getattr(self, "_IconFactory__command_%s"%command) except: raise else: surface = f(surface, **args) # Todo: add size correction. self.surfaces[type] = surface del self.temp gc.collect() if dnd: surface = self.__dd_highlight(surface, self.orient, dnd) gc.collect() return surface def __dd_highlight(self, surface, is_vertical, position="start"): w = surface.get_width() h = surface.get_height() if is_vertical: h = h + 4 else: w = w + 4 bg = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) ctx = cairo.Context(bg) if is_vertical and position == "start": ctx.move_to(1, 1.5) ctx.line_to(w - 1, 1.5) ctx.set_source_rgba(1, 1, 1, 0.2) ctx.set_line_width(2) ctx.stroke() ctx.move_to(2, 1.5) ctx.line_to(w - 2, 1.5) ctx.set_source_rgba(0, 0, 0, 0.7) ctx.set_line_width(1) ctx.stroke() elif is_vertical: ctx.move_to(1, h - 1.5) ctx.line_to(w - 1, h - 1.5) ctx.set_source_rgba(1, 1, 1, 0.2) ctx.set_line_width(2) ctx.stroke() ctx.move_to(2, h - 1.5) ctx.line_to(w - 2, h - 1.5) ctx.set_source_rgba(0, 0, 0, 0.7) ctx.set_line_width(1) ctx.stroke() elif position == "start": ctx.move_to(1.5, 1) ctx.line_to(1.5, h - 1) ctx.set_source_rgba(1, 1, 1, 0.2) ctx.set_line_width(2) ctx.stroke() ctx.move_to(1.5, 2) ctx.line_to(1.5, h - 2) ctx.set_source_rgba(0, 0, 0, 0.7) ctx.set_line_width(1) ctx.stroke() else: ctx.move_to(w - 1.5, 1) ctx.line_to(w - 1.5, h - 1) ctx.set_source_rgba(1, 1, 1, 0.2) ctx.set_line_width(2) ctx.stroke() ctx.move_to(w - 1.5, 2) ctx.line_to(w - 1.5, h - 2) ctx.set_source_rgba(0, 0, 0, 0.7) ctx.set_line_width(1) ctx.stroke() x, y = 0, 0 if is_vertical and position == "start": y = 4 elif position == "start": x = 4 ctx.set_source_surface(surface, x, y) ctx.paint() return bg def __get_color(self, color): if color == "active_color": color = "color5" if color in ["color%s"%i for i in range(1, 9)]: color = self.globals.colors[color] if color == "icon_average": color = self.__get_average_color() else: try: if len(color) != 7: raise ValueError("The string has the wrong lenght") t = int(color[1:], 16) except: logger.exception("Theme error: the color attribute " + "for a theme command"+ \ " should be a six digit hex string eg. \"#FFFFFF\" or"+ \ " the a dockbarx color (\"color1\"-\"color8\").") color = "#000000" return color def __get_alpha(self, alpha): # Transparency if alpha == "active_opacity": # For backwards compability alpha = "color5" for i in range(1, 9): if alpha in ("color%s"%i, "opacity%s"%i): if self.globals.colors.has_key("color%s_alpha"%i): a = float(self.globals.colors["color%s_alpha"%i])/255 else: logger.warning("Theme error: The theme has no" + \ " opacity option for color%s." % i) a = 1.0 break else: try: a = float(alpha)/100 if a > 1.0 or a < 0: raise except: logger.exception("Theme error: The opacity attribute of a theme " + \ "command should be a number between \"0\" " + \ " and \"100\" or \"color1\" to \"color8\".") a = 1.0 return a def __get_average_color(self): if self.average_color is not None: return self.average_color r = 0 b = 0 g = 0 i = 0 im = self.__surface2pil(self.icon) pixels = im.load() width, height = im.size for x in range(width): for y in range(height): pix = pixels[x, y] if pix[3] > 30: i += 1 r += pix[0] g += pix[1] b += pix[2] if i > 0: r = int(round(float(r) / i)) g = int(round(float(g) / i)) b = int(round(float(b) / i)) r = ("0%s"%hex(r)[2:])[-2:] g = ("0%s"%hex(g)[2:])[-2:] b = ("0%s"%hex(b)[2:])[-2:] self.average_color = "#"+r+g+b return self.average_color #### Flow commands def __command_if(self, surface, type=None, windows=None, size=None, orient=None, content=None): if content is None: return surface # TODO: complete this ## l = [] ## splits = ["!", "(", ")", "&", "|"] ## for c in type: ## if c in splits: ## l.append(c) ## elif l[-1] in splits: ## l.append(c) ## elif not l: ## l.append(c) ## else: ## l[-1] += c # Check if the type condition is satisfied if type is not None: negation = False if type[0] == "!" : type = type[1:] negation = True is_type = bool(type in self.TYPE_DICT \ and self.type & self.TYPE_DICT[type]) if not (is_type ^ negation): return surface #Check if the window number condition is satisfied if windows is not None: arg = windows negation = False if arg[0] == "!" : arg = windows[1:] negation = True if arg[0] == ":": arg = "0" + arg elif arg[-1] == ":": arg = arg +"15" l = arg.split(":", 1) try: l = [int(n) for n in l] except ValueError: logger.exception("Theme Error: The windows attribute of " + \ "an <if> statement can\'t look like this:" + \ " \"%s\"." % windows + \ "See Theming HOWTO for more information") return surface if len(l) == 1: if not ((l[0] == self.win_nr) ^ negation): return surface else: if not ((l[0]<=self.win_nr and self.win_nr<=l[1]) ^ negation): return surface #Check if the icon size condition is satisfied if size is not None: arg = size negation = False if arg[0] == "!" : arg = size[1:] negation = True if arg[0] == ":": arg = "0" + arg elif arg[-1] == ":": arg = arg +"200" l = arg.split(":", 1) try: l = [int(n) for n in l] except ValueError: logger.exception("Theme Error: The size attribute of " + \ "an <if> statement can\'t look like this:" + \ " \"%s\". See Theming HOWTO for more information" % size) return surface us = int(round(self.__get_use_size())) if len(l) == 1: if not ((l[0] == self.win_nr) ^ negation): return surface else: if not ((l[0]<=us and us<=l[1]) ^ negation): return surface # Test if the orient condition is satisfied. if orient is not None: orients = orient.split(",") if not self.orient in orients: return surface # All tests passed, proceed. for command, args in content.items(): try: f = getattr(self,"_IconFactory__command_%s"%command) except: raise else: surface = f(surface, **args) return surface def __command_pixmap_from_self(self, surface, name, content=None): if not name: logger.warning("Theme Error: no name given for pixmap_from_self") raise Exeption w = int(surface.get_width()) h = int(surface.get_height()) self.temp[name] = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) ctx = cairo.Context(self.temp[name]) ctx.set_source_surface(surface) ctx.paint() if content is None: return surface for command,args in content.items(): try: f = getattr(self,"_IconFactory__command_%s"%command) except: raise else: self.temp[name] = f(self.temp[name], **args) return surface def __command_pixmap(self, surface, name, content=None, size=None): if size is not None: # TODO: Fix for different height and width w = h = int(round(self.__get_use_size() + \ self.__process_size(size))) elif surface is None: w = h = int(round(self.__get_use_size())) else: w = surface.get_width() h = surface.get_height() self.temp[name] = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) if content is None: return surface for command,args in content.items(): try: f = getattr(self,"_IconFactory__command_%s"%command) except: raise else: self.temp[name] = f(self.temp[name], **args) return surface #### Get icon def __command_get_icon(self,surface=None, size="0"): size = int(self.__get_use_size() + self.__process_size(size)) if size <= 0: # To avoid chrashes. size = 15 if self.icon and\ self.icon.get_width() == size and \ self.icon.get_height() == size: return self.icon del self.icon self.icon = None pb = self.__find_icon_pixbuf(size) if pb.get_width() != pb.get_height(): if pb.get_width() < pb.get_height(): h = size w = pb.get_width() * size/pb.get_height() elif pb.get_width() > pb.get_height(): w = size h = pb.get_height() * size/pb.get_width() self.icon = cairo.ImageSurface(cairo.FORMAT_ARGB32, size, size) ctx = gtk.gdk.CairoContext(cairo.Context(self.icon)) pbs = pb.scale_simple(w, h, gtk.gdk.INTERP_BILINEAR) woffset = round((size - w) / 2.0) hoffset = round((size - h) / 2.0) ctx.set_source_pixbuf(pb, woffset, hoffset) ctx.paint() del pb del pbs elif pb.get_width() != size: pbs = pb.scale_simple(size, size, gtk.gdk.INTERP_BILINEAR) self.icon = self.__pixbuf2surface(pbs) del pb del pbs else: self.icon = self.__pixbuf2surface(pb) del pb return self.icon def __find_icon_pixbuf(self, size): # Returns the icon pixbuf for the program. Uses the following metods: # 1) If it is a launcher, return the icon from the # launcher's desktopfile # 2) Get the icon from the gio app # 3) Check if the res_class fits an themed icon. # 4) Search in path after a icon matching reclass. # 5) Use the mini icon for the class pixbuf = None icon_name = None if self.desktop_entry: icon_name = self.desktop_entry.getIcon() if icon_name is not None and os.path.isfile(icon_name): pixbuf = self.__icon_from_file_name(icon_name, size) if pixbuf is not None: return pixbuf if not icon_name: if self.identifier: icon_name = self.identifier.lower() elif self.class_group: icon_name = self.class_group.get_res_class().lower() else: icon_name = "" # Special cases if icon_name.startswith("openoffice"): icon_name = "ooo-writer" if icon_name.startswith("libreoffice"): icon_name = "libreoffice-writer" if self.icon_theme.has_icon(icon_name): return self.icon_theme.load_icon(icon_name,size,0) if icon_name[-4:] in (".svg", ".png", ".xpm"): if self.icon_theme.has_icon(icon_name[:-4]): pixbuf = self.icon_theme.load_icon(icon_name[:-4],size,0) if pixbuf is not None: return pixbuf pixbuf = self.__icon_search_in_data_path(icon_name, size) if pixbuf is not None: return pixbuf if self.class_group: return self.class_group.get_icon().copy() # If no pixbuf has been found (can only happen for an unlaunched # launcher), make an empty pixbuf and show a warning. if self.icon_theme.has_icon("application-default-icon"): pixbuf = self.icon_theme.load_icon("application-default-icon", size, 0) else: pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8, size,size) pixbuf.fill(0x00000000) if self.desktop_entry: name = self.desktop_entry.getName() else: name = None return pixbuf def __icon_from_file_name(self, icon_name, icon_size = -1): if os.path.isfile(icon_name): try: return gtk.gdk.pixbuf_new_from_file_at_size(icon_name, -1, icon_size) except: pass return None def __icon_search_in_data_path(self, icon_name, icon_size): data_folders = None if os.environ.has_key("XDG_DATA_DIRS"): data_folders = os.environ["XDG_DATA_DIRS"] if not data_folders: data_folders = "/usr/local/share/:/usr/share/" for data_folder in data_folders.split(":"): #The line below line used datafolders instead of datafolder. #I changed it because I suspect it was a bug. paths = (os.path.join(data_folder, "pixmaps", icon_name), os.path.join(data_folder, "icons", icon_name)) for path in paths: if os.path.isfile(path): icon = self.__icon_from_file_name(path, icon_size) if icon: return icon return None #### Other commands def __command_clear(self, surface): if self.dockbar_r().orient in ("left", "right"): w = self.size h = int(self.size * self.ar) else: w = int(self.size * self.ar) h = self.size new = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) ctx = cairo.Context(new) ctx.set_source_rgba(0, 0, 0) ctx.set_operator(cairo.OPERATOR_SOURCE) ctx.paint_with_alpha(0) return new def __command_get_pixmap(self, surface, name): if surface is None: if self.dockbar_r().orient in ("left", "right"): width = self.size height = int(self.size * self.ar) else: width = int(self.size * self.ar) height = self.size else: width = surface.get_width() height = surface.get_height() if self.theme.has_surface(name): surface = self.__resize_surface(self.theme.get_surface(name), width, height) else: logger.warning("theme error: pixmap %s not found" % name) return surface def __command_fill(self, surface, color, opacity="100"): w = surface.get_width() h = surface.get_height() new = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) ctx = cairo.Context(new) ctx.set_source_surface(surface) ctx.paint() alpha = self.__get_alpha(opacity) c = self.__get_color(color) r = float(int(c[1:3], 16))/255 g = float(int(c[3:5], 16))/255 b = float(int(c[5:7], 16))/255 ctx.set_source_rgba(r, g, b) ctx.set_operator(cairo.OPERATOR_SOURCE) ctx.paint_with_alpha(alpha) return new def __command_combine(self, surface, pix1, pix2, degrees=None): # Combines left half of surface with right half of surface2. # The transition between the two halves are soft. # Degrees keyword are kept of compability reasons. w = surface.get_width() h = surface.get_height() if pix1=="self": p1 = surface elif pix1 in self.temp: p1 = self.temp[pix1] elif self.theme.has_surface(pix1): w = surface.get_width() h = surface.get_height() p1 = self.__resize_surface(self.theme.get_surface(bg), w, h) else: logger.warning("theme error: pixmap %s not found"%pix1) if pix2=="self": p2 = surface elif pix2 in self.temp: p2 = self.temp[pix2] elif self.theme.has_surface(pix2): w = surface.get_width() h = surface.get_height() p2 = self.__resize_surface(self.theme.get_surface(bg), w, h) else: logger.warning("theme error: pixmap %s not found" % pix2) surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, p1.get_width(), p1.get_height()) ctx = cairo.Context(surface) linear = cairo.LinearGradient(0, 0, p1.get_width(), 0) linear.add_color_stop_rgba(0.4, 0, 0, 0, 0.5) linear.add_color_stop_rgba(0.6, 0, 0, 0, 1) ctx.set_source_surface(p2, 0, 0) #ctx.mask(linear) ctx.paint() linear = cairo.LinearGradient(0, 0, p1.get_width(), 0) linear.add_color_stop_rgba(0.4, 0, 0, 0, 1) linear.add_color_stop_rgba(0.6, 0, 0, 0, 0) ctx.set_source_surface(p1, 0, 0) ctx.mask(linear) try: del pb del pbs except: pass return surface def __command_transp_sat(self, surface, opacity="100", saturation="100"): # Makes the icon desaturized and/or transparent. alpha = self.__get_alpha(opacity) # Todo: Add error check for saturation sat = float(saturation) if sat != 100: im = self.__surface2pil(surface) w, h = im.size pixels = im.load() for x in range(w): for y in range(h): r, g, b, a = pixels[x, y] l = (r + g + b) / 3.0 * (100 - sat) / 100.0 r = int(r * sat / 100.0 + l) g = int(g * sat / 100.0 + l) b = int(b * sat / 100.0 + l) a = int(a * alpha) pixels[x, y] = (r, g, b, a) return self.__pil2surface(im) else: w = surface.get_width() h = surface.get_height() new = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) ctx = gtk.gdk.CairoContext(cairo.Context(new)) ctx.set_source_surface(surface) ctx.paint_with_alpha(alpha) return new def __command_composite(self, surface, bg, fg, opacity="100", xoffset="0", yoffset="0", angle="0"): if fg == "self": foreground = surface if angle and angle != "0": foreground = self.__command_rotate(foreground, angle, True) elif fg in self.temp: foreground = self.temp[fg] if angle and angle != "0": foreground = self.__command_rotate(foreground, angle, True) elif self.theme.has_surface(fg): foreground = self.theme.get_surface(fg) if angle and angle != "0": foreground = self.__command_rotate(foreground, angle, True) w = surface.get_width() h = surface.get_height() foreground = self.__resize_surface(foreground, w, h) else: logger.warning("theme error: pixmap %s not found" % fg) return surface if bg == "self": background = surface elif bg in self.temp: w = self.temp[bg].get_width() h = self.temp[bg].get_height() background = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) ctx = cairo.Context(background) ctx.set_source_surface(self.temp[bg]) ctx.paint() elif self.theme.has_surface(bg): w = surface.get_width() h = surface.get_height() background = self.__resize_surface(self.theme.get_surface(bg), w, h) else: logger.warning("theme error: pixmap %s not found" % bg) return surface xoffset = self.__get_from_set(xoffset) yoffset = self.__get_from_set(yoffset) opacity = self.__get_alpha(opacity) xoffset = self.__process_size(xoffset) yoffset = self.__process_size(yoffset) ctx = cairo.Context(background) ctx.set_source_surface(foreground, xoffset, yoffset) ctx.paint_with_alpha(opacity) return background def __command_shrink(self, surface, percent="0", pixels="0"): w0 = surface.get_width() h0 = surface.get_height() new = cairo.ImageSurface(cairo.FORMAT_ARGB32, w0, h0) ctx = cairo.Context(new) pixels = self.__get_from_set(pixels) percent = self.__get_from_set(percent) w = int(((100-int(percent)) * w0)/100)-int(pixels) h = int(((100-int(percent)) * h0)/100)-int(pixels) shrinked = self.__resize_surface(surface, w, h) x = round((w0 - w) / 2.0) y = round((h0 - h) / 2.0) ctx.set_source_surface(shrinked, x, y) ctx.paint() del shrinked return new def __command_rotate(self, surface, angle="0", resize="False"): w0 = surface.get_width() h0 = surface.get_height() # Check if the angle should be taken from a set. angle = self.__get_from_set(angle) a = float(angle)/180*pi if not resize or resize in ("False", "0"): w = w0 h = h0 else: w = abs(int(round(cos(a) * w0 + sin(a) * h0))) h = abs(int(round(cos(a) * h0 + sin(a) * w0))) new = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) ctx = cairo.Context(new) ctx.translate(w/2.0, h/2.0) ctx.rotate(a) ctx.translate(-w0/2.0, -h0/2.0) ctx.set_source_surface(surface, 0,0) ctx.paint() return new def __command_correct_size(self, surface): if surface is None: return if self.dockbar_r().orient in ("left", "right"): width = self.size height = int(self.size * self.ar) else: width = int(self.size * self.ar) height = self.size if surface.get_width() == width and surface.get_height() == height: return surface woffset = round((width - surface.get_width()) / 2.0) hoffset = round((height - surface.get_height()) / 2.0) new = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height) ctx = cairo.Context(new) ctx.set_source_surface(surface, woffset, hoffset) ctx.paint() return new def __command_glow(self, surface, color, opacity="100"): # Adds a glow around the parts of the surface # that isn't completely transparent. alpha = self.__get_alpha(opacity) # Thickness (pixels) tk = 1.5 # Prepare the glow that should be put behind the icon cs = self.__command_colorize(surface, color) w = surface.get_width() h = surface.get_height() glow = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) ctx = cairo.Context(glow) tk1 = tk/2.0 for x, y in ((-tk1,-tk1), (-tk1,tk1), (tk1,-tk1), (tk1,tk1)): ctx.set_source_surface(cs, x, y) ctx.paint_with_alpha(0.66) for x, y in ((-tk,-tk), (-tk,tk), (tk,-tk), (tk,tk)): ctx.set_source_surface(cs, x, y) ctx.paint_with_alpha(0.27) # Add glow and icon to a new canvas new = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) ctx = cairo.Context(new) ctx.set_source_surface(glow) ctx.paint_with_alpha(alpha) ctx.set_source_surface(surface) ctx.paint() return new def __command_colorize(self, surface, color): # Changes the color of all pixels to color. # The pixels alpha values are unchanged. # Convert color hex-string (format "#FFFFFF")to int r, g, b color = self.__get_color(color) r = int(color[1:3], 16)/255.0 g = int(color[3:5], 16)/255.0 b = int(color[5:7], 16)/255.0 w = surface.get_width() h = surface.get_height() new = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) ctx = cairo.Context(new) ctx.set_source_rgba(r,g,b,1.0) ctx.mask_surface(surface) return new def __command_bright(self, surface, strength = None, strenght = None): if strength is None and strenght is not None: # For compability with older themes. strength = strenght alpha = self.__get_alpha(strength) w = surface.get_width() h = surface.get_height() # Colorize white white = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) ctx = cairo.Context(white) ctx.set_source_rgba(1.0, 1.0, 1.0, 1.0) ctx.mask_surface(surface) # Apply the white version over the icon # with the chosen alpha value new = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) ctx = cairo.Context(new) ctx.set_source_surface(surface) ctx.paint() ctx.set_source_surface(white) ctx.paint_with_alpha(alpha) return new def __command_alpha_mask(self, surface, mask, angle="0"): if mask in self.temp: mask = self.temp[mask] if angle and angle != "0": mask = self.__command_rotate(mask, angle, True) elif self.theme.has_surface(mask): mask = self.theme.get_surface(mask) if angle and angle != "0": mask = self.__command_rotate(mask, angle, True) w = surface.get_width() h = surface.get_height() mask = self.__resize_surface(mask, w, h) w = surface.get_width() h = surface.get_height() new = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) ctx = cairo.Context(new) ctx.set_source_surface(surface) ctx.mask_surface(mask) return new #### Format conversions def __pixbuf2surface(self, pixbuf): if pixbuf is None: return None w = pixbuf.get_width() h = pixbuf.get_height() surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) ctx = gtk.gdk.CairoContext(cairo.Context(surface)) ctx.set_source_pixbuf(pixbuf, 0, 0) ctx.paint() del pixbuf return surface def __surface2pil(self, surface): w = surface.get_width() h = surface.get_height() return Image.frombuffer("RGBA", (w, h), surface.get_data(), "raw", "BGRA", 0,1) def __pil2surface(self, im): """Transform a PIL Image into a Cairo ImageSurface.""" # This function is only supposed to work with little endinan # systems. Could that be a problem ever? if im.mode != 'RGBA': im = im.convert('RGBA') s = im.tobytes('raw', 'BGRA') a = array.array('B', s) dest = cairo.ImageSurface(cairo.FORMAT_ARGB32, im.size[0], im.size[1]) ctx = cairo.Context(dest) non_premult_src_wo_alpha = cairo.ImageSurface.create_for_data( a, cairo.FORMAT_RGB24, im.size[0], im.size[1]) non_premult_src_alpha = cairo.ImageSurface.create_for_data( a, cairo.FORMAT_ARGB32, im.size[0], im.size[1]) ctx.set_source_surface(non_premult_src_wo_alpha) ctx.mask_surface(non_premult_src_alpha) return dest def __process_size(self, size_str): us = self.__get_use_size() size = 0 size_str = size_str.replace("-", "+-") for s in size_str.split("+"): if s=="": continue if s[-1] == "%": # Rounding to whole pixels to avoid uninteded bluring. size += round(float(s[:-1]) / 100 * us) continue if s.endswith("px"): s = s[:-2] # Here no rounding is done. Let's assume that the # theme maker knows what he is doing if he chooses # to use decimal pixel values. size += float(s) return size def __get_use_size(self): is_vertical = self.dockbar_r().orient in ("left", "right") if "aspect_ratio_v" in self.theme.theme["button_pixmap"] or \ not is_vertical: us = self.size * self.ar if self.ar < 1 else self.size else: # For old vertical themes us = self.size return us def __get_from_set(self, setname): s = self.theme.get_from_set(setname, self.orient) if s is not None: return s else: return setname def __resize_surface(self, surface, w, h): im = self.__surface2pil(surface) im = im.resize((w, h), Image.ANTIALIAS) return self.__pil2surface(im) def __command_print_size(self, surface): w = surface.get_width() h = surface.get_height() print w, h return surface
# any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. # This module *just* use for test module under dtk.ui from skin_config import skin_config from theme import Theme, ui_theme from deepin_utils.file import get_parent_dir import os # Init skin config. skin_config.init_skin( "01", os.path.join(get_parent_dir(__file__, 3), "skin"), os.path.expanduser("~/.config/deepin-demo/skin"), os.path.expanduser("~/.config/deepin-demo/skin_config.ini"), "deepin-media-player", "1.0") # Create application theme. app_theme = Theme(os.path.join(get_parent_dir(__file__, 3), "app_theme"), os.path.expanduser("~/.config/deepin-demo/theme")) # Set theme. skin_config.load_themes(ui_theme, app_theme)
class MainWindow(object): def __init__(self, liststore): self.liststore = liststore self.gui = gui = Gtk.Builder() gui.add_from_file(SHARED_DATA_FILE("gfeedline.glade")) self.window = window = gui.get_object("main_window") self.column = MultiColumnDict(gui) # multi-columns for Notebooks self.theme = Theme() self.font = FontSet() self.notification = StatusNotification(liststore) dnd_list = [Gtk.TargetEntry.new("text/uri-list", 0, 1), Gtk.TargetEntry.new("text/x-moz-url", 0, 4)] window.drag_dest_set(Gtk.DestDefaults.ALL, dnd_list, Gdk.DragAction.COPY) target = Gtk.TargetList.new([]) target.add(Gdk.Atom.intern("text/x-moz-url", False), 0, 4) target.add(Gdk.Atom.intern("text/uri-list", False), 0, 1) window.drag_dest_set_target_list(target) window.connect("drag-data-received", self.on_drag_data_received) SETTINGS.connect("changed::window-sticky", self.on_settings_sticky_change) self.on_settings_sticky_change(SETTINGS, "window-sticky") SETTINGS_VIEW.connect("changed::theme", self.on_settings_theme_change) self.on_settings_theme_change(SETTINGS_VIEW, "theme") is_multi_column = SETTINGS_VIEW.get_boolean("multi-column") menuitem_multicolumn = gui.get_object("menuitem_multicolumn") menuitem_multicolumn.set_active(is_multi_column) menuitem_update = MenuItemUpdate(gui, liststore) x, y, w, h = self._get_geometry_from_settings() # window.show() # for wrong position when auto-start if x >= 0 and y >= 0: window.move(x, y) window.resize(w, h) window.show() gui.connect_signals(self) def on_drag_data_received(self, widget, context, x, y, selection, info, time): text, image_file = DnDSelection.parse(info, selection, True) if text or image_file: updatewindow = UpdateWindow(self) if text: updatewindow.text_buffer.set_text(text) else: updatewindow.set_upload_media(image_file) def get_notebook(self, group_name): if not SETTINGS_VIEW.get_boolean("multi-column"): group_name = "dummy for single column" if group_name in self.column: notebook = self.column.get(group_name) else: notebook = FeedNotebook(self.column, group_name, self.liststore) self.column.add(group_name, notebook) return notebook def toggle_multicolumn_mode(self): for row in self.liststore: notebook = self.get_notebook(row[Column.GROUP]) view = row[Column.API].view view.force_remove() view.append(notebook, -1) reactor.callLater(0.1, self._jump_all_tabs_to_bottom, self.theme.is_ascending()) def _jump_all_tabs_to_bottom(self, is_bottom=True): for notebook in self.column.values(): notebook.jump_all_tabs_to_bottom(is_bottom) def change_font(self, font=None, size=None): for notebook in self.column.values(): notebook.change_font(font, size) def delete_status(self, status_id): js = 'hideStatus("%s")' % status_id for notebook in self.column.values(): notebook.exec_js_all_views(js) def _get_geometry_from_settings(self): x = SETTINGS_GEOMETRY.get_int("window-x") y = SETTINGS_GEOMETRY.get_int("window-y") w = SETTINGS_GEOMETRY.get_int("window-width") h = SETTINGS_GEOMETRY.get_int("window-height") return x, y, w, h def on_window_leave_notify_event(self, widget, event): ox, oy, ow, oh = self._get_geometry_from_settings() x, y = widget.get_position() w, h = widget.get_size() if x != ox or y != oy: SETTINGS_GEOMETRY.set_int("window-x", x) SETTINGS_GEOMETRY.set_int("window-y", y) if w != ow or h != oh: SETTINGS_GEOMETRY.set_int("window-width", w) SETTINGS_GEOMETRY.set_int("window-height", h) def on_stop(self, *args): for row in self.liststore: row[Column.OPTIONS]["last_id"] = row[Column.API].last_id self.liststore.save_settings() reactor.stop() # self.window.destroy() def on_menuitem_quit_activate(self, menuitem): self.on_stop() def on_menuitem_update_activate(self, menuitem): UpdateWindow(self.liststore) def on_menuitem_prefs_activate(self, menuitem): Preferences(self) def on_menuitem_multicolumn_toggled(self, menuitem): is_multi_column = menuitem.get_active() SETTINGS_VIEW.set_boolean("multi-column", is_multi_column) self.toggle_multicolumn_mode() def on_menuitem_about_activate(self, menuitem): AboutDialog(self.window) def on_menuitem_help_activate(self, menuitem): Gtk.show_uri(None, "http://code.google.com/p/gfeedline/wiki/Tips", Gdk.CURRENT_TIME) def on_menuitem_top_activate(self, menuitem=None): self._jump_all_tabs_to_bottom(False) def on_menuitem_bottom_activate(self, menuitem=None): self._jump_all_tabs_to_bottom() def on_menuitem_clear_activate(self, menuitem=None): for notebook in self.column.values(): notebook.clear_all_tabs() def on_menuitem_fullscreen_activate(self, menuitem): if menuitem.get_active(): self.window.fullscreen() else: self.window.unfullscreen() def on_menuitem_zoom_in_activate(self, menuitem): font_css = self.font.zoom_in() self.change_font(font_css) def on_menuitem_zoom_out_activate(self, menuitem): font_css = self.font.zoom_out() self.change_font(font_css) def on_menuitem_zoom_default_activate(self, menuitem): font_css = self.font.zoom_default() self.change_font(font_css) def on_settings_sticky_change(self, settings, key): if settings.get_boolean(key): self.window.stick() else: self.window.unstick() def on_settings_theme_change(self, settings, key): top = self.gui.get_object("menuitem_top") bottom = self.gui.get_object("menuitem_bottom") if not self.theme.is_ascending(): top, bottom = bottom, top top.hide() bottom.show()
class DemoPrinter(object): def __init__(self): self.LV_HOR_RES = lv.scr_act().get_disp().driver.hor_res self.LV_VER_RES = lv.scr_act().get_disp().driver.ver_res # Bg positions self.LV_DEMO_PRINTER_BG_NONE = -self.LV_VER_RES self.LV_DEMO_PRINTER_BG_FULL = 0 self.LV_DEMO_PRINTER_BG_NORMAL = -2 * (self.LV_VER_RES // 3) self.LV_DEMO_PRINTER_BG_SMALL = -5 * (self.LV_VER_RES // 6) # Animations self.LV_DEMO_PRINTER_ANIM_Y = self.LV_VER_RES // 20 self.LV_DEMO_PRINTER_ANIM_DELAY = 40 self.LV_DEMO_PRINTER_ANIM_TIME = 150 self.LV_DEMO_PRINTER_ANIM_TIME_BG = 300 self.LV_DEMO_PRINTER_BG_NORMAL = (-2 * (self.LV_VER_RES // 3)) self.log = logging.getLogger("DemoPrinter") self.log.setLevel(logging.ERROR) self.icon_wifi_data = None self.icon_wifi_dsc = None self.icon_tel_data = None self.icon_tel_dsc = None self.icon_eco_data = None self.icon_eco_dsc = None self.icon_pc_data = None self.icon_pc_dsc = None self.img_btn_bg_1_data = None self.img_btn_bg_1_dsc = None self.img_btn_bg_2_data = None self.img_btn_bg_2_dsc = None self.img_btn_bg_3_data = None self.img_btn_bg_3_dsc = None self.img_btn_bg_4_data = None self.img_btn_bg_4_dsc = None self.img_copy_data = None self.img_copy_dsc = None self.img_print_data = None self.img_print_dsc = None self.img_scan_data = None self.img_scan_dsc = None self.img_setup_data = None self.img_setup_dsc = None self.scan_img = None self.bg_top = None self.bg_bottom = None self.bg_color_prev = LV_DEMO_PRINTER_BLUE self.bg_color_act = LV_DEMO_PRINTER_BLUE self.bg_top = lv.obj(lv.scr_act(), None) self.bg_top.set_size(self.LV_HOR_RES, self.LV_VER_RES) # read all the images fromm the raw image files (self.icon_wifi_data, self.icon_wifi_dsc) = self.get_icon("icon_wifi_48x34", 48, 34) (self.icon_tel_data, self.icon_tel_dsc) = self.get_icon("icon_tel_35x35", 35, 35) (self.icon_eco_data, self.icon_eco_dsc) = self.get_icon("icon_eco_38x34", 38, 34) (self.icon_pc_data, self.icon_pc_dsc) = self.get_icon("icon_pc_41x33", 41, 33) (self.icon_bright_data, self.icon_bright_dsc) = self.get_icon("icon_bright_29x29", 29, 29) (self.icon_hue_data, self.icon_hue_dsc) = self.get_icon("icon_hue_23x23", 23, 23) (self.img_btn_bg_1_data, self.img_btn_bg_1_dsc) = self.get_icon("img_btn_bg_1_174x215", 174, 215) (self.img_btn_bg_2_data, self.img_btn_bg_2_dsc) = self.get_icon("img_btn_bg_2_174x215", 174, 215) (self.img_btn_bg_3_data, self.img_btn_bg_3_dsc) = self.get_icon("img_btn_bg_3_174x215", 174, 215) (self.img_btn_bg_4_data, self.img_btn_bg_4_dsc) = self.get_icon("img_btn_bg_4_174x215", 174, 215) (self.img_copy_data, self.img_copy_dsc) = self.get_icon("img_copy_51x60", 51, 60) (self.img_print_data, self.img_print_dsc) = self.get_icon("img_print_65x64", 65, 64) (self.img_scan_data, self.img_scan_dsc) = self.get_icon("img_scan_51x61", 51, 61) (self.img_setup_data, self.img_setup_dsc) = self.get_icon("img_setup_63x64", 63, 64) (self.img_usb_data, self.img_usb_dsc) = self.get_icon("img_usb_62x61", 62, 61) (self.img_internet_data, self.img_internet_dsc) = self.get_icon("img_internet_65x64", 65, 64) (self.img_mobile_data, self.img_mobile_dsc) = self.get_icon("img_mobile_50x60", 50, 60) (self.img_wave_data, self.img_wave_dsc) = self.get_icon("img_wave_27x47", 27, 47) (self.img_phone_data, self.img_phone_dsc) = self.get_icon("img_phone_77x99", 77, 99) (self.img_ready, self.img_ready_dsc) = self.get_icon("img_ready_158x158", 158, 158) (self.img_printer2_data, self.img_printer2_dsc) = self.get_icon("img_printer2_107x104", 107, 104) (self.img_no_internet_data, self.img_no_internet_dsc) = self.get_icon("img_no_internet_42x42", 42, 42) (self.img_cloud_data, self.img_cloud_dsc) = self.get_icon("img_cloud_93x59", 93, 59) (self.scan_example_data, self.scan_example_dsc) = self.get_icon("scan_example_522x340", 522, 340) self.theme = Theme() self.home_open(0) def home_open(self, delay): self.bg_top.set_style_local_bg_opa(lv.obj.PART.MAIN, lv.STATE.DEFAULT, lv.OPA.COVER) self.bg_top.set_style_local_bg_color(lv.obj.PART.MAIN, lv.STATE.DEFAULT, LV_DEMO_PRINTER_BLUE) self.bg_top.set_y(self.LV_DEMO_PRINTER_BG_NORMAL) self.cont = lv.cont(lv.scr_act(), None) self.cont.set_size(350, 80) self.cont.clean_style_list(lv.cont.PART.MAIN) self.cont.align(None, lv.ALIGN.IN_TOP_LEFT, 60, 0) icon = lv.img(self.cont, None) icon.set_src(self.icon_wifi_dsc) icon.align(None, lv.ALIGN.IN_TOP_LEFT, 20, 45) self.anim_in(icon, delay) icon = lv.img(self.cont, None) icon.set_src(self.icon_tel_dsc) icon.align(None, lv.ALIGN.IN_TOP_LEFT, 110, 45) self.anim_in(icon, delay) icon = lv.img(self.cont, None) icon.set_src(self.icon_eco_dsc) icon.align(None, lv.ALIGN.IN_TOP_LEFT, 200, 45) self.anim_in(icon, delay) icon = lv.img(self.cont, None) icon.set_src(self.icon_pc_dsc) icon.align(None, lv.ALIGN.IN_TOP_LEFT, 290, 45) self.anim_in(icon, delay) title = self.add_title("23 February 2021 20:13") title.align(None, lv.ALIGN.IN_TOP_RIGHT, -60, LV_DEMO_PRINTER_TITLE_PAD) delay += self.LV_DEMO_PRINTER_ANIM_DELAY self.anim_in(title, delay) box_w = 720 box = lv.obj(lv.scr_act(), None) box.set_size(box_w, 260) self.theme.apply(box, lv.THEME.CONT) box.align(None, lv.ALIGN.IN_TOP_MID, 0, 100) delay += self.LV_DEMO_PRINTER_ANIM_DELAY self.anim_in(box, delay) icon = self.add_icon(box, self.img_btn_bg_1_dsc, self.img_copy_dsc, "COPY") icon.align(None, lv.ALIGN.IN_LEFT_MID, 1 * (box_w - 20) // 8 - 80, 0) icon.set_event_cb(self.copy_open_icon_event_cb) icon.fade_in(self.LV_DEMO_PRINTER_ANIM_TIME * 2, delay + self.LV_DEMO_PRINTER_ANIM_TIME + 50) icon = self.add_icon(box, self.img_btn_bg_2_dsc, self.img_scan_dsc, "SCAN") icon.align(None, lv.ALIGN.IN_LEFT_MID, 3 * (box_w - 20) // 8 - 80, 0) icon.fade_in(self.LV_DEMO_PRINTER_ANIM_TIME * 2, delay + self.LV_DEMO_PRINTER_ANIM_TIME + 50) icon.set_event_cb(self.scan_open_icon_event_cb) icon = self.add_icon(box, self.img_btn_bg_3_dsc, self.img_print_dsc, "PRINT") icon.align(None, lv.ALIGN.IN_LEFT_MID, 5 * (box_w - 20) // 8 - 80, 0) icon.fade_in(self.LV_DEMO_PRINTER_ANIM_TIME * 2, delay + self.LV_DEMO_PRINTER_ANIM_TIME + 50) icon.set_event_cb(self.print_open_event_cb) icon = self.add_icon(box, self.img_btn_bg_4_dsc, self.img_setup_dsc, "SETUP") icon.align(None, lv.ALIGN.IN_LEFT_MID, 7 * (box_w - 20) // 8 - 80, 0) icon.fade_in(self.LV_DEMO_PRINTER_ANIM_TIME * 2, delay + self.LV_DEMO_PRINTER_ANIM_TIME + 50) icon.set_event_cb(self.setup_icon_event_cb) box = lv.obj(lv.scr_act(), None) box.set_size(500, 80) box.align(None, lv.ALIGN.IN_BOTTOM_LEFT, self.LV_HOR_RES // 20, -self.LV_HOR_RES // 40) label = lv.label(box, None) label.set_text("What do you want to do today?") self.theme.apply(label, lv.THEME.LABEL) label.align(box, lv.ALIGN.CENTER, 0, 0) delay += self.LV_DEMO_PRINTER_ANIM_DELAY self.anim_in(box, delay) box = lv.obj(lv.scr_act(), None) box_w = 200 box.set_size(box_w, 80) box.align(None, lv.ALIGN.IN_BOTTOM_RIGHT, -self.LV_HOR_RES // 20, -self.LV_HOR_RES // 40) bar = lv.bar(box, None) bar.set_style_local_bg_color(lv.bar.PART.INDIC, lv.STATE.DEFAULT, lv.color_hex(0x01d3d4)) bar.set_size(25, 50) bar.align(None, lv.ALIGN.IN_LEFT_MID, 1 * (box_w - 20) // 8 + 10, 0) bar.set_value(60, lv.ANIM.ON) bar = lv.bar(box, None) bar.set_style_local_bg_color(lv.bar.PART.INDIC, lv.STATE.DEFAULT, lv.color_hex(0xe600e6)) bar.set_size(25, 50) bar.align(None, lv.ALIGN.IN_LEFT_MID, 3 * (box_w - 20) // 8 + 10, 0) bar.set_value(30, lv.ANIM.ON) bar = lv.bar(box, None) bar.set_style_local_bg_color(lv.bar.PART.INDIC, lv.STATE.DEFAULT, lv.color_hex(0xefef01)) bar.set_size(25, 50) bar.align(None, lv.ALIGN.IN_LEFT_MID, 5 * (box_w - 20) // 8 + 10, 0) bar.set_value(80, lv.ANIM.ON) bar = lv.bar(box, None) bar.set_style_local_bg_color(lv.bar.PART.INDIC, lv.STATE.DEFAULT, lv.color_hex(0x1d1d25)) bar.set_size(25, 50) bar.align(None, lv.ALIGN.IN_LEFT_MID, 7 * (box_w - 20) // 8 + 10, 0) bar.set_value(20, lv.ANIM.ON) # # get an icon # def get_icon(self, filename, xres, yres): try: sdl_filename = 'images/' + filename + "_argb8888.bin" self.log.debug('sdl filename: ' + sdl_filename) with open(sdl_filename, 'rb') as f: icon_data = f.read() self.log.debug(sdl_filename + " successfully read") except: self.log.error("Could not find image file: " + filename) return None icon_dsc = lv.img_dsc_t({ "header": { "always_zero": 0, "w": xres, "h": yres, "cf": lv.img.CF.TRUE_COLOR_ALPHA }, "data": icon_data, "data_size": len(icon_data), }) return (icon_data, icon_dsc) def add_title(self, txt): title = lv.label(lv.scr_act(), None) self.theme.apply(title, LV_DEMO_PRINTER_THEME_TITLE) title.set_text(txt) title.align(None, lv.ALIGN.IN_TOP_MID, 0, LV_DEMO_PRINTER_TITLE_PAD) return title def add_icon(self, parent, src_bg_dsc, src_icon_dsc, txt): bg = lv.img(parent, None) bg.set_click(True) bg.set_src(src_bg_dsc) self.theme.apply(bg, LV_DEMO_PRINTER_THEME_ICON) bg.set_antialias(False) icon = lv.img(bg, None) icon.set_src(src_icon_dsc) icon.set_style_local_image_recolor_opa(lv.img.PART.MAIN, lv.STATE.DEFAULT, lv.OPA.TRANSP) icon.align(None, lv.ALIGN.IN_TOP_RIGHT, -30, 30) label = lv.label(bg, None) label.set_text(txt) label.align(None, lv.ALIGN.IN_BOTTOM_LEFT, 30, -30) self.theme.apply(label, lv.THEME.LABEL) return bg def copy_open_icon_event_cb(self, obj, evt): if evt == lv.EVENT.CLICKED: self.anim_out_all(lv.scr_act(), 0) self.log.debug("copy_open_icon_event_cb") self.scan_btn_txt = "NEXT" delay = 200 self.anim_bg(150, LV_DEMO_PRINTER_BLUE, self.LV_DEMO_PRINTER_BG_FULL) arc = self.add_loader(self.scan_anim_ready) arc.align(None, lv.ALIGN.CENTER, 0, -40) txt = lv.label(lv.scr_act(), None) txt.set_text("Scanning, please wait...") self.theme.apply(txt, LV_DEMO_PRINTER_THEME_LABEL_WHITE) txt.align(arc, lv.ALIGN.OUT_BOTTOM_MID, 0, 60) self.anim_in(arc, delay) delay += self.LV_DEMO_PRINTER_ANIM_DELAY self.anim_in(txt, delay) self.icon_generic_event_cb(obj, evt) def scan_open_icon_event_cb(self, obj, evt): if evt == lv.EVENT.CLICKED: self.log.debug("scan_open_icon_event_cb") self.scan_btn_txt = "SAVE" self.anim_out_all(lv.scr_act(), 0) delay = 200 self.anim_bg(150, LV_DEMO_PRINTER_BLUE, self.LV_DEMO_PRINTER_BG_FULL) arc = self.add_loader(self.scan_anim_ready) arc.align(None, lv.ALIGN.CENTER, 0, -40) txt = lv.label(lv.scr_act(), None) txt.set_text("Scanning, please wait...") self.theme.apply(txt, LV_DEMO_PRINTER_THEME_LABEL_WHITE) txt.align(arc, lv.ALIGN.OUT_BOTTOM_MID, 0, 60) self.anim_in(arc, delay) delay += self.LV_DEMO_PRINTER_ANIM_DELAY self.anim_in(txt, delay) def print_open_event_cb(self, obj, evt): if evt == lv.EVENT.CLICKED: self.anim_out_all(lv.scr_act(), 0) self.print_open(200) self.icon_generic_event_cb(obj, evt) def print_open(self, delay): back = self.add_back(self.back_to_home_event_cb) self.anim_in(back, delay) title = self.add_title("PRINT MENU") box_w = 720 box = lv.obj(lv.scr_act(), None) box.set_size(box_w, 260) box.align(None, lv.ALIGN.IN_TOP_MID, 0, 100) delay += self.LV_DEMO_PRINTER_ANIM_DELAY self.anim_in(box, delay) icon = self.add_icon(box, self.img_btn_bg_2_dsc, self.img_usb_dsc, "USB") icon.align(None, lv.ALIGN.IN_LEFT_MID, 1 * box_w // 7 - 40, 0) icon.set_event_cb(self.usb_icon_event_cb) icon.fade_in(self.LV_DEMO_PRINTER_ANIM_TIME * 2, delay + self.LV_DEMO_PRINTER_ANIM_TIME + 50) icon = self.add_icon(box, self.img_btn_bg_3_dsc, self.img_mobile_dsc, "MOBILE") icon.align(None, lv.ALIGN.IN_LEFT_MID, 3 * box_w // 7 - 40, 0) icon.set_event_cb(self.mobile_icon_event_cb) icon.fade_in(self.LV_DEMO_PRINTER_ANIM_TIME * 2, delay + self.LV_DEMO_PRINTER_ANIM_TIME + 50) icon = self.add_icon(box, self.img_btn_bg_4_dsc, self.img_internet_dsc, "INTERNET") icon.align(None, lv.ALIGN.IN_LEFT_MID, 5 * box_w // 7 - 40, 0) icon.set_event_cb(self.internet_icon_event_cb) icon.fade_in(self.LV_DEMO_PRINTER_ANIM_TIME * 2, delay + self.LV_DEMO_PRINTER_ANIM_TIME + 50) box = lv.obj(lv.scr_act(), None) box.set_size(box_w, 80) box.align(None, lv.ALIGN.IN_BOTTOM_LEFT, self.LV_HOR_RES // 20, -self.LV_HOR_RES // 40) label = lv.label(box, None) self.theme.apply(label, lv.THEME.LABEL) label.set_text("From where do you want to print?") label.align(box, lv.ALIGN.CENTER, 0, 0) delay += self.LV_DEMO_PRINTER_ANIM_DELAY self.anim_in(box, delay) self.anim_bg(0, LV_DEMO_PRINTER_BLUE, self.LV_DEMO_PRINTER_BG_NORMAL) def icon_generic_event_cb(self, obj, evt): if evt == lv.EVENT.PRESSED: img = obj.get_child_back(None) txt = obj.get_child(None) self.log.debug("icon_generic_event") a = lv.anim_t() a.init() a.set_time(100) a.set_var(img) a.set_custom_exec_cb(lambda a, val: self.set_x(img, val)) # a.set_custom_exec_cb(lv_obj_set_x) a.set_values(img.get_x(), obj.get_width() - img.get_width() - 35) lv.anim_t.start(a) # a.set_custom_exec_cb(&a, (lv_anim_exec_xcb_t)lv_obj_set_y); a.set_custom_exec_cb(lambda a, val: self.set_y(img, val)) a.set_values(img.get_y(), 35) lv.anim_t.start(a) a.set_var(txt) a.set_custom_exec_cb(lambda a, val: self.set_x(txt, val)) a.set_values(txt.get_x(), 35) lv.anim_t.start(a) a.set_custom_exec_cb(lambda a, val: self.set_y(txt, val)) a.set_values(txt.get_y(), obj.get_height() - txt.get_height() - 35) lv.anim_t.start(a) def setup_icon_event_cb(self, obj, evt): if evt == lv.EVENT.CLICKED: self.log.debug("setup_icon_event_cb") self.anim_out_all(lv.scr_act(), 0) self.anim_bg(0, LV_DEMO_PRINTER_RED, self.LV_DEMO_PRINTER_BG_FULL) delay = 200 img = lv.img(lv.scr_act(), None) img.set_src(self.img_printer2_dsc) img.align(None, lv.ALIGN.CENTER, -90, 0) self.anim_in(img, delay) delay += self.LV_DEMO_PRINTER_ANIM_DELAY img = lv.img(lv.scr_act(), None) img.set_src(self.img_no_internet_dsc) img.align(None, lv.ALIGN.CENTER, 0, -40) self.anim_in(img, delay) delay += self.LV_DEMO_PRINTER_ANIM_DELAY img = lv.img(lv.scr_act(), None) img.set_src(self.img_cloud_dsc) img.align(None, lv.ALIGN.CENTER, 80, -80) self.anim_in(img, delay) delay += self.LV_DEMO_PRINTER_ANIM_DELAY self.info_bottom_create( "You have no permission to change the settings.", "BACK", self.back_to_home_event_cb, delay) def add_loader(self, end_cb): arc = lv.arc(lv.scr_act(), None) arc.set_bg_angles(0, 0) arc.set_start_angle(270) arc.set_size(220, 220) self.theme.apply(arc, lv.THEME.ARC) self.log.debug("Starting loader anim") a = lv.anim_t() a.init() a.set_custom_exec_cb(lambda a, val: self.loader_anim_cb(a, arc, val)) a.set_values(0, 110) a.set_time(2000) a.set_ready_cb(end_cb) lv.anim_t.start(a) return arc def loader_anim_cb(self, a, arc, v): # self.log.debug("loader_anim_cb called with value: %d"%v) if v > 100: v = 100 arc.set_end_angle(v * 360 // 100 + 270) percent_txt = "%d %%" % v arc.set_style_local_value_str(lv.arc.PART.BG, lv.STATE.DEFAULT, percent_txt) def anim_in(self, obj, delay): a = lv.anim_t() a.init() a.set_var(obj) a.set_time(self.LV_DEMO_PRINTER_ANIM_TIME) a.set_delay(delay) # a.set_exec_cb(obj.set_y) # a.set_values(obj.get_y() - self.LV_DEMO_PRINTER_ANIM_Y, obj.get_y()) # a.start() obj.fade_in(self.LV_DEMO_PRINTER_ANIM_TIME - 50, delay) def anim_out_all(self, obj, delay): self.log.debug("anim_out_all") child = obj.get_child_back(None) while child: if child != self.scan_img and child != self.bg_top and child != self.bg_bottom and child != lv.scr_act( ): a = lv.anim_t() a.init() a.set_var(child) a.set_time(self.LV_DEMO_PRINTER_ANIM_TIME) # a.set_exec_cb(lambda y: lv.obj.set_y(y)) if child.get_y() < 80: a.set_values(child.get_y(), child.get_y() - self.LV_DEMO_PRINTER_ANIM_Y) else: a.set_values(child.get_y(), child.get_y() + self.LV_DEMO_PRINTER_ANIM_Y) delay += self.LV_DEMO_PRINTER_ANIM_DELAY a.set_ready_cb(lv.obj.del_anim_ready_cb) lv.anim_t.start(a) child = obj.get_child_back(child) def scan_anim_ready(self, a): self.log.debug("scan_anim_ready") self.anim_out_all(lv.scr_act(), 0) self.scan1_open(self.scan_btn_txt) def scan1_open(self, btn_txt): self.log.debug("scan1_open " + btn_txt) self.anim_out_all(lv.scr_act(), 0) self.anim_bg(0, LV_DEMO_PRINTER_BLUE, self.LV_DEMO_PRINTER_BG_NORMAL) delay = 200 back = self.add_back(self.back_to_home_event_cb) title = self.add_title("ADJUST IMAGE") self.scan_img = lv.img(lv.scr_act(), None) self.scan_img.set_src(self.scan_example_dsc) self.scan_img.align(None, lv.ALIGN.IN_TOP_LEFT, 40, 100) self.scan_img.set_style_local_radius(lv.img.PART.MAIN, lv.STATE.DEFAULT, 10) self.scan_img.set_style_local_clip_corner(lv.img.PART.MAIN, lv.STATE.DEFAULT, True) self.scan_img.set_style_local_image_recolor_opa( lv.img.PART.MAIN, lv.STATE.DEFAULT, 80) box_w = 160 settings_box = lv.obj(lv.scr_act(), None) settings_box.set_size(box_w, 245) settings_box.align(self.scan_img, lv.ALIGN.OUT_RIGHT_TOP, 40, 0) self.lightness_act = 0 self.hue_act = 180 slider = lv.slider(settings_box, None) slider.set_size(8, 160) slider.align(None, lv.ALIGN.IN_TOP_MID, -35, 65) slider.set_event_cb(self.lightness_slider_event_cb) slider.set_range(-80, 80) slider.set_value(0, lv.ANIM.OFF) slider.set_ext_click_area(30, 30, 30, 30) self.theme.apply(slider, lv.THEME.SLIDER) icon = lv.img(settings_box, None) icon.set_src(self.icon_bright_dsc) icon.align(slider, lv.ALIGN.OUT_TOP_MID, 0, -30) slider = lv.slider(settings_box, slider) slider.align(None, lv.ALIGN.IN_TOP_MID, 35, 65) slider.set_event_cb(self.hue_slider_event_cb) slider.set_range(0, 359) slider.set_value(180, lv.ANIM.OFF) self.theme.apply(slider, lv.THEME.SLIDER) icon = lv.img(settings_box, None) icon.set_src(self.icon_hue_dsc) icon.align(slider, lv.ALIGN.OUT_TOP_MID, 0, -30) self.scan_img_color_refr() next_btn = lv.btn(lv.scr_act(), None) self.theme.apply(next_btn, LV_DEMO_PRINTER_THEME_BTN_CIRCLE) next_btn.set_size(box_w, 60) next_btn.align(self.scan_img, lv.ALIGN.OUT_RIGHT_BOTTOM, 40, 0) if btn_txt == "NEXT": next_btn.set_event_cb(self.scan_next_event_cb) next_btn.set_style_local_value_str(lv.obj.PART.MAIN, lv.STATE.DEFAULT, "NEXT") next_btn.set_style_local_value_font(lv.obj.PART.MAIN, lv.STATE.DEFAULT, self.theme.get_font_subtitle()) elif btn_txt == "SAVE": next_btn.set_event_cb(self.scan_save_event_cb) next_btn.set_style_local_value_str(lv.obj.PART.MAIN, lv.STATE.DEFAULT, "SAVE") next_btn.set_style_local_value_font(lv.obj.PART.MAIN, lv.STATE.DEFAULT, self.theme.get_font_subtitle()) next_btn.set_style_local_bg_color(lv.obj.PART.MAIN, lv.STATE.DEFAULT, LV_DEMO_PRINTER_GREEN) next_btn.set_style_local_bg_color( lv.obj.PART.MAIN, lv.STATE.PRESSED, LV_DEMO_PRINTER_GREEN.color_darken(lv.OPA._20)) def scan_save_event_cb(self, obj, evt): if evt == lv.EVENT.CLICKED: self.scan_img = None self.anim_out_all(lv.scr_act(), 0) self.anim_bg(0, LV_DEMO_PRINTER_GREEN, self.LV_DEMO_PRINTER_BG_FULL) delay = 200 img = lv.img(lv.scr_act(), None) img.set_src(self.img_ready_dsc) img.align(None, lv.ALIGN.CENTER, 0, -40) delay += self.LV_DEMO_PRINTER_ANIM_DELAY self.anim_in(img, delay) self.info_bottom_create("File saved", "CONTINUE", self.back_to_home_event_cb, delay) def scan_next_event_cb(self, obj, evt): LV_IMG_ZOOM_NONE = 250 if evt == lv.EVENT.CLICKED: self.anim_out_all(lv.scr_act(), 0) delay = 400 back = self.add_back(self.back_to_home_event_cb) self.anim_in(back, delay) title = self.add_title("ADJUST IMAGE") self.anim_in(title, delay) box_w = 400 self.scan_img.set_pivot(0, 0) self.scan_img.set_antialias(False) a = lv.anim_t() a.init() a.set_var(self.scan_img) a.set_custom_exec_cb( lambda a, val: self.set_zoom(self.scan_img, val)) a.set_values(LV_IMG_ZOOM_NONE, 190) a.set_time(200) a.set_delay(200) lv.anim_t.start(a) # self.scan_img = None # To allow anim out dropdown_box = lv.obj(lv.scr_act(), None) dropdown_box.set_size(box_w, self.LV_VER_RES // 5) dropdown_box.align(None, lv.ALIGN.IN_BOTTOM_LEFT, 40, -20) dropdown = lv.dropdown(dropdown_box, None) dropdown.align(None, lv.ALIGN.IN_LEFT_MID, self.LV_HOR_RES // 60, 0) dropdown.set_max_height(self.LV_VER_RES // 3) dropdown.set_options_static("Best\nNormal\nDraft") dropdown.set_width((box_w - 3 * self.LV_HOR_RES // 60) // 2) self.theme.apply(dropdown, lv.THEME.DROPDOWN) dropdown = lv.dropdown(dropdown_box, dropdown) dropdown.align(None, lv.ALIGN.IN_RIGHT_MID, -self.LV_HOR_RES // 60, 0) dropdown.set_options_static( "72 DPI\n96 DPI\n150 DPI\n300 DPI\n600 DPI\n900 DPI\n1200 DPI") self.theme.apply(dropdown, lv.THEME.DROPDOWN) box_w = 320 - 40 settings_box = lv.obj(lv.scr_act(), None) settings_box.set_size(box_w, self.LV_VER_RES // 2) settings_box.align(None, lv.ALIGN.IN_TOP_RIGHT, -40, 100) numbox = lv.cont(settings_box, None) self.theme.apply(numbox, LV_DEMO_PRINTER_THEME_BOX_BORDER) numbox.set_size(self.LV_HOR_RES // 7, self.LV_HOR_RES // 13) numbox.align(settings_box, lv.ALIGN.IN_TOP_MID, 0, self.LV_VER_RES // 10) numbox.set_style_local_value_str(lv.obj.PART.MAIN, lv.STATE.DEFAULT, "Copies") numbox.set_style_local_value_align(lv.obj.PART.MAIN, lv.STATE.DEFAULT, lv.ALIGN.OUT_TOP_MID) numbox.set_style_local_value_ofs_y(lv.obj.PART.MAIN, lv.STATE.DEFAULT, -self.LV_VER_RES // 50) numbox.set_style_local_value_font(lv.obj.PART.MAIN, lv.STATE.DEFAULT, self.theme.get_font_subtitle()) numbox.set_layout(lv.LAYOUT.CENTER) self.print_cnt = 1 self.print_cnt_label = lv.label(numbox, None) self.print_cnt_label.set_text("1") self.print_cnt_label.set_style_local_text_font( lv.label.PART.MAIN, lv.STATE.DEFAULT, self.theme.get_font_subtitle()) btn = lv.btn(settings_box, None) btn.set_size(self.LV_HOR_RES // 13, self.LV_HOR_RES // 13) btn.align(numbox, lv.ALIGN.OUT_LEFT_MID, -self.LV_VER_RES // 60, 0) btn.set_style_local_value_str(lv.obj.PART.MAIN, lv.STATE.DEFAULT, lv.SYMBOL.DOWN) btn.set_style_local_value_font(lv.obj.PART.MAIN, lv.STATE.DEFAULT, self.theme.get_font_subtitle()) btn.set_event_cb(self.print_cnt_btn_event_cb) btn.set_ext_click_area(10, 10, 10, 10) self.theme.apply(btn, lv.THEME.BTN) sw = lv.switch(settings_box, None) sw.set_size(self.LV_HOR_RES // 10, self.LV_VER_RES // 12) sw.align(btn, lv.ALIGN.OUT_BOTTOM_LEFT, self.LV_HOR_RES // 50, self.LV_VER_RES // 7) sw.set_style_local_value_ofs_y(lv.obj.PART.MAIN, lv.STATE.DEFAULT, -self.LV_VER_RES // 50) sw.set_style_local_value_align(lv.obj.PART.MAIN, lv.STATE.DEFAULT, lv.ALIGN.OUT_TOP_MID) sw.set_style_local_value_str(lv.obj.PART.MAIN, lv.STATE.DEFAULT, "Color") sw.set_style_local_value_font(lv.obj.PART.MAIN, lv.STATE.DEFAULT, self.theme.get_font_subtitle()) self.theme.apply(sw, lv.THEME.SWITCH) btn = lv.btn(settings_box, btn) btn.align(numbox, lv.ALIGN.OUT_RIGHT_MID, self.LV_VER_RES // 60, 0) btn.set_style_local_value_str(lv.obj.PART.MAIN, lv.STATE.DEFAULT, lv.SYMBOL.UP) btn.set_event_cb(self.print_cnt_btn_event_cb) self.theme.apply(btn, lv.THEME.BTN) sw = lv.switch(settings_box, sw) sw.align(btn, lv.ALIGN.OUT_BOTTOM_RIGHT, -self.LV_HOR_RES // 50, self.LV_VER_RES // 7) sw.set_style_local_value_str(lv.obj.PART.MAIN, lv.STATE.DEFAULT, "Vertical") print_btn = lv.btn(lv.scr_act(), None) self.theme.apply(print_btn, LV_DEMO_PRINTER_THEME_BTN_CIRCLE) print_btn.set_size(box_w, 60) print_btn.set_event_cb(self.print_start_event_cb) btn_ofs_y = (dropdown_box.get_height() - print_btn.get_height()) // 2 print_btn.align(settings_box, lv.ALIGN.OUT_BOTTOM_MID, 0, self.LV_HOR_RES // 30 + btn_ofs_y) print_btn.set_style_local_value_str(lv.obj.PART.MAIN, lv.STATE.DEFAULT, "PRINT") print_btn.set_style_local_value_font( lv.obj.PART.MAIN, lv.STATE.DEFAULT, self.theme.get_font_subtitle()) print_btn.set_style_local_bg_color(lv.obj.PART.MAIN, lv.STATE.DEFAULT, LV_DEMO_PRINTER_GREEN) print_btn.set_style_local_bg_color( lv.obj.PART.MAIN, lv.STATE.PRESSED, LV_DEMO_PRINTER_GREEN.color_darken(lv.OPA._20)) delay += self.LV_DEMO_PRINTER_ANIM_DELAY self.anim_in(settings_box, delay) delay += self.LV_DEMO_PRINTER_ANIM_DELAY self.anim_in(dropdown_box, delay) delay += self.LV_DEMO_PRINTER_ANIM_DELAY self.anim_in(print_btn, delay) self.anim_bg(0, LV_DEMO_PRINTER_BLUE, self.LV_DEMO_PRINTER_BG_NORMAL) def anim_bg(self, delay, color, y_new): self.log.debug("anim_bg: new y: %d" % y_new) y_act = self.bg_top.get_y() act_color = self.bg_top.get_style_bg_color(lv.obj.PART.MAIN) self.log.debug("current y: %d" % y_act) if y_new != self.LV_DEMO_PRINTER_BG_NORMAL and y_new == y_act and act_color.full == color.full: return if (y_new == self.LV_DEMO_PRINTER_BG_NORMAL and y_new == y_act) or \ (y_new == self.LV_DEMO_PRINTER_BG_NORMAL and y_act == self.LV_DEMO_PRINTER_BG_FULL): path = lv.anim_path_t() path.init() path.set_cb(self.triangle_path_cb) a = lv.anim_t() a.set_var(self.bg_top) a.set_time(self.LV_DEMO_PRINTER_ANIM_TIME_BG + 200) a.set_delay(delay) a.set_custom_exec_cb(lambda a, val: self.set_y(self.bg_top, val)) a.set_values(y_act, y_new) a.set_path(path) lv.anim_t.start(a) else: a = lv.anim_t() a.set_var(self.bg_top) a.set_time(self.LV_DEMO_PRINTER_ANIM_TIME_BG) a.set_delay(delay) a.set_custom_exec_cb(lambda a, val: self.set_y(self.bg_top, val)) a.set_values(self.bg_top.get_y(), y_new) lv.anim_t.start(a) color_anim = lv.anim_t() self.bg_color_prev = self.bg_color_act self.bg_color_act = color color_anim.set_custom_exec_cb( lambda color_anim, val: self.anim_bg_color_cb(val)) color_anim.set_values(0, 255) color_anim.set_time(self.LV_DEMO_PRINTER_ANIM_TIME_BG) path = lv.anim_path_t() path.init() path.set_cb(lv.anim_path_t.linear) # a.set_path(lv.anim_t.path_def) lv.anim_t.start(color_anim) def triangle_path_cb(self, path, a): if a.time == a.act_time: return a.end if a.act_time < a.time // 2: step = a.act_time * 1024 // (a.time // 2) new_value = step * self.LV_DEMO_PRINTER_BG_SMALL - a.start new_value >>= 10 new_value += a.start self.log.debug("triangle: new value: %d" % new_value) return new_value else: t = a.act_time - a.time // 2 step = a.act_time * 1024 // (a.time // 2) new_value = step * (a.end - self.LV_DEMO_PRINTER_BG_SMALL) new_value >>= 10 new_value += self.LV_DEMO_PRINTER_BG_SMALL self.log.debug("triangle: new value: %d" % new_value) return new_value def set_y(self, obj, new_y): self.log.debug("Setting y to %d" % new_y) obj.set_y(new_y) def set_x(self, obj, new_x): self.log.debug("Setting x to %d" % new_x) obj.set_x(new_x) def set_zoom(self, obj, new_size): self.log.debug("Setting zoom to %d" % new_size) obj.set_zoom(new_size) def anim_bg_color_cb(self, v): self.log.debug("anim_bg_color_cb: Mixing colors with value: %d" % v) c = self.bg_color_act.color_mix(self.bg_color_prev, v) self.bg_top.set_style_local_bg_color(lv.obj.PART.MAIN, lv.STATE.DEFAULT, c) def info_bottom_create(self, label_txt, btn_txt, btn_event_cb, delay): LV_DEMO_PRINTER_BTN_W = 200 LV_DEMO_PRINTER_BTN_H = 50 txt = lv.label(lv.scr_act(), None) txt.set_text(label_txt) self.theme.apply(txt, LV_DEMO_PRINTER_THEME_LABEL_WHITE) txt.align(None, lv.ALIGN.CENTER, 0, 100) btn = lv.btn(lv.scr_act(), None) self.theme.apply(btn, LV_DEMO_PRINTER_THEME_BTN_BORDER) btn.set_size(LV_DEMO_PRINTER_BTN_W, LV_DEMO_PRINTER_BTN_H) btn.align(txt, lv.ALIGN.OUT_BOTTOM_MID, 0, 60) btn.set_style_local_value_str(lv.btn.PART.MAIN, lv.STATE.DEFAULT, btn_txt) btn.set_style_local_value_font(lv.btn.PART.MAIN, lv.STATE.DEFAULT, self.theme.get_font_normal()) btn.set_event_cb(btn_event_cb) self.anim_in(txt, delay) delay += self.LV_DEMO_PRINTER_ANIM_DELAY self.anim_in(btn, delay) delay += self.LV_DEMO_PRINTER_ANIM_DELAY self.anim_in(btn, delay) def back_to_home_event_cb(self, obj, evt): if evt == lv.EVENT.CLICKED: self.scan_img = None self.anim_out_all(lv.scr_act(), 0) self.home_open(200) pass def add_back(self, event_cb): btn = lv.btn(lv.scr_act(), None) self.theme.apply(btn, LV_DEMO_PRINTER_THEME_BTN_BACK) btn.set_size(80, 80) btn.set_pos(30, 10) btn.set_event_cb(event_cb) return btn def lightness_slider_event_cb(self, obj, evt): if evt == lv.EVENT.VALUE_CHANGED: self.lightness_act = obj.get_value() self.log.debug("lightness_slider_event: new slider value: %d" % self.lightness_act) self.scan_img_color_refr() def hue_slider_event_cb(self, obj, evt): if evt == lv.EVENT.VALUE_CHANGED: self.hue_act = obj.get_value() self.log.debug("hue_slider_event: new slider value: %d" % self.hue_act) self.scan_img_color_refr() def scan_img_color_refr(self): if self.lightness_act > 0: s = 100 - self.lightness_act v = 100 else: s = 100 v = 100 + self.lightness_act self.log.debug("scan_img_color_refr: hue, s, v: %d %d %d" % (self.hue_act, s, v)) c = lv.color_hsv_to_rgb(self.hue_act, s, v) self.scan_img.set_style_local_image_recolor(lv.img.PART.MAIN, lv.STATE.DEFAULT, c) def internet_icon_event_cb(self, obj, evt): if evt == lv.EVENT.CLICKED: self.anim_out_all(lv.scr_act(), 0) self.anim_bg(0, LV_DEMO_PRINTER_RED, self.LV_DEMO_PRINTER_BG_FULL) delay = 200 img = lv.img(lv.scr_act(), None) img.set_src(self.img_printer2_dsc) img.align(None, lv.ALIGN.CENTER, -90, 0) self.anim_in(img, delay) delay += self.LV_DEMO_PRINTER_ANIM_DELAY img = lv.img(lv.scr_act(), None) img.set_src(self.img_no_internet_dsc) img.align(None, lv.ALIGN.CENTER, 0, -40) self.anim_in(img, delay) delay += self.LV_DEMO_PRINTER_ANIM_DELAY img = lv.img(lv.scr_act(), None) img.set_src(self.img_cloud_dsc) img.align(None, lv.ALIGN.CENTER, 80, -80) self.anim_in(img, delay) delay += self.LV_DEMO_PRINTER_ANIM_DELAY self.info_bottom_create("No internet connection", "BACK", self.back_to_print_event_cb, delay) self.icon_generic_event_cb(obj, evt) def mobile_icon_event_cb(self, obj, evt): if evt == lv.EVENT.CLICKED: self.anim_out_all(lv.scr_act(), 0) self.anim_bg(0, LV_DEMO_PRINTER_BLUE, self.LV_DEMO_PRINTER_BG_FULL) delay = 200 img = lv.img(lv.scr_act(), None) img.set_src(self.img_printer2_dsc) img.align(None, lv.ALIGN.CENTER, -90, 0) self.anim_in(img, delay) delay += self.LV_DEMO_PRINTER_ANIM_DELAY img = lv.img(lv.scr_act(), None) img.set_src(self.img_wave_dsc) img.align(None, lv.ALIGN.CENTER, 0, 0) self.anim_in(img, delay) delay += self.LV_DEMO_PRINTER_ANIM_DELAY img = lv.img(lv.scr_act(), None) img.set_src(self.img_phone_dsc) img.align(None, lv.ALIGN.CENTER, 80, 0) self.anim_in(img, delay) delay += self.LV_DEMO_PRINTER_ANIM_DELAY self.info_bottom_create("Put you phone near to the printer", "BACK", self.back_to_print_event_cb, delay) self.icon_generic_event_cb(obj, evt) def usb_icon_event_cb(self, obj, evt): if evt == lv.EVENT.CLICKED: self.anim_out_all(lv.scr_act(), 0) delay = 200 back = self.add_back(self.back_to_print_event_cb) self.anim_in(back, delay) title = self.add_title("PRINTING FROM USB DRIVE") self.anim_in(title, delay) box_w = self.LV_HOR_RES * 5 // 10 list = lv.list(lv.scr_act(), None) list.set_size(box_w, self.LV_VER_RES // 2) list.align(None, lv.ALIGN.IN_TOP_LEFT, self.LV_HOR_RES // 20, self.LV_VER_RES // 5) dummy_file_list = [ "Contract 12.pdf", "Scanned_05_21.pdf", "Photo_132210.jpg", "Photo_232141.jpg", "Photo_091640.jpg", "Photo_124019.jpg", "Photo_232032.jpg", "Photo_232033.jpg", "Photo_232034.jpg", "Monday schedule.pdf", "Email from John.txt", "New file.txt", "Untitled.txt", "Untitled (1).txt", "Gallery_40.jpg", "Gallery_41.jpg", "Gallery_42.jpg", "Gallery_43.jpg", "Gallery_44.jpg" ] for filename in dummy_file_list: btn = lv.btn.__cast__(list.add_btn(lv.SYMBOL.FILE, filename)) btn.set_checkable(True) self.theme.apply(btn, lv.THEME.LIST_BTN) dropdown_box = lv.obj(lv.scr_act(), None) dropdown_box.set_size(box_w, self.LV_VER_RES // 5) dropdown_box.align(list, lv.ALIGN.OUT_BOTTOM_MID, 0, self.LV_HOR_RES // 30) dropdown = lv.dropdown(dropdown_box, None) dropdown.align(None, lv.ALIGN.IN_LEFT_MID, self.LV_HOR_RES // 60, 0) dropdown.set_max_height(self.LV_VER_RES // 3) dropdown.set_options_static("Best\nNormal\nDraft") dropdown.set_width((box_w - 3 * self.LV_HOR_RES // 60) // 2) dropdown.set_ext_click_area(5, 5, 5, 5) self.theme.apply(dropdown, lv.THEME.DROPDOWN) dropdown = lv.dropdown(dropdown_box, dropdown) dropdown.align(None, lv.ALIGN.IN_RIGHT_MID, -self.LV_HOR_RES // 60, 0) # dropdown.set_options_static("100 DPI\n200 DPI\n300 DPI\n400 DPI\n500 DPI\n1500 DPI") dropdown.set_options_static("\n".join([ "100 DPI", "200 DPI", "300 DPI", "400 DPI", "500 DPI", "1500 DPI" ])) self.theme.apply(dropdown, lv.THEME.DROPDOWN) box_w = 320 - 40 settings_box = lv.obj(lv.scr_act(), None) settings_box.set_size(box_w, self.LV_VER_RES // 2) settings_box.align(list, lv.ALIGN.OUT_RIGHT_TOP, self.LV_HOR_RES // 20, 0) self.print_cnt = 1 numbox = lv.cont(settings_box, None) self.theme.apply(numbox, LV_DEMO_PRINTER_THEME_BOX_BORDER) numbox.set_size(self.LV_HOR_RES // 7, self.LV_HOR_RES // 13) numbox.align(settings_box, lv.ALIGN.IN_TOP_MID, 0, self.LV_VER_RES // 10) numbox.set_style_local_value_str(lv.obj.PART.MAIN, lv.STATE.DEFAULT, "Copies") numbox.set_style_local_value_align(lv.obj.PART.MAIN, lv.STATE.DEFAULT, lv.ALIGN.OUT_TOP_MID) numbox.set_style_local_value_ofs_y(lv.obj.PART.MAIN, lv.STATE.DEFAULT, -self.LV_VER_RES // 50) numbox.set_style_local_value_font(lv.obj.PART.MAIN, lv.STATE.DEFAULT, self.theme.get_font_subtitle()) numbox.set_layout(lv.LAYOUT.CENTER) self.print_cnt_label = lv.label(numbox, None) self.print_cnt_label.set_text("1") self.print_cnt_label.set_style_local_text_font( lv.label.PART.MAIN, lv.STATE.DEFAULT, self.theme.get_font_subtitle()) btn = lv.btn(settings_box, None) btn.set_size(self.LV_HOR_RES // 13, self.LV_HOR_RES // 13) btn.align(numbox, lv.ALIGN.OUT_LEFT_MID, -self.LV_VER_RES // 60, 0) btn.set_style_local_value_str(lv.obj.PART.MAIN, lv.STATE.DEFAULT, lv.SYMBOL.DOWN) btn.set_style_local_value_font(lv.obj.PART.MAIN, lv.STATE.DEFAULT, self.theme.get_font_subtitle()) btn.set_event_cb(self.print_cnt_btn_event_cb) btn.set_ext_click_area(10, 10, 10, 10) self.theme.apply(btn, lv.THEME.BTN) sw = lv.switch(settings_box, None) sw.set_size(self.LV_HOR_RES // 10, self.LV_VER_RES // 12) sw.align(btn, lv.ALIGN.OUT_BOTTOM_LEFT, self.LV_HOR_RES // 50, self.LV_VER_RES // 7) sw.set_style_local_value_ofs_y(lv.obj.PART.MAIN, lv.STATE.DEFAULT, -self.LV_VER_RES // 50) sw.set_style_local_value_align(lv.obj.PART.MAIN, lv.STATE.DEFAULT, lv.ALIGN.OUT_TOP_MID) sw.set_style_local_value_str(lv.obj.PART.MAIN, lv.STATE.DEFAULT, "Color") sw.set_style_local_value_font(lv.obj.PART.MAIN, lv.STATE.DEFAULT, self.theme.get_font_subtitle()) self.theme.apply(sw, lv.THEME.SWITCH) btn = lv.btn(settings_box, btn) btn.align(numbox, lv.ALIGN.OUT_RIGHT_MID, self.LV_VER_RES // 60, 0) btn.set_style_local_value_str(lv.obj.PART.MAIN, lv.STATE.DEFAULT, lv.SYMBOL.UP) btn.set_style_local_value_font(lv.obj.PART.MAIN, lv.STATE.DEFAULT, self.theme.get_font_subtitle()) self.theme.apply(btn, lv.THEME.BTN) btn.set_event_cb(self.print_cnt_btn_event_cb) sw = lv.switch(settings_box, sw) sw.align(btn, lv.ALIGN.OUT_BOTTOM_RIGHT, -self.LV_HOR_RES // 50, self.LV_VER_RES // 7) sw.set_style_local_value_str(lv.obj.PART.MAIN, lv.STATE.DEFAULT, "Vertical") self.theme.apply(sw, lv.THEME.SWITCH) print_btn = lv.btn(lv.scr_act(), None) self.theme.apply(print_btn, LV_DEMO_PRINTER_THEME_BTN_CIRCLE) print_btn.set_size(box_w, 60) btn_ofs_y = (dropdown_box.get_height() - print_btn.get_height()) // 2 print_btn.align(settings_box, lv.ALIGN.OUT_BOTTOM_MID, 0, self.LV_HOR_RES // 30 + btn_ofs_y) print_btn.set_style_local_value_str(lv.obj.PART.MAIN, lv.STATE.DEFAULT, "PRINT") print_btn.set_style_local_value_font( lv.obj.PART.MAIN, lv.STATE.DEFAULT, self.theme.get_font_subtitle()) print_btn.set_style_local_bg_color(lv.obj.PART.MAIN, lv.STATE.DEFAULT, LV_DEMO_PRINTER_GREEN) print_btn.set_style_local_bg_color( lv.obj.PART.MAIN, lv.STATE.PRESSED, LV_DEMO_PRINTER_GREEN.color_darken(lv.OPA._20)) print_btn.set_event_cb(self.print_start_event_cb) delay += self.LV_DEMO_PRINTER_ANIM_DELAY self.anim_in(list, delay) delay += self.LV_DEMO_PRINTER_ANIM_DELAY self.anim_in(settings_box, delay) delay += self.LV_DEMO_PRINTER_ANIM_DELAY self.anim_in(dropdown_box, delay) delay += self.LV_DEMO_PRINTER_ANIM_DELAY self.anim_in(print_btn, delay) self.anim_bg(0, LV_DEMO_PRINTER_BLUE, self.LV_DEMO_PRINTER_BG_NORMAL) def print_cnt_btn_event_cb(self, obj, evt): if evt == lv.EVENT.CLICKED or evt == lv.EVENT.LONG_PRESSED_REPEAT: # if evt == lv.EVENT.CLICKED: txt = obj.get_style_value_str(lv.btn.PART.MAIN) if txt == lv.SYMBOL.DOWN: if self.print_cnt > 1: self.print_cnt -= 1 else: if self.print_cnt < 1000: self.print_cnt += 1 self.print_cnt_label.set_text(str(self.print_cnt)) def print_start_event_cb(self, obj, evt): if evt == lv.EVENT.CLICKED: self.scan_img = None self.anim_out_all(lv.scr_act(), 0) delay = 200 self.anim_bg(150, LV_DEMO_PRINTER_BLUE, self.LV_DEMO_PRINTER_BG_FULL) arc = self.add_loader(lambda a: self.print_start_ready()) arc.align(None, lv.ALIGN.CENTER, 0, -40) txt = lv.label(lv.scr_act(), None) txt.set_text("Printing, please wait...") self.theme.apply(txt, LV_DEMO_PRINTER_THEME_LABEL_WHITE) txt.align(arc, lv.ALIGN.OUT_BOTTOM_MID, 0, 60) self.anim_in(arc, delay) delay += self.LV_DEMO_PRINTER_ANIM_DELAY self.anim_in(txt, delay) def print_start_ready(self): self.anim_bg(0, LV_DEMO_PRINTER_GREEN, self.LV_DEMO_PRINTER_BG_FULL) self.anim_out_all(lv.scr_act(), 0) img = lv.img(lv.scr_act(), None) img.set_src(self.img_ready_dsc) img.align(None, lv.ALIGN.CENTER, 0, -40) delay = 200 self.anim_in(img, delay) delay += self.LV_DEMO_PRINTER_ANIM_DELAY self.info_bottom_create("Printing finished", "CONTINUE", self.back_to_home_event_cb, delay) def back_to_print_event_cb(self, obj, evt): if evt == lv.EVENT.CLICKED: self.anim_out_all(lv.scr_act(), 0) self.print_open(150)
def init_skin( project_name, project_version, skin_name, application_skin_dir, application_theme_dir=None, ): ''' Initialize skin easily. @param project_name: Project name. @param project_version: Project version. @param skin_name: Default skin name. @param application_skin_dir: Application's skin directory in system level, user space skin directory at ~/.config/project_name/skin . @param application_skin_dir: Application's theme directory in system level, user space theme directory at ~/.config/project_name/theme, set as None if don't you just want use theme of deepin-ui. @return: Return application theme, return None if application_theme_dir is None. >>> from dtk.ui.init_skin import init_skin >>> from deepin_utils.file import get_parent_dir >>> import os >>> >>> app_theme = init_skin( >>> "deepin-ui-demo", >>> "1.0", >>> "01", >>> os.path.join(get_parent_dir(__file__), "skin"), >>> os.path.join(get_parent_dir(__file__), "app_theme"), >>> ) Equal to below code: >>> from dtk.ui.skin_config import skin_config >>> from dtk.ui.theme import Theme, ui_theme >>> from deepin_utils.file import get_parent_dir >>> import os >>> >>> # Init skin config. >>> skin_config.init_skin( >>> "01", >>> os.path.join(get_parent_dir(__file__), "skin"), >>> os.path.expanduser("~/.config/deepin-ui-demo/skin"), >>> os.path.expanduser("~/.config/deepin-ui-demo/skin_config.ini"), >>> "deepin-ui-demo", >>> "1.0" >>> ) >>> >>> # Create application theme. >>> app_theme = Theme( >>> os.path.join(get_parent_dir(__file__), "app_theme"), >>> os.path.expanduser("~/.config/deepin-ui-demo/theme") >>> ) >>> >>> # Set theme. >>> skin_config.load_themes(ui_theme, app_theme) ''' # Init skin config. skin_config.init_skin( skin_name, application_skin_dir, os.path.expanduser("~/.config/%s/skin" % (project_name)), os.path.expanduser("~/.config/%s/skin_config.ini" % (project_name)), project_name, project_version, ) # Create application theme. if application_theme_dir != None: app_theme = Theme( application_theme_dir, os.path.expanduser("~/.config/%s/theme" % (project_name))) else: app_theme = None # Set theme. skin_config.load_themes(ui_theme, app_theme) return app_theme
def __init__(self): self.LV_HOR_RES = lv.scr_act().get_disp().driver.hor_res self.LV_VER_RES = lv.scr_act().get_disp().driver.ver_res # Bg positions self.LV_DEMO_PRINTER_BG_NONE = -self.LV_VER_RES self.LV_DEMO_PRINTER_BG_FULL = 0 self.LV_DEMO_PRINTER_BG_NORMAL = -2 * (self.LV_VER_RES // 3) self.LV_DEMO_PRINTER_BG_SMALL = -5 * (self.LV_VER_RES // 6) # Animations self.LV_DEMO_PRINTER_ANIM_Y = self.LV_VER_RES // 20 self.LV_DEMO_PRINTER_ANIM_DELAY = 40 self.LV_DEMO_PRINTER_ANIM_TIME = 150 self.LV_DEMO_PRINTER_ANIM_TIME_BG = 300 self.LV_DEMO_PRINTER_BG_NORMAL = (-2 * (self.LV_VER_RES // 3)) self.log = logging.getLogger("DemoPrinter") self.log.setLevel(logging.ERROR) self.icon_wifi_data = None self.icon_wifi_dsc = None self.icon_tel_data = None self.icon_tel_dsc = None self.icon_eco_data = None self.icon_eco_dsc = None self.icon_pc_data = None self.icon_pc_dsc = None self.img_btn_bg_1_data = None self.img_btn_bg_1_dsc = None self.img_btn_bg_2_data = None self.img_btn_bg_2_dsc = None self.img_btn_bg_3_data = None self.img_btn_bg_3_dsc = None self.img_btn_bg_4_data = None self.img_btn_bg_4_dsc = None self.img_copy_data = None self.img_copy_dsc = None self.img_print_data = None self.img_print_dsc = None self.img_scan_data = None self.img_scan_dsc = None self.img_setup_data = None self.img_setup_dsc = None self.scan_img = None self.bg_top = None self.bg_bottom = None self.bg_color_prev = LV_DEMO_PRINTER_BLUE self.bg_color_act = LV_DEMO_PRINTER_BLUE self.bg_top = lv.obj(lv.scr_act(), None) self.bg_top.set_size(self.LV_HOR_RES, self.LV_VER_RES) # read all the images fromm the raw image files (self.icon_wifi_data, self.icon_wifi_dsc) = self.get_icon("icon_wifi_48x34", 48, 34) (self.icon_tel_data, self.icon_tel_dsc) = self.get_icon("icon_tel_35x35", 35, 35) (self.icon_eco_data, self.icon_eco_dsc) = self.get_icon("icon_eco_38x34", 38, 34) (self.icon_pc_data, self.icon_pc_dsc) = self.get_icon("icon_pc_41x33", 41, 33) (self.icon_bright_data, self.icon_bright_dsc) = self.get_icon("icon_bright_29x29", 29, 29) (self.icon_hue_data, self.icon_hue_dsc) = self.get_icon("icon_hue_23x23", 23, 23) (self.img_btn_bg_1_data, self.img_btn_bg_1_dsc) = self.get_icon("img_btn_bg_1_174x215", 174, 215) (self.img_btn_bg_2_data, self.img_btn_bg_2_dsc) = self.get_icon("img_btn_bg_2_174x215", 174, 215) (self.img_btn_bg_3_data, self.img_btn_bg_3_dsc) = self.get_icon("img_btn_bg_3_174x215", 174, 215) (self.img_btn_bg_4_data, self.img_btn_bg_4_dsc) = self.get_icon("img_btn_bg_4_174x215", 174, 215) (self.img_copy_data, self.img_copy_dsc) = self.get_icon("img_copy_51x60", 51, 60) (self.img_print_data, self.img_print_dsc) = self.get_icon("img_print_65x64", 65, 64) (self.img_scan_data, self.img_scan_dsc) = self.get_icon("img_scan_51x61", 51, 61) (self.img_setup_data, self.img_setup_dsc) = self.get_icon("img_setup_63x64", 63, 64) (self.img_usb_data, self.img_usb_dsc) = self.get_icon("img_usb_62x61", 62, 61) (self.img_internet_data, self.img_internet_dsc) = self.get_icon("img_internet_65x64", 65, 64) (self.img_mobile_data, self.img_mobile_dsc) = self.get_icon("img_mobile_50x60", 50, 60) (self.img_wave_data, self.img_wave_dsc) = self.get_icon("img_wave_27x47", 27, 47) (self.img_phone_data, self.img_phone_dsc) = self.get_icon("img_phone_77x99", 77, 99) (self.img_ready, self.img_ready_dsc) = self.get_icon("img_ready_158x158", 158, 158) (self.img_printer2_data, self.img_printer2_dsc) = self.get_icon("img_printer2_107x104", 107, 104) (self.img_no_internet_data, self.img_no_internet_dsc) = self.get_icon("img_no_internet_42x42", 42, 42) (self.img_cloud_data, self.img_cloud_dsc) = self.get_icon("img_cloud_93x59", 93, 59) (self.scan_example_data, self.scan_example_dsc) = self.get_icon("scan_example_522x340", 522, 340) self.theme = Theme() self.home_open(0)
def _write_theme_file(self): # Write the theme xml file. theme = Theme() theme._set_xml_writer(self._filename('xl/theme/theme1.xml')) theme._assemble_xml_file()
class MyElement (QObject): hasLockChanged = pyqtSignal() hasLoginChanged = pyqtSignal() hasErrorChanged = pyqtSignal() hasRegisterChanged = pyqtSignal() varChanged = pyqtSignal() themeChanged = pyqtSignal() overlayChanged = pyqtSignal() def __init__(self, parent=None): super(MyElement, self).__init__() self.setObjectName('mainObject') self._users = [] self._index = 0 self._myTheme = Theme() self._myColor = self._myTheme.getTheme() self.mainProc = QProcess() self.secondProc = QProcess() self.mainProc.finished.connect(self.finishProc) self.mainProc.started.connect(self.startProc) self.secondProc.finished.connect(self.secondFinishProc) self.secondProc.started.connect(self.startProc) self.auth = Auth() self._isiPesan = "" self._judulPesan = "Error" self._overlay = "" self._isLock = False self._hasRegister = False self._hasLogin = False self._hasError = False self._userListData = UserItemModel() self._userListData.addRootElement() self.addNewUser() @pyqtProperty(bool, notify=hasLockChanged) def isLock(self): return os.path.isfile("/var/ubezee/LOCKED") def finishProc(self, exitCode): if not exitCode: self.setError(True, "Proses Berhasil", "Proses buka/tutup kunci telah berhasil, silakan hidupkan ulang komputer anda untuk mengimplementasikan perubahan.") self._overlay = "" self.hasLockChanged.emit() else: self.setError(True, "Proses Gagal", "Terjadi kesalahan saat akan melakukan proses buka/tutup kunci, silakan coba lagi.") def secondFinishProc(self, exitCode): if not exitCode: self.setError(True, "Proses Berhasil", "Proses buka/tutup kunci pada pengguna telah berhasil, silakan hidupkan ulang komputer anda untuk mengimplementasikan perubahan.") self._overlay = "" h = self._userListData.index(self._index, 0) if self._userListData.itemFromIndex(h).data(5): self._userListData.itemFromIndex(h).setData(False, 5) else: self._userListData.itemFromIndex(h).setData(True, 5) else: self.setError(True, "Proses Gagal", "Terjadi kesalahan saat akan melakukan proses buka/tutup kunci, silakan coba lagi.") def startProc(self): self.setInfo("Harap Tunggu", "Proses buka/tutup pengunci sistem sedang berlangsung, mohon tunggu sebentar...") self.setOverlay("loading") @pyqtSlot(bool) def changeLock(self, todo): if todo: self.mainProc.start("bash locker.sh -l sistem") else: self.mainProc.start("bash locker.sh -u sistem") @pyqtSlot(int, str, bool) def lockUser(self, index, nama, locked): self._index = index if not locked: self.secondProc.start("bash locker.sh -l %s" % nama) else: self.secondProc.start("bash locker.sh -u %s" % nama) @pyqtProperty(bool, notify=hasLoginChanged) def hasLogin(self): return self._hasLogin @pyqtProperty(str, notify=themeChanged) def myColor1(self): return self._myColor[0] @pyqtProperty(str, notify=themeChanged) def myColor2(self): return self._myColor[1] @pyqtSlot(str) def setTheme(self, theme): self._myTheme.setTheme(theme) self.themeChanged.emit() @pyqtProperty(str, notify=varChanged) def isiPesan(self): return self._isiPesan @pyqtSlot(str, str) def setInfo(self, judul,isi): if self._isiPesan != isi: self._isiPesan = isi if self._judulPesan != judul: self._judulPesan = judul self.varChanged.emit() @pyqtProperty(str, notify=varChanged) def judulPesan(self): return self._judulPesan @pyqtProperty(str, notify=varChanged) def getPassword(self): return self.auth.get_password() @pyqtProperty(bool, notify=hasRegisterChanged) def hasRegister(self): return self.auth.check() def setRegister(self, register): if self._hasRegister != register: self._hasRegister = register self.hasRegisterChanged.emit() @pyqtSlot(str, str) def doRegister(self, hint, userPass): if self.auth.set_password(userPass, hint): self.setError(True, "Proses Gagal", "Terjadi kesalahan pada proses pembuatan kata kunci baru.") else: self.setError(True, "Perubahan Berhasil", "Kata kunci anda berhasil dirubah dan disimpan.") self.setRegister(True) def setLogin(self, login): if self._hasLogin != login: self._hasLogin = login self.hasLoginChanged.emit() @pyqtProperty(bool, notify=hasErrorChanged) def hasError(self): return self._hasError @pyqtProperty(str, notify=overlayChanged) def overlay(self): return self._overlay @pyqtSlot(str) def setOverlay(self, overlay): self._overlay = overlay self.overlayChanged.emit() print(self._overlay) @pyqtSlot(bool, str, str) def setError(self, error, judul, isi): if self._hasError != error: self.setInfo(judul, isi) self._hasError = error self.hasErrorChanged.emit() @pyqtProperty(QStandardItemModel, constant=True) def userListData(self): return self._userListData @pyqtSlot(str) def check_pass(self, password): if self.auth.checkAuth(str(password)): self.setLogin(True) self.setOverlay("") else: self.setError(True, "Gagal Masuk", "kata kunci yang anda masukkan salah, silakan coba lagi.") def addNewUser(self): self.getUsers() for i in self._users: user = MyUser(i[0],i[4],i[5]) self._userListData.addUserItem(user.getName(), user.getAvatar(), user.getHome(), user.getRealName(), user.getLock()) def getUsers(self): for users in pwd.getpwall(): if users[2] >= 1000: self._users.append(users)
# -*- coding: UTF-8 -*- import OpenGL from OpenGL import GLU from OpenGL import GL from OpenGL.GL import * from OpenGL.GLU import * from MenuCAIDViewer import MenuCAIDViewer import numpy as np from numpy import sin, pi, cos from theme import theme as Theme theme = Theme() ALPHA = theme.alpha BETA = theme.beta class GLEvaluator(): def __init__(self, nrb): self.nrb = nrb self.glID = gluNewNurbsRenderer() def __del__(self): gluDeleteNurbsRenderer(self.glID) def draw(self): pass
def createFontPanel(self): fcp = wx.Panel(self.book) font = wx.Font(prefs.get('font')) fgcolour = prefs.get('fgcolour') bgcolour = prefs.get('bgcolour') # output sample/controls fcp.sample = ExpandoTextCtrl(fcp, style=wx.TE_READONLY | wx.TE_RICH | wx.TE_MULTILINE, size=wx.Size(400, -1)) fcp.font_ctrl = wx.FontPickerCtrl(fcp, style=wx.FNTP_FONTDESC_AS_LABEL | wx.FNTP_USEFONT_FOR_LABEL, font=font) fcp.theme_picker = wx.Choice(fcp, choices=Theme.all_theme_names()) fcp.ansi_checkbox = wx.CheckBox(fcp, -1, 'Use ANSI colors') fcp.ansi_blink_checkbox = wx.CheckBox(fcp, -1, 'Honor ANSI blink') # TODO - get and set these two at display time not create time fcp.theme = prefs.get('theme') fcp.theme_picker.SetSelection(fcp.theme_picker.FindString(fcp.theme)) if prefs.get('use_ansi'): fcp.ansi_checkbox.SetValue(True) fcp.theme_picker.Enable() else: fcp.ansi_checkbox.SetValue(False) fcp.theme_picker.Disable() ansi_sizer = wx.BoxSizer(wx.HORIZONTAL) ansi_sizer.Add(fcp.ansi_checkbox, 0, wx.ALL | wx.EXPAND | wx.ALIGN_CENTER) ansi_sizer.Add(fcp.ansi_blink_checkbox, 0, wx.ALL | wx.EXPAND | wx.ALIGN_CENTER) ansi_sizer.Add(fcp.theme_picker, 0, wx.ALL | wx.EXPAND | wx.ALIGN_CENTER) panel_sizer = wx.BoxSizer(wx.VERTICAL) panel_sizer.Add(fcp.sample, 0, wx.RIGHT | wx.LEFT | wx.EXPAND | wx.TOP, 10) panel_sizer.AddSpacer(10) panel_sizer.Add(fcp.font_ctrl, 0, wx.EXPAND, 0) panel_sizer.AddSpacer(10) panel_sizer.Add(ansi_sizer, 0, wx.RIGHT | wx.LEFT | wx.EXPAND, 10) self.Bind(wx.EVT_FONTPICKER_CHANGED, self.update_sample_text, fcp.font_ctrl) self.Bind(wx.EVT_CHOICE, self.update_sample_text, fcp.theme_picker) self.Bind(wx.EVT_CHECKBOX, self.update_sample_text, fcp.ansi_checkbox) self.Bind(EVT_ETC_LAYOUT_NEEDED, self.resize_everything, fcp.sample) fcp.SetSizer(panel_sizer) fcp.Layout() return fcp
def parse(self, config, source): """Parse presentation from source stream. Parameters ---------- config : MatisseConfig MaTiSSe configuration source: str """ complete_source = self.parser.includes(source=source) self.__get_metadata(source=complete_source) self.__get_theme(source=complete_source) new_theme = Theme() new_theme.set_from(other=self.theme) tokens = self.parser.tokenize(source=complete_source) self.__check_bad_sectioning(tokens=tokens) chapters_number = 0 sections_number = 0 subsections_number = 0 slides_number = 0 titlepage_inserted = False for chap in tokens['chapters']: chapters_number += 1 slide_local_numbers = [0, 0, 0] if chap['match'].group('expr'): chapter = Chapter(number=chapters_number, title=chap['match'].group('expr')) else: chapter = Chapter(number=chapters_number, title='') for sec in tokens['sections']: if sec['start'] >= chap['start'] and sec['start'] <= chap['end_next']: sections_number += 1 slide_local_numbers[1] = 0 slide_local_numbers[2] = 0 section = Section(number=sections_number, title=sec['match'].group('expr')) for subsec in tokens['subsections']: if subsec['start'] >= sec['start'] and subsec['start'] <= sec['end_next']: subsections_number += 1 slide_local_numbers[2] = 0 subsection = Subsection(number=subsections_number, title=subsec['match'].group('expr')) for sld in tokens['slides']: if '$titlepage' in sld['match'].group().lower() and not titlepage_inserted: slide = Slide(number=0, title='titlepage', contents=complete_source[sld['end']:sld['end_next']]) slide.get_overtheme(parser=self.parser) if slide.overtheme.copy_from_theme is not None and slide.overtheme.copy_from_theme: slide.overtheme.copy_from(other=self.theme) self.position.update_position(presentation_theme=self.theme, overtheme=slide.overtheme) slide.set_position(position=self.position.position) subsection.add_slide(slide=slide) titlepage_inserted = True else: if sld['start'] >= subsec['start'] and sld['start'] <= subsec['end_next']: slide_local_numbers[0] += 1 slide_local_numbers[1] += 1 slide_local_numbers[2] += 1 if slide_local_numbers[0] == 1 and config.toc_at_chap_beginning is not None: slides_number += 1 self.position.update_position(presentation_theme=self.theme) subsection.add_slide(slide=Slide(number=slides_number, position=self.position.position, title='Table of Contents', contents='$toc[depth:' + str(config.toc_at_chap_beginning) + ']')) if slide_local_numbers[1] == 1 and config.toc_at_sec_beginning is not None: slides_number += 1 self.position.update_position(presentation_theme=self.theme) subsection.add_slide(slide=Slide(number=slides_number, position=self.position.position, title='Table of Contents', contents='$toc[depth:' + str(config.toc_at_sec_beginning) + ']')) if slide_local_numbers[2] == 1 and config.toc_at_subsec_beginning is not None: slides_number += 1 self.position.update_position(presentation_theme=self.theme) subsection.add_slide(slide=Slide(number=slides_number, position=self.position.position, title='Table of Contents', contents='$toc[depth:' + str(config.toc_at_subsec_beginning) + ']')) slides_number += 1 slide = Slide(number=slides_number, title=sld['match'].group('expr'), contents=complete_source[sld['end']:sld['end_next']]) slide.get_overtheme(parser=self.parser) if slide.overtheme.copy_from_theme is not None and slide.overtheme.copy_from_theme: slide.overtheme.copy_from(other=self.theme) self.position.update_position(presentation_theme=self.theme, overtheme=slide.overtheme) slide.set_position(position=self.position.position) subsection.add_slide(slide=slide) section.add_subsection(subsection=subsection) chapter.add_section(section=section) self.__add_chapter(chapter=chapter) self.metadata['total_slides_number'].update_value(value=str(Subsection.slides_number))
class OutputPane(BasePane): def __init__(self, parent, connection): BasePane.__init__( self, parent, connection, style=wx.TE_AUTO_URL | wx.TE_READONLY | wx.TE_NOHIDESEL | wx.TE_MULTILINE ) # state toggles for ANSI processing self.intensity = "" self.inverse = False self.theme = Theme() # TODO - this probably should be a preference, but for now, this is the # least-bad default behavior. self.Bind(wx.EVT_SIZE, self.on_size) self.Bind(wx.EVT_SET_FOCUS, self.focus_input) self.Bind(wx.EVT_TEXT_URL, self.process_url_click) self.Bind(wx.EVT_MIDDLE_DOWN, self.connection.input_pane.paste_from_selection) self.Bind(rtc.EVT_RICHTEXT_SELECTION_CHANGED, self.copy_from_selection) self.Bind(EVT_ROW_COL_CHANGED, self.on_row_col_changed) # EVENT HANDLERS ####################### def on_row_col_changed(self, evt): pass # TODO - "if preferences dictate, send @linelength to self.connection" # This updates the widget's internal notion of "how big" it is in characters # it throws an event if the size *in chars* changes, nothing if the change in size was < 1 char def on_size(self, evt): font_width, font_height = self.font_size() self_width, self_height = self.GetSizeTuple() new_cols = math.floor(self_width / font_width) - 2 # "-2" to allow for margins new_rows = math.floor(self_height / font_height) if (new_cols != self.cols) or (new_rows != self.rows): self.cols = new_cols self.rows = new_rows rc_evt = RowColChangeEvent() wx.PostEvent(self, rc_evt) wx.CallAfter(self.ScrollIfAppropriate) evt.Skip() def copy_from_selection(self, evt): uxcp = prefs.get("use_x_copy_paste") == "True" if uxcp and platform == "linux": wx.TheClipboard.UsePrimarySelection(True) self.Copy() if uxcp and platform == "linux": wx.TheClipboard.UsePrimarySelection(False) def process_url_click(self, evt): url = evt.GetString() wx.BeginBusyCursor() if not re.match(r"^https?://", url): url = "http://" + url webbrowser.open(url) wx.EndBusyCursor() def focus_input(self, evt): self.connection.input_pane.SetFocus() ###################################### def WriteText(self, rest): super(OutputPane, self).WriteText(rest) self.ScrollIfAppropriate() def is_at_bottom(self): return True def ScrollIfAppropriate(self): if self.is_at_bottom() or prefs.get("scroll_on_output") == "True": self.ShowPosition(self.GetLastPosition()) self.Refresh() def Thaw(self): super(OutputPane, self).Thaw() self.ScrollIfAppropriate() def display(self, text): self.SetInsertionPointEnd() text = text.decode("latin-1") # TODO - is this the right thing and/or place for this? # self.Freeze() # causing delay on last line - TODO: investigate for line in text.split("\n"): line = line + "\n" if prefs.get("use_mcp") == "True": line = self.connection.mcp.output_filter(line) if not line: continue # output_filter returns falsie if it handled it. # if (True or prefs.get('render_emoji') == 'True'): # TODO - preference? "if (we detect an emoji)?" # line = emoji.emojize(line, use_aliases = True) if prefs.get("use_ansi") == "True": # Dear lord this is sorta ugly # snip and ring bells # TODO -- "if beep is enabled in the prefs" line, count = re.subn("\007", "", line) for b in range(0, count): print("DEBUG: found an ANSI beep") wx.Bell() # chop the line into text, ansi, text, ansi.... bits = re.split("\033\[(\d+(?:;\d+)*)m", line) for idx, bit in enumerate(bits): if bit == "": continue # if it's ansi... if idx % 2: # pick apart the ANSI stuff. codes = [int(c) for c in bit.split(";")] while codes: command, payload = ansi_codes[codes.pop(0)] if command == "control": if payload == "normal": self.EndAllStyles() self.intensity = "" self.inverse = False self.fg_colour = prefs.get("fgcolour") self.bg_colour = prefs.get("bgcolour") self.set_current_colours() elif payload == "bright": self.intensity = "bright" self.set_current_colours() elif payload == "dim": self.intensity = "dim" self.set_current_colours() elif payload == "italic": self.BeginItalic() elif payload == "underline": self.BeginUnderline() elif payload == "blink": print('Got an ANSI "blink"') # TODO - create timer # apply style name # periodically switch foreground color to background elif payload == "inverse": self.inverse = True self.set_current_colours() elif payload == "conceal": print('Got an ANSI "conceal"') elif payload == "strike": font = self.GetFont() font.SetStrikethrough(True) self.BeginFont(font) elif payload == "normal_weight": self.intensity = "" self.set_current_colours() elif payload == "no_italic": self.EndItalic() elif payload == "no_underline": self.EndUnderline() elif payload == "no_blink": print('Got an ANSI "no_blink"') # TODO - remove blink-code-handles style elif payload == "no_conceal": print('Got an ANSI "no_conceal"') elif payload == "no_strike": font = self.GetFont() font.SetStrikethrough(False) self.BeginFont(font) elif payload == "framed": print('Got an ANSI "framed"') elif payload == "encircled": print('Got an ANSI "encircled"') elif payload == "overline": print('Got an ANSI "overline"') elif payload == "no_framed_encircled": print('Got an ANSI "no_framed_encircled"') elif payload == "no_overline": print('Got an ANSI "no_overline"') elif command == "foreground" or command == "background": if payload == "extended": subtype = codes.pop(0) # 24-bit color if subtype == 2: colour = self.theme.rgb_to_hex((codes.pop(0), codes.pop(0), codes.pop(0))) # 256-color elif subtype == 5: colour = self.theme.index256_to_hex(codes.pop(0)) else: print("Got an unknown fg/bg ANSI subtype: " + str(subtype)) else: colour = payload if command == "foreground": self.fg_colour = colour else: self.bg_colour = colour self.set_current_colours() else: print("unknown ANSI command:", command) else: # is a text-only chunk, check for URLs if prefs.get("highlight_urls") == "True": matches = re.split(utility.URL_REGEX, bit) for chunk in matches: if chunk is None: continue if re.match(utility.URL_REGEX, chunk): self.BeginURL(chunk) self.BeginUnderline() current_intensity = self.intensity self.intensity = "normal" self.BeginTextColour(self.lookup_colour("blue")) self.intensity = current_intensity self.WriteText(chunk) self.EndTextColour() self.EndUnderline() self.EndURL() else: self.WriteText(chunk) else: self.WriteText(bit) # self.Thaw() # causing delay on last line - TODO investigate. def foreground_colour(self): return self.theme.Colour(self.fg_colour, self.intensity) def background_colour(self): return self.theme.Colour(self.bg_colour) def lookup_colour(self, color): return self.theme.Colour(color, self.intensity) def set_current_colours(self): current = rtc.RichTextAttr() if self.inverse: current.SetTextColour(self.background_colour()) current.SetBackgroundColour(self.foreground_colour()) else: current.SetTextColour(self.foreground_colour()) current.SetBackgroundColour(self.background_colour()) self.BeginStyle(current) def ansi_test(self): self.Freeze() self.display("") self.display("--- ANSI TEST BEGIN ---") self.display("System Colors:") fg_cube = bg_cube = "" for c in range(0, 7): fg_cube += "\033[3" + str(c) + "m*\033[0m" bg_cube += "\033[4" + str(c) + "m \033[0m" self.display(fg_cube + " " + bg_cube) fg_cube = bg_cube = "" self.display("") self.display("Color cube, 6x6x6") for g in range(0, 6): for b in range(0, 6): for r in range(0, 6): c = ((r * 36) + (g * 6) + b) + 16 fg_cube += "\033[38;5;" + str(c) + "m*\033[0m" bg_cube += "\033[48;5;" + str(c) + "m \033[0m" self.display(fg_cube + " " + bg_cube) fg_cube = bg_cube = "" self.display("") self.display("Greyscale ramp:") for c in range(232, 255): fg_cube += "\033[38;5;" + str(c) + "m*\033[0m" bg_cube += "\033[48;5;" + str(c) + "m \033[0m" self.display(fg_cube + " " + bg_cube) fg_cube = bg_cube = "" self.display("") self.display("Some random 24-bit color samples:") from random import randint line = "" for i in range(0, 6): for j in range(0, 6): r = randint(0, 255) g = randint(0, 255) b = randint(0, 255) fg_bg = 48 if (j % 2) else 38 line += "\033[" + ("%d;2;%d;%d;%dm (%3d,%3d,%3d) " % (fg_bg, r, g, b, r, g, b)) + "\033[0m" self.display(line) line = "" self.display("") self.display("--- ANSI TEST END ---") self.display("") self.Thaw()
Handles communication between Electron/Flask and the terminal code. """ from flask import Flask, render_template, request, send_from_directory from term import Terminal from theme import Theme import os # Global variables THEMES = list() TERMINAL = Terminal(name='main') # Load themes THEMES_DIR = os.getcwd() + '/themes/' for root in os.walk(THEMES_DIR): for folder in root[1]: THEMES.append(Theme(path=THEMES_DIR + folder)) # Initialize flask app if len(THEMES) > 0: APP = Flask(__name__, static_folder=THEMES_DIR + THEMES[0].name) else: APP = Flask(__name__) APP.debug = False @APP.route('/') def peyl_page(): """Provides the main.html template""" return render_template('main.html')
def update_sample_text(self, evt): fp = self.fonts_page theme = Theme.fetch(fp.theme_picker.GetStringSelection()) fgcolour = theme.get('foreground') bgcolour = theme.get('background') font = fp.font_ctrl.GetSelectedFont() textattr = wx.TextAttr(fgcolour, bgcolour, font) fp.sample.SetBackgroundColour(bgcolour) fp.sample.SetValue(""" Emerson says, "This is what your window will look like." Emerson waves around a brightly-colored banner. It's super effective! 01234567 89ABCDEF """) fp.sample.SetStyle(0, fp.sample.GetLastPosition(), textattr) # Mock up ANSI if ANSI pref is on # TODO - maybe actually just shove ANSI-code-ful stuff through the actual output_panel ANSIfier? if fp.ansi_checkbox.GetValue(): textattr.SetTextColour(theme.Colour('blue')) fp.sample.SetStyle(1, 8, textattr) fp.sample.SetStyle(58, 66, textattr) textattr.SetTextColour(theme.Colour('red')) fp.sample.SetStyle(81, 89, textattr) textattr.SetTextColour(theme.Colour('yellow')) fp.sample.SetStyle(90, 97, textattr) textattr.SetTextColour(theme.Colour('green')) fp.sample.SetStyle(98, 104, textattr) fp.theme_picker.Enable() textattr.SetTextColour(theme.Colour('white')) textattr.SetFontWeight(wx.FONTWEIGHT_BOLD) fp.sample.SetStyle(107, 128, textattr) textattr.SetTextColour(theme.Colour('red', 'bright')) fp.sample.SetStyle(112, 117, textattr) textattr.SetFontWeight(wx.FONTWEIGHT_NORMAL) textattr.SetTextColour(theme.Colour('black')) fp.sample.SetStyle(130, 131, textattr) textattr.SetTextColour(theme.Colour('red')) fp.sample.SetStyle(131, 132, textattr) textattr.SetTextColour(theme.Colour('green')) fp.sample.SetStyle(132, 133, textattr) textattr.SetTextColour(theme.Colour('yellow')) fp.sample.SetStyle(133, 134, textattr) textattr.SetTextColour(theme.Colour('blue')) fp.sample.SetStyle(134, 135, textattr) textattr.SetTextColour(theme.Colour('magenta')) fp.sample.SetStyle(135, 136, textattr) textattr.SetTextColour(theme.Colour('cyan')) fp.sample.SetStyle(136, 137, textattr) textattr.SetTextColour(theme.Colour('white')) fp.sample.SetStyle(137, 138, textattr) textattr.SetTextColour(fgcolour) textattr.SetBackgroundColour(theme.Colour('black')) fp.sample.SetStyle(139, 140, textattr) textattr.SetBackgroundColour(theme.Colour('red')) fp.sample.SetStyle(140, 141, textattr) textattr.SetBackgroundColour(theme.Colour('green')) fp.sample.SetStyle(141, 142, textattr) textattr.SetBackgroundColour(theme.Colour('yellow')) fp.sample.SetStyle(142, 143, textattr) textattr.SetBackgroundColour(theme.Colour('blue')) fp.sample.SetStyle(143, 144, textattr) textattr.SetBackgroundColour(theme.Colour('magenta')) fp.sample.SetStyle(144, 145, textattr) textattr.SetBackgroundColour(theme.Colour('cyan')) fp.sample.SetStyle(145, 146, textattr) textattr.SetBackgroundColour(theme.Colour('white')) fp.sample.SetStyle(146, 147, textattr) else: fp.theme_picker.Disable() if evt: evt.Skip()
class MainWindow(object): def __init__(self, liststore): self.liststore = liststore self.gui = gui = Gtk.Builder() gui.add_from_file(SHARED_DATA_FILE('gfeedline.glade')) self.window = window = gui.get_object('main_window') self.column = MultiColumnDict(gui) # multi-columns for Notebooks self.theme = Theme() self.font = FontSet() self.notification = StatusNotification(liststore) dnd_list = [ Gtk.TargetEntry.new("text/uri-list", 0, 1), Gtk.TargetEntry.new("text/x-moz-url", 0, 4), ] window.drag_dest_set(Gtk.DestDefaults.ALL, dnd_list, Gdk.DragAction.COPY) target = Gtk.TargetList.new([]) target.add(Gdk.Atom.intern("text/x-moz-url", False), 0, 4) target.add(Gdk.Atom.intern("text/uri-list", False), 0, 1) window.drag_dest_set_target_list(target) window.connect("drag-data-received", self.on_drag_data_received) SETTINGS.connect("changed::window-sticky", self.on_settings_sticky_change) self.on_settings_sticky_change(SETTINGS, 'window-sticky') SETTINGS_VIEW.connect("changed::theme", self.on_settings_theme_change) self.on_settings_theme_change(SETTINGS_VIEW, 'theme') is_multi_column = SETTINGS_VIEW.get_boolean('multi-column') menuitem_multicolumn = gui.get_object('menuitem_multicolumn') menuitem_multicolumn.set_active(is_multi_column) menuitem_update = MenuItemUpdate(gui, liststore) x, y, w, h = self._get_geometry_from_settings() # window.show() # for wrong position when auto-start if x >= 0 and y >= 0: window.move(x, y) window.resize(w, h) window.show() gui.connect_signals(self) def on_drag_data_received(self, widget, context, x, y, selection, info, time): text, image_file = DnDSelection.parse(info, selection, True) if text or image_file: updatewindow = UpdateWindow(self) if text: updatewindow.text_buffer.set_text(text) else: updatewindow.set_upload_media(image_file) def get_notebook(self, group_name): if not SETTINGS_VIEW.get_boolean('multi-column'): group_name = 'dummy for single column' if group_name in self.column: notebook = self.column.get(group_name) else: notebook = FeedNotebook(self.column, group_name, self.liststore) self.column.add(group_name, notebook) return notebook def toggle_multicolumn_mode(self): for row in self.liststore: notebook = self.get_notebook(row[Column.GROUP]) view = row[Column.API].view view.force_remove() view.append(notebook, -1) reactor.callLater(0.1, self._jump_all_tabs_to_bottom, self.theme.is_ascending()) def _jump_all_tabs_to_bottom(self, is_bottom=True): for notebook in self.column.values(): notebook.jump_all_tabs_to_bottom(is_bottom) def change_font(self, font=None, size=None): for notebook in self.column.values(): notebook.change_font(font, size) def delete_status(self, status_id): js = 'hideStatus(\"%s\")' % status_id for notebook in self.column.values(): notebook.exec_js_all_views(js) def _get_geometry_from_settings(self): x = SETTINGS_GEOMETRY.get_int('window-x') y = SETTINGS_GEOMETRY.get_int('window-y') w = SETTINGS_GEOMETRY.get_int('window-width') h = SETTINGS_GEOMETRY.get_int('window-height') return x, y, w, h def on_window_leave_notify_event(self, widget, event): ox, oy, ow, oh = self._get_geometry_from_settings() x, y = widget.get_position() w, h = widget.get_size() if x != ox or y != oy: SETTINGS_GEOMETRY.set_int('window-x', x) SETTINGS_GEOMETRY.set_int('window-y', y) if w != ow or h != oh: SETTINGS_GEOMETRY.set_int('window-width', w) SETTINGS_GEOMETRY.set_int('window-height', h) def on_stop(self, *args): for row in self.liststore: row[Column.OPTIONS]['last_id'] = row[Column.API].last_id self.liststore.save_settings() reactor.stop() #self.window.destroy() def on_menuitem_quit_activate(self, menuitem): self.on_stop() def on_menuitem_update_activate(self, menuitem): UpdateWindow(self.liststore) def on_menuitem_prefs_activate(self, menuitem): Preferences(self) def on_menuitem_multicolumn_toggled(self, menuitem): is_multi_column = menuitem.get_active() SETTINGS_VIEW.set_boolean('multi-column', is_multi_column) self.toggle_multicolumn_mode() def on_menuitem_about_activate(self, menuitem): AboutDialog(self.window) def on_menuitem_help_activate(self, menuitem): Gtk.show_uri(None, 'http://code.google.com/p/gfeedline/wiki/Tips', Gdk.CURRENT_TIME) def on_menuitem_top_activate(self, menuitem=None): self._jump_all_tabs_to_bottom(False) def on_menuitem_bottom_activate(self, menuitem=None): self._jump_all_tabs_to_bottom() def on_menuitem_clear_activate(self, menuitem=None): for notebook in self.column.values(): notebook.clear_all_tabs() def on_menuitem_fullscreen_activate(self, menuitem): if menuitem.get_active(): self.window.fullscreen() else: self.window.unfullscreen() def on_menuitem_zoom_in_activate(self, menuitem): font_css = self.font.zoom_in() self.change_font(font_css) def on_menuitem_zoom_out_activate(self, menuitem): font_css = self.font.zoom_out() self.change_font(font_css) def on_menuitem_zoom_default_activate(self, menuitem): font_css = self.font.zoom_default() self.change_font(font_css) def on_settings_sticky_change(self, settings, key): if settings.get_boolean(key): self.window.stick() else: self.window.unstick() def on_settings_theme_change(self, settings, key): top = self.gui.get_object('menuitem_top') bottom = self.gui.get_object('menuitem_bottom') if not self.theme.is_ascending(): top, bottom = bottom, top top.hide() bottom.show()
class IconFactory(): """IconFactory finds the icon for a program and prepares the cairo surface.""" icon_theme = gtk.icon_theme_get_default() # Constants # Icon types SOME_MINIMIZED = 1 << 4 ALL_MINIMIZED = 1 << 5 LAUNCHER = 1 << 6 # Icon effects MOUSE_OVER = 1 << 7 MOUSE_BUTTON_DOWN = 1 << 8 NEEDS_ATTENTION = 1 << 9 BLINK = 1 << 10 # ACTIVE_WINDOW ACTIVE = 1 << 11 LAUNCH_EFFECT = 1 << 12 # Double width/height icons for drag and drop situations. DRAG_DROPP_START = 1 << 13 DRAG_DROPP_END = 1 << 14 TYPE_DICT = { "some_minimized": SOME_MINIMIZED, "all_minimized": ALL_MINIMIZED, "launcher": LAUNCHER, "mouse_over": MOUSE_OVER, "needs_attention": NEEDS_ATTENTION, "blink": BLINK, "active": ACTIVE, "launching": LAUNCH_EFFECT, "mouse_button_down": MOUSE_BUTTON_DOWN } def __init__(self, group, class_group=None, desktop_entry=None, identifier=None): self.dockbar_r = weakref.ref(group.dockbar_r()) self.theme = Theme() self.globals = Globals() connect(self.globals, "color-changed", self.reset_surfaces) self.desktop_entry = desktop_entry self.identifier = identifier self.class_group = class_group # Setting size to something other than zero to # avoid crashes if surface_update() is runned # before the size is set. self.size = 15 self.icon = None self.surfaces = {} self.average_color = None self.max_win_nr = self.theme.get_windows_cnt() self.types_in_theme = 0 for type in self.theme.get_types(): if not type in self.TYPE_DICT: continue self.types_in_theme = self.types_in_theme | self.TYPE_DICT[type] def remove(self): del self.desktop_entry del self.class_group del self.icon del self.surfaces del self.theme def set_desktop_entry(self, desktop_entry): self.desktop_entry = desktop_entry self.surfaces = {} del self.icon self.icon = None def set_class_group(self, class_group): if not self.desktop_entry and not self.class_group: self.surfaces = {} del self.icon self.icon = None self.class_group = class_group def set_size(self, size): if size <= 0: # To avoid chrashes. size = 15 self.size = size self.surfaces = {} self.average_color = None def get_size(self): return self.size def get_icon(self, size): return self.__find_icon_pixbuf(size) def reset_icon(self): self.icon = None def reset_surfaces(self, arg=None): self.surfaces = {} self.average_color = None def surface_update(self, type=0): # Checks if the requested pixbuf is already # drawn and returns it if it is. # Othervice the surface is drawn, saved and returned. #The first four bits of type is for telling the number of windows self.win_nr = min(type & 15, self.max_win_nr) # Remove all types that are not used by the theme (saves memory) dnd = (type & self.DRAG_DROPP_START and "start") or \ (type & self.DRAG_DROPP_END and "end") type = type & self.types_in_theme type += self.win_nr self.orient = self.dockbar_r().orient is_vertical = self.orient in ("left", "right") if type in self.surfaces: surface = self.surfaces[type] else: self.temp = {} surface = None commands = self.theme.get_icon_dict() self.ar = self.theme.get_aspect_ratio(is_vertical) self.type = type for command, args in commands.items(): try: f = getattr(self, "_IconFactory__command_%s" % command) except: raise else: surface = f(surface, **args) # Todo: add size correction. self.surfaces[type] = surface del self.temp gc.collect() if dnd: surface = self.__dd_highlight(surface, self.orient, dnd) gc.collect() return surface def __dd_highlight(self, surface, is_vertical, position="start"): w = surface.get_width() h = surface.get_height() if is_vertical: h = h + 4 else: w = w + 4 bg = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) ctx = cairo.Context(bg) if is_vertical and position == "start": ctx.move_to(1, 1.5) ctx.line_to(w - 1, 1.5) ctx.set_source_rgba(1, 1, 1, 0.2) ctx.set_line_width(2) ctx.stroke() ctx.move_to(2, 1.5) ctx.line_to(w - 2, 1.5) ctx.set_source_rgba(0, 0, 0, 0.7) ctx.set_line_width(1) ctx.stroke() elif is_vertical: ctx.move_to(1, h - 1.5) ctx.line_to(w - 1, h - 1.5) ctx.set_source_rgba(1, 1, 1, 0.2) ctx.set_line_width(2) ctx.stroke() ctx.move_to(2, h - 1.5) ctx.line_to(w - 2, h - 1.5) ctx.set_source_rgba(0, 0, 0, 0.7) ctx.set_line_width(1) ctx.stroke() elif position == "start": ctx.move_to(1.5, 1) ctx.line_to(1.5, h - 1) ctx.set_source_rgba(1, 1, 1, 0.2) ctx.set_line_width(2) ctx.stroke() ctx.move_to(1.5, 2) ctx.line_to(1.5, h - 2) ctx.set_source_rgba(0, 0, 0, 0.7) ctx.set_line_width(1) ctx.stroke() else: ctx.move_to(w - 1.5, 1) ctx.line_to(w - 1.5, h - 1) ctx.set_source_rgba(1, 1, 1, 0.2) ctx.set_line_width(2) ctx.stroke() ctx.move_to(w - 1.5, 2) ctx.line_to(w - 1.5, h - 2) ctx.set_source_rgba(0, 0, 0, 0.7) ctx.set_line_width(1) ctx.stroke() x, y = 0, 0 if is_vertical and position == "start": y = 4 elif position == "start": x = 4 ctx.set_source_surface(surface, x, y) ctx.paint() return bg def __get_color(self, color): if color == "active_color": color = "color5" if color in ["color%s" % i for i in range(1, 9)]: color = self.globals.colors[color] if color == "icon_average": color = self.__get_average_color() else: try: if len(color) != 7: raise ValueError("The string has the wrong lenght") t = int(color[1:], 16) except: logger.exception("Theme error: the color attribute " + "for a theme command"+ \ " should be a six digit hex string eg. \"#FFFFFF\" or"+ \ " the a dockbarx color (\"color1\"-\"color8\").") color = "#000000" return color def __get_alpha(self, alpha): # Transparency if alpha == "active_opacity": # For backwards compability alpha = "color5" for i in range(1, 9): if alpha in ("color%s" % i, "opacity%s" % i): if self.globals.colors.has_key("color%s_alpha" % i): a = float(self.globals.colors["color%s_alpha" % i]) / 255 else: logger.warning("Theme error: The theme has no" + \ " opacity option for color%s." % i) a = 1.0 break else: try: a = float(alpha) / 100 if a > 1.0 or a < 0: raise except: logger.exception("Theme error: The opacity attribute of a theme " + \ "command should be a number between \"0\" " + \ " and \"100\" or \"color1\" to \"color8\".") a = 1.0 return a def __get_average_color(self): if self.average_color is not None: return self.average_color r = 0 b = 0 g = 0 i = 0 im = self.__surface2pil(self.icon) pixels = im.load() width, height = im.size for x in range(width): for y in range(height): pix = pixels[x, y] if pix[3] > 30: i += 1 r += pix[0] g += pix[1] b += pix[2] if i > 0: r = int(round(float(r) / i)) g = int(round(float(g) / i)) b = int(round(float(b) / i)) r = ("0%s" % hex(r)[2:])[-2:] g = ("0%s" % hex(g)[2:])[-2:] b = ("0%s" % hex(b)[2:])[-2:] self.average_color = "#" + r + g + b return self.average_color #### Flow commands def __command_if(self, surface, type=None, windows=None, size=None, orient=None, content=None): if content is None: return surface # TODO: complete this ## l = [] ## splits = ["!", "(", ")", "&", "|"] ## for c in type: ## if c in splits: ## l.append(c) ## elif l[-1] in splits: ## l.append(c) ## elif not l: ## l.append(c) ## else: ## l[-1] += c # Check if the type condition is satisfied if type is not None: negation = False if type[0] == "!": type = type[1:] negation = True is_type = bool(type in self.TYPE_DICT \ and self.type & self.TYPE_DICT[type]) if not (is_type ^ negation): return surface #Check if the window number condition is satisfied if windows is not None: arg = windows negation = False if arg[0] == "!": arg = windows[1:] negation = True if arg[0] == ":": arg = "0" + arg elif arg[-1] == ":": arg = arg + "15" l = arg.split(":", 1) try: l = [int(n) for n in l] except ValueError: logger.exception("Theme Error: The windows attribute of " + \ "an <if> statement can\'t look like this:" + \ " \"%s\"." % windows + \ "See Theming HOWTO for more information") return surface if len(l) == 1: if not ((l[0] == self.win_nr) ^ negation): return surface else: if not ( (l[0] <= self.win_nr and self.win_nr <= l[1]) ^ negation): return surface #Check if the icon size condition is satisfied if size is not None: arg = size negation = False if arg[0] == "!": arg = size[1:] negation = True if arg[0] == ":": arg = "0" + arg elif arg[-1] == ":": arg = arg + "200" l = arg.split(":", 1) try: l = [int(n) for n in l] except ValueError: logger.exception("Theme Error: The size attribute of " + \ "an <if> statement can\'t look like this:" + \ " \"%s\". See Theming HOWTO for more information" % size) return surface us = int(round(self.__get_use_size())) if len(l) == 1: if not ((l[0] == self.win_nr) ^ negation): return surface else: if not ((l[0] <= us and us <= l[1]) ^ negation): return surface # Test if the orient condition is satisfied. if orient is not None: orients = orient.split(",") if not self.orient in orients: return surface # All tests passed, proceed. for command, args in content.items(): try: f = getattr(self, "_IconFactory__command_%s" % command) except: raise else: surface = f(surface, **args) return surface def __command_pixmap_from_self(self, surface, name, content=None): if not name: logger.warning("Theme Error: no name given for pixmap_from_self") raise Exeption w = int(surface.get_width()) h = int(surface.get_height()) self.temp[name] = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) ctx = cairo.Context(self.temp[name]) ctx.set_source_surface(surface) ctx.paint() if content is None: return surface for command, args in content.items(): try: f = getattr(self, "_IconFactory__command_%s" % command) except: raise else: self.temp[name] = f(self.temp[name], **args) return surface def __command_pixmap(self, surface, name, content=None, size=None): if size is not None: # TODO: Fix for different height and width w = h = int(round(self.__get_use_size() + \ self.__process_size(size))) elif surface is None: w = h = int(round(self.__get_use_size())) else: w = surface.get_width() h = surface.get_height() self.temp[name] = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) if content is None: return surface for command, args in content.items(): try: f = getattr(self, "_IconFactory__command_%s" % command) except: raise else: self.temp[name] = f(self.temp[name], **args) return surface #### Get icon def __command_get_icon(self, surface=None, size="0"): size = int(self.__get_use_size() + self.__process_size(size)) if size <= 0: # To avoid chrashes. size = 15 if self.icon and\ self.icon.get_width() == size and \ self.icon.get_height() == size: return self.icon del self.icon self.icon = None pb = self.__find_icon_pixbuf(size) if pb.get_width() != pb.get_height(): if pb.get_width() < pb.get_height(): h = size w = pb.get_width() * size / pb.get_height() elif pb.get_width() > pb.get_height(): w = size h = pb.get_height() * size / pb.get_width() self.icon = cairo.ImageSurface(cairo.FORMAT_ARGB32, size, size) ctx = gtk.gdk.CairoContext(cairo.Context(self.icon)) pbs = pb.scale_simple(w, h, gtk.gdk.INTERP_BILINEAR) woffset = round((size - w) / 2.0) hoffset = round((size - h) / 2.0) ctx.set_source_pixbuf(pb, woffset, hoffset) ctx.paint() del pb del pbs elif pb.get_width() != size: pbs = pb.scale_simple(size, size, gtk.gdk.INTERP_BILINEAR) self.icon = self.__pixbuf2surface(pbs) del pb del pbs else: self.icon = self.__pixbuf2surface(pb) del pb return self.icon def __find_icon_pixbuf(self, size): # Returns the icon pixbuf for the program. Uses the following metods: # 1) If it is a launcher, return the icon from the # launcher's desktopfile # 2) Get the icon from the gio app # 3) Check if the res_class fits an themed icon. # 4) Search in path after a icon matching reclass. # 5) Use the mini icon for the class pixbuf = None icon_name = None if self.desktop_entry: icon_name = self.desktop_entry.getIcon() if icon_name is not None and os.path.isfile(icon_name): pixbuf = self.__icon_from_file_name(icon_name, size) if pixbuf is not None: return pixbuf if not icon_name: if self.identifier: icon_name = self.identifier.lower() elif self.class_group: icon_name = self.class_group.get_res_class().lower() else: icon_name = "" # Special cases if icon_name.startswith("openoffice"): icon_name = "ooo-writer" if icon_name.startswith("libreoffice"): icon_name = "libreoffice-writer" if self.icon_theme.has_icon(icon_name): return self.icon_theme.load_icon(icon_name, size, 0) if icon_name[-4:] in (".svg", ".png", ".xpm"): if self.icon_theme.has_icon(icon_name[:-4]): pixbuf = self.icon_theme.load_icon(icon_name[:-4], size, 0) if pixbuf is not None: return pixbuf pixbuf = self.__icon_search_in_data_path(icon_name, size) if pixbuf is not None: return pixbuf if self.class_group: return self.class_group.get_icon().copy() # If no pixbuf has been found (can only happen for an unlaunched # launcher), make an empty pixbuf and show a warning. if self.icon_theme.has_icon("application-default-icon"): pixbuf = self.icon_theme.load_icon("application-default-icon", size, 0) else: pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8, size, size) pixbuf.fill(0x00000000) if self.desktop_entry: name = self.desktop_entry.getName() else: name = None return pixbuf def __icon_from_file_name(self, icon_name, icon_size=-1): if os.path.isfile(icon_name): try: return gtk.gdk.pixbuf_new_from_file_at_size( icon_name, -1, icon_size) except: pass return None def __icon_search_in_data_path(self, icon_name, icon_size): data_folders = None if os.environ.has_key("XDG_DATA_DIRS"): data_folders = os.environ["XDG_DATA_DIRS"] if not data_folders: data_folders = "/usr/local/share/:/usr/share/" for data_folder in data_folders.split(":"): #The line below line used datafolders instead of datafolder. #I changed it because I suspect it was a bug. paths = (os.path.join(data_folder, "pixmaps", icon_name), os.path.join(data_folder, "icons", icon_name)) for path in paths: if os.path.isfile(path): icon = self.__icon_from_file_name(path, icon_size) if icon: return icon return None #### Other commands def __command_clear(self, surface): if self.dockbar_r().orient in ("left", "right"): w = self.size h = int(self.size * self.ar) else: w = int(self.size * self.ar) h = self.size new = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) ctx = cairo.Context(new) ctx.set_source_rgba(0, 0, 0) ctx.set_operator(cairo.OPERATOR_SOURCE) ctx.paint_with_alpha(0) return new def __command_get_pixmap(self, surface, name): if surface is None: if self.dockbar_r().orient in ("left", "right"): width = self.size height = int(self.size * self.ar) else: width = int(self.size * self.ar) height = self.size else: width = surface.get_width() height = surface.get_height() if self.theme.has_surface(name): surface = self.__resize_surface(self.theme.get_surface(name), width, height) else: logger.warning("theme error: pixmap %s not found" % name) return surface def __command_fill(self, surface, color, opacity="100"): w = surface.get_width() h = surface.get_height() new = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) ctx = cairo.Context(new) ctx.set_source_surface(surface) ctx.paint() alpha = self.__get_alpha(opacity) c = self.__get_color(color) r = float(int(c[1:3], 16)) / 255 g = float(int(c[3:5], 16)) / 255 b = float(int(c[5:7], 16)) / 255 ctx.set_source_rgba(r, g, b) ctx.set_operator(cairo.OPERATOR_SOURCE) ctx.paint_with_alpha(alpha) return new def __command_combine(self, surface, pix1, pix2, degrees=None): # Combines left half of surface with right half of surface2. # The transition between the two halves are soft. # Degrees keyword are kept of compability reasons. w = surface.get_width() h = surface.get_height() if pix1 == "self": p1 = surface elif pix1 in self.temp: p1 = self.temp[pix1] elif self.theme.has_surface(pix1): w = surface.get_width() h = surface.get_height() p1 = self.__resize_surface(self.theme.get_surface(bg), w, h) else: logger.warning("theme error: pixmap %s not found" % pix1) if pix2 == "self": p2 = surface elif pix2 in self.temp: p2 = self.temp[pix2] elif self.theme.has_surface(pix2): w = surface.get_width() h = surface.get_height() p2 = self.__resize_surface(self.theme.get_surface(bg), w, h) else: logger.warning("theme error: pixmap %s not found" % pix2) surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, p1.get_width(), p1.get_height()) ctx = cairo.Context(surface) linear = cairo.LinearGradient(0, 0, p1.get_width(), 0) linear.add_color_stop_rgba(0.4, 0, 0, 0, 0.5) linear.add_color_stop_rgba(0.6, 0, 0, 0, 1) ctx.set_source_surface(p2, 0, 0) #ctx.mask(linear) ctx.paint() linear = cairo.LinearGradient(0, 0, p1.get_width(), 0) linear.add_color_stop_rgba(0.4, 0, 0, 0, 1) linear.add_color_stop_rgba(0.6, 0, 0, 0, 0) ctx.set_source_surface(p1, 0, 0) ctx.mask(linear) try: del pb del pbs except: pass return surface def __command_transp_sat(self, surface, opacity="100", saturation="100"): # Makes the icon desaturized and/or transparent. alpha = self.__get_alpha(opacity) # Todo: Add error check for saturation sat = float(saturation) if sat != 100: im = self.__surface2pil(surface) w, h = im.size pixels = im.load() for x in range(w): for y in range(h): r, g, b, a = pixels[x, y] l = (r + g + b) / 3.0 * (100 - sat) / 100.0 r = int(r * sat / 100.0 + l) g = int(g * sat / 100.0 + l) b = int(b * sat / 100.0 + l) a = int(a * alpha) pixels[x, y] = (r, g, b, a) return self.__pil2surface(im) else: w = surface.get_width() h = surface.get_height() new = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) ctx = gtk.gdk.CairoContext(cairo.Context(new)) ctx.set_source_surface(surface) ctx.paint_with_alpha(alpha) return new def __command_composite(self, surface, bg, fg, opacity="100", xoffset="0", yoffset="0", angle="0"): if fg == "self": foreground = surface if angle and angle != "0": foreground = self.__command_rotate(foreground, angle, True) elif fg in self.temp: foreground = self.temp[fg] if angle and angle != "0": foreground = self.__command_rotate(foreground, angle, True) elif self.theme.has_surface(fg): foreground = self.theme.get_surface(fg) if angle and angle != "0": foreground = self.__command_rotate(foreground, angle, True) w = surface.get_width() h = surface.get_height() foreground = self.__resize_surface(foreground, w, h) else: logger.warning("theme error: pixmap %s not found" % fg) return surface if bg == "self": background = surface elif bg in self.temp: w = self.temp[bg].get_width() h = self.temp[bg].get_height() background = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) ctx = cairo.Context(background) ctx.set_source_surface(self.temp[bg]) ctx.paint() elif self.theme.has_surface(bg): w = surface.get_width() h = surface.get_height() background = self.__resize_surface(self.theme.get_surface(bg), w, h) else: logger.warning("theme error: pixmap %s not found" % bg) return surface xoffset = self.__get_from_set(xoffset) yoffset = self.__get_from_set(yoffset) opacity = self.__get_alpha(opacity) xoffset = self.__process_size(xoffset) yoffset = self.__process_size(yoffset) ctx = cairo.Context(background) ctx.set_source_surface(foreground, xoffset, yoffset) ctx.paint_with_alpha(opacity) return background def __command_shrink(self, surface, percent="0", pixels="0"): w0 = surface.get_width() h0 = surface.get_height() new = cairo.ImageSurface(cairo.FORMAT_ARGB32, w0, h0) ctx = cairo.Context(new) pixels = self.__get_from_set(pixels) percent = self.__get_from_set(percent) w = int(((100 - int(percent)) * w0) / 100) - int(pixels) h = int(((100 - int(percent)) * h0) / 100) - int(pixels) shrinked = self.__resize_surface(surface, w, h) x = round((w0 - w) / 2.0) y = round((h0 - h) / 2.0) ctx.set_source_surface(shrinked, x, y) ctx.paint() del shrinked return new def __command_rotate(self, surface, angle="0", resize="False"): w0 = surface.get_width() h0 = surface.get_height() # Check if the angle should be taken from a set. angle = self.__get_from_set(angle) a = float(angle) / 180 * pi if not resize or resize in ("False", "0"): w = w0 h = h0 else: w = abs(int(round(cos(a) * w0 + sin(a) * h0))) h = abs(int(round(cos(a) * h0 + sin(a) * w0))) new = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) ctx = cairo.Context(new) ctx.translate(w / 2.0, h / 2.0) ctx.rotate(a) ctx.translate(-w0 / 2.0, -h0 / 2.0) ctx.set_source_surface(surface, 0, 0) ctx.paint() return new def __command_correct_size(self, surface): if surface is None: return if self.dockbar_r().orient in ("left", "right"): width = self.size height = int(self.size * self.ar) else: width = int(self.size * self.ar) height = self.size if surface.get_width() == width and surface.get_height() == height: return surface woffset = round((width - surface.get_width()) / 2.0) hoffset = round((height - surface.get_height()) / 2.0) new = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height) ctx = cairo.Context(new) ctx.set_source_surface(surface, woffset, hoffset) ctx.paint() return new def __command_glow(self, surface, color, opacity="100"): # Adds a glow around the parts of the surface # that isn't completely transparent. alpha = self.__get_alpha(opacity) # Thickness (pixels) tk = 1.5 # Prepare the glow that should be put behind the icon cs = self.__command_colorize(surface, color) w = surface.get_width() h = surface.get_height() glow = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) ctx = cairo.Context(glow) tk1 = tk / 2.0 for x, y in ((-tk1, -tk1), (-tk1, tk1), (tk1, -tk1), (tk1, tk1)): ctx.set_source_surface(cs, x, y) ctx.paint_with_alpha(0.66) for x, y in ((-tk, -tk), (-tk, tk), (tk, -tk), (tk, tk)): ctx.set_source_surface(cs, x, y) ctx.paint_with_alpha(0.27) # Add glow and icon to a new canvas new = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) ctx = cairo.Context(new) ctx.set_source_surface(glow) ctx.paint_with_alpha(alpha) ctx.set_source_surface(surface) ctx.paint() return new def __command_colorize(self, surface, color): # Changes the color of all pixels to color. # The pixels alpha values are unchanged. # Convert color hex-string (format "#FFFFFF")to int r, g, b color = self.__get_color(color) r = int(color[1:3], 16) / 255.0 g = int(color[3:5], 16) / 255.0 b = int(color[5:7], 16) / 255.0 w = surface.get_width() h = surface.get_height() new = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) ctx = cairo.Context(new) ctx.set_source_rgba(r, g, b, 1.0) ctx.mask_surface(surface) return new def __command_bright(self, surface, strength=None, strenght=None): if strength is None and strenght is not None: # For compability with older themes. strength = strenght alpha = self.__get_alpha(strength) w = surface.get_width() h = surface.get_height() # Colorize white white = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) ctx = cairo.Context(white) ctx.set_source_rgba(1.0, 1.0, 1.0, 1.0) ctx.mask_surface(surface) # Apply the white version over the icon # with the chosen alpha value new = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) ctx = cairo.Context(new) ctx.set_source_surface(surface) ctx.paint() ctx.set_source_surface(white) ctx.paint_with_alpha(alpha) return new def __command_alpha_mask(self, surface, mask, angle="0"): if mask in self.temp: mask = self.temp[mask] if angle and angle != "0": mask = self.__command_rotate(mask, angle, True) elif self.theme.has_surface(mask): mask = self.theme.get_surface(mask) if angle and angle != "0": mask = self.__command_rotate(mask, angle, True) w = surface.get_width() h = surface.get_height() mask = self.__resize_surface(mask, w, h) w = surface.get_width() h = surface.get_height() new = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) ctx = cairo.Context(new) ctx.set_source_surface(surface) ctx.mask_surface(mask) return new #### Format conversions def __pixbuf2surface(self, pixbuf): if pixbuf is None: return None w = pixbuf.get_width() h = pixbuf.get_height() surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) ctx = gtk.gdk.CairoContext(cairo.Context(surface)) ctx.set_source_pixbuf(pixbuf, 0, 0) ctx.paint() del pixbuf return surface def __surface2pil(self, surface): w = surface.get_width() h = surface.get_height() return Image.frombuffer("RGBA", (w, h), surface.get_data(), "raw", "BGRA", 0, 1) def __pil2surface(self, im): """Transform a PIL Image into a Cairo ImageSurface.""" # This function is only supposed to work with little endinan # systems. Could that be a problem ever? if im.mode != 'RGBA': im = im.convert('RGBA') s = im.tobytes('raw', 'BGRA') a = array.array('B', s) dest = cairo.ImageSurface(cairo.FORMAT_ARGB32, im.size[0], im.size[1]) ctx = cairo.Context(dest) non_premult_src_wo_alpha = cairo.ImageSurface.create_for_data( a, cairo.FORMAT_RGB24, im.size[0], im.size[1]) non_premult_src_alpha = cairo.ImageSurface.create_for_data( a, cairo.FORMAT_ARGB32, im.size[0], im.size[1]) ctx.set_source_surface(non_premult_src_wo_alpha) ctx.mask_surface(non_premult_src_alpha) return dest def __process_size(self, size_str): us = self.__get_use_size() size = 0 size_str = size_str.replace("-", "+-") for s in size_str.split("+"): if s == "": continue if s[-1] == "%": # Rounding to whole pixels to avoid uninteded bluring. size += round(float(s[:-1]) / 100 * us) continue if s.endswith("px"): s = s[:-2] # Here no rounding is done. Let's assume that the # theme maker knows what he is doing if he chooses # to use decimal pixel values. size += float(s) return size def __get_use_size(self): is_vertical = self.dockbar_r().orient in ("left", "right") if "aspect_ratio_v" in self.theme.theme["button_pixmap"] or \ not is_vertical: us = self.size * self.ar if self.ar < 1 else self.size else: # For old vertical themes us = self.size return us def __get_from_set(self, setname): s = self.theme.get_from_set(setname, self.orient) if s is not None: return s else: return setname def __resize_surface(self, surface, w, h): im = self.__surface2pil(surface) im = im.resize((w, h), Image.ANTIALIAS) return self.__pil2surface(im) def __command_print_size(self, surface): w = surface.get_width() h = surface.get_height() print w, h return surface
class Graphics: screen = None theme = None def start(self): self.screen = curses.initscr() curses.noecho() curses.cbreak() curses.curs_set(0) curses.start_color() self.screen.nodelay(1) # Needs to be done after `initscr()` call self.theme = Theme() def draw_tile(self, x, y, tile='', color=None): color = color or self.theme.get_color('default') x = x * 2 + stage.padding[3] * 2 + stage.width / 2 y += stage.padding[0] + stage.height / 2 self.screen.addstr(y, x, tile, color) if (len(tile) < 2): self.screen.addstr(y, x + 1, tile, color) def draw_game_over(self): self.draw_tile(-4, -1, ' GAME OVER ', self.theme.get_color('text')) self.draw_tile(-7, 1, ' Press ENTER to restart ', self.theme.get_color('text')) def draw_score(self): score_formatted = str(game.score).zfill(2) self.draw_tile((stage.width / 2) - 1, (-stage.height / 2) - 1, score_formatted, self.theme.get_color('text')) def draw_lives(self): posx = (-stage.width / 2) + 3 for x in xrange(1, game.lives + 1): posx += 1 self.draw_tile(posx, (-stage.height / 2) - 1, self.theme.get_tile('lives'), self.theme.get_color('lives')) posx += 1 self.draw_tile(posx, (-stage.height / 2) - 1, self.theme.get_tile('border-h'), self.theme.get_color('border')) def draw_snake(self): for part in game.snake: self.draw_tile(part[0], part[1], self.theme.get_tile('snake-body'), self.theme.get_color('snake')) # Clean last tile self.draw_tile(game.lastPos[0], game.lastPos[1], self.theme.get_tile('bg'), self.theme.get_color('bg')) def draw_apples(self): for apple in game.apples: self.draw_tile(apple[0], apple[1], self.theme.get_tile('apple'), self.theme.get_color('apple')) def draw_game(self): for y in range(stage.boundaries['top'], stage.boundaries['bottom']): for x in range(stage.boundaries['left'], stage.boundaries['right']): self.draw_tile(x, y, self.theme.get_tile('bg'), self.theme.get_color('bg')) self.draw_borders() self.draw_text() def draw_borders(self): tile_v = self.theme.get_tile('border-v') tile_h = self.theme.get_tile('border-h') tile_c = self.theme.get_tile('border-c') color = self.theme.get_color('border') x_left = stage.boundaries['left'] x_right = stage.boundaries['right'] y_top = stage.boundaries['top'] y_bottom = stage.boundaries['bottom'] for y in xrange(y_top, y_bottom): self.draw_tile(x_left - 1, y, tile_v, color) self.draw_tile(x_right, y, tile_v, color) for x in xrange(x_left, x_right): self.draw_tile(x, y_top - 1, tile_h, color) self.draw_tile(x, y_bottom, tile_h, color) self.draw_tile(x_left - 1, y_top - 1, tile_c, color) self.draw_tile(x_left - 1, y_bottom, tile_c, color) self.draw_tile(x_right, y_top - 1, tile_c, color) self.draw_tile(x_right, y_bottom, tile_c, color) def draw_text(self): color = self.theme.get_color('text') self.draw_tile((stage.width / 2) - 4, (-stage.height / 2) - 1, 'score:', color) self.draw_tile((-stage.width / 2), (-stage.height / 2) - 1, 'lives:', color) self.draw_tile(-5, (stage.height / 2), ' Press Q to quit ', color) def update(self): self.draw_snake() self.draw_apples() self.draw_score() self.draw_lives() def exit(self): self.screen.clear() self.screen.keypad(0) curses.echo() curses.nocbreak() curses.endwin()
def process_request(self, request): if not settings.INSTALLED_THEMES: raise ValueError('There are no themes installed!') request.theme = Theme(settings.INSTALLED_THEMES[0])
class SettingsManager(object): """Organizes user settings""" def __init__(self, alot_rc=None, notmuch_rc=None): """ :param alot_rc: path to alot's config file :type alot_rc: str :param notmuch_rc: path to notmuch's config file :type notmuch_rc: str """ self.hooks = None self._mailcaps = mailcap.getcaps() self._config = ConfigObj() self._notmuchconfig = None self._theme = None self._accounts = None self._accountmap = None bindings_path = os.path.join(DEFAULTSPATH, 'default.bindings') self._bindings = ConfigObj(bindings_path) if alot_rc is not None: self.read_config(alot_rc) if notmuch_rc is not None: self.read_notmuch_config(notmuch_rc) def read_notmuch_config(self, path): """parse notmuch's config file from path""" spec = os.path.join(DEFAULTSPATH, 'notmuch.rc.spec') self._notmuchconfig = read_config(path, spec) def read_config(self, path): """parse alot's config file from path""" spec = os.path.join(DEFAULTSPATH, 'alot.rc.spec') newconfig = read_config(path, spec, checks={'mail_container': mail_container, 'force_list': force_list, 'align': align_mode, 'attrtriple': attr_triple, 'gpg_key_hint': gpg_key}) self._config.merge(newconfig) hooks_path = os.path.expanduser(self._config.get('hooksfile')) try: self.hooks = imp.load_source('hooks', hooks_path) except: logging.debug('unable to load hooks file:%s' % hooks_path) if 'bindings' in newconfig: newbindings = newconfig['bindings'] if isinstance(newbindings, Section): self._bindings.merge(newbindings) # themes themestring = newconfig['theme'] themes_dir = self._config.get('themes_dir') if themes_dir: themes_dir = os.path.expanduser(themes_dir) else: configdir = os.environ.get('XDG_CONFIG_HOME', os.path.expanduser('~/.config')) themes_dir = os.path.join(configdir, 'alot', 'themes') logging.debug(themes_dir) # if config contains theme string use that if themestring: if not os.path.isdir(themes_dir): err_msg = 'cannot find theme %s: themes_dir %s is missing' raise ConfigError(err_msg % (themestring, themes_dir)) else: theme_path = os.path.join(themes_dir, themestring) try: self._theme = Theme(theme_path) except ConfigError as e: err_msg = 'Theme file %s failed validation:\n' raise ConfigError((err_msg % themestring) + str(e.message)) # if still no theme is set, resort to default if self._theme is None: theme_path = os.path.join(DEFAULTSPATH, 'default.theme') self._theme = Theme(theme_path) self._accounts = self._parse_accounts(self._config) self._accountmap = self._account_table(self._accounts) def _parse_accounts(self, config): """ read accounts information from config :param config: valit alot config :type config: `configobj.ConfigObj` :returns: list of accounts """ accounts = [] if 'accounts' in config: for acc in config['accounts'].sections: accsec = config['accounts'][acc] args = dict(config['accounts'][acc]) # create abook for this account abook = accsec['abook'] logging.debug('abook defined: %s' % abook) if abook['type'] == 'shellcommand': cmd = abook['command'] regexp = abook['regexp'] if cmd is not None and regexp is not None: args['abook'] = MatchSdtoutAddressbook(cmd, match=regexp) else: msg = 'underspecified abook of type \'shellcommand\':' msg += '\ncommand: %s\nregexp:%s' % (cmd, regexp) raise ConfigError(msg) elif abook['type'] == 'abook': contacts_path = abook['abook_contacts_file'] args['abook'] = AbookAddressBook( contacts_path, ignorecase=abook['ignorecase']) else: del(args['abook']) cmd = args['sendmail_command'] del(args['sendmail_command']) newacc = SendmailAccount(cmd, **args) accounts.append(newacc) return accounts def _account_table(self, accounts): """ creates a lookup table (emailaddress -> account) for a given list of accounts :param accounts: list of accounts :type accounts: list of `alot.account.Account` :returns: hashtable :rvalue: dict (str -> `alot.account.Account`) """ accountmap = {} for acc in accounts: accountmap[acc.address] = acc for alias in acc.aliases: accountmap[alias] = acc return accountmap def get(self, key, fallback=None): """ look up global config values from alot's config :param key: key to look up :type key: str :param fallback: fallback returned if key is not present :type fallback: str :returns: config value with type as specified in the spec-file """ value = None if key in self._config: value = self._config[key] if isinstance(value, Section): value = None if value is None: value = fallback return value def set(self, key, value): """ setter for global config values :param key: config option identifise :type key: str :param value: option to set :type value: depends on the specfile :file:`alot.rc.spec` """ self._config[key] = value def get_notmuch_setting(self, section, key, fallback=None): """ look up config values from notmuch's config :param section: key is in :type section: str :param key: key to look up :type key: str :param fallback: fallback returned if key is not present :type fallback: str :returns: config value with type as specified in the spec-file """ value = None if section in self._notmuchconfig: if key in self._notmuchconfig[section]: value = self._notmuchconfig[section][key] if value is None: value = fallback return value def get_theming_attribute(self, mode, name, part=None): """ looks up theming attribute :param mode: ui-mode (e.g. `search`,`thread`...) :type mode: str :param name: identifier of the atttribute :type name: str :rtype: urwid.AttrSpec """ colours = int(self._config.get('colourmode')) return self._theme.get_attribute(colours, mode, name, part) def get_threadline_theming(self, thread): """ looks up theming info a threadline displaying a given thread. This wraps around :meth:`~alot.settings.theme.Theme.get_threadline_theming`, filling in the current colour mode. :param thread: thread to theme :type thread: alot.db.thread.Thread """ colours = int(self._config.get('colourmode')) return self._theme.get_threadline_theming(thread, colours) def get_tagstring_representation(self, tag, onebelow_normal=None, onebelow_focus=None): """ looks up user's preferred way to represent a given tagstring. :param tag: tagstring :type tag: str :param onebelow_normal: attribute that shines through if unfocussed :type onebelow_normal: urwid.AttrSpec :param onebelow_focus: attribute that shines through if focussed :type onebelow_focus: urwid.AttrSpec If `onebelow_normal` or `onebelow_focus` is given these attributes will be used as fallbacks for fg/bg values '' and 'default'. This returns a dictionary mapping :normal: to :class:`urwid.AttrSpec` used if unfocussed :focussed: to :class:`urwid.AttrSpec` used if focussed :translated: to an alternative string representation """ colourmode = int(self._config.get('colourmode')) theme = self._theme cfg = self._config colours = [1, 16, 256] def colourpick(triple): """ pick attribute from triple (mono,16c,256c) according to current colourmode""" if triple is None: return None return triple[colours.index(colourmode)] # global default attributes for tagstrings. # These could contain values '' and 'default' which we interpret as # "use the values from the widget below" default_normal = theme.get_attribute(colourmode, 'global', 'tag') default_focus = theme.get_attribute(colourmode, 'global', 'tag_focus') # local defaults for tagstring attributes. depend on next lower widget fallback_normal = resolve_att(onebelow_normal, default_normal) fallback_focus = resolve_att(onebelow_focus, default_focus) for sec in cfg['tags'].sections: if re.match('^' + sec + '$', tag): normal = resolve_att(colourpick(cfg['tags'][sec]['normal']), fallback_normal) focus = resolve_att(colourpick(cfg['tags'][sec]['focus']), fallback_focus) translated = cfg['tags'][sec]['translated'] if translated is None: translated = tag translation = cfg['tags'][sec]['translation'] if translation: translated = re.sub(translation[0], translation[1], tag) break else: normal = fallback_normal focus = fallback_focus translated = tag return {'normal': normal, 'focussed': focus, 'translated': translated} def get_hook(self, key): """return hook (`callable`) identified by `key`""" if self.hooks: if key in self.hooks.__dict__: return self.hooks.__dict__[key] return None def get_mapped_input_keysequences(self, mode='global', prefix=u''): candidates = self._bindings.scalars if mode != 'global': candidates = candidates + self._bindings[mode].scalars if prefix is not None: prefixs = prefix + ' ' cand = filter(lambda x: x.startswith(prefixs), candidates) if prefix in candidates: candidates = cand + [prefix] else: candidates = cand return candidates def get_keybinding(self, mode, key): """look up keybinding from `MODE-maps` sections :param mode: mode identifier :type mode: str :param key: urwid-style key identifier :type key: str :returns: a command line to be applied upon keypress :rtype: str """ cmdline = None bindings = self._bindings if key in bindings.scalars: cmdline = bindings[key] if mode in bindings.sections: if key in bindings[mode].scalars: value = bindings[mode][key] if value: cmdline = value # Workaround for ConfigObj misbehaviour. cf issue #500 # this ensures that we get at least strings only as commandlines if isinstance(cmdline, list): cmdline = ','.join(cmdline) return cmdline def get_accounts(self): """ returns known accounts :rtype: list of :class:`Account` """ return self._accounts def get_account_by_address(self, address): """ returns :class:`Account` for a given email address (str) :param address: address to look up :type address: string :rtype: :class:`Account` or None """ for myad in self.get_addresses(): if myad in address: return self._accountmap[myad] return None def get_main_addresses(self): """returns addresses of known accounts without its aliases""" return [a.address for a in self._accounts] def get_addresses(self): """returns addresses of known accounts including all their aliases""" return self._accountmap.keys() def get_addressbooks(self, order=[], append_remaining=True): """returns list of all defined :class:`AddressBook` objects""" abooks = [] for a in order: if a: if a.abook: abooks.append(a.abook) if append_remaining: for a in self._accounts: if a.abook and a.abook not in abooks: abooks.append(a.abook) return abooks def mailcap_find_match(self, *args, **kwargs): """ Propagates :func:`mailcap.find_match` but caches the mailcap (first argument) """ return mailcap.findmatch(self._mailcaps, *args, **kwargs) def represent_datetime(self, d): """ turns a given datetime obj into a unicode string representation. This will: 1) look if a fixed 'timestamp_format' is given in the config 2) check if a 'timestamp_format' hook is defined 3) use :func:`~alot.helper.pretty_datetime` as fallback """ fixed_format = self.get('timestamp_format') if fixed_format: rep = string_decode(d.strftime(fixed_format), 'UTF-8') else: format_hook = self.get_hook('timestamp_format') if format_hook: rep = string_decode(format_hook(d), 'UTF-8') else: rep = pretty_datetime(d) return rep
maximum_device = components['audioLoader'].get_device_count() # List all the devices supported by the Host API. # Selection is not avialable due to regressions (would be fixed later). for device_index in range(maximum_device): device_info = components['audioLoader'].get_device_info_by_index( device_index) print("[%d %s%s] %s" % (device_info['index'], green('I') if device_info['maxInputChannels'] else str(), red('O') if device_info['maxOutputChannels'] else str(), device_info['name'])) # Intialize the component theme. And get the color # palette to draw on the screen. components['themeLoader'] = Theme(CONFIG_FILES[1]) _theme = components['themeLoader'].getPalette() def _process_audio(frames, nFrames, timeInfo, status): audio_buffer = list( map(lambda sample: sample[0], components['pcmUnpacker'].iter_unpack(frames))) # Draw each buffer recieved from the callback. # In the Backend SDL does all the work. isClosed = components['visualiser'] \ .draw(audio_buffer, ( _theme['background'], _theme['foreground'] ))
from gameDriver import GameDriver from theme import Theme import pygame, sys dim = (15, 10) if dim[0] < 4 or dim[1] <= 0: print("Invalid Squares Per Row/Column") sys.exit(0) width = 50 if width <= 0: print("Invalid Square Width") sys.exit(0) # Bomb img, flag img, font name normal = Theme("explosion.png", "flag_0.png", "Arial", width) american = Theme("firework.png", "flag_1.png", "Comic Sans", width) traditional = Theme("bomb_2.png", "flag_2.png", "Times New Roman", width) driver = GameDriver(dim, width, traditional) playing = True old_time = pygame.time.get_ticks() while True: dt = pygame.time.get_ticks() - old_time old_time = pygame.time.get_ticks() events = pygame.event.get() if playing: playing = driver.playGame(dim, width, events, dt)