from pywin.mfc import dialog
import win32api
import win32con
import win32ui
import copy
import string
import scintillacon

# Used to indicate that style should use default color
from win32con import CLR_INVALID

######################################################
# Property Page for syntax formatting options
    
# The standard 16 color VGA palette should always be possible    
paletteVGA = (
	("Black", win32api.RGB(0,0,0)),
	("Navy", win32api.RGB(0,0,128)),
	("Green", win32api.RGB(0,128,0)),
	("Cyan", win32api.RGB(0,128,128)),
	("Maroon", win32api.RGB(128,0,0)),
	("Purple", win32api.RGB(128,0,128)),
	("Olive", win32api.RGB(128,128,0)),
	("Gray", win32api.RGB(128,128,128)), 
	("Silver", win32api.RGB(192,192,192)),
	("Blue", win32api.RGB(0,0,255)),
	("Lime", win32api.RGB(0,255,0)),
	("Aqua", win32api.RGB(0,255,255)), 
	("Red", win32api.RGB(255,0,0)),
	("Fuchsia", win32api.RGB(255,0,255)),
	("Yellow", win32api.RGB(255,255,0)),
	("White", win32api.RGB(255,255,255)),
# and a few others will generally be possible.
	("DarkGrey", win32api.RGB(64,64,64)),
	("PurpleBlue", win32api.RGB(64,64,192)),
	("DarkGreen", win32api.RGB(0,96,0)),
	("DarkOlive", win32api.RGB(128,128,64)),
	("MediumBlue", win32api.RGB(0,0,192)),
	("DarkNavy", win32api.RGB(0,0,96)),
	("Magenta", win32api.RGB(96,0,96)),
	("OffWhite", win32api.RGB(255,255,220)),
	("LightPurple", win32api.RGB(220,220,255)),
	("<Default>", win32con.CLR_INVALID)
)

