#-------------------------------------------------------------------------------
# Screenlets - (c) 2007-2009 by RYX (aka Rico Pfaus) <ryx@ryxperience.com> 
#
# with contributions by:
# - Whise (Helder Fraga) <helder.fraga@hotmail.com>
#
#-------------------------------------------------------------------------------

==Developers==


===Screenlets API===
You can find online Api documentation [http://screenlets.org//Documentation/index.html here]

===Submit patch/Improve core===
You can easily submit a patch or help improve the Screenlets core by sending a mail to helder.fraga@hotmail.com.
If you want to help but you dont have ideas you can check out our TODO list [http://bazaar.launchpad.net/~screenlets-dev/screenlets/trunk/files here](Click on the TODO file)


===Where/how can I get the development version?===

The screenlets' sourcecode is hosted on [https://launchpad.net/screenlets launchpad]. You can easily download and install the latest development branch using these commands (you need to install [http://bazaar-vcs.org/ 'bzr'] first):


===Some information about Screenlets===

====Builtin controlers====
Screenlets can be controled using builtin variables , for example , if you want to set the scale of the screenlet just do self.scale = 1,2 , or move it self.x = 10 , this will put the screenlet in x = 10 , this also aplys for scale , width , height etc , you can find all this in the api.

====Drawing====
Screenlets are usually drawn using cairo , but you can also use gtk to add gtk widgets to it , however gtk widgets wont resize the way cairo does , so you need to resize the gtk widgets manually , this may be done using a gtk.Box and setting a border width , then in on_scale event set the border you want

====Theming====
Screenlets themes are very costumizable , you can choose to develop a screenlet themes in 3 diferent ways.
1 - Using the builtin theme controls , using funtions like draw_rectangle , draw_triangle , draw_shadow , draw_line , draw_circle and others.
2 - You can use custom images to generate your themes.
3 - You can use both the above

You can also develop themes in a static way , leaving the buttons , text and other stuff also static , or you can change its position , size etc using a theme override .conf file.

You can take a look at the example screenlet for basic theming , and also the radio screenlet (since 0.1.2) that takes the theming to the max.

===Is it easy to create screenlets?===

Screenlets api is relativly easy , but the easiest way to create a screenlet is to edit a screenlet that is already made , for that you can use the example screenlet , included in the core package , or any other screenlet , because Screenlets is an open source project



===Getting Started===

====File structure====

Your screenlet folder should look like this

Clock/ClockScreenlet.py
Clock/icon.png or icon.svg
Clock/themes/defaut/ (containing the default skin) 

====Sarting the python file====
=====First we do the basic imports=====
<pre>
import screenlets 
from screenlets.options import StringOption , BoolOption , IntOption , FileOption , DirectoryOption , ListOption , AccountOption , TimeOption , FontOption, ColorOption , ImageOption
</pre>

=====We import some more stuff=====
<pre>
import gobject
import gtk
</pre>

=====Lets start the base class =====
<pre>
class ExampleScreenlet (screenlets.Screenlet):
	"""A simple example of how to create a Screenlet"""
</pre>
=====Lets set some global vars =====
<pre>
	__name__	= 'ExampleScreenlet' #Name of the screenlet followed by "Screenlet"
	__version__	= '0.1'
	__author__	= 'My name here'
	__desc__	= __doc__	# set description to docstring of class
</pre>
=====Lets set some other global vars that we need=====
<pre>
	test_text = 'Hi.. im a screenlet'
	demo_text = ''
	demo_number = ''
	int_example = 1
	bool_example = True
	time_example =  (7, 30, 0)
	account_example =  ('','')
	color_example =(0.0, 0.0, 0.0, 1)
	font_example = "Sans Medium 5"
	image_example = ''
	file_example = ''
	directory_example = ''
	list_example = ('','')
	hover = False
</pre>

=====Call super=====
<pre>
	def __init__ (self, **keyword_args):
		screenlets.Screenlet.__init__(self, width=200, height=200, 
			uses_theme=True, **keyword_args)
</pre>

=====Set the default theme=====
<pre>
		self.theme_name = "default"
</pre>

=====Add menu items or configurable settings=====
<pre>
		self.add_options_group('Example', 'This is an example of ' +\
			' editable options within an OptionGroup ...')
		# add editable option to the group
		self.add_option(StringOption('Example','test_text',			# attribute-name
			self.test_text,						# default-value
			'Test-Text', 						# widget-label
			'The Test-Text option for this Screenlet ...'	# description
			))

		self.add_option(BoolOption('Example','bool_example', 
			self.bool_example, 'Option group bool', 
			'Example options group using bool'))

		self.add_option(TimeOption('Example','time_example', self.time_example, 
 			'Option group time', 'Example options group using time'))

		self.add_option(IntOption('Example','int_example', 
			self.int_example, 'Option group integer', 
			'Example options group using integer', 
			min=0, max=5000))

		self.add_option(FontOption('Example','font_example', 
			self.font_example, 'Option group font', 
			'Example options group using font'))

		self.add_option(ColorOption('Example','color_example', 
			self.color_example, 'Option group color', 
			'Example options group using color'))

		self.add_option(AccountOption('Example','account_example',self.account_example,
			'Option group account','Using keyring encryption'))
		self.add_option(ImageOption('Example','image_example', self.image_example, 
			'Option group Image', 'Example options group using Image')) 

		self.add_option(FileOption('Example','file_example', self.file_example, 
			'Option group file', 'Example options group using file')) 

		self.add_option(DirectoryOption('Example','directory_example', self.directory_example, 
			'Option group directory', 'Example options group using directory')) 

		self.add_option(ListOption('Example','list_example', self.list_example, 
			'Option group list', 'Example options group using list')) 
</pre>

=====The event handlers=====

<pre>
	def on_after_set_atribute(self,name, value):
		"""Called after setting screenlet atributes"""
		print name + ' is going to change from ' + str(value)
		pass

	def on_before_set_atribute(self,name, value):
		"""Called before setting screenlet atributes"""
		print name + ' has changed to ' + str(value)
		pass


	def on_create_drag_icon (self):
		"""Called when the screenlet's drag-icon is created. You can supply
		your own icon and mask by returning them as a 2-tuple."""
		return (None, None)

	def on_composite_changed(self):
		"""Called when composite state has changed"""
		pass

	def on_drag_begin (self, drag_context):
		"""Called when the Screenlet gets dragged."""
		pass
	
	def on_drag_enter (self, drag_context, x, y, timestamp):
		"""Called when something gets dragged into the Screenlets area."""
		pass
	
	def on_drag_leave (self, drag_context, timestamp):
		"""Called when something gets dragged out of the Screenlets area."""
		pass

	def on_drop (self, x, y, sel_data, timestamp):
		"""Called when a selection is dropped on this Screenlet."""
		return False
		
	def on_focus (self, event):
		"""Called when the Screenlet's window receives focus."""
		pass
	
	def on_hide (self):
		"""Called when the Screenlet gets hidden."""
		pass
	
	def on_init (self):
		"""Called when the Screenlet's options have been applied and the 
		screenlet finished its initialization. If you want to have your
		Screenlet do things on startup you should use this handler."""
		print 'i just got started'
		# add  menu items from xml file
		self.add_default_menuitems(DefaultMenuItem.XML)
		# add menu item
		self.add_menuitem("at_runtime", "A")
		# add default menu items
		self.add_default_menuitems()


	def on_key_down(self, keycode, keyvalue, event):
		"""Called when a keypress-event occured in Screenlet's window."""
		key = gtk.gdk.keyval_name(event.keyval)
		
		if key == "Return" or key == "Tab":
			screenlets.show_message(self, 'This is the ' + self.__name__ +'\n' + 'It is installed in ' + self.__path__)
	
	def on_load_theme (self):
		"""Called when the theme is reloaded (after loading, before redraw)."""
		pass
	
	def on_menuitem_select (self, id):
		"""Called when a menuitem is selected."""
		if id == "at_runtime":
			screenlets.show_message(self, 'This is an example on a menu created at runtime')
		if id == "at_xml":
			screenlets.show_message(self, 'This is an example on a menu created in the menu.xml')
		pass
	
	def on_mouse_down (self, event):
		"""Called when a buttonpress-event occured in Screenlet's window. 
		Returning True causes the event to be not further propagated."""
	    
		return False
	
	def on_mouse_enter (self, event):
		"""Called when the mouse enters the Screenlet's window."""
	        self.theme.show_tooltip("this is a tooltip , it is set to shows on mouse hover",self.x+self.mousex,self.y+self.mousey)
		self.hover = True
		print 'mouse is over me'
		
	def on_mouse_leave (self, event):
		"""Called when the mouse leaves the Screenlet's window."""
		self.theme.hide_tooltip()
		self.hover = False
		print 'mouse leave'

	def on_mouse_move(self, event):
		"""Called when the mouse moves in the Screenlet's window."""
		self.redraw_canvas()
		pass

	def on_mouse_up (self, event):
		"""Called when a buttonrelease-event occured in Screenlet's window. 
		Returning True causes the event to be not further propagated."""
		return False
	
	def on_quit (self):
		"""Callback for handling destroy-event. Perform your cleanup here!"""
		screenlets.show_question(self, 'Do you like screenlets?')
		return True
		
	def on_realize (self):
		""""Callback for handling the realize-event."""
	
	def on_scale (self):
		"""Called when Screenlet.scale is changed."""
		pass
	
	def on_scroll_up (self):
		"""Called when mousewheel is scrolled up (button4)."""
		pass

	def on_scroll_down (self):
		"""Called when mousewheel is scrolled down (button5)."""
		pass
	
	def on_show (self):
		"""Called when the Screenlet gets shown after being hidden."""
		pass
	
	def on_switch_widget_state (self, state):
		"""Called when the Screenlet enters/leaves "Widget"-state."""
		pass
	
	def on_unfocus (self, event):
		"""Called when the Screenlet's window loses focus."""
		pass
	
	def on_draw (self, ctx):
                """In here we load the theme"""
		# if theme is loaded
		if self.theme:
			# set scale rel. to scale-attribute
			ctx.scale(self.scale, self.scale)
			ctx.set_source_rgba(self.color_example[2], self.color_example[1], self.color_example[0],0.4)	
			if self.hover:
				self.theme.draw_rounded_rectangle(ctx,0,0,20,self.width,self.height)
			self.draw_circle(ctx,0,0,self.width,self.height)
			# TEST: render example-bg into context (either PNG or SVG)
			self.theme.render(ctx, 'example-bg')
			ctx.set_source_rgba( self.color_example[0], self.color_example[1], self.color_example[2],self.color_example[3])
			self.draw_text(ctx, self.test_text, 0, 0, self.font_example , 10,self.width,pango.ALIGN_LEFT)
			self.draw_line(ctx,0,40,self.width,0,1)
			self.draw_text(ctx, 'timer - ' + str(self.number), 0, 130, self.font_example , 10, self.width,pango.ALIGN_LEFT)

			self.draw_text(ctx, self.theme_name, 0, 50, self.font_example , 10, self.width,pango.ALIGN_LEFT)

			self.draw_text(ctx, 'mouse x ' + str(self.mousex ) + ' \n mouse y ' + str(self.mousey ) , 0, 170, self.font_example , 10,self.width,pango.ALIGN_LEFT)


			# render svg-file
			#self.theme['example-bg.svg'].render_cairo(ctx)
			# render png-file
			#ctx.set_source_surface(self.theme['example-test.png'], 0, 0)
			#ctx.paint()
	
	def on_draw_shape (self, ctx):
		self.on_draw(ctx)
</pre>

=====Lets add the screenlet to session=====
<pre>
if __name__ == "__main__":
	# create new session
	import screenlets.session
	screenlets.session.create_session(ExampleScreenlet)
</pre>


=====Builtin drawing funtion=====
<pre>
                        ctx.scale(self.scale, self.scale)
			ctx.set_source_rgba(self.color_example[2], self.color_example[1], self.color_example[0],0.4)	
			if self.hover:
				self.draw_rounded_rectangle(ctx,0,0,20,self.width,self.height)
			self.draw_circle(ctx,0,0,self.width,self.height)
			# TEST: render example-bg into context (either PNG or SVG)
			self.theme.render(ctx, 'example-bg')
			ctx.set_source_rgba( self.color_example[0], self.color_example[1], self.color_example[2],self.color_example[3])
			self.draw_text(ctx, self.test_text, 0, 0, self.font_example , 10,self.width,pango.ALIGN_LEFT)
			self.draw_line(ctx,0,40,self.width,0,1)
			self.draw_text(ctx, 'timer - ' + str(self.number), 0, 130, self.font_example , 10, self.width,pango.ALIGN_LEFT)

			self.draw_text(ctx, self.theme_name, 0, 50, self.font_example , 10, self.width,pango.ALIGN_LEFT)

			self.draw_text(ctx, 'mouse x ' + str(self.mousex ) + ' \n mouse y ' + str(self.mousey ) , 0, 170, self.font_example , 10,self.width,pango.ALIGN_LEFT)


			# render svg-file
			#self.theme['example-bg.svg'].render_cairo(ctx)
			# render png-file
			#ctx.set_source_surface(self.theme['example-test.png'], 0, 0)
			#ctx.paint()
</pre>



===So where do i start?===
i sugest you get the [http://screenlets.org/images/c/c6/Template.tar.gz template] screenlet and start coding from there

===Codding Rules===
  *A Screenlet's classname must end on "Screenlet" (e.g. ClockScreenlet)
  *Not more than 80 chars per line (where possible).
  *Tabs are 4 char-wide "\t"-characters.
  *Classes MUST have a documentation-string.
  *After class-headers's documentation, one separating line.
  *Internal attributes MUST start with TWO leading underscores.
  *Editable options NEVER have leading underscores.
  *All functions that are no inherited event-handlers MUST have a documentation-string.
  *Constructors of Screenlet-subclasses must implement the **keyword_args parameter as last argument to their __init__-function.
  *All screenlet-files MUST have the name of the Screenlet-classes they contain (with a .py-extension).
  *All Screenlets MUST have a head-comment containing license/author note,
  *Screenlets need to be placed into a directory named like the Screenlet's class (without trailing "Screenlet"). This directory may contain a "themes"-directory where the Screenlet's themes are stored. It may also contain other files (of course).
  *Screenlets should supply an icon named "icon.svg" or "icon.png" within their directory.
  *When possible set the width and height of the screenlet matching the background theme image , to avoid confusion
  *Always call super before anything else ... of course
  *Never call exit() or sys.exit().But if you need to check the utils.is_manager_running_me() and only call the exit() if that returns false 

===Avoiding memory leaks===
Old versions of screenlets suffered from memory leaks expecilly in the way they draw text , to avoid this use the built in draw_text function.
Also remember to clean all your variables to avoid memory leaks

===Packaging a screenlet===

use the screenlets-packager tool to package your screenlet for release (e.g.):
  screenlets-packager ~/.screenlets/Weather

===Finding a host for your package===

One suggestion ,post your screenlet on www.gnome-look.org under the screenlet section , gnome-look provides you to upload your content there , so it will remain in their servers forever , and your screenlet will be safe and backed up, then you can post it on www.screenlets.org and provide the download link from gnome-look


