From 3e7c54479075f940ef9d4560e40ec2f574b6be8e Mon Sep 17 00:00:00 2001 From: Emma <31828821+Gemmstone@users.noreply.github.com> Date: Sun, 11 Feb 2024 18:24:01 -0500 Subject: [PATCH] Added controller support for assets --- .gitignore | 1 - Assets/hands/hands.png | Bin 0 -> 43369 bytes Assets/hands/thumbs/down.png | Bin 0 -> 8945 bytes Assets/hands/thumbs/hands.png | Bin 0 -> 10151 bytes Assets/hands/thumbs/idle.png | Bin 0 -> 8945 bytes Assets/hands/thumbs/left.png | Bin 0 -> 8945 bytes Assets/hands/thumbs/right.png | Bin 0 -> 8945 bytes Core/Settings.py | 107 ++- Core/ShortcutsManager.py | 24 +- Core/Viewer.py | 42 +- Core/audioManager.py | 5 +- Data/current.json | 2 +- Data/keys.json | 6 + Data/parameters.json | 503 ++++++++++++- Data/settings.json | 6 +- Models/Avatars/Default/model.json | 24 +- Models/Avatars/Default/thumb.png | Bin 8139 -> 8139 bytes UI/settingsWidget.ui | 1130 +++++++++++++++++++++++++++-- Viewer/mouseControl.js | 72 -- Viewer/script.js | 188 +++++ Viewer/viewer.html | 408 ++++++++++- main.py | 4 +- 22 files changed, 2306 insertions(+), 216 deletions(-) create mode 100644 Assets/hands/hands.png create mode 100644 Assets/hands/thumbs/down.png create mode 100644 Assets/hands/thumbs/hands.png create mode 100644 Assets/hands/thumbs/idle.png create mode 100644 Assets/hands/thumbs/left.png create mode 100644 Assets/hands/thumbs/right.png create mode 100644 Data/keys.json delete mode 100644 Viewer/mouseControl.js create mode 100644 Viewer/script.js diff --git a/.gitignore b/.gitignore index 3eb04e30..acfe7423 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,6 @@ /venv/ /Builds/ /.idea/ -/Data/keys.json /Data/user_token.json build.sh build.bat \ No newline at end of file diff --git a/Assets/hands/hands.png b/Assets/hands/hands.png new file mode 100644 index 0000000000000000000000000000000000000000..165c5404689ca8b5889c0e2a81db6eb7b738b051 GIT binary patch literal 43369 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

