#!/usr/bin/env python3
# Python demo for the Sensoray Model 2263 and 3364
# Copyright(c) 2010-2026 Sensoray Co., Inc.


"""
Python demo for the Sensoray Model 2263, 3364
"""

import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Gdk
import os, ctypes, glob, threading, time, string, sys, socket, re
import pyudev
from threading import Thread
from functools import partial
#USB event handler.
def handle_usb_event(action, device, demo=None):
	vendor_id = str(device.get('ID_VENDOR_ID')).lower()
	model_id = str(device.get('ID_MODEL_ID')).lower()
	TARGET_VID = "1943"
	TARGET_PID = "2263"
	if vendor_id == TARGET_VID and model_id == TARGET_PID:
		if action == 'add':
			print("Sensoray device plugged in!")
			S2263.GetNumDevices()  # just to exercise the function
			while True:
				try:
					print('try open board' + str(board_num))
					demo.brd.Open(board_num)
					print('try open board done' + str(board_num) + str(demo.brd))
					demo.set_device_connected(True)
					demo.redo_setup()
					return
				except IOError as e:
					print(f"io error opening board: {e}")
					continue;
		elif action == 'remove':
			print("remove action.")  # remove event doesn't know vendor id/pid, so we use io-error in the resolution check thread

def start_usb_monitor(demo):
	context = pyudev.Context()
	monitor = pyudev.Monitor.from_netlink(context)
	monitor.filter_by(subsystem='usb')
	custom_callback = partial(handle_usb_event,
				  demo=demo)
	observer = pyudev.MonitorObserver(monitor, custom_callback)
	observer.start()
	print("✨ USB background listener started successfully.")

try:
	import S2263
except OSError as e:
	msg = Gtk.MessageDialog(parent=None,
		modal=True,
		message_type=Gtk.MessageType.ERROR,
		buttons=Gtk.ButtonsType.CLOSE,
		text="Unable to open 'libs2263.so' shared library. Please check README file and run 'make'.")

	msg.show()
	msg.run()
	msg.destroy()
	sys.exit(0)


board_num = 0

for arg in sys.argv:
	if arg == "-d":
		S2263.Debug(1)
	elif arg == "-hd-sdi":
		S2263.AVStreamRename("HD-SDI Grabber")
	elif arg == "-2253":
		S2263.AVStreamRename("Sensoray Model 2253")
	elif arg == "-1":
		board_num = 1
	elif arg == "-2":
		board_num = 2
	elif arg == "-3":
		board_num = 3
	elif arg == "-4":
		board_num = 4
	elif arg == "-5":
		board_num = 5
	elif arg == "-h":
		print("Usage: ./demo.py [-d] [-<n>]\n" +
		      "	 -d   Enable debug information prints\n"+
		      "	 -<n> Select board where <n> is from 1 to 5. (Default board 0)\n")
		
		exit()

def align_value(adj):
	val = int(adj.get_value())
	val -= val % int(adj.get_step_increment())
	adj.set_value(val)
	return val

def enable_controls(controls, en):
	for c in controls:
		c.set_sensitive(en)

def changeExt(path, ext):
	return os.path.splitext(path)[0] + ext

def changeEntryExt(entry, ext):
	entry.set_text(changeExt(entry.get_text(), ext))
	
def setRecordingMode(mode, audModeBox, bitrateBox, jpegBox, faststartBox):
	if mode == S2263.RECMODE_TS or mode == S2263.RECMODE_MP4 or mode == S2263.RECMODE_AVI:
		audModeBox.show()
	else:
		audModeBox.hide()
	if mode == S2263.RECMODE_MJPEG:
		bitrateBox.hide()
		jpegBox.show()
	else:
		bitrateBox.show()
		jpegBox.hide()
	if mode == S2263.RECMODE_MP4 or mode == S2263.RECMODE_MP4_NOAUDIO:
		faststartBox.show()
	else:
		faststartBox.hide()

sock = None
callback = None
isS3364 = 0

def streamCallback(addr, length, devid, strmidx):
	#print "length %d" % (length)
	data = (ctypes.c_char * length).from_address(addr)
	if sock:
		pkt_sz = 1316
		i = 0
		while i+pkt_sz < length:
			try:
				sock.send(data[i:i+pkt_sz])
			except:
				print("Failed socket send. Open receive connection before starting stream.")
				return -1
			i += pkt_sz
		try:
			sock.send(data[i:length])
		except:
			print("Failed socket send. Open receive connection before starting stream.")
			return -1
	return 0


# Resolution thread updates the label every five seconds, 
# or every 1 second after triggering (by changing the input)
class ResolutionThread(threading.Thread):
	def __init__(self, brd, label, demo):
		threading.Thread.__init__(self)
		self.brd = brd
		self.label = label
		self.cond = threading.Condition()
		self.triggered = 5
		self.running = True
		self.demo = demo
	def stop(self):
		self.running = False
		self.trigger()
	def run(self):
		G_is_interlaced = -1
		G_width = -1
		G_height = -1
		isS3364 = self.brd.Is3364()
		isAHD = self.brd.GetNumInputs() == 2
		while self.running:
			self.cond.acquire()
			if self.triggered == 0:
				self.cond.wait(5)
			else:
				self.cond.wait(1)
			self.cond.release()
			if not self.running: return
			
			try:
				locked = self.brd.GetVideoLock()
			except IOError as e:
				if e.errno != 110:
#                   old method of exiting app if board unplugged
#					msg = Gtk.MessageDialog(parent=None,
#					modal=True,
#					message_type=Gtk.MessageType.ERROR,
#					buttons=Gtk.ButtonsType.CLOSE,
#					text="IO error")
#					'self.running = False
#					Gtk.main_quit()
					demo.set_device_connected(False)
					self.brd.Close()
					break
				continue
			if locked:
				info = self.brd.GetVideoInfo()
				w = info["width"]
				h = info["height"]

				if info["interlaced"]:
					info["interlaced"] = "i"
					i = 1
					#demo.interlacedLabel.show()
					#demo.interlacedMenu.show()
				else:
					info["interlaced"] = "p"
					i = 0
					#demo.interlacedLabel.hide()
					#demo.interlacedMenu.hide()
				info["framerate"] /= 1000.0
				if isAHD:
					standard = self.brd.GetAnalogHDStandard()
					if standard == S2263.STANDARD_CVBS:
						info["standard"] = " CVBS"
					elif standard == S2263.STANDARD_AHD:
						info["standard"] = " AHD"
					elif standard == S2263.STANDARD_TVI:
						info["standard"] = " TVI"
					elif standard == S2263.STANDARD_CVI:
						info["standard"] = " CVI"
					else:
						info["standard"] = ""
				else:
					info["standard"] = ""
				
				self.label.set_text("%(width)dx%(height)d%(interlaced)s%(framerate)g%(standard)s" % info)
				self.triggered = 0
				if (isS3364):
					if (i != G_is_interlaced) or (w != G_width) or (h != G_height):
						G_width = w
						G_height = h
						G_is_interlaced = i
						self.brd.Set3364VideoFormat(i, w, h)
			else:
				self.label.set_text("no lock")
				if self.triggered > 0: self.triggered -= 1
			if hasattr(self.demo, 'gpiCheckBox'):
				try:
					self.demo.gpiCheckBox.set_active(self.brd.GetGPI())
				except IOError:
					pass
				
	def trigger(self):
		self.triggered = 10
		self.cond.acquire()
		self.cond.notify()
		self.cond.release()
		
	

class Demo(Gtk.Window):
	def __init__(self):
		self.brd = None
		self.thr = None
		self.window = None

		S2263.GetNumDevices()  # just to exercise the function
		while True:
			try:
				self.brd = S2263.Board(board_num)
			except IOError:
				if self.message_box("Failed to open board", ["Retry", "Quit"]) != 0:
					sys.exit(0)
			else:
				break
