# -*- coding: UTF-8 -*-
""" capellaScript -- (C) 2025 Ken Haiker, acaMusic (www.acamusic.de)
                         Implementation: Brian Schueler
>>> aL.Tabber
    Rev 0.3.6 (26.07.2026) --- Plugin für Gitarristen (und andere Saiteninstrumente wie Bass, Ukulele usw.)
    ||Das aL.Tabber-Plugin (aL = acaLead) wandelt eine ein- oder mehrstimmige klassische Gitarren-Notenzeile
	(mit Noten bis zum 4.Bund) oder eine acaLead-Notenzeile mit Noten über dem 4. Bund und Fret-Index in eine 
	VOLLSTÄNDIGE Tabulatur (aLT) um. 
	||
	"Vollständig" heißt, die Tab enthält sämtliche vom Gitarristen benötigten 
	Spiel-Informationen, inklusive den für den Fret-Index typischen, intrinsisch gegebenen Fingersatz. Auch 
	für mehrstimmige, hoch-komplexe Gitarrenstücke werden die Tondauern sämtlicher Noten richtig und sehr 
	leicht lesbar wiedergegeben. Eine zusätzliche Notenzeile zur Ergänzung fehlender Spiel-Informationen, 
	wie bei der klassischen Tabulatur erforderlich, wird nicht mehr benötigt.
    ||
	Weitere Informationen, ein ausführliches Plugin-Handbuch sowie viele bekannte klassische Gitarrenstücke, 
	die zusätzlich zu den Notendarstellungen in acaLead Notation (aLN) für die Tabulaturdarstellungen in acaLead Tab (aLT)
	geschrieben sind, gibt es auf der Homepage
	||
    -------------   www.acaMusic.de   -------------
    ||
<<<

History:  Dezember 2025 - Erste Version

"""

import pprint
import re
import tempfile
import zipfile
from caplib.capDOM import ScoreChange, childElements
from xml.dom.minidom import NodeList, Node, Element

sys.stdout = open(tempfile.gettempdir()+'capella-al-tabber.log', 'w')
tremoloBarTag = '13113-20'

def getElementObjects(objList):  # returns a List
        newList = NodeList()
        for n in range(objList.length):
                if objList[n].nodeType == objList[n].ELEMENT_NODE:
                        newList.append(objList[n])
        return newList

def gotoChild(self, name, new=False):
        newEl = None
        for child in self.childNodes:
                if child.nodeType == child.ELEMENT_NODE and child.tagName == name:
                        newEl = child
                        break

        if new == False:
                return newEl

        if newEl == None:
                newEl = doc.createElement(name)
                self.appendChild(newEl)
        return newEl
import new
Node.gotoChild = new.instancemethod(gotoChild,None,Node)

# Get the base child object and the child list of an object
def getChildren(el, name, forcedPlural = None):
	if name == 'staff':
		namePlural = 'staves'
	elif name == 'drawObj':
		namePlural = 'drawObjects'
	elif name == 'noteObj':
		namePlural = 'noteObjects'
	else:
		namePlural = name+'s'
	if forcedPlural is not None:
		namePlural = forcedPlural
	plElems = childElements(el, namePlural)
	if len(plElems) > 0:
		plFirstElem = plElems[0]
		retval = childElements(plFirstElem, name)
		return (plFirstElem, retval)
	else:           
		xElem = el.getElementsByTagName(name)
		if xElem.length > 0:
			x = xElem[0]
			childNodes = getElementObjects(x.childNodes)
			return (x, childNodes)
		else:
			return (None, [])

# Replace a named child tree
def setChildren(el, children, name):
        oldchildren = childElements(el, name)
        for oldchild in oldchildren:
                el.removeChild(oldchild)
        for child in children:
                el.appendChild(child)

def getDurationByBase(base, dots = 0, tuplet = 0):
	base = base.split('/')
	value = 0
	if len(base) == 2:
		value = float(base[0])/float(base[1])
	else:
		value = float(base[0])

	# Tuplet Note
	if tuplet > 0:
		if tuplet == 3:
			value = value * 2.0 / 3.0

	# Dotted Note
	dot_value = value
	if dots > 0:
		for i in range(0,dots):
			dot_value = dot_value / 2
			value = value + dot_value
	return value

# Get the decimal duration of a note/chord/rest
def getObjDuration(noteObj):
	duration = noteObj.getElementsByTagName('duration')
	# Only NoteObjects that have a duration
	if len(duration) > 0:
		noDuration = duration[0].getAttribute('noDuration')
		if noDuration == 'true':
			return 0.0

		baseT = duration[0].getAttribute('base')
		if baseT is None or baseT == "":
			return 0.0

		dots = duration[0].getAttribute('dots')
		if dots is None or dots == '':
			dots = '0'

		tuplet = '0'
		tupletNode = duration[0].gotoChild('tuplet', False)
		if tupletNode is not None:
			tuplet = tupletNode.getAttribute('count')

		return getDurationByBase(baseT, int(dots), int(tuplet))
	return None

# Get the total duration of a voice
def getVoiceTotalTime(voice):
	totalTime = 0.0
	onoteObjects, noteObjects = getChildren(voice, 'noteObjects')
	for obj in noteObjects:
		duration = getObjDuration(obj)
		if duration is not None:
			totalTime = totalTime + duration
	return totalTime

# Get the total duration of a staff
def getStaffTotalTime(staff):
	totalTime = 0.0
	ovoices, voices = getChildren(staff, 'voice')
	for voice in voices:
		tt = getVoiceTotalTime(voice)
		totalTime = max(totalTime, tt)
	return totalTime

def getPosAtCursor(score):
	pos = 0.0
	sys1 = curSelection()[0][0]
	sta1 = curSelection()[0][1]
	voi1 = curSelection()[0][2]
	nObj1 = curSelection()[0][3]

	osystens, systems = getChildren(score, 'system')
	systemID = 0
	for system in systems:
		ostaves, staves = getChildren(system, 'staff')
		staffID = 0
		savedPosSystem = pos
		for staff in staves:
			pos = savedPosSystem
			ovoices, voices = getChildren(staff, 'voice')
			voiceID = 0
			savedPosStaff = pos
			for voice in voices:
				pos = savedPosStaff
				oobjs, objs = getChildren(voice, 'noteObjects')
				numObjs = len(objs)
				objID = 0
				for i in range(0, numObjs):
					obj = objs[i]
					if (systemID, staffID, voiceID, objID) == (sys1, sta1, voi1, nObj1):
						return pos
					dura = getObjDuration(obj)
					if dura is not None:
						pos = pos + dura
					objID = objID + 1
				voiceID = voiceID + 1
			staffID = staffID + 1
		systemID = systemID + 1
	return None

def getSimpleTexts(noteObj):
	retval = []
	odrawObjs, drawObjs = getChildren(noteObj, 'drawObj')
	
	for drawObj in drawObjs:
		texts  = childElements(drawObj, 'text')
		if len(texts) > 0:
			for text in texts:
				try:
					content = text.getElementsByTagName('content')[0].firstChild.data
					fonts = text.getElementsByTagName('font')
					if fonts.length > 0:
						color = fonts[0].getAttribute('color')
						height = int(fonts[0].getAttribute('height'))
					content = re.sub('\n$', '', content)
					retval.append(content)
				except:
					pass
	return retval

def removeChordSym(chord):
	odrawObjects, drawObjects = getChildren(chord, 'drawObj')
	if len(drawObjects) == 0:
		return

	removeList = []
	for drawObj in drawObjects:
		transposable = drawObj.gotoChild('transposable', False)
		group = drawObj.gotoChild('group', False)
		if transposable is not None:
			removeList.append(drawObj)
		elif group is not None:
			removeList.append(drawObj)
	for elem in removeList:
		drawObjects.remove(elem)
	setChildren(odrawObjects, drawObjects, 'drawObj')

def setGroupText(group, x=0.0, y=0.0, text_root = '', text_deri = '', text_bass = ''):
	x, y = setText(group, text_root, 10, x, y)
	if text_deri != '':
		y = y - 1.0
		x, y = setText(group, text_deri, 7, x, y)
	if text_bass != '':
		text_bass = text_bass.replace('/', '')
		y = y + 2.0
		x = x - 0.6
		x, y = setText(group, '/', 18, x, y)
		x = x - 1.5
		x, y = setText(group, text_bass, 10, x, y)
		

def setText(group, text, font_size, x, y):
	text_elems = []
	part = ''
	counter = 0
	for ch in text:
		if ch in ['b', '#'] and counter > 0:
			text_elems.append(part)
			text_elems.append(ch)
			part = ''
		else:
			part = part + ch
		counter = counter + 1
	text_elems.append(part)

	counter = 0
	for text_elem in text_elems:
		fact_extra = 1.0
		size_fact = 1.0
		x_offs = 0
		y_offs = 0
		if text_elem not in ['b', '#'] or counter == 0:
			font_func = setStandardFont
		else:
			text_elem = text_elem.replace('b', 'Q').replace('#', 'S')
			fact_extra = 0.3
			x_offs = -0.05 * font_size / 7.0
			y_offs = -0.25 * font_size / 7.0
			size_fact = 1.0
			font_func = setCapellaFont
		setTextElement(group, text_elem, font_size*size_fact, x+x_offs, y+y_offs, font_func)
		x = x + measureText(text_elem) * font_size*size_fact * fact_extra / 6.0
		counter = counter + 1
	return x, y

def setSlur(obj, noteRange, x1, y1, x2, y2, x3, y3, x4, y4):
	drawObj = addDrawObject(obj)
	slur = drawObj.gotoChild('slur', True)
	slur.setAttribute('x1', str(x1))
	slur.setAttribute('x2', str(x2))
	slur.setAttribute('x3', str(x3))
	slur.setAttribute('x4', str(x4))
	slur.setAttribute('y1', str(y1))
	slur.setAttribute('y2', str(y2))
	slur.setAttribute('y3', str(y3))
	slur.setAttribute('y4', str(y4))
	basic = drawObj.gotoChild('basic', True)
	basic.setAttribute('noteRange', str(noteRange))
	#basic.setAttribute('noAdjust', 'true')

def measureText(text):
	letters_s = ['i', 'I', 'l', '1', '*', "'", '!', '[', ']']
	letters_l = ['M', 'm', 'W', 'w', 'V', 'C', 'D', 'E', 'F', 'G', 'H', 'K', 'N', 'O' , 'Q', 'S', 'U', 'X', 'Z']
	width = 0
	for letter in text:
		if letter in letters_s:
			# Thin letters
			width = width + 0.5
		elif letter in letters_l:
			# Thick letters
			width = width + 1.1
		else:
			# Normal sized letters
			width = width + 0.85
	return width

def setTextElement(group, text, font_size, x, y, font_func):
	newEl = doc.createElement('drawObj')
	textEl = newEl.gotoChild('text', True)
	textEl.setAttribute('x', str(x))
	textEl.setAttribute('y', str(y))
	font_func(textEl, font_size)
	content = addNewElementNode(textEl, 'content')
	textNode = doc.createTextNode(text)
	content.appendChild(textNode)	
	group.appendChild(newEl)

def setStandardFont(text, height = 10):
	font = text.gotoChild('font', True)
	font.setAttribute('face', 'Times New Roman')
	font.setAttribute('height', str(height))

