
class SelectLayer extends Layer {
	var onClickFunction;
	var par;
	var gard = [];
	var drop;
	var click;

	function SelectLayer(win, par, func){
		super.Layer(win, par);
		this.par = par;
		cursor = crArrow;
		type = ltPsDifference;
		onClickFunction = func;
	}

	function finalize(){
		invalidate par;
		super.finalize();
	}

	function onMouseDown(x, y, button, shift){
		with(par){
			gard[0] = .drag[0];
			gard[1] = .drag[1];
			gard[1] = .drag[0] + .range;
		}
		click = true;
		drop = true;
	}

	function onMouseMove(x, y, shift){
		if(shift & ssLeft){
			click = false;
			with(par){
				if((0 <= x && x < width && -3 < y && y < height+3) ||
				(.cursorX<0 || .width<.cursorX || .cursorY<0 || .height<.cursorY)){
					if(drop){
						drop = false;
						cursor = crNo;
						.hideCaret();
					}
				} else {
					if(!drop){
						drop = true;
						cursor = crDrag;
						.showCaret();
					}
					.drag[1] = .getCaretPosFromX(.cursorX);
					if(.Edit_selStart!=.drag[1]) .CaretMove(.drag[1]);
				}
			}
		}
	}

	function onMouseUp(x, y, button, shift){
		if(button == mbMiddle) return;
		cursor = crArrow;
		with(par){
			if(shift & ssShift) .Select(.getCaretPosFromX(.cursorX));
			else if(click) onClickFunction(0);
			else if(drop){
				var ctrl = 0, cut = "";
				if(shift & ssCtrl){
					ctrl = 2;
					if(.range>0)
						cut = .Edit_text.substr(gard[0], .range), paste(.drag[1], .drag[1], cut);
					else if(.range<0)
						cut = .Edit_text.substr(gard[1], -.range), paste(.drag[1], .drag[1], cut);
				} else {
					if(gard[0]==.drag[1] || gard[1]==.drag[1]) return;
					ctrl = 1;
					if(.range>0){
						cut = .Edit_text.substr(gard[0], .range);
						if(gard[0]>.drag[1])
							delet(gard[0], gard[1]), paste(.drag[1], .drag[1], cut), .drag[0] = .drag[1];
						else if(gard[1]<.drag[1])
							paste(.drag[1], .drag[1], cut), delet(gard[0], gard[1]), .drag[0] = .drag[1] - .range;
					}
					else if(.range<0){
						cut = .Edit_text.substr(gard[1], -.range);
						if(gard[1]>.drag[1])
							delet(gard[1], gard[0]), paste(.drag[1], .drag[1], cut), .drag[0] = .drag[1] - .range;
						else if(gard[0]<.drag[1])
							paste(.drag[1], .drag[1], cut), delet(gard[1], gard[0]), .drag[0] = .drag[1];
					}
				}
				.Record();
				onClickFunction(ctrl);
			}
		}
	}

	function delet(r, s){
		par.Edit_text = par.Edit_text.substr(0, r) + par.Edit_text.substr(s);
	}

	function paste(r, s, cut){
		par.Edit_text = par.Edit_text.substr(0, r) + cut + par.Edit_text.substr(s);
	}
}


class CustomEditLayer extends EditLayer
{
	var par;
	var selectLayer;
	var drag = [];
	var range;
	var clkx, clky, dclk;
	var num;
	var nText;
	var nPos;
	var nNum;

	function CustomEditLayer(win, par)
	{
		super.EditLayer(...);
		this.par = par;
		selectLayer = new global.SelectLayer(win, this, onLayer);

		cursor = crIBeam;
		font.face = "‚l‚r ƒSƒVƒbƒN";
		antialiased = false;
		visible = true;
		joinFocusChain = false;
	}

	function finalize(){
		invalidate selectLayer;
		super.finalize();
	}

	function onKeyDown(key, shift){
		if(shift & ssShift){
			if(key == VK_RETURN) selectCancel();
			else if(key == VK_HOME) Select(0);
			else if(key == VK_END) Select(Edit_text.length);
			else if(key == VK_RIGHT) Select(Edit_selStart+1);
			else if(key == VK_LEFT) Select(Edit_selStart-1);
			return;
		}
		if(shift & ssCtrl){
			if(key==VK_X || key==VK_C){
				if(range==0) return;
				else if(range>0) Clipboard.asText = Edit_text.substr(drag[0], drag[1]);
				else if(range<0) Clipboard.asText = Edit_text.substr(drag[1], drag[0]);
				if(key == VK_X) deleteAfterCaret();
			}
			else if(key == VK_V) insertCharacter(Clipboard.asText);
			else if(key == VK_A){
				drag[0] = 0;
				Select(Edit_text.length);
				hideCaret();
			}
			else if(key == VK_Z && nNum != 0){
				Edit_text = nText[--nNum];
				CaretMove(nPos[nNum]);
				update();
			}
			else if(key == VK_Y && nText[nNum+1] !== void){
				Edit_text = nText[++nNum];
				CaretMove(nPos[nNum]);
				update();
			}
			return;
		}

		if(key == VK_RETURN || key == VK_ESCAPE) removeMode(sf.Comment[num]=Edit_text);
		else if(key==VK_HOME) CaretMove(0);
		else if(key==VK_END) CaretMove(Edit_text.length);
		else if(key==VK_LEFT && range!=0) CaretMove(range>0 ? drag[0] : drag[1]);
		else if(key==VK_RIGHT && range!=0) CaretMove(range<0 ? drag[0] : drag[1]);
		else if(key == VK_LEFT) CaretMove(Edit_selStart-1);
		else if(key == VK_RIGHT) CaretMove(Edit_selStart+1);
		else if(key == VK_DELETE) deleteAfterCaret();
		else if(key == VK_BACK) deleteBeforeCaret();
		else{
			super.onKeyDown(...);
			return;
		}

		selectCancel();
	}