#       Start unplug/replug monitor
		start_usb_monitor(self);
		super().__init__(title="Sensoray %d Demo" % (self.brd.GetModelNumber()))
		
		self.stack = Gtk.Stack();
		self.stack.set_transition_type(Gtk.StackTransitionType.CROSSFADE)
		self.add(self.stack)
	
		# disconnected layout screen page
		self.disconnected_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
		self.status_label = Gtk.Label(label="Please plug in device")
		self.disconnected_box.pack_start(self.status_label, True, True, 0)
	
		# actual app layout page
		self.app_panel = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)

		
		# add both pages to the stack
		self.stack.add_named(self.disconnected_box, "no_device")
		self.stack.add_named(self.app_panel, "device_connected")
		
		self.connect("delete_event", self.delete_event)
		self.connect("destroy", self.destroy)
		self.set_border_width(10)
		self.default_stream_ip = None
		self.default_stream_port = None
		self.default_folder = os.getcwd()
		self.brd.RegisterCallback(streamCallback, 0)
		self.app_panel.pack_start(self.setup(0), True, True, 0)
		self.connect("realize", self.on_realize)
		self.show_all()
		self.set_device_connected(True)
		self.thr.start()

	def set_device_connected(self, connected):
		if connected:
			self.stack.set_visible_child_name("device_connected")
		else:
			self.stack.set_visible_child_name("no_device")

	def main(self):
		if self.brd:
			try:
				Gtk.main()
			except:
				pass
			self.brd.Close()
		if self.thr:
			if not self.thr.running:
				msg = Gtk.MessageDialog(parent=self.window,
					modal=True,
					message_type=Gtk.MessageType.ERROR,
					buttons=Gtk.ButtonsType.CLOSE,
					text="Device is disconnected.")
				msg.show()
				msg.run()
				msg.destroy()
			self.thr.stop()

	def delete_event(self, widget, event, data=None):
		return False

	def destroy(self, widget, data=None):
		Gtk.main_quit()

	def message_box(self, text, buttons=None):
		msg = Gtk.MessageDialog(parent=self.window,
			modal=True,
			message_type=Gtk.MessageType.INFO,
			buttons=Gtk.ButtonsType.NONE if buttons else Gtk.ButtonsType.CLOSE,
			text=text)
		for i,b in enumerate(buttons):
			msg.add_button(b, i)
		msg.show()
		result = msg.run()
		msg.destroy()
		return result
	def on_realize(self, widget, data=None):
		#set focus to defaults button. otherwise, "update firmware"
		# button may be the focus and pressing "enter" twice at start
		# causes program to exit and device to enter firmware update
		# unexpectantly
		self.defaultsButton.grab_focus();

	def message_box_yes_no(self, msg):
		msg = Gtk.MessageDialog(parent=self.window,
			modal=True,
			message_type=Gtk.MessageType.INFO,
			buttons=Gtk.ButtonsType.YES_NO,
			text=msg)
		msg.show()
		result = msg.run()
		msg.destroy()
		return result == Gtk.ResponseType.YES
		
	def save_dialog(self, name):
		save = Gtk.FileChooserDialog(
			title="Save Capture As...", 
			parent=self.window, 
			action=Gtk.FileChooserAction.SAVE)
		save.add_buttons(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_SAVE, Gtk.ResponseType.OK)
		save.set_default_response(1)
		save.set_current_name(name)
		if self.default_folder:
			save.set_current_folder(self.default_folder)
		save.show()
		if save.run() == Gtk.ResponseType.OK:
			self.default_folder = save.get_current_folder()
			name = save.get_filename()
		save.destroy()
		return name
	
	def record(self, enableRecord, filename, enableStream, address, port):
		global sock
		global callback
		if enableStream:
			sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
			sock.connect((address, int(port)))
			print(address, " ", port)
			callback = self.brd.RegisterCallback(streamCallback, 0)
		else:
			sock = None
			callback = self.brd.RegisterCallback(None, 0)
		if enableRecord:
			if (os.path.exists(filename) and not self.message_box_yes_no("File exists - overwrite?")):
				return False
			self.brd.StartRecord(filename, 0)
		elif enableStream:
			self.brd.StartCallback(0)
		return True

	def load_user_data(self, userData, data):
		hexData = data
		self.brd.Get3364UserData(userData)
		hexData.set_text("%02x %02x %02x %02x %02x "
			 "%02x %02x %02x %02x %02x" %
			 (ord(userData[0]),ord(userData[1]),
			  ord(userData[2]),ord(userData[3]),
			  ord(userData[4]),ord(userData[5]),
			  ord(userData[6]),ord(userData[7]),
			  ord(userData[8]),ord(userData[9])))
		return True
		
	def set_deint_mode(self, enable, ch, low, high, start, count):
		failed = False
		red = Gdk.RGBA()
		Gdk.RGBA.parse(red, "red")
		try:
			l = int(low.get_text())
			low.override_background_color(Gtk.StateFlags.NORMAL, None)
		except:
			failed = True
			low.override_background_color(Gtk.StateFlags.NORMAL, red)
		try:
			h = int(high.get_text())
			high.override_background_color(Gtk.StateFlags.NORMAL, None)
		except:
			failed = True
			high.override_background_color(Gtk.StateFlags.NORMAL, red)
		try:
			s = int(start.get_text())
			start.override_background_color(Gtk.StateFlags.NORMAL, None)
		except:
			failed = True
			start.override_background_color(Gtk.StateFlags.NORMAL, red)
		try:
			c = int(count.get_text())
			count.override_background_color(Gtk.StateFlags.NORMAL, None)
		except:
			failed = True
			count.override_background_color(Gtk.StateFlags.NORMAL, red)
		if failed:
			return
		try:
			self.brd.SetDeintMode(enable, ch, l, h, s, c)
		except:
			high.override_background_color(Gtk.StateFlags.NORMAL, red)
			

	def save_user_data(self, udata, data):
		hexData = data
		str1 = hexData.get_text();
		entries = re.split("\\s+", str1)
		print(entries)
		for j in xrange(0, 10):
			try:
				udata[j] = chr(string.atoi(entries[j], 16))
			except:
				hexData.set_text("Invalid Hex String. Please re-enter.")
				return False
		try:
			rc1 = self.brd.Set3364UserData(udata)
		except:
			rc1 = False
			
		if (rc1 == True):
			hexData.set_text("Data Saved. Click to reload")
		else:
			hexData.set_text("Data Save Error. Try Again")
		return True
		
	def osd_window(self):
		window = Gtk.Window(title="OSD Controls", parent=self.window)
		window.set_border_width(10)
		window.show()
		

	def setup(self, restart):
		recordControls = []
		brd = self.brd
		
		#Doesn't work in Python3/GTK3
		#Gtk.settings_get_default().set_string_property("gtk-font-name", "Sans 9", "")
	
		vbox = Gtk.VBox(homogeneous=False, spacing=10)
		vbox.show()
		
		row1 = Gtk.HBox(homogeneous=False, spacing=10)
		row1.show()
		vbox.pack_start(row1, False, False, 0)
		
		
		boardFrame = Gtk.Frame(label="Board %d" % board_num)
		boardFrame.show()
		row1.pack_start(boardFrame, False, False, 0)

		boardBox = Gtk.VBox(homogeneous=False, spacing=10)
		boardBox.set_border_width(10)
		boardBox.show()
		boardFrame.add(boardBox)
		
		boardRow = Gtk.HBox(homogeneous=False, spacing=0)
		labelSerial = Gtk.Label(label="Serial: %d" % self.brd.GetSerialNumber())
		labelSerial.set_justify(Gtk.Justification.LEFT)
		labelSerial.show()
		boardBox.pack_start(labelSerial, False, False, 0)
		
		fw_ver = self.brd.GetFirmwareVersion()
		labelFirmware = Gtk.Label(label="Firmware: %d" % fw_ver)
		labelFirmware.set_justify(Gtk.Justification.LEFT)
		labelFirmware.show()
		boardBox.pack_start(labelFirmware, False, False, 0)

		model = self.brd.GetModelNumber()
		numInputs = self.brd.GetNumInputs()
		isS3364 = self.brd.Is3364()
		if isS3364:
			try:
				board_type = self.brd.Get3364BoardType()
				if (board_type == 1):
					labelS3364 = Gtk.Label(label="Model: 3364-SDI")
				else:
					labelS3364 = Gtk.Label(label="Model: 3364-DVI")
			except:
				labelS3364 = Gtk.Label(label="Model: 3364")
		elif model == 3364:
			if self.brd.GetFeatureFlags() & S2263.FLAG_SDI:
				labelS3364 = Gtk.Label(label="Model: 3364-SDI")
			else:
				labelS3364 = Gtk.Label(label="Model: 3364-DVI")
		else:
			labelS3364 = Gtk.Label(label="Model: %d" % model)

		labelS3364.set_justify(Gtk.Justification.LEFT)
		labelS3364.show()
		boardBox.pack_start(labelS3364, False, False, 0)
		
		if isS3364:
			labelUsbSpeed = Gtk.Label(label="USB Speed: %d" % self.brd.Get3364UsbSpeed())
			labelUsbSpeed.set_justify(Gtk.Justification.LEFT)
			labelUsbSpeed.show()
			boardBox.pack_start(labelUsbSpeed, False, False, 0)

		api_ver = self.brd.GetAPIVersion()
		labelAPIVer = Gtk.Label(label="API Ver: %d.%d.%d" % ((api_ver>>16)&0xff, (api_ver>>8)&0xff, api_ver&0xff))
		labelAPIVer.set_justify(Gtk.Justification.LEFT)
		labelAPIVer.show()
		boardBox.pack_start(labelAPIVer, False, False, 0)

		updateFirmwareButton = Gtk.Button(label="Update FW")
		updateFirmwareButton.show()
		boardBox.pack_start(updateFirmwareButton, False, False, 0)
		updateFirmwareButton.connect("clicked",
			lambda button: (
				brd.FirmwareUpdate(),
				self.destroy(button)))
				
		if fw_ver >= 3919:  # GPIO testing
			gpoCheckBox = Gtk.CheckButton(label="GPO")
			gpoCheckBox.set_active(0)
			gpoCheckBox.show()
			boardBox.pack_start(gpoCheckBox, False, False, 0)
			gpoCheckBox.connect("toggled",
				lambda button: (brd.SetGPO(gpoCheckBox.get_active())))
			
			gpiCheckBox = Gtk.CheckButton(label="GPI")
			gpiCheckBox.set_active(0)
			gpiCheckBox.set_sensitive(False)
			gpiCheckBox.show()
			boardBox.pack_start(gpiCheckBox, False, False, 0)
			self.gpiCheckBox = gpiCheckBox

		if fw_ver >= 4115:  # Temperature Robustness
			tempRobustButton = Gtk.Button(label="Temp Robust")
			tempRobustButton.show()
			boardBox.pack_start(tempRobustButton, False, False, 0)
			tempRobustButton.connect("clicked",
				lambda button: (brd.SetTemperatureRobustness()))


		if False:  # Overlay testing
			testOSDButton = Gtk.Button(label="Test OSD")
			testOSDButton.show()
			boardBox.pack_start(testOSDButton, False, False, 0)
			testOSDButton.connect("clicked",
				lambda button: (
					brd.OverlayText("TEST^c^n^d ^t ^c^nHello World!", 
					S2263.OVERLAY_TEXT_FONT_8x14 + S2263.OVERLAY_TEXT_BG_SHADED,
					100, 100, 1),
					brd.OverlayText("^d ^t^nHello World!", 
					S2263.OVERLAY_TEXT_FONT_8x14 + 
					S2263.OVERLAY_TEXT_BG_SHADED,
					100, 100, 0)
					))

			resetFCButton = Gtk.Button(label="Reset Frame Counts")
			resetFCButton.show()
			boardBox.pack_start(resetFCButton, False, False, 0)
			resetFCButton.connect("clicked",
				lambda button: (
					brd.SetFrameCount(0,0),
					brd.SetFrameCount(0,1)
					))

			opt = Gtk.ComboBoxText()
			for s in [
				"MM_DD_YYYY",
				"DD_MM_YYYY",
				"MM_DD_YY",
				"DD_MM_YY",
				"MMM_DD_YYYY",
				"DD_MMM_YYYY",
				"MMM_DD_YY",
				"DD_MMM_YY",
				"MMM_DDc_YYYY",
				"DDMMMYYYY",
				"MMM_DDc_YY",
				"DDMMMYY",
				"YYYYMMDD",
				"YYYYMMMDD",
				"YYMMDD",
				"YYMMMDD",
				"YYYY_MM_DD",
				"YYYY_MMM_DD",
				"YY_MM_DD",
				"YY_MMM_DD",
				]:
				opt.append_text(s)
			DateOpts = [
				S2263.OVERLAY_TEXT_DATE_MM_DD_YYYY,
				S2263.OVERLAY_TEXT_DATE_DD_MM_YYYY,
				S2263.OVERLAY_TEXT_DATE_MM_DD_YY,
				S2263.OVERLAY_TEXT_DATE_DD_MM_YY,
				S2263.OVERLAY_TEXT_DATE_MMM_DD_YYYY,
				S2263.OVERLAY_TEXT_DATE_DD_MMM_YYYY,
				S2263.OVERLAY_TEXT_DATE_MMM_DD_YY,
				S2263.OVERLAY_TEXT_DATE_DD_MMM_YY,
				S2263.OVERLAY_TEXT_DATE_MMM_DDc_YYYY,
				S2263.OVERLAY_TEXT_DATE_DDMMMYYYY,
				S2263.OVERLAY_TEXT_DATE_MMM_DDc_YY,
				S2263.OVERLAY_TEXT_DATE_DDMMMYY,
				S2263.OVERLAY_TEXT_DATE_YYYYMMDD,
				S2263.OVERLAY_TEXT_DATE_YYYYMMMDD,
				S2263.OVERLAY_TEXT_DATE_YYMMDD,
				S2263.OVERLAY_TEXT_DATE_YYMMMDD,
				S2263.OVERLAY_TEXT_DATE_YYYY_MM_DD,
				S2263.OVERLAY_TEXT_DATE_YYYY_MMM_DD,
				S2263.OVERLAY_TEXT_DATE_YY_MM_DD,
				S2263.OVERLAY_TEXT_DATE_YY_MMM_DD,
				]
			opt.connect("changed",
				lambda cb: (
					brd.OverlayText("TEST^c^n^d ^t ^c^nHello World!", 
					S2263.OVERLAY_TEXT_FONT_8x14 + S2263.OVERLAY_TEXT_BG_SHADED + 
					S2263.OVERLAY_TEXT_HOURS_MINUTES_A_P + #S2263.OVERLAY_TEXT_SECONDS_THOUSANDTHS +
					DateOpts[cb.get_active()],
					100, 100, 1),
				))
			opt.show()
			opt.set_active(brd.GetFlip(0))
			boardBox.pack_start(opt, False, False, 0)
			brd.SetClock()

		