def setCapellaFont(text, height = 12):
	font = text.gotoChild('font', True)
	font.setAttribute('face', 'capella3')
	font.setAttribute('height', str(height))
	font.setAttribute('charSet', '2')
	font.setAttribute('pitchAndFamily', '2')

def addDrawObject(object, createPluralChild = True):
	if createPluralChild:
		drawObjs = object.gotoChild('drawObjects', True)
	else:
		drawObjs = object
	newEl = doc.createElement('drawObj')
	drawObjs.appendChild(newEl)
	return newEl

def addTextGroup(drawObj):
	newEl = doc.createElement('group')
	drawObj.appendChild(newEl)
	return newEl

def addText(obj, content = u'', x = 0, y = 0, fontFace = u'Times New Roman', height = 12, charset = 1, tag = '', color = None, weight = None, italic = False, underline = False, leftline = False, trembars = None):
	basic = obj.gotoChild('basic', True)
	basic.setAttribute('scope', 'brace')
	basic.setAttribute('placement', 'manual')
	basic.setAttribute('placementHint', 'performanceInstruction')

	text = obj.gotoChild('text', True)
	text.setAttribute('x', str(x))
	text.setAttribute('y', str(y))

	font = text.gotoChild('font', True)
	font.setAttribute('charSet', str(charset))
	font.setAttribute('height', str(height))
	font.setAttribute('italic', str(bool(italic)).lower())
	font.setAttribute('face', fontFace)
	if color is not None:
		font.setAttribute('color', color)
	if weight is not None:
		font.setAttribute('weight', str(weight))
	if underline is not None:
		font.setAttribute('underline', str(bool(underline)).lower())

	contentEl = text.gotoChild('content', True)
	if leftline == True:
		content = '|'+content

	if trembars is not None:
		content = '/'*trembars + content
	textName = doc.createTextNode(content)
	contentEl.appendChild(textName)

def setTextObjFretFingeringVisibility(noteObj):
	fingeringTextObjs = getObjTextObjsByCriteria(noteObj, 'fingering')
	fretIndexTextObjs = getObjTextObjsByCriteria(noteObj, 'localFretIndex')
	oAllTextObjs, allTextObjs = getChildren(noteObj, 'drawObjects')
	valFingeringTextObjs = []
	valFretIndexTextObjs = []
	for fingeringTextObj in fingeringTextObjs:
		content = getTextContent(fingeringTextObj)
		if content is not None and content != '' and content.strip() != '-':
			valFingeringTextObjs.append(fingeringTextObj)
	for fretIndexTextObj in fretIndexTextObjs:
		content = getTextContent(fretIndexTextObj)
		if content is not None and content != '' and content.strip() != '-':
			valFretIndexTextObjs.append(fretIndexTextObj)

def cap2acaTone(head, baseOct4):
	pitch = head.getAttribute('pitch')
	alter = head.gotoChild('alter', False)
	step = 0
	if alter is not None:
		step = int(alter.getAttribute('step'))
	tone = pitch
	octave = int(tone[1])
	if baseOct4:
		octave = octave - 1
	if step == 1:
		tone = tone[0] + '#' + str(octave)
	elif step == -1:
		tone = tone[0] + 'b' + str(octave)
	return tone

def aca2capTone(tone, baseOct4):
	step = 0
	if len(tone) < 2:
		return (None, None)
	base = tone[0]
	tone = tone[1:]
	while tone[0] in [u'b', u'#']:
		if tone[0] == 'b':
			step = step - 1
		else:
			step = step + 1
		tone = tone[1:]
	if len(tone) < 1:
		return (None, None)
	octave = tone[0]
	if baseOct4:
		octave = str(int(octave) + 1)
	return (base+octave, step)

def addNote(voice, newNoteObj):
	oNoteObjs, noteObjs = getChildren(voice, 'noteObjects')
	newObjs = []
	for noteObj in noteObjs:
		newObjs.append(noteObj)
	newObjs.append(newNoteObj)
	setChildren(oNoteObjs, newObjs, 'noteObjects')

def clearStaff(staff):
	ovoices, voices = getChildren(staff, 'voice')
	for voice in voices:
		clearVoice(voice)

def copyStaff(src_staff, dest_staff):
	osrc_voices, src_voices = getChildren(dest_staff, 'voice')
	odest_voices, dest_voices = getChildren(dest_staff, 'voice')
	cloned_staff= src_staff.cloneNode(deep=True)
	voices = dest_staff.gotoChild('voices', False)
	if voices is not None:
		for dest_voice in dest_voices:
			voices.removeChild(dest_voice)
	ocloned_voices, cloned_voices = getChildren(cloned_staff, 'voice')
	setChildren(odest_voices, cloned_voices, 'voices')

def clearVoice(voice):
	oNoteObjs, noteObjs = getChildren(voice, 'noteObjects')
	newObjs = []
	for noteObj in noteObjs:
		name = noteObj.localName
		print(name)
		oNoteObjs.removeChild(noteObj)
	setChildren(oNoteObjs, newObjs, 'noteObjects')

def getTies(noteObj):
	retval = []
	oheads, heads = getChildren(noteObj, 'head')
	for head in heads:
		tie = head.gotoChild('tie', False)
		tieBegin = False
		tieEnd = False
		if tie is not None:
			begin = tie.getAttribute('begin')
			end = tie.getAttribute('end')
			if begin == 'true':
				tieBegin = True
			if end == 'true':
				tieEnd = True
		retval.append((tieBegin, tieEnd))
	return retval

def getPitches(noteObj):
	retval = []
	oheads, heads = getChildren(noteObj, 'head')
	for head in heads:
		pitch = head.getAttribute('pitch')
		alter = head.gotoChild('alter')
		step = 0
		if alter is not None:
			tstep = alter.getAttribute('step')
			if tstep is not None and tstep != '':
				step = int(tstep)
		stepSigns = [ 'bb', 'b', '', '#', '##' ]
		if pitch is not None:
			retval.append(pitch[0]+stepSigns[step+2]+pitch[1])
	return retval

def transposeTone(tone, htOffset, use_sharp = True):
	m_pitch = midiPitch(tone) + htOffset
	return pitchFromMidi(m_pitch, use_sharp)

def force_sign(tone_s, sharp = True):
	flats  = ['Db', 'Eb', 'Gb', 'Ab', 'Bb']
	sharps = ['C#', 'D#', 'F#', 'G#', 'A#']
	srcs = flats
	tgts = sharps
	if sharp == False or sharp == 'b':
		srcs = sharps
		tgts = flats

	# in case of a list
	if type(tone_s) is list:
		retval = []
		for tone in tone_s:
			for i in range(0, 5):
				tone = re.sub('^'+srcs[i], tgts[i], tone)	
			retval.append(tone)
		return retval

	# in case of a string
	for i in range(0, 5):
		tone_s = re.sub('^'+srcs[i], tgts[i], tone_s)	
	return tone_s

def midiPitch(tone):
	key_notes = "CDEFGAB"
	step = 0
	i = key_notes.find(tone[0])
	tone = tone[1:]
	if len(tone) < 1:
		return None
	while tone[0] in [u'b', u'#']:
		if tone[0] == 'b':
			step = step - 1
		else:
			step = step + 1
		tone = tone[1:]
	n = (0,2,4,5,7,9,11)[i] + 12 * int(tone[0]) + step
	return n

def pitchFromMidi(n, use_sharp = True):
	octave = int(n)/12
	itone = int(n)%12
	tonesSharp = 'CCDDEFFGGAAB'
	tonesFlat  = 'CDDEEFGGAABB'
	steps      = '010100101010'
	toneSharp = tonesSharp[itone]
	toneFlat  = tonesFlat[itone]
	step = -int(steps[itone])
	tone = toneFlat

	# Use Sharp sign if set
	if use_sharp:
		tone = toneSharp
		step = -step

	sign = ''
	if step < 0:
		sign = 'b'
	elif step > 0:
		sign = '#'
	return tone+sign+str(octave)

# Determine FretIndex color and font size - keyword "Fret"
def getFretColorAndSize(score):
	fretInfoStaves = []
	selected_staff = curSelection()[0][1]

	# Search for Fret Keyword in Note Objects
	osystens, systems = getChildren(score, 'system')
	for system in systems:
		ostaves, staves = getChildren(system, 'staff')
		staffID = 0
		for staff in staves:	
			ovoices, voices = getChildren(staff, 'voice')
			staffName = staff.getAttribute('layout')
			for voice in voices:
				oObjs, objs = getChildren(voice, 'noteObjects')
				for i in range(0,len(objs)):
					obj = objs[i]
					texts = obj.getElementsByTagName('text')
					if texts.length > 0:
						for text in texts:
							content = ''
							content_t = text.getElementsByTagName('content')[0].firstChild
							if content_t is not None:
								content = content_t.data
							fonts = text.getElementsByTagName('font')
							print('content=',content)
							if fonts.length > 0 and content.lower().replace("!","") == u'fret':
								is_aln = False
								if content.lower() == (u'fret!'):
									is_aln = True
								color = fonts[0].getAttribute('color')
								height = int(fonts[0].getAttribute('height'))
								fretInfoStaves.append((color, height, staffName, staffID, is_aln))
			staffID = staffID + 1
	if len(fretInfoStaves) > 1:
		for fretInfoStaff in fretInfoStaves:
			color, height, staffName, staffID, is_aln = fretInfoStaff
			if (selected_staff == staffID):
				return (color, height, staffName, is_aln)

	elif len(fretInfoStaves) == 1:
		color, height, staffName, staffID, is_aln = fretInfoStaves[0]
		return (color, height, staffName, is_aln)

	return (u'', 0, u'<?>', False)


def setLayoutClef(layout, clef):
	notation = layout.gotoChild('notation', True)
	notation.setAttribute('defaultClef', clef)

def setLayoutNoteLines(layout, noteLines):
	notation = layout.gotoChild('notation', True)
	notation.setAttribute('notelines', noteLines)

def setLayoutBarlines(layout, blFrom, blTo, blMode = 'internal'):
	notation = layout.gotoChild('notation', True)
	barlines = notation.gotoChild('barlines', True)
	barlines.setAttribute('from', str(blFrom))
	barlines.setAttribute('to', str(blTo))
	barlines.setAttribute('mode', blMode)

def setLayoutDistances(layout, disTop, disBottom, disLine):
	distances = layout.gotoChild('distances', True)
	distances.setAttribute('top', str(disTop))
	distances.setAttribute('bottom', str(disBottom))
	distances.setAttribute('lineDist', disLine)

def setSound(layout, instr, volume, sample, genericSound):
	sound = layout.gotoChild('sound', True)
	sound.setAttribute('instr', str(instr))
	sound.setAttribute('volume', str(volume))
	sound.setAttribute('sample', sample)
	sound.setAttribute('genericSound', genericSound)

def setInstrumentProperty(layout, tag, value):
	instrument = layout.gotoChild('instrument', True)
	names = instrument.getElementsByTagName(tag)
	for name in names:
		instrument.removeChild(name)
	instrument.setAttribute(tag, value)
	contentEl = doc.createElement(tag)
	textName = doc.createTextNode(value)
	contentEl.appendChild(textName)
	instrument.appendChild(contentEl)
	
