Témata mají uživatelé přístupná v nastavení Screenletu po kliknutí „pravou myší“, v nabídce Properties, na kartě Themes, nebo také mohou jednoduše témata přepínat po kliknutí „pravou myší“ na Screenlet pod nabídkou Theme.
Pomocí témat se mění vzhled Screenletu, ať už jen drobně či úplně. Drobná úprava Screenletu pomocí témat může být například změna sady ikon, které jsou v našem Screenletu použity, nebo změna pozadí – buďto nějaké pěkné grafické obrázky nebo průhledné. Naopak úplná změna může být změna ikon, pozadí, rozmístění prvků, prostě všeho.
Dobrým příkladem úplné změny Screenletu pomocí témat je třeba zobrazení zaplnění oddílů – v jednom případě může mít Screenlet pěkné barevné ikonky na pěkném pozadí, s grafickým ukazatelem a zobrazení celkového a volného místa a v druhém (tématu) může mít černobíle ikonky na průhledném pozadí, bez grafického zobrazení a zobrazení kompletních informací o zaplnění disku (celkové, volné, využité místo).
Budeme se však držet dvou zásad:
- První zásada je, že nebudeme pomocí témat měnit barvy fontů a různých grafických prvků. Výběr jiné barvy necháme kompletně na uživateli a uděláme mu na to možnost v nastavení (ukážeme si příště). Samozřejmě, pokud používáme nějaké pozadí (myšleno jako obrázek), tak ten si samozřejmě vytvoříme v různých barvách a uděláme potřebná témata.
- Druhá zásada je, že nebudeme pomocí témat měnit funkčnost Screenletu. Myslím tím, že nebudeme v jednom tématu zobrazovat zaplnění disku a v druhém tématu zobrazovat vytížení procesoru. Pokud bychom chtěli v jednom Screenletu sledovat více takových věcí a zobrazovat jen jednu, kterou si uživatel přeje sledovat, jde to udělat jednoduše přes nastavení. Opět samozřejmě nemám namysli, že chci zobrazovat využití disků (oddílů) 3× a pokaždé jinak, jako v příkladu výše.
Ukázka
V ukázce MyFirstScreenlet-1.0.tar.gz se již nespokojíme s jedním souborem. Nyní budeme upravovat soubor se zdrojovým kódem Screenletu a soubor se zdrojovým kódem témata ke Screenletu.
Schválně zde ukazuji jen jednoduchý příklad, abyste to co nejlépe pochopili. Jiný (složitější) případy si vyzkoušejte sami za domácí úkol.
MyFirstScreenlet.py
:
#!/usr/bin/env python import screenlets from screenlets import DefaultMenuItem import gobject, gtk, cairo import time, os, sys class MyFirstScreenlet( screenlets.Screenlet ): """MyFisrstScreenlet""" __name__ = 'My First Screenlet' __version__ = '1.0' __author__ = 'Michal Horejsek' __desc__ = __doc__ __timer = None __buffers = {} __themeModule = None firstDrawing = True width = 220 height = 80 def __init__( self, **keyword_args ): screenlets.Screenlet.__init__( self, width=self.width, height=self.height, **keyword_args ) pridame si do pythonni promenny s adresarema oznacujici moduly nas adresar s tematama tohoto screenletu # (pro pozdejsi jednoduchy import temata) os.chdir( self.get_screenlet_dir() ) sys.path.append( 'themes' ) # importujeme si pouzivane tema self.__themeModule = __import__( self.theme_name ) def on_init( self ): self.add_default_menuitems() self.initBuffers() def on_load_theme( self ): # tato metoda se vola po inicializaci noveho temata, ale pred prekreslenim (pri zmene temata uzivatelem napriklad) # zde si naimportujeme nove pouzivane tema if not self.__themeModule or self.theme_name != self.__themeModule.__name__: self.__themeModule = __import__( self.theme_name ) def on_map( self ): if not self.__timer: self.__timer = gobject.timeout_add( 1000, self.update ) self.update() def on_unmap( self ): if self.__timer: gobject.source_remove( self.__timer ) self.__timer = None def initBuffers(self): self.__buffers['time2'] = gtk.gdk.Pixmap( self.window.window, self.width, gtk.gdk.screen_height(), -1 ) def update( self ): self.redraw_canvas() return True def on_draw( self, ctx ): if self.scale > 5: self.scale = 5 ctx.save() ctx.scale( self.scale, self.scale ) # pozadi self.__themeModule.drawBackground( self, ctx ) # ziskame cas foo = str( time.localtime()[3] ) + ':' + str( time.localtime()[4] ) + ':' + str( time.localtime()[5] ) ctx.set_source_rgba( 1, 1, 1 ) # vykreslime cas do hlavni vrstvy self.draw_text( ctx, 'Prave je '+foo, 45, 10, 'FreeSans', 12, 200 ) # druhy cas aktualizujeme pouze, kdyz je vterina suda nebo probiha prvni vykresleni if time.localtime()[5] % 2 == 0 or self.firstDrawing: # vytvoreni nove cairo vrstvy ctxLayer = self.__buffers['time2'].cairo_create() # vyprazdneni (priprava) vrstvy self.clear_cairo_context( ctxLayer ) ctxLayer.set_source_rgba( 1, 1, 1 ) # vykreslime cas do nove vytvorene vrstvy (do bufferu) self.draw_text( ctxLayer, 'Prave je '+foo, 45, 50, 'FreeSans', 12, 200 ) # vzdy vypise buffer time2 ctx.set_source_pixmap( self.__buffers['time2'], 0, 0 ) ctx.paint() ctx.restore() self.firstDrawing = False def on_draw_shape(self, ctx): self.draw_rectangle(ctx, 0, 0, self.width, self.height) if __name__ == "__main__": import screenlets.session screenlets.session.create_session( MyFirstScreenlet )
themes/default/__init__.py
:
def drawBackground( self, ctx ): ctx.save() ctx.set_source_rgba( 0, 0, 0, 0.1 ) self.draw_rounded_rectangle( ctx, 0, 0, 20, self.width, self.height, fill=True ) # ohraniceni ctx.restore()
themes/myNewTheme/__init__.py
:
def drawBackground( self, ctx ): ctx.save() ctx.set_source_rgba( 0, 0, 0, 0.1 ) self.draw_rounded_rectangle( ctx, 0, 0, 20, self.width, self.height, fill=False ) # ohraniceni self.draw_circle( ctx, 5, self.height/2-10, 20, 20 ) # leve kolecko self.draw_circle( ctx, self.width-25, self.height/2-10, 20, 20 ) # prave kolecko self.draw_triangle( ctx, self.width/2-10, self.height-12, 20, 10, fill=True ) # trojuhelnik dole uprostred ctx.restore()
Chtěl bych upozornit na to, že téma si importuji v konstruktoru a handleru on_load_theme
, který se zavolá po inicializaci témata, ale ještě před jeho vykreslením, příkazem self.__themeModule =
__import__( self.theme_name )
. Není to nic složitého, jen si laicky řečeno do připravené proměnné připravím funkce, které v daném tématu jsou. Aby to bylo takto jednoduché, je zařízené v konstruktoru (na řádku 30 a 31), kde si přidáme do pythoní proměnné s adresáři označující moduly náš adresář, který obsahuje všechny témata tohoto Screenletu.
Poté již jen stačí si zavolat určitou funkci, kterou jsme si v našem tématu vytvořili. V tomto příkladě témata využíváme pouze pro pozadí, takže obě témata obsahují funkci drawBackground
, která nám pozadí vykreslí a samozřejmě, že každé téma jinak. Ve funkci jsou dva parametry, self
a ctx
. Parametr self
předáváme proto, abychom mohli využívat všechny metody třídy jako v samotném Screenletu a parametr ctx
proto, abychom mohli malovat. Jednoduše bez cairo vrstvy a metod, které kreslí, bychom toho moc nenamalovali.
V tématech, resp. ve funkcích drawBackground
ještě používám příkazy ctx.save()
a ctx.restore()
. To je proto, abychom si mohli s vrstvou v určitém úseku dělat co chci a poté nemusel vše ručně vracet do původního stavu. Právě kvůli tomu existují tyto metody a první (tedy save
) nám aktuální nastavení cairo vrstvy uloží (barvu, pozici, ..) a druhá (tedy restore
) nastavení opět navrátí zpět podle posledně uložených dat.
Výsledek
Dnes máme dva grafické výsledky, jeden s prvním tématem (default):
![Screenlet témata](https://i.iinfo.cz/images/616/screenlet-temata-1.png)
a druhý s druhým tématem (myNewTheme).
![Screenlet témata](https://i.iinfo.cz/images/616/screenlet-temata-2.png)
Příště
To je pro dnešek vše a příště se podíváme, jak udělat nastavení.