#		overlaysButton = Gtk.Button(label="Overlays")
#		overlaysButton.show()
#		boardBox.pack_start(overlaysButton, False, False, 0)
#		overlaysButton.connect("clicked",
#			lambda button:
#				True)

	
		vidInputFrame = Gtk.Frame()
		vidInputFrame.set_label("Video Input")
		vidInputFrame.show()
		row1.pack_start(vidInputFrame, False, False, 0)
		
		vidInputBox = Gtk.VBox(homogeneous=False, spacing=0)
		vidInputBox.set_border_width(10)
		vidInputBox.show()
		vidInputFrame.add(vidInputBox)
		vidInput = brd.GetInput()
		
		
		if model == 2253:
			vidInputCVideo = Gtk.RadioButton.new_with_label_from_widget(None, "Composite")
			vidInputCVideo.set_active(vidInput == S2263.VIDEO_COMPOSITE)
			vidInputCVideo.connect("toggled",
				lambda button: vidInputCVideo.get_active()
					and brd.SetInput(S2263.VIDEO_COMPOSITE))
			vidInputCVideo.show()
			vidInputBox.pack_start(vidInputCVideo, False, False, 0)
			recordControls.append(vidInputCVideo)
			
		elif numInputs == 1:
			vidInputSDI = Gtk.RadioButton.new_with_label_from_widget(None, "SDI")
			vidInputSDI.set_active(vidInput == S2263.VIDEO_SDI)
			vidInputSDI.connect("toggled",
				lambda button: vidInputSDI.get_active()
					and brd.SetInput(S2263.VIDEO_SDI))
			vidInputSDI.show()
			vidInputBox.pack_start(vidInputSDI, False, False, 0)
			recordControls.append(vidInputSDI)
			vidInputDVI = vidInputSDI # For switching to analog audio
			
		elif model == 2231:
			vidInputAHD1 = Gtk.RadioButton.new_with_label_from_widget(None, "IN1")
			vidInputAHD1.set_active(vidInput == S2263.VIDEO_AHD1)
			vidInputAHD1.connect("toggled",
				lambda button: vidInputAHD1.get_active()
					and brd.SetInput(S2263.VIDEO_AHD1))
			vidInputAHD1.show()
			vidInputBox.pack_start(vidInputAHD1, False, False, 0)
			recordControls.append(vidInputAHD1)

			vidInputAHD2 = Gtk.RadioButton.new_with_label_from_widget(vidInputAHD1, "IN2")
			vidInputAHD2.set_active(vidInput == S2263.VIDEO_AHD2)
			vidInputAHD2.connect("toggled",
				lambda button: vidInputAHD2.get_active()
					and brd.SetInput(S2263.VIDEO_AHD2))
			vidInputAHD2.show()
			vidInputBox.pack_start(vidInputAHD2, False, False, 0)
			recordControls.append(vidInputAHD2)
			
		else:
		
			vidInputDVI = Gtk.RadioButton.new_with_label_from_widget(None, "DVI-D")
			vidInputDVI.set_active(vidInput == S2263.VIDEO_DVI)
			vidInputDVI.connect("toggled",
				lambda button: vidInputDVI.get_active()
					and brd.SetInput(S2263.VIDEO_DVI))
			vidInputDVI.show()
			vidInputBox.pack_start(vidInputDVI, False, False, 0)
			recordControls.append(vidInputDVI)

			vidInputCVideo = Gtk.RadioButton.new_with_label_from_widget(vidInputDVI, "Composite")
			vidInputCVideo.set_active(vidInput == S2263.VIDEO_COMPOSITE)
			vidInputCVideo.connect("toggled",
				lambda button: vidInputCVideo.get_active()
					and brd.SetInput(S2263.VIDEO_COMPOSITE))
			vidInputCVideo.show()
			vidInputBox.pack_start(vidInputCVideo, False, False, 0)
			recordControls.append(vidInputCVideo)

			vidInputComp = Gtk.RadioButton.new_with_label_from_widget(vidInputDVI, "Component")
			vidInputComp.set_active(vidInput == S2263.VIDEO_COMPONENT)
			vidInputComp.connect("toggled",
				lambda button: vidInputComp.get_active()
					and brd.SetInput(S2263.VIDEO_COMPONENT))
			vidInputComp.show()
			vidInputBox.pack_start(vidInputComp, False, False, 0)
			recordControls.append(vidInputComp)

			vidInputVGA = Gtk.RadioButton.new_with_label_from_widget(vidInputDVI, "VGA")
			vidInputVGA.set_active(vidInput == S2263.VIDEO_VGA)
			vidInputVGA.connect("toggled",
				lambda button: vidInputVGA.get_active()
					and brd.SetInput(S2263.VIDEO_VGA))
			vidInputVGA.show()
			vidInputBox.pack_start(vidInputVGA, False, False, 0)
			recordControls.append(vidInputVGA)
                        
			if numInputs == 6:
			        vidInputSDI = Gtk.RadioButton.new_with_label_from_widget(vidInputDVI, "SDI")
			        vidInputSDI.set_active(vidInput == S2263.VIDEO_SDI2)
			        vidInputSDI.connect("toggled",
				        lambda button: vidInputSDI.get_active()
					        and brd.SetInput(S2263.VIDEO_SDI2))
			        vidInputSDI.show()
			        vidInputBox.pack_start(vidInputSDI, False, False, 0)
			        recordControls.append(vidInputSDI)
                        
		
		#vidInputResolutionFrame = Gtk.Frame("Current Mode")
		#vidInputResolutionFrame.show()

		
		labelInputResolution = Gtk.Label(label="Current Mode:");
		labelInputResolution.set_justify(Gtk.Justification.LEFT)
		labelInputResolution.show()
		vidInputBox.pack_start(labelInputResolution, False, False, 5)
		#vidInputBox.pack_start(vidInputResolutionFrame, False, False, 5)
		
		labelShowResolution = Gtk.Label(label="");
		self.labelShowResolution = labelShowResolution
		labelShowResolution.show()
		vidInputBox.pack_start(labelShowResolution, False, False, 0)
		#vidInputResolutionFrame.add(labelShowResolution)
		if (restart != 1):
			self.thr = ResolutionThread(brd, self.labelShowResolution, self)
		audFlipBox = Gtk.VBox(homogeneous=False, spacing=10)
		audFlipBox.set_border_width(0)
		audFlipBox.show()
		row1.pack_start(audFlipBox, False, False, 0)

		audInputFrame = Gtk.Frame()
		audInputFrame.set_label("Audio Input")
		audInputFrame.show()
		audFlipBox.pack_start(audInputFrame, False, False, 0)

		audInputBox = Gtk.VBox(homogeneous=False, spacing=0)
		audInputBox.set_border_width(10)
		audInputBox.show()
		audInputFrame.add(audInputBox)

		audInput = brd.GetAudioInput()

		if model == 2271:
			audInputDigital = Gtk.RadioButton.new_with_label_from_widget(None, "Digital")
			audInputDigital.connect("toggled",
				lambda button: audInputDigital.get_active() and
					brd.SetAudioInput(S2263.AUDIO_DIGITAL))
			audInputDigital.set_active(audInput == S2263.AUDIO_DIGITAL)
			audInputDigital.set_sensitive(True)
			audInputDigital.show()
			audInputBox.pack_start(audInputDigital, False, False, 0)
			recordControls.append(audInputDigital)
                
		elif model != 2231:
			audInputDigital = Gtk.RadioButton.new_with_label_from_widget(None, "Digital")
			audInputDigital.connect("toggled",
				lambda button: audInputDigital.get_active() and
					brd.SetAudioInput(S2263.AUDIO_DIGITAL))
			audInputDigital.set_active(audInput == S2263.AUDIO_DIGITAL)
			audInputDigital.set_sensitive(vidInputDVI.get_active())
			audInputDigital.show()
			audInputBox.pack_start(audInputDigital, False, False, 0)
			recordControls.append(audInputDigital)

			audInputAnalog = Gtk.RadioButton.new_with_label_from_widget(audInputDigital, "Line in")
			audInputAnalog.connect("toggled",
				lambda button: audInputAnalog.get_active() and
					brd.SetAudioInput(S2263.AUDIO_ANALOG))
			audInputAnalog.set_active(audInput == S2263.AUDIO_ANALOG)
			audInputAnalog.show()
			audInputBox.pack_start(audInputAnalog, False, False, 0)
			recordControls.append(audInputAnalog)

			if model != 2263:
				audInputMic = Gtk.RadioButton.new_with_label_from_widget(audInputDigital, "Mic")
				audInputMic.connect("toggled",
					lambda button: audInputMic.get_active() and
						brd.SetAudioInput(S2263.AUDIO_MIC))
				audInputMic.set_active(audInput == S2263.AUDIO_MIC)
				audInputMic.show()
				audInputBox.pack_start(audInputMic, False, False, 0)
				recordControls.append(audInputMic)

			self.SetInput = lambda idx: (
				brd.SetInput(idx),
				self.thr.trigger(),
				audInputDigital.set_sensitive(vidInputDVI.get_active()),
				audInputDigital.set_active(vidInputDVI.get_active()),
				audInputAnalog.set_active(not vidInputDVI.get_active()))
		else:
			audInputLine = Gtk.RadioButton.new_with_label_from_widget(None, "Line in")
			audInputLine.connect("toggled",
				lambda button: audInputLine.get_active() and
					brd.SetAudioInput(S2263.AUDIO_LINE_IN))
			audInputLine.set_active(audInput == S2263.AUDIO_LINE_IN)
			audInputLine.show()
			audInputBox.pack_start(audInputLine, False, False, 0)
			recordControls.append(audInputLine)

			audInputMic = Gtk.RadioButton.new_with_label_from_widget(audInputLine, "Mic")
			audInputMic.connect("toggled",
				lambda button: audInputMic.get_active() and
					brd.SetAudioInput(S2263.AUDIO_MIC))
			audInputMic.set_active(audInput == S2263.AUDIO_MIC)
			audInputMic.show()
			audInputBox.pack_start(audInputMic, False, False, 0)
			recordControls.append(audInputMic)
		
			self.SetInput = lambda idx: (
				brd.SetInput(idx),
				self.thr.trigger())
		
		if model != 2271:
			audGainFrame = Gtk.Frame()
			audGainFrame.set_label("Audio Gain")
			audGainFrame.show()
			audFlipBox.pack_start(audGainFrame, True, True, 0)

			audGainBox = Gtk.VBox(homogeneous=False, spacing=10)
			audGainBox.set_border_width(10)
			audGainBox.show()
			audGainFrame.add(audGainBox)

			gain = self.brd.GetAudioGain()

			gainAdjustment = Gtk.Adjustment(value=gain[1], lower=0, upper=119, step_increment=1, page_size=1)
			gainScale = Gtk.HScale(adjustment=gainAdjustment)
			gainScale.set_digits(0)
			gainScale.set_value_pos(Gtk.PositionType.LEFT)
			gainScale.set_size_request(100, -1)
			gainScale.show()
			audGainBox.pack_start(gainScale, False, False, 0)

			agcCheckBox = Gtk.CheckButton(label="AGC")
			agcCheckBox.set_active(gain[0] == 1)
			agcCheckBox.show()
			audGainBox.pack_start(agcCheckBox, False, False, 0)

			gainAdjustment.connect("value-changed",
				lambda adj: (brd.SetAudioGain(agcCheckBox.get_active(), align_value(gainAdjustment))))

			agcCheckBox.connect("toggled",
				lambda button: (brd.SetAudioGain(agcCheckBox.get_active(), align_value(gainAdjustment))))


		levelsFrame = Gtk.Frame()
		levelsFrame.set_label("Levels")
		levelsFrame.show()
		row1.pack_start(levelsFrame, True, True, 0)
		
		levelsRow = Gtk.HBox(homogeneous=False, spacing=10)
		levelsRow.set_border_width(10)
		levelsRow.show()
		levelsFrame.add(levelsRow)
		
		levelsBox = Gtk.VBox(homogeneous=False, spacing=0)
		levelsBox.show()
		levelsRow.pack_start(levelsBox, True, True, 0)
		
		brightnessBox = Gtk.HBox(homogeneous=False, spacing=10)
		brightnessBox.show()
		levelsBox.pack_start(brightnessBox, False, False, 0)
		
		brightnessLabel = Gtk.Label(label="Brightness:")
		brightnessLabel.show()
		brightnessBox.pack_start(brightnessLabel, False, False, 0)
		
		brightnessAdjustment = Gtk.Adjustment(value=brd.GetLevel(S2263.BRIGHTNESS), lower=0, upper=255, step_increment=1, page_increment=1)
		brightnessAdjustment.connect("value-changed",
			lambda adj: brd.SetLevel(S2263.BRIGHTNESS, align_value(adj)))
		brightnessScale = Gtk.HScale(adjustment=brightnessAdjustment)
		brightnessScale.set_digits(0)
		brightnessScale.set_value_pos(Gtk.PositionType.LEFT)
		brightnessScale.set_size_request(100, -1)
		brightnessScale.show()
		brightnessBox.pack_start(brightnessScale, True, True, 0)


		contrastBox = Gtk.HBox(homogeneous=False, spacing=10)
		contrastBox.show()
		levelsBox.pack_start(contrastBox, False, False, 0)
	
		contrastLabel = Gtk.Label(label="Contrast:")
		contrastLabel.show()
		contrastBox.pack_start(contrastLabel, False, False, 0)
		
		contrastAdjustment = Gtk.Adjustment(value=brd.GetLevel(S2263.CONTRAST), lower=0, upper=255, step_increment=1, page_increment=1)
		contrastAdjustment.connect("value-changed",
			lambda adj: brd.SetLevel(S2263.CONTRAST, align_value(adj)))
		contrastScale = Gtk.HScale(adjustment=contrastAdjustment)
		contrastScale.set_digits(0)
		contrastScale.set_value_pos(Gtk.PositionType.LEFT)
		contrastScale.set_size_request(100, -1)
		contrastScale.show()
		contrastBox.pack_start(contrastScale, True, True, 0)
		

		hueBox = Gtk.HBox(homogeneous=False, spacing=10)
		hueBox.show()
		levelsBox.pack_start(hueBox, False, False, 0)

		hueLabel = Gtk.Label(label="Hue:")
		hueLabel.show()
		hueBox.pack_start(hueLabel, False, False, 0)
		
		hueAdjustment = Gtk.Adjustment(value=brd.GetLevel(S2263.HUE), lower=-128, upper=127, step_increment=1, page_increment=1)
		hueAdjustment.connect("value-changed",
			lambda adj: brd.SetLevel(S2263.HUE, align_value(adj)))
		hueScale = Gtk.HScale(adjustment=hueAdjustment)
		hueScale.set_digits(0)
		hueScale.set_value_pos(Gtk.PositionType.LEFT)
		hueScale.set_size_request(100, -1)
		hueScale.show()
		hueBox.pack_start(hueScale, True, True, 0)


		saturationBox = Gtk.HBox(homogeneous=False, spacing=10)
		saturationBox.show()
		levelsBox.pack_start(saturationBox, False, False, 0)

		saturationLabel = Gtk.Label(label="Saturation:")
		saturationLabel.show()
		saturationBox.pack_start(saturationLabel, False, False, 0)
		
		saturationAdjustment = Gtk.Adjustment(value=brd.GetLevel(S2263.SATURATION), lower=0, upper=255, step_increment=1, page_increment=1)
		saturationAdjustment.connect("value-changed",
			lambda adj: brd.SetLevel(S2263.SATURATION, align_value(adj)))
		saturationScale = Gtk.HScale(adjustment=saturationAdjustment)
		saturationScale.set_digits(0)
		saturationScale.set_value_pos(Gtk.PositionType.LEFT)
		saturationScale.set_size_request(100, -1)
		saturationScale.show()
		saturationBox.pack_start(saturationScale, True, True, 0)
		

		defaultsBox = Gtk.HBox(homogeneous=False, spacing=10)
		defaultsBox.show()
		levelsBox.pack_start(defaultsBox, False, False, 0)
		
		defaultsButton = Gtk.Button(label="Reset Defaults")
		defaultsButton.connect("clicked",
			lambda button: (
				brightnessAdjustment.set_value(S2263.DEF_BRIGHTNESS),
				contrastAdjustment.set_value(S2263.DEF_CONTRAST),
				hueAdjustment.set_value(S2263.DEF_HUE),
				saturationAdjustment.set_value(S2263.DEF_SATURATION)
			))
		defaultsButton.show()
		self.defaultsButton = defaultsButton
		defaultsBox.pack_start(defaultsButton, True, False, 0)
		
		
		flipLabel = Gtk.Label(label="Video Flip:")
		flipLabel.show()
		defaultsBox.pack_start(flipLabel, False, False, 0)

		
		#opt = Gtk.OptionMenu()
		#menu = Gtk.Menu()
		#menu.append(make_menu_item("None", 
		#	lambda menu: [brd.SetFlip(0, 0), brd.SetFlip(0, 1)]))
		#menu.append(make_menu_item("Horizontal", 
		#	lambda menu: [brd.SetFlip(S2263.FLIP_H, 0), brd.SetFlip(S2263.FLIP_H, 1)]))
		#menu.append(make_menu_item("Vertical", 
		#	lambda menu: [brd.SetFlip(S2263.FLIP_V, 0), brd.SetFlip(S2263.FLIP_V, 1)]))
		#menu.append(make_menu_item("Rotate 180", 
		#	lambda menu: [brd.SetFlip(S2263.ROT_180, 0), brd.SetFlip(S2263.ROT_180, 1)]))
		#opt.set_menu(menu);
		#opt.set_active(brd.GetFlip(0))
		
		opt = Gtk.ComboBoxText()
		for s in ["None","Horizontal","Vertical","Rotate 180"]:
			opt.append_text(s)
		FlipOpts = [0, S2263.FLIP_H, S2263.FLIP_V, S2263.ROT_180]
		opt.connect("changed",
			lambda cb: (
				brd.SetFlip(FlipOpts[cb.get_active()], 0),
				brd.SetFlip(FlipOpts[cb.get_active()], 1)
			))
		opt.show()
		opt.set_active(brd.GetFlip(0))
		opt.set_border_width(10)
		defaultsBox.pack_start(opt, False, False, 0)

		if (isS3364) :
			hdPreviewFrame = Gtk.Frame()
			hdPreviewFrame.set_label("HD Preview")
			hdPreviewFrame.show()
			vbox.pack_start(hdPreviewFrame, False, False, 0)

			hdPreviewBox = Gtk.HBox(homogeneous=False, spacing=10)
			hdPreviewBox.set_border_width(10)
			hdPreviewBox.show()
			hdPreviewFrame.add(hdPreviewBox)
		
			hdPreviewStartButton = Gtk.Button(label="Start")
			hdPreviewStartButton.show()
			hdPreviewBox.pack_start(hdPreviewStartButton, False, False, 0)
		
			hdPreviewStopButton = Gtk.Button(label="Stop")
			hdPreviewStopButton.show()
			hdPreviewStopButton.set_sensitive(False);		
			hdPreviewBox.pack_start(hdPreviewStopButton, False, False, 0)

			hdPreviewLabel = Gtk.Label(label="Interlaced Preview Mode(1080i only):")
			hdPreviewLabel.show()
			hdPreviewBox.pack_start(hdPreviewLabel, False, False, 0)
			

			hdPreviewInterlacedOpt = Gtk.ComboBoxText()
			for s in ["Interlaced","Top","Bottom","Sequential TB"]:
				hdPreviewInterlacedOpt.append_text(s)
			hdPreviewOpts = [S2263.S3364_INTERLACED, S2263.S3364_TOP_FIELD,
					S2263.S3364_BOTTOM_FIELD, S2263.S3364_FIELD_SEQ_TB]
			hdPreviewInterlacedOpt.connect("changed", lambda cb: (
				brd.Set3364HDPreviewMode(hdPreviewOpts[cb.get_active()])
				))
			hdPreviewInterlacedOpt.set_active(brd.GetInterlaceMode(1));
			hdPreviewInterlacedOpt.show()
			hdPreviewBox.pack_start(hdPreviewInterlacedOpt, False, False, 0)

			hdPreviewControls = [
				hdPreviewStartButton, 
				hdPreviewInterlacedOpt]
			
			hdPreviewStartButton.connect("clicked",
				lambda button, ctrls: (
					brd.Start3364FullSizePreview(),
					enable_controls(ctrls, False),
					hdPreviewStopButton.set_sensitive(True)),
					hdPreviewControls)

			hdPreviewStopButton.connect("clicked", 
				lambda button, ctrls: (
					brd.Stop3364FullSizePreview(),
					enable_controls(ctrls, True),
					hdPreviewStopButton.set_sensitive(False)),
					hdPreviewControls)

		
		#
		# Preview --------------------------------------------------------
		#
			
		previewFrame = Gtk.Frame()
		previewFrame.set_label("Preview")
		previewFrame.show()
		vbox.pack_start(previewFrame, False, False, 0)
		
		previewBox = Gtk.HBox(homogeneous=False, spacing=10)
		previewBox.set_border_width(10)
		previewBox.show()
		previewFrame.add(previewBox)
		
		previewStartButton = Gtk.Button(label="Start")
		previewStartButton.show()
		previewBox.pack_start(previewStartButton, False, False, 0)
		
		previewStopButton = Gtk.Button(label="Stop")
		previewStopButton.show()
		previewStopButton.set_sensitive(False);		
		previewBox.pack_start(previewStopButton, False, False, 0)
		
		imagesizeLabel = Gtk.Label(label="Image Size:")
		imagesizeLabel.show()
		previewBox.pack_start(imagesizeLabel, False, False, 0)
		
		previewSizeOpt = Gtk.ComboBoxText()
		img_size = brd.GetImageSize(1)
		if img_size == (768, 576):
			img_size = (640, 480)
			brd.SetImageSize(640, 480, 1)
		elif img_size == (1920,1200):
			img_size = (1920,1080)
			brd.SetImageSize(1920, 1080, 1)
		if model == 2273:
			previewSizeOpts = [(1920,1200),(1920,1080),(1280,720),(768,576),(720,576),(720,480),(720,405),(640,480),(640,360),(320,240),(320,180)]
		else:
			previewSizeOpts = [(768,576),(720,576),(720,480),(720,405),(640,480),(640,360),(320,240),(320,180)]
		if not img_size in previewSizeOpts:
			previewSizeOpts.append(img_size)
		for w,h in previewSizeOpts:
			previewSizeOpt.append_text("%dx%d" % (w,h))
		previewSizeOpt.connect("changed", lambda cb: (
			brd.SetImageSize(
				previewSizeOpts[cb.get_active()][0],
				previewSizeOpts[cb.get_active()][1],
				1)))
		#for w,h in [(1280,720),(1920,1080)]:
		#	menu.append(make_menu_item("%dx%d" % (w,h),
		#		(lambda x, y: lambda menu: brd.SetImageFormat(S2263.FORMAT_NV12, x, y, 1))(w,h)))
		#	if w == img_size[0] and h == img_size[1]:
		#		index = len(menu.get_children())-1
		previewSizeOpt.set_active(previewSizeOpts.index(img_size))
		previewSizeOpt.show()
		previewBox.pack_start(previewSizeOpt, False, False, 0)
		
		previewInterlacedOpt = Gtk.ComboBoxText()
		for s in ["Interpolated","Interlaced","Top","Bottom",
			  "Interlaced","Sequential TB","Sequential BT",
			  "Alternate","Interlaced TB","Interlaced BT"]:
			previewInterlacedOpt.append_text(s)
		previewInterlacedOpts = [S2263.INTERPOLATED,S2263.INTERLACED,S2263.FIELD_TOP,S2263.FIELD_BOTTOM,
					 S2263.FIELD_INTERLACED,S2263.FIELD_SEQ_TB,S2263.FIELD_SEQ_BT,
					 S2263.FIELD_ALTERNATE,S2263.FIELD_INTERLACED_TB,S2263.FIELD_INTERLACED_BT]
		previewInterlacedOpt.connect("changed", lambda cb: (
			brd.SetInterlaceMode(previewInterlacedOpts[cb.get_active()], 1)))
		previewInterlacedOpt.set_active(previewInterlacedOpts.index(brd.GetInterlaceMode(1)));
		previewInterlacedOpt.show()
		previewBox.pack_start(previewInterlacedOpt, False, False, 0)
		
		previewControls = [
			previewStartButton, 
			previewSizeOpt,
			previewInterlacedOpt]