def getStavesByLayout(score, name):
	retval = []
	osystens, systems = getChildren(score, 'system')
	for system in systems:
		ostaves, staves = getChildren(system, 'staff')
		newStaves = []
		for staff in staves:
			if staff.getAttribute('layout') == name:
				retval.append(staff)
	return retval

def analyzeScore(score):
	global estHasALTstaff
	global estFretIndexFontSize	
	global estFretIndexFontColor
	global estFretIndexStaffName
	global isAln
	global estCursorStaffName

	estCursorStaffName = '-'
	isAln = False
	estFretIndexFontColor, estFretIndexFontSize, estFretIndexStaffName, isAln = getFretColorAndSize(score)
	alnStaves = getStavesByLayout(score, setGenStaffName)
	if len(alnStaves) > 0:
		estHasALTstaff = True

	cursor = curSelection()[0]
	print('cursor', cursor)

	systemID = 0
	oSystems, systems = getChildren(score, 'system')
	for system in systems:
		oStaves, staves = getChildren(system, 'staff')
		staffID = 0
		for staff in staves:
			oVoices, voices = getChildren(staff, 'voice')
			voiceID = 0
			for voice in voices:
				oNoteObjs, noteObjs = getChildren(voice, 'noteObjects')
				objID = 0
				for obj in noteObjs:
					if cursor == (systemID, staffID, voiceID, objID):
						# get staff name
						estCursorStaffName = staff.getAttribute('layout')
					objID = objID + 1
				voiceID = voiceID + 1
			staffID = staffID + 1
		systemID = systemID + 1

# Analyze Phase
class ScoreAnalyze(ScoreChange):
	def changeScore(self, score):
		global doc
		doc = score.parentNode
		analyzeScore(score)

# Plugin Processing Phase
class ScoreChange(ScoreChange):
	def changeScore(self, score):
		global doc
		doc = score.parentNode
		aLT(score)

def objChord(tones = [], dura = '1/4', dots = None, tie_begin = False, tie_end = False):
	if tones == []:
		newEl = doc.createElement('rest')
	else:
		newEl = doc.createElement('chord')

	duration = newEl.gotoChild('duration', True)
	duration.setAttribute('base', dura)
	if dots is not None:
		duration.setAttribute('dots', str(dots))
	if tones != []:
		heads = newEl.gotoChild('heads', True)
		for tone in tones:
			head = doc.createElement('head')
			pitch, step = aca2capTone(tone, setOct4)
			if pitch is not None:
				head.setAttribute('pitch', pitch)
				if step is not None and step != 0:
					alter = doc.createElement('alter')
					alter.setAttribute('step', str(step))
					head.appendChild(alter)
				if tie_begin or tie_end:
					tienode = doc.createElement('tie')
					if tie_begin:
						tienode.setAttribute('begin', 'true')
					if tie_end:
						tienode.setAttribute('end', 'true')
					head.appendChild(tienode)
				heads.appendChild(head)
	return newEl

def setAlTabClef(obj, x, strings0):
	newUpperDrawObj = addDrawObject(obj)
	newTextGroup = addTextGroup(newUpperDrawObj)
	numStrings = len(strings0)
	stringNo = 0
	tonesLow = []
	if setShowStrings:
		for string in strings0:
			tone = re.sub('(.*)?[0-9].*', '\\1', string)
			if setUseGermanH:
				tone = re.sub('^B', 'H', tone)
				tone = re.sub('^b', 'h', tone)
				tone = re.sub('Hb', 'B', tone)
				tone = re.sub('hb', 'b', tone)
			tonesLow.append(tone)
			newDrawObj = addDrawObject(newTextGroup, False)
			addText(newDrawObj, tone, -8+x, -(stringNo - numStrings+2)*1.00-0.65, 'Arial', 4, weight=700)
			stringNo = stringNo + 1
		
	bottom = -(0 - numStrings+2)*1.00-0.6
	top = -1.00-0.6

	xPos = -6.5
	if not setShowStrings:
		xPos = -7.5
	size = numStrings * 9.0/ 6.5
	edgeOffs = size * 0.075
	textPositions = [top+edgeOffs, (bottom+top) / 2, bottom-edgeOffs]
	pos = 0
	for text in "aLT":
		newDrawObj = addDrawObject(newTextGroup, False)
		sizeOffs = (size-4) * 0.05
		addText(newDrawObj, text, xPos+x, textPositions[pos]+sizeOffs, 'Arial', size, weight=900)
		pos = pos + 1

def setAlTabClefInStaff(staff, strings0):
	ovoices, voices = getChildren(staff, 'voice')
	clefWasSet = False
	for voice in voices:
		onoteObjs, noteObjs = getChildren(voice, 'noteObjects')
		newNoteObjs = []
		first = True
		anchorPause = objChord([], '1/128')
		duration = anchorPause.gotoChild('duration', True)
		duration.setAttribute('noDuration', 'true')
		display = anchorPause.gotoChild('display', True)
		display.setAttribute('invisible', 'true')
		xOffs = 4.0
		for obj in noteObjs:
			if obj.localName == 'timeSign':
				xOffs = xOffs - 3.5 
			if obj.localName == 'barline':
				xOffs = xOffs - 3.5
			if obj.localName in ['chord', 'rest'] and first:
				if not clefWasSet:
					setAlTabClef(anchorPause, xOffs, getStringNames([strings0]))
				newNoteObjs.append(anchorPause)
				clefWasSet = True
				first = False
			newNoteObjs.append(obj)
		setChildren(onoteObjs, newNoteObjs, 'noteObjects')
	
def adjustAlTabChordsGlobalFretIndexes(staff, yTop, yBottom):
	ovoices, voices = getChildren(staff, 'voice')
	for voice in voices:
		onoteObjs, noteObjs = getChildren(voice, 'noteObjects')
		for obj in noteObjs:
			if obj.localName in ['chord', 'rest']:
				odrawObjs, drawObjs = getChildren(obj, 'drawObjects')
				for drawObj in drawObjs:
					if isTextCriteriaDrawObj(drawObj, 'chord') or getTextContent(drawObj) == 'aCN':
						if setChordsPosAbove:
							adjustGroupedTextPos(drawObj,yTop)
						else:
							adjustGroupedTextPos(drawObj,yBottom)
					elif isTextCriteriaDrawObj(drawObj, 'globalFretIndex'):
						if setFretIndexPosAbove:
							adjustGroupedTextPos(drawObj,yTop)
						else:
							adjustGroupedTextPos(drawObj,yBottom)

def adjustGroupedTextPos(drawObj, y):
	basics = drawObj.getElementsByTagName('basic')
	for basic in basics:
		if basic.getAttribute('placement') != '':
			basic.removeAttribute('placement')
	texts = drawObj.getElementsByTagName('text')
	yRel = None
	for text in texts:
		ty = text.getAttribute('y')
		try:
			float_ty = float(ty)
		except:
			float_ty = 0.0
		if yRel is None:
			yRel = y - float_ty
		text.setAttribute('y', str(yRel+float_ty))


def hideNonAlnObjsInStaff(staff):
	ovoices, voices = getChildren(staff, 'voice')
	for voice in voices:
		onoteObjs, noteObjs = getChildren(voice, 'noteObjects')
		for obj in noteObjs:
			if obj.localName == 'keySign':
				obj.setAttribute('fifths', '0')
			elif obj.localName in ['clefSign', 'chord', 'rest']:
				display = obj
				if obj.localName in ['chord', 'rest']:
					pass
					#display = obj.gotoChild('display', True)
					#display.setAttribute('invisible', 'true')
				else:
					obj.setAttribute('clef', 'N2')

def scale(value, original_min, original_max, new_min, new_max):
	return ((value - original_min) / (original_max - original_min)) * (new_max - new_min) + new_min

def getObjTextScaledYcoordsByCriteria(noteObj, criteria):
	ys = []
	minY = None
	maxY = None
	if noteObj.localName == 'chord':
		odrawObjs, drawObjs = getChildren(noteObj, 'drawObjects')
		if drawObjs is not None and len(drawObjs) > 0:
			for drawObj in drawObjs:
				if isTextCriteriaDrawObj(drawObj, criteria):
					text = drawObj.gotoChild('text', False)
					# invert sign to treat higher text to higher note
					_y = -float(text.getAttribute('y'))
					if minY is None:
						minY = _y
					else:
						minY = min(minY, _y)
					if maxY is None:
						maxY = _y
					else:
						maxY = max(maxY, _y)
					ys.append(_y)
	scaled_ys = []
	if len(ys) < 2 or abs(maxY-minY) < 0.001:
		return None
	for y in ys:
		scaled_ys.append(scale(y, minY, maxY, 0, 100))
	return scaled_ys

def deleteObjLyrics(noteObj):
	lyric = noteObj.gotoChild('lyric', False)
	if lyric is not None:
		noteObj.removeChild(lyric)

def deleteObjTextAttributesByCriteria(noteObj, criteria, keepDrawObjs=None):
	_keepDrawObjs = []
	if noteObj.localName in ['chord', 'rest']:
		odrawObjs, drawObjs = getChildren(noteObj, 'drawObjects')
		if drawObjs is not None and len(drawObjs) > 0:
			for drawObj in drawObjs:
				keepCount = 0
				if keepDrawObjs is not None:
					keepCount = keepDrawObjs.count(drawObj)
				if not isTextCriteriaDrawObj(drawObj, criteria) or keepCount > 0:
					_keepDrawObjs.append(drawObj)
		if len(drawObjs) > 0:
			noteObj.removeChild(odrawObjs)
		if len(_keepDrawObjs) > 0:
			drawObjects = noteObj.gotoChild('drawObjects', True)
			setChildren(drawObjects, _keepDrawObjs, 'drawObjects')
	
def getObjTextObjsByCriteria(noteObj, criteria):
	texts = []
	if noteObj.localName == 'chord':
		odrawObjs, drawObjs = getChildren(noteObj, 'drawObjects')
		if drawObjs is not None and len(drawObjs) > 0:
			for drawObj in drawObjs:
				if isTextCriteriaDrawObj(drawObj, criteria):
					texts.append(drawObj)
	return texts

def isTextCriteriaDrawObj(drawObj, criteria):
	text = drawObj.gotoChild('text', False)
	richText = drawObj.gotoChild('richText', False)
	basic = drawObj.gotoChild('basic', False)
	transposable = drawObj.gotoChild('transposable', False)
	group = drawObj.gotoChild('group', False)
	if transposable is not None:
		if criteria == 'chord':
			return True
		else:
			return False
	if group is not None: 
		drOb = group.gotoChild('drawObj', False)
		if drOb is not None:
			if criteria == 'chord':
				return True
			else:
				return False
	if text is not None:
		font = text.gotoChild('font', False)
		if font is not None:
			face = font.getAttribute('face')
			# Music Symbol Criteria (capella3 font face)
			if face == 'capella3':
				if criteria == 'musicSymbol':
					return True
				else:
					return False
			height = font.getAttribute('height')
			try:
				height = int(height)
			except:
				height = 0
			color = font.getAttribute('color')
			# Global Fret Index Criteria (font color and size)
			if color == estFretIndexFontColor and height == estFretIndexFontSize:
				if criteria == 'globalFretIndex':
					return True
				else:
					return False
			# Local Fret Index Criteria (font color and size)
			if color == estFretIndexFontColor and height < estFretIndexFontSize:
				if criteria == 'localFretIndex':
					return True
				else:
					return False
		# Fingering criteria (placementHint)
		if basic is not None and basic.getAttribute('placementHint') == 'fingering':
			if criteria == 'fingering':
				return True
			else:
				return False 
		# Simple Text (without placementHint) or Performance Instruction (placementHint)
		if (basic is None) or (basic is not None and basic.getAttribute('placementHint') in ['', 'performanceInstruction']) :
			if criteria == 'simple':
				return True
			else:
				return False
	# Rich Text (richText Child is present)
	if richText is not None:
		if criteria == 'richText':
			return True
		else:
			return False
	return False