class ScintillaFormatPropertyPage(dialog.PropertyPage):
	def __init__(self, scintillaClass = None, caption = 0):
		self.scintillaClass = scintillaClass
		dialog.PropertyPage.__init__(self, win32ui.IDD_PP_FORMAT, caption=caption)

	def OnInitDialog(self):
		try:
			if self.scintillaClass is None:
				import control
				sc = control.CScintillaEdit
			else:
				sc = self.scintillaClass

			self.scintilla = sc()
			style = win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.ES_MULTILINE
			# Convert the rect size
			rect = self.MapDialogRect( (5, 5, 120, 75))
			self.scintilla.CreateWindow(style, rect, self, 111)
			self.HookNotify(self.OnBraceMatch, scintillacon.SCN_CHECKBRACE)
			self.scintilla.HookKeyStroke(self.OnEsc, 27)
			self.scintilla.SCISetViewWS(1)
			self.pos_bstart = self.pos_bend = self.pos_bbad = 0

			colorizer = self.scintilla._GetColorizer()
			text = colorizer.GetSampleText()
			items = text.split('|', 2)
			pos = len(items[0])
			self.scintilla.SCIAddText(''.join(items))
			self.scintilla.SetSel(pos, pos)
			self.scintilla.ApplyFormattingStyles()
			self.styles = self.scintilla._GetColorizer().styles

			self.cbo = self.GetDlgItem(win32ui.IDC_COMBO1)
			for c in paletteVGA:
				self.cbo.AddString(c[0])

			self.cboBoldItalic = self.GetDlgItem(win32ui.IDC_COMBO2)
			for item in ["Bold Italic", "Bold", "Italic", "Regular"]:
				self.cboBoldItalic.InsertString(0, item)

			self.butIsDefault = self.GetDlgItem(win32ui.IDC_CHECK1)
			self.butIsDefaultBackground = self.GetDlgItem(win32ui.IDC_CHECK2)
			self.listbox = self.GetDlgItem(win32ui.IDC_LIST1)
			self.HookCommand(self.OnListCommand, win32ui.IDC_LIST1)
			names = self.styles.keys()
			names.sort()
			for name in names:
				if self.styles[name].aliased is None:
					self.listbox.AddString(name)
			self.listbox.SetCurSel(0)

			idc = win32ui.IDC_RADIO1
			if not self.scintilla._GetColorizer().bUseFixed: idc = win32ui.IDC_RADIO2
			self.GetDlgItem(idc).SetCheck(1)
			self.UpdateUIForStyle(self.styles[names[0]])

			self.scintilla.HookFormatter(self)
			self.HookCommand(self.OnButDefaultFixedFont, win32ui.IDC_BUTTON1)
			self.HookCommand(self.OnButDefaultPropFont, win32ui.IDC_BUTTON2)
			self.HookCommand(self.OnButThisFont, win32ui.IDC_BUTTON3)
			self.HookCommand(self.OnButUseDefaultFont, win32ui.IDC_CHECK1)
			self.HookCommand(self.OnButThisBackground, win32ui.IDC_BUTTON4)
			self.HookCommand(self.OnButUseDefaultBackground, win32ui.IDC_CHECK2)
			self.HookCommand(self.OnStyleUIChanged, win32ui.IDC_COMBO1)
			self.HookCommand(self.OnStyleUIChanged, win32ui.IDC_COMBO2)
			self.HookCommand(self.OnButFixedOrDefault, win32ui.IDC_RADIO1)
			self.HookCommand(self.OnButFixedOrDefault, win32ui.IDC_RADIO2)
		except:
			import traceback
			traceback.print_exc()

	def OnEsc(self, ch):
		self.GetParent().EndDialog(win32con.IDCANCEL)

	def OnBraceMatch(self, std, extra):
		import pywin.scintilla.view
		pywin.scintilla.view.DoBraceMatch(self.scintilla)

	def GetSelectedStyle(self):
		return self.styles[self.listbox.GetText(self.listbox.GetCurSel())]

	def _DoButDefaultFont(self, extra_flags, attr):
		baseFormat = getattr(self.scintilla._GetColorizer(), attr)
		flags = extra_flags | win32con.CF_SCREENFONTS | win32con.CF_EFFECTS | win32con.CF_FORCEFONTEXIST
		d=win32ui.CreateFontDialog(baseFormat, flags, None, self)
		if d.DoModal()==win32con.IDOK:
			setattr(self.scintilla._GetColorizer(), attr, d.GetCharFormat())
			self.OnStyleUIChanged(0, win32con.BN_CLICKED)

	def OnButDefaultFixedFont(self, id, code):
		if code==win32con.BN_CLICKED:
			self._DoButDefaultFont(win32con.CF_FIXEDPITCHONLY, "baseFormatFixed")
			return 1

	def OnButDefaultPropFont(self, id, code):
		if code==win32con.BN_CLICKED:
			self._DoButDefaultFont(win32con.CF_SCALABLEONLY, "baseFormatProp")
			return 1

	def OnButFixedOrDefault(self, id, code):
		if code==win32con.BN_CLICKED:
			bUseFixed = id == win32ui.IDC_RADIO1
			self.GetDlgItem(win32ui.IDC_RADIO1).GetCheck() != 0
			self.scintilla._GetColorizer().bUseFixed = bUseFixed
			self.scintilla.ApplyFormattingStyles(0)
			return 1

	def OnButThisFont(self, id, code):
		if code==win32con.BN_CLICKED:
			flags = win32con.CF_SCREENFONTS | win32con.CF_EFFECTS | win32con.CF_FORCEFONTEXIST
			style = self.GetSelectedStyle()
			# If the selected style is based on the default, we need to apply
			# the default to it.
			def_format = self.scintilla._GetColorizer().GetDefaultFormat()
			format = style.GetCompleteFormat(def_format)
			d=win32ui.CreateFontDialog(format, flags, None, self)
			if d.DoModal()==win32con.IDOK:
				style.format = d.GetCharFormat()
				self.scintilla.ApplyFormattingStyles(0)
			return 1

	def OnButUseDefaultFont(self, id, code):
		if code == win32con.BN_CLICKED:
			isDef = self.butIsDefault.GetCheck()
			self.GetDlgItem(win32ui.IDC_BUTTON3).EnableWindow(not isDef)
			if isDef: # Being reset to the default font.
				style = self.GetSelectedStyle()
				style.ForceAgainstDefault()
				self.UpdateUIForStyle(style)
				self.scintilla.ApplyFormattingStyles(0)
			else:
				# User wants to override default -
				# do nothing!
				pass

	def OnButThisBackground(self, id, code):
		if code==win32con.BN_CLICKED:
			style = self.GetSelectedStyle()
			bg = win32api.RGB(0xff, 0xff, 0xff)
			if style.background != CLR_INVALID:
				bg = style.background
			d=win32ui.CreateColorDialog(bg, 0, self)
			if d.DoModal()==win32con.IDOK:
				style.background = d.GetColor()
				self.scintilla.ApplyFormattingStyles(0)
			return 1

	def OnButUseDefaultBackground(self, id, code):
		if code == win32con.BN_CLICKED:
			isDef = self.butIsDefaultBackground.GetCheck()
			self.GetDlgItem(win32ui.IDC_BUTTON4).EnableWindow(not isDef)
			if isDef: # Being reset to the default color
				style = self.GetSelectedStyle()
				style.background = style.default_background
				self.UpdateUIForStyle(style)
				self.scintilla.ApplyFormattingStyles(0)
			else:
				# User wants to override default -
				# do nothing!
				pass


	def OnListCommand(self, id, code):
		if code==win32con.LBN_SELCHANGE:
			style = self.GetSelectedStyle()
			self.UpdateUIForStyle(style)
		return 1

	def UpdateUIForStyle(self, style ):
		format = style.format
		sel = 0
		for c in paletteVGA:
			if format[4] == c[1]:
#				print "Style", style.name, "is", c[0]
				break
			sel = sel + 1
		else:
			sel = -1
		self.cbo.SetCurSel(sel)
		self.butIsDefault.SetCheck(style.IsBasedOnDefault())
		self.GetDlgItem(win32ui.IDC_BUTTON3).EnableWindow(not style.IsBasedOnDefault())

		self.butIsDefaultBackground.SetCheck(style.background == style.default_background)
		self.GetDlgItem(win32ui.IDC_BUTTON4).EnableWindow(style.background != style.default_background)
		
		bold = format[1] & win32con.CFE_BOLD != 0; italic = format[1] & win32con.CFE_ITALIC != 0
		self.cboBoldItalic.SetCurSel( bold*2 + italic )

	def OnStyleUIChanged(self, id, code):
		if code in [win32con.BN_CLICKED, win32con.CBN_SELCHANGE]:
			style = self.GetSelectedStyle()
			self.ApplyUIFormatToStyle(style)
			self.scintilla.ApplyFormattingStyles(0)
			return 0
		return 1

	def ApplyUIFormatToStyle(self, style):
		format = style.format
		color = paletteVGA[self.cbo.GetCurSel()]
		effect = 0
		sel = self.cboBoldItalic.GetCurSel()
		if sel==0:
			effect = 0
		elif sel==1:
			effect = win32con.CFE_ITALIC
		elif sel==2:
			effect = win32con.CFE_BOLD
		else:
			effect = win32con.CFE_BOLD | win32con.CFE_ITALIC
		maskFlags=format[0]|win32con.CFM_COLOR|win32con.CFM_BOLD|win32con.CFM_ITALIC
		style.format = (maskFlags, effect, style.format[2], style.format[3], color[1]) + style.format[5:]

	def OnOK(self):
		self.scintilla._GetColorizer().SavePreferences()
		return 1

def test():
	page = ColorEditorPropertyPage()
	sheet = pywin.mfc.dialog.PropertySheet("Test")
	sheet.AddPage(page)
	sheet.CreateWindow()