#		try:
#			slicemodeLabel = Gtk.Label(label="Slice Mode:")
#			slicemodeLabel.show()
#
#			opt = Gtk.OptionMenu()
#			menu = Gtk.Menu()
#			menu.append(make_menu_item("Off",
#				lambda menu: brd.SetSliceMode(S2263.SLICEMODE_OFF, 1)))
#			menu.append(make_menu_item("On",
#				lambda menu: brd.SetSliceMode(S2263.SLICEMODE_ON, 1)))
#			opt.set_menu(menu)
#		
#			opt.set_active(brd.GetSliceMode(1));
#			opt.show()
#			previewBox.pack_start(slicemodeLabel, False, False, 0)
#			previewBox.pack_start(opt, False, False, 0)
#			previewControls.append(opt)
#		except:
#			pass # older firmware may not have slice mode
		
		
		previewAudio = Gtk.CheckButton(label="Audio")
		previewAudio.set_active(False)
		previewAudio.show()
		previewBox.pack_start(previewAudio, False, False, 0)
		previewControls.append(previewAudio)
		
		
		previewStartButton.connect("clicked",
			lambda button, ctrls: (
				brd.StartPreview(1),
				previewAudio.get_active() and brd.StartAudioPreview(),
				enable_controls(ctrls, False),
				previewStopButton.set_sensitive(True)),
			previewControls)

		previewStopButton.connect("clicked", 
			lambda button, ctrls: (
				brd.StopPreview(1),
				brd.StopAudioPreview(),
				enable_controls(ctrls, True),
				previewStopButton.set_sensitive(False)),
			previewControls)

		#
		# Record/Stream --------------------------------------------------------
		#

		recordFrame = Gtk.Frame()
		recordFrame.set_label("Record/Stream")
		recordFrame.show()
		vbox.pack_start(recordFrame, False, False, 0)


		recordFrameBox = Gtk.HBox(homogeneous=False, spacing=30)
		recordFrameBox.set_border_width(10)
		recordFrameBox.show()
		recordFrame.add(recordFrameBox)
		
		recordBox = Gtk.VBox(homogeneous=False, spacing=10)
		recordBox.show()
		recordFrameBox.pack_start(recordBox, True, True, 0)
		
		controlBox = Gtk.HBox(homogeneous=False, spacing=10)
		controlBox.show()
		recordBox.pack_start(controlBox, False, False, 0)
		
		recordStartButton = Gtk.Button(label="Start")
		recordStartButton.show()
		controlBox.pack_start(recordStartButton, False, False, 0)
		recordControls.append(recordStartButton)
		
		recordStopButton = Gtk.Button(label="Stop")
		recordStopButton.show()
		recordStopButton.set_sensitive(False)
		controlBox.pack_start(recordStopButton, False, False, 0)
		
		recordStartButton.connect("clicked", 
			lambda button, ctrls: self.record(
				recordCheckBox.get_active(),
				recordFilename.get_text(),
				streamCheckBox.get_active(),
				streamAddress.get_text(),
				streamPort.get_text()) and
				(enable_controls(ctrls, False),
				recordStopButton.set_sensitive(True)), 
			recordControls)
		recordStopButton.connect("clicked", 
			lambda button, ctrls: (
				brd.StopRecord(0),
				enable_controls(ctrls, True),
				recordStopButton.set_sensitive(False)),
			recordControls)
		# solves strange bug when stopping, where only stream is checked
		#NameError: free variable 'recordStopButton' referenced before assignment in enclosing scope
		self.recordStopButton = recordStopButton
		self.recordStartButton = recordStartButton
		self.previewStopButton = previewStopButton
		self.previewStartButton = previewStartButton
		self.previewAudio = previewAudio

		filenameBox = Gtk.HBox(homogeneous=False, spacing=10)
		streamBox = Gtk.HBox(homogeneous=False, spacing=10)
		
		recordCheckBox = Gtk.CheckButton(label="Record")
		recordCheckBox.show()
		recordCheckBox.set_active(True)
		controlBox.pack_start(recordCheckBox, False, False, 0)
		recordControls.append(recordCheckBox)
		recordCheckBox.connect("toggled",
			lambda button: (
				(recordCheckBox.get_active() and filenameBox.show()),
				(not recordCheckBox.get_active() and filenameBox.hide()),
				recordStartButton.set_sensitive(
					recordCheckBox.get_active() or streamCheckBox.get_active())))
				
		
		streamCheckBox = Gtk.CheckButton(label="Stream")
		streamCheckBox.show()
		controlBox.pack_start(streamCheckBox, False, False, 0)
		recordControls.append(streamCheckBox)
		streamCheckBox.connect("toggled",
			lambda button: (
				(streamCheckBox.get_active() and streamBox.show()),
				(not streamCheckBox.get_active() and streamBox.hide()),
				recordStartButton.set_sensitive(
					recordCheckBox.get_active() or streamCheckBox.get_active())))

		defaultsButton = Gtk.Button(label="Snapshot")
		defaultsButton.connect("clicked",
			lambda button: (
				brd.Snapshot("snapshot.jpg", 0)
			))


		if recordCheckBox.get_active():
			filenameBox.show()
		else:
			filenameBox.hide()
		recordBox.pack_start(filenameBox, True, True, 0)
		
		filenameLabel = Gtk.Label(label="Record Filename:")
		filenameLabel.show()
		filenameBox.pack_start(filenameLabel, False, False, 0)
		
		recordFilename = Gtk.Entry()
		recordFilename.set_text("demo.ts")
		recordFilename.show()
		filenameBox.pack_start(recordFilename, True, True, 0)
		recordControls.append(recordFilename)
		
		recordSelect = Gtk.Button(label="Select")
		recordSelect.show()
		filenameBox.pack_start(recordSelect, False, False, 0)
		recordControls.append(recordSelect)
		recordSelect.connect("clicked",
			lambda button: recordFilename.set_text(self.save_dialog(recordFilename.get_text())))
				
		if streamCheckBox.get_active():
			streamBox.show()
		else:
			streamBox.hide()
		recordBox.pack_start(streamBox, True, True, 0)
		
		addressLabel = Gtk.Label(label="Stream Address:")
		addressLabel.show()
		streamBox.pack_start(addressLabel, False, False, 0)
		
		streamAddress = Gtk.Entry()
		streamAddress.show()
		streamAddress.set_text("127.0.0.1")
		streamBox.pack_start(streamAddress, True, True, 0)
		recordControls.append(streamAddress)
		
		portLabel = Gtk.Label(label="UDP Port:")
		portLabel.show()
		streamBox.pack_start(portLabel, False, False, 0)
		
		streamPort = Gtk.Entry()
		streamPort.set_max_length(5)
		streamPort.show()
		streamPort.set_text("1234")
		streamBox.pack_start(streamPort, False, False, 0)
		recordControls.append(streamPort)

		settingsBox = Gtk.HBox(homogeneous=False, spacing=10)
		settingsBox.show()
		recordBox.pack_start(settingsBox, True, True, 0)
		
		formatLabel = Gtk.Label(label="Format:")
		formatLabel.show()
		settingsBox.pack_start(formatLabel, False, False, 0)

		audModeBox = Gtk.HBox(homogeneous=False, spacing=10)
		bitrateBox = Gtk.HBox(homogeneous=False, spacing=10)
		jpegBox = Gtk.HBox(homogeneous=False, spacing=10)
		faststartBox = Gtk.HBox(homogeneous=False, spacing=10)
		opt = Gtk.ComboBoxText()
		recDescs = ["TS","TS no audio","H264","MJPEG","MP4","MP4 no audio","AVI", "AVI no audio"]
		recExts = [".ts",".ts",".264",".mjpg",".mp4",".mp4", ".avi", ".avi"]
		recModes = [S2263.RECMODE_TS,S2263.RECMODE_TS_NOAUDIO,S2263.RECMODE_H264,
			    S2263.RECMODE_MJPEG,S2263.RECMODE_MP4,S2263.RECMODE_MP4_NOAUDIO, S2263.RECMODE_AVI,
			    S2263.RECMODE_AVI_NOAUDIO]
		if model == 2273:
			recDescs.insert(3, "H265")
			recExts.insert(3, ".265")
			recModes.insert(3, S2263.RECMODE_H265)
		for s in recDescs:
			opt.append_text(s)
		opt.connect("changed", lambda cb: (
			changeEntryExt(recordFilename, recExts[cb.get_active()]),
			setRecordingMode(recModes[cb.get_active()], 
				audModeBox, bitrateBox, jpegBox, faststartBox),
			brd.SetRecordMode(recModes[cb.get_active()], 0)))
		recmode = brd.GetRecordMode(0)
		opt.set_active(recModes.index(recmode))
		changeEntryExt(recordFilename, recExts[opt.get_active()])
		opt.show()
		settingsBox.pack_start(opt, False, False, 0)
		recordControls.append(opt)
		imagesizeLabel = Gtk.Label(label="Image Size:")
		imagesizeLabel.show()
		settingsBox.pack_start(imagesizeLabel, False, False, 0)
		opt = Gtk.ComboBoxText()
		index = 0
		try:
			# Use the video input resolution
			info = self.brd.GetVideoInfo()
			img_size = (info['width'], info['height'])
			brd.SetImageSize(info['width'], info['height'],0)
		except:
			# Use the last used resolution
			img_size = brd.GetImageSize(0)
		recordSizes = [(1920,1200),(1920,1080),(1280,720),(720,576),(720,480),(640,480),(640,360)]
		if not img_size in recordSizes:
			recordSizes.insert(0, img_size)
		for w,h in recordSizes:
			opt.append_text("%dx%d" % (w,h))
		opt.connect("changed", lambda cb: (
			brd.SetImageSize(recordSizes[cb.get_active()][0], recordSizes[cb.get_active()][1], 0)))
		opt.set_active(recordSizes.index(img_size))
		opt.show()
		settingsBox.pack_start(opt, False, False, 0)
		recordControls.append(opt)
		aspectLabel = Gtk.Label(label="Aspect Ratio:")
		aspectLabel.show()
		try: 
			opt = Gtk.ComboBoxText()
			for s in ["None","4:3","16:9"]:
				opt.append_text(s)
			aspectRatios = [S2263.ASPECT_NONE,S2263.ASPECT_4_3,S2263.ASPECT_16_9]
			opt.connect("changed", lambda cb: (
				brd.SetAspectRatio(aspectRatios[cb.get_active()], 0)))
			opt.set_active(aspectRatios.index(brd.GetAspectRatio(0)))
			opt.show()
			settingsBox.pack_start(aspectLabel, False, False, 0)
			settingsBox.pack_start(opt, False, False, 0)
			recordControls.append(opt)
		except:
			pass # older firmware may not have aspect control
		
		
		interlacedLabel = Gtk.Label(label="Interlace Mode:")
		interlacedLabel.show()
		settingsBox.pack_start(interlacedLabel, False, False, 0)
		self.interlacedLabel = interlacedLabel
		
		recordInterlacedOpt = Gtk.ComboBoxText()
		for s in ["Interpolated","Interlaced","Top","Bottom","Interlaced","Sequential TB","Alternate",
			  "Interlaced TB","Interlaced BT"]:
			recordInterlacedOpt.append_text(s)
		recordInterlacedOpts = [S2263.INTERPOLATED,S2263.INTERLACED,S2263.FIELD_TOP,S2263.FIELD_BOTTOM,
					 S2263.FIELD_INTERLACED,S2263.FIELD_SEQ_TB,S2263.FIELD_SEQ_BT,
					 S2263.FIELD_ALTERNATE,S2263.FIELD_INTERLACED_TB,S2263.FIELD_INTERLACED_BT]
		recordInterlacedOpt.connect("changed", lambda cb: (
			brd.SetInterlaceMode(recordInterlacedOpts[cb.get_active()], 0)))
		recordInterlacedOpt.set_active(recordInterlacedOpts.index(brd.GetInterlaceMode(0)));
		recordInterlacedOpt.show()
		self.interlacedMenu = recordInterlacedOpt
		settingsBox.pack_start(recordInterlacedOpt, False, False, 0)
		recordControls.append(recordInterlacedOpt)
		
		
		settings2Box = Gtk.HBox(homogeneous=False, spacing=10)
		#settings2Box.show()
		recordBox.pack_start(settings2Box, True, True, 0)
		
		frameskipLabel = Gtk.Label(label="Frame skip:")
		frameskipLabel.show()
		settings2Box.pack_start(frameskipLabel, False, False, 0)
		
		opt = Gtk.ComboBoxText()
		for s in ["0", "1", "2", "3"]:
			opt.append_text(s)
		opt.connect("changed", lambda cb:
			brd.SetFrameSkip(cb.get_active(), 0))
		opt.set_active(brd.GetFrameSkip(0))
		opt.show()
		settings2Box.pack_start(opt, False, False, 0)
		recordControls.append(opt)

		profileLabel = Gtk.Label(label="Profile:")
		profileLabel.show()
		settings2Box.pack_start(profileLabel, False, False, 0)
		opt = Gtk.ComboBoxText()
		for s in ["Baseline", "Main", "High"]:
			opt.append_text(s)
		profileOpts = [66, 77, 100]
		opt.connect("changed", lambda cb:
			brd.SetH264Profile(profileOpts[cb.get_active()], 0))
		opt.set_active(profileOpts.index(brd.GetH264Profile(0)))
		opt.show()
		settings2Box.pack_start(opt, False, False, 0)
		recordControls.append(opt)

		levelLabel = Gtk.Label(label="Level:")
		levelLabel.show()
		settings2Box.pack_start(levelLabel, False, False, 0)
		opt = Gtk.ComboBoxText()
		for s in ["1.0", "1B", "1.1", "1.2", "1.3", "2.0", "2.1", "2.2",
			"3.0", "3.1", "3.2", "4.0", "4.1", "4.2", "5.0"]:
			opt.append_text(s)
		levelOpts = [10,9,11,12,13,20,21,22,30,31,32,40,41,42,50]
		opt.connect("changed", lambda cb:
			brd.SetH264Level(levelOpts[cb.get_active()], 0))
		opt.set_active(levelOpts.index(brd.GetH264Level(0)))
		opt.show()
		settings2Box.pack_start(opt, False, False, 0)
		recordControls.append(opt)

		
		
		if recmode != S2263.RECMODE_MJPEG:
			bitrateBox.show()
		else:
			bitrateBox.hide()
		recordBox.pack_start(bitrateBox, False, False, 0)


		rateModeLabel = Gtk.Label(label="Rate Mode:")
		rateModeLabel.show()
		bitrateBox.pack_start(rateModeLabel, False, False, 0)
		
		opt = Gtk.ComboBoxText()
		for s in ["CBR", "VBR", "FixedQP"]:
			opt.append_text(s)
		ratemodes = [S2263.RATEMODE_CBR, S2263.RATEMODE_VBR, S2263.RATEMODE_FIXEDQP]
		opt.connect("changed", lambda cb:
			brd.SetRateMode(ratemodes[cb.get_active()], 0))
		opt.set_active(ratemodes.index(brd.GetRateMode(0)))
		opt.show()
		bitrateBox.pack_start(opt, False, False, 0)
		recordControls.append(opt)

		
		bitrateLabel = Gtk.Label(label="Video Bitrate:")
		bitrateLabel.show()
		bitrateBox.pack_start(bitrateLabel, False, False, 0)
		
                # The 2273 supports bitrate up to 60000, but the scrollbar gets unwieldy
		bitrateAdjustment = Gtk.Adjustment(value=brd.GetBitrate(0), lower=100, upper=(20000 if model != 2273 else 40000), step_increment=100, page_increment=1000)
		bitrateAdjustment.connect("value-changed",
			lambda adj: brd.SetBitrate(align_value(adj), 0))
		bitrateScale = Gtk.HScale(adjustment=bitrateAdjustment)
		bitrateScale.set_digits(0)
		bitrateScale.set_value_pos(Gtk.PositionType.LEFT)
		bitrateScale.show()
		bitrateBox.pack_start(bitrateScale, True, True, 0)
		recordControls.append(bitrateScale)
		
		
		gopsizeLabel = Gtk.Label(label="GOP Size:")
		gopsizeLabel.show()
		bitrateBox.pack_start(gopsizeLabel, False, False, 0)
		
		gopsizeAdjustment = Gtk.Adjustment(value=brd.GetGOPSize(0), lower=1, upper=255, step_increment=1, page_increment=10)
		gopsizeAdjustment.connect("value-changed",
			lambda adj: brd.SetGOPSize(align_value(adj), 1))
		gopsizeScale = Gtk.HScale(adjustment=gopsizeAdjustment)
		gopsizeScale.set_digits(0)
		gopsizeScale.set_value_pos(Gtk.PositionType.LEFT)
		gopsizeScale.show()
		bitrateBox.pack_start(gopsizeScale, True, True, 0)
		recordControls.append(gopsizeScale)

		