	function selectCancel(){
		selectLayer.visible = false;
		drag[0] = Edit_selStart;
		range = 0;
	}

	function onBlink(){
		dclk = false;
		Edit_caretLayer.visible = !Edit_caretLayer.visible;
	}

	function onFocus(focused, direction){
		super.onFocus(...);
		showCaret();
		setMode();
		nText = [], nPos = [];
		nText[nNum=0] = Edit_text;
		nPos[0] = getCaretPosFromX(cursorX);
	}

	function onBlur(focused){
		super.onBlur(...);
		selectLayer.visible = false;
		hideCaret();
	}

	function onMouseDown(x, y, button, shift){
		if(!Edit_blinkTimer.enabled) focus();
		if(shift & ssShift){
			Select(getCaretPosFromX(x));
			return;
		}
		if(shift & ssCtrl){
			drag[0] = 0;
			Select(Edit_text.length);
			hideCaret();
			return;
		}
		if(clkx==x && clky==y && dclk){
			drag[0] = 0;
			Select(Edit_text.length);
			hideCaret();
			return;
		}
		if(button == mbLeft){
			CaretMove(drag[0]=getCaretPosFromX(x));
			range = 0;
			selectLayer.visible = false;
			clkx = x, clky = y;
		}
		super.onMouseDown(...);
	}

	function onMouseUp(x, y, button, shift){
		if(button == mbRight) removeMode(sf.Comment[num]=Edit_text);
		if(button == mbLeft) dclk = true;
	}

	function onMouseMove(x, y, shift){
		drag[1] = getCaretPosFromX(x);
		if(shift&ssLeft && Edit_selStart!=drag[1]) Select(drag[1]);
	}

	function getPosLen(pos, len){
		return font.getTextWidth(Edit_text.substr(pos, len));
	}

	function fillSelect(p1, l1, p2, l2){
		with(selectLayer){
			.setPos(3+getPosLen(p1, l1), 2, getPosLen(p2, l2), height-4);
			.fillRect(0, 0, 400, height, 0xffffffff);
			.visible = true;
		}
	}

	function CaretMove(x){
		if(x<0 || Edit_text.length<x) return;
		Edit_selStart = drag[1] = x;
		showCaret();
	}

	function Select(x){
		CaretMove(x);
		range = drag[1] - drag[0];
		if(range>0) fillSelect(0, drag[0], drag[0], range);
		else if(range<0) fillSelect(0, drag[1], drag[1], -range);
		else selectLayer.visible = false;
		hideCaret();
	}

	function onLayer(ctrl){
		clkx = cursorX, clky = cursorY;
		if(ctrl>0){
			if(ctrl==2) drag[0] = drag[1] - (range<0 ? range : 0);
			Select(drag[0] + range);
		} else {
			selectLayer.visible = false;
			CaretMove(getCaretPosFromX(clkx));
			range = 0;
		}
		cursor = crIBeam;
	}

	function insertCharacter(ch){
		if(range>0) onRange(-range, 0, drag[0]+1-Edit_selStart, ch);
		else if(range<0) onRange(0, -range, ch.length, ch);
		else onRange(0, 0, ch.length, ch);
	}

	function deleteBeforeCaret(){
		if(Edit_text!=""){
			if(range>0) onRange(-range, 0, -range);
			else if(range<0) onRange(0, -range);
			else if(drag[0]!=0) onRange(-1, 0, -1);
		}
	}

	function deleteAfterCaret(){
		if(Edit_text!=""){
			if(range>0) onRange(-range, 0, -range);
			else if(range<0) onRange(0, -range);
			else onRange(0, 1);
		}
	}

	function onRange(b, a, i=0, ch=""){
  		Edit_text = Edit_text.substr(0, Edit_selStart + b) + ch + Edit_text.substr(Edit_selStart + a);
		Edit_selStart += i;
		drag[0] = drag[1] = Edit_selStart;
		range = 0;
		showCaret();
		Record();
		selectLayer.visible = false;
	}

	function Record(){
		nText[++nNum] = Edit_text;
		for(var i=nNum+1; i<nText.count; i++){
			if(nText[i] === void) break;
			else nText[i] = void;
		}
		nPos[nNum] = Edit_selStart;
		update();
	}








	function onHitTest(x, y, process){
		if(process){
			if(System.getKeyState(VK_RBUTTON) || System.getKeyState(VK_MBUTTON))
				super.onHitTest(x, y, false);
			else
				super.onHitTest(x, y, true);
		}
	}
}