#83)GxpwwdE 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 literal 0 HcmV?d00001 diff --git a/Assets/hands/thumbs/down.png b/Assets/hands/thumbs/down.png new file mode 100644 index 0000000000000000000000000000000000000000..493c4067647576f2ed4b4cb9753cd609b2b6cccf GIT binary patch literal 8945 zcmeHNUr19?82`@QmUFt5sY#0>Mj&Vgg}Fe|YiYTMq(3eweCVMl10fIu>ESwwpztLq zG9saZpp7C3f<*9UL6H?s@(T8k=s_cw)44y_-QCl<;lu9W=2Fpn$31X%&UfxP`+mRg z_kDK{XIBn49JE^O767oi>T8dZaTn>^&1=YK@sD38$&h`a{zNN)?UmHgjZ)htfUV%F zt!X@GLS2s5FJzD2^a$t?SX2ZsAdE3u)Y%m{l!}c~^2q>$eBe`ju5@mt)>&W;$-Yzz zG#O+%bL|pg<@B^mgw7Nq8Ka0?5YTRF=|oZ@u<9l)N1)x*Vl#z^u83So)mhrD5k0lk zmQ1=LYEvWyk9Lb)Cz29@RX1rl0_~<2n<+$eMdV7V&eCp;=&7Z)WYQH;n<6QAv|H>t zk(3Cmx=G6s80F@YEXwQkBDdQu*3=*a3rU^|3o(EXpajUs%scS_c!r$s>#H`*+!_e^j{7DgM^#)C z8L6Ane*uUoeeuFdv1C_LTM8*j6(EFi+b*>}s@t=-5``lc$JbAArmVE$+BkVRW*LDO zco1R*8T7ipVD&k-@hrOR+U;uM@IsRigK#U zb~t-``~7Th-*D8H_wMs_WbEf`go`HxE;`4LVwCXb7ua6L;=CUy{DzN5Kax2Y6?iTZ z4vtvu_Tj#byZy|Qw?j_Hw!qHf5+{)ZyE#r$MX}L9%hIp?!T9wT_qmJG0asl^?c;r? GI{yHA+yPhs literal 0 HcmV?d00001 diff --git a/Assets/hands/thumbs/hands.png b/Assets/hands/thumbs/hands.png new file mode 100644 index 0000000000000000000000000000000000000000..5b6e2cd0a3400773ef4f5e6a860a946b62fa728f GIT binary patch literal 10151 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 J)TKAx`#+oX66pW{ literal 0 HcmV?d00001 diff --git a/Assets/hands/thumbs/idle.png b/Assets/hands/thumbs/idle.png new file mode 100644 index 0000000000000000000000000000000000000000..4e6938d6b1a8a0b613a5537818dc9931bac1b444 GIT binary patch literal 8945 zcmeHNZ)jUp6hG(Qq-jFZX8oHcHO;!kHQ5%og8S>t+uCg{u2aMac2(=2jp~;TDySbM zjUNO>{HB6m9QZ+KQO0CQ5llK)q=h2*p`utnv^uew>u_7srn&ceAM051YD(KYLs#B| zm;2tm=iGD8?|07S@=o4;;^c9M&20k!M|)fAld^4=_m0vM`MYf@*(n?AxwdC|0m`nZ zH-5Oi%md(q_SVBs^_cPf#@-1jV_XIT1_A{jfCcFOuc|_boVAgB)}qlU>F@8)JDyLk zSp9v81kJX!ZWo%p$p3m)G@bXYBS}RO*}mMjj#MWSE6b5=Z`b3q!N_`JWy3I{1=dJ* zEh5E!-!P$NY`?`0oz>bil6|#^=`C+0yWWTvI-kKvp$O`&zhM~B0%L5yT11NdzF|Vk zIBOLuI27zi}jJ58pPePC9QNo7G72+yF~d;hg!IaL?Y@O_Z-b5 zt9HlZ@f;FzUY5~YZU`Y3;~0~OyX?U|kGHjq{_^8xs48~?l~pB&RlwBr3<$;`od)pK zmV=3w!0ZA-^6Ed^DjK$wSgX>ActILjF)O-;mW&sa@QJc!-@dbvQ_nuUb4T~s*MqjO zWfKfvcK|~QEXhD*+`u^pf&}m?0YWK|^a9M*_@UZW3vV6_z^~!(;HO_*IzRHq&lh3r z&(tDvIW>@MH1#`cMS*~jc4{n*AHDYaaF-H()%^Vx+l!XDOz*A$R9l?!o_~XXaofqg4T0mI^}Y4E<%6F60OVu!zW@h( zJ71QI7fMuFHf*)*togVSg(#7sAv(KHJ=a+4#&=Hlr2IGk;ucEjZ_`P^1jD(Ej2;uB z*H^Ihh|p#v|eEX4cbTsAAp z9aVmz6oxvEf!$Lt+73V3@ssO^PvZS?RbB;r$)ydg!NifHmjV^< Qse#(wHdg6*Uquh~R;@hJYGSVr^@?>nss)wr+8vQ+B~D*&Wcl)Kj9wh%w_EhhY*|MtTM+$8TRuc`+~yQx0txFc;QKps@MoSqsE zHO{Voj(rlpgaQc##-)G)NWsszVkaR;Q4|6jqnA?v0X2i7JFXWuS??u~l77ua0owel zuc7-CB3|Qymq=(7A_lGq9~Y5CMM$|O!J;g!NkH(2Qc#E(cxh<_pb$xHc8y*WU`phi z|4T(k)`qg;tB9eX#{@%JS}|k)?jTR5rw}pl@hineBys$ba!rKw&s0Ps4rPyMybWwp zh!}XYYec0GNo;nFUK3zS z{E~7_g!Ru2ZFOCF&&d!l{O=?E37koaS zjC+a(fWFD=4-q4RA}~#gLR_X04$%g_;Zhik1n~eYhC9@ccGG{OG&QODMo8*=0<^TW z5Je!2=)kd6L=Xg46vZ$?Xjsv(geMc#35Tx8d<^VvHbHo4CiH#FfNv<<+8?s|2YNX7 zGG~=-TF#A=`;MMLK3~5YGNvC-dg-!PE8+kL@*!V@4AHfw>}lA2_d zw*W`PBU|wm;GhViD$uYv0f9Tn@tdj$PkfbU|AM|!60xPCvz5y92ocn$#V*nU~vgFK5B(IpI_RxuUYN6 z+TMOwJSR5tJkLs!Gy?SZ2u9yhPOwo&ZBI>vNhpOLe*J+RJNKKqpXE-yavnT$b6{$U z88cKsPGW#DbC5mV1}tvp71$wtN;(tz9%2#0u!FC=xvVce+~Qf8+=FMY;NsCkcIgJc&r(k@SnQ>gwu-%I+#&p5OiCMeBu=r#h2UQac{?ettUe)&CSJk*-i6 z*p;1``LJ-&f_vGvtoGX4&3DU6ovi`CzsoO29@|5GZ8d2h?`$&nJ~+Ll;+~_xe#^aV pY1fL<;wm+v*Xz~Y20ZY@vb$Y0c>iG83bz_pQL@%`cIBqMKLEg&3;zHB literal 0 HcmV?d00001 diff --git a/Assets/hands/thumbs/right.png b/Assets/hands/thumbs/right.png new file mode 100644 index 0000000000000000000000000000000000000000..4fb7584e21d10c6ad620b9af3eb3ed442ff9c23c GIT binary patch literal 8945 zcmeHNOKcNI82)D;j_qI*S8*$7C=~*Q#tl&*raXjMx2Z?~Q3AwLOAjGJ0=24(06 z4xpk|h=Wye;SjZ`N-EU$z@buQN2HB71rTZvRY;&J39Z_^TGqSq>@e#PDYL~M7ByxC zUTJsz@67-BzHk1yj6d1CXGg%l+z$YO_O{l2^u3i967Q@JV(R2X<71_&TR?j+3?`(^1` z4C|Ru#6}LMM{KiQY;u6OxY=!_a)4Bt-Nx43MWrhH^PvJsL z>kIEv*ame%{_kmXc0>w!^~4*|C7<>59E0JBn^uzUj`#neLVa%i z7r>shm~E*OkH_=#;~aJ7r?Kze-d=$M!n?coe-vwKUUBBghuX($!cz35T44r>WEumh z@>T)DBJp4hAzzJX7=|E=l3$V~znRm*MqOP!*|-g&=q~)2PXBcAhyHWvFV3GMWAN8Q zrXBSYX9r^e6fD~4i9`ZdH`X;C-nsMi_?_QD>3GNIKlFh-($FFfYDm&Bk-;?Or8PlM zOG~q7X(%W*HbqcPI0ObU!9)a1pC4AncEF_U-RaIV}0w`>4 zjuq+rxs#s!_QATA4O_Nvie3+RyxPRQKg7xD8C<(123MwxB~wHFQb?{Qp-|0iL&MtK zyg!~gJ07%mP{sbDwSd@ ewOI-%jAHV)%T9h5`2M^#t^Msit(V^HI{5(TGcfi5 literal 0 HcmV?d00001 diff --git a/Core/Settings.py b/Core/Settings.py index 7c2e42c0..7eb87b0f 100644 --- a/Core/Settings.py +++ b/Core/Settings.py @@ -22,9 +22,27 @@ def __init__(self, parameters, exe_dir): self.og_height = self.parameters["sizeY"] self.posX.setValue(self.parameters["posX"]) - self.posY.setValue(self.parameters["posY"]) + self.posY.setValue(self.parameters["posY"] * -1) self.posZ.setValue(self.parameters["posZ"]) self.rotation.setValue(self.parameters["rotation"]) + + self.originX.setValue(self.parameters.get("originX", 0)) + self.originY.setValue(self.parameters.get("originY", 0) * -1) + self.deg.setValue(self.parameters.get("deg", 90)) + self.deadzone.setValue(self.parameters.get("deadzone", 0.0550)) + self.player.setValue(self.parameters.get("player", 0)) + self.buttonCombo.setCurrentIndex(self.parameters.get("buttons", 0)) + + self.posBothX.setValue(self.parameters.get("posBothX", 0)) + self.posBothY.setValue(self.parameters.get("posBothY", 0) * -1) + self.rotationBoth.setValue(self.parameters.get("rotationBoth", 0)) + self.posLeftX.setValue(self.parameters.get("posLeftX", 0)) + self.posLeftY.setValue(self.parameters.get("posLeftY", 0) * -1) + self.rotationLeft.setValue(self.parameters.get("rotationLeft", 0)) + self.posRightX.setValue(self.parameters.get("posRightX", 0)) + self.posRightY.setValue(self.parameters.get("posRightY", 0) * -1) + self.rotationRight.setValue(self.parameters.get("rotationRight", 0)) + self.check_hotkeys() self.sizeX.valueChanged.connect(self.maintain_aspect_ratio_w) @@ -36,30 +54,63 @@ def __init__(self, parameters, exe_dir): self.posY.valueChanged.connect(self.save_current) self.posZ.valueChanged.connect(self.save_current) self.rotation.valueChanged.connect(self.save_current) + self.originY.valueChanged.connect(self.save_current) + self.originY.valueChanged.connect(self.save_current) + + self.posBothX.valueChanged.connect(self.save_current) + self.posBothY.valueChanged.connect(self.save_current) + self.rotationBoth.valueChanged.connect(self.save_current) + self.posLeftX.valueChanged.connect(self.save_current) + self.posLeftY.valueChanged.connect(self.save_current) + self.rotationLeft.valueChanged.connect(self.save_current) + self.posRightX.valueChanged.connect(self.save_current) + self.posRightY.valueChanged.connect(self.save_current) + self.rotationRight.valueChanged.connect(self.save_current) + + self.deg.valueChanged.connect(self.save_current) + self.deadzone.valueChanged.connect(self.save_current) + self.player.valueChanged.connect(self.save_current) + self.buttonCombo.currentIndexChanged.connect(self.save_current) self.setShortcut.clicked.connect(self.request_shortcut) + if "controller" not in self.parameters.keys(): + self.parameters["controller"] = "ignore" + self.blinkingGroup.setChecked(self.parameters["blinking"] != "ignore") self.talkingGroup.setChecked(self.parameters["talking"] != "ignore") + self.controllerGroup.setChecked(self.parameters["controller"] != "ignore") self.cssGroup.setChecked(self.parameters["use_css"]) self.css.setPlainText(self.parameters["css"]) self.blinkingGroup.toggled.connect(self.hide_blinking) self.talkingGroup.toggled.connect(self.hide_talking) + self.controllerGroup.toggled.connect(self.hide_controller) self.cssGroup.toggled.connect(self.hide_css) self.blinkOpen.setChecked(self.parameters["blinking"] == "blinking_open") self.blinkClosed.setChecked(self.parameters["blinking"] == "blinking_closed") + self.display.setChecked(self.parameters.get("mode", 'display') == "display") + self.move.setChecked(self.parameters.get("mode", 'display') == "move") + self.talkOpen.setChecked(self.parameters["talking"] == "talking_open") self.talkClosed.setChecked(self.parameters["talking"] == "talking_closed") self.talkScreaming.setChecked(self.parameters["talking"] == "talking_screaming") + self.controllerButtons.setChecked("controller_buttons" in self.parameters["controller"]) + self.controllerWheel.setChecked("controller_wheel" in self.parameters["controller"]) + self.blinkOpen.toggled.connect(self.save_current) self.blinkClosed.toggled.connect(self.save_current) self.talkOpen.toggled.connect(self.save_current) self.talkClosed.toggled.connect(self.save_current) self.talkScreaming.toggled.connect(self.save_current) + self.controllerButtons.toggled.connect(self.save_current) + self.controllerWheel.toggled.connect(self.save_current) + + self.display.toggled.connect(self.save_current) + self.move.toggled.connect(self.save_current) self.css.textChanged.connect(self.css_finished_edit) @@ -67,6 +118,7 @@ def __init__(self, parameters, exe_dir): self.hide_blinking() self.hide_talking() + self.hide_controller() self.hide_css() def check_hotkeys(self): @@ -107,6 +159,16 @@ def hide_talking(self): "QGroupBox::title{border-bottom-left-radius: 9px;border-bottom-right-radius: 9px;}") self.save_current() + def hide_controller(self): + if self.controllerGroup.isChecked(): + self.frame_6.show() + self.controllerGroup.setStyleSheet("") + else: + self.frame_6.hide() + self.controllerGroup.setStyleSheet( + "QGroupBox::title{border-bottom-left-radius: 9px;border-bottom-right-radius: 9px;}") + self.save_current() + def hide_css(self): if self.cssGroup.isChecked(): self.frame_5.show() @@ -123,13 +185,40 @@ def save(self): self.parameters["sizeX"] = self.sizeX.value() self.parameters["sizeY"] = self.sizeY.value() self.parameters["posX"] = self.posX.value() - self.parameters["posY"] = self.posY.value() + self.parameters["posY"] = self.posY.value() * -1 self.parameters["posZ"] = self.posZ.value() + self.parameters["originX"] = self.originX.value() + self.parameters["originY"] = self.originY.value() * -1 + self.parameters["deg"] = self.deg.value() + self.parameters["deadzone"] = self.deadzone.value() + self.parameters["player"] = self.player.value() + self.parameters["buttons"] = self.buttonCombo.currentIndex() + + self.parameters['mode'] = 'display' if self.display.isChecked() else 'move' + + if self.display.isChecked(): + self.frame_10.show() + self.tabWidget.hide() + else: + self.frame_10.hide() + self.tabWidget.show() + + self.parameters['posBothX'] = self.posBothX.value() + self.parameters['posBothY'] = self.posBothY.value() * -1 + self.parameters['rotationBoth'] = self.rotationBoth.value() + self.parameters['posLeftX'] = self.posLeftX.value() + self.parameters['posLeftY'] = self.posLeftY.value() * -1 + self.parameters['rotationLeft'] = self.rotationLeft.value() + self.parameters['posRightX'] = self.posRightX.value() + self.parameters['posRightY'] = self.posRightY.value() * -1 + self.parameters['rotationRight'] = self.rotationRight.value() + self.parameters["use_css"] = True if self.cssGroup.isChecked() else False self.parameters["css"] = self.css.toPlainText() self.parameters["rotation"] = self.rotation.value() self.parameters["blinking"] = self.getBlinking() if self.blinkingGroup.isChecked() else "ignore" self.parameters["talking"] = self.getTalking() if self.talkingGroup.isChecked() else "ignore" + self.parameters["controller"] = self.getController() if self.controllerGroup.isChecked() else ["ignore"] def save_current(self): self.save() @@ -144,6 +233,20 @@ def getBlinking(self): return "blinking_open" return "blinking_closed" + def getController(self): + checked = [] + if self.controllerButtons.isChecked(): + self.frame_8.show() + checked.append("controller_buttons") + else: + self.frame_8.hide() + if self.controllerWheel.isChecked(): + self.frame_7.show() + checked.append("controller_wheel") + else: + self.frame_7.hide() + return checked if checked else ["ignore"] + def getTalking(self): if self.talkOpen.isChecked(): return "talking_open" diff --git a/Core/ShortcutsManager.py b/Core/ShortcutsManager.py index e301a4c6..f9e4dffb 100644 --- a/Core/ShortcutsManager.py +++ b/Core/ShortcutsManager.py @@ -10,6 +10,7 @@ from twitchAPI.twitch import Twitch from twitchAPI.helper import first from PyQt6.QtGui import QIcon +from aiohttp.client_exceptions import ClientConnectionError import os.path import asyncio import json @@ -90,17 +91,22 @@ async def on_gifted_sub(self, data: ChannelSubscriptionGiftEvent): ) async def _run(self): - await self.authorize() - user = await first(self.twitch.get_users()) - await self.listen(user) + auth = await self.authorize() + if auth: + user = await first(self.twitch.get_users()) + await self.listen(user) async def authorize(self): - self.twitch = await Twitch(self.APP_ID, self.APP_SECRET) - helper = UserAuthenticationStorageHelper( - self.twitch, self.TARGET_SCOPES, - storage_path=os.path.normpath(f"Data{os.path.sep}user_token.json") - ) - await helper.bind() + try: + self.twitch = await Twitch(self.APP_ID, self.APP_SECRET) + helper = UserAuthenticationStorageHelper( + self.twitch, self.TARGET_SCOPES, + storage_path=os.path.normpath(f"Data{os.path.sep}user_token.json") + ) + await helper.bind() + return True + except ClientConnectionError: + return False async def listen(self, user): self.eventsub = EventSubWebsocket(self.twitch) diff --git a/Core/Viewer.py b/Core/Viewer.py index bb021118..8ee27438 100644 --- a/Core/Viewer.py +++ b/Core/Viewer.py @@ -63,6 +63,42 @@ def handle_runtime_html(self, runtime_page, soup, image_div, image_list): if image_list is not None: for layer in sorted(image_list, key=lambda x: x['posZ']): + controller_wheel_div = soup.new_tag('div', style=f""" + position: absolute !important; + transform-origin: calc(50% + {layer.get('originX', 0)}px) calc(50% + {layer.get('originY', 0)}px); + transform: rotate(0deg); + """) + controller_wheel_div['class'] = ["controller_wheel" if "controller_wheel" in layer.get('controller', ["ignore"]) else "ignore"] + controller_wheel_div['player'] = layer.get("player", 1) - 1 + controller_wheel_div['deg'] = layer.get('deg', -90) + controller_wheel_div['deadzone'] = layer.get("deadzone", 0.0550) + + controller_buttons_div = soup.new_tag('div', style=f""" + position: absolute !important; + left: calc(50% + {layer.get('posIdleX', 0)}px); + top: calc(50% + {layer.get('posIdleY', 0)}px); + transform: rotate({layer.get('rotationIdle', 0)}deg); + display: {("block" if layer.get("buttons", 0) == 0 else "none") if layer.get("mode", 'display') else "block"}; + """) + + controller_buttons_div['class'] = ["controller_buttons" if "controller_buttons" in layer.get('controller', ["ignore"]) else "ignore"] + controller_buttons_div['player'] = layer.get("player", 1) - 1 + + controller_buttons_div['mode'] = layer.get("mode", 'display') + controller_buttons_div['buttons'] = layer.get("buttons", 0) + + controller_buttons_div['posBothX'] = layer.get("posBothX", 0) + controller_buttons_div['posBothY'] = layer.get("posBothY", 0) + controller_buttons_div['rotationBoth'] = layer.get("rotationBoth", 0) + + controller_buttons_div['posLeftX'] = layer.get("posLeftX", 0) + controller_buttons_div['posLeftY'] = layer.get("posLeftY", 0) + controller_buttons_div['rotationLeft'] = layer.get("rotationLeft", 0) + + controller_buttons_div['posRightX'] = layer.get("posRightX", 0) + controller_buttons_div['posRightY'] = layer.get("posRightY", 0) + controller_buttons_div['rotationRight'] = layer.get("rotationRight", 0) + img_tag = soup.new_tag('img', src=f"../{layer['route']}", style=f""" position: absolute !important; left: calc(50% + {layer['posX']}px); @@ -76,10 +112,12 @@ def handle_runtime_html(self, runtime_page, soup, image_div, image_list): """) img_tag['class'] = [layer['blinking'], layer['talking']] - image_div.append(img_tag) + controller_buttons_div.append(img_tag) + controller_wheel_div.append(controller_buttons_div) + + image_div.append(controller_wheel_div) beautiful_html = soup.prettify() with open('Viewer/viewer.html', 'w') as html_file: html_file.write(beautiful_html) - self.reload() diff --git a/Core/audioManager.py b/Core/audioManager.py index 95b5bfb3..3c03e8ca 100644 --- a/Core/audioManager.py +++ b/Core/audioManager.py @@ -183,5 +183,6 @@ def update_volume(self, volume): self.activeAudio.emit(self.active_audio_signal) def check_inactivity(self): - print("No audio data received for a while. Restarting the stream.") - self.update_audio_stream(force=True) + if not self.mute.isChecked(): + print("No audio data received for a while. Restarting the stream.") + self.update_audio_stream(force=True) diff --git a/Data/current.json b/Data/current.json index 3d8daa65..85e496c1 100644 --- a/Data/current.json +++ b/Data/current.json @@ -3,7 +3,7 @@ "Assets/right eye/right eye_058.png", "Assets/left eye/left eye_001.png", "Assets/left eye/left eye_058.png", - "Assets/hands/hands_118.png", + "Assets/hands/hands_017.png", "Assets/hairbows/hairbows_360.png", "Assets/ahoge/ahoge_027.png", "Assets/bangs/bangs_171.png", diff --git a/Data/keys.json b/Data/keys.json new file mode 100644 index 00000000..715c4b7e --- /dev/null +++ b/Data/keys.json @@ -0,0 +1,6 @@ +{ + "twitch": { + "client": "", + "secret": "" + } +} \ No newline at end of file diff --git a/Data/parameters.json b/Data/parameters.json index 71ed8091..85d628d3 100644 --- a/Data/parameters.json +++ b/Data/parameters.json @@ -2867,7 +2867,27 @@ "talking": "ignore", "hotkeys": [], "rotation": 0, - "use_css": false + "use_css": false, + "controller": [ + "controller_buttons", + "controller_wheel" + ], + "originX": 0, + "originY": 500, + "deg": -10, + "deadzone": 0.055, + "player": 1, + "buttons": 0, + "mode": "move", + "posBothX": 0, + "posBothY": 20, + "rotationBoth": 0, + "posLeftX": 35, + "posLeftY": 20, + "rotationLeft": 5, + "posRightX": -35, + "posRightY": 20, + "rotationRight": -5 }, "Assets/hands/hands_002.png": { "sizeX": 600, @@ -2881,7 +2901,27 @@ "talking": "ignore", "hotkeys": [], "rotation": 0, - "use_css": false + "use_css": false, + "controller": [ + "controller_buttons", + "controller_wheel" + ], + "originX": 0, + "originY": 500, + "deg": -10, + "deadzone": 0.055, + "player": 1, + "buttons": 0, + "mode": "move", + "posBothX": 0, + "posBothY": 20, + "rotationBoth": 0, + "posLeftX": 35, + "posLeftY": 20, + "rotationLeft": 5, + "posRightX": -35, + "posRightY": 20, + "rotationRight": -5 }, "Assets/hands/hands_004.png": { "sizeX": 600, @@ -2895,7 +2935,27 @@ "talking": "ignore", "hotkeys": [], "rotation": 0, - "use_css": false + "use_css": false, + "controller": [ + "controller_buttons", + "controller_wheel" + ], + "originX": 0, + "originY": 500, + "deg": -10, + "deadzone": 0.055, + "player": 1, + "buttons": 0, + "mode": "move", + "posBothX": 0, + "posBothY": 20, + "rotationBoth": 0, + "posLeftX": 35, + "posLeftY": 20, + "rotationLeft": 5, + "posRightX": -35, + "posRightY": 20, + "rotationRight": -5 }, "Assets/hands/hands_003.png": { "sizeX": 600, @@ -2909,7 +2969,27 @@ "talking": "ignore", "hotkeys": [], "rotation": 0, - "use_css": false + "use_css": false, + "controller": [ + "controller_buttons", + "controller_wheel" + ], + "originX": 0, + "originY": 500, + "deg": -10, + "deadzone": 0.055, + "player": 1, + "buttons": 0, + "mode": "move", + "posBothX": 0, + "posBothY": 20, + "rotationBoth": 0, + "posLeftX": 35, + "posLeftY": 20, + "rotationLeft": 5, + "posRightX": -35, + "posRightY": 20, + "rotationRight": -5 }, "Assets/hands/hands_005.png": { "sizeX": 600, @@ -2923,7 +3003,27 @@ "talking": "ignore", "hotkeys": [], "rotation": 0, - "use_css": false + "use_css": false, + "controller": [ + "controller_buttons", + "controller_wheel" + ], + "originX": 0, + "originY": 500, + "deg": -10, + "deadzone": 0.055, + "player": 1, + "buttons": 0, + "mode": "move", + "posBothX": 0, + "posBothY": 20, + "rotationBoth": 0, + "posLeftX": 35, + "posLeftY": 20, + "rotationLeft": 5, + "posRightX": -35, + "posRightY": 20, + "rotationRight": -5 }, "Assets/hands/hands_006.png": { "sizeX": 600, @@ -2937,7 +3037,27 @@ "talking": "ignore", "hotkeys": [], "rotation": 0, - "use_css": false + "use_css": false, + "controller": [ + "controller_buttons", + "controller_wheel" + ], + "originX": 0, + "originY": 500, + "deg": -10, + "deadzone": 0.055, + "player": 1, + "buttons": 0, + "mode": "move", + "posBothX": 0, + "posBothY": 20, + "rotationBoth": 0, + "posLeftX": 35, + "posLeftY": 20, + "rotationLeft": 5, + "posRightX": -35, + "posRightY": 20, + "rotationRight": -5 }, "Assets/hands/hands_008.png": { "sizeX": 600, @@ -2951,7 +3071,27 @@ "talking": "ignore", "hotkeys": [], "rotation": 0, - "use_css": false + "use_css": false, + "controller": [ + "controller_buttons", + "controller_wheel" + ], + "originX": 0, + "originY": 500, + "deg": -10, + "deadzone": 0.055, + "player": 1, + "buttons": 0, + "mode": "move", + "posBothX": 0, + "posBothY": 20, + "rotationBoth": 0, + "posLeftX": 35, + "posLeftY": 20, + "rotationLeft": 5, + "posRightX": -35, + "posRightY": 20, + "rotationRight": -5 }, "Assets/hands/hands_007.png": { "sizeX": 600, @@ -2965,7 +3105,27 @@ "talking": "ignore", "hotkeys": [], "rotation": 0, - "use_css": false + "use_css": false, + "controller": [ + "controller_buttons", + "controller_wheel" + ], + "originX": 0, + "originY": 500, + "deg": -10, + "deadzone": 0.055, + "player": 1, + "buttons": 0, + "mode": "move", + "posBothX": 0, + "posBothY": 20, + "rotationBoth": 0, + "posLeftX": 35, + "posLeftY": 20, + "rotationLeft": 5, + "posRightX": -35, + "posRightY": 20, + "rotationRight": -5 }, "Assets/hands/hands_009.png": { "sizeX": 600, @@ -2979,7 +3139,27 @@ "talking": "ignore", "hotkeys": [], "rotation": 0, - "use_css": false + "use_css": false, + "controller": [ + "controller_buttons", + "controller_wheel" + ], + "originX": 0, + "originY": 500, + "deg": -10, + "deadzone": 0.055, + "player": 1, + "buttons": 0, + "mode": "move", + "posBothX": 0, + "posBothY": 20, + "rotationBoth": 0, + "posLeftX": 35, + "posLeftY": 20, + "rotationLeft": 5, + "posRightX": -35, + "posRightY": 20, + "rotationRight": -5 }, "Assets/hands/hands_010.png": { "sizeX": 600, @@ -2993,7 +3173,27 @@ "talking": "ignore", "hotkeys": [], "rotation": 0, - "use_css": false + "use_css": false, + "controller": [ + "controller_buttons", + "controller_wheel" + ], + "originX": 0, + "originY": 500, + "deg": -10, + "deadzone": 0.055, + "player": 1, + "buttons": 0, + "mode": "move", + "posBothX": 0, + "posBothY": 20, + "rotationBoth": 0, + "posLeftX": 35, + "posLeftY": 20, + "rotationLeft": 5, + "posRightX": -35, + "posRightY": 20, + "rotationRight": -5 }, "Assets/hands/hands_012.png": { "sizeX": 600, @@ -3007,7 +3207,27 @@ "talking": "ignore", "hotkeys": [], "rotation": 0, - "use_css": false + "use_css": false, + "controller": [ + "controller_buttons", + "controller_wheel" + ], + "originX": 0, + "originY": 500, + "deg": -10, + "deadzone": 0.055, + "player": 1, + "buttons": 0, + "mode": "move", + "posBothX": 0, + "posBothY": 20, + "rotationBoth": 0, + "posLeftX": 35, + "posLeftY": 20, + "rotationLeft": 5, + "posRightX": -35, + "posRightY": 20, + "rotationRight": -5 }, "Assets/hands/hands_011.png": { "sizeX": 600, @@ -3021,7 +3241,27 @@ "talking": "ignore", "hotkeys": [], "rotation": 0, - "use_css": false + "use_css": false, + "controller": [ + "controller_buttons", + "controller_wheel" + ], + "originX": 0, + "originY": 500, + "deg": -10, + "deadzone": 0.055, + "player": 1, + "buttons": 0, + "mode": "move", + "posBothX": 0, + "posBothY": 20, + "rotationBoth": 0, + "posLeftX": 35, + "posLeftY": 20, + "rotationLeft": 5, + "posRightX": -35, + "posRightY": 20, + "rotationRight": -5 }, "Assets/hands/hands_014.png": { "sizeX": 600, @@ -3035,7 +3275,27 @@ "talking": "ignore", "hotkeys": [], "rotation": 0, - "use_css": false + "use_css": false, + "controller": [ + "controller_buttons", + "controller_wheel" + ], + "originX": 0, + "originY": 500, + "deg": -10, + "deadzone": 0.055, + "player": 1, + "buttons": 0, + "mode": "move", + "posBothX": 0, + "posBothY": 20, + "rotationBoth": 0, + "posLeftX": 35, + "posLeftY": 20, + "rotationLeft": 5, + "posRightX": -35, + "posRightY": 20, + "rotationRight": -5 }, "Assets/hands/hands_013.png": { "sizeX": 600, @@ -3049,7 +3309,27 @@ "talking": "ignore", "hotkeys": [], "rotation": 0, - "use_css": false + "use_css": false, + "controller": [ + "controller_buttons", + "controller_wheel" + ], + "originX": 0, + "originY": 500, + "deg": -10, + "deadzone": 0.055, + "player": 1, + "buttons": 0, + "mode": "move", + "posBothX": 0, + "posBothY": 20, + "rotationBoth": 0, + "posLeftX": 35, + "posLeftY": 20, + "rotationLeft": 5, + "posRightX": -35, + "posRightY": 20, + "rotationRight": -5 }, "Assets/hands/hands_015.png": { "sizeX": 600, @@ -3063,7 +3343,27 @@ "talking": "ignore", "hotkeys": [], "rotation": 0, - "use_css": false + "use_css": false, + "controller": [ + "controller_buttons", + "controller_wheel" + ], + "originX": 0, + "originY": 500, + "deg": -10, + "deadzone": 0.055, + "player": 1, + "buttons": 0, + "mode": "move", + "posBothX": 0, + "posBothY": 20, + "rotationBoth": 0, + "posLeftX": 35, + "posLeftY": 20, + "rotationLeft": 5, + "posRightX": -35, + "posRightY": 20, + "rotationRight": -5 }, "Assets/hands/hands_016.png": { "sizeX": 600, @@ -3077,7 +3377,27 @@ "talking": "ignore", "hotkeys": [], "rotation": 0, - "use_css": false + "use_css": false, + "controller": [ + "controller_buttons", + "controller_wheel" + ], + "originX": 0, + "originY": 500, + "deg": -10, + "deadzone": 0.055, + "player": 1, + "buttons": 0, + "mode": "move", + "posBothX": 0, + "posBothY": 20, + "rotationBoth": 0, + "posLeftX": 35, + "posLeftY": 20, + "rotationLeft": 5, + "posRightX": -35, + "posRightY": 20, + "rotationRight": -5 }, "Assets/hands/hands_018.png": { "sizeX": 600, @@ -3105,7 +3425,27 @@ "talking": "ignore", "hotkeys": [], "rotation": 0, - "use_css": false + "use_css": false, + "controller": [ + "controller_buttons", + "controller_wheel" + ], + "originX": 0, + "originY": 500, + "deg": -10, + "deadzone": 0.055, + "player": 1, + "buttons": 0, + "mode": "move", + "posBothX": 0, + "posBothY": 20, + "rotationBoth": 0, + "posLeftX": 35, + "posLeftY": 20, + "rotationLeft": 5, + "posRightX": -35, + "posRightY": 20, + "rotationRight": -5 }, "Assets/hands/hands_019.png": { "sizeX": 600, @@ -52401,5 +52741,134 @@ "hotkeys": [], "animation": [], "rotation": 0 + }, + "Assets/hands/hands.png": { + "sizeX": 300, + "sizeY": 300, + "posX": 0, + "posY": 290, + "posZ": 40, + "blinking": "ignore", + "talking": "ignore", + "css": "", + "use_css": false, + "hotkeys": [], + "animation": [], + "rotation": 0, + "controller": [ + "controller_wheel" + ], + "originX": 0, + "originY": 290, + "deg": -70, + "deadzone": 0.055, + "player": 1, + "buttons": 0, + "mode": "display", + "posBothX": 0, + "posBothY": 0, + "rotationBoth": 0, + "posLeftX": 0, + "posLeftY": 0, + "rotationLeft": 0, + "posRightX": 0, + "posRightY": 0, + "rotationRight": 0 + }, + "Assets/hands/down.png": { + "sizeX": 600, + "sizeY": 600, + "posX": 0, + "posY": 0, + "posZ": 40, + "blinking": "ignore", + "talking": "ignore", + "css": "", + "use_css": false, + "hotkeys": [], + "animation": [], + "rotation": 0, + "controller": [ + "controller_buttons", + "controller_wheel" + ], + "originX": 50, + "originY": -120, + "deg": -15, + "deadzone": 0.055, + "player": 1, + "buttons": 3 + }, + "Assets/hands/idle.png": { + "sizeX": 600, + "sizeY": 600, + "posX": 0, + "posY": 0, + "posZ": 40, + "blinking": "ignore", + "talking": "ignore", + "css": "", + "use_css": false, + "hotkeys": [], + "animation": [], + "rotation": 0, + "controller": [ + "controller_buttons", + "controller_wheel" + ], + "originX": 50, + "originY": -120, + "deg": -15, + "deadzone": 0.055, + "player": 1, + "buttons": 0 + }, + "Assets/hands/left.png": { + "sizeX": 600, + "sizeY": 600, + "posX": 0, + "posY": 0, + "posZ": 40, + "blinking": "ignore", + "talking": "ignore", + "css": "", + "use_css": false, + "hotkeys": [], + "animation": [], + "rotation": 0, + "controller": [ + "controller_buttons", + "controller_wheel" + ], + "originX": 50, + "originY": -120, + "deg": -15, + "deadzone": 0.055, + "player": 1, + "buttons": 1 + }, + "Assets/hands/right.png": { + "sizeX": 600, + "sizeY": 600, + "posX": 0, + "posY": 0, + "posZ": 40, + "blinking": "ignore", + "talking": "ignore", + "css": "", + "use_css": false, + "hotkeys": [], + "animation": [], + "rotation": 0, + "controller": [ + "controller_buttons", + "controller_wheel" + ], + "originX": 50, + "originY": -120, + "deg": -15, + "deadzone": 0.055, + "player": 1, + "buttons": 2 } } \ No newline at end of file diff --git a/Data/settings.json b/Data/settings.json index 4f0d82fe..ebcf0682 100644 --- a/Data/settings.json +++ b/Data/settings.json @@ -1,9 +1,9 @@ { - "volume threshold": 7, + "volume threshold": 17, "scream threshold": 93, - "delay threshold": 2, + "delay threshold": 12, "microphone selection": 11, - "microphone mute": false, + "microphone mute": true, "background color": 0, "export mode": 0, "hide UI": true, diff --git a/Models/Avatars/Default/model.json b/Models/Avatars/Default/model.json index a8cbc25b..786d1284 100644 --- a/Models/Avatars/Default/model.json +++ b/Models/Avatars/Default/model.json @@ -1,6 +1,6 @@ [ { - "route": "Assets/hands/hands_118.png", + "route": "Assets/hands/hands_017.png", "sizeX": 600, "sizeY": 600, "posX": 0, @@ -12,7 +12,27 @@ "talking": "ignore", "hotkeys": [], "rotation": 0, - "use_css": false + "use_css": false, + "controller": [ + "controller_buttons", + "controller_wheel" + ], + "originX": 0, + "originY": 500, + "deg": -10, + "deadzone": 0.055, + "player": 1, + "buttons": 0, + "mode": "move", + "posBothX": 0, + "posBothY": 20, + "rotationBoth": 0, + "posLeftX": 35, + "posLeftY": 20, + "rotationLeft": 5, + "posRightX": -35, + "posRightY": 20, + "rotationRight": -5 }, { "route": "Assets/hairbows/hairbows_360.png", diff --git a/Models/Avatars/Default/thumb.png b/Models/Avatars/Default/thumb.png index a9cb63d8404f91231f2cbc3cea033edbe208a862..03da29ba40931a99c6e9c33dac87574b745c23ad 100644 GIT binary patch literal 8139 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 M$`$qNCNEg=ZxjqX0ssI2 literal 8139 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 diff --git a/UI/settingsWidget.ui b/UI/settingsWidget.ui index b069265b..8842eecb 100644 --- a/UI/settingsWidget.ui +++ b/UI/settingsWidget.ui @@ -6,8 +6,8 @@ 0 0 - 323 - 543 + 330 + 1044 @@ -119,32 +119,6 @@ QFrame{ QFrame::Raised - - - - - 0 - 0 - - - - H: - - - - - - - - 0 - 0 - - - - X: - - - @@ -173,8 +147,8 @@ QFrame{ - - + + 0 @@ -182,7 +156,7 @@ QFrame{ - Z: + W: @@ -208,17 +182,27 @@ QFrame{ - - + + - + 0 0 + + Z: + + + + + Qt::ClickFocus + + false + Qt::AlignCenter @@ -236,19 +220,22 @@ QFrame{ - - + + + + + 0 + 0 + + Qt::ClickFocus - - false - Qt::AlignCenter - px + -9999 @@ -257,12 +244,35 @@ QFrame{ 9999 - 5 + 1 - - + + + + PointingHandCursor + + + Qt::LeftToRight + + + background-color: rgba(255, 255, 255, 0); + +QCheckBox::indicator:unchecked { + background-color : cyan; +} + + + Lock Aspect Ratio + + + true + + + + + 0 @@ -270,7 +280,7 @@ QFrame{ - R: + H: @@ -285,6 +295,9 @@ QFrame{ Qt::ClickFocus + + Rotation + Qt::AlignCenter @@ -302,8 +315,8 @@ QFrame{ - - + + 0 @@ -311,12 +324,12 @@ QFrame{ - Y: + R: - - + + 0 @@ -330,7 +343,7 @@ QFrame{ Qt::AlignCenter - + px -9999 @@ -339,12 +352,12 @@ QFrame{ 9999 - 1 + 5 - - + + 0 @@ -352,30 +365,20 @@ QFrame{ - W: + Y: - - - - PointingHandCursor - - - Qt::LeftToRight - - - background-color: rgba(255, 255, 255, 0); - -QCheckBox::indicator:unchecked { - background-color : cyan; -} + + + + + 0 + 0 + - Lock Aspect Ratio - - - true + X: @@ -589,6 +592,989 @@ QCheckBox::indicator:unchecked { + + + + PointingHandCursor + + + Controller + + + false + + + true + + + false + + + + 0 + + + 0 + + + 23 + + + 0 + + + 0 + + + + + QLabel{ + background-color: transparent; +} + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + 0 + + + + + + 0 + 0 + + + + PointingHandCursor + + + background-color: rgba(255, 255, 255, 0); + + + Buttons + + + false + + + + + + + + 0 + 0 + + + + Qt::ClickFocus + + + Qt::AlignCenter + + + + + + Player + + + 1 + + + 12 + + + 1 + + + 1 + + + + + + + + + #frame_8 { + background-color: rgba(0, 0, 0, 40); + border-top-left-radius: 9px; +} + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 6 + + + 6 + + + + + 0 + + + + + + 0 + 0 + + + + PointingHandCursor + + + background-color: rgba(255, 255, 255, 0); + + + Display + + + true + + + + + + + + 0 + 0 + + + + PointingHandCursor + + + background-color: rgba(255, 255, 255, 0); + + + Move + + + + + + + + + #frame_10 { + background-color: rgba(0, 0, 0, 40); + border-top-left-radius: 9px; +} + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + 0 + 0 + + + + Show when + + + + + + + QComboBox::AdjustToMinimumContentsLengthWithIcon + + + true + + + + no button is pressed + + + + + a left button is pressed + + + + + a right button is pressed + + + + + both sides have a button pressed + + + + + + + + + + + QTabBar{ + background-color: rgba(255, 255, 255, 0); +} +QTabBar::tab { + background-color: rgba(255, 255, 255, 40); + background-color: rgb(0, 157, 235); + min-width: 50px; + min-height:22px; + padding: 0px 2px; + color: white; + border-radius: 10px; + margin-left:2px; + margin-right:2px; +} +QTabBar::tab:selected { + color: white; + background-color: black;; +} +QTabBar::tab:hover { + color: black; + background-color: rgba(255, 0, 0, 100); +} + + + 0 + + + true + + + + Left + + + When a button on the left side of the controller is pressed + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + 0 + 0 + + + + Y: + + + + + + + + 0 + 0 + + + + X: + + + + + + + + 0 + 0 + + + + Qt::ClickFocus + + + Qt::AlignCenter + + + px + + + -9999 + + + 9999 + + + 5 + + + + + + + + 0 + 0 + + + + R: + + + + + + + + 0 + 0 + + + + Qt::ClickFocus + + + Qt::AlignCenter + + + px + + + -9999 + + + 9999 + + + 5 + + + + + + + + 0 + 0 + + + + Qt::ClickFocus + + + Rotation + + + Qt::AlignCenter + + + px + + + -360 + + + 360 + + + 5 + + + + + + + + + + + Right + + + When a button on the right side of the controller is pressed + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + 0 + 0 + + + + X: + + + + + + + + 0 + 0 + + + + Y: + + + + + + + + 0 + 0 + + + + Qt::ClickFocus + + + Rotation + + + Qt::AlignCenter + + + px + + + -360 + + + 360 + + + 5 + + + + + + + + 0 + 0 + + + + Qt::ClickFocus + + + Qt::AlignCenter + + + px + + + -9999 + + + 9999 + + + 5 + + + + + + + + 0 + 0 + + + + Qt::ClickFocus + + + Qt::AlignCenter + + + px + + + -9999 + + + 9999 + + + 5 + + + + + + + + 0 + 0 + + + + R: + + + + + + + + + + + Both + + + When buttons on both sides of the controller are pressed + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + 0 + 0 + + + + Qt::ClickFocus + + + Qt::AlignCenter + + + px + + + -9999 + + + 9999 + + + 5 + + + + + + + + 0 + 0 + + + + R: + + + + + + + + 0 + 0 + + + + Qt::ClickFocus + + + Rotation + + + Qt::AlignCenter + + + px + + + -360 + + + 360 + + + 5 + + + + + + + + 0 + 0 + + + + X: + + + + + + + + 0 + 0 + + + + Qt::ClickFocus + + + Qt::AlignCenter + + + px + + + -9999 + + + 9999 + + + 5 + + + + + + + + 0 + 0 + + + + Y: + + + + + + + + + + + + + + + + + + 0 + 0 + + + + PointingHandCursor + + + background-color: rgba(255, 255, 255, 0); + + + Wheel/Stick + + + false + + + + + + + #frame_7 { + background-color: rgba(0, 0, 0, 40); + border-top-left-radius: 9px; +} + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + 0 + 0 + + + + Qt::ClickFocus + + + Qt::AlignCenter + + + px + + + -9999 + + + 9999 + + + 5 + + + 50 + + + + + + + + 0 + 0 + + + + Y: + + + + + + + + 0 + 0 + + + + X: + + + + + + + + 0 + 0 + + + + Qt::ClickFocus + + + Qt::AlignCenter + + + px + + + -9999 + + + 9999 + + + 5 + + + 50 + + + + + + + + 0 + 0 + + + + Rotation origin: + + + + + + + + 0 + 0 + + + + Deadzone: + + + + + + + Qt::AlignCenter + + + 4 + + + 1.000000000000000 + + + 0.005000000000000 + + + 0.055000000000000 + + + + + + + + 0 + 0 + + + + Qt::ClickFocus + + + Qt::AlignCenter + + + deg + + + -360 + + + 360 + + + 5 + + + 90 + + + + + + + + 0 + 0 + + + + Rotation radius: + + + + + + + + + + + + diff --git a/Viewer/mouseControl.js b/Viewer/mouseControl.js deleted file mode 100644 index 6928e33f..00000000 --- a/Viewer/mouseControl.js +++ /dev/null @@ -1,72 +0,0 @@ -// Get the image container and the first image -const imageContainer = document.getElementById("image-wrapper"); -const moveContainer = document.getElementById("move-wrapper"); -const container = document.getElementById("container"); - -// Variables to track the mouse position and dragging state -let isDragging = false; -let initialMouseX; -let initialMouseY; -let initialImageX; -let initialImageY; - -// Variables to store the current offset due to mouse movement -let mouseMovementX = 0; -let mouseMovementY = 0; - -// Function to handle the mouse down event -function onMouseDown(event) { - isDragging = true; - initialMouseX = event.clientX; - initialMouseY = event.clientY; - // Initialize mouse movement offsets with the current position - mouseMovementX = 0; - mouseMovementY = 0; - - // Add "grabbing" cursor style - moveContainer.style.cursor = "grabbing"; -} - -// Function to handle the mouse move event -function onMouseMove(event) { - if (!isDragging) return; - - const deltaX = event.clientX - initialMouseX; - const deltaY = event.clientY - initialMouseY; - - // Apply the new position to each image separately while preserving their existing offset - const images = imageContainer.querySelectorAll("img"); - images.forEach((img) => { - const imgLeft = img.style.left; - const imgTop = img.style.top; - console.log(imgLeft + " " + imgTop) - const newLeft = `calc(${imgLeft} + ${deltaX}px)`; - const newTop = `calc(${imgTop} + ${deltaY}px)`; - img.style.left = `${newLeft}`; - img.style.top = `${newTop}`; - }); - - // Update the initial mouse position - initialMouseX = event.clientX; - initialMouseY = event.clientY; -} - -// Function to handle the mouse up event -function onMouseUp() { - isDragging = false; - // Restore the default cursor style - moveContainer.style.cursor = "grab"; -} - -// Function to prevent the default drag behavior -function preventDefaultDrag(event) { - event.preventDefault(); -} - -// Add event listeners for mouse events on the move-container -document.addEventListener("mousedown", onMouseDown); -document.addEventListener("mousemove", onMouseMove); -document.addEventListener("mouseup", onMouseUp); - -// Add an event listener to prevent default drag behavior on the move-container -moveContainer.addEventListener("dragstart", preventDefaultDrag); diff --git a/Viewer/script.js b/Viewer/script.js new file mode 100644 index 00000000..ef0b358b --- /dev/null +++ b/Viewer/script.js @@ -0,0 +1,188 @@ +// Get the image container and the first image +const imageContainer = document.getElementById("image-wrapper"); +const moveContainer = document.getElementById("move-wrapper"); +const container = document.getElementById("container"); + +const leftButtons = [4,6,8,10,12,13,14,15]; +const rightButtons = [0,1,2,3,5,7,9,11]; + +// Variables to track the mouse position and dragging state +let isDragging = false; +let initialMouseX; +let initialMouseY; +let initialImageX; +let initialImageY; + +// Variables to store the current offset due to mouse movement +let mouseMovementX = 0; +let mouseMovementY = 0; + +async function pool(){ + while(true){ + + // Wheel / stick control + + var controllerWheels = document.querySelectorAll(".controller_wheel"); + if(controllerWheels.length > 0) { + controllerWheels.forEach(function(controllerWheel) { + + let rawx = navigator.getGamepads()[controllerWheel.attributes.player.value].axes[0] + let x = 0 + if(rawx > controllerWheel.attributes.deadzone.value) + x = rawx-controllerWheel.attributes.deadzone.value/(1-controllerWheel.attributes.deadzone.value) + else if(rawx < -controllerWheel.attributes.deadzone.value) + x = rawx-controllerWheel.attributes.player.value/(1-controllerWheel.attributes.deadzone.value) + let rotation = x * controllerWheel.attributes.deg.value; + + var currentTransform = controllerWheel.style.transform; + var currentRotate = 0; + if(currentTransform && currentTransform.includes("rotate")) { + var rotateIndex = currentTransform.indexOf("rotate"); + var endIndex = currentTransform.indexOf("deg", rotateIndex); + currentRotate = parseFloat(currentTransform.substring(rotateIndex + 7, endIndex)); + } + controllerWheel.style.transform = currentTransform.replace(`rotate(${currentRotate}deg)`, `rotate(${rotation}deg)`); + }); + } + + // Button control + var controllerButtons = document.querySelectorAll(".controller_buttons"); + if(controllerButtons.length > 0) { + controllerButtons.forEach(function(controllerButton) { + let buttons = navigator.getGamepads()[controllerButton.attributes.player.value].buttons + let left = false + let right = false + + for(let i = 0; i < buttons.length; i++){ + if(buttons[i].pressed){ + if(!left && leftButtons.indexOf(i) !== -1){ + left = true + }else if(!right && rightButtons.indexOf(i) !== -1){ + right = true + } + } + } + + switch(true){ + case left && right: + if (controllerButton.attributes.mode.value == "display") { + if (controllerButton.attributes.buttons.value == 3){ + controllerButton.style.display = "block"; + } else { + controllerButton.style.display = "none"; + } + } else { + controllerButton.style.left = `calc(50% + ${controllerButton.attributes.posBothX.value}px)`; + controllerButton.style.top = `calc(50% + ${controllerButton.attributes.posBothY.value}px)`; + controllerButton.style.transform = `rotate(${controllerButton.attributes.rotationBoth.value}deg)`; + } + break; + case left: + if (controllerButton.attributes.mode.value == "display") { + if (controllerButton.attributes.buttons.value == 1){ + controllerButton.style.display = "block"; + } else { + controllerButton.style.display = "none"; + } + } else { + controllerButton.style.left = `calc(50% + ${controllerButton.attributes.posLeftX.value}px)`; + controllerButton.style.top = `calc(50% + ${controllerButton.attributes.posLeftY.value}px)`; + controllerButton.style.transform = `rotate(${controllerButton.attributes.rotationLeft.value}deg)`; + } + break; + case right: + if (controllerButton.attributes.mode.value == "display") { + if (controllerButton.attributes.buttons.value == 2){ + controllerButton.style.display = "block"; + } else { + controllerButton.style.display = "none"; + } + } else { + controllerButton.style.left = `calc(50% + ${controllerButton.attributes.posRightX.value}px)`; + controllerButton.style.top = `calc(50% + ${controllerButton.attributes.posRightY.value}px)`; + controllerButton.style.transform = `rotate(${controllerButton.attributes.rotationRight.value}deg)`; + } + break; + default: + if (controllerButton.attributes.mode.value == "display") { + if (controllerButton.attributes.buttons.value == 0){ + controllerButton.style.display = "block"; + } else { + controllerButton.style.display = "none"; + } + } else { + controllerButton.style.left = `calc(50% + 0px)`; + controllerButton.style.top = `calc(50% + 0px)`; + controllerButton.style.transform = `rotate(0deg)`; + } + break; + } + + }); + } + + await new Promise(r => setTimeout(r, 1000/60)); + } +} + +// Function to handle the mouse down event +function onMouseDown(event) { + isDragging = true; + initialMouseX = event.clientX; + initialMouseY = event.clientY; + // Initialize mouse movement offsets with the current position + mouseMovementX = 0; + mouseMovementY = 0; + + // Add "grabbing" cursor style + moveContainer.style.cursor = "grabbing"; +} + +// Function to handle the mouse move event +function onMouseMove(event) { + if (!isDragging) return; + + const deltaX = event.clientX - initialMouseX; + const deltaY = event.clientY - initialMouseY; + + // Apply the new position to each image separately while preserving their existing offset + const images = imageContainer.querySelectorAll("img"); + images.forEach((img) => { + const imgLeft = img.style.left; + const imgTop = img.style.top; + console.log(imgLeft + " " + imgTop) + const newLeft = `calc(${imgLeft} + ${deltaX}px)`; + const newTop = `calc(${imgTop} + ${deltaY}px)`; + img.style.left = `${newLeft}`; + img.style.top = `${newTop}`; + }); + + // Update the initial mouse position + initialMouseX = event.clientX; + initialMouseY = event.clientY; +} + +// Function to handle the mouse up event +function onMouseUp() { + isDragging = false; + // Restore the default cursor style + moveContainer.style.cursor = "grab"; +} + +// Function to prevent the default drag behavior +function preventDefaultDrag(event) { + event.preventDefault(); +} + +// Add event listeners for mouse events on the move-container +document.addEventListener("mousedown", onMouseDown); +document.addEventListener("mousemove", onMouseMove); +document.addEventListener("mouseup", onMouseUp); + +// Add an event listener to prevent default drag behavior on the move-container +moveContainer.addEventListener("dragstart", preventDefaultDrag); + +// Control the listening for gamepads +window.addEventListener("gamepadconnected", (e) => { + pool(); +}); diff --git a/Viewer/viewer.html b/Viewer/viewer.html index b6ef720b..e6bccbfe 100644 --- a/Viewer/viewer.html +++ b/Viewer/viewer.html @@ -11,7 +11,19 @@