#		try:
#			slicemodeLabel = Gtk.Label(label="Slice Mode:")
#			slicemodeLabel.show()
#
#			opt = Gtk.OptionMenu()
#			menu = Gtk.Menu()
#			menu.append(make_menu_item("Off",
#				lambda menu: brd.SetSliceMode(S2263.SLICEMODE_OFF, 0)))
#			menu.append(make_menu_item("On",
#				lambda menu: brd.SetSliceMode(S2263.SLICEMODE_ON, 0)))
#			opt.set_menu(menu)
#		
#			opt.set_active(brd.GetSliceMode(0));
#			opt.show()
#			bitrateBox.pack_start(slicemodeLabel, False, False, 0)
#			bitrateBox.pack_start(opt, False, False, 0)
#			recordControls.append(opt)
#		except:
#			pass # older firmware may not have slice mode


##
#faststart
		recordBox.pack_start(faststartBox, False, False, 0)
		
		faststartCheckBox = Gtk.CheckButton(label="MP4 Fast Start")
		faststartCheckBox.show()
		faststartBox.pack_start(faststartCheckBox, False, False, 0)
		recordControls.append(faststartCheckBox)
		faststartCheckBox.connect("toggled",
			lambda button: (
				(faststartCheckBox.get_active() and (
					faststartminLabel.show(),
					faststartmin.show(),
					faststartsecLabel.show(),
					faststartsec.show(),
					faststartSet.show(),
					)),
				(not faststartCheckBox.get_active() and (
					faststartminLabel.hide(),
					faststartmin.hide(),
					faststartsecLabel.hide(),
					faststartsec.hide(),
					faststartSet.hide(),
					))))

		faststartminLabel = Gtk.Label(label="max minutes:")
		faststartBox.pack_start(faststartminLabel, False, False, 0)

		faststartmin = Gtk.Entry()
		faststartmin.set_text("1")
		faststartBox.pack_start(faststartmin, False, False, 0)

		faststartsecLabel = Gtk.Label(label="interval seconds:")
		faststartBox.pack_start(faststartsecLabel, False, False, 0)

		faststartsec = Gtk.Entry()
		faststartsec.set_text("10")
		faststartBox.pack_start(faststartsec, False, False, 0)

		faststartSet = Gtk.Button(label="Set")
		faststartBox.pack_start(faststartSet, False, False, 0)
		faststartSet.connect("clicked",
			lambda button: brd.SetMP4FastStart( int(faststartmin.get_text()), int(faststartsec.get_text()), 0))
