From c266bf1ac0e7445e1e0981c6a23333eb33bc6068 Mon Sep 17 00:00:00 2001 From: Yoshman29 <81191621+YoshiCrafter29@users.noreply.github.com> Date: Mon, 17 Apr 2023 20:35:57 +0200 Subject: [PATCH] input box --- assets/images/editors/ui/inputbox.png | Bin 3693 -> 4035 bytes source/funkin/editors/UIDebugState.hx | 1 + source/funkin/editors/ui/IUIFocusable.hx | 10 +++ source/funkin/editors/ui/UISprite.hx | 16 ++++ source/funkin/editors/ui/UIState.hx | 29 ++++++ source/funkin/editors/ui/UITextBox.hx | 110 +++++++++++++++++++++++ source/funkin/scripting/Script.hx | 2 +- 7 files changed, 167 insertions(+), 1 deletion(-) create mode 100644 source/funkin/editors/ui/IUIFocusable.hx create mode 100644 source/funkin/editors/ui/UITextBox.hx diff --git a/assets/images/editors/ui/inputbox.png b/assets/images/editors/ui/inputbox.png index a81994a5b88ff929ea08b8d34008a87663355524..229df739d8ce6666e1109e38c01b4d72b8a62040 100644 GIT binary patch delta 4017 zcmV;i4^Hsy9K#=wIDZdyNklkD#j$TY<##+%|&uA7#9U1WH7 z^^ueN&8J%{t~6WfjtFm#X}|7h6JN3O^SlV7#uOE!-#9xtDrs8pAF1uG|Ged&wn68C z_1lW;3s>g^*nj7g-z;6abnWKNoA-8hc4~Wjd!ehV3s5xhcsx^nfYj7fNKQ_sbJna` z_P5`Dd&8+yrw)g@cSG8PYd3CPx3{~sPdm^v1U>Cnp}X}8cm?m2?I+BOf%x>%Zt&ul2PP(j3SWzTp>@!L0nbSMHyYwnW1(uT4-rN!;LjjDJPZU6K7kick2g>_>5!j{Q=w&!10JtV zryKfvEMOh9gWD-UOmZ~Yztq;Z?hl`B``Gt)7A#n>X8rp0|Ej5};agf-z+$nG=*(b% z5%0tVU=I-dJ%eE|7+8pd{QP|3`0?YnRaaMk#D9LjD(07K*51DAU#I@l%%5*+hi+){ zi4OFyS9(dW;#EhrPG9mTP{2rlESQ^>2HA^Kg)ghVx@~{^t7Ly$;nTNd6{Z|!_Pbkq zVg8~N0>DILr$_LBfTsuFpYx8c1A9*|np80Wyb4r!vcJPl!Q}z-i3^aB5kvMbwfC)k zu7B#$Pq>VX4E45c+iV989N;fryf{Mq$wCMvekcg5SFaXcdF2&d+J$9s*W;UPN8hXA zJ1=xX543;)E*kHm=;E%a<=NUbbvm)$ZN9VQ_FzbTftcqk)*H7qDyaXQR;wCX)$jYimnl zd-7q~^5Uw4uT?@PG@|%!DcHzC$DAY7{^09t)GdXtwt z;pQzxFnrZ|6IWVV`n1#OeEjIqqhPgKM-_fL0D?haWdt|hd^2dZ+Gk>~WP@vvfBe{| zUqByV!lx1MrK=JE`=6c(h9D-l7k?lCfQmdp{4^VqVc9Juz#D~UjM`|S|FY%D`Y)O> z^rV8_;sD#QL-GI@c>oiQ@}OjTEDw+#fxMl;6g@x$pwnwWYtX>C+6$0Zk_l0bK zdE}ACy1KgTvuDpz(jCnMCIdkkhC+D&OUQY7c`PBDHRltd;rNB@)6FNq3V#EV^z2LU zf$#^Q3EKCCAWk7XPoLSR2#A6OS&N}?^?b8)NbsJnYR+M!J{FUtjRCOOarC>v$pD}S zc%<+%nfIq~!~if4U;wmXpfhOk)WGGAe!4DRlh??-^wLY-7himl!VjY?S3I)8v5d;U z3y%At9!9>0Mh2eI(b4eGLw^rJ)YZB0PFV$Xff<93Ly}zZjehVU3H2Pl+GE6TR0{F^ zUcgJ~SOZCX4*cS`x6!@Ke&&KC3LVxV6rY743_mWcV%%;~6HZ}%Tn}LPaB>x>0yS1q z6oxPa;k z7fVu1=xP>*bm5@JFr+u?z<_7{@fNZl0AMuXX97Sl2pK?Be;T}1_8}(VGXcW0&wk;j z9)iG^0r&tANeJNX@_!9|E>cHc(0^FdM)o-rp8yOD41^SZ zs^TjlgaQ#26-5A|22$ZKWqUCPG$=;CEWXDlz85AJ1LXQ&grHJ*f#?Z|kPE*q-$eH? z`?&~UXuyg9>?FSE0b=<%9RMs0@iG7{1Az1Ls0e640L=cV0H!
    mapR{}5&q`;eH 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 Xth?%Ao5j9500000NkvXXu0mjfM1P6z delta 3672 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 = null; public var hoveredSprite:UISprite = null; + public var currentFocus:IUIFocusable = null; private var __rect:FlxRect; private var __mousePos:FlxPoint; @@ -27,6 +31,25 @@ class UIState extends MusicBeatState { __mousePos = FlxPoint.get(); super.create(); Framerate.offset.y = 30; + + FlxG.stage.window.onKeyDown.add(onKeyDown); + FlxG.stage.window.onKeyUp.add(onKeyUp); + FlxG.stage.window.onTextInput.add(onTextInput); + } + + private function onKeyDown(e:KeyCode, modifier:KeyModifier) { + if (currentFocus != null) + currentFocus.onKeyDown(e, modifier); + } + + private function onKeyUp(e:KeyCode, modifier:KeyModifier) { + if (currentFocus != null) + currentFocus.onKeyUp(e, modifier); + } + + private function onTextInput(str:String) { + if (currentFocus != null) + currentFocus.onTextInput(str); } public function updateButtonHandler(spr:UISprite, buttonHandler:Void->Void) { @@ -69,6 +92,9 @@ class UIState extends MusicBeatState { buttonHandler = null; } + if (FlxG.mouse.justReleased) + currentFocus = (hoveredSprite is IUIFocusable) ? (cast hoveredSprite) : null; + if (hoveredSprite != null) { Mouse.cursor = hoveredSprite.cursor; hoveredSprite = null; @@ -80,6 +106,9 @@ class UIState extends MusicBeatState { public override function destroy() { super.destroy(); __mousePos.put(); + FlxG.stage.window.onKeyDown.remove(onKeyDown); + FlxG.stage.window.onKeyUp.remove(onKeyUp); + FlxG.stage.window.onTextInput.remove(onTextInput); } public function openContextMenu(options:Array, ?callback:UIContextMenuCallback, ?x:Float, ?y:Float) { diff --git a/source/funkin/editors/ui/UITextBox.hx b/source/funkin/editors/ui/UITextBox.hx new file mode 100644 index 00000000..887ef063 --- /dev/null +++ b/source/funkin/editors/ui/UITextBox.hx @@ -0,0 +1,110 @@ +package funkin.editors.ui; + +import flixel.math.FlxPoint; +import lime.ui.KeyModifier; +import lime.ui.KeyCode; +import openfl.desktop.Clipboard; +import openfl.geom.Rectangle; + +class UITextBox extends UISliceSprite implements IUIFocusable { + public var label:UIText; + + public var position:Int = 0; + public var multiline:Bool = false; + public var caretSpr:FlxSprite; + + public function new(x:Float, y:Float, text:String = "", width:Int = 320, height:Int = 32, multiline:Bool = false) { + super(x, y, width, height, 'editors/ui/inputbox'); + + label = new UIText(0, 0, width, text); + members.push(label); + + caretSpr = new FlxSprite(0, 0); + caretSpr.makeGraphic(1, 1, -1); + caretSpr.scale.set(1, label.size); + caretSpr.updateHitbox(); + members.push(caretSpr); + this.multiline = multiline; + } + + var cacheRect:Rectangle = new Rectangle(); + + public override function update(elapsed:Float) { + super.update(elapsed); + var off = multiline ? 4 : ((bHeight - label.height) / 2); + label.follow(this, 4, off); + + if (hovered && FlxG.mouse.justReleased) { + // get caret pos + var pos = FlxG.mouse.getScreenPosition(camera, FlxPoint.get()); + pos.x -= label.x; + pos.y -= label.y; + + var index = label.textField.getCharIndexAtPoint(pos.x, pos.y); + if (index > -1) + position = index; + + pos.put(); + } + framesOffset = (focused ? 18 : (hovered ? 9 : 0)); + @:privateAccess { + if (focused) { + caretSpr.alpha = (FlxG.game.ticks % 666) >= 333 ? 1 : 0; + + var curPos = switch(position) { + case 0: + FlxPoint.get(0, 0); + default: + if (position >= label.text.length) { + label.textField.__getCharBoundaries(label.text.length-1, cacheRect); + FlxPoint.get(cacheRect.x + cacheRect.width, cacheRect.y); + } else { + label.textField.__getCharBoundaries(position, cacheRect); + FlxPoint.get(cacheRect.x, cacheRect.y); + } + }; + caretSpr.follow(this, 4 + curPos.x, off + curPos.y); + curPos.put(); + } else { + caretSpr.alpha = 0; + } + } + } + + public function onKeyDown(e:KeyCode, modifier:KeyModifier) { + switch(e) { + case LEFT: + changeSelection(-1); + case RIGHT: + changeSelection(1); + case BACKSPACE: + if (position > 0) { + label.text = label.text.substr(0, position-1) + label.text.substr(position); + changeSelection(-1); + } + case HOME: + position = 0; + case END: + position = label.text.length; + case V: + if (modifier == KeyModifier.LEFT_CTRL || modifier == KeyModifier.RIGHT_CTRL ) { + // paste + var data:String = Clipboard.generalClipboard.getData(TEXT_FORMAT); + if (data != null) + onTextInput(data); + } + default: + // nothing + } + } + + public function changeSelection(change:Int) { + position = FlxMath.wrap(position + change, 0, label.text.length); + } + public function onKeyUp(e:KeyCode, modifier:KeyModifier) {} + + public function onTextInput(text:String):Void { + label.text = label.text.substr(0, position) + text + label.text.substr(position); + position += text.length; + } +} \ No newline at end of file diff --git a/source/funkin/scripting/Script.hx b/source/funkin/scripting/Script.hx index b25aa4ca..ff06a8a3 100644 --- a/source/funkin/scripting/Script.hx +++ b/source/funkin/scripting/Script.hx @@ -31,7 +31,7 @@ class Script extends FlxBasic implements IFlxDestroyable { // Flixel related stuff "FlxG" => flixel.FlxG, - "FlxSprite" => flixel.FlxSprite, + "FlxSprite" => funkin.system.FunkinSprite, "FlxBasic" => flixel.FlxBasic, "FlxCamera" => flixel.FlxCamera, "state" => flixel.FlxG.state,