import gtk

VAR_TYPE_BOOLEAN = 0
VAR_TYPE_INTEGER = 1
VAR_TYPE_STRING = 2
VAR_TYPE_PACKED_BIT_BOOLEAN = 3

MOD_HIDE = 1	# hide entry with ****s. eg for passwords

class big_edit_box(gtk.VBox):
	"""
	A gtk.VBox derived widget for editing of specified instance
	variables of a class instance. <-- er
	"""
	def __init__(self, object, varlist):
		# varlist should be a list of tuples of form:
		# ( "var name", "Variable label:", VAR_TYPE_XXX, MOD_WHATEVER | MOD_WHATEVER2, EXTRA1 [, FUNC_ARGS] )
		# EXTRA1 is needed for 'PACKED_BIT_BOOLEAN', where it should be the bitmask
		# on integers, EXTRA1 should be an integer (not enforced) default value if
		# used if the entered value cannot be parsed as an integer

		# Optional:
		# FUNC_ARGS should be a tuple of (function, arguments tuple) if you
		# want a button next to the field. value returned by function
		# placed in the field. Only for type STRING ATM.
		gtk.VBox.__init__(self, spacing=5)
		self.set_border_width(5)

		self.the_varlist = varlist
		self.the_object = object
		self.entry_objects = []

		table = gtk.Table(5, len(varlist))
		table.set_row_spacings(5)
		table.set_col_spacings(5)
		self.pack_start(table, expand=False)

		for x in xrange(0, len(varlist)):
			var_name, var_label, var_type, mods, extra1 = varlist[x][:5]

			if var_type == VAR_TYPE_BOOLEAN:
				# an integer considered either false (==0) or true
				entry_object = gtk.CheckButton(var_label)
				table.attach(entry_object, 3,5, x, x+1)
				if object.__dict__[var_name] == 0:
					entry_object.set_active(False)
				else:
					entry_object.set_active(True)
				entry_object.show()
				self.entry_objects.append(entry_object)
			elif var_type == VAR_TYPE_INTEGER:
				# regular integer
				label = gtk.Label(var_label)
				label.set_justify(gtk.JUSTIFY_LEFT)
				table.attach(label, 0,2, x,x+1)
				label.show()

				entry_object = gtk.Entry()
				# make sure the value is a nice integer. if not then do not set text.
				try:
					int(object.__dict__[var_name])
				except TypeError:
					pass
				else:
					entry_object.set_text(str(object.__dict__[var_name]))
				table.attach(entry_object, 2,5, x,x+1)
				if mods & MOD_HIDE:
					entry_object.set_visibility(False)
				entry_object.show()
				self.entry_objects.append(entry_object)
			elif var_type == VAR_TYPE_STRING:
				# plain string
				label = gtk.Label(var_label)
				label.set_justify(gtk.JUSTIFY_LEFT)
				table.attach(label, 0,2, x,x+1)
				label.show()

				entry_object = gtk.Entry()
				entry_object.set_text(str(object.__dict__[var_name]))
				table.attach(entry_object, 2,5, x,x+1)
				if mods & MOD_HIDE:
					entry_object.set_visibility(False)
				entry_object.show()
				self.entry_objects.append(entry_object)
			elif var_type == VAR_TYPE_PACKED_BIT_BOOLEAN:
				# boolean. bit in 'extra1' bitmask.
				entry_object = gtk.CheckButton(var_label)
				table.attach(entry_object, 3,5, x,x+1)
				if object.__dict__[var_name] & extra1:
					entry_object.set_active(True)
				else:
					entry_object.set_active(False)
				entry_object.show()
				self.entry_objects.append(entry_object)
			# Optional FUNC_ARGS thing for clicky button
			if len(varlist[x]) == 6:
				func_args = varlist[x][5]
				button = gtk.Button("...")
				table.attach(button, 5,6, x,x+1)
				button.connect("clicked", self._func_args_button, (entry_object,)+func_args)
				button.show()
		table.show()

	def _func_args_button(self, _gtk_obj, user_data):
		gtk_entry, function, args = user_data
		thing = apply(function, args)
		if thing != None:
			gtk_entry.set_text(thing)

	def change_object(self, newobj):
		"""
		Update fields for new object.
		"""
		self.the_object = newobj
		
		for i in xrange(0, len(self.the_varlist)):
			var_name, var_label, var_type, mods, extra1 = self.the_varlist[i][:5]

			gtk_object = self.entry_objects[i]
			
			if var_type == VAR_TYPE_BOOLEAN:
				if newobj.__dict__[var_name] == 0:
					gtk_object.set_active(False)
				else:
					gtk_object.set_active(True)
			elif var_type == VAR_TYPE_PACKED_BIT_BOOLEAN:
				if newobj.__dict__[var_name] & extra1:
					gtk_object.set_active(True)
				else:
					gtk_object.set_active(False)
			elif var_type == VAR_TYPE_STRING:
				gtk_object.set_text(str(newobj.__dict__[var_name]))
			elif var_type == VAR_TYPE_INTEGER:
				try:
					int(newobj.__dict__[var_name])
				except TypeError:
					gtk_object.set_text("")
				else:
					gtk_object.set_text(str(newobj.__dict__[var_name]))

	def apply_changes(self):
		"""
		Apply user input to gtk objects to the object thingy.
		"""
		for i in xrange(0, len(self.the_varlist)):
			var_name, var_label, var_type, mods, extra1 = self.the_varlist[i][:5]

			gtk_object = self.entry_objects[i]

			if var_type == VAR_TYPE_BOOLEAN:
				self.the_object.__dict__[var_name] = gtk_object.get_active()
			elif var_type == VAR_TYPE_PACKED_BIT_BOOLEAN:
				if gtk_object.get_active() == True:
					self.the_object.__dict__[var_name] = self.the_object.__dict__[var_name] | extra1
				else:
					self.the_object.__dict__[var_name] = self.the_object.__dict__[var_name] & (~extra1)
			elif var_type == VAR_TYPE_STRING:
				self.the_object.__dict__[var_name] = gtk_object.get_text()
			elif var_type == VAR_TYPE_INTEGER:
				try:
					self.the_object.__dict__[var_name] = int(gtk_object.get_text())
				except ValueError:
					self.the_object.__dict__[var_name] = extra1
					


syntax highlighted by Code2HTML, v. 0.9.1