##

		
		if recmode == S2263.RECMODE_TS or recmode == S2263.RECMODE_MP4:
			audModeBox.show()
		else:
			audModeBox.hide()
		recordBox.pack_start(audModeBox, False, False, 0)
		audModeLabel = Gtk.Label(label="Audio:")
		audModeLabel.show()
		audModeBox.pack_start(audModeLabel, False, False, 0)
		# List box for audio modes
		opt = Gtk.ComboBoxText()
		#if self.brd.GetFeatureFlags() & S2263.FLAG_MP3_AUDIO:
		if fw_ver >= 4107:
			audionames = ["AAC", "MP3", "PCM", "None"]
			audiomodes = [S2263.AUDIO_AAC, S2263.AUDIO_MP3, S2263.AUDIO_PCM, S2263.AUDIO_NONE]
			audiomode_max = S2263.AUDIO_PCM
		else:
			audionames = ["AAC", "None"]
			audiomodes = [S2263.AUDIO_AAC, S2263.AUDIO_NONE]
			audiomode_max = S2263.AUDIO_AAC

		for s in audionames:
			opt.append_text(s)
		opt.connect("changed", lambda cb:
			brd.SetAudioMode(audiomodes[cb.get_active()]))


		cur_audio_setting = brd.GetAudioMode()
		if cur_audio_setting <= audiomode_max:
				opt.set_active(audiomodes.index(brd.GetAudioMode()))
		opt.show()
		audModeBox.pack_start(opt, False, False, 0)
		recordControls.append(opt)
		
		bitrateLabel = Gtk.Label(label="Audio Bitrate:")
		bitrateLabel.show()
		audModeBox.pack_start(bitrateLabel, False, False, 0)

		opt = Gtk.ComboBoxText()
		audiorates = [64, 128, 192, 256, 320]
		for n in audiorates:
			opt.append_text("%dkbps" % (n))
		opt.connect("changed", lambda cb:
			brd.SetAudioBitrate(audiorates[cb.get_active()]))
		opt.set_active(audiorates.index(brd.GetAudioBitrate()))
		opt.show()
		audModeBox.pack_start(opt, False, False, 0)
		recordControls.append(opt)


		if recmode == S2263.RECMODE_MJPEG:
			jpegBox.show()
		else:
			jpegBox.hide()
		recordBox.pack_start(jpegBox, False, False, 0)
		
		jpegQualityLabel = Gtk.Label(label="JPEG Quality:")
		jpegQualityLabel.show()
		jpegBox.pack_start(jpegQualityLabel, False, False, 0)
		
		jpegAdjustment = Gtk.Adjustment(value=brd.GetJPEGQuality(0), lower=2, upper=97, step_increment=1, page_increment=5)
		jpegAdjustment.connect("value-changed",
			lambda adj: brd.SetJPEGQuality(align_value(adj), 0))
		jpegScale = Gtk.HScale(adjustment=jpegAdjustment)
		jpegScale.set_digits(0)
		jpegScale.set_value_pos(Gtk.PositionType.LEFT)
		jpegScale.show()
		jpegBox.pack_start(jpegScale, True, True, 0)
		recordControls.append(jpegScale)
		
		jpegRotationLabel = Gtk.Label(label="Rotation:")
		jpegRotationLabel.show()
		jpegBox.pack_start(jpegRotationLabel, False, False, 0)
		
		opt = Gtk.ComboBoxText()
		for s in ["0", "90", "180", "270"]:
			opt.append_text(s)
		jpegrots = [0, S2263.ROT_90, S2263.ROT_180, S2263.ROT_270]
		opt.connect("changed", lambda cb:
			brd.SetFlip(jpegrots[cb.get_active()], 0))
		opt.set_active(jpegrots.index(brd.GetFlip(0)))
		opt.show()
		jpegBox.pack_start(opt, False, False, 0)
		recordControls.append(opt)

		#
		# Deinterlace --------------------------------------------------------
		#

		deintFrame = Gtk.Frame()
		deintFrame.set_label("Deinterlace")
		vbox.pack_start(deintFrame, False, False, 0)
		
		deintBox = Gtk.HBox(homogeneous=False, spacing=10)
		deintBox.set_border_width(10)
		deintBox.show()
		deintFrame.add(deintBox)

		deiEnableOpt = Gtk.ComboBoxText()
		deintBox.pack_start(deiEnableOpt, False, False, 0)
		deiEnableOpt.append_text("Disabled")
		deiEnableOpt.append_text("Enabled");
		deiEnableOpt.show()
		deiEnableOpt.set_tooltip_text("Stream should be restarted for enabling/disabling deinterlacer to take effect.")

		deiChannelOpt = Gtk.ComboBoxText()
		deintBox.pack_start(deiChannelOpt, False, False, 0)
		deiChannelOpt.append_text("Recording Stream A");
		deiChannelOpt.append_text("Preview Stream B");
		deiChannelOpt.show()
		deiChannelOpt.set_tooltip_text("Deinterlacer can only be applied to one stream at a time.  Camera input must be interlaced, and stream resolution must be 720x576 or smaller.")
		
		deiThresholdLowLabel = Gtk.Label(label="Threshold low:")
		deiThresholdLowLabel.show()
		deintBox.pack_start(deiThresholdLowLabel, False, False, 0)
		
		deiAdjustment = Gtk.Adjustment(value=0, lower=0, upper=255, step_increment=1, page_increment=5)
		deiThresholdLowEntry = Gtk.SpinButton(adjustment=deiAdjustment)
		deiThresholdLowEntry.set_width_chars(3)
		deintBox.pack_start(deiThresholdLowEntry, False, False, 0)
		deiThresholdLowEntry.show()

		deiThresholdHighLabel = Gtk.Label(label="high:")
		deiThresholdHighLabel.show()
		deintBox.pack_start(deiThresholdHighLabel, False, False, 0)
				
		deiAdjustment = Gtk.Adjustment(value=0, lower=0, upper=255, step_increment=1, page_increment=5)
		deiThresholdHighEntry = Gtk.SpinButton(adjustment=deiAdjustment)
		deiThresholdHighEntry.set_width_chars(3)
		deintBox.pack_start(deiThresholdHighEntry, False, False, 0)
		deiThresholdHighEntry.show()
		
		for x in [deiThresholdLowEntry, deiThresholdHighEntry]:
			x.set_tooltip_text("Threshold high minus low must be one of 1, 2, 4, 8, 16, 32, 64, 128")

		deiExcludeStartLabel = Gtk.Label(label="Exclude start:")
		#deiExcludeStartLabel.show()
		deintBox.pack_start(deiExcludeStartLabel, False, False, 0)
		
		deiAdjustment = Gtk.Adjustment(value=0, lower=0, upper=1600, step_increment=1, page_increment=5)
		deiExcludeStartEntry = Gtk.SpinButton(adjustment=deiAdjustment)
		deiExcludeStartEntry.set_width_chars(3)
		deintBox.pack_start(deiExcludeStartEntry, False, False, 0)
		#deiExcludeStartEntry.show()

		deiExcludeCountLabel = Gtk.Label(label="count:")
		#deiExcludeCountLabel.show()
		deintBox.pack_start(deiExcludeCountLabel, False, False, 0)
		
		deiAdjustment = Gtk.Adjustment(value=0, lower=0, upper=1600, step_increment=1, page_increment=5)
		deiExcludeCountEntry = Gtk.SpinButton(adjustment=deiAdjustment)
		deiExcludeCountEntry.set_width_chars(3)
		deintBox.pack_start(deiExcludeCountEntry, False, False, 0)
		#deiExcludeCountEntry.show()
		
		deiExcludeButton = Gtk.Button(label="Exclude...");
		deiExcludeButton.show()
		deintBox.pack_start(deiExcludeButton, False, False, 0)
		deiExcludeButton.connect("clicked", lambda button: (
			deiExcludeButton.hide(),
			deiExcludeStartLabel.show(),
			deiExcludeStartEntry.show(),
			deiExcludeCountLabel.show(),
			deiExcludeCountEntry.show()))
		try:
			current = brd.GetDeintMode()
		except:
			current = None   # Deinterlace not supported

		if current:
			#print(current)
			deintFrame.show()
			self.deintFrame = deintFrame
			
			deiEnableOpt.set_active(current["enable"])
			deiChannelOpt.set_active(current["channel"])
			deiThresholdLowEntry.set_text("%d" % current["threshold_low"])
			deiThresholdHighEntry.set_text("%d" % current["threshold_high"])
			deiExcludeStartEntry.set_text("%d" % current["exclude_start"])
			deiExcludeCountEntry.set_text("%d" % current["exclude_count"])
		
			deiFunc = lambda x: self.set_deint_mode(
				deiEnableOpt.get_active(),
				deiChannelOpt.get_active(),
				deiThresholdLowEntry,
				deiThresholdHighEntry,
				deiExcludeStartEntry,
				deiExcludeCountEntry)
			deiEnableOpt.connect("changed", deiFunc)
			deiChannelOpt.connect("changed", deiFunc)
			deiThresholdLowEntry.connect("changed", deiFunc)
			deiThresholdHighEntry.connect("changed", deiFunc)
			deiExcludeStartEntry.connect("changed", deiFunc)
			deiExcludeCountEntry.connect("changed", deiFunc)

		#
		# Snapshot --------------------------------------------------------
		#

		snapshotFrame = Gtk.Frame()
		snapshotFrame.set_label("Snapshot")
		snapshotFrame.show()
		vbox.pack_start(snapshotFrame, False, False, 0)
		
		snapshotBox = Gtk.HBox(homogeneous=False, spacing=10)
		snapshotBox.set_border_width(10)
		snapshotBox.show()
		snapshotFrame.add(snapshotBox)
		
		takeSnapshotButton = Gtk.Button(label="Snap")
		takeSnapshotButton.show()
		takeSnapshotButton.set_sensitive(True)
		snapshotBox.pack_start(takeSnapshotButton, False, False, 0)
		
		snapshotLabel = Gtk.Label(label="Filename:")
		snapshotLabel.show()
		snapshotBox.pack_start(snapshotLabel, False, False, 0)
		
		snapshotFilename = Gtk.Entry()
		snapshotFilename.set_text("demo.jpg")
		snapshotFilename.show()
		snapshotBox.pack_start(snapshotFilename, True, True, 0)
		
		snapshotSelect = Gtk.Button(label="Select")
		snapshotSelect.show()
		snapshotBox.pack_start(snapshotSelect, False, False, 0)
		snapshotSelect.connect("clicked",
			lambda button: snapshotFilename.set_text(self.save_dialog(snapshotFilename.get_text())))

		snapshotQualityLabel = Gtk.Label(label="Quality:")
		snapshotQualityLabel.show()
		snapshotBox.pack_start(snapshotQualityLabel, False, False, 0)
		
		# Note: reuses JPEG adjustment from Recording pane since it's the same parameter
		snapshotScale = Gtk.HScale(adjustment=jpegAdjustment)
		snapshotScale.set_digits(0)
		snapshotScale.set_value_pos(Gtk.PositionType.LEFT)
		snapshotScale.show()
		snapshotBox.pack_start(snapshotScale, True, True, 0)
		
		takeSnapshotButton.connect("clicked",
			lambda button: (
				brd.Snapshot(snapshotFilename.get_text(),0)))
				


		#
		# Output ----------------------------------------------------------
		#
		# TODO: Remove output for 2231, 2267, 2271
		try:
			outputFrame = Gtk.Frame()
			outputFrame.set_label("Output")
			outputFrame.show()

			outputBox = Gtk.HBox(homogeneous=False, spacing=10)
			outputBox.set_border_width(10)
			outputBox.show()
			outputFrame.add(outputBox)

			vidOutput = brd.GetOutput()
			if (isS3364):
				usb_speed = brd.Get3364UsbSpeed()