- +
+ - +
+ - +
+ - +
+ - +
+ - +
+ - +
+ - +
+ - +
+ - +
+ - +
+ - +
+ - +
+ - +
+ - +
+ - +
+ - +
+ - +
+ - +
+ - +
+ - +
+ - +
+ - +
+ - +
+ - +
+ +
+
- - - diff --git a/main.py b/main.py index ac138d5c..926dcaf0 100644 --- a/main.py +++ b/main.py @@ -64,12 +64,12 @@ def __init__(self): self.settings_json_file = os.path.join(exe_dir, "Data", "settings.json") self.apiKeys = os.path.join(exe_dir, "Data", "keys.json") - self.js_file = os.path.join(exe_dir, "Viewer", "mouseControl.js") + self.js_file = os.path.join(exe_dir, "Viewer", "script.js") self.css_file = os.path.join(exe_dir, "Viewer", "styles.css") self.anim_file = os.path.join(exe_dir, "Viewer", "animations.css") self.html_file = os.path.join(exe_dir, "Viewer", "viewer.html") - self.js_file_default = os.path.join(exe_dir, "Viewer", "default", "mouseControl.js") + self.js_file_default = os.path.join(exe_dir, "Viewer", "default", "script.js") self.css_file_default = os.path.join(exe_dir, "Viewer", "default", "styles.css") self.anim_file_default = os.path.join(exe_dir, "Viewer", "default", "animations.css") self.html_file_default = os.path.join(exe_dir, "Viewer", "default", "viewer.html")