def hideTremoloBars(noteObj):
	oDrawObjects, drawObjects = getChildren(noteObj, 'drawObjects')
	if drawObjects is not None:
		for drawObject in drawObjects:
			oGroupElements, groupElements = getChildren(drawObject,'group')
			for groupElement in groupElements:
				if groupElement is not None:
					gdoPolygon = groupElement.gotoChild('polygon')
					if gdoPolygon is not None:
						gdoPolygon.setAttribute('fillColor', 'ffffff')

def getTextContent(drawObj):
	text = drawObj.gotoChild('text', False)
	if text is not None:
		content = ''
		content_t = text.getElementsByTagName('content')[0].firstChild
		if content_t is not None:
			content = content_t.data
		return content
	return None

def getObjTextIndexByCriteria(noteObj, pitch, pitches, scaled_ys, criteria):
	texts = getObjTextObjsByCriteria(noteObj, criteria)
	if len(texts) == 0:
		return None
	elif len(texts) == 1:
		return 0
	else:
		minPitch = float(midiPitch(pitch))
		maxPitch = float(midiPitch(pitch))
		for p in pitches:
			mp = float(midiPitch(p))
			minPitch = min(minPitch, mp)
			maxPitch = max(maxPitch, mp)
			
		scaled_pitch = scale(float(midiPitch(pitch)), minPitch, maxPitch, 0.0, 100.0)

		diffs = []
		if scaled_ys is None:
			return None
		for scaled_y in scaled_ys:
			diffs.append(abs(scaled_y - scaled_pitch))

		# Get the Text object that is neartest to the pitch (scaled values)
		min_diff=min(diffs)
		return diffs.index(min_diff)

def getStringNames(fretBoard, withOctave = False):
	retval = []

	openStrings = fretBoard[0]
	stringNames = []
	for string in openStrings:
		stringName = re.sub('(.*)?[0-9].*','\\1',string)
		stringNames.append(stringName)

	countedStrings = []
	for string in openStrings:
		stringName = re.sub('(.*)?[0-9].*','\\1',string)
		octave = re.sub('.*?([0-9].*)','\\1',string)
		count = stringNames.count(stringName)
		countedStrings.append(stringName)
		currentString = countedStrings.count(stringName)
		makeLower = False
		makeStroke = False
		if count <= 2:
			if currentString == 2:
				makeLower = True
		elif count == 3:
			if currentString == 1:
				makeStroke = True
			elif currentString == 3:
				makeLower = True
		elif count == 4:
			if currentString == 1:
				makeStroke = True
			elif currentString == 3:
				makeLower = True
			elif currentString == 4:
				makeStroke = True
				makeLower = True
		if makeStroke:
			stringName = stringName + "'"
		if makeLower:
			stringName = stringName.lower()
		if withOctave:
			stringName = stringName + octave
		retval.append(stringName)
	return retval

def getTremoloNotesAndDura(obj, nextObj=None):
	baseNotePitches = None
	if obj is not None:
		baseNotePitches = getPitches(obj)
	nextNotePitches = None
	if nextObj is not None:
		nextNotePitches = getPitches(nextObj)

	baseNoteBase = None
	baseNoteDots = None
	baseNoteNoDura = False
	tremoloBars = None
	if obj is not None:
		if obj.localName == 'chord':
			duration = obj.gotoChild('duration')
			if duration is not None:
				baseNoteBase = duration.getAttribute('base')
				baseNoteDots = duration.getAttribute('dots')
				noDuration = duration.getAttribute('noDuration')
				if noDuration == 'true':
					baseNoteNoDura = True
			stem = obj.gotoChild('stem', False)
			if stem is not None:
				tremBars = stem.getAttribute('tremoloBars')
				if tremBars != '':
					tremoloBars = int(tremBars)

	nextNoteBase = None
	nextNoteDots = None
	nextNoteNoDura = False
	if nextObj is not None:
		if nextObj.localName == 'chord':
			duration = nextObj.gotoChild('duration', False)
			if duration is not None:
				nextNoteBase = duration.getAttribute('base')
				nextNoteDots = duration.getAttribute('dots')
				noDuration = duration.getAttribute('noDuration')
				if noDuration == 'true':
					nextNoteNoDura = True

	odrawObjs, drawObjs = getChildren(obj, 'drawObjects')
	for drawObj in drawObjs:
		basic = drawObj.gotoChild('basic', False)
		if basic is not None:
			tag = basic.getAttribute('tag')
			if tag == tremoloBarTag:
				group = drawObj.gotoChild('group', False)
				if group is not None:
					gDrawObjs = childElements(group, 'drawObj')
					tremoloBars = len(gDrawObjs)

	if baseNoteNoDura == False and nextNoteNoDura == True:
		if baseNoteBase == nextNoteBase and baseNoteDots == nextNoteDots:
			# Dual Tremolo
			return ((baseNoteBase, baseNoteDots, tremoloBars), baseNotePitches, nextNotePitches)
		else:
			# Mono Tremolo
			return ((baseNoteBase, baseNoteDots, tremoloBars), baseNotePitches, None)
	else:
		if baseNoteNoDura == False:
			# Mono Tremolo
			return ((baseNoteBase, baseNoteDots, tremoloBars), baseNotePitches, None)

	# Not a valid Tremolo Base Note
	return ((None, None, None), None, None)

def getALNstaffIDs(score):
	osystems, systems = getChildren(score, 'system')
	# Find "fret!" Keyword
	aLNstaffIDs = []
	systemID = 0
	for system in systems:
		staffID = 0
		ostaves, staves = getChildren(system, 'staff')
		for staff in staves:
			ovoices, voices = getChildren(staff, 'voice')
			for voice in voices:
				onoteobjs, noteObjs = getChildren(voice, 'noteObjects')
				for obj in noteObjs:
					texts = getObjTextObjsByCriteria(obj, 'globalFretIndex')
					for text in texts:
						content = getTextContent(text)
						if content.strip().lower() == 'fret!':
							aLNstaffIDs.append(staffID)
			staffID = staffID + 1
		systemID = systemID + 1
	return list(set(aLNstaffIDs))