#		       print usb_speed
			if brd.GetNumInputs() == 1:
				outputSDI = Gtk.RadioButton.new_with_label_from_widget(None, "SDI")
				outputSDI.set_active(vidOutput == S2263.OUTPUT_SDI)
				outputSDI.connect("toggled",
					lambda button: outputSDI.get_active()
						and brd.SetOutput(S2263.OUTPUT_SDI))
				outputSDI.show()
				outputBox.pack_start(outputSDI, False, False, 0)
			else:
				outputCVideo = Gtk.RadioButton.new_with_label_from_widget(None, "Composite")
				outputCVideo.set_active(vidOutput == S2263.OUTPUT_COMPOSITE)
				outputCVideo.connect("toggled",
					lambda button: outputCVideo.get_active()
						and brd.SetOutput(S2263.OUTPUT_COMPOSITE))
				outputCVideo.show()
				outputBox.pack_start(outputCVideo, False, False, 0)

				outputDVI = Gtk.RadioButton.new_with_label_from_widget(outputCVideo, "DVI-D")
				outputDVI.set_active(vidOutput == S2263.OUTPUT_DVI)
				outputDVI.connect("toggled",
					lambda button: outputDVI.get_active()
						and brd.SetOutput(S2263.OUTPUT_DVI))
				outputDVI.show()
				outputBox.pack_start(outputDVI, False, False, 0)

			outputModeLabel = Gtk.Label(label="Mode:")
			outputModeLabel.show()
			outputBox.pack_start(outputModeLabel, False, False, 0)

			outputModeOpt = Gtk.ComboBoxText()
			for s in ["Idle", "Passthru HD", "Passthru SD", "ColorBars"]:
				outputModeOpt.append_text(s)
			outputModes = [S2263.OUTPUT_IDLE, S2263.OUTPUT_PASSTHRU, S2263.OUTPUT_PASSTHRU_SD, S2263.OUTPUT_COLORBARS];
			outputModeOpt.connect("changed",
				lambda cb: brd.SetOutputMode(outputModes[cb.get_active()]))
			outputModeOpt.set_active(outputModes.index(brd.GetOutputMode()))
			outputModeOpt.show()
			outputBox.pack_start(outputModeOpt, False, False, 0)

			outputStdLabel = Gtk.Label(label="Standard:")
			outputStdLabel.show()
			outputBox.pack_start(outputStdLabel, False, False, 0)

			outputStdOpt = Gtk.ComboBoxText()
			index = 0
			cur_std = brd.GetOutputStd()
			for s in ["Auto","NTSC","PAL","VGA","480p60","576p50","720p60","720p50",
				"1080i60","1080i50","1080p30","1080p25","1080p24"]:
				outputStdOpt.append_text(s)
			outputStds = [S2263.OUTPUT_AUTO, S2263.OUTPUT_NTSC, S2263.OUTPUT_PAL, S2263.OUTPUT_VGA, S2263.OUTPUT_480P60,
				S2263.OUTPUT_576P50, S2263.OUTPUT_720P60, S2263.OUTPUT_720P50, S2263.OUTPUT_1080I60,
				S2263.OUTPUT_1080I50, S2263.OUTPUT_1080P30, S2263.OUTPUT_1080P25, S2263.OUTPUT_1080P24]
			outputStdOpt.connect("changed",
				lambda cb: brd.SetOutputStd(outputStds[cb.get_active()]))
			outputStdOpt.set_active(outputStds.index(cur_std))
			outputStdOpt.show()
			outputBox.pack_start(outputStdOpt, False, False, 0)
			vbox.pack_start(outputFrame, False, False, 0)
		except:
			pass # older firmware may not have output control


		if isS3364:
			userDataFrame = Gtk.Frame()
			userDataFrame.set_label("User Data")
			userDataFrame.show()

			dataBox = Gtk.HBox(homogeneous=False, spacing=10)
			dataBox.set_border_width(10)
			dataBox.show()
			userDataFrame.add(dataBox)

			labelHex = Gtk.Label(label="Hex String(separate with spaces):")
			labelHex.show()
			dataBox.add(labelHex)
			

			
			hexData = Gtk.Entry()
			hexData.set_text("0x00")
			hexData.show()
			dataBox.add(hexData)

			userData = (ctypes.c_char * 10)()
			self.load_user_data(userData, hexData)
			self.brd.Get3364UserData(userData)
			hexData.set_text("%02x %02x %02x %02x %02x "
					 "%02x %02x %02x %02x %02x" %
					 (ord(userData[0]),ord(userData[1]),
					  ord(userData[2]),ord(userData[3]),
					  ord(userData[4]),ord(userData[5]),
					  ord(userData[6]),ord(userData[7]),
					  ord(userData[8]),ord(userData[9])))

			readUserDataBtn = Gtk.Button(label="Load")
			readUserDataBtn.show()
			dataBox.add(readUserDataBtn)
			readUserDataBtn.connect("clicked",
				lambda button1: (
					self.load_user_data(userData, hexData)
				))

			saveUserDataBtn = Gtk.Button(label="Save")
			saveUserDataBtn.show()
			dataBox.add(saveUserDataBtn)
			saveUserDataBtn.connect("clicked",
				lambda button1: (
					self.save_user_data(userData, hexData)
				))
			
			vbox.pack_start(userDataFrame, False, False, 0)		
		return vbox


	def redo_setup(self):
		self.thr = ResolutionThread(self.brd, self.labelShowResolution, self)
		self.setup(1)
		self.thr.start()
		return


if __name__ == "__main__":
	demo = Demo()
	demo.main()
