471 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Haxe
		
	
	
	
	
	
		
		
			
		
	
	
			471 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Haxe
		
	
	
	
	
	
|  | package lnx2d; | ||
|  | 
 | ||
|  | // Zui | ||
|  | import zui.Zui; | ||
|  | import zui.Themes; | ||
|  | import zui.Id; | ||
|  | using zui.Ext; | ||
|  | import leenkx.ui.Popup; | ||
|  | import leenkx.ui.Canvas; | ||
|  | 
 | ||
|  | // Editor | ||
|  | import lnx2d.Path; | ||
|  | import lnx2d.Assets; | ||
|  | import lnx2d.tools.Math; | ||
|  | import lnx2d.ui.UIToolBar; | ||
|  | import lnx2d.ui.UIProperties; | ||
|  | import lnx2d.tools.CanvasTools; | ||
|  | 
 | ||
|  | @:access(zui.Zui) | ||
|  | class Editor { | ||
|  | 	var ui:Zui; | ||
|  | 	public var cui:Zui; | ||
|  | 	public var canvas:TCanvas; | ||
|  | 
 | ||
|  | 	public static var defaultWindowW = 240; | ||
|  | 	public static var windowW = defaultWindowW; | ||
|  | 	static var uiw(get, null):Int; | ||
|  | 	static function get_uiw():Int { | ||
|  | 		return Std.int(windowW * Main.prefs.scaleFactor); | ||
|  | 	} | ||
|  | 	var toolbarw(get, null):Int; | ||
|  | 	function get_toolbarw():Int { | ||
|  | 		return Std.int(140 * ui.SCALE()); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	// Canvas offset from the editor window | ||
|  | 	// Should be a multiple of gridSize to ensure visual grid alignment | ||
|  | 	public static var coffX = 160.0; | ||
|  | 	public static var coffY = 40.0; | ||
|  | 
 | ||
|  | 	var dropPath = ""; | ||
|  | 	public static var currentOperation = ""; | ||
|  | 	public static var assetNames:Array<String> = [""]; | ||
|  | 	public static var dragAsset:TAsset = null; | ||
|  | 	var resizeCanvas = false; | ||
|  | 	var zoom = 1.0; | ||
|  | 
 | ||
|  | 	public static var showFiles = false; | ||
|  | 	public static var foldersOnly = false; | ||
|  | 	public static var filesDone:String->Void = null; | ||
|  | 	var uimodal:Zui; | ||
|  | 
 | ||
|  | 	public static var gridSnapBounds:Bool = false; | ||
|  | 	public static var gridSnapPos:Bool = true; | ||
|  | 	public static var gridUseRelative:Bool = true; | ||
|  | 	public static var useRotationSteps:Bool = false; | ||
|  | 	public static var rotationSteps:Float = Math.toRadians(15); | ||
|  | 	public static var gridSize:Int = 20; | ||
|  | 	public static var redrawGrid = false; | ||
|  | 	static var grid:kha.Image = null; | ||
|  | 	static var timeline:kha.Image = null; | ||
|  | 
 | ||
|  | 	var selectedFrame = 0; | ||
|  | 	public static var selectedTheme:zui.Themes.TTheme = null; | ||
|  | 	public static var selectedElem:TElement = null; | ||
|  | 	var lastW = 0; | ||
|  | 	var lastH = 0; | ||
|  | 	var lastCanvasW = 0; | ||
|  | 	var lastCanvasH = 0; | ||
|  | 
 | ||
|  | 	public function new(canvas:TCanvas) { | ||
|  | 		this.canvas = canvas; | ||
|  | 
 | ||
|  | 		// Reimport assets | ||
|  | 		if (canvas.assets.length > 0) { | ||
|  | 			var assets = canvas.assets; | ||
|  | 			canvas.assets = []; | ||
|  | 			for (a in assets) Assets.importAsset(canvas, a.file); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		Assets.importThemes(); | ||
|  | 
 | ||
|  | 		kha.Assets.loadEverything(loaded); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	function loaded() { | ||
|  | 		var t = Reflect.copy(Themes.dark); | ||
|  | 		t.FILL_WINDOW_BG = true; | ||
|  | 		ui = new Zui({scaleFactor: Main.prefs.scaleFactor, font: kha.Assets.fonts.font_default, theme: t, color_wheel: kha.Assets.images.color_wheel, black_white_gradient: kha.Assets.images.black_white_gradient}); | ||
|  | 		cui = new Zui({scaleFactor: 1.0, font: kha.Assets.fonts.font_default, autoNotifyInput: true, theme: Reflect.copy(Canvas.getTheme(canvas.theme))}); | ||
|  | 		uimodal = new Zui( { font: kha.Assets.fonts.font_default, scaleFactor: Main.prefs.scaleFactor } ); | ||
|  | 		ElementController.initialize(ui, cui); | ||
|  | 
 | ||
|  | 		if (Canvas.getTheme(canvas.theme) == null) { | ||
|  | 			Popup.showMessage(new Zui(ui.ops), "Warning!", | ||
|  | 				'Theme "${canvas.theme}" was not found!' | ||
|  | 				+ '\nUsing first theme in list instead: "${Canvas.themes[0].NAME}"'); | ||
|  | 			canvas.theme = Canvas.themes[0].NAME; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		kha.System.notifyOnDropFiles(function(path:String) { | ||
|  | 			dropPath = StringTools.rtrim(path); | ||
|  | 			dropPath = Path.toRelative(dropPath, Main.cwd); | ||
|  | 		}); | ||
|  | 
 | ||
|  | 		kha.System.notifyOnFrames(onFrames); | ||
|  | 		kha.Scheduler.addTimeTask(update, 0, 1 / 60); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	function resize() { | ||
|  | 		if (grid != null) { | ||
|  | 			grid.unload(); | ||
|  | 			grid = null; | ||
|  | 		} | ||
|  | 		if (timeline != null) { | ||
|  | 			timeline.unload(); | ||
|  | 			timeline = null; | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	function drawGrid() { | ||
|  | 		redrawGrid = false; | ||
|  | 
 | ||
|  | 		var scaledGridSize = scaled(gridSize); | ||
|  | 		var doubleGridSize = scaled(gridSize * 2); | ||
|  | 
 | ||
|  | 		var ww = kha.System.windowWidth(); | ||
|  | 		var wh = kha.System.windowHeight(); | ||
|  | 		var w = ww + doubleGridSize * 2; | ||
|  | 		var h = wh + doubleGridSize * 2; | ||
|  | 
 | ||
|  | 		if (grid == null) { | ||
|  | 			grid = kha.Image.createRenderTarget(w, h); | ||
|  | 		} | ||
|  | 		grid.g2.begin(true, 0xff242424); | ||
|  | 
 | ||
|  | 		for (i in 0...Std.int(h / doubleGridSize) + 1) { | ||
|  | 			grid.g2.color = 0xff282828; | ||
|  | 			grid.g2.drawLine(0, i * doubleGridSize + scaledGridSize, w, i * doubleGridSize + scaledGridSize); | ||
|  | 			grid.g2.color = 0xff323232; | ||
|  | 			grid.g2.drawLine(0, i * doubleGridSize, w, i * doubleGridSize); | ||
|  | 		} | ||
|  | 		for (i in 0...Std.int(w / doubleGridSize) + 1) { | ||
|  | 			grid.g2.color = 0xff282828; | ||
|  | 			grid.g2.drawLine(i * doubleGridSize + scaledGridSize, 0, i * doubleGridSize + scaledGridSize, h); | ||
|  | 			grid.g2.color = 0xff323232; | ||
|  | 			grid.g2.drawLine(i * doubleGridSize, 0, i * doubleGridSize, h); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		grid.g2.end(); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	function drawTimeline(timelineLabelsHeight:Int, timelineFramesHeight:Int) { | ||
|  | 		var sc = ui.SCALE(); | ||
|  | 
 | ||
|  | 		var timelineHeight = timelineLabelsHeight + timelineFramesHeight; | ||
|  | 
 | ||
|  | 		timeline = kha.Image.createRenderTarget(kha.System.windowWidth() - uiw - toolbarw, timelineHeight); | ||
|  | 
 | ||
|  | 		var g = timeline.g2; | ||
|  | 		g.begin(true, 0xff222222); | ||
|  | 		g.font = kha.Assets.fonts.font_default; | ||
|  | 		g.fontSize = Std.int(16 * sc); | ||
|  | 
 | ||
|  | 		// Labels | ||
|  | 		var frames = Std.int(timeline.width / (11 * sc)); | ||
|  | 		for (i in 0...Std.int(frames / 5) + 1) { | ||
|  | 			var frame = i * 5; | ||
|  | 
 | ||
|  | 			var frameTextWidth = kha.Assets.fonts.font_default.width(g.fontSize, frame + ""); | ||
|  | 			g.drawString(frame + "", i * 55 * sc + 5 * sc - frameTextWidth / 2, timelineLabelsHeight / 2 - g.fontSize / 2); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		// Frames | ||
|  | 		for (i in 0...frames) { | ||
|  | 			g.color = i % 5 == 0 ? 0xff444444 : 0xff333333; | ||
|  | 			g.fillRect(i * 11 * sc, timelineHeight - timelineFramesHeight, 10 * sc, timelineFramesHeight); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		g.end(); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function onFrames(framebuffers: Array<kha.Framebuffer>): Void { | ||
|  | 		// Prevent crash when minimizing window | ||
|  | 		if (kha.System.windowWidth() == 0 || kha.System.windowHeight() == 0) return; | ||
|  | 
 | ||
|  | 		var framebuffer = framebuffers[0]; | ||
|  | 
 | ||
|  | 		// Disable UI if a popup is displayed | ||
|  | 		if (Popup.show && ui.inputRegistered) { | ||
|  | 			ui.unregisterInput(); | ||
|  | 			cui.unregisterInput(); | ||
|  | 		} else if (!Popup.show && !ui.inputRegistered) { | ||
|  | 			ui.registerInput(); | ||
|  | 			cui.registerInput(); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		// Update preview when choosing a color | ||
|  | 		if (Popup.show) UIProperties.hwin.redraws = 1; | ||
|  | 
 | ||
|  | 		if (dropPath != "") { | ||
|  | 			Assets.importAsset(canvas, dropPath); | ||
|  | 			dropPath = ""; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		var sc = ui.SCALE(); | ||
|  | 		var timelineLabelsHeight = Std.int(30 * sc); | ||
|  | 		var timelineFramesHeight = Std.int(40 * sc); | ||
|  | 
 | ||
|  | 		// Bake and redraw if the UI scale has changed | ||
|  | 		if (grid == null || redrawGrid) drawGrid(); | ||
|  | 		if (timeline == null || timeline.height != timelineLabelsHeight + timelineFramesHeight) drawTimeline(timelineLabelsHeight, timelineFramesHeight); | ||
|  | 
 | ||
|  | 		var g = framebuffer.g2; | ||
|  | 		g.begin(); | ||
|  | 
 | ||
|  | 		g.color = 0xffffffff; | ||
|  | 		var doubleGridSize = scaled(gridSize * 2); | ||
|  | 		g.drawImage(grid, coffX % doubleGridSize - doubleGridSize, coffY % doubleGridSize - doubleGridSize); | ||
|  | 
 | ||
|  | 		// Canvas outline | ||
|  | 		canvas.x = coffX; | ||
|  | 		canvas.y = coffY; | ||
|  | 		g.drawRect(canvas.x, canvas.y, scaled(canvas.width), scaled(canvas.height), 1.0); | ||
|  | 
 | ||
|  | 		// Canvas resize | ||
|  | 		var handleSize = ElementController.handleSize; | ||
|  | 		if (Math.hitbox(cui, canvas.x + scaled(canvas.width) - handleSize / 2, canvas.y + scaled(canvas.height) - handleSize / 2, handleSize, handleSize)) { | ||
|  | 			g.color = 0xff205d9c; | ||
|  | 			g.fillRect(canvas.x + scaled(canvas.width) - handleSize / 2, canvas.y + scaled(canvas.height) - handleSize / 2, handleSize, handleSize); | ||
|  | 			g.color = 0xffffffff; | ||
|  | 		} | ||
|  | 		g.drawRect(canvas.x + scaled(canvas.width) - handleSize / 2, canvas.y + scaled(canvas.height) - handleSize / 2, handleSize, handleSize, 1); | ||
|  | 
 | ||
|  | 		Canvas.screenW = canvas.width; | ||
|  | 		Canvas.screenH = canvas.height; | ||
|  | 		Canvas.draw(cui, canvas, g); | ||
|  | 
 | ||
|  | 		ElementController.render(g, canvas); | ||
|  | 
 | ||
|  | 		if (currentOperation != "") { | ||
|  | 			g.fontSize = Std.int(14 * ui.SCALE()); | ||
|  | 			g.color = 0xffaaaaaa; | ||
|  | 			g.drawString(currentOperation, toolbarw, kha.System.windowHeight() - timeline.height - g.fontSize); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		// Timeline | ||
|  | 		var showTimeline = true; | ||
|  | 		if (showTimeline) { | ||
|  | 			g.color = 0xffffffff; | ||
|  | 			var ty = kha.System.windowHeight() - timeline.height; | ||
|  | 			g.drawImage(timeline, toolbarw, ty); | ||
|  | 
 | ||
|  | 			g.color = 0xff205d9c; | ||
|  | 			g.fillRect(toolbarw + selectedFrame * 11 * sc, ty + timelineLabelsHeight, 10 * sc, timelineFramesHeight); | ||
|  | 
 | ||
|  | 			// Show selected frame number | ||
|  | 			g.font = kha.Assets.fonts.font_default; | ||
|  | 			g.fontSize = Std.int(16 * sc); | ||
|  | 
 | ||
|  | 			var frameIndicatorMargin = 4 * sc; | ||
|  | 			var frameIndicatorPadding = 4 * sc; | ||
|  | 			var frameIndicatorWidth = 30 * sc; | ||
|  | 			var frameIndicatorHeight = timelineLabelsHeight - frameIndicatorMargin * 2; | ||
|  | 			var frameTextWidth = kha.Assets.fonts.font_default.width(g.fontSize, "" + selectedFrame); | ||
|  | 
 | ||
|  | 			// Scale the indicator if the contained text is too long | ||
|  | 			if (frameTextWidth > frameIndicatorWidth + frameIndicatorPadding) { | ||
|  | 				frameIndicatorWidth = frameTextWidth + frameIndicatorPadding; | ||
|  | 			} | ||
|  | 
 | ||
|  | 			g.fillRect(toolbarw + selectedFrame * 11 * sc + 5 * sc - frameIndicatorWidth / 2, ty + frameIndicatorMargin, frameIndicatorWidth, frameIndicatorHeight); | ||
|  | 			g.color = 0xffffffff; | ||
|  | 			g.drawString("" + selectedFrame, toolbarw + selectedFrame * 11 * sc + 5 * sc - frameTextWidth / 2, ty + timelineLabelsHeight / 2 - g.fontSize / 2); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		g.end(); | ||
|  | 
 | ||
|  | 		ui.begin(g); | ||
|  | 
 | ||
|  | 		UIToolBar.renderToolbar(ui, cui, canvas, toolbarw); | ||
|  | 
 | ||
|  | 		if (ui.window(Id.handle(), toolbarw, 0, kha.System.windowWidth() - uiw - toolbarw, Std.int((ui.t.ELEMENT_H + 2) * ui.SCALE()))) { | ||
|  | 			ui.tab(Id.handle(), canvas.name); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		UIProperties.renderProperties(ui, uiw, canvas); | ||
|  | 
 | ||
|  | 		ui.end(); | ||
|  | 
 | ||
|  | 		if (ui.changed && !ui.inputDown) drawGrid(); | ||
|  | 
 | ||
|  | 		g.begin(false); | ||
|  | 
 | ||
|  | 		if (dragAsset != null) { | ||
|  | 			var w = std.Math.min(128, Assets.getImage(dragAsset).width); | ||
|  | 			var ratio = w / Assets.getImage(dragAsset).width; | ||
|  | 			var h = Assets.getImage(dragAsset).height * ratio; | ||
|  | 			g.drawScaledImage(Assets.getImage(dragAsset), ui.inputX, ui.inputY, w, h); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		g.end(); | ||
|  | 
 | ||
|  | 		if (lastW > 0 && (lastW != kha.System.windowWidth() || lastH != kha.System.windowHeight())) { | ||
|  | 			resize(); | ||
|  | 		} | ||
|  | 		else if (lastCanvasW > 0 && (lastCanvasW != canvas.width || lastCanvasH != canvas.height)) { | ||
|  | 			resize(); | ||
|  | 		} | ||
|  | 		lastW = kha.System.windowWidth(); | ||
|  | 		lastH = kha.System.windowHeight(); | ||
|  | 		lastCanvasW = canvas.width; | ||
|  | 		lastCanvasH = canvas.height; | ||
|  | 
 | ||
|  | 		if (showFiles) renderFiles(g); | ||
|  | 		if (Popup.show) Popup.render(g); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	function acceptDrag(index:Int) { | ||
|  | 		var elem = CanvasTools.makeElem(cui, canvas, ElementType.Image); | ||
|  | 		elem.asset = assetNames[index + 1]; // assetNames[0] == "" | ||
|  | 		elem.x = ui.inputX - canvas.x; | ||
|  | 		elem.y = ui.inputY - canvas.y; | ||
|  | 		elem.width = Assets.getImage(canvas.assets[index]).width; | ||
|  | 		elem.height = Assets.getImage(canvas.assets[index]).height; | ||
|  | 		selectedElem = elem; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function update() { | ||
|  | 
 | ||
|  | 		// Drag from assets panel | ||
|  | 		if (ui.inputReleased && dragAsset != null) { | ||
|  | 			if (ui.inputX < kha.System.windowWidth() - uiw) { | ||
|  | 				var index = 0; | ||
|  | 				for (i in 0...canvas.assets.length) if (canvas.assets[i] == dragAsset) { index = i; break; } | ||
|  | 				acceptDrag(index); | ||
|  | 			} | ||
|  | 			dragAsset = null; | ||
|  | 		} | ||
|  | 		if (dragAsset != null) return; | ||
|  | 
 | ||
|  | 		updateCanvas(); | ||
|  | 
 | ||
|  | 		// Select frame | ||
|  | 		if (timeline != null) { | ||
|  | 			var ty = kha.System.windowHeight() - timeline.height; | ||
|  | 			if (ui.inputDown && ui.inputY > ty && ui.inputX < kha.System.windowWidth() - uiw && ui.inputX > toolbarw) { | ||
|  | 				selectedFrame = Std.int((ui.inputX - toolbarw) / 11 / ui.SCALE()); | ||
|  | 			} | ||
|  | 		} | ||
|  | 
 | ||
|  | 		ElementController.update(ui, cui, canvas); | ||
|  | 
 | ||
|  | 		if (Popup.show) Popup.update(); | ||
|  | 
 | ||
|  | 		updateFiles(); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	function updateCanvas() { | ||
|  | 		if (showFiles || ui.inputX > kha.System.windowWidth() - uiw) return; | ||
|  | 
 | ||
|  | 		ElementController.selectElement(canvas); | ||
|  | 
 | ||
|  | 		if (!ElementController.isManipulating) { | ||
|  | 			// Pan canvas | ||
|  | 			if (ui.inputDownR) { | ||
|  | 				coffX += Std.int(ui.inputDX); | ||
|  | 				coffY += Std.int(ui.inputDY); | ||
|  | 			} | ||
|  | 
 | ||
|  | 			// Zoom canvas | ||
|  | 			if (ui.inputWheelDelta != 0) { | ||
|  | 				var prevZoom = zoom; | ||
|  | 				zoom += -ui.inputWheelDelta / 10; | ||
|  | 				if (zoom < 0.4) zoom = 0.4; | ||
|  | 				else if (zoom > 1.0) zoom = 1.0; | ||
|  | 				zoom = std.Math.round(zoom * 10) / 10; | ||
|  | 				cui.setScale(zoom); | ||
|  | 
 | ||
|  | 				// Update the grid only when necessary, this prevents lag from scrolling too fast | ||
|  | 				if (prevZoom != zoom) { | ||
|  | 					drawGrid(); | ||
|  | 				} | ||
|  | 			} | ||
|  | 		} | ||
|  | 
 | ||
|  | 		// Canvas resize | ||
|  | 		var handleSize = ElementController.handleSize; | ||
|  | 		if (ui.inputStarted && Math.hitbox(cui, canvas.x + scaled(canvas.width) - handleSize / 2, canvas.y + scaled(canvas.height) - handleSize / 2, handleSize, handleSize)) { | ||
|  | 			resizeCanvas = true; | ||
|  | 		} | ||
|  | 		if (ui.inputReleased && resizeCanvas) { | ||
|  | 			resizeCanvas = false; | ||
|  | 		} | ||
|  | 		if (resizeCanvas) { | ||
|  | 			canvas.width += Std.int(ui.inputDX); | ||
|  | 			canvas.height += Std.int(ui.inputDY); | ||
|  | 			if (canvas.width < 1) canvas.width = 1; | ||
|  | 			if (canvas.height < 1) canvas.height = 1; | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	function updateFiles() { | ||
|  | 		if (!showFiles) return; | ||
|  | 
 | ||
|  | 		if (ui.inputReleased) { | ||
|  | 			var appw = kha.System.windowWidth(); | ||
|  | 			var apph = kha.System.windowHeight(); | ||
|  | 			var left = appw / 2 - modalRectW / 2; | ||
|  | 			var right = appw / 2 + modalRectW / 2; | ||
|  | 			var top = apph / 2 - modalRectH / 2; | ||
|  | 			var bottom = apph / 2 + modalRectH / 2; | ||
|  | 			if (ui.inputX < left || ui.inputX > right || ui.inputY < top + modalHeaderH || ui.inputY > bottom) { | ||
|  | 				showFiles = false; | ||
|  | 			} | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	static var modalW = 625; | ||
|  | 	static var modalH = 545; | ||
|  | 	static var modalHeaderH = 66; | ||
|  | 	static var modalRectW = 625; // No shadow | ||
|  | 	static var modalRectH = 545; | ||
|  | 
 | ||
|  | 	static var path = '/'; | ||
|  | 	function renderFiles(g:kha.graphics2.Graphics) { | ||
|  | 		var appw = kha.System.windowWidth(); | ||
|  | 		var apph = kha.System.windowHeight(); | ||
|  | 		var left = appw / 2 - modalW / 2; | ||
|  | 		var top = apph / 2 - modalH / 2; | ||
|  | 
 | ||
|  | 		g.begin(false); | ||
|  | 		g.color = 0xff202020; | ||
|  | 		g.fillRect(left, top, modalW, modalH); | ||
|  | 		g.end(); | ||
|  | 
 | ||
|  | 		var leftRect = Std.int(appw / 2 - modalRectW / 2); | ||
|  | 		var rightRect = Std.int(appw / 2 + modalRectW / 2); | ||
|  | 		var topRect = Std.int(apph / 2 - modalRectH / 2); | ||
|  | 		var bottomRect = Std.int(apph / 2 + modalRectH / 2); | ||
|  | 		topRect += modalHeaderH; | ||
|  | 
 | ||
|  | 		uimodal.begin(g); | ||
|  | 		if (uimodal.window(Id.handle(), leftRect, topRect, modalRectW, modalRectH - 100)) { | ||
|  | 			var pathHandle = Id.handle(); | ||
|  | 			pathHandle.text = uimodal.textInput(pathHandle); | ||
|  | 			path = uimodal.fileBrowser(pathHandle, foldersOnly); | ||
|  | 		} | ||
|  | 		uimodal.end(false); | ||
|  | 
 | ||
|  | 		g.begin(false); | ||
|  | 
 | ||
|  | 		uimodal.beginRegion(g, rightRect - 100, bottomRect - 30, 100); | ||
|  | 		if (uimodal.button("OK")) { | ||
|  | 			showFiles = false; | ||
|  | 			filesDone(path); | ||
|  | 		} | ||
|  | 		uimodal.endRegion(false); | ||
|  | 
 | ||
|  | 		uimodal.beginRegion(g, rightRect - 200, bottomRect - 30, 100); | ||
|  | 		if (uimodal.button("Cancel")) { | ||
|  | 			showFiles = false; | ||
|  | 		} | ||
|  | 		uimodal.endRegion(); | ||
|  | 
 | ||
|  | 		g.end(); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	inline function scaled(f: Float): Int { return Std.int(f * cui.SCALE()); } | ||
|  | } |