def aLT(score):
	global estHasALTstaff

	aLNstaffIDs = getALNstaffIDs(score)
	layout = score.gotoChild("layout")

	selected_staff = curSelection()[0][1]
	selected_system = curSelection()[0][0]
	
	systemID = 0
	instIndex = None
	osystems, systems = getChildren(score, 'system')
	# Find Instrument Marker
	for system in systems:
		staffID = 0
		ostaves, staves = getChildren(system, 'staff')
		for staff in staves:
			if selected_staff == staffID:
				ovoices, voices = getChildren(staff, 'voice')
				for voice in voices:
					onoteobjs, noteObjs = getChildren(voice, 'noteObjects')
					for obj in noteObjs:
						texts = getSimpleTexts(obj)
						for text in texts:
							text = text.strip()
							instNameList = [x[0] for x in instruments]
							if instNameList.count(text) > 0:
								if instIndex is not None:
									msgInstMarkerNotAllowed(instNameList[instIndex],text)
								instIndex = instNameList.index(text)
			staffID = staffID + 1
		systemID = systemID + 1

	# Take the selected Instrument Index if no Instrument Marker was set
	if instIndex is None:
		instIndex = setInstrumentIndex
	instrumentName, instrumentOpenTuning, instrumentFretCycle = instruments[instIndex]
	fretBoard = genFretBoard(instrumentOpenTuning, instrumentFretCycle)

	ostaffLayouts, staffLayouts = getChildren(layout, 'staffLayout', forcedPlural = 'staves')
	lastLayout = None
	oldAlnLayout = None
	allStaffNames = []
	for staffLayout in staffLayouts:
		description = staffLayout.getAttribute('description')
		lastLayout = staffLayout
		allStaffNames.append(description)
		if description == setGenStaffName:
			oldAlnLayout = staffLayout.cloneNode(deep=True)

	alnLayout = lastLayout.cloneNode(deep=True)

	alnLayout.removeAttribute('description')
	alnLayout.setAttribute('description', setGenStaffName)
	distances = layout.gotoChild('distances', True)
	staffLines = distances.gotoChild('staffLines', True)
	staffLines.setAttribute('small', '2.72')

	setInstrumentProperty(alnLayout, 'name', setInstrumentName)
	setInstrumentProperty(alnLayout, 'abbrev', '')
	#setSound(patternLayout, 127, 80, 'MIDI-Schlagzeugkanal', 'percussion.midi')
	setLayoutClef(alnLayout, 'N2')
	numStrings = len(instrumentOpenTuning)
	setLayoutNoteLines(alnLayout, '_'*(8-numStrings)+'|'*numStrings+'___')
	setLayoutBarlines(alnLayout, 8-numStrings, 7, 'internal')
	setLayoutDistances(alnLayout, 8, 4, 'small')
	reCreate = False

	if oldAlnLayout is not None:
		notation = oldAlnLayout.gotoChild('notation', False)
		if notation is not None:
			noteLines = notation.getAttribute('notelines')
			lineCount = noteLines.count('|')
			if lineCount != numStrings:
				msgInstrumentChanged(lineCount, numStrings)
				return

	if setGenStaffName not in allStaffNames:
		staffLayouts.extend([alnLayout])
	setChildren(ostaffLayouts, staffLayouts, 'staves')

	italic_voices = [setItalicVoice1, setItalicVoice2, setItalicVoice3]
	color_voices = [colorMap[setColorVoice1][1], colorMap[setColorVoice2][1], colorMap[setColorVoice3][1]]
	if setColorFingerNumbers:
		fingeringColor = 'FF0000'
	else:
		fingeringColor = '000000'
	stringsWoOctave = getStringNames(fretBoard, withOctave = False)
	systemID = 0
	osystems, systems = getChildren(score, 'system')
	failed = False

	extraDistTopList = []
	for system in systems:
		staffID = 0
		ostaves, staves = getChildren(system, 'staff')
		for staff in staves:
			extraDistance = staff.gotoChild('extraDistance', False)
			if extraDistance is not None:
				top = extraDistance.getAttribute('top')
				if top is not None:
					extraDistTopList.append((systemID, staffID, top))
			else:
				extraDistTopList.append((systemID, staffID, 0))
			staffID = staffID + 1
		systemID = systemID + 1

	systemID = 0
	for system in systems:
		staffID = 0
		ostaves, staves = getChildren(system, 'staff')
		new_staves = []
		origStaff = None
		for staff in staves:
			if selected_staff == staffID:
				origStaff = staff
			layout = staff.getAttribute('layout')
			reCreate = False
			if layout == setGenStaffName:
				reCreate = True
			staffID = staffID + 1

		if selected_system == systemID or setALNcreate == 0:
			staffID = 0
			for staff in staves:
				ovoices, voices = getChildren(staff, 'voice')
				# Shor/Hide all '-' for Fingering / Local Fret Index if set
				for voice in voices:
					oNoteObjs, noteObjs = getChildren(voice, 'noteObjects')
					for noteObj in noteObjs:
						setTextObjFretFingeringVisibility(noteObj)
				new_staff = None
				layout = staff.getAttribute('layout')
				if selected_staff == staffID and layout == setGenStaffName and not failed:
					msgALNselected()
					failed = True
				if not reCreate and selected_staff == staffID and (selected_system == systemID or setALNcreate == 0) and not failed:
					new_staff = origStaff.cloneNode(deep = True)
					new_staff.setAttribute('layout', setGenStaffName)
					index = None
					idx = 0
					for distElem in extraDistTopList:
						if distElem[0]==systemID and distElem[1]==staffID:
							index = idx
						idx = idx + 1
					if index is not None:
						top = extraDistTopList[min(index + 1, len(extraDistTopList)-1)][2]
						extraDistance = new_staff.gotoChild('extraDistance', True)
						try:
							distance = int(top)+int(setALNtopDistance)
						except:
							distance = 0
						extraDistance.setAttribute('top', str(distance))
				elif staff.getAttribute('layout') == setGenStaffName and not failed:
					new_staff = staff
					clearStaff(new_staff)
					origClone = origStaff.cloneNode(deep = True)
					copyStaff(origClone, new_staff)
				if new_staff is not None:
					hideNonAlnObjsInStaff(new_staff)
					try:
						yChordFretIndexPos = float(setChordFretIndexPos)
					except:
						yChordFretIndexPos = 0.0
					yTop = -yChordFretIndexPos
					yBottom = numStrings + (yChordFretIndexPos-3.5)
					adjustAlTabChordsGlobalFretIndexes(new_staff, yTop, yBottom)
					setAlTabClefInStaff(new_staff, instrumentOpenTuning)
					oTabVoices, tabVoices = getChildren(new_staff, 'voice')
					oSoundVoices, soundVoices = getChildren(new_staff, 'voice')
					if isAln and selected_staff in aLNstaffIDs:
						tabVoices = tabVoices[0:len(tabVoices)/2]	
						soundVoices = soundVoices[len(soundVoices)/2+1:len(soundVoices)/2+1]	
					voiceID = 0
					tieEndFirstUnplaced = True
					for voice in tabVoices:
						italic = italic_voices[voiceID % len(italic_voices)]
						custom_color = color_voices[voiceID % len(color_voices)]
						onoteObjects, noteObjects = getChildren(voice, 'noteObjects')
						numObjs = len(noteObjects)
						tab_notes = []
						tabClefAnchorUsed = False
						for i in range(0, numObjs):
							obj = noteObjects[i]
							if i+1 < numObjs:
								nextObj = noteObjects[i+1]
							else:
								nextObj = None
							prefix = None
							suffix = None
							pauseSymCap3 = None
							numAposthophs = None
							numDots = None
							display = None
							invisible = False
							small = False
							if obj.localName in ['chord','rest']:
								duration = obj.gotoChild('duration')
								noDuration = duration.getAttribute('noDuration')
								base = duration.getAttribute('base')
								dots = duration.getAttribute('dots')
								display = obj.gotoChild('display', False)
								if display is not None:
									invisible_t = display.getAttribute('invisible')
									if invisible_t == 'true':
										invisible = True
									small_t = display.getAttribute('small')
									if small_t == 'true':
										small = True
								display = obj.gotoChild('display', True)
								display.setAttribute('invisible', 'true')
								if dots is None or dots == '':
									dots = '0'
								prefix = ''
								suffix = ''
								pauseSymCap3 = 'K'
								numAposthophs = 0
								baseSplit = base.split('/')
								baseNum = baseSplit[0]
								if len(baseSplit) > 1:
									baseDenum = baseSplit[1] 
								else:
									baseDenum = '1'
								baseNum = int(baseNum)
								baseDenum = int(baseDenum)
								if baseNum == 1:
									if baseDenum <= 2:
										prefix = '('
										pauseSymCap3 = 'I'
									if baseDenum == 1:
										suffix = ')'
										pauseSymCap3 = 'J'
									while baseDenum > 4:
										baseDenum = baseDenum / 2
										numAposthophs = numAposthophs + 1
								numDots = int(dots)
								if numAposthophs > 0:
									pauseSymCap3 = chr(ord('L')+numAposthophs-1)
								pauseSymCap3 = pauseSymCap3 +'.'*numDots
								if noDuration == 'true':
									pauseSymCap3 = ''
							if obj.localName == 'rest':
								verticalPos = obj.gotoChild('verticalPos', False)
								if verticalPos is not None:
									obj.removeChild(verticalPos)
								noteColor = None
								color = display.getAttribute('color')
								if color is not None and color != '':
									noteColor = color
								if custom_color is not None:
									if custom_color == '-':
										noteColor = None
									else:
										noteColor = custom_color
								if len(tabVoices) == 1:
									yPos = -(-voiceID*2)*1.00+float(setSizeFretNumbers)*0.1-1.15
								elif len(tabVoices) == 2:
									yPos = -(-voiceID*2)*1.00+float(setSizeFretNumbers)*0.1-1.15
								else:
									yPos = -(-voiceID)*1.00+float(setSizeFretNumbers)*0.1-1.15
								if len(pauseSymCap3) > 0 and not invisible:
									if len(pauseSymCap3) == 1:
										newDrawObj = addDrawObject(obj)
										yOffs = 0.0
										if pauseSymCap3[0] in ['L', 'M', 'N', 'O']:
											yOffs = 0.6
										elif pauseSymCap3[0] == 'I':
											yOffs = 1.0
										addText(newDrawObj, pauseSymCap3, 0+0.3, yPos+yOffs, 'Capella3', float(setSizeFretNumbers)*2.5, color = noteColor, italic = italic)
										tab_notes.append(newDrawObj)
									elif len(pauseSymCap3) > 1:
										newDrawObj = addDrawObject(obj)
										newTextGroup = addTextGroup(newDrawObj)
										newInnerDrawObj = addDrawObject(newTextGroup, False)
										yOffs = 0.0
										if pauseSymCap3[0] in ['L', 'M', 'N', 'O']:
											yOffs = 0.6
										elif pauseSymCap3[0] == 'I':
											yOffs = 1.0
										addText(newInnerDrawObj, pauseSymCap3[0], 0, yPos + yOffs, 'Capella3', float(setSizeFretNumbers)*2.5, color = noteColor, italic = italic)
										tab_notes.append(newDrawObj)
										xPos = 0.2+0.3
										for char in pauseSymCap3[1:]:
											newInner2DrawObj = addDrawObject(newTextGroup, False)
											addText(newInner2DrawObj, char, xPos, yPos + 0.1, 'Capella3', float(setSizeFretNumbers)*2.5, color = noteColor, italic = italic)
											xPos = xPos + 0.3

							if obj.localName == 'chord':
								pitches = getPitches(obj)
								ties = getTies(obj)

								tremoloBars = None
								stem = obj.gotoChild('stem', False)
								if stem is not None:
									tremoloBars = stem.getAttribute('tremoloBars')
						
								pitches_org = pitches	
								pitches = []
								for pitch in pitches_org:
									has_sharp = pitch.count('#') > 0
									pitch = transposeTone(pitch, -12, has_sharp)
									pitches.append(pitch)

								fingeringScaled_ys = getObjTextScaledYcoordsByCriteria(obj, 'fingering')
								fingeringTextObjs = getObjTextObjsByCriteria(obj, 'fingering')
								localFretIndexScaled_ys = getObjTextScaledYcoordsByCriteria(obj, 'localFretIndex')
								localFretIndexTextObjs = getObjTextObjsByCriteria(obj, 'localFretIndex')
								objDrawObjs = obj.gotoChild('drawObjects', False)

								# Get Fingering Text Objects in the order of Pitches
								pitchFingeringTexts = []
								for pitch in pitches:
									index = None
									if len(pitches) == 1:
										if len(fingeringTextObjs) == 1:
											index = 0
									else:
										index = getObjTextIndexByCriteria(obj, pitch, pitches, fingeringScaled_ys, 'fingering')
									if index is not None and len(fingeringTextObjs) == len(pitches):
										ft = fingeringTextObjs[index]
										text = getTextContent(ft)
										pitchFingeringTexts.append(text)
									else:
										pitchFingeringTexts.append('')

								# Get Local Fret Index Text Objects in the order of Pitches
								pitchLocalFretIndexTexts = []
								for pitch in pitches:
									index = None
									if len(pitches) == 1:
										if len(localFretIndexTextObjs) == 1:
											index = 0
									else:
										index = getObjTextIndexByCriteria(obj, pitch, pitches, localFretIndexScaled_ys, 'localFretIndex')
									if index is not None and len(localFretIndexTextObjs) == len(pitches):
										ft = localFretIndexTextObjs[index]
										text = getTextContent(ft)
										pitchLocalFretIndexTexts.append(text)
									else:
										pitchLocalFretIndexTexts.append('')

								# Remove original Fingering Text
								for ft in fingeringTextObjs:
									if objDrawObjs:
										objDrawObjs.removeChild(ft)

								# Remove original local Fret Index Text
								for ft in localFretIndexTextObjs:
									if objDrawObjs:
										objDrawObjs.removeChild(ft)

								noteColor = None
								display = obj.gotoChild('display', False)
								if display is not None:
									color = display.getAttribute('color')
									if color is not None and color != '':
										noteColor = color
								if color is not None and color != '':
									noteColor = color
								if custom_color is not None:
									if custom_color == '-':
										noteColor = None
									else:
										noteColor = custom_color
								duration = obj.gotoChild('duration', False)
								noDuration = None
								if duration is not None:
									noDuration = duration.getAttribute('noDuration')
		
								pitchID = 0
								tieFirstPlaced = False
								for pitch in pitches:
									localFretIndexText = ''								
									if pitchLocalFretIndexTexts[pitchID] is not None:
										localFretIndexText = pitchLocalFretIndexTexts[pitchID]

									fingerText = ''
									if pitchFingeringTexts[pitchID] is not None:
										fingerText = pitchFingeringTexts[pitchID]

									sfs = getStringFretList(fretBoard, pitch)
									if fingerText.count(',') == 1:
										fingerString, fingerText = fingerText.split(',')
										fString = re.sub('(.*)?[0-9].*','\\1',fingerString)
										if stringsWoOctave.count(fString) > 0:
											string = stringsWoOctave.index(fString)
											fFret = re.sub('.*?([0-9].*)','\\1',fingerString)
											fret = int(fFret)
											sfs = [(string, fret)]
									else:
										fString = re.sub('(.*)?[0-9].*','\\1',fingerText)
										if stringsWoOctave.count(fString) > 0:
											string = stringsWoOctave.index(fString)
											fFret = re.sub('.*?([0-9].*)','\\1',fingerText)
											fret = int(fFret)
											sfs = [(string, fret)]
											fingerText = ''
		
									if len(sfs) > 0:
										string, fret = sfs[0]
										yPos = -(string - numStrings+2)*1.00+float(setSizeFretNumbers)*0.1-1.1
										symbol = prefix+str(fret)+suffix+"'"*numAposthophs+'.'*numDots
										weight = None
										if len(pitches) > 1 and setChordTypeBold:
											weight = 700
										xPos = -symbol.count('(')*0.45+0.3
										newDrawObj = addDrawObject(obj)
										if not invisible:
											underline = False
											leftLine = False
											tremDura, tremBasePitches, tremNextPitches = getTremoloNotesAndDura(obj, nextObj)
											numTremBars = None
											if tremDura is not None:
												tremDuraBase = tremDura[0]
												tremDuraDots = tremDura[1]
												tremDuraTremBars = tremDura[2]
												if tremDuraTremBars is not None and tremDuraTremBars > 0:
													numTremBars = tremDuraTremBars
													xPos = xPos - numTremBars * 0.3
											if tremoloBars == "1" and small:
												underline = True
											elif noDuration == 'true':
												leftLine = True
											addText(newDrawObj, symbol, xPos, yPos, 'Arial', float(setSizeFretNumbers), weight = weight, italic = italic, color = noteColor, underline = underline, leftline = leftLine, trembars  = numTremBars)
											tab_notes.append(newDrawObj)
										xOffs = xPos + symbol.count('(')*0.40+symbol.count(')')*0.40 + symbol.count('.')*0.30

										newDrawObj = addDrawObject(obj)
										weight = 100
										if localFretIndexText.strip() == '-':
											localFretIndexText = ''
										addText(newDrawObj, localFretIndexText, 0.7+xOffs, yPos+0.36, 'Arial', float(setSizeLocalFretIndex), weight = weight, italic = italic, color = estFretIndexFontColor)
										tab_notes.append(newDrawObj)
		
										if setShowFingering:
											newDrawObj = addDrawObject(obj)
											weight = 100
											if fingerText.strip() == '-':
												fingerText = ''
											addText(newDrawObj, fingerText, 0.7+xOffs, yPos+0.36, 'Arial', float(setSizeFingerNumbers), weight = weight, italic = italic, color = fingeringColor)
											tab_notes.append(newDrawObj)
										else:
											deleteObjTextAttributesByCriteria(obj, 'fingering')
										xTieOffs = 0.0
										stemDir = voice.getAttribute('stemDir')
										# Get Tie end for pitchID
										slurYoffsTip = -0.7
										slurYoffsBow = -2.0
										if stemDir == 'down':
											slurYoffsTip = 0.0
											slurYoffsBow = 1.3

										if ties[pitchID][1] and tieEndFirstUnplaced:
											tieFirstPlaced = True
											setSlur(obj, 0, 0.3, yPos+slurYoffsTip, 0.3, yPos+slurYoffsBow, -3.0, yPos+slurYoffsBow, -3.0, yPos+slurYoffsTip)
										# Get Tie begin for pitchID
										if ties[pitchID][0]:
											# On last Note, a tie must be stretched
											tieFirstPlaced = True
											noteRange = 1
											if i == numObjs-1:
												xTieOffs = 3.0
												noteRange = 0
											setSlur(obj, noteRange, 0.5, yPos+slurYoffsTip, 0.5, yPos+slurYoffsBow, 0.3+xTieOffs, yPos+slurYoffsBow, 0.3+xTieOffs, yPos+slurYoffsTip)
									else:
										#yPos = -(string - numStrings+2)*1.00+float(setSizeFretNumbers)*0.1-1.1
										if len(tabVoices) == 1:
											yPos = 0
										elif len(tabVoices) == 2:
											yPos = -(-voiceID*2)*1.00+float(setSizeFretNumbers)*0.1-1.1
										else:
											yPos = -(-voiceID)*1.00+float(setSizeFretNumbers)*0.1-1.1
										newDrawObj = addDrawObject(obj)
										# Out of range note
										addText(newDrawObj, pitch.lower() , 0, yPos, 'Arial', float(setSizeFretNumbers)*1.2, color = 'FF0000', italic = italic)
										tab_notes.append(newDrawObj)
										deleteObjTextAttributesByCriteria(obj, 'fingering')
										deleteObjTextAttributesByCriteria(obj, 'localFretIndex')
									pitchID = pitchID + 1
									if tieFirstPlaced:
										tieEndFirstUnplaced = False

							if tabClefAnchorUsed:
								if not setChordsShow:
									deleteObjTextAttributesByCriteria(obj, 'chord', keepDrawObjs=tab_notes)
								if not setSimpleTextShow:
									deleteObjTextAttributesByCriteria(obj, 'simple', keepDrawObjs=tab_notes)
								if not setMusicSymbolsShow:
									deleteObjTextAttributesByCriteria(obj, 'musicSymbol', keepDrawObjs=tab_notes)
								if not setRichTextShow:
									deleteObjTextAttributesByCriteria(obj, 'richText')
								if not setLyricsShow:
									deleteObjLyrics(obj)
								hideTremoloBars(obj)
							if obj.localName == 'rest':
								tabClefAnchorUsed = True
							oDrawObjs, drawObjs = getChildren(obj, 'drawObjects')
							if drawObjs is not None:
								for drawObj in drawObjs:
									volta = drawObj.gotoChild('volta', False)
									basic = drawObj.gotoChild('basic', False)
									if volta is not None:
										basic.setAttribute('placement', 'auto')

						voiceID = voiceID + 1
					if not reCreate:
						new_staves.append(new_staff)
				staffID = staffID + 1
		if not failed:
			staves.extend(new_staves)
			setChildren(ostaves, staves, 'staves')
		systemID = systemID + 1
	global embeddedFileCopyList
	embeddedFileCopyList = getReAlignFileCopyList(score)

class Config:
	def __init__(self):
		self.file = ScriptOptions()
		self.dic = {}

	def get(self, varName, defValue = None):
		try:
			value = self.dic.get(varName)
			if defValue is not None:
				if value is None:
					value = defValue
					if type(defValue) is bool:
						defValue = str(value).lower
					elif type(defValue) is int:
						defValue = int(value)
					self.set(varName, defValue)
				else:
					if type(defValue) is bool:
						if value == 'true':
							value = True
						elif value == 'false':
							value = False
						elif value == '1':
							value = True
						elif value == '0':
							value = False
					if type(defValue) is int:
						value = int(value)
			return value
		except:
			pass
		return None
	
	def set(self, varName, value):
		if type(value) is bool:
			value = str(value).lower()
		if type(value) is int:
			value = str(value)
		self.dic.update({varName: value})

	def load(self):
		try:
			self.dic = self.file.get()
			for key in self.dic.keys():
				value = self.dic.get(key)
				if value == 'false':
					value = False
				elif value == 'true':
					value = True
				self.dic.update({key: value})
			print("loaded", self.dic)
		except:
			print("Could not open configuration file",self.file)

	def save(self):
		try:
			for key in self.dic.keys():
				value = self.dic.get(key)
				if type(value) is bool:
					value = str(value).lower()
				self.dic.update({key: value})
			self.file.set(self.dic)
		except:
			print("Could not save configuration file",self.file)

def getReAlignFileCopyList(score):
	copyList = []
	RTFobjs = score.getElementsByTagName('richText')
	objCounter = 1
	for RTFobj in RTFobjs:
		oldfilename = RTFobj.getAttribute('file')
		newfilename = re.sub('(.*)[0-9]+\.rtf','\\1', oldfilename)+str(objCounter)+'.rtf'
		oldfilenameHtml = RTFobj.getAttribute('fileHtml')
		newfilenameHtml = re.sub('(.*)[0-9]+\.html','\\1', oldfilenameHtml)+str(objCounter)+'.html'
		RTFobj.setAttribute('file',newfilename)
		RTFobj.setAttribute('fileHtml',newfilenameHtml)
		copyList.append((oldfilename, newfilename))
		copyList.append((oldfilenameHtml, newfilenameHtml))
		objCounter = objCounter + 1
	#WMFobjs = src_staff.getElementsByTagName('metafile')
	#for WMFobj in WMFobjs:
		#oldfilnam = WMFobj.getAttribute('file')
		#WMFobj.setAttribute('file',mapOtherFiles[oldfilnam])
	return copyList

def copyAndRepackFiles(zipFile, copyList):
	writeFileNameWithDataList = []

	zip = zipfile.ZipFile(zipFile,'r', zipfile.ZIP_DEFLATED)
	for fileInfo in zip.filelist:
		fileName = fileInfo.filename
		srcFile = zip.open(fileName)
		data = srcFile.read()
		srcFile.close()
		skip = False
		for copyListItem in copyList:
			srcFileName, destFileName = copyListItem
			if fileName == destFileName and srcFileName != destFileName:
				skip = True
		if not skip:
			writeFileNameWithDataList.append((fileName, data))

	for fileSrcDst in copyList:
		srcFileName, destFileName = fileSrcDst
		if srcFileName != destFileName:
			srcFile = zip.open(srcFileName)
			data = srcFile.read()
			srcFile.close()
			writeFileNameWithDataList.append((destFileName, data))
	zip.close()

	zip2 = zipfile.ZipFile(zipFile,'w', zipfile.ZIP_DEFLATED)
	for writeFileNWD in writeFileNameWithDataList:
		destFileName, data = writeFileNWD
		zi = zipfile.ZipInfo(destFileName, (1980, 1, 1, 0, 0, 0))
		zip2.writestr(zi, data)
	zip2.close()

estHasALTstaff = False
config = Config()
config.load()
setGenStaffName = config.get('setGenStaffName', 'Pattern')

colorMap = [
	['Original', None],   # None is used to keep original color
	['Schwarz', '-'],     # '-' is used to delete color attribute
	['Rot', 'AA0000'],
	['Orange', 'FFAA00'],
	['Grün', '00AA00'],
	['Blau', '00AAFF'],
	['Violett', 'AA00FF'],
]

instruments = [
	('S6 Gitarre Std', ['E3', 'A3', 'D4', 'G4', 'B4', 'E5'], 5),
	('S7 Gitarre Std', ['B2', 'E3', 'A3', 'D4', 'G4', 'B4', 'E5'], 5),
	('S4 Bass Std', ['E2', 'A2', 'D3', 'G3'], 5),
	('S5 Bass Std',['B1', 'E2', 'A2', 'D3', 'G3'], 5),
	('S4 acaBass-Low', ['E3', 'A3', 'D4', 'G4'], 5),
	('S4 acaBass-High', ['E4', 'A4', 'D5', 'G5'], 5),
	('S5 acaBass-Low', ['B2', 'E3', 'A3', 'D4', 'G4'], 5),
	('S5 acaBass-High', ['B3', 'E4', 'A4', 'D5', 'G5'], 5),
	('S4 Ukulele Std', ['G4', 'C4', 'E4', 'A4'], 5),
	('S4 Ukulele aLT', ['G5', 'C4', 'E4', 'A4'], 5),
	('S4 Mandoline Std', ['G3', 'D4', 'A4', 'E5'], 7),
	('S6 Gitarre DADGAD', ['D3', 'A3', 'D4', 'G4', 'A4', 'D5'], 7),
	('S6 Gitarre Open-C', ['C3', 'G3', 'C4', 'G4', 'C5', 'E5'], 7),
	('S6 Gitarre Drop-C', ['C3', 'G3', 'C4', 'F4', 'A4', 'D5'], 7),
	('S6 Gitarre Open-D', ['D3', 'A3', 'D4', 'F#4', 'A4', 'D5'], 7),
	('S6 Gitarre Open-Dm', ['D3', 'A3', 'D4', 'F4', 'A4', 'D5'], 7),
	('S6 Gitarre Drop-D', ['D3', 'A3', 'D4', 'G4', 'B4', 'E5'], 7),
	('S6 Gitarre Double-Drop-D', ['D3', 'A3', 'D4', 'G4', 'B4', 'D5'], 7),
	('S6 Gitarre Open-E', ['E3', 'B3', 'E4', 'G#4', 'B4', 'E5'], 7),
	('S6 Gitarre Open-Em', ['E3', 'B3', 'E4', 'G4', 'B4', 'E5'], 7),
	('S6 Gitarre Drop-E', ['E3', 'B3', 'E4', 'A4', 'C#5', 'F#5'], 7),
	('S6 Gitarre Open-G', ['D3', 'G3', 'D4', 'G4', 'B4', 'D5'], 7),
	('S6 Gitarre Open-Gm', ['D3', 'G3', 'D4', 'G4', 'Bb4', 'D5'], 7),
	('S6 Gitarre Open-A1', ['E3', 'A3', 'E4', 'A4', 'C#5', 'E5'], 7),
	('S6 Gitarre Open-A2', ['E3', 'A3', 'C#4', 'E4', 'A4', 'E5'], 7),
	('S6 Gitarre Open-Am1', ['E3', 'A3', 'E4', 'A4', 'C5', 'E5'], 7),
	('S6 Gitarre Open-Am2', ['E3', 'A3', 'C4', 'E4', 'A4', 'E5'], 7),
]

def genFretBoard(strings, numFrets):
	fretBoard = []
	for fret in range(0,numFrets+1):
		newStrings = []
		numStrings = len(strings)
		for stringIdx in range(0, numStrings):
			newTone = transposeTone(strings[stringIdx], fret)
			newStrings.append(newTone)
		fretBoard.append(newStrings)
	return fretBoard

def getStringFretList(fretBoard, tone):
	# acaLead mode
	retval = []
	fretNo = 0
	for strings in fretBoard:
		stringNo = 0
		for string in strings:
			if force_sign(string) == force_sign(tone):
				retval.append((stringNo, fretNo))
			stringNo = stringNo + 1
		fretNo = fretNo + 1
	# Slide mode on highest String (if acaLead mode failed because tone out of range)
	if len(retval) == 0:
		string_pitches = []
		max_pitch0 = 0     # Only for open tones
		for string in fretBoard[0]:
			string_pitch=midiPitch(string)
			string_pitches.append(midiPitch(string))
			max_pitch0 = max(max_pitch0, string_pitch)
		high_string_idx = string_pitches.index(max_pitch0)
		pitch = midiPitch(tone)
		if pitch > max_pitch0:
			fret = pitch - max_pitch0
			retval.append((high_string_idx, fret))
	return retval

def msgALNselected():
	messageBox('Notenzeile an Cursor', 'Cursor steht in keiner "Notenzeile".')

def msgInstrumentChanged(oldNumStrings, numStrings):
	messageBox('Instrument geändert', '"Änderung" des Instrumentes nicht möglich!\nVorher existierende Tab in Mustersystem löschen.\nGrund: Saitenanzahl (alt: '+str(oldNumStrings)+',  neu: '+str(numStrings)+') ungleich.')

def msgInstMarkerNotAllowed(firstOccurr, nextOccurr):
	messageBox('Mehrere Instrumentenmarker', 'Wechsel des Instrument-Markers erkannt.  Letzterer ist gültig ('+firstOccurr+' → '+nextOccurr+').')

# Plugin Dialog
def dialog():
	global config
	global setGenStaffName
	global setInstrumentName
	global setALNtopDistance
	global setALNcreate
	global setInstrumentIndex
	global setSizeFretNumbers
	global setSizeGlobalFretIndex
	global setSizeLocalFretIndex
	global setSizeFingerNumbers
	global setColorFingerNumbers
	global setChordFretIndexPos
	global setFretIndexPosAbove
	global setChordsPosAbove
	global setUseGermanH
	global setItalicVoice1
	global setItalicVoice2
	global setItalicVoice3
	global setColorVoice1
	global setColorVoice2
	global setColorVoice3
	global setChordTypeBold
	global setShowStrings
	global setShowFingering
	global setSimpleTextShow
	global setMusicSymbolsShow
	global setRichTextShow
	global setChordsShow
	global setLyricsShow

	global editGenStaffName
	global editInstrumentName
	global editALNtopDistance
	global radioALNcreate
	global comboInstrument
	global editSizeFretNumbers
	global editSizeGlobalFretIndex
	global editSizeLocalFretIndex
	global editSizeFingerNumbers
	global checkColorFingerNumbers
	global editChordFretIndexPos
	global checkFretIndexPosAbove
	global checkChordsPosAbove
	global checkUseGermanH
	global checkItalicVoice1
	global checkItalicVoice2
	global checkItalicVoice3
	global comboColorVoice1
	global comboColorVoice2
	global comboColorVoice3
	global checkChordTypeBold
	global checkReset
	global checkShowStrings
	global checkShowFingering
	global checkSimpleTextShow
	global checkMusicSymbolsShow
	global checkRichTextShow
	global checkChordsShow
	global checkLyricsShow

	global estCursorStaffName

	checkReset = CheckBox('reset', value = False)

	config.load()
	setGenStaffName = config.get('setGenStaffName', 'aLT')
	setInstrumentName = config.get('setInstrumentName', 'Tab')
	setALNtopDistance = config.get('setALNtopDistance', '0')
	setALNcreate = config.get('setALNcreate', 0)
	setInstrumentIndex = config.get('setInstrumentIndex', 0)
	setSizeFretNumbers = config.get('setSizeFretNumbers', '5')
	setSizeGlobalFretIndex = config.get('setSizeGlobalFretIndex', '5')
	setSizeLocalFretIndex = config.get('setSizeLocalFretIndex', '4')
	setSizeFingerNumbers = config.get('setSizeFingerNumbers', '4')
	setColorFingerNumbers = config.get('setColorFingerNumbers', True)
	setChordFretIndexPos = config.get('setChordFretIndexPos', '3.5')
	setFretIndexPosAbove = config.get('setFretIndexPosAbove', True)
	setChordsPosAbove = config.get('setChordsPosAbove', False)
	setUseGermanH = config.get('setUseGermanH', False)
	setItalicVoice1 = config.get('setItalicVoice1', False)
	setItalicVoice2 = config.get('setItalicVoice2', True)
	setItalicVoice3 = config.get('setItalicVoice3', False)
	setColorVoice1 = config.get('setColorVoice1', 0)
	setColorVoice2 = config.get('setColorVoice2', 0)
	setColorVoice3 = config.get('setColorVoice3', 0)
	setChordTypeBold = config.get('setChordTypeBold', True)
	setShowStrings = config.get('setShowStrings', True)
	setShowFingering = config.get('setShowFingering', True)
	setSimpleTextShow = config.get('setSimpleTextShow', True)
	setMusicSymbolsShow = config.get('setMusicSymbolsShow', True)
	setRichTextShow = config.get('setRichTextShow', True)
	setChordsShow = config.get('setChordsShow', True)
	setLyricsShow = config.get('setLyricsShow', True)

	wdt = 41
	wdtRight = 38
	spacer = Label('')

	labelCursorStaffName = Label('Name', width = wdtRight/2)
	fretIndexColor = Label('Fret-Index Font-Farbe', width=wdtRight/2)
	fretIndexHeight = Label('Fret-Index Font-Größe', width=wdtRight/2)
	textIsParsed = Label('Fret-Index aktuell aktiv', width=wdtRight/2)
	vBoxEstPropLabels = VBox([labelCursorStaffName, fretIndexColor, fretIndexHeight, textIsParsed])

	labelCursorStaffNameValue = Label(': '+estCursorStaffName, width = wdtRight/2-1)
	fColor = '-'
	fSize = '-'
	if estFretIndexFontColor != '':
		fColor = '#'+estFretIndexFontColor
		fSize = str(estFretIndexFontSize)+' px'
	fretIndexColorValue = Label(': '+fColor, width=wdtRight/2-1)
	fretIndexHeightValue = Label(': '+fSize, width=wdtRight/2-1)
	if fColor == '-':
		isConv = '-'
	else:
		if isAln:
			isConv = "Ja"
		else:
			isConv = "Nein"
	textIsParsedValue = Label(': '+isConv, width=wdtRight/2-1)
	vBoxEstPropValues = VBox([labelCursorStaffNameValue, fretIndexColorValue, fretIndexHeightValue, textIsParsedValue])

	labelGenStaffName = Label('aLT-Zeilenname', width = wdtRight / 2 + 5)
	editGenStaffName = Edit(value = setGenStaffName, width = wdtRight / 3)
	hBoxGenStaffName = HBox([labelGenStaffName, editGenStaffName])
	labelInstrumentName = Label('Instrumentenbezeichnung', width = wdtRight / 2 + 5)
	editInstrumentName = Edit(value = setInstrumentName, width = wdtRight / 3)
	hBoxInstrumentName = HBox([labelInstrumentName, editInstrumentName])
	sHasALTStaff = 'nein'
	if estHasALTstaff:
		sHasALTStaff = 'ja'
	labelEstHasALNStaff = Label('aLT-Zeile vorhanden: '+sHasALTStaff, width = wdtRight)
	labelALNtopDistance = Label('Zus.  Abst.  zur Notenzeile nach oben', width = wdtRight / 2 + 10)
	editALNtopDistance = Edit(value = setALNtopDistance, width = wdtRight / 4 - 2)
	hBoxALNtopDistance = HBox([labelALNtopDistance, editALNtopDistance])
	alnCreateOptions = ['in allen Systemen', 'nur in System mit Cursor']
	radioALNcreate = Radio(alnCreateOptions, text = 'aLT-Zeile erstellen', value = setALNcreate)
	instrumentOptions = []
	for instrument in instruments:
		stringNames = getStringNames([instrument[1]], withOctave=True)
		joinedStringNames = str.join(',', stringNames)
		instrumentOptions.append(instrument[0]+' ('+joinedStringNames+'), '+str(instrument[2])+'  ')
	labelInstrument = Label('Instrument / Stimmung / Saiten / Zyklus', width = wdtRight)
	comboInstrument = ComboBox(instrumentOptions, value=setInstrumentIndex, width = wdtRight)

	checkReset = CheckBox('EINSTELLUNGEN ZURÜCKSETZEN', value=False, width=wdtRight)
	checkShowStrings = CheckBox('Saitennamen anzeigen', value = setShowStrings, width=wdtRight)
	checkShowFingering = CheckBox('Fingersatzzahlen anzeigen', value = setShowFingering, width=wdtRight)
	checkSimpleTextShow = CheckBox('Einfach-Text "T" anzeigen', value = setSimpleTextShow, width=wdtRight)
	checkRichTextShow = CheckBox('Textfeld "abc" anzeigen', value = setRichTextShow, width=wdtRight)
	checkMusicSymbolsShow = CheckBox('Capella3 Musik-Textzeichen anzeigen', value = setMusicSymbolsShow, width=wdtRight)
	checkChordsShow = CheckBox('Chords/Steps/"T"-Gruppen anzeigen', value = setChordsShow, width=wdtRight)
	checkLyricsShow = CheckBox('Liedtext anzeigen', value = setLyricsShow, width=wdtRight)
	vBoxPlugin = VBox([checkReset, checkShowStrings, checkShowFingering, checkSimpleTextShow, checkRichTextShow, checkMusicSymbolsShow, checkChordsShow, checkLyricsShow])
	hBoxSourceProps = HBox([vBoxEstPropLabels, vBoxEstPropValues],text = 'Quell-Notenzeile-Eigenschaften (Cursor-Position)')
	vBoxStaffSettings = VBox([hBoxGenStaffName, hBoxInstrumentName, labelEstHasALNStaff, hBoxALNtopDistance, spacer, radioALNcreate, spacer, labelInstrument, spacer, comboInstrument])
	hBoxStaffSettings = HBox([vBoxStaffSettings],text = 'Ziel-Tabulatur-Eigenschaften')
	hBoxPlugin = HBox([vBoxPlugin], text = 'Plugin-Anwendung')
	vBoxRight = VBox([hBoxSourceProps, spacer, hBoxStaffSettings, spacer, hBoxPlugin])

	labelSizeFretNumbers = Label('Bundzahlen', width = wdt / 2)
	editSizeFretNumbers = Edit(value = setSizeFretNumbers, width = wdt / 3)
	hBoxSizeFretNumbers = HBox([labelSizeFretNumbers, editSizeFretNumbers])
	labelSizeGlobalFretIndex = Label('Globale Fret-Indexe', width = wdt / 2)
	editSizeGlobalFretIndex = Edit(value = setSizeGlobalFretIndex, width = wdt / 3)
	hBoxSizeGlobalFretIndex = HBox([labelSizeGlobalFretIndex, editSizeGlobalFretIndex])
	labelSizeLocalFretIndex = Label('Lokale Fret-Indexe', width = wdt / 2)
	editSizeLocalFretIndex = Edit(value = setSizeLocalFretIndex, width = wdt / 3)
	hBoxSizeLocalFretIndex = HBox([labelSizeLocalFretIndex, editSizeLocalFretIndex])
	labelSizeFingerNumbers = Label('Fingersatzzahlen', width = wdt / 2)
	editSizeFingerNumbers = Edit(value = setSizeFingerNumbers, width = wdt / 3)
	hBoxSizeFingerNumbers = HBox([labelSizeFingerNumbers, editSizeFingerNumbers])
	checkColorFingerNumbers = CheckBox('Fingersatzfarbe rot (oder schwarz)', value = setColorFingerNumbers, width = wdt-6)
	vBoxPlacedNumbersProps = VBox([hBoxSizeFretNumbers, hBoxSizeGlobalFretIndex, hBoxSizeLocalFretIndex, hBoxSizeFingerNumbers, checkColorFingerNumbers])
	hBoxPlacedNumbersProps = HBox([vBoxPlacedNumbersProps], text = 'Zahlen: Größe (px) und Farbe')
	
	labelChordFretIndexPos = Label('Abstand zum Notensystem', width = wdt / 2)
	editChordFretIndexPos = Edit(value = setChordFretIndexPos, width = wdt / 3)
	hBoxChordFretIndexPos = HBox([labelChordFretIndexPos, editChordFretIndexPos])
	checkFretIndexPosAbove = CheckBox('Glob.  Fret-Index über aLT-Zeile (oder unter)', value = setFretIndexPosAbove, width = wdt - 6)
	checkChordsPosAbove = CheckBox('Chords/Steps über aLT-Zeile (oder unter)', value = setChordsPosAbove, width = wdt-6)
	checkUseGermanH = CheckBox('Verwende h statt b (in Saitennamen)', value = setUseGermanH, width = wdt-6)
	vBoxFretIndexProps = VBox([hBoxChordFretIndexPos, checkFretIndexPosAbove, checkChordsPosAbove, checkUseGermanH])
	hBoxFretIndexProps = HBox([vBoxFretIndexProps], text = 'Anzeigeeigenschaften')
	
	optColors = []
	for item in colorMap:
		optColors.append(item[0])

	labelVoice1 = Label('Stimme 1:', width = 7)
	checkItalicVoice1 = CheckBox('kursiv', value = setItalicVoice1, width = 8)
	labelColorVoice1 = Label('Farbe:', width = 4)
	comboColorVoice1 = ComboBox(optColors, value = setColorVoice1, width = 13)
	hBoxVoice1 = HBox([labelVoice1, checkItalicVoice1, labelColorVoice1, comboColorVoice1])
	labelVoice2 = Label('Stimme 2:', width = 7)
	checkItalicVoice2 = CheckBox('kursiv', value = setItalicVoice2, width = 8)
	labelColorVoice2 = Label('Farbe:', width = 4)
	comboColorVoice2 = ComboBox(optColors, value = setColorVoice2, width = 13)
	hBoxVoice2 = HBox([labelVoice2, checkItalicVoice2, labelColorVoice2, comboColorVoice2])
	labelVoice3 = Label('Stimme 3:', width = 7)
	checkItalicVoice3 = CheckBox('kursiv', value = setItalicVoice3, width = 8)
	labelColorVoice3 = Label('Farbe:', width = 4)
	comboColorVoice3 = ComboBox(optColors, value = setColorVoice3, width = 13)
	hBoxVoice3 = HBox([labelVoice3, checkItalicVoice3, labelColorVoice3, comboColorVoice3])
	vBoxOptVoiceProps = VBox([hBoxVoice1, hBoxVoice2, hBoxVoice3])
	hBoxOptVoiceProps = HBox([vBoxOptVoiceProps], text = 'Optische Stimmen-Eigenschaften')
	checkChordTypeBold = CheckBox('fett', value = setChordTypeBold, width = wdt - 6)
	vBoxOptChordProps = VBox([checkChordTypeBold])
	hBoxOptChordProps = HBox([vBoxOptChordProps], text = 'Optische Mehrton-/Chord-Eigenschaften')
	vBoxLeft = VBox([hBoxPlacedNumbersProps, spacer, hBoxFretIndexProps, spacer, hBoxOptVoiceProps, spacer, hBoxOptChordProps])

	hBox = HBox([vBoxLeft, spacer, vBoxRight])
	vBox = VBox([hBox])
	dlg = Dialog('aL.Tabber', vBox)
	return dlg

if activeScore():
	tempInput = tempfile.mktemp('.capx')
	tempOutput = tempfile.mktemp('.capx')
	activeScore().write(tempInput)
	ScoreAnalyze(tempInput, tempOutput)
	os.remove(tempInput)
	os.remove(tempOutput)

	dialogPass = False
	while not dialogPass:
		dialogOkClicked = dialog().run()
		setReset = checkReset.value()
		if setReset and dialogOkClicked:
			config.dic = {}
			dialogStatus = False
			dialogPass = False
			config.save()
		else:
			dialogPass = True

	if dialogOkClicked:
		setGenStaffName = editGenStaffName.value()
		setInstrumentName = editInstrumentName.value()
		setALNtopDistance = editALNtopDistance.value()
		setALNcreate = radioALNcreate.value()
		setInstrumentIndex = comboInstrument.value()
		setSizeFretNumbers = editSizeFretNumbers.value()
		setSizeGlobalFretIndex = editSizeGlobalFretIndex.value()
		setSizeLocalFretIndex = editSizeLocalFretIndex.value()
		setSizeFingerNumbers = editSizeFingerNumbers.value()
		setColorFingerNumbers = checkColorFingerNumbers.value()
		setChordFretIndexPos = editChordFretIndexPos.value()
		setFretIndexPosAbove = checkFretIndexPosAbove.value()
		setChordsPosAbove = checkChordsPosAbove.value()
		setUseGermanH = checkUseGermanH.value()
		setItalicVoice1 = checkItalicVoice1.value()
		setItalicVoice2 = checkItalicVoice2.value()
		setItalicVoice3 = checkItalicVoice3.value()
		setColorVoice1 = comboColorVoice1.value()
		setColorVoice2 = comboColorVoice2.value()
		setColorVoice3 = comboColorVoice3.value()
		setChordTypeBold = bool(checkChordTypeBold.value())
		setShowStrings = bool(checkShowStrings.value())
		setShowFingering = bool(checkShowFingering.value())
		setSimpleTextShow = bool(checkSimpleTextShow.value())
		setRichTextShow = bool(checkRichTextShow.value())
		setMusicSymbolsShow = bool(checkMusicSymbolsShow.value())
		setChordsShow = bool(checkChordsShow.value())
		setLyricsShow = bool(checkLyricsShow.value())
		config.set("setGenStaffName", setGenStaffName)
		config.set("setInstrumentName", setInstrumentName)
		config.set("setALNtopDistance", setALNtopDistance)
		config.set("setALNcreate", setALNcreate)
		config.set("setInstrumentIndex", setInstrumentIndex)
		config.set("setSizeFretNumbers", setSizeFretNumbers)
		config.set("setSizeGlobalFretIndex", setSizeGlobalFretIndex)
		config.set("setSizeLocalFretIndex", setSizeLocalFretIndex)
		config.set("setSizeFingerNumbers", setSizeFingerNumbers)
		config.set("setColorFingerNumbers", setColorFingerNumbers)
		config.set("setChordFretIndexPos", setChordFretIndexPos)
		config.set("setFretIndexPosAbove", setFretIndexPosAbove)
		config.set("setChordsPosAbove", setChordsPosAbove)
		config.set("setUseGermanH", setUseGermanH)
		config.set("setItalicVoice1", setItalicVoice1)
		config.set("setItalicVoice2", setItalicVoice2)
		config.set("setItalicVoice3", setItalicVoice3)
		config.set("setColorVoice1", setColorVoice1)
		config.set("setColorVoice2", setColorVoice2)
		config.set("setColorVoice3", setColorVoice3)
		config.set("setChordTypeBold", setChordTypeBold)
		config.set("setShowStrings", setShowStrings)
		config.set("setShowFingering", setShowFingering)
		config.set("setSimpleTextShow", setSimpleTextShow)
		config.set("setRichTextShow", setRichTextShow)
		config.set("setMusicSymbolsShow", setMusicSymbolsShow)
		config.set("setChordsShow", setChordsShow)
		config.set("setLyricsShow", setLyricsShow)

		print(config.dic)
		config.save()

		activeScore().registerUndo("aL.Tabber")
		tempInput = tempfile.mktemp('.capx')
		tempOutput = tempfile.mktemp('.capx')
		activeScore().write(tempInput)
		global embeddedFileCopyList
		embeddedFileCopyList = []

		# embeddedFileCopyList is set after ScoreChange
		ScoreChange(tempInput, tempOutput)
		# tempOutput must be extended by
		# new (obj___X)-Files here (e.g. Rich Text)
		# listed in embeddedFileCopyList
		if len(embeddedFileCopyList) > 0:
			copyAndRepackFiles(tempOutput, embeddedFileCopyList)

		activeScore().read(tempOutput)
		os.remove(tempInput)
		os.remove(tempOutput)