From 08f5dd0c2d4caccb7715e21e576ea6532ba34429 Mon Sep 17 00:00:00 2001 From: prayerie Date: Tue, 11 Nov 2025 19:16:57 +0000 Subject: [PATCH 1/2] add basic theme editor --- static/theme-editor/FT2FONT.otf | Bin 0 -> 6616 bytes static/theme-editor/LICENSE | 427 ++++ static/theme-editor/font_3x5.png | Bin 0 -> 256 bytes static/theme-editor/font_8x11.png | Bin 0 -> 4241 bytes static/theme-editor/haken.png | Bin 0 -> 281 bytes static/theme-editor/icon_copy.png | Bin 0 -> 296 bytes static/theme-editor/icon_cut.png | Bin 0 -> 298 bytes static/theme-editor/icon_disk.png | Bin 0 -> 302 bytes static/theme-editor/icon_flp.png | Bin 0 -> 202 bytes static/theme-editor/icon_new_folder.png | Bin 0 -> 4204 bytes static/theme-editor/icon_paste.png | Bin 0 -> 295 bytes static/theme-editor/icon_pause.png | Bin 0 -> 268 bytes static/theme-editor/icon_play.png | Bin 0 -> 283 bytes static/theme-editor/icon_record.png | Bin 0 -> 4353 bytes static/theme-editor/icon_redo.png | Bin 0 -> 552 bytes static/theme-editor/icon_sample.png | Bin 0 -> 296 bytes static/theme-editor/icon_song.png | Bin 0 -> 300 bytes static/theme-editor/icon_stop.png | Bin 0 -> 268 bytes static/theme-editor/icon_trumpet.png | Bin 0 -> 300 bytes static/theme-editor/icon_undo.png | Bin 0 -> 554 bytes static/theme-editor/icon_wrench.png | Bin 0 -> 302 bytes static/theme-editor/index.html | 434 ++++ static/theme-editor/logo.png | Bin 0 -> 805 bytes static/theme-editor/piano.png | Bin 0 -> 457 bytes static/theme-editor/sampleedit_all.png | Bin 0 -> 287 bytes static/theme-editor/sampleedit_chip_icon.png | Bin 0 -> 276 bytes .../theme-editor/sampleedit_control_icon.png | Bin 0 -> 277 bytes static/theme-editor/sampleedit_del.png | Bin 0 -> 289 bytes static/theme-editor/sampleedit_draw.png | Bin 0 -> 290 bytes static/theme-editor/sampleedit_draw_small.png | Bin 0 -> 286 bytes static/theme-editor/sampleedit_fadein.png | Bin 0 -> 288 bytes static/theme-editor/sampleedit_fadeout.png | Bin 0 -> 285 bytes static/theme-editor/sampleedit_loop_icon.png | Bin 0 -> 285 bytes static/theme-editor/sampleedit_none.png | Bin 0 -> 288 bytes static/theme-editor/sampleedit_normalize.png | Bin 0 -> 269 bytes static/theme-editor/sampleedit_record.png | Bin 0 -> 290 bytes static/theme-editor/sampleedit_reverse.png | Bin 0 -> 291 bytes static/theme-editor/sampleedit_trim.png | Bin 0 -> 4123 bytes static/theme-editor/sampleedit_wave_icon.png | Bin 0 -> 283 bytes static/theme-editor/tobkit.js | 1899 +++++++++++++++++ static/theme-editor/tobkit.js.min | 1 + 41 files changed, 2761 insertions(+) create mode 100644 static/theme-editor/FT2FONT.otf create mode 100644 static/theme-editor/LICENSE create mode 100644 static/theme-editor/font_3x5.png create mode 100644 static/theme-editor/font_8x11.png create mode 100644 static/theme-editor/haken.png create mode 100644 static/theme-editor/icon_copy.png create mode 100644 static/theme-editor/icon_cut.png create mode 100644 static/theme-editor/icon_disk.png create mode 100644 static/theme-editor/icon_flp.png create mode 100644 static/theme-editor/icon_new_folder.png create mode 100644 static/theme-editor/icon_paste.png create mode 100644 static/theme-editor/icon_pause.png create mode 100644 static/theme-editor/icon_play.png create mode 100644 static/theme-editor/icon_record.png create mode 100644 static/theme-editor/icon_redo.png create mode 100644 static/theme-editor/icon_sample.png create mode 100644 static/theme-editor/icon_song.png create mode 100644 static/theme-editor/icon_stop.png create mode 100644 static/theme-editor/icon_trumpet.png create mode 100644 static/theme-editor/icon_undo.png create mode 100644 static/theme-editor/icon_wrench.png create mode 100644 static/theme-editor/index.html create mode 100644 static/theme-editor/logo.png create mode 100644 static/theme-editor/piano.png create mode 100644 static/theme-editor/sampleedit_all.png create mode 100644 static/theme-editor/sampleedit_chip_icon.png create mode 100644 static/theme-editor/sampleedit_control_icon.png create mode 100644 static/theme-editor/sampleedit_del.png create mode 100644 static/theme-editor/sampleedit_draw.png create mode 100644 static/theme-editor/sampleedit_draw_small.png create mode 100644 static/theme-editor/sampleedit_fadein.png create mode 100644 static/theme-editor/sampleedit_fadeout.png create mode 100644 static/theme-editor/sampleedit_loop_icon.png create mode 100644 static/theme-editor/sampleedit_none.png create mode 100644 static/theme-editor/sampleedit_normalize.png create mode 100644 static/theme-editor/sampleedit_record.png create mode 100644 static/theme-editor/sampleedit_reverse.png create mode 100644 static/theme-editor/sampleedit_trim.png create mode 100644 static/theme-editor/sampleedit_wave_icon.png create mode 100644 static/theme-editor/tobkit.js create mode 100644 static/theme-editor/tobkit.js.min diff --git a/static/theme-editor/FT2FONT.otf b/static/theme-editor/FT2FONT.otf new file mode 100644 index 0000000000000000000000000000000000000000..e589b348bfa2569cb5c8d71128a095b568a0e363 GIT binary patch literal 6616 zcmd5>dvH|M8UN1i-FuUhxI|$AamDZy6(M)?Mo~}`(OR&D$&4MVgonhMl^9YBR%g%( zL{@pUYEhJjk0!pM)~Z!REBL6`W!mc4I-?k>gNP1V%RcUIw!iP3vq^|h@sG}QmwWGb z&iT&w_M(6t$ohvY2O5|VGvT#uw z?Bu0&xRnxC`19G8-OH~WaQ45c2x|L%a#`A79dPDgx`2FU5&JN+fv2!e)`7gFp3TdN zU|KcDI&=Ch0J__3Vh{; zhD_gNI-eF&3oU_VSJMJ&qBh{=Qmy)q2i;0HV09wRqzj17U)Zvw_38ypZKZB)ZSDBd z)*F^goQe5*YNSQj+6MMU0D2A02USWJ;Y;<6i`v>+8|Pj#zqRxt9{+zZHz*qy!R>`~ zt#Wz-mBDptnBThS>V?;qx)aJUI9b>;{Dd*=wY!n{00)+p9%F3LwC_1#=X;^M=dg|D!woOaGeHMXc3&%soJ8JkAYIrL+i zjqH1gcGA1_F&)a~uwIJZIEAhR!rN#E=Ksm_xsP&tavu`qw&!ln-I#06U7owd$VZFC zuD+kiBn-=cu+6coy$;^Tq?N{&Ba;GodpAwy3bc2fA{;dDyrh>@d4 zj~RRFxYJHQWBi#DCYHI8@`}o;>YCa~XPr%xoujWSO;e`gaUPRXh{@iMn(Q6^?cR(bFHFv+WTQyV@g?W_lOZcs?2i>&!zEem<4%didWd4DJrN08 z2g1&rK-fQGKo}7TTV=TnU;CtQsBi3o<|QpnuDVyK zd!@Qpse6sO*Q&d#ncRpTX$H4ik2Fg}vqUsYM9Yh4&WM&(UZysbYtHg=J<>YMwXkw6 ztil+jg;i)_6W4~sp)GSq+rAo6@X_hLjs7foU){3gNE!EnVYRyuu zS!y&(jb^FQEHwrlt)W(HsMQ*3wGp+N#Vyl3Zkc9s%QTl;rrF#w!{-{lJjkx$a}A$s z_#%eSAnh8cU4yl2z;+GVZn@E0UctTo$cI~>%*W|<_=pQf;C;uBGuB29H&G!;yyq1o zn}aj}o#%Ku0eL-$Lg;HlaJHXF!{{XRzLN>y#452G`Mp;B zQv6EXDee+?i(ez#?-BQk_2NEpzt|u)BKJ3o2gHNoA@Q*Ijp#rnJR%+ykBP^{6XHqn z6zXED_^o(a{7yV0elMOyl{_#0AYKqJif!U0u^lz@iuj{=RqPNu#cSeqRM4B^PvR|V z=VHc723)G6)i5w83PiQI4g%j6?}#q3Uwr8s?wjPh&G%Q|=l)^-nf^Ba7XM!VSN@z; zWnF45x8ATm50nI^2Id9s4m=b1Fp#xRvd^+x?OW`J>}~cZPN6f=sdHMLHO?c>hXtZw zM#18OhYMaTNEenAh6`5~dUCA1Sl%RWmbc1fa=Ba~+vRO?rHskj98AekKpd&*ee+rTj|%EA0Iu=v^1g z)}|h}ysAVT{je(F?MiOLp2%UP8^ClK^5LwmF`&520D#W(IGql3LT#ypDH!9&St zIIuF5a5GWQwKG`6v=>Rld4qW>DjDS&2U8I*?nM+EKNXdULJ}(~mC0y#U8q!c?;Sis z1`j3T>AfK((Dhs|Zl~+4kurgOJPG-BRwmpKo99K6Y^2fMV*%`N*ly@^vy!)Xn8Lp+)fy#(8Nmbuu_?x8O{Fl$RmsGr+PDr;UX*3K;PKnhl9~*xngR#JlSNr58`vg}Uq5Y~`n$u47FZ&$*F}ZBSmOc|D%) z%DWE`JDlKj$m8va2*aPp$UGI)PR5Ht3?sr&0T*>=F+8K@;TY3U#o`zVV@R@Dp<$w? z4LX7(##u?tG&AN2HkxxND^n77#Q`>Fsuxc-J4exxi6-K3-tDf-N+%_mIpNv>Y8N(# zM$2ztq)p>(3_OPbv1ib14I1nB+!Qvl^B&{F3RD)c8PkOf#nu95D$12%@N|e3C#n4}{4^2zl~(({-yUK0T85oBjk>71?M6hRS6i^iO7&> zXS21)@xYppw`*A}+ldMdw5J^9D1?mLNg)l z!Lv``Q<4LpKs>c$I`~JH#YLo2#>qa>6By)&F%n*z0IN2slZlg>@l{cc=!hU@oVcut zVP*fjyYvjB!>Og8=ncwO_`nID>h$2R2Ou1ri~vD*0j)w6syUfdxyAW>VyHP5xF_Ov z9$Y0a-DTvd)&#lew2<5HAj|Jn5|l3-LkMIGwQ#U-sMQ#ipoiQV6pGyXOg`qVN1A#- z;6}9SWHTCeyzj}vRj%dhC(b40oNjum;p8FXdSyrW%;7TBFAEBiyg~h*cvDe!_M2vd zA+%6OO(F}q$?}N^{BeSMI0cpbBepVC#;UKQz&MAv%W4PgTNCeiXDq`h#3w%(`Q!sG zd`9)BQ!>Cyyuev+2fs*lBE&b! zp|7~td&Q}GRQ=6GJ!-M@v{-)k%>F&t`^nY@y&nY8B6_ES(}T!jH3rpyVMEV%I!1?> zA+s4zbvuNYAC#E-w;4xY@C&SG3e|p|#3x)pgTmHLp`UT%NpvNK$87u@F!ibhx#GfD zvBY2g1IZSm@VtwEH0LJ_I?|}9e=u~wP2f4r^1(d(X&1qBeC;9*h1#UX4(9nqBR}u( z52yI!gz(py{!Pe-r-h53=EorX4u4RM`rZ7S!0;Y^xWX^?*1q1$*Md3xzND@#c;ZrX zcrw4@orWi0Q_M3zo|en@%wvuD^YXyEfn}=oOU<*UcYohCWtZU000IE00000Vd2UG00001b5ch_0Itp) z=>Px#x=BPqR49?nl2HysAqWGf@BVk5{Q&l%*#j)bs6bjj9TD-a6afl|EgLmtLMnQ_yjuCR$x~Vx16C z4aVeUxwnyhru))!Z$kuc)JYtgM<80NGc8>^#~Yy@5u_C;Wj6{Fw|3AwC{8mQJlM+p z*J4)pJWqV~Kd_lQCZ2bSVr(BR)7#@DcVXs~(q@W`og*%{T`vT>SxVb6T`!Z z6JmVm@rTU<_1c=_DsIXxYThMDTkf(lCl*E2t&bQ^99Q2a-_=IwsvNNLWxIDSdiDx$ZU^-sds9*_P|UxrEWD0B4DX<_a@bIu1+sb z_FS^P2bvto;}0hnt^)kunk2)}XlRLkTkz-jP5e##xgyTz&oEMkVCT4*_%65{7$(ib z6#zCH06=O608D|GQo+R%;Q-)m2mp`|0)TpSVdFY$Frnb?;zjv3Hv@)qb8|i5xiae% z*nxyPQypQ-3NGVdM>d+~9}56-qml}-uOxvZ00<%7m4X;RNUJVIRhi3t06Et-d-(}H z7@IKB0)99riiHs-M6)pSPlV+krJeyh(K-qQ19S4YUW*Ol()l3#lt_wdxI%eDPZ-kcaUq5)m zqwNA29&=#o$jGNZd(UWnDwqzvG>6%27CHrM;$yI9Z$4`UzuvxdM>{WCOY>e=UN=rD zlbU*ABs5+-u5T8lbn)IQO5e2QsFcDvYgTW8j>FRGj%9KgHS96!fJL60p02@5@BQC$ z$=@QL)~i?O2kdKnY*t{rW?!AY^H6q^RS5FPh_Om z6FPEk%iXHyUE8MPB3%s{MMINrlW@S3m+QQ;@la)gYtN@hW7Q-5{>!qzENu3@SAEI@ zPO7`5=kestMJD9JOydlDSgrHb?UO4fr#O%5V3v(=GJa!~YLIkeakOAOv%kuA?ye!_ zN)n6}#3W@}2e}Oo84SLA{o*Xw0YYAIc678xJ9zmjMfs}=%`L|k-RUE1S2#C&>ZkhT z9u3iehHNX`xyr$+hK|3&M;mR@x1`+WZu1(`G3? zUP5)1g5akeOpkevlmb2u!yMG=nT!V1{_$rpt&wsVfEVVe4!wlkO^<2UuOQ#M0}E|{ z%?|E+D4eosY}n5qI{w1(lwg{kbuCCfK#3|Jy*$FH`N}WtshW<@`Lwd|vJG{^ z75FT%bhvHR_;|`VbuusZvfS*7Yg6ROQoj`z03dyn7!5(e z@JB2U_Ms3MAlYU%gH;0}HIGRJW6dA&b}%*qF%qr>hlfA`MX=okRst9!!L|sjoUHHT z*MPAYtTOW-G#E*kKU*r@)g41H#p6uzmLMNTz>#qlWSkiWZ$T!Skx5n{8glIWY!aTN zfck&vl??S$yF|-R?Iz%L*bj~1UI|G5C06^3b_n#lMjVKT{)i7sN#^*eckapD3qZ+f z4SfwbkwiLpn(GD}02yg%gtU|l0)dc~m620GDk{j!D=bz~U5M1u&|adYfktDnriK{Z zWqN3|k%jRx9G*lXX&YMESQ4yFi6nw#5Qwa-tb)7(N>LF-&_U}E{?BFZDxfR_It341 z0ICduDMRMOfHtU83Nl~5TLJq}7+gvkAtNg%4+83xBzFo1g~Ozz;BYXT4CVp2vXqJr z-cDL|9Rr~ogCuOtKQ5zZUwuu@qhl0H3>Bow$}LhyE!NOCFf=kYA(@$5SXz-C94Tw4 zG`f?gm$#3vpZ|Jh7%M!2&Dj_$6vb_dPuQHEk-05v`;P40d-m?zf8gMu!^I^hO3O}` zSDdP;Jy&b#KD1+2Y6TUTn?xV|^M++5RZShMPtwE!)v! z6y((#uDsb9z4FL1+Ld#xMvwUb)ynLM5xh+@!WOsAR&)K%y2Qxhw>y;Up*`Q4L!Was)s_V2^J?*KHCV= zwMFcv#&Ontx-nAameHZk_Z_$h&1kWj^-NBCoy|A>FPG`!JC)VDOz$Oa&qBv_@4TLE z1Zb;V3e??AtR$Yuip@$hZ|$yaoC7wczuWW9A<1bha!vk`0GUJAbJ(d?*uuVqR_sJk z!aE8QBGr;N<0djZw5q(_@KzSCCBH7rHn#rE(-VWUl^!*A)Lw1NOC>K7XK$ zukVBeuNr#utorS3I_NTT4A$)9v#qPs?=UJiC0JQW>9Sv5dT!p{1yrlAmp_}Wvko|; z7pPrdJ6q~)Fu|m%NaczNDD+Gg;$iAq8XV~^{W|MZ(CRER?uO5@$t9@Z>oo9pj_m%x z)orKLYF1xburjn(vn548+1l@j^DK%?L)xKq_MSF|n{F;Hx>Pt=(MkclADxXz_f~aW zhuz&FUvr}*=CITRu_bwUvK@8Y+PjLfqCo2f-RkROtYW&(uH3Dko$*+q4SuIlaVjQg zix=&%(T6U5)3Dk5r4;vkm|F-n8Xr=QzW@LF__W{+52?W%5Z&cyntCkdMY0UU7?1c3L+I^?@{?G3^ ztF~f`%Ce1tHgHn8A9eNIQ~JhbmEbEtUr6y2hB1UJGE=|;oB17NInH7^&fE)cMJ5o) zB(tSBa8JQy+8c)cjlkuHal#Y+MzAE~z=QCeU}&L?G$%X%!_T_|uSql=WmE-t# zGoJi#;U1-C+hd+F`AQ}ARhf2yaS&bEnvmQa`-&J z{3|Qk_kY3t)dkTie)|Ftr}dlh=5gQc5X{WCOHWCDW*Gej=;ThJ(s@FbfXQa?B3Ntq z0xm-c5OJhRYC9X`toUy^KW{CGNXT~WEeEM4zoELb`9eOIB@}R&^Rt4cg$&`mYZbL@ z4UmQT4eR?eBzc2}t@abmW$;Ad45m;dUeyFkUNC9V-ADTyViR>?)FK#IZ0z{o(?z+BhBEX2^#%E-vd#8TV9z{5;D(iiX_$l+3hBbPa}9rWOzln?hZiff^V*UHx3vIVCg!0Nb%7 literal 0 HcmV?d00001 diff --git a/static/theme-editor/icon_copy.png b/static/theme-editor/icon_copy.png new file mode 100644 index 0000000000000000000000000000000000000000..1c489e96e3280b9ee8263bf4ca69ea657ab27a94 GIT binary patch literal 296 zcmeAS@N?(olHy`uVBq!ia0vp^0wBx?BpA#)4xIr~Ea{HEjtmSN`?>!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD8ZEE?e4C9Np!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD8ZEE?e42OC7#SED=o*;o z8kmI`T3VSHS(zAU8yHv_7}%db)P|xVH$NpatrE8eze!bAKn)C@u6{1-oD!M<@!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD8ZEE?e42OC7#SED z=o*;o8kmI`T3VSHS(zAU8yHv_7}%db)P|xVH$NpatrE8eze!bAKn)C@u6{1-oD!M< Db*NV0 literal 0 HcmV?d00001 diff --git a/static/theme-editor/icon_flp.png b/static/theme-editor/icon_flp.png new file mode 100644 index 0000000000000000000000000000000000000000..78f49e109ea43567e7da4de9d7c806f1a612d673 GIT binary patch literal 202 zcmeAS@N?(olHy`uVBq!ia0vp^{2k44ofvPP)Tsw@SkfJR9T^xl z_H+M9WCijSl0AZa85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP{PC0 z#W95AdThU=7=t2*ll{JT^{Hur8NJ$$tWzqp7`Z+in|muJ8Ez t)OYQj?A>8aa|EWQ)cs+0x3{eSUn??$Pv=tbEGD3t44$rjF6*2UngIT$Jw^Zk literal 0 HcmV?d00001 diff --git a/static/theme-editor/icon_new_folder.png b/static/theme-editor/icon_new_folder.png new file mode 100644 index 0000000000000000000000000000000000000000..bb6aef3ee9ac9246aec86cb78773a5f2fb591a40 GIT binary patch literal 4204 zcmeHKeQXnD7(YJT#>Qm8K$st#Hx$OW-nG4U?b!mO9b1t?8Rct;aJ_r4J7{~iyX)Fb zh=`zWAh0P>=9CZ;t@6z*Oi#^9MGz$2Q{*m&_Z00)=?{M&59fRbZw;0H1!^%9LnT?{g%Cj1 z3JIVfF7OBvZwdRpO>aU6-wsx9ST$zV=;tZ_Pe~6pBt15}w6b>0tvyZUKW@F5>qyG5 zNfT<9pPAjbIoIkPo7K{uQBm2{*jO@T+%qNEi z>)C5Ymd>EApI^HxZD>|M!)KwrukL>NYU-kmxy_+{A061R@~QidwZ73lX6m(pnO_dy zpFX8&yzlIqw}|btzpbmQC^I@gZg}j$lqFY;3o~1$OIr}6-?M_t<@2~)ovFYC>Q~k{ zi<+i9aAL{X>FfLtwB$EG?1~;(S8e-hLgu!qJ4Td5$s_G)b)#xC?<;IPbm79uz?Y3D z7S2zepPz9XDT|gBt2M*!ypmbc9GAY^7`ypUtPR;VH&{1fdcV5JYe#03Ow63${7dfC zlLO>r(PQVWHFWAe#~~}Gl zt=E=SWiOTPKYaM-Wv3pJjtm&=9DN|?Xz`{ueTD&T!FF!}TAtSacIC0?jk4d6OFMU8 zOP8dS^>fER^~vS)HLb0GI?rBdOU~IUS6N?pLH8Fvqx{12ni7oK@P?snJlrm5T5-*4gwti7POMZ_C7K{&v6vxdHi&YNFxu^Qf;15(6AmqKr6Qs-aXg}AYY+(xH&9qvkW@j8 zpc*C<5TmLS!=N7Rj4v#Cy2NFoLLdxH6}YOg$C8B}udmBPqaY}RCEW{>-NRB9 z_`78Fh)vVz>2wbSx_9CBuiUT;XnmLAI7>1=x-Jm=XMP(u^(4Zi=L4Y`{owBkl$KY1hX2L1T9Kdai z)r{M1l$oV?inSZNL(Gx|*p*DEdsG?}2cftC%d=*y4Yvc%j8kNu9S^W39=DTuR?fy* zj8@L5N5ir7G*J#Su$)4e2?9cj1a*Z*IGykFI5CrfyesjA7?p<(PHct{iN^0L{6ZMa zQ5lU*qt!;*U@mz!yM;7a6EW*}^MI_tPSh}sq`^$-?pj%Bm<%MA(fSku=yI3~?UDhb zin3o6LrzSCKsC=UwHIzDj!_vmqXGy@n#?pw(PWkLG zgE|r=FA@~EeuXYd?5H`QEb*3j4GH>ILQ#EF&CqcdX%@i$H!xp!C__3m*BMBu-m7(6U3 zYK+~62dzO;(Lx15(uQkSKcudH6ci?_9&bVN<$=k=(}rzp+vR~G+~dyor<~hdy+0j6 z2d}EWb7#G4@8`|;nre{QJ93W8mhgM)4(@amE_F9OUAkrB*IDh~FTO!TN5oSw)4gx% H($#+fh??L> literal 0 HcmV?d00001 diff --git a/static/theme-editor/icon_paste.png b/static/theme-editor/icon_paste.png new file mode 100644 index 0000000000000000000000000000000000000000..9c761423ccc43d81d1f341ed5f80df2cebf43549 GIT binary patch literal 295 zcmeAS@N?(olHy`uVBq!ia0vp^0wBx?BpA#)4xIr~Ea{HEjtmSN`?>!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD8ZEE?e4<9jVMV;EJ?LWE=mPb3`Pb<2D%33x&~$; whL%<)Mph;U+6D$z1_t)$54E9a$jwj5OsmAL!EaKP6;K0%r>mdKI;Vst0Bh_~`v3p{ literal 0 HcmV?d00001 diff --git a/static/theme-editor/icon_pause.png b/static/theme-editor/icon_pause.png new file mode 100644 index 0000000000000000000000000000000000000000..37fcd6c689fe102a52b4d0ae08ccb5177c725e2c GIT binary patch literal 268 zcmeAS@N?(olHy`uVBq!ia0vp^JRr;nBpB-W61{*FOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>21sKVfGR*3zqt`BsDZ)L)z4*}Q$iB}P3=O{ literal 0 HcmV?d00001 diff --git a/static/theme-editor/icon_play.png b/static/theme-editor/icon_play.png new file mode 100644 index 0000000000000000000000000000000000000000..2b798c3834f3ec15768eb03d25a81cf02dced1ba GIT binary patch literal 283 zcmeAS@N?(olHy`uVBq!ia0vp^JRr;nBpB-W61{*FOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>21sKVfGR*3zq}DKVjl~ zd4{R}Vh$G4Tl#>?RZCnWN>UO_QmvAUQh^kMk%5tcu7SC(fmw*5rIm@1m5G72fq|8Q jf&KYIZ73RY^HVa@DsgM@n^a{5)WG2B>gTe~DWM4fh>S}d literal 0 HcmV?d00001 diff --git a/static/theme-editor/icon_record.png b/static/theme-editor/icon_record.png new file mode 100644 index 0000000000000000000000000000000000000000..3d60202af04689f1abcafb61ed538922ceeb048c GIT binary patch literal 4353 zcmeHKYitx%6dtJBT3UfnD=%Rj(5g5)kDZ;J8ME!@evGaRWK5XZ!0QB5EP6C8;ns53f|f6Gn$x2`PWTmXYRS* z`R+O2IrnB}RcPka-0YFr7>4Brruoa!J;%AS&>v=v$(V?4Z!W5sZg9spg$zllTH3lJ_9LFR z4z}I*QhsCeaL)}31{!q!h|veahsD9+2MgaGBko)9!sR2U^&z`nS>P(&T6*BUt2g{| zj2hSU#**Fp#_FnmIPdDR75OJ_Z?j)}031J>vnHd(e|G=UpZ1vT`!7r^d(j=Q)iw`b zb`hLBGv%5+USeC#$PpmuzV}G0@5W_=^~sgVb4@EyG6M*`xHuFjF78YQrLeta-Tvu^ zLU|9je!9EF96LAZG0 z`;%4q)aXlV4~dtTwm-DFWu^Yb*Nxns>|^bNsm6J~emu&M_U;dOvyQ&no-E*Yd@%2h zCn(?Pw!+`eRz7-)-T3}pmCZL?KYy_tp8MUyciCp`fAE2= zWrxPjvbJp!4hr5SZM^H9?WcfSes|@{rXAdzvssM`pPfqT=jgHA%9aymO>^xJTb90le$YvGsOrOHWCey@cejp8KR;L|DW>59swqQP!iYJ& zffY_p#DG!*ZCr+7J?bOc54IAxuKI|1o**5J6~k(M+M+m|vuI|8vZzK8Rbuj_?81bE z2n=WgJYhtlmXz=jDP9RZJ7$W&QxLnxN6Zg~@M1F#an8lLXtE@s*R#Z=Y`ie8YErqs zw1WbTd_=Wv$0UksXlQUXxLsyEOfjM;QZ!4kEQt`Lm5kaTK}M}{4n>;74=p9G$86n< z;tnT}%{tph5NICnjL(P#gI)Adt3w5(2bBOZigD4DVNg9iEW4y0k#q#~j~-S9+Cfw~ zw9LA=0!!*))E?K9LRGr_V|DRJDjij!U<4WnYN1t`UQ1351VddOjs#)dh^4%c*u9Xp zu62vmD>i2)l}^tgOcA=>YVTbejnkiFR7-Yt5WJwWMoa?M4EJ~ zJWFz34CmJ~f6h2$6(y4@%mSyoe2 zsv?z|aRZ=o>IMiyDi#f=CLF<~qENs`ur9jW5{dv@Lk>QoOpn$jx+f}h1J1F5qb9=( zwCLq{LEvdo@VdJ}b79;*pG1tb_rbEG2}lFco#e1~Avl~0j_jEAA!Zc?TNNOFLcNzn@+sqqZM16g4K3wj6r zUsLSe6CEiQQqHm1S=2)6Z)HyddYq$3nzRj_&*-?Py3YF!&5+1f^4HOBS8@p)?_Z=( z`u5A!FIS%w=o7fVyZYtolLCDL_jlL-CRcX%7bA?K7rh4bJy@`5^sne!a-ck8svpCi zTQiPDqibW+DlH5fG|agMU|Y8jN5)J$5G=_&dsWuZ;q=VLXeKhz0e?|N*0CjPin1{} z=dDwpUvAyL@EQZ$;l18d9$AJBTz}8K`7NK-j-Px}`%A*C)fsVfQ0~r+6&H~&7ATqN J-#4Xd`Co4V@9Y2o literal 0 HcmV?d00001 diff --git a/static/theme-editor/icon_redo.png b/static/theme-editor/icon_redo.png new file mode 100644 index 0000000000000000000000000000000000000000..eb957f85cac1a0c2aaf7d8c8c1553e2527cd88ed GIT binary patch literal 552 zcmV+@0@wYCP)EX>4Tx04R}tkv&MmKpe$iQ%j3fMC>5qkfAzRC@SKpRVYG*P%E_RU~=gfG-*gu zTpR`0f`cE6RR@G%ypV0NMaF7kRU=q4P{hdBSx!EiiI@oCp`Sau3sXTLas6x zITlcb2HEw4|H1EWt-|C)D=C}+0xyp9F$x5Cfo9!tzK?&Kfh)b^uQq_0Ptxlh zEqVm>Zvz+C9ZlH-E_Z;TCqp)6SMt*o3I*W(jJ_!c4Bi60Ypvee`#607GSpS-1~@nb z#)_1^?(yzWcW?imY4`U7KCE(*VXBP?00009a7bBm000XU000XU0RWnu7ytkO2XskI zMF->u2oX39LSGKb0000tNklkwv6T1-*40Z9PR>zjN@ qqHzVWi%B{^MpG=5?dYR(d-njziX--1me7a*0000!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD8ZEE?e4P#CPr2!2HFM&Rt5(4=MS}^Xvob^$xN%nt-)_nl@(9}gQu&X%Q~loCIHZ~R51Vm literal 0 HcmV?d00001 diff --git a/static/theme-editor/icon_song.png b/static/theme-editor/icon_song.png new file mode 100644 index 0000000000000000000000000000000000000000..e5e45fc75c326018a4c0fd09e5635866c8e224a9 GIT binary patch literal 300 zcmeAS@N?(olHy`uVBq!ia0vp^0wBx?BpA#)4xIr~Ea{HEjtmSN`?>!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD8ZEE?e4@V+hCf*!8DTbk7NCCB64!{5l*E!$tK_0oAjM#0U}T_c zV6JOm7Gh{=WnyGyVxVncU}a!nfBsM#iiX_$l+3hB+#38QRapTwFnGH9xvXo literal 0 HcmV?d00001 diff --git a/static/theme-editor/icon_stop.png b/static/theme-editor/icon_stop.png new file mode 100644 index 0000000000000000000000000000000000000000..d0ec90dd1f7d8220da20915cc41c67db8581a9a5 GIT binary patch literal 268 zcmeAS@N?(olHy`uVBq!ia0vp^JRr;nBpB-W61{*FOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>21sKVfGR*3zqUO_QmvAUQh^kMk%5tcu7SC(fmw*5rIm@1m5G72fq|8Qf&KYIZ73RY^HVa@DsgM@ Tn^a{5)WG2B>gTe~DWM4f%;!PE literal 0 HcmV?d00001 diff --git a/static/theme-editor/icon_trumpet.png b/static/theme-editor/icon_trumpet.png new file mode 100644 index 0000000000000000000000000000000000000000..be5a3b759af2c2fef508e6419df82047ff78cbf2 GIT binary patch literal 300 zcmeAS@N?(olHy`uVBq!ia0vp^0wBx?BpA#)4xIr~Ea{HEjtmSN`?>!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD8ZEE?e4@V+hCf({{c*Zs3mTN{T7DiXzr+QeN z5Rf{ZAay>WZ2rP3`@{3A*fw}E91a!E61#Fl6sTXd#5JNMC9x#cD!C{XNHG{07#Zjq znClvtg&0~|nHX7_7-$<9SQ!}DpFh-wq9HdwB{QuOw+6pSRaQU^44$rjF6*2UngEd* BR5}0v literal 0 HcmV?d00001 diff --git a/static/theme-editor/icon_undo.png b/static/theme-editor/icon_undo.png new file mode 100644 index 0000000000000000000000000000000000000000..5efa0ca386d05a044b151e15933167349c746569 GIT binary patch literal 554 zcmV+_0@eMAP)EX>4Tx04R}tkv&MmKpe$iQ%j3fMC>5qkfAzRC@SKpRVYG*P%E_RU~=gfG-*gu zTpR`0f`cE6RR@G%ypV0NMaF7kRU=q4P{hdBSx!EiiI@oCp`Sau3sXTLas6x zITlcb2HEw4|H1EWt-|C)D=C}+0xyp9F$x5Cfo9!tzK?&Kfh)b^uQq_0Ptxlh zEqVm>Zvz+C9ZlH-E_Z;TCqp)6SMt*o3I*W(jJ_!c4Bi60Ypvee`#607GSpS-1~@nb z#)_1^?(yzWcW?imY4`U7KCE(*VXBP?00009a7bBm000XU000XU0RWnu7ytkO2XskI zMF->u2oX32)s5Fe0000vNkls4k6n5Wgs9Z2><|+A>Bz+ s5q_m=+t!`NSGF;HcnnBN@>$PE4hWYZ{~|f6b^rhX07*qoM6N<$f=deDs{jB1 literal 0 HcmV?d00001 diff --git a/static/theme-editor/icon_wrench.png b/static/theme-editor/icon_wrench.png new file mode 100644 index 0000000000000000000000000000000000000000..77dffeabae04723258bc1011767097c257de992b GIT binary patch literal 302 zcmeAS@N?(olHy`uVBq!ia0vp^0wBx?BpA#)4xIr~Ea{HEjtmSN`?>!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD8ZEE?e4mdKI;Vst E0LNonZU6uP literal 0 HcmV?d00001 diff --git a/static/theme-editor/index.html b/static/theme-editor/index.html new file mode 100644 index 0000000..fd38381 --- /dev/null +++ b/static/theme-editor/index.html @@ -0,0 +1,434 @@ + + + + + + + + + + + + + + +
+
+
+
+ + +
+ +
+ + + + + + +
+
hue shift : D
+ + +
+ +
dfg
+
+ +
+
+
+ +
+
+
+ +
+
+
+ + + +
+
+ +
+
+ +
+ +
+
+ + + + + + diff --git a/static/theme-editor/logo.png b/static/theme-editor/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..3f1c3fa3b3318e7bacb30c69e7257f8969c12c13 GIT binary patch literal 805 zcmV+=1KRwFP)EX>4Tx04R}tkv&MmKpe$iQ$^8M2aAYw$WWc^q9Ts93Pq?8YK2xEOfLO`CJjl7 zi=*ILaPVWX>fqw6tAnc`2!4RLx;QDiNQwVT3N2ziIPS;0dyl(!fKV?p&FYE)nr@q^ zL|n{dSH+%J^dpP`1Tic#%b1g-Bsz|-d-(Wz7v))<&;2=qYR+PSPb7{p!?cMvh-Wr! zgY!Odh!tg(_?&pcqze*1a$WKGjdQ_efoF!ybZVYBL@XBCSZQNcG&SOB;)ts0lrLmF zRyl8R*2-1ZyeEHQAg8Y^bDd@w2`pj>5=1DdqJ%PRL}}GYv5=zucnANe>zBx-kgEhn zjs;YpL3aJ%fAG6oD?c^qB?aO@_lx6vi~&8nK%?e3-^Y&AI05|6z?I(eSL(p*C+W48 z7C8b2w}Ff6mZt0hmpj17lOdb3EBR>(`8@D`M&FbLhHinrHLthkK29HiGQ2_%o>^78QAoSJ^Psv7UI<_FIiik~W$buAzB`H3~=#KCNE)e)-pG=VSB6 z9&|M~>~Arfxzv{>-A`SX>-nauCH>jSu*^@QXS#-w)@r(Pi!KsFy}t(J7h>48Ww%Wv#f&XJkz^>ngYL-pn(dG9KfC&Lu_loqHt%v?sxq(!iD_ jh4d?E0S2qm#{a`F`o8EW=y=Nn{1`6_P!Id>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!u! zz$3Dlfq`2Xgc%uT&5-~KvX^-Jy0X9IW)%{a_S|`ICD1;3PZ!6Kid%1Q8+J7Z2ryhY zIms#iAuCHX_xiMlSL+gA2kPi!AU8x-Z rf5rS|ny<4T-F757#dm_7=8hT8eT9klo~KFyh>nTu$sZZAYL$MSD+10f+@+{-GzbiZkO;9AdkJo z)7O>#2|JsxmR|MrHD*8|bx#+^5RU7~2|$pT5RjU1AvIw`{DFY~jSv6x3vi~qZaUhy ziHC=w=Qq2NS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5lweBoc6VW5yxS$b1ju7A z@$_|Nf5Ofttff~yeT^AVNXFB}F@)oK@{j)w53`t@o0**dGK#Q>Fn0Z~XJB|(!n;Jj z=<#i!I@J=_h?11Vl2ohYqEsNoU}Ruqple{RYhV^)XlZ3)WMyKYZD3$!U|@g#P#cPd c-29Zxv`X9>{3cad0W~mqy85}Sb4q9e01|jdg#Z8m literal 0 HcmV?d00001 diff --git a/static/theme-editor/sampleedit_control_icon.png b/static/theme-editor/sampleedit_control_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..2ad8999721aaef7c4c0c17064542f61ca5852708 GIT binary patch literal 277 zcmeAS@N?(olHy`uVBq!ia0vp^+#t*dBp4d6dvyaTmUKs7M+SzC{oH>NS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5lweBoc6VW5yxS$b1ju7A z@$_|Nf5Ofttff~yeT^AVNY>NEF@)oK@{j)w56hSi>#_>moXeop_(G}Y<9|kmm$&%L z^|Eb#02Qj1xJHzuB$lLFB^RXvDF!10BLiInb6o?o5JO8V6C*1V18oBXD+2@j^M~3{ dH00)|WTsW(*5Eg($_l7~!PC{xWt~$(696oVNofE8 literal 0 HcmV?d00001 diff --git a/static/theme-editor/sampleedit_del.png b/static/theme-editor/sampleedit_del.png new file mode 100644 index 0000000000000000000000000000000000000000..d00967ed4f6880d51dc741f52595fdca1ed59193 GIT binary patch literal 289 zcmeAS@N?(olHy`uVBq!ia0vp@Aj}9P7@{WJya=RN(j9#r85lP9bN@+X1@aY=J%W50 z7^>757#dm_7=8hT8eT9klo~KFyh>nTu$sZZAYL$MSD+10f+@+{-GzbiZkO;9AdkJo z)7O>#2|JsxmR|MrHD*8|O-~oc5RU7~8|n`z)Hf{L-~4a~%VA~iHhxha`?>}X1!)Z? z5%yEJ>=_u8`uOgCpS757#dm_7=8hT8eT9klo~KFyh>nTu$sZZAYL$MSD+10f+@+{-GzbiZkO;9AdkJo z)7O>#2|JsxmR|MrHD*8|El(H65RU7~KmIo}w%8f`sXzGPKhxp=qCEeVB>qJi{8^V! z@vXU$QRz1`!(K(vziS`uCPsvQH#I3<^Qk4}@1B0ilpUXO@geCyW$5I~v literal 0 HcmV?d00001 diff --git a/static/theme-editor/sampleedit_draw_small.png b/static/theme-editor/sampleedit_draw_small.png new file mode 100644 index 0000000000000000000000000000000000000000..a41ca41d21f9dc960e62a02bf937020b3a989674 GIT binary patch literal 286 zcmeAS@N?(olHy`uVBq!ia0vp^+#t*dBp4d6dvyaTmUKs7M+SzC{oH>NS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5lweBoc6VW5yxS$b1ju7A z@$_|Nf5Ofttff~yeT^AVNX^s5F@)oK@{j)wj4gZyf8q~(xZn8jJX2ddC(nI3gE_Sa z4sc9jV$c&7oO-O<+!d%pwZt`|BqgyV)hf9t6-Y4{85kMp8kp-En1vWxTA3JGnHXpr m7+4t?*q=YthN2-iKP5A*61N7wNmW)r4Gf;HelF{r5}E)oC`^9< literal 0 HcmV?d00001 diff --git a/static/theme-editor/sampleedit_fadein.png b/static/theme-editor/sampleedit_fadein.png new file mode 100644 index 0000000000000000000000000000000000000000..1bbcf0454abe7dde87ec4854db7d35867c77648e GIT binary patch literal 288 zcmeAS@N?(olHy`uVBq!ia0vp@Aj}9P7@{WJya=RN(j9#r85lP9bN@+X1@aY=J%W50 z7^>757#dm_7=8hT8eT9klo~KFyh>nTu$sZZAYL$MSD+10f+@+{-GzbiZkO;9AdkJo z)7O>#2|JsxmR|MrHD*8|4Nn)x5RU7~KmIpA{Lj-?FT`W7A|dBtATuF>p@})cEPzFW zZ_3~Q%nTae_&GNRy*Uolqgvt`QIe8al4_M)lnSI6j0}tnbPddP4a`CeEv-z9tV|5F n4GgRd4D8PzYD3YGo1c=IR*74K-=r!lpaup{S3j3^P6757#dm_7=8hT8eT9klo~KFyh>nTu$sZZAYL$MSD+10f+@+{-GzbiZkO;9AdkJo z)7O>#2|JsxmR|MrHD*8|RZkbk5RU7~KmIpA{KMaN*j|ENS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5lweBoc6VW5yxS$b1ju7A z@$_|Nf5Ofttff~yeT^AVNY&HDF@)oKa>a*+hcQftYgpUo>z40H|5bq&ly3@xopjI2xyv<(cb k3=HhgA8JF9nO2EggWseoE1(7jPgg&ebxsLQ09;T_cK`qY literal 0 HcmV?d00001 diff --git a/static/theme-editor/sampleedit_none.png b/static/theme-editor/sampleedit_none.png new file mode 100644 index 0000000000000000000000000000000000000000..8b35a593c0f9a8da1629dcf5c07009d7dc653a3d GIT binary patch literal 288 zcmeAS@N?(olHy`uVBq!ia0vp@Aj}9P7@{WJya=RN(j9#r85lP9bN@+X1@aY=J%W50 z7^>757#dm_7=8hT8eT9klo~KFyh>nTu$sZZAYL$MSD+10f+@+{-GzbiZkO;9AdkJo z)7O>#2|JsxmR|MrHD*8|4Nn)x5RU7~KmIpA{LbGNZ7-qsH^D;S;DrMR8CV>IPV8e5 zV?XupKO;lxG9h0vmyK3HJ*p+H5hW>!C8<`)MX5lF!N|bKK-a)r*T5{q(9+7p$jZb( n+rYrez`*|ep*9o^x%nxXX_dG&_)V$;*}&lG>gTe~DWM4fIL}Ro literal 0 HcmV?d00001 diff --git a/static/theme-editor/sampleedit_normalize.png b/static/theme-editor/sampleedit_normalize.png new file mode 100644 index 0000000000000000000000000000000000000000..c9eb5e0608208db5cfcccf8d2740dd25699f2081 GIT binary patch literal 269 zcmeAS@N?(olHy`uVBq!ia0vp@Aj}9P7@{WJya=RN(j9#r85lP9bN@+X1@aY=J%W50 z7^>757#dm_7=8hT8eT9klo~KFyh>nTu$sZZAYL$MSD+10f+@+{-GzbiZkO;9AdkJo z)7O>#2|JsxmR|MrHD*8|QBN1g5RU7~KmIpAtY^3S#po;>z{1d1Ep#dKbAlUCfoh3s zL`h0wNvc(HQ7VvPFfuSQ&^0jEH82Y?w6roYvNAEyHZZU757#dm_7=8hT8eT9klo~KFyh>nTu$sZZAYL$MSD+10f+@+{-GzbiZkO;9AdkJo z)7O>#2|JsxmR|MrHD*8|El(H65RU7~7XO+T{$yuX<}v-7U=erlLpA&1`_erB;|%`j zC;Zso`0zg`L!6kf(es=VU7#-264!{5l*E!$tK_0oAjM#0U}T_cV6JOm7Gh{=WnyGy qVxVncU}a!nfBsM#iiX_$l+3hB+#38QRapTwFnGH9xvX757#dm_7=8hT8eT9klo~KFyh>nTu$sZZAYL$MSD+10f+@+{-GzbiZkO;9AdkJo z)7O>#2|JsxmR|MrHD*8|ZBG}+5RU7~KRz};tYSI*QHwl2^HI$A715YbCuz7 zU{GnyS#aXNJVVGKfge8t`BsDZ)L)z4*}Q$iB}djL@! literal 0 HcmV?d00001 diff --git a/static/theme-editor/sampleedit_trim.png b/static/theme-editor/sampleedit_trim.png new file mode 100644 index 0000000000000000000000000000000000000000..a0993bca7d880c87e314b024b6bb5120766d9cdd GIT binary patch literal 4123 zcmeHKYitx%6dnknbuFOK5HQ3Jiy{waXLj~EV;5+5Te`r)QYuh^!rhrW+o8KV%kFf$ zZ9uUJS}J0Lq`Z|!!SK>HDA?A}3RoTq6(SL8c!UT-tw;btL9yPM?Ndoi6aCjsW@qks zeD|F1oO?2}(mj3h0L^n648sOEGaQ-9UAf}XA2w%s?N)UAvM6h=oCyl>U`P@~AH?Ot zAjDx*6fi9Mo!>og@KHSej~j`$;$&lV#5Wf+h6Z-ci}OV%)Y* z7N%ZXecbWOhG!PX>kIqXw>~_Sxw~e5UF8F#{nDbco5>HpURHI>-*g#lZ#;2wefCo9 z`G)$_eVelPKg-OU7TE~L9`lWCeIR3(7bj#(19#nAi(!3m(QbD;?e_L$Pzsy3lvPbR z>P~#C?%ejYA1kaS_WtKr3!%z!{Zd9YXwpA2I;++nE2~JnQg1o?b~7G-xVX0XK(zSsI|&dm$r+E*_vJ8`#0ehh-c=QoX)`})k8-q+^lI*QZ1N2>Ie)=o)`@R zE)UAM2YSVTO?$hxPK%4YO*_ZrqFg~c%oQ_=LU2~m^enC@k7Ic4#0i?@D2o96PzHF^ z?+b+4s7Wn&yNQ;UQT0235Cx>`}&2*%Cu3!R> zlrP(~TBOI@xQzwG2N?xHQm>;(zn|>t5th>;2&65bCwhdl(D@-VVOYu! zaWE|c1M;Y@5Ioo6AIuN=)O2``gg)p;reUK2=#QPb%f2y*Yh?PlGcyK0QATrSojarsJkPKQma?9cKNC-Q9U5m+pMvH-#eX^Jq? z9y0-e9uknYcsyp_V-QT%E>O-uSOx(ODo_YqCn6ju0E@>=n+YpzvJghj;~{`WUXNzWKm zD4t`}rH~(>a*BT7g=8?`RTT>1Y>L}y)6zPsQ{wgkSwIdp?KClvAMI3RiGDas1`3;c zvz21Zl-_JGnrMnPcN)!xp)l%11yfJy3`SL>l!ZmfAYy^irwBlmqg+^f2m)COWl56H zrd2}170(W}3mqpO$iM+)h(IaYz*0t*vS#T`EKRdUdOSt5R2O@R7lp!qvsMldo*XNA zh8RZs7pkJziJAqM#8$DTPgIW*j;n`)1zaqJFo-~2jT2$TR9r3ycp;h|ZSC4F7oX4y zCbPw4G1GuBKntoLKz+rSISXN8^Z;4~;GzGH9+m{T0EA$Q7x9R=LhY$?g^y7SHMV;! z1-VeE0wRo{j6^44hBm^;wuDJ#X0&IVO#XwDWYwU{kU@Si85&+_7Lpyqu#Gci?EH_v zwp#p;J0R%ZO?t#{FI~NK^@xEU8TWQqFI_!iphw2N-SwZ*rRn^ff&ugvRDeE~&YUho z-`Chv!Hn!MhCMw*x%yxmHxEO?IN9k+i@VV;e!$T2GZvg#fT{IbRrP5q>V z)U)d@wl+re&f#Out-w#5*Cf6fY1wq@)BF8PXUE}-b6d9T-B7-6u&wq)_S{pg>*5Xy W1BZ=kdZ8}@!klT-9UrGID*g+(6w literal 0 HcmV?d00001 diff --git a/static/theme-editor/sampleedit_wave_icon.png b/static/theme-editor/sampleedit_wave_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..8b88143975cc324980a7a214277c5ae8dde2482f GIT binary patch literal 283 zcmeAS@N?(olHy`uVBq!ia0vp^+#t*dBp4d6dvyaTmUKs7M+SzC{oH>NS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5lweBoc6VW5yxS$b1ju7A z@$_|Nf5Ofttff~yeT^AVNZHfHF@)oKa>axLACwv&hB6&~%hL9fTjGhd!;{<%907kE znHcVH@LEjxlLfL{wZt`|BqgyV)hf9t6-Y4{85kMp8kp-En1vWxTA3JGnHXpr7+4t? i*q=YthN2-iKP5A*61N7wNmW)r4Gf;HelF{r5}E+* { + font_loaded = true; + redraw(); +}; +font_img.src = 'font_8x11.png'; + +let icons_loaded = 0; +const icons = {}; +['icon_song', 'icon_disk', 'icon_sample', 'icon_trumpet', 'icon_wrench', + 'icon_play', 'icon_pause', 'icon_stop', 'icon_flp', 'icon_undo', 'icon_redo', + 'haken', 'icon_record'] + .forEach(name => { + const img = new Image(); + img.onload = () => { + const c = document.createElement('canvas'); + c.width = img.width; + c.height = img.height; + const ctx = c.getContext('2d'); + ctx.drawImage(img, 0, 0); + const d = ctx.getImageData(0, 0, img.width, img.height).data; + const bits = []; + for (let i = 0; i < d.length; i += 4) { + bits.push(d[i] < 128 ? 1 : 0); + } + icons[name] = {w: img.width, h: img.height, bits}; + icons_loaded++; + redraw(); + }; + img.src = name + '.png'; + }); + +let piano_img = new Image(); +let piano_loaded = false; +piano_img.onload = () => { + piano_loaded = true; + redraw(); +}; +piano_img.src = 'piano.png'; + +let logo_img = new Image(); +let logo_loaded = false; +logo_img.onload = () => { + logo_loaded = true; + redraw(); +}; +logo_img.src = 'logo.png'; + +let font_3x5_img = new Image(); +let font_3x5_loaded = false; +font_3x5_img.onload = () => { + font_3x5_loaded = true; + redraw(); +}; +font_3x5_img.src = 'font_3x5.png'; + + +fb_main.imageSmoothingEnabled = false; + +const pv_char_w = 4; +const pv_char_h = 8; +const pv_cell_h = 8; +const pv_border_w = 10; +const pv_cols = 4; +const pv_rows = 0x40; +const pv_cursorbar_y = 88; +const pv_cellw = 32; + +let sel_x1 = 0, sel_y1 = 0, sel_x2 = 0, sel_y2 = 0; + +// map ascii to tiles in font_8x11 +// otherwise render ascii 64 '?' for unknown +const font_index = [ + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 92, 63, 62, 69, 86, 70, + 71, 84, 72, 73, 67, 65, 74, 66, 75, 79, 52, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 81, 87, 76, 77, 78, 64, 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 82, 80, 83, 90, + 68, 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 88, 64, 89, 91, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64 +]; +const font_widths = [ + 6, 6, 6, 6, 6, 4, 6, 6, 2, 4, 6, 2, 8, 6, 6, 6, 6, 4, 6, 4, 6, 7, 8, 7, + 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 2, 7, 7, 7, 8, 8, 7, 7, 7, 7, 7, 8, 7, 7, + 8, 8, 8, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 2, 7, 6, 5, 6, 6, 7, 7, 7, + 4, 4, 3, 2, 4, 4, 4, 4, 5, 2, 4, 4, 3, 6, 6, 3, 4, 4, 6, 8, 3 +]; + +// randomise the memory bar on page load +const mem_use = Math.floor(Math.random() * 100) + 1; +const scalexy = 2; + +sel_x1 = Math.floor(Math.random() * pv_cols); +sel_y1 = Math.floor(Math.random() * 10); +sel_x2 = sel_x1 + 1 + Math.floor(Math.random() * (pv_cols - sel_x1)); +sel_y2 = sel_y1 + 1 + Math.floor(Math.random() * 5); + +const vis_rows = Math.floor(192 / pv_cell_h); +const cursor_pos = Math.floor(vis_rows / 2) - 1; +const firstrow = 5 - cursor_pos; + +const sel_sx1 = pv_border_w + (sel_x1 - 0) * pv_cellw; +const sel_sx2 = sel_sx1 + (sel_x2 - sel_x1) * pv_cellw; +const sel_sy1 = (sel_y1 - firstrow) * pv_cell_h; +const sel_sy2 = sel_sy1 + (sel_y2 - sel_y1) * pv_cell_h; +const effective_width = pv_border_w + pv_cols * pv_cellw; +// if the lck checkbox is checked them +// modifying one of these colours also +// changes the other +const tobkitSimilarCols = { + col_light_ctrl_disabled: 'col_light_bg', + col_dark_ctrl_disabled: 'col_medium_bg', + col_selected_tab: 'col_light_bg', + col_unselected_tab: 'col_medium_bg', + col_list_1: 'col_medium_bg', + col_list_2: 'col_light_bg', + col_scrollbar_bg1: 'col_medium_bg', + col_scrollbar_bg2: 'col_light_bg', + col_scrollbar_inactive: 'col_dark_ctrl', + col_scrollbar_active: 'col_light_ctrl', + col_scrollbar_arr_bg1: 'col_dark_ctrl', + col_scrollbar_arr_bg2: 'col_light_ctrl', + col_tab_outline: 'col_outline', + col_icon_tab: 'col_icon', + col_env_bg: 'col_bg', + col_env_line: 'col_dark_ctrl', + col_env_pt: 'col_light_ctrl', + col_env_pt_border: 'col_outline', + col_env_pt_border_active: 'col_signal', + col_smp_bg: 'col_bg', + col_smp_bg_sel: 'col_light_ctrl', + col_pv_bg: 'col_bg', + col_pv_lines: 'col_light_bg', + col_pv_lines_record: 'col_dark_ctrl', + col_pv_cb_col1: 'col_medium_bg', + col_pv_cb_col2: 'col_light_bg', + col_pv_cb_col1_highlight: 'col_list_highlight1', + col_pv_cb_col2_highlight: 'col_list_highlight2', + col_pv_left_numbers: 'col_list_highlight1', + col_pv_pb: 'col_outline', + col_pv_pb_cell: 'col_outline', + col_pv_mutesolo_col1: 'col_medium_bg', + col_pv_mutesolo_col2: 'col_light_bg', + col_pv_mutesolo_col1_highlight: 'col_list_highlight1', + col_pv_mutesolo_col2_highlight: 'col_list_highlight2', + col_list_sep_vertical: 'col_sepline', + col_tb_bg: 'col_dark_ctrl', + col_tb_fg_off: 'col_text_bt', + col_tb_fg_on: 'col_light_ctrl' +}; + +function updateColsFrom(changed_key) { + if (!lockcols) return; + + for (const [dep_key, source_key] of Object.entries(tobkitSimilarCols)) { + if (source_key == changed_key) { + colours[dep_key] = colours[changed_key]; + const idx = cols_ordered.indexOf(dep_key); + if (idx >= 0) update_swatch(idx); + } + } + + for (const [dep_key, source_key] of Object.entries(tobkitSimilarCols)) { + if (dep_key == changed_key && colours[source_key]) { + colours[changed_key] = colours[source_key]; + const idx = cols_ordered.indexOf(changed_key); + if (idx >= 0) update_swatch(idx); + } + } +} + +function stringToRGB15(hex) { + const r = parseInt(hex.substr(0, 2), 16); + const g = parseInt(hex.substr(2, 2), 16); + const b = parseInt(hex.substr(4, 2), 16); + return ((b >> 3) << 10) | ((g >> 3) << 5) | (r >> 3) | 0x8000; +} + +// tobkit drawing functions +function interpolateColor(c1, c2, alpha) { + return (((((c1 & 0x1f) - (c2 & 0x1f)) * alpha) + ((c2 & 0x1f) << 12)) >> 12) | + ((((((c1 >> 5) & 0x1f) - ((c2 >> 5) & 0x1f)) * alpha) + + (((c2 >> 5) & 0x1f) << 12)) >> + 12) + << 5 | + ((((((c1 >> 10) & 0x1f) - ((c2 >> 10) & 0x1f)) * alpha) + + (((c2 >> 10) & 0x1f) << 12)) >> + 12) + << 10 | + 0x8000; +} + + +function drawPixel(x, y, col, __canvas__) { + const r = (col & 0x1f) * 255 / 31; + const g = ((col >> 5) & 0x1f) * 255 / 31; + const b = ((col >> 10) & 0x1f) * 255 / 31; + __canvas__.fillStyle = `rgb(${r},${g},${b})`; + __canvas__.fillRect(x * scalexy, y * scalexy, scalexy, scalexy); +} + +function drawFullBox(x, y, w, h, col, __canvas__) { + const r = (col & 0x1f) * 255 / 31; + const g = ((col >> 5) & 0x1f) * 255 / 31; + const b = ((col >> 10) & 0x1f) * 255 / 31; + __canvas__.fillStyle = `rgb(${r},${g},${b})`; + __canvas__.fillRect(x * scalexy, y * scalexy, w * scalexy, h * scalexy); +} + +function drawGradient(x, y, w, h, c1, c2, __canvas__) { + if (c1 == c2) { + drawFullBox(x, y, w, h, c1, __canvas__); + return; + } + const step = Math.floor(4096 / h); + let pos = 0; + for (let j = 0; j < h; j++, pos += step) { + const col = interpolateColor(c1, c2, pos); + const r = (col & 0x1f) * 255 / 31; + const g = ((col >> 5) & 0x1f) * 255 / 31; + const b = ((col >> 10) & 0x1f) * 255 / 31; + __canvas__.fillStyle = `rgb(${r},${g},${b})`; + __canvas__.fillRect( + x * scalexy, (y + j) * scalexy, w * scalexy, 1 * scalexy); + } +} + +function drawBorder(x, y, w, h, col, __canvas__) { + drawFullBox(x, y, w, 1, col, __canvas__); + drawFullBox(x, y + h - 1, w, 1, col, __canvas__); + drawFullBox(x, y, 1, h, col, __canvas__); + drawFullBox(x + w - 1, y, 1, h, col, __canvas__); +} + +function drawHLine(x, y, w, col, __canvas__) { + drawFullBox(x, y, w, 1, col, __canvas__); +} + +function drawVLine(x, y, h, col, __canvas__) { + drawFullBox(x, y, 1, h, col, __canvas__); +} + +function drawString(str, x, y, col, maxw, maxh, __canvas__) { + if (!font_loaded) return; + const font_canvas = document.createElement('canvas'); + font_canvas.width = font_img.width; + font_canvas.height = font_img.height; + const font_ctx = font_canvas.getContext('2d'); + font_ctx.drawImage(font_img, 0, 0); + const font_data = + font_ctx.getImageData(0, 0, font_img.width, font_img.height).data; + + let drawpos = 0; + for (let c of str) { + const code = c.charCodeAt(0); + const idx = font_index[code]; + const w = font_widths[idx]; + if (maxw && drawpos + w > maxw) break; + const h = maxh ? Math.min(11, maxh) : 11; + for (let j = 0; j < h; j++) { + for (let i = 0; i < 8; i++) { + const px = idx * 8 + i; + const py = j; + if (px < font_img.width && py < font_img.height) { + const didx = (py * font_img.width + px) * 4; + if (font_data[didx] < 128) { + drawPixel(x + drawpos + i, y + j, col, __canvas__); + } + } + } + } + drawpos += w + 1; + } +} + +function drawMonochromeIcon(x, y, w, h, name, col, __canvas__) { + const icon = icons[name]; + let pixelidx = 0; + for (let j = 0; j < h; j++) { + for (let i = 0; i < w; i++, pixelidx++) { + if (icon.bits[pixelidx]) { + drawPixel(x + i, y + j, col, __canvas__); + } + } + } +} + + +// pv notes +function drawMiniChar(c, cx, cy, col, ctx_main) { + const font_3x5_raw = [ + 0x92, 0xD6, 0xFB, 0xBF, 0xE6, 0xFD, 0xAE, 0xDE, 0x74, 0x9A, 0xE6, + 0xB7, 0x6D, 0x0F, 0x14, 0x5D, 0xD9, 0x84, 0x6D, 0x9B, 0x26, 0xA9, + 0xD4, 0xBC, 0x6D, 0x1B, 0xB5, 0x6D, 0x09, 0x1C, 0x15, 0xF5, 0x5D, + 0xFF, 0x97, 0x6E, 0xBD, 0xB4, 0xBC, 0x5D, 0x27, 0xB5, 0x97, 0xA4, + 0x17, 0x95, 0x48, 0x56, 0x65, 0x9B, 0x26, 0xAD, 0xD4, 0xB4, 0xCD, + 0x4A, 0xF5, 0xAF, 0x02, 0x1C, 0xFA, 0xC7, 0x3D, 0x5F, 0xE7, 0x3D, + 0xAE, 0xD2, 0xB7, 0x8A, 0x3B, 0x59, 0xAD, 0x0E, 0x14 + ]; + + const GLYPH_3X5_COUNT = 40; + const r = (col & 0x1f) * 255 / 31; + const g = ((col >> 5) & 0x1f) * 255 / 31; + const b = ((col >> 10) & 0x1f) * 255 / 31; + ctx_main.fillStyle = `rgb(${r},${g},${b})`; + + for (let j = 0; j < 5; j++) { + for (let i = 0; i < 3; i++) { + const pixelidx = 3 * GLYPH_3X5_COUNT * j + 3 * c + i; + if (font_3x5_raw[Math.floor(pixelidx / 8)] & (1 << (pixelidx % 8))) { + ctx_main.fillRect( + (cx + i) * scalexy, (cy + j) * scalexy, scalexy, scalexy); + } + } + } +} + +function drawHexByte(byte, cx, cy, col, ctx_main) { + drawMiniChar(Math.floor(byte / 16), cx, cy, col, ctx_main); + drawMiniChar(byte % 16, cx + pv_char_w, cy, col, ctx_main); +} + +function drawSampleDisplay(x, y, width, height, __canvas__) { + const col_s_bg = stringToRGB15(colours.col_smp_bg); + const col_s_bg_s = stringToRGB15(colours.col_smp_bg_sel); + const col_s_w = stringToRGB15(colours.col_smp_waveform); + const col_s_w_s = stringToRGB15(colours.col_smp_waveform_sel); + const col_signal = stringToRGB15(colours.col_signal); + const cscrollarr2 = stringToRGB15(colours.col_scrollbar_arr_bg2); + const cscrollarr1 = stringToRGB15(colours.col_scrollbar_arr_bg1); + + drawFullBox(1, 1, width - 2, height - 2, col_s_bg, __canvas__); + drawBorder(x, y, width, height, col_signal, __canvas__); + drawGradient(width-9, height-SCROLLBAR_WIDTH+1, 8, 8, cscrollarr2, cscrollarr1); + // TODO FINISH THIS +} +// void SampleDisplay::draw(void) +// { +// if(!isExposed()) +// return; + +// // +// // Border and background +// // +// drawFullBox(1, 1, width - 2, height - 2, theme->col_smp_bg); + +// if(active==false) { +// drawBorder(theme->col_outline); +// } else { +// drawBorder(theme->col_signal); +// } + +// // Now comes sample-dependant stuff, so return if we have no sample +// if((smp==0)||(smp->getNSamples()==0)) return; + +// // +// // Selection +// // +// s32 selleft = 0; +// s32 selwidth = 0; +// s32 selright = 0; + +// if(selection_exists) { +// selleft = sampleToPixel(std::min(selstart, selend)); +// selright = sampleToPixel(std::max(selstart, selend)); +// bool dontdraw = false; + +// if (selleft < 1) selleft = 1; +// else if (selleft > (width-1)) dontdraw = true; + +// if (selright > width-1) selright = width-1; +// else if (selright < 1) dontdraw = true; + +// selwidth = selright - selleft; +// if(!dontdraw) { +// drawFullBox(selleft, 1, selwidth, DRAW_HEIGHT+1, theme->col_smp_bg_sel); +// } +// } + +// // +// // Scrollbar +// // + +// // Right Button +// if(pen_on_scroll_right) { +// drawGradient(theme->col_scrollbar_arr_bg1, theme->col_scrollbar_arr_bg2, width-9, height-SCROLLBAR_WIDTH+1, 8, 8); +// } else { +// drawGradient(theme->col_scrollbar_arr_bg2, theme->col_scrollbar_arr_bg1, width-9, height-SCROLLBAR_WIDTH+1, 8, 8); +// } + +// // This draws the right-arrow +// s8 j, p; +// for(j=0;j<3;j++) { +// for(p=-j;p<=j;++p) { +// *(*vram+SCREEN_WIDTH*(y+height-SCROLLBAR_WIDTH+4+p)+x+width-j-3) = theme->col_icon_bt; +// } +// } + +// drawBox(width-SCROLLBAR_WIDTH, height-SCROLLBUTTON_HEIGHT, 9, 9, theme->col_outline); + +// // Left Button +// if(pen_on_scroll_left) { +// drawGradient(theme->col_scrollbar_arr_bg1, theme->col_scrollbar_arr_bg2, 1, height-9, 8, 8); +// } else { +// drawGradient(theme->col_scrollbar_arr_bg2, theme->col_scrollbar_arr_bg1, 1, height-9, 8, 8); +// } + +// // This draws the down-arrow +// for(j=2;j>=0;j--) { +// for(p=-j;p<=j;++p) { +// *(*vram+SCREEN_WIDTH*(y+height-SCROLLBAR_WIDTH+4+p)+x+j+3) = theme->col_icon_bt; +// } +// } + +// drawBox(0, height-9, 9, 9, theme->col_outline); + + +// drawBox(0, height-SCROLLBAR_WIDTH, width, SCROLLBAR_WIDTH, theme->col_outline); + +// // Clear Scrollbar +// drawGradient(theme->col_scrollbar_bg1, theme->col_scrollbar_bg2, SCROLLBUTTON_HEIGHT, height-SCROLLBAR_WIDTH+1, width-2*SCROLLBUTTON_HEIGHT, SCROLLBAR_WIDTH-2); + +// // The scroll thingy +// if(pen_on_scrollthingy) { +// drawFullBox(SCROLLBUTTON_HEIGHT+scrollthingypos, height-SCROLLBAR_WIDTH+1, scrollthingywidth-2, SCROLLBAR_WIDTH-2, theme->col_scrollbar_active); +// } else { +// drawFullBox(SCROLLBUTTON_HEIGHT+scrollthingypos, height-SCROLLBAR_WIDTH+1, scrollthingywidth-2, SCROLLBAR_WIDTH-2, theme->col_scrollbar_inactive); +// } + +// drawBox(SCROLLBUTTON_HEIGHT-1+scrollthingypos, height-SCROLLBAR_WIDTH, scrollthingywidth, SCROLLBAR_WIDTH, theme->col_outline); + +// // +// // Sample +// // + +// u16 colortable[DRAW_HEIGHT+2]; +// u16 colortable_selected[DRAW_HEIGHT+2]; +// for(s32 i=0; icol_light_ctrl, theme->col_dark_ctrl, i<<4); +// colortable[i] = theme->col_smp_waveform; +// //colortable_selected[i] = ((colortable[i] >> 2) & 0x1CE7) | 0x8000; +// colortable_selected[i] = theme->col_smp_waveform_sel; +// } + +// int32 step = divf32(inttof32(smp->getNSamples() >> zoom_level), inttof32(width-2)); +// int32 pos = 0; + +// u32 renderwindow = (u32)std::max(1, std::min(100, (int) ceil_f32toint(step))); + +// u16 middle = (DRAW_HEIGHT+2)/2;//-1; + +// s32 lastmax=0, lastmin=0; +// if(smp->is16bit() == true) { + +// s16 *data; +// s16 *base = (s16*)smp->getData() + pixelToSample(0); + +// for(s32 i=1; i= selleft && i < selright) ? colortable_selected : colortable; +// data = &(base[f32toint(pos)]); + +// s32 maxsmp = -32767, minsmp = 32767; + +// for(u32 j=0;j maxsmp) maxsmp = *data; +// if(*data < minsmp) minsmp = *data; +// data++; +// } + +// s32 maxy = div32((DRAW_HEIGHT+2) * maxsmp, 2 * 32767); +// s32 miny = div32((DRAW_HEIGHT+2) * minsmp, 2 * 32767); + +// if(i>1) { +// if(lastmin > maxy) maxy = lastmin; +// if(lastmax < miny) miny = lastmax; +// } + +// for(s16 j=miny; j<=maxy; ++j) (*vram)[SCREEN_WIDTH*(y+middle-j)+x+i] = colortable_current[middle-j]; + +// lastmax = maxy; +// lastmin = miny; + +// *(*vram+SCREEN_WIDTH*(y+middle)+x+i) = colortable_current[middle]; + +// pos += step; +// } + +// } else { + +// s8 *data; +// s8 *base = (s8*)smp->getData() + pixelToSample(0); + +// for(s32 i=1; i= selleft && i < selright) ? colortable_selected : colortable; +// data = &(base[f32toint(pos)]); + +// s8 maxsmp = -127, minsmp = 127; + +// for(u32 j=0;j maxsmp) maxsmp = *data; +// if(*data < minsmp) minsmp = *data; +// data++; +// } + +// s8 maxy = div32((DRAW_HEIGHT+2) * maxsmp, 2 * 127); +// s8 miny = div32((DRAW_HEIGHT+2) * minsmp, 2 * 127); + +// if(i>1) { +// if(lastmin > maxy) maxy = lastmin; +// if(lastmax < miny) miny = lastmax; +// } + +// for(s16 j=miny; j<=maxy; ++j) (*vram)[SCREEN_WIDTH*(y+middle-j)+x+i] = colortable_current[middle-j]; + +// lastmax = maxy; +// lastmin = miny; + +// *(*vram+SCREEN_WIDTH*(y+middle)+x+i) = colortable_current[middle]; + +// pos += step; +// } + +// } + +// // +// // Loop Points +// // +// if( (loop_points_visible) && (smp->getLoop() != NO_LOOP) && !draw_mode ) +// { +// s32 loop_start_pos = sampleToPixel(smp->getLoopStart()); +// s32 loop_end_pos = sampleToPixel(smp->getLoopStart() + smp->getLoopLength()); + +// // Loop Start + +// if( (loop_start_pos >= 0) && (loop_start_pos <= width-2) ) { +// // Line +// for(u8 i=1; icol_loop; + +// /* unused +// u8 cutoff = 0; +// if(loop_start_pos < 1+LOOP_TRIANGLE_SIZE) +// cutoff = 1+LOOP_TRIANGLE_SIZE - loop_start_pos; +// */ + +// // Left Triangle +// if(loop_start_pos > 1 + LOOP_TRIANGLE_SIZE) +// { +// drawHLine(loop_start_pos-2, DRAW_HEIGHT+1-LOOP_TRIANGLE_SIZE, 2, theme->col_outline); + +// for(u8 i=0; icol_loop); +// drawPixel(loop_start_pos-i-3, DRAW_HEIGHT+2-LOOP_TRIANGLE_SIZE+i, theme->col_outline); +// } + +// drawHLine(loop_start_pos-LOOP_TRIANGLE_SIZE+1, DRAW_HEIGHT, LOOP_TRIANGLE_SIZE-1, +// theme->col_loop); +// drawPixel(loop_start_pos-LOOP_TRIANGLE_SIZE, DRAW_HEIGHT, theme->col_outline); +// } + +// // Right Triangle +// if(loop_start_pos < width - 2 - LOOP_TRIANGLE_SIZE) +// { +// drawHLine(loop_start_pos+1, DRAW_HEIGHT+1-LOOP_TRIANGLE_SIZE, 2, theme->col_outline); +// for(u8 i=0; icol_loop); +// drawPixel(loop_start_pos+3+i, DRAW_HEIGHT+2-LOOP_TRIANGLE_SIZE+i, theme->col_outline); +// } +// drawHLine(loop_start_pos+1, DRAW_HEIGHT-LOOP_TRIANGLE_SIZE+LOOP_TRIANGLE_SIZE, LOOP_TRIANGLE_SIZE-1, +// theme->col_loop); +// drawPixel(loop_start_pos+LOOP_TRIANGLE_SIZE, DRAW_HEIGHT, theme->col_outline); +// } +// } + +// // Loop End + +// if( (loop_end_pos >= 0) && (loop_end_pos <= width-2) ) { +// // Line +// for(u8 i=1; icol_loop; + +// // Left Triangle +// if(loop_end_pos > 1 + LOOP_TRIANGLE_SIZE) +// { +// drawHLine(loop_end_pos-LOOP_TRIANGLE_SIZE+1, 1, LOOP_TRIANGLE_SIZE-1, +// theme->col_loop); +// drawPixel(loop_end_pos-LOOP_TRIANGLE_SIZE, 1, theme->col_outline); + +// for(u8 i=0; icol_loop); +// drawPixel(loop_end_pos-1-LOOP_TRIANGLE_SIZE+i+1, 2+i, theme->col_outline); +// } + +// drawHLine(loop_end_pos-2, LOOP_TRIANGLE_SIZE, 2, theme->col_outline); +// } + +// // Right Triangle +// if(loop_end_pos < width-1-LOOP_TRIANGLE_SIZE) +// { +// drawHLine(loop_end_pos+1, 1, LOOP_TRIANGLE_SIZE-1, theme->col_loop); +// drawPixel(loop_end_pos+LOOP_TRIANGLE_SIZE, 1, theme->col_outline); + +// for(u8 i=0; icol_loop); +// drawPixel(loop_end_pos+LOOP_TRIANGLE_SIZE-i, 2+i, theme->col_outline); +// } + +// drawHLine(loop_end_pos+1, LOOP_TRIANGLE_SIZE, 2, theme->col_outline); +// } +// } +// } + +// // +// // Zoom buttons +// // + +// if(!draw_mode) { +// // Outlines +// drawHLine(2, 1, 7, theme->col_light_bg); +// drawHLine(10, 1, 7, theme->col_light_bg); + +// drawHLine(2, 9, 7, theme->col_light_bg); +// drawHLine(10, 9, 7, theme->col_light_bg); + +// drawVLine(1, 2, 7, theme->col_light_bg); +// drawVLine(9, 2, 7, theme->col_light_bg); +// drawVLine(17, 2, 7, theme->col_light_bg); + +// // + +// if(pen_on_zoom_in) { +// drawFullBox(2, 2, 7, 7, theme->col_light_bg); +// drawHLine(3, 5, 5, theme->col_smp_bg); +// drawVLine(5, 3, 5, theme->col_smp_bg); +// } else { +// drawHLine(3, 5, 5, theme->col_light_bg); +// drawVLine(5, 3, 5, theme->col_light_bg); +// } + +// // - +// if(pen_on_zoom_out) { +// drawFullBox(10, 2, 7, 7, theme->col_light_bg); +// drawHLine(11, 5, 5, theme->col_smp_bg); +// } else { +// drawHLine(11, 5, 5, theme->col_light_bg); +// } +// } +// } + +function drawCell(cellx, celly, px, py, dark, ctx_main) { + const notecol = dark ? stringToRGB15(colours.col_pv_notes_dark) : + stringToRGB15(colours.col_pv_notes); + const instrcol = dark ? stringToRGB15(colours.col_pv_instr_dark) : + stringToRGB15(colours.col_pv_instr); + const volumecol = dark ? stringToRGB15(colours.col_pv_volume_dark) : + stringToRGB15(colours.col_pv_volume); + + const realx = pv_border_w + 1 + px * pv_cellw; + const realy = 2 + py * pv_char_h; + + const note = Math.floor(Math.random() * 96); + const instr = Math.floor(Math.random() * 128); + const vol = Math.floor(Math.random() * 128); + const notes_chars = [12, 12, 13, 13, 14, 15, 15, 16, 16, 10, 10, 17]; + const notes_signs = [0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0]; + const MINUS = 37; + const SHARP = 38; + + if (Math.random() > 0.3) { + drawMiniChar(notes_chars[note % 12], realx, realy, notecol, ctx_main); + if (notes_signs[note % 12]) { + drawMiniChar(SHARP, realx + pv_char_w, realy, notecol, ctx_main); + } else { + drawMiniChar(MINUS, realx + pv_char_w, realy, notecol, ctx_main); + } + drawMiniChar( + Math.floor(note / 12), realx + 2 * pv_char_w, realy, notecol, ctx_main); + } + + if (Math.random() > 0.5) { + drawHexByte( + instr + 1, realx + 3 * pv_char_w + 1, realy, instrcol, ctx_main); + } + + if (Math.random() > 0.5) { + drawHexByte(vol, realx + 5 * pv_char_w + 2, realy, volumecol, ctx_main); + } +} + +// NitrousTracker logo +function drawGradientIcon(x, y, w, h, img, __canvas__) { + if (!logo_loaded) return; + const c1 = stringToRGB15(colours.col_light_ctrl); + const c2 = stringToRGB15(colours.col_dark_ctrl); + const outline = stringToRGB15(colours.col_outline); + + const canvas = document.createElement('canvas'); + canvas.width = img.width; + canvas.height = img.height; + const ctx = canvas.getContext('2d'); + ctx.drawImage(img, 0, 0); + const data = ctx.getImageData(0, 0, img.width, img.height).data; + + for (let j = 0; j < h && j < img.height; j++) { + const alpha = Math.floor((j / h) * 4096); + const col = interpolateColor(c1, c2, alpha); + for (let i = 0; i < w && i < img.width; i++) { + const idx = (j * img.width + i) * 4; + const r = data[idx], g = data[idx + 1], b = data[idx + 2]; + if (r > 128 && g < 128 && b > 128) continue; + if (r < 128 && g < 128 && b < 128) { + drawPixel(x + i, y + j, outline, __canvas__); + } else { + drawPixel(x + i, y + j, col, __canvas__); + } + } + } +} + +// just draw the piano as a bitmap since +// it can't be themed anyway +function drawPiano(x, y, w, h, __canvas__) { + if (!piano_loaded) return; + const canvas = document.createElement('canvas'); + canvas.width = piano_img.width; + canvas.height = piano_img.height; + const ctx = canvas.getContext('2d'); + ctx.drawImage(piano_img, 0, 0); + const data = ctx.getImageData(0, 0, piano_img.width, piano_img.height).data; + + for (let j = 0; j < h && j < piano_img.height; j++) { + for (let i = 0; i < w && i < piano_img.width; i++) { + const idx = (j * piano_img.width + i) * 4; + const r = data[idx]; + const g = data[idx + 1]; + const b = data[idx + 2]; + const col = ((b >> 3) << 10) | ((g >> 3) << 5) | (r >> 3) | 0x8000; + drawPixel(x + i, y + j, col, __canvas__); + } + } +} + +function drawButton(x, y, w, h, caption, down, __canvas__) { + const c1 = stringToRGB15(colours.col_light_ctrl); + const c2 = stringToRGB15(colours.col_dark_ctrl); + const outline = stringToRGB15(colours.col_outline); + const text = stringToRGB15(colours.col_text_bt); + + if (down) + drawGradient(x + 1, y + 1, w - 2, h - 2, c1, c2, __canvas__); + else + drawGradient(x + 1, y + 1, w - 2, h - 2, c2, c1, __canvas__); + + drawBorder(x, y, w, h, outline, __canvas__); + + let tw = 0; + for (let c of caption) { + const code = c.charCodeAt(0); + const idx = font_index[code]; + tw += font_widths[idx] + 1; + } + tw -= 1; + drawString( + caption, x + (w - tw) / 2 | 0, y + h / 2 - 5 | 0, text, 255, 255, + __canvas__); +} + +function drawBitButton(x, y, w, h, im, down, bh, bw, bx, by, __canvas__) { + const c1 = stringToRGB15(colours.col_light_ctrl); + const c2 = stringToRGB15(colours.col_dark_ctrl); + const c1d = stringToRGB15(colours.col_light_ctrl_disabled); + const c2d = stringToRGB15(colours.col_dark_ctrl_disabled); + const outline = stringToRGB15(colours.col_outline); + const icon_col = stringToRGB15(colours.col_icon); + + if (Math.random() <= 0.5) { + if (down) + drawGradient(x + 1, y + 1, w - 2, h - 2, c1, c2, __canvas__); + else + drawGradient(x + 1, y + 1, w - 2, h - 2, c2, c1, __canvas__); + + } else { + drawGradient(x + 1, y + 1, w - 2, h - 2, c2d, c1d, __canvas__); + } + drawBorder(x, y, w, h, outline, __canvas__); + drawMonochromeIcon(x + bx, y + by, bw, bh, im, icon_col, __canvas__); +} + +function drawCheckbox(x, y, w, h, caption, checked, albino, __canvas__) { + const c1 = stringToRGB15(colours.col_light_ctrl); + const c2 = stringToRGB15(colours.col_dark_ctrl); + const outline = stringToRGB15(colours.col_outline); + const text = stringToRGB15(colours.col_text); + const check_col = stringToRGB15(colours.col_checkmark); + + if (!albino) { + drawFullBox(x, y, 11, 1, stringToRGB15(colours.col_light_bg), __canvas__); + } else { + drawFullBox(x, y, 11, 3, stringToRGB15(colours.col_bg), __canvas__); + } + + drawBorder(x + 1, y + 3, 9, 9, outline, __canvas__); + drawGradient(x + 2, y + 4, 7, 7, c1, c2, __canvas__); + if (checked) { + drawMonochromeIcon(x + 1, y, 10, 10, 'haken', check_col, __canvas__); + } + + let tw = 0; + for (let c of caption) { + const code = c.charCodeAt(0); + const idx = font_index[code]; + tw += font_widths[idx] + 1; + } + tw -= 1; + + if (!albino) { + drawString(caption, 13 + x, 2 + y, text, 255, 255, __canvas__); + } else { + drawString( + caption, 13 + x, 2 + y, stringToRGB15(colours.col_text_light), 255, 255, + __canvas__); + } +} + +function drawTogglebutton(x, y, w, h, caption, on, bmp, __canvas__) { + const bg = stringToRGB15(colours.col_tb_bg); + const outline = stringToRGB15(colours.col_outline); + const col_on = stringToRGB15(colours.col_tb_fg_on); + const col_off = stringToRGB15(colours.col_tb_fg_off); + const sig_off = stringToRGB15(colours.col_signal_off); + + drawFullBox(x + 1, y + 1, w - 2, h - 2, bg, __canvas__); + drawBorder(x, y, w, h, outline, __canvas__); + + const col = on ? col_on : (bmp ? sig_off : col_off); + + if (bmp) { + drawMonochromeIcon(x + 2, y + 2, 12, 12, bmp, col, __canvas__); + } else { + let tw = 0; + for (let c of caption) { + const code = c.charCodeAt(0); + const idx = font_index[code]; + tw += font_widths[idx] + 1; + } + if (tw > 0) tw -= 1; + drawString( + caption, x + Math.max(2, ((w - tw) / 2) | 0), y + h / 2 - 5 | 0, col, + 255, 255, __canvas__); + } +} + +function drawLabel(x, y, w, h, caption, albino, __canvas__) { + const text = albino ? stringToRGB15(colours.col_text_light) : + stringToRGB15(colours.col_text); + drawString(caption, x, y + h / 2 - 5 | 0, text, 255, 255, __canvas__); +} + +function drawNumberBox(x, y, w, h, value, __canvas__, thin) { + const light_ctrl = stringToRGB15(colours.col_light_ctrl); + const dark_ctrl = stringToRGB15(colours.col_dark_ctrl); + const outline = stringToRGB15(colours.col_outline); + const icon = stringToRGB15(colours.col_icon); + const lighter_bg = stringToRGB15(colours.col_lighter_bg); + const text = stringToRGB15(colours.col_text_value); + + drawGradient(x + 1, y + 1, 8, 8, light_ctrl, dark_ctrl, __canvas__); + for (let j = 0; j < 3; j++) { + for (let i = -j; i <= j; i++) { + drawPixel(x + 4 + i, y + j + 3, icon, __canvas__); + } + } + drawBorder(x, y, 9, 9, outline, __canvas__); + + drawGradient(x + 1, y + 8, 8, 8, light_ctrl, dark_ctrl, __canvas__); + for (let j = 2; j >= 0; j--) { + for (let i = -j; i <= j; i++) { + drawPixel(x + 4 + i, y - j + 13, icon, __canvas__); + } + } + drawBorder(x, y + 8, 9, 9, outline, __canvas__); + + drawFullBox(x + 9, y + 1, w - 9, h - 1, lighter_bg, __canvas__); + if (thin == true) { + drawString( + String(value).padStart(2, ' '), x + 6, y + 5, text, 255, 255, __canvas__); + } else { + drawString( + String(value).padStart(2, ' '), x + 10, y + 5, text, 255, 255, + __canvas__); + } + + drawBorder(x, y, w, h, outline, __canvas__); +} + + +function drawNumberSlider(x, y, w, h, value, is_hex, __canvas__) { + const light_ctrl = stringToRGB15(colours.col_light_ctrl); + const dark_ctrl = stringToRGB15(colours.col_dark_ctrl); + const outline = stringToRGB15(colours.col_outline); + const icon = stringToRGB15(colours.col_icon); + const lighter_bg = stringToRGB15(colours.col_lighter_bg); + const text = stringToRGB15(colours.col_text_value); + + drawGradient(x + 1, y + 1, 8, 15, light_ctrl, dark_ctrl, __canvas__); + for (let j = 0; j < 3; j++) { + for (let i = -j; i <= j; i++) { + drawPixel(x + 4 + i, y + j + 3, icon, __canvas__); + } + } + drawVLine(x + 4, y + 6, 5, outline, __canvas__); + for (let j = 2; j >= 0; j--) { + for (let i = -j; i <= j; i++) { + drawPixel(x + 4 + i, y - j + 13, icon, __canvas__); + } + } + drawBorder(x, y, 9, 17, outline, __canvas__); + + drawFullBox(x + 9, y + 1, w - 10, h - 2, lighter_bg, __canvas__); + const valstr = is_hex ? value.toString(16).padStart(2, ' ') : + String(value).padStart(3, ' '); + drawString(valstr, x + 10, y + 5, text, 255, 255, __canvas__); + drawBorder(x, y, w, h, outline, __canvas__); +} + +function drawMemoryIndicator(x, y, w, h, __canvas__) { + const outline = stringToRGB15(colours.col_outline); + const light_bg = stringToRGB15(colours.col_light_bg); + const ok = stringToRGB15(colours.col_mem_ok); + const warn = stringToRGB15(colours.col_mem_warn); + const alert = stringToRGB15(colours.col_mem_alert); + + const boxw = Math.floor((w - 2) * mem_use / 100); + + let col; + if (mem_use < 62) + col = ok; + else if (mem_use < 78) + col = interpolateColor(warn, ok, (mem_use - 62) << 8); + else if (mem_use < 94) + col = interpolateColor(alert, warn, (mem_use - 78) << 8); + else + col = alert; + + drawBorder(x, y, w, h, outline, __canvas__); + drawFullBox(x + 1, y + 1, w - 2, h - 2, light_bg, __canvas__); + drawFullBox(x + 1, y + 1, boxw, h - 2, col, __canvas__); +} + +function drawListBox(x, y, w, h, show_numbers, __canvas__, mini) { + const row_h = 11; + const sb_w = 9; + const rows = Math.floor((h - 1) / row_h); + const outline = stringToRGB15(colours.col_outline); + const sepline = stringToRGB15(colours.col_sepline); + const vsepline = stringToRGB15(colours.col_list_sep_vertical); + const med_bg = stringToRGB15(colours.col_list_1); + const light_bg = stringToRGB15(colours.col_list_2); + const hl1 = stringToRGB15(colours.col_list_highlight1); + const hl2 = stringToRGB15(colours.col_list_highlight2); + const lighter_bg = stringToRGB15(colours.col_lighter_bg); + const light_ctrl = stringToRGB15(colours.col_scrollbar_arr_bg2); + const dark_ctrl = stringToRGB15(colours.col_scrollbar_arr_bg1); + const text = stringToRGB15(colours.col_text_lb); + const text_2 = stringToRGB15(colours.col_text_lb_highlight); + + for (let i = 0; i < rows - 1; i++) { + drawHLine(x + 1, y + row_h * (i + 1), w - sb_w - 1, sepline, __canvas__); + } + + for (let i = 0; i < rows; i++) { + let c_bot = med_bg; + let c_top = light_bg; + if (i == 0) { + c_bot = hl1; + c_top = hl2; + } else if (i == 1) { + c_bot = light_bg; + c_top = lighter_bg; + } + drawGradient( + x + 1, y + row_h * i + 1, w - sb_w - 1, row_h - 1, c_bot, c_top, + __canvas__); + } + + if (show_numbers) { + drawVLine(x + 17, y + 1, h - 2, vsepline, __canvas__); + } + + drawGradient( + x + w - sb_w + 1, y + 1, 8, 8, light_ctrl, dark_ctrl, __canvas__); + for (let j = 0; j < 3; j++) { + for (let p = -j; p <= j; p++) { + drawPixel(x + w - sb_w + 4 + p, y + j + 3, outline, __canvas__); + } + } + drawBorder(x + w - sb_w, y, 9, 9, outline, __canvas__); + + drawGradient( + x + w - sb_w + 1, y + h - 9, 8, 8, light_ctrl, dark_ctrl, __canvas__); + for (let j = 2; j >= 0; j--) { + for (let p = -j; p <= j; p++) { + drawPixel(x + w - sb_w + 4 + p, y - j + h - 4, outline, __canvas__); + } + } + drawBorder(x + w - sb_w, y + h - 9, 9, 9, outline, __canvas__); + + drawBorder(x + w - sb_w, y, sb_w, h, outline, __canvas__); + drawGradient( + x + w - sb_w + 1, y + 9, sb_w - 2, h - 18, + stringToRGB15(colours.col_scrollbar_bg1), + stringToRGB15(colours.col_scrollbar_bg2), __canvas__); + + const st_h = 20; + const st_pos = 0; + // draw the scrollbar + if (mini !== true) { // don't bother with the sample listbox + drawFullBox( + x + w - sb_w + 1, y + 9 + st_pos, sb_w - 2, st_h, + stringToRGB15(colours.col_scrollbar_inactive), __canvas__); + drawBorder(x + w - sb_w, y + 9 + st_pos, sb_w, st_h, outline, __canvas__); + } + + + // in case we add the file picker to the preview + if (show_numbers) { + for (let i = 0; i < Math.min(rows, 8); i++) { + if (i == 0) { + drawString( + ' ' + (i + 1).toString(16), x + 2, y + row_h * i + 2, text_2, 255, + 255, __canvas__); + } else { + drawString( + ' ' + (i + 1).toString(16), x + 2, y + row_h * i + 2, text, 255, + 255, __canvas__); + } + } + drawString( + 'Text : D', x + 19, y + 2, text_2, w - 19 - 2 - sb_w - 2, h - 6, + __canvas__); + } + + drawBorder(x, y, w, h, outline, __canvas__); +} + +function drawTabbox(x, y, w, h, __canvas__) { + const icon_sz = 16; + const sz_border = icon_sz + 2; + const outline = stringToRGB15(colours.col_tab_outline); + const bg = stringToRGB15(colours.col_bg); + const sel_tab = stringToRGB15(colours.col_selected_tab); + const light_bg = stringToRGB15(colours.col_light_bg); + const med_bg = stringToRGB15(colours.col_unselected_tab); + const icon_col = stringToRGB15(colours.col_icon_tab); + + drawFullBox( + x + 1, y + sz_border + 1, w - 2, h - (sz_border + 2), light_bg, + __canvas__); + drawBorder(x, y + sz_border, w, h - sz_border, outline, __canvas__); + + drawFullBox(x, y, 3 + sz_border * 5, 3, bg, __canvas__); + + const tab_icons = + ['icon_song', 'icon_disk', 'icon_sample', 'icon_trumpet', 'icon_wrench']; + for (let i = 0; i < 5; i++) { + const sel = i == 0; + const off = sel ? 0 : 3; + drawFullBox( + x + 3 + sz_border * i, y + 1 + off, sz_border, sz_border - off, + sel ? sel_tab : med_bg, __canvas__); + drawVLine( + x + 2 + sz_border * i, y + 1 + off, sz_border - off, outline, + __canvas__); + drawHLine(x + 3 + sz_border * i, y + off, sz_border, outline, __canvas__); + drawVLine( + x + 2 + sz_border * (i + 1), y + 1 + off, sz_border - off, outline, + __canvas__); + drawMonochromeIcon( + x + 4 + sz_border * i, y + 2 + off, icon_sz, icon_sz - off, + tab_icons[i], icon_col, __canvas__); + } +} + +function drawSubSamp() { + const bg = stringToRGB15(colours.col_bg); + drawFullBox(0, 0, 256, 192, bg, fb_sub_samped); + drawFullBox(0, 0, 256, 192, bg, fb_sub_samped); + + drawTabbox(1, 1, 139, 151, fb_sub_samped); + + drawListBox(4, 21, 50, 78, true, fb_sub_samped); + drawButton(70, 47, 14, 12, '>', false, fb_sub_samped); + drawButton(55, 47, 14, 12, '<', false, fb_sub_samped); + drawButton(55, 21, 29, 12, 'ins', false, fb_sub_samped); + drawButton(55, 60, 29, 12, 'del', false, fb_sub_samped); + drawButton(55, 34, 29, 12, 'cln', false, fb_sub_samped); + + drawGradientIcon(98, 1, 80, 17, logo_img, fb_sub_samped); + + drawBitButton(180, 3, 23, 15, 'icon_play', false, 12, 12, 5, 0, fb_sub_samped); + drawBitButton(204, 3, 23, 15, 'icon_stop', true, 12, 12, 5, 0, fb_sub_samped); + drawBitButton(236, 1, 19, 19, 'icon_flp', false, 15, 15, 2, 2, fb_sub_samped); + + drawTogglebutton(55, 74, 29, 12, 'lock', true, null, fb_sub_samped); + drawTogglebutton(55, 87, 29, 12, 'loop', false, null, fb_sub_samped); + drawTogglebutton(141, 136, 16, 16, '', false, 'icon_record', fb_sub_samped); + drawTogglebutton(165, 20, 10, 10, '+', false, null, fb_sub_samped); + + drawCheckbox(179, 18, 30, 12, 'scr lock', true, true, fb_sub_samped); + + drawLabel(87, 48, 50, 12, 'ptn len:', false, fb_sub_samped); + drawNumberSlider(105, 60, 32, 17, 16, true, fb_sub_samped); + + drawLabel(87, 22, 48, 12, 'chn: 4', false, fb_sub_samped); + drawButton(112, 34, 12, 12, '-', false, fb_sub_samped); + drawButton(125, 34, 12, 12, '+', false, fb_sub_samped); + + drawLabel(4, 103, 32, 12, 'tmp', false, fb_sub_samped); + drawLabel(38, 103, 32, 12, 'bpm', false, fb_sub_samped); + drawLabel(72, 103, 46, 12, 'restart', false, fb_sub_samped); + drawNumberBox(4, 115, 32, 17, 6, fb_sub_samped); + drawLabel(182, 126, 22, 12, 'add', true, fb_sub_samped); + drawLabel(206, 126, 25, 12, 'oct', true, fb_sub_samped); + drawNumberBox(185, 135, 18, 17, 6, fb_sub_samped, true); + drawNumberBox(206, 135, 18, 17, 4, fb_sub_samped, true); + drawNumberSlider(38, 115, 32, 17, 120, false, fb_sub_samped); + drawNumberSlider(72, 115, 32, 17, 0, true, fb_sub_samped); +} +function drawSub() { + const bg = stringToRGB15(colours.col_bg); + drawFullBox(0, 0, 256, 192, bg, fb_sub); + + drawTabbox(1, 1, 139, 151, fb_sub); + + drawListBox(4, 21, 50, 78, true, fb_sub); + drawButton(70, 47, 14, 12, '>', false, fb_sub); + drawButton(55, 47, 14, 12, '<', false, fb_sub); + drawButton(55, 21, 29, 12, 'ins', false, fb_sub); + drawButton(55, 60, 29, 12, 'del', false, fb_sub); + drawButton(55, 34, 29, 12, 'cln', false, fb_sub); + + drawGradientIcon(98, 1, 80, 17, logo_img, fb_sub); + + drawBitButton(180, 3, 23, 15, 'icon_play', false, 12, 12, 5, 0, fb_sub); + drawBitButton(204, 3, 23, 15, 'icon_stop', true, 12, 12, 5, 0, fb_sub); + drawBitButton(236, 1, 19, 19, 'icon_flp', false, 15, 15, 2, 2, fb_sub); + + drawTogglebutton(55, 74, 29, 12, 'lock', true, null, fb_sub); + drawTogglebutton(55, 87, 29, 12, 'loop', false, null, fb_sub); + drawTogglebutton(141, 136, 16, 16, '', false, 'icon_record', fb_sub); + drawTogglebutton(165, 20, 10, 10, '+', false, null, fb_sub); + + drawCheckbox(179, 18, 30, 12, 'scr lock', true, true, fb_sub); + + drawLabel(87, 48, 50, 12, 'ptn len:', false, fb_sub); + drawNumberSlider(105, 60, 32, 17, 16, true, fb_sub); + + drawLabel(87, 22, 48, 12, 'chn: 4', false, fb_sub); + drawButton(112, 34, 12, 12, '-', false, fb_sub); + drawButton(125, 34, 12, 12, '+', false, fb_sub); + + drawLabel(4, 103, 32, 12, 'tmp', false, fb_sub); + drawLabel(38, 103, 32, 12, 'bpm', false, fb_sub); + drawLabel(72, 103, 46, 12, 'restart', false, fb_sub); + drawNumberBox(4, 115, 32, 17, 6, fb_sub); + drawLabel(182, 126, 22, 12, 'add', true, fb_sub); + drawLabel(206, 126, 25, 12, 'oct', true, fb_sub); + drawNumberBox(185, 135, 18, 17, 6, fb_sub, true); + drawNumberBox(206, 135, 18, 17, 4, fb_sub, true); + drawNumberSlider(38, 115, 32, 17, 120, false, fb_sub); + drawNumberSlider(72, 115, 32, 17, 0, true, fb_sub); + + drawLabel(4, 134, 113, 14, 'unnamed', false, fb_sub); + drawButton(118, 134, 20, 14, '...', false, fb_sub); + drawButton(141, 19, 23, 12, 'ren', false, fb_sub); + drawButton(107, 116, 30, 14, 'zap!', false, fb_sub); + + drawLabel(87, 78, 52, 12, 'ram use', false, fb_sub); + drawMemoryIndicator(87, 90, 50, 8, fb_sub); + + drawListBox(141, 32, 114, 89, true, fb_sub); + + drawBitButton(225, 127, 14, 12, 'icon_undo', false, 8, 8, 3, 2, fb_sub); + drawBitButton(241, 127, 14, 12, 'icon_redo', false, 8, 8, 3, 2, fb_sub); + drawButton(225, 140, 30, 12, 'ins', false, fb_sub); + drawButton(225, 153, 30, 12, 'del', false, fb_sub); + drawButton(225, 166, 30, 12, 'clr', false, fb_sub); + drawButton(225, 179, 30, 12, '--', false, fb_sub); + + drawPiano(0, 152, 224, 40, fb_sub); +} +function drawMain() { + if (!font_loaded || !font_3x5_loaded) return; + + + + const bg = stringToRGB15(colours.col_pv_bg); + const r = (bg & 0x1f) * 255 / 31; + const g = ((bg >> 5) & 0x1f) * 255 / 31; + const b = ((bg >> 10) & 0x1f) * 255 / 31; + fb_main.fillStyle = `rgb(${r},${g},${b})`; + fb_main.fillRect(0, 0, 256 * scalexy, 192 * scalexy); + + const linescol = stringToRGB15(colours.col_pv_lines); + const outline = stringToRGB15(colours.col_pv_pb); + const cell_outline = stringToRGB15(colours.col_pv_pb_cell); + const left_nums = stringToRGB15(colours.col_pv_left_numbers); + const left_nums2 = stringToRGB15(colours.col_pv_left_numbers_highlight); + const chn_text = stringToRGB15(colours.col_pv_chn); + + + + + + + if (!(sel_sx1 >= effective_width || sel_sx2 <= 0 || sel_sy1 >= 192 || + sel_sy2 <= 0)) { + const clamped_x1 = Math.max(sel_sx1, 0); + const clamped_x2 = Math.min(sel_sx2, effective_width); + const clamped_y1 = Math.max(sel_sy1, 0); + const clamped_y2 = Math.min(sel_sy2, 192); + + drawFullBox( + clamped_x1, clamped_y1, clamped_x2 - clamped_x1, + clamped_y2 - clamped_y1 + 1, + stringToRGB15(colours.col_pv_cb_sel_highlight), fb_main); + } + + for (let i = 0; i <= vis_rows; i++) { + const realrow = i - cursor_pos + 5; + if (realrow >= 0 && realrow <= pv_rows) { + if (realrow % 4 == 0) { + drawHLine( + 0, pv_cell_h * i, pv_border_w + pv_cols * pv_cellw, linescol, + fb_main); + } else { + drawHLine( + pv_border_w, pv_cell_h * i, pv_cols * pv_cellw, + stringToRGB15(colours.col_pv_sublines), fb_main); + } + } + } + + for (let i = 0; i <= pv_cols; i++) { + drawVLine(pv_border_w - 1 + i * pv_cellw, 0, 192, linescol, fb_main); + } + + drawGradient( + 0, pv_cursorbar_y, pv_border_w + pv_cols * pv_cellw, pv_cell_h, + stringToRGB15(colours.col_pv_cb_col1), + stringToRGB15(colours.col_pv_cb_col2), fb_main); + drawBorder(0, pv_cursorbar_y, pv_border_w + pv_cols * pv_cellw, pv_cell_h + 1, outline, fb_main); + + if (sel_sy1 <= pv_cursorbar_y + 1 && + sel_sy2 >= pv_cursorbar_y + 1 + pv_cell_h - 1 && + sel_sx1 <= pv_border_w + pv_cols * pv_cellw && sel_sx2 >= pv_border_w) { + const cursor_highlight_x1 = Math.max(sel_sx1, pv_border_w + 1); + drawFullBox( + cursor_highlight_x1, pv_cursorbar_y + 1, + sel_sx2 - cursor_highlight_x1 - 1, pv_cell_h - 1, + stringToRGB15(colours.col_pv_cb_sel_highlight), fb_main); + } + + drawFullBox( + pv_border_w - 1, pv_cursorbar_y, pv_cellw + 1, pv_cell_h + 1, + cell_outline, fb_main); + drawGradient( + pv_border_w, pv_cursorbar_y + 1, pv_cellw - 1, pv_cell_h - 1, + stringToRGB15(colours.col_pv_cb_col1_highlight), + stringToRGB15(colours.col_pv_cb_col2_highlight), fb_main); + + for (let ip = 5 - cursor_pos; ip <= 5 + cursor_pos + 1; ip++) { + if (ip >= 0 && ip < pv_rows) { + if (ip % 4 == 0) + drawHexByte( + ip, 1, 2 + (ip + cursor_pos - 5) * pv_char_h, left_nums2, + fb_main); + else + drawHexByte( + ip, 1, 2 + (ip + cursor_pos - 5) * pv_char_h, left_nums, + fb_main); + } + } + + const highlight_row = cursor_pos; + + for (let i = 0; i < pv_cols; i++) { + for (let j = 0; j < vis_rows; j++) { + if (firstrow + j >= 0 && firstrow + j < pv_rows) { + drawCell(i, firstrow + j, i, j, j == highlight_row, fb_main); + } + } + } + + for (let i = 0; i < pv_cols; i++) { + drawFullBox( + pv_border_w + i * pv_cellw + 1, 1, pv_cellw - 2, 11, bg, fb_main); + const hex = i.toString(16).padStart(2, '0'); + drawString( + hex, pv_border_w + i * pv_cellw + 1, 1, chn_text, 255, 255, + fb_main); + } + + const mutesolo_text = stringToRGB15(colours.col_pv_mutesolo_text); + const mute_y = 1; + const mute_w = 10; + const mute_h = 9; + const mute_rel_x = 9; + const solo_rel_x = 20; + + for (let i = 0; i < pv_cols; i++) { + const muted = i == 1; + const soloed = i == 2; + + const mute_col1 = muted ? + stringToRGB15(colours.col_pv_mutesolo_col1_highlight) : + stringToRGB15(colours.col_pv_mutesolo_col1); + const mute_col2 = muted ? + stringToRGB15(colours.col_pv_mutesolo_col2_highlight) : + stringToRGB15(colours.col_pv_mutesolo_col2); + + drawGradient( + pv_border_w + i * pv_cellw + mute_rel_x, mute_y, mute_w, mute_h, + mute_col1, mute_col2, fb_main); + drawString( + 'm', pv_border_w + i * pv_cellw + mute_rel_x + 1, 0, mutesolo_text, 255, + 255, fb_main); + + const solo_col1 = soloed ? + stringToRGB15(colours.col_pv_mutesolo_col1_highlight) : + stringToRGB15(colours.col_pv_mutesolo_col1); + const solo_col2 = soloed ? + stringToRGB15(colours.col_pv_mutesolo_col2_highlight) : + stringToRGB15(colours.col_pv_mutesolo_col2); + + drawGradient( + pv_border_w + i * pv_cellw + solo_rel_x, mute_y, mute_w, mute_h, + solo_col1, solo_col2, fb_main); + drawString( + 's', pv_border_w + i * pv_cellw + solo_rel_x + 2, 0, mutesolo_text, 255, + 255, fb_main); + } + + drawBitButton(236, 1, 19, 19, 'icon_flp', false, 15, 15, 2, 2, fb_main); + drawButton(225, 22, 30, 12, '-m/s', false, fb_main); + drawLabel(230, 34, 25, 9, 'vol', true, fb_main); + drawNumberSlider(225, 45, 30, 17, 127, true, fb_main); + drawButton(225, 61, 30, 12, 'set', false, fb_main); + drawButton(225, 74, 14, 12, '-', false, fb_main); + drawButton(241, 74, 14, 12, '+', false, fb_main); + drawButton(225, 88, 30, 12, 'cut', false, fb_main); + drawButton(225, 101, 30, 12, 'cp', false, fb_main); + drawButton(225, 114, 30, 12, 'pst', false, fb_main); + drawButton(225, 127, 30, 12, 'sel', false, fb_main); + drawButton(225, 140, 30, 12, 'ins', false, fb_main); + drawButton(225, 153, 30, 12, 'del', false, fb_main); + drawButton(225, 166, 30, 12, 'clr', false, fb_main); + drawButton(225, 179, 30, 12, '--', false, fb_main); +} + +function redraw() { + drawSub(); + // drawSubSamp(); + drawMain(); +} + +function save_theme() { + const name = document.getElementById('theme-name').value || 'theme'; + const content = cols_ordered + .map( + key => cols_ordered.indexOf(key) + '=' + + colours[key] + ' ; ' + colscheme[key].name) + .join('\n'); + const blob = new Blob([content], {type: 'text/plain'}); + const a = document.createElement('a'); + a.href = URL.createObjectURL(blob); + if (!name.endsWith('.nttheme')) + a.download = name + '.nttheme'; + else + a.download = name; + a.click(); +} + + +function select_swatch(key) { + active = key; + document.querySelectorAll('.swatch').forEach((el, idx) => { + el.classList.toggle('active', cols_ordered[idx] == key); + }); + if (colours[key]) { + color_to_pos(tinycolor('#' + colours[key])); + } +} + +function update_input() { + inp.value = cols_ordered + .map( + key => cols_ordered.indexOf(key) + '=' + colours[key] + + ' ; ' + colscheme[key].name) + .join('\n'); +} + +function update_swatch(idx) { + const item = swatch_list.children[idx * 2]; + const key = cols_ordered[idx]; + item.querySelector('.swatchcol').style.backgroundColor = + '#' + colours[key]; +} + +function parse_theme(text) { + const lines = text.split('\n'); + const parsed = {}; + let line_num = 0; + + for (let line of lines) { + line_num++; + const l = line.trim(); + if (!l) continue; + + const hexmatch = l.match(/^(\d+)=([0-9a-fA-F]{6})/); + if (!hexmatch) { + parseres.textContent = `!!line ${line_num}`; + return null; + } + + const index = parseInt(hexmatch[1], 10); + const hex = hexmatch[2].toLowerCase(); + + if (index < 0 || index >= cols_ordered.length) { + parseres.textContent = `!!line ${line_num} key ${ + index} out of bounds (max ${cols_ordered.length - 1})`; + return null; + } + + const key = cols_ordered[index]; + if (key) { + parsed[key] = hex; + } + } + + for (const key of cols_ordered) { + if (!parsed[key]) parsed[key] = '000000'; + } + + return parsed; +} + +function loadDefCols() { + if (Object.keys(colours).length > 0 && + !confirm('lose progress and use default skin?')) + return; + colours = {}; + base_colours = {}; + for (const key of cols_ordered) { + colours[key] = colscheme[key].hex; + base_colours[key] = colscheme[key].hex; + } + update_input(); + inp.disabled = false; + load_btn.disabled = false; + parseres.textContent = ''; + for (let i = 0; i < cols_ordered.length; i++) update_swatch(i); + redraw(); +} + +function loadTheme() { + const parsed = parse_theme(inp.value); + if (!parsed) return; + colours = parsed; + base_colours = {}; + for (const key in parsed) { + base_colours[key] = parsed[key]; + } + inp.disabled = false; + load_btn.disabled = false; + parseres.textContent = ''; + for (let i = 0; i < cols_ordered.length; i++) update_swatch(i); + redraw(); +} + +// most of this colour spectrum stuff is stolen from someones codepen +function draw_spectrum(colour) { + spec_ctx.clearRect(0, 0, spec_canvas.width, spec_canvas.height); + if (!colour) colour = '#f00'; + spec_ctx.fillStyle = colour; + spec_ctx.fillRect(0, 0, spec_canvas.width, spec_canvas.height); + const white_grad = spec_ctx.createLinearGradient(0, 0, spec_canvas.width, 0); + white_grad.addColorStop(0, '#fff'); + white_grad.addColorStop(1, 'transparent'); + spec_ctx.fillStyle = white_grad; + spec_ctx.fillRect(0, 0, spec_canvas.width, spec_canvas.height); + const black_grad = spec_ctx.createLinearGradient(0, 0, 0, spec_canvas.height); + black_grad.addColorStop(0, 'transparent'); + black_grad.addColorStop(1, '#000'); + spec_ctx.fillStyle = black_grad; + spec_ctx.fillRect(0, 0, spec_canvas.width, spec_canvas.height); +} + + + +function color_to_pos(colour) { + const hsl = colour.toHsl(); + hue = hsl.h; + const hsv = colour.toHsv(); + const x = spec_canvas.width * hsv.s; + const y = spec_canvas.height * (1 - hsv.v); + const hue_x = (hue / 360) * hue_canvas.width; + spec_cursor.style.left = x + 'px'; + spec_cursor.style.top = y + 'px'; + hue_cursor.style.left = hue_x + 'px'; + spec_cursor.style.backgroundColor = colour.toHexString(); + hue_cursor.style.backgroundColor = 'hsl(' + hue + ',100%,50%)'; + draw_spectrum('hsl(' + hue + ',100%,50%)'); +} + +function get_spec_color(e) { + e.preventDefault(); + const rect = spec_canvas.getBoundingClientRect(); + let x = e.pageX - rect.left; + let y = e.pageY - rect.top; + x = Math.max(0, Math.min(rect.width, x)); + y = Math.max(0, Math.min(rect.height, y)); + const x_ratio = x / rect.width; + const y_ratio = y / rect.height; + const hsv_v = 1 - y_ratio; + const hsv_s = x_ratio; + lit = (hsv_v / 2) * (2 - hsv_s); + sat = (hsv_v * hsv_s) / (1 - Math.abs(2 * lit - 1)); + const colour = tinycolor('hsl ' + hue + ' ' + sat + ' ' + lit); + spec_cursor.style.left = x + 'px'; + spec_cursor.style.top = y + 'px'; + spec_cursor.style.backgroundColor = colour.toHexString(); + if (active) { + colours[active] = colour.toHex(); + base_colours[active] = colour.toHex(); + updateColsFrom(active); + const idx = cols_ordered.indexOf(active); + if (idx >= 0) update_swatch(idx); + update_input(); + redraw(); + } +} + +// This (the colour picker) is broken on mobile and other quirky +// scaling situations. probably quite a simple +// fix but I will fix it some other time soon +function get_hue_colour(e) { + e.preventDefault(); + const rect = hue_canvas.getBoundingClientRect(); + let x = e.pageX - rect.left; + x = Math.max(0, Math.min(rect.width, x)); + hue = (x / rect.width) * 360; + const hue_colour = 'hsl(' + hue + ',100%,50%)'; + draw_spectrum(hue_colour); + hue_cursor.style.left = x + 'px'; + hue_cursor.style.backgroundColor = hue_colour; + const colour = tinycolor('hsl ' + hue + ' ' + sat + ' ' + lit); + spec_cursor.style.backgroundColor = colour.toHexString(); + if (active) { + colours[active] = colour.toHex(); + base_colours[active] = colour.toHex(); + updateColsFrom(active); + const idx = cols_ordered.indexOf(active); + if (idx >= 0) update_swatch(idx); + update_input(); + redraw(); + } +} + +spec_canvas.addEventListener('mousedown', function(e) { + get_spec_color(e); + spec_cursor.classList.add('dragging'); + const move = (e) => get_spec_color(e); + const up = () => { + spec_cursor.classList.remove('dragging'); + window.removeEventListener('mousemove', move); + window.removeEventListener('mouseup', up); + }; + window.addEventListener('mousemove', move); + window.addEventListener('mouseup', up); +}); + +hue_canvas.addEventListener('mousedown', function(e) { + get_hue_colour(e); + hue_cursor.classList.add('dragging'); + const move = (e) => get_hue_colour(e); + const up = () => { + hue_cursor.classList.remove('dragging'); + window.removeEventListener('mousemove', move); + window.removeEventListener('mouseup', up); + }; + window.addEventListener('mousemove', move); + window.addEventListener('mouseup', up); +}); +// ---------- end colour picker stuff ------------ + +// copy pasted from +// https://stackoverflow.com/questions/2353211/hsl-to-rgb-color-conversion +function rgbToHsl(r,g,b) { + // Make r, g, and b fractions of 1 + r /= 255; + g /= 255; + b /= 255; + + // Find greatest and smallest channel values + let cmin = Math.min(r,g,b), + cmax = Math.max(r,g,b), + delta = cmax - cmin, + h = 0, + s = 0, + l = 0; + + // Calculate hue + // No difference + if (delta === 0) + h = 0; + // Red is max + else if (cmax === r) + h = ((g - b) / delta) % 6; + // Green is max + else if (cmax === g) + h = (b - r) / delta + 2; + // Blue is max + else + h = (r - g) / delta + 4; + + h = Math.round(h * 60); + + // Make negative hues positive behind 360° + if (h < 0) + h += 360; + + // Calculate lightness + l = (cmax + cmin) / 2; + + // Calculate saturation + s = delta === 0 ? 0 : delta / (1 - Math.abs(2 * l - 1)); + + // Multiply l and s by 100 + s = +(s * 100).toFixed(1); + l = +(l * 100).toFixed(1); + + return [h, s, l]; +} + + +// copy pasted from +// https://gist.github.com/vahidk/05184faf3d92a0aa1b46aeaa93b07786?permalink_comment_id=4095278#gistcomment-4095278 +const hslToRgb = (h, s, l) => { + + // IMPORTANT if s and l between 0,1 remove the next two lines: + s /= 100 + l /= 100 + + const k = (n) => (n + h / 30) % 12 + const a = s * Math.min(l, 1 - l) + const f = (n) => + l - a * Math.max(-1, Math.min(k(n) - 3, Math.min(9 - k(n), 1))) + return [Math.round(255 * f(0)), Math.round(255 * f(8)), Math.round(255 * f(4))] +} + + +function stringToHsl(hex) { + const r = parseInt(hex.substr(0, 2), 16); + const g = parseInt(hex.substr(2, 2), 16); + const b = parseInt(hex.substr(4, 2), 16); + return rgbToHsl(r, g, b); +} + +function hslToString(h, s, l) { + const [r, g, b] = hslToRgb(h, s, l); + return ((r << 16) | (g << 8) | b).toString(16).padStart(6, '0'); +} + +function hueshift(hex, shift) { + const [h, s, l] = stringToHsl(hex); + return hslToString((h + shift) % 360, s, l); +} + + +// generate a completely random colour for everything +function randcols() { + for (const key of cols_ordered) { + // random 24 bit int + colours[key] = + Math.floor(Math.random() * 16777216).toString(16).padStart(6, '0'); + base_colours[key] = colours[key]; + const idx = cols_ordered.indexOf(key); + if (idx >= 0) update_swatch(idx); + } + update_input(); + redraw(); +} + +// listen for hue slider +document.getElementById('hueshifter').addEventListener('input', evt => { + const shift = parseInt(evt.target.value, 10); + for (const key of cols_ordered) { + colours[key] = hueshift(base_colours[key], shift); + const idx = cols_ordered.indexOf(key); + if (idx >= 0) update_swatch(idx); + } + update_input(); + redraw(); +}); + +// init swatchs +swatch_list.innerHTML = ''; +for (let i = 0; i < cols_ordered.length; i++) { + const key = cols_ordered[i]; + const item = document.createElement('div'); + item.className = 'swatch'; + const colour_div = document.createElement('div'); + colour_div.className = 'swatchcol'; + const label = document.createElement('span'); + label.className = 'swatchlb'; + label.textContent = colscheme[key].name; + const line = document.createElement('hr'); + line.className = 'swatchhr'; + + item.appendChild(colour_div); + item.appendChild(label); + item.onclick = () => select_swatch(key); + swatch_list.appendChild(item); + swatch_list.appendChild(line); + +} + +const grad = hue_ctx.createLinearGradient(0, 0, hue_canvas.width, 0); +grad.addColorStop(0, 'hsl(0,100%,50%)'); +grad.addColorStop(0.17, 'hsl(61.2,100%,50%)'); +grad.addColorStop(0.33, 'hsl(118.8,100%,50%)'); +grad.addColorStop(0.50, 'hsl(180,100%,50%)'); +grad.addColorStop(0.67, 'hsl(241.2,100%,50%)'); +grad.addColorStop(0.83, 'hsl(298.8,100%,50%)'); +grad.addColorStop(1, 'hsl(360,100%,50%)'); +hue_ctx.fillStyle = grad; +hue_ctx.fillRect(0, 0, hue_canvas.width, hue_canvas.height); +draw_spectrum(); +loadDefCols(); + + + +// if the 'lck' checkbox is checked, then constrain +// certain colours to others to make editing easier +// for instance, list item gradients to +// one of the background colours, etc +document.getElementById('cb_lock').addEventListener('change', evt => { + lockcols = evt.target.checked; +}); diff --git a/static/theme-editor/tobkit.js.min b/static/theme-editor/tobkit.js.min new file mode 100644 index 0000000..a6ff8df --- /dev/null +++ b/static/theme-editor/tobkit.js.min @@ -0,0 +1 @@ +const colscheme={col_bg:{hex:"20317b",name:"Background"},col_env_bg:{hex:"20317b",name:"Envelope editor background"},col_medium_bg:{hex:"4a5a8b",name:"Medium background"},col_light_bg:{hex:"8394c5",name:"Light background"},col_lighter_bg:{hex:"bdcdff",name:"Lighter background"},col_light_ctrl:{hex:"ffff00",name:"Light control / button gradient 1"},col_dark_ctrl:{hex:"ff9400",name:"Dark control / button gradient 2"},col_light_ctrl_disabled:{hex:"8394c5",name:"Light control (disabled)"},col_dark_ctrl_disabled:{hex:"4a5a8b",name:"Dark control (disabled)"},col_selected_tab:{hex:"8394c5",name:"Selected tab"},col_unselected_tab:{hex:"4a5a8b",name:"Unselected tab"},col_list_1:{hex:"4a5a8b",name:"List item gradient 1"},col_list_2:{hex:"8394c5",name:"List item gradient 2"},col_list_highlight1:{hex:"e67b00",name:"List item gradient 1 (highlighted)"},col_list_highlight2:{hex:"e6e600",name:"List item gradient 2 (highlighted)"},col_scrollbar_bg1:{hex:"4a5a8b",name:"Scrollbar background gradient 1"},col_scrollbar_bg2:{hex:"8394c5",name:"Scrollbar background gradient 2"},col_scrollbar_inactive:{hex:"ff9400",name:"Scrollbar thumb (inactive)"},col_scrollbar_active:{hex:"ffff00",name:"Scrollbar thumb (active)"},col_scrollbar_arr_bg1:{hex:"ff9400",name:"Scrollbar arrow background gradient 1"},col_scrollbar_arr_bg2:{hex:"ffff00",name:"Scrollbar arrow background gradient 2"},col_outline:{hex:"000000",name:"Widget outline"},col_tab_outline:{hex:"000000",name:"Tab/tab box outline"},col_sepline:{hex:"ffff00",name:"List item separator line"},col_icon_tab:{hex:"000000",name:"Tab icon"},col_icon:{hex:"000000",name:"Button icon and scrollbar arrows"},col_checkmark:{hex:"000000",name:"Checkmark"},col_text:{hex:"000000",name:"Text"},col_text_light:{hex:"8394c5",name:"Text (light)"},col_text_bt:{hex:"000000",name:"Text (buttons)"},col_text_value:{hex:"000000",name:"Text (value input)"},col_text_lb:{hex:"000000",name:"Text (list items)"},col_text_lb_highlight:{hex:"000000",name:"Text (highlighted list item)"},col_signal:{hex:"ff0000",name:"Recording/signal (red)"},col_signal_off:{hex:"940000",name:"Recording/signal (off, dark red)"},col_piano_label:{hex:"000000",name:"Piano mapping label (naturals)"},col_piano_label_inv:{hex:"ffffff",name:"Piano mapping label (inverted, sharps)"},col_loop:{hex:"39cd29",name:"Loop points"},col_env_sustain:{hex:"00ff00",name:"Envelope sustain line"},col_env_line:{hex:"ff9400",name:"Envelope line"},col_env_pt:{hex:"ffff00",name:"Envelope point fill"},col_env_pt_border:{hex:"000000",name:"Envelope point outline"},col_env_pt_border_active:{hex:"ff0000",name:"Envelope point outline (active)"},col_mem_ok:{hex:"8bc583",name:"Memory usage: OK"},col_mem_warn:{hex:"ffff00",name:"Memory usage: Warning"},col_mem_alert:{hex:"ff0000",name:"Memory usage: Alert"},col_typewriter_cursor:{hex:"000000",name:"Text entry cursor"},col_smp_bg:{hex:"20317b",name:"Sample editor background"},col_smp_bg_sel:{hex:"ffff00",name:"Sample editor background (selection)"},col_smp_waveform:{hex:"ff9c00",name:"Sample editor waveform"},col_smp_waveform_sel:{hex:"000000",name:"Sample editor waveform (selection)"},col_pv_bg:{hex:"20317b",name:"Pattern - background"},col_pv_chn:{hex:"8394c5",name:"Pattern - channel number"},col_pv_lines:{hex:"8394c5",name:"Pattern - lines"},col_pv_sublines:{hex:"394a8b",name:"Pattern - sublines"},col_pv_lines_record:{hex:"ff9400",name:"Pattern - lines (recording)"},col_pv_cb_col1:{hex:"4a5a8b",name:"Pattern - cursor bar gradient 1"},col_pv_cb_col2:{hex:"8394c5",name:"Pattern - cursor bar gradient 2"},col_pv_cb_col1_highlight:{hex:"e67b00",name:"Pattern - cursor bar gradient 1 (highlight)"},col_pv_cb_col2_highlight:{hex:"e6e600",name:"Pattern - cursor bar gradient 2 (highlight)"},col_pv_left_numbers:{hex:"e67b00",name:"Pattern - row numbers"},col_pv_notes:{hex:"4a7bff",name:"Pattern - notes"},col_pv_notes_dark:{hex:"0031d5",name:"Pattern - notes (dark)"},col_pv_instr:{hex:"ff5a00",name:"Pattern - instruments"},col_pv_instr_dark:{hex:"a43100",name:"Pattern - instruments (dark)"},col_pv_volume:{hex:"00de00",name:"Pattern - volume"},col_pv_volume_dark:{hex:"008300",name:"Pattern - volume (dark)"},col_pv_effect:{hex:"ff62ee",name:"Pattern - effect command"},col_pv_effect_dark:{hex:"623194",name:"Pattern - effect command (dark)"},col_pv_effect_param:{hex:"f6d541",name:"Pattern - effect parameter"},col_pv_effect_param_dark:{hex:"4a4129",name:"Pattern - effect parameter (dark)"},col_pv_cb_sel_highlight:{hex:"ffc500",name:"Pattern - selection"},col_pv_pb:{hex:"000000",name:"Pattern - row outline"},col_pv_pb_cell:{hex:"000000",name:"Pattern - cursor outline"},col_pv_mutesolo_text:{hex:"000000",name:"Pattern - mute/solo text color"},col_pv_mutesolo_col1:{hex:"4a5a8b",name:"Pattern - mute/solo gradient 1"},col_pv_mutesolo_col2:{hex:"8394c5",name:"Pattern - mute/solo gradient 2"},col_pv_mutesolo_col1_highlight:{hex:"e67b00",name:"Pattern - mute/solo gradient 1 (highlight)"},col_pv_mutesolo_col2_highlight:{hex:"e6e600",name:"Pattern - mute/solo gradient 2 (highlight)"},col_pv_left_numbers_highlight:{hex:"e67b00",name:"Pattern - row numbers (highlight)"},col_list_sep_vertical:{hex:"ffff00",name:"List item separator line (vertical)"},col_tb_bg:{hex:"ff9400",name:"Togglebutton background"},col_tb_fg_off:{hex:"000000",name:"Togglebutton foreground (off)"},col_tb_fg_on:{hex:"ffff00",name:"Togglebutton foreground (on)"}},cols_ordered=Object.keys(colscheme);let base_colours={},colours={},lockcols=!1,active=null,hue=0,sat=1,lit=.5;const inp=document.getElementById("input"),parseres=document.getElementById("parseres"),swatch_list=document.getElementById("swatches"),load_btn=document.getElementById("load-btn"),spec_canvas=document.getElementById("spectrum-canvas"),spec_ctx=spec_canvas.getContext("2d"),spec_cursor=document.getElementById("spectrum-cursor"),hue_canvas=document.getElementById("hue-canvas"),hue_ctx=hue_canvas.getContext("2d"),hue_cursor=document.getElementById("hue-cursor"),prev_canvas=document.getElementById("preview-canvas"),fb_sub=prev_canvas.getContext("2d"),prev_canvas_main=document.getElementById("preview-canvas-main"),fb_main=prev_canvas_main.getContext("2d");fb_sub.imageSmoothingEnabled=!1,fb_main.imageSmoothingEnabled=!1;let font_img=new Image,font_loaded=!1;font_img.onload=()=>{font_loaded=!0,redraw()},font_img.src="font_8x11.png";let icons_loaded=0;const icons={};["icon_song","icon_disk","icon_sample","icon_trumpet","icon_wrench","icon_play","icon_pause","icon_stop","icon_flp","icon_undo","icon_redo","haken","icon_record"].forEach((o=>{const e=new Image;e.onload=()=>{const t=document.createElement("canvas");t.width=e.width,t.height=e.height;const r=t.getContext("2d");r.drawImage(e,0,0);const l=r.getImageData(0,0,e.width,e.height).data,a=[];for(let o=0;o{piano_loaded=!0,redraw()},piano_img.src="piano.png";let logo_img=new Image,logo_loaded=!1;logo_img.onload=()=>{logo_loaded=!0,redraw()},logo_img.src="logo.png";let font_3x5_img=new Image,font_3x5_loaded=!1;font_3x5_img.onload=()=>{font_3x5_loaded=!0,redraw()},font_3x5_img.src="font_3x5.png",fb_main.imageSmoothingEnabled=!1;const pv_char_w=4,pv_char_h=8,pv_cell_h=8,pv_border_w=10,pv_cols=4,pv_rows=64,pv_cursorbar_y=88,pv_cellw=32;let sel_x1=0,sel_y1=0,sel_x2=0,sel_y2=0;const font_index=[64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,92,63,62,69,86,70,71,84,72,73,67,65,74,66,75,79,52,53,54,55,56,57,58,59,60,61,81,87,76,77,78,64,64,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,82,80,83,90,68,64,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,88,64,89,91,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64],font_widths=[6,6,6,6,6,4,6,6,2,4,6,2,8,6,6,6,6,4,6,4,6,7,8,7,6,6,7,7,7,7,7,7,7,7,2,7,7,7,8,8,7,7,7,7,7,8,7,7,8,8,8,7,6,6,6,6,6,6,6,6,6,6,5,2,7,6,5,6,6,7,7,7,4,4,3,2,4,4,4,4,5,2,4,4,3,6,6,3,4,4,6,8,3],mem_use=Math.floor(100*Math.random())+1,scalexy=2;sel_x1=Math.floor(Math.random()*pv_cols),sel_y1=Math.floor(10*Math.random()),sel_x2=sel_x1+1+Math.floor(Math.random()*(pv_cols-sel_x1)),sel_y2=sel_y1+1+Math.floor(5*Math.random());const vis_rows=Math.floor(192/pv_cell_h),cursor_pos=Math.floor(vis_rows/2)-1,firstrow=5-cursor_pos,sel_sx1=pv_border_w+(sel_x1-0)*pv_cellw,sel_sx2=sel_sx1+(sel_x2-sel_x1)*pv_cellw,sel_sy1=(sel_y1-firstrow)*pv_cell_h,sel_sy2=sel_sy1+(sel_y2-sel_y1)*pv_cell_h,effective_width=pv_border_w+pv_cols*pv_cellw,tobkitSimilarCols={col_light_ctrl_disabled:"col_light_bg",col_dark_ctrl_disabled:"col_medium_bg",col_selected_tab:"col_light_bg",col_unselected_tab:"col_medium_bg",col_list_1:"col_medium_bg",col_list_2:"col_light_bg",col_scrollbar_bg1:"col_medium_bg",col_scrollbar_bg2:"col_light_bg",col_scrollbar_inactive:"col_dark_ctrl",col_scrollbar_active:"col_light_ctrl",col_scrollbar_arr_bg1:"col_dark_ctrl",col_scrollbar_arr_bg2:"col_light_ctrl",col_tab_outline:"col_outline",col_icon_tab:"col_icon",col_env_bg:"col_bg",col_env_line:"col_dark_ctrl",col_env_pt:"col_light_ctrl",col_env_pt_border:"col_outline",col_env_pt_border_active:"col_signal",col_smp_bg:"col_bg",col_smp_bg_sel:"col_light_ctrl",col_pv_bg:"col_bg",col_pv_lines:"col_light_bg",col_pv_lines_record:"col_dark_ctrl",col_pv_cb_col1:"col_medium_bg",col_pv_cb_col2:"col_light_bg",col_pv_cb_col1_highlight:"col_list_highlight1",col_pv_cb_col2_highlight:"col_list_highlight2",col_pv_left_numbers:"col_list_highlight1",col_pv_pb:"col_outline",col_pv_pb_cell:"col_outline",col_pv_mutesolo_col1:"col_medium_bg",col_pv_mutesolo_col2:"col_light_bg",col_pv_mutesolo_col1_highlight:"col_list_highlight1",col_pv_mutesolo_col2_highlight:"col_list_highlight2",col_list_sep_vertical:"col_sepline",col_tb_bg:"col_dark_ctrl",col_tb_fg_off:"col_text_bt",col_tb_fg_on:"col_light_ctrl"};function updateColsFrom(o){if(lockcols){for(const[e,t]of Object.entries(tobkitSimilarCols))if(t==o){colours[e]=colours[o];const t=cols_ordered.indexOf(e);t>=0&&update_swatch(t)}for(const[e,t]of Object.entries(tobkitSimilarCols))if(e==o&&colours[t]){colours[o]=colours[t];const e=cols_ordered.indexOf(o);e>=0&&update_swatch(e)}}}function stringToRGB15(o){const e=parseInt(o.substr(0,2),16),t=parseInt(o.substr(2,2),16);return parseInt(o.substr(4,2),16)>>3<<10|t>>3<<5|e>>3|32768}function interpolateColor(o,e,t){return((31&o)-(31&e))*t+((31&e)<<12)>>12|((o>>5&31)-(e>>5&31))*t+((e>>5&31)<<12)>>12<<5|((o>>10&31)-(e>>10&31))*t+((e>>10&31)<<12)>>12<<10|32768}function drawPixel(o,e,t,r){const l=255*(31&t)/31,a=255*(t>>5&31)/31,c=255*(t>>10&31)/31;r.fillStyle=`rgb(${l},${a},${c})`,r.fillRect(o*scalexy,e*scalexy,scalexy,scalexy)}function drawFullBox(o,e,t,r,l,a){const c=255*(31&l)/31,n=255*(l>>5&31)/31,_=255*(l>>10&31)/31;a.fillStyle=`rgb(${c},${n},${_})`,a.fillRect(o*scalexy,e*scalexy,t*scalexy,r*scalexy)}function drawGradient(o,e,t,r,l,a,c){if(l==a)return void drawFullBox(o,e,t,r,l,c);const n=Math.floor(4096/r);let _=0;for(let s=0;s>5&31)/31,d=255*(r>>10&31)/31;c.fillStyle=`rgb(${n},${i},${d})`,c.fillRect(o*scalexy,(e+s)*scalexy,t*scalexy,1*scalexy)}}function drawBorder(o,e,t,r,l,a){drawFullBox(o,e,t,1,l,a),drawFullBox(o,e+r-1,t,1,l,a),drawFullBox(o,e,1,r,l,a),drawFullBox(o+t-1,e,1,r,l,a)}function drawHLine(o,e,t,r,l){drawFullBox(o,e,t,1,r,l)}function drawVLine(o,e,t,r,l){drawFullBox(o,e,1,t,r,l)}function drawString(o,e,t,r,l,a,c){if(!font_loaded)return;const n=document.createElement("canvas");n.width=font_img.width,n.height=font_img.height;const _=n.getContext("2d");_.drawImage(font_img,0,0);const s=_.getImageData(0,0,font_img.width,font_img.height).data;let i=0;for(let n of o){const o=n.charCodeAt(0),_=font_index[o],d=font_widths[_];if(l&&i+d>l)break;const u=a?Math.min(11,a):11;for(let o=0;o>5&31)/31,_=255*(r>>10&31)/31;l.fillStyle=`rgb(${c},${n},${_})`;for(let r=0;r<5;r++)for(let c=0;c<3;c++){const n=120*r+3*o+c;a[Math.floor(n/8)]&1<.3&&(drawMiniChar(g[d%12],s,i,c,a),drawMiniChar(b[d%12]?38:37,s+pv_char_w,i,c,a),drawMiniChar(Math.floor(d/12),s+2*pv_char_w,i,c,a)),Math.random()>.5&&drawHexByte(u+1,s+3*pv_char_w+1,i,n,a),Math.random()>.5&&drawHexByte(h,s+5*pv_char_w+2,i,_,a)}function drawGradientIcon(o,e,t,r,l,a){if(!logo_loaded)return;const c=stringToRGB15(colours.col_light_ctrl),n=stringToRGB15(colours.col_dark_ctrl),_=stringToRGB15(colours.col_outline),s=document.createElement("canvas");s.width=l.width,s.height=l.height;const i=s.getContext("2d");i.drawImage(l,0,0);const d=i.getImageData(0,0,l.width,l.height).data;for(let s=0;s128&&n<128&&u>128||drawPixel(o+r,e+s,c<128&&n<128&&u<128?_:i,a)}}}function drawPiano(o,e,t,r,l){if(!piano_loaded)return;const a=document.createElement("canvas");a.width=piano_img.width,a.height=piano_img.height;const c=a.getContext("2d");c.drawImage(piano_img,0,0);const n=c.getImageData(0,0,piano_img.width,piano_img.height).data;for(let a=0;a>3<<10|_>>3<<5|c>>3|32768,l)}}function drawButton(o,e,t,r,l,a,c){const n=stringToRGB15(colours.col_light_ctrl),_=stringToRGB15(colours.col_dark_ctrl),s=stringToRGB15(colours.col_outline),i=stringToRGB15(colours.col_text_bt);a?drawGradient(o+1,e+1,t-2,r-2,n,_,c):drawGradient(o+1,e+1,t-2,r-2,_,n,c),drawBorder(o,e,t,r,s,c);let d=0;for(let o of l){const e=o.charCodeAt(0),t=font_index[e];d+=font_widths[t]+1}d-=1,drawString(l,o+(t-d)/2|0,e+r/2-5|0,i,255,255,c)}function drawBitButton(o,e,t,r,l,a,c,n,_,s,i){const d=stringToRGB15(colours.col_light_ctrl),u=stringToRGB15(colours.col_dark_ctrl),h=stringToRGB15(colours.col_light_ctrl_disabled),g=stringToRGB15(colours.col_dark_ctrl_disabled),b=stringToRGB15(colours.col_outline),m=stringToRGB15(colours.col_icon);Math.random()<=.5?a?drawGradient(o+1,e+1,t-2,r-2,d,u,i):drawGradient(o+1,e+1,t-2,r-2,u,d,i):drawGradient(o+1,e+1,t-2,r-2,g,h,i),drawBorder(o,e,t,r,b,i),drawMonochromeIcon(o+_,e+s,n,c,l,m,i)}function drawCheckbox(o,e,t,r,l,a,c,n){const _=stringToRGB15(colours.col_light_ctrl),s=stringToRGB15(colours.col_dark_ctrl),i=stringToRGB15(colours.col_outline),d=stringToRGB15(colours.col_text),u=stringToRGB15(colours.col_checkmark);c?drawFullBox(o,e,11,3,stringToRGB15(colours.col_bg),n):drawFullBox(o,e,11,1,stringToRGB15(colours.col_light_bg),n),drawBorder(o+1,e+3,9,9,i,n),drawGradient(o+2,e+4,7,7,_,s,n),a&&drawMonochromeIcon(o+1,e,10,10,"haken",u,n);let h=0;for(let o of l){const e=o.charCodeAt(0),t=font_index[e];h+=font_widths[t]+1}h-=1,drawString(l,13+o,2+e,c?stringToRGB15(colours.col_text_light):d,255,255,n)}function drawTogglebutton(o,e,t,r,l,a,c,n){const _=stringToRGB15(colours.col_tb_bg),s=stringToRGB15(colours.col_outline),i=stringToRGB15(colours.col_tb_fg_on),d=stringToRGB15(colours.col_tb_fg_off),u=stringToRGB15(colours.col_signal_off);drawFullBox(o+1,e+1,t-2,r-2,_,n),drawBorder(o,e,t,r,s,n);const h=a?i:c?u:d;if(c)drawMonochromeIcon(o+2,e+2,12,12,c,h,n);else{let a=0;for(let o of l){const e=o.charCodeAt(0),t=font_index[e];a+=font_widths[t]+1}a>0&&(a-=1),drawString(l,o+Math.max(2,(t-a)/2|0),e+r/2-5|0,h,255,255,n)}}function drawLabel(o,e,t,r,l,a,c){drawString(l,o,e+r/2-5|0,stringToRGB15(a?colours.col_text_light:colours.col_text),255,255,c)}function drawNumberBox(o,e,t,r,l,a,c){const n=stringToRGB15(colours.col_light_ctrl),_=stringToRGB15(colours.col_dark_ctrl),s=stringToRGB15(colours.col_outline),i=stringToRGB15(colours.col_icon),d=stringToRGB15(colours.col_lighter_bg),u=stringToRGB15(colours.col_text_value);drawGradient(o+1,e+1,8,8,n,_,a);for(let t=0;t<3;t++)for(let r=-t;r<=t;r++)drawPixel(o+4+r,e+t+3,i,a);drawBorder(o,e,9,9,s,a),drawGradient(o+1,e+8,8,8,n,_,a);for(let t=2;t>=0;t--)for(let r=-t;r<=t;r++)drawPixel(o+4+r,e-t+13,i,a);drawBorder(o,e+8,9,9,s,a),drawFullBox(o+9,e+1,t-9,r-1,d,a),drawString(String(l).padStart(2," "),1==c?o+6:o+10,e+5,u,255,255,a),drawBorder(o,e,t,r,s,a)}function drawNumberSlider(o,e,t,r,l,a,c){const n=stringToRGB15(colours.col_light_ctrl),_=stringToRGB15(colours.col_dark_ctrl),s=stringToRGB15(colours.col_outline),i=stringToRGB15(colours.col_icon),d=stringToRGB15(colours.col_lighter_bg),u=stringToRGB15(colours.col_text_value);drawGradient(o+1,e+1,8,15,n,_,c);for(let t=0;t<3;t++)for(let r=-t;r<=t;r++)drawPixel(o+4+r,e+t+3,i,c);drawVLine(o+4,e+6,5,s,c);for(let t=2;t>=0;t--)for(let r=-t;r<=t;r++)drawPixel(o+4+r,e-t+13,i,c);drawBorder(o,e,9,17,s,c),drawFullBox(o+9,e+1,t-10,r-2,d,c);drawString(a?l.toString(16).padStart(2," "):String(l).padStart(3," "),o+10,e+5,u,255,255,c),drawBorder(o,e,t,r,s,c)}function drawMemoryIndicator(o,e,t,r,l){const a=stringToRGB15(colours.col_outline),c=stringToRGB15(colours.col_light_bg),n=stringToRGB15(colours.col_mem_ok),_=stringToRGB15(colours.col_mem_warn),s=stringToRGB15(colours.col_mem_alert),i=Math.floor((t-2)*mem_use/100);let d;d=mem_use<62?n:mem_use<78?interpolateColor(_,n,mem_use-62<<8):mem_use<94?interpolateColor(s,_,mem_use-78<<8):s,drawBorder(o,e,t,r,a,l),drawFullBox(o+1,e+1,t-2,r-2,c,l),drawFullBox(o+1,e+1,i,r-2,d,l)}function drawListBox(o,e,t,r,l,a,c){const n=11,_=Math.floor((r-1)/n),s=stringToRGB15(colours.col_outline),i=stringToRGB15(colours.col_sepline),d=stringToRGB15(colours.col_list_sep_vertical),u=stringToRGB15(colours.col_list_1),h=stringToRGB15(colours.col_list_2),g=stringToRGB15(colours.col_list_highlight1),b=stringToRGB15(colours.col_list_highlight2),m=stringToRGB15(colours.col_lighter_bg),f=stringToRGB15(colours.col_scrollbar_arr_bg2),p=stringToRGB15(colours.col_scrollbar_arr_bg1),w=stringToRGB15(colours.col_text_lb),v=stringToRGB15(colours.col_text_lb_highlight);for(let r=0;r<_-1;r++)drawHLine(o+1,e+n*(r+1),t-9-1,i,a);for(let r=0;r<_;r++){let l=u,c=h;0==r?(l=g,c=b):1==r&&(l=h,c=m),drawGradient(o+1,e+n*r+1,t-9-1,10,l,c,a)}l&&drawVLine(o+17,e+1,r-2,d,a),drawGradient(o+t-9+1,e+1,8,8,f,p,a);for(let r=0;r<3;r++)for(let l=-r;l<=r;l++)drawPixel(o+t-9+4+l,e+r+3,s,a);drawBorder(o+t-9,e,9,9,s,a),drawGradient(o+t-9+1,e+r-9,8,8,f,p,a);for(let l=2;l>=0;l--)for(let c=-l;c<=l;c++)drawPixel(o+t-9+4+c,e-l+r-4,s,a);drawBorder(o+t-9,e+r-9,9,9,s,a),drawBorder(o+t-9,e,9,r,s,a),drawGradient(o+t-9+1,e+9,7,r-18,stringToRGB15(colours.col_scrollbar_bg1),stringToRGB15(colours.col_scrollbar_bg2),a);if(!0!==c&&(drawFullBox(o+t-9+1,e+9+0,7,20,stringToRGB15(colours.col_scrollbar_inactive),a),drawBorder(o+t-9,e+9+0,9,20,s,a)),l){for(let t=0;t",!1,fb_sub_samped),drawButton(55,47,14,12,"<",!1,fb_sub_samped),drawButton(55,21,29,12,"ins",!1,fb_sub_samped),drawButton(55,60,29,12,"del",!1,fb_sub_samped),drawButton(55,34,29,12,"cln",!1,fb_sub_samped),drawGradientIcon(98,1,80,17,logo_img,fb_sub_samped),drawBitButton(180,3,23,15,"icon_play",!1,12,12,5,0,fb_sub_samped),drawBitButton(204,3,23,15,"icon_stop",!0,12,12,5,0,fb_sub_samped),drawBitButton(236,1,19,19,"icon_flp",!1,15,15,2,2,fb_sub_samped),drawTogglebutton(55,74,29,12,"lock",!0,null,fb_sub_samped),drawTogglebutton(55,87,29,12,"loop",!1,null,fb_sub_samped),drawTogglebutton(141,136,16,16,"",!1,"icon_record",fb_sub_samped),drawTogglebutton(165,20,10,10,"+",!1,null,fb_sub_samped),drawCheckbox(179,18,30,12,"scr lock",!0,!0,fb_sub_samped),drawLabel(87,48,50,12,"ptn len:",!1,fb_sub_samped),drawNumberSlider(105,60,32,17,16,!0,fb_sub_samped),drawLabel(87,22,48,12,"chn: 4",!1,fb_sub_samped),drawButton(112,34,12,12,"-",!1,fb_sub_samped),drawButton(125,34,12,12,"+",!1,fb_sub_samped),drawLabel(4,103,32,12,"tmp",!1,fb_sub_samped),drawLabel(38,103,32,12,"bpm",!1,fb_sub_samped),drawLabel(72,103,46,12,"restart",!1,fb_sub_samped),drawNumberBox(4,115,32,17,6,fb_sub_samped),drawLabel(182,126,22,12,"add",!0,fb_sub_samped),drawLabel(206,126,25,12,"oct",!0,fb_sub_samped),drawNumberBox(185,135,18,17,6,fb_sub_samped,!0),drawNumberBox(206,135,18,17,4,fb_sub_samped,!0),drawNumberSlider(38,115,32,17,120,!1,fb_sub_samped),drawNumberSlider(72,115,32,17,0,!0,fb_sub_samped)}function drawSub(){drawFullBox(0,0,256,192,stringToRGB15(colours.col_bg),fb_sub),drawTabbox(1,1,139,151,fb_sub),drawListBox(4,21,50,78,!0,fb_sub),drawButton(70,47,14,12,">",!1,fb_sub),drawButton(55,47,14,12,"<",!1,fb_sub),drawButton(55,21,29,12,"ins",!1,fb_sub),drawButton(55,60,29,12,"del",!1,fb_sub),drawButton(55,34,29,12,"cln",!1,fb_sub),drawGradientIcon(98,1,80,17,logo_img,fb_sub),drawBitButton(180,3,23,15,"icon_play",!1,12,12,5,0,fb_sub),drawBitButton(204,3,23,15,"icon_stop",!0,12,12,5,0,fb_sub),drawBitButton(236,1,19,19,"icon_flp",!1,15,15,2,2,fb_sub),drawTogglebutton(55,74,29,12,"lock",!0,null,fb_sub),drawTogglebutton(55,87,29,12,"loop",!1,null,fb_sub),drawTogglebutton(141,136,16,16,"",!1,"icon_record",fb_sub),drawTogglebutton(165,20,10,10,"+",!1,null,fb_sub),drawCheckbox(179,18,30,12,"scr lock",!0,!0,fb_sub),drawLabel(87,48,50,12,"ptn len:",!1,fb_sub),drawNumberSlider(105,60,32,17,16,!0,fb_sub),drawLabel(87,22,48,12,"chn: 4",!1,fb_sub),drawButton(112,34,12,12,"-",!1,fb_sub),drawButton(125,34,12,12,"+",!1,fb_sub),drawLabel(4,103,32,12,"tmp",!1,fb_sub),drawLabel(38,103,32,12,"bpm",!1,fb_sub),drawLabel(72,103,46,12,"restart",!1,fb_sub),drawNumberBox(4,115,32,17,6,fb_sub),drawLabel(182,126,22,12,"add",!0,fb_sub),drawLabel(206,126,25,12,"oct",!0,fb_sub),drawNumberBox(185,135,18,17,6,fb_sub,!0),drawNumberBox(206,135,18,17,4,fb_sub,!0),drawNumberSlider(38,115,32,17,120,!1,fb_sub),drawNumberSlider(72,115,32,17,0,!0,fb_sub),drawLabel(4,134,113,14,"unnamed",!1,fb_sub),drawButton(118,134,20,14,"...",!1,fb_sub),drawButton(141,19,23,12,"ren",!1,fb_sub),drawButton(107,116,30,14,"zap!",!1,fb_sub),drawLabel(87,78,52,12,"ram use",!1,fb_sub),drawMemoryIndicator(87,90,50,8,fb_sub),drawListBox(141,32,114,89,!0,fb_sub),drawBitButton(225,127,14,12,"icon_undo",!1,8,8,3,2,fb_sub),drawBitButton(241,127,14,12,"icon_redo",!1,8,8,3,2,fb_sub),drawButton(225,140,30,12,"ins",!1,fb_sub),drawButton(225,153,30,12,"del",!1,fb_sub),drawButton(225,166,30,12,"clr",!1,fb_sub),drawButton(225,179,30,12,"--",!1,fb_sub),drawPiano(0,152,224,40,fb_sub)}function drawMain(){if(!font_loaded||!font_3x5_loaded)return;const o=stringToRGB15(colours.col_pv_bg),e=255*(31&o)/31,t=255*(o>>5&31)/31,r=255*(o>>10&31)/31;fb_main.fillStyle=`rgb(${e},${t},${r})`,fb_main.fillRect(0,0,256*scalexy,192*scalexy);const l=stringToRGB15(colours.col_pv_lines),a=stringToRGB15(colours.col_pv_pb),c=stringToRGB15(colours.col_pv_pb_cell),n=stringToRGB15(colours.col_pv_left_numbers),_=stringToRGB15(colours.col_pv_left_numbers_highlight),s=stringToRGB15(colours.col_pv_chn);if(!(sel_sx1>=effective_width||sel_sx2<=0||sel_sy1>=192||sel_sy2<=0)){const o=Math.max(sel_sx1,0),e=Math.min(sel_sx2,effective_width),t=Math.max(sel_sy1,0);drawFullBox(o,t,e-o,Math.min(sel_sy2,192)-t+1,stringToRGB15(colours.col_pv_cb_sel_highlight),fb_main)}for(let o=0;o<=vis_rows;o++){const e=o-cursor_pos+5;e>=0&&e<=pv_rows&&(e%4==0?drawHLine(0,pv_cell_h*o,pv_border_w+pv_cols*pv_cellw,l,fb_main):drawHLine(pv_border_w,pv_cell_h*o,pv_cols*pv_cellw,stringToRGB15(colours.col_pv_sublines),fb_main))}for(let o=0;o<=pv_cols;o++)drawVLine(pv_border_w-1+o*pv_cellw,0,192,l,fb_main);if(drawGradient(0,pv_cursorbar_y,pv_border_w+pv_cols*pv_cellw,pv_cell_h,stringToRGB15(colours.col_pv_cb_col1),stringToRGB15(colours.col_pv_cb_col2),fb_main),drawBorder(0,pv_cursorbar_y,pv_border_w+pv_cols*pv_cellw,pv_cell_h+1,a,fb_main),sel_sy1<=pv_cursorbar_y+1&&sel_sy2>=pv_cursorbar_y+1+pv_cell_h-1&&sel_sx1<=pv_border_w+pv_cols*pv_cellw&&sel_sx2>=pv_border_w){const o=Math.max(sel_sx1,pv_border_w+1);drawFullBox(o,pv_cursorbar_y+1,sel_sx2-o-1,pv_cell_h-1,stringToRGB15(colours.col_pv_cb_sel_highlight),fb_main)}drawFullBox(pv_border_w-1,pv_cursorbar_y,pv_cellw+1,pv_cell_h+1,c,fb_main),drawGradient(pv_border_w,pv_cursorbar_y+1,pv_cellw-1,pv_cell_h-1,stringToRGB15(colours.col_pv_cb_col1_highlight),stringToRGB15(colours.col_pv_cb_col2_highlight),fb_main);for(let o=5-cursor_pos;o<=5+cursor_pos+1;o++)o>=0&&o=0&&firstrow+ecols_ordered.indexOf(o)+"="+colours[o]+" ; "+colscheme[o].name)).join("\n"),t=new Blob([e],{type:"text/plain"}),r=document.createElement("a");r.href=URL.createObjectURL(t),o.endsWith(".nttheme")?r.download=o:r.download=o+".nttheme",r.click()}function select_swatch(o){active=o,document.querySelectorAll(".swatch").forEach(((e,t)=>{e.classList.toggle("active",cols_ordered[t]==o)})),colours[o]&&color_to_pos(tinycolor("#"+colours[o]))}function update_input(){inp.value=cols_ordered.map((o=>cols_ordered.indexOf(o)+"="+colours[o]+" ; "+colscheme[o].name)).join("\n")}function update_swatch(o){const e=swatch_list.children[2*o],t=cols_ordered[o];e.querySelector(".swatchcol").style.backgroundColor="#"+colours[t]}function parse_theme(o){const e=o.split("\n"),t={};let r=0;for(let o of e){r++;const e=o.trim();if(!e)continue;const l=e.match(/^(\d+)=([0-9a-fA-F]{6})/);if(!l)return parseres.textContent=`!!line ${r}`,null;const a=parseInt(l[1],10),c=l[2].toLowerCase();if(a<0||a>=cols_ordered.length)return parseres.textContent=`!!line ${r} key ${a} out of bounds (max ${cols_ordered.length-1})`,null;const n=cols_ordered[a];n&&(t[n]=c)}for(const o of cols_ordered)t[o]||(t[o]="000000");return t}function loadDefCols(){if(!(Object.keys(colours).length>0)||confirm("lose progress and use default skin?")){colours={},base_colours={};for(const o of cols_ordered)colours[o]=colscheme[o].hex,base_colours[o]=colscheme[o].hex;update_input(),inp.disabled=!1,load_btn.disabled=!1,parseres.textContent="";for(let o=0;o=0&&update_swatch(o),update_input(),redraw()}}function get_hue_colour(o){o.preventDefault();const e=hue_canvas.getBoundingClientRect();let t=o.pageX-e.left;t=Math.max(0,Math.min(e.width,t)),hue=t/e.width*360;const r="hsl("+hue+",100%,50%)";draw_spectrum(r),hue_cursor.style.left=t+"px",hue_cursor.style.backgroundColor=r;const l=tinycolor("hsl "+hue+" "+sat+" "+lit);if(spec_cursor.style.backgroundColor=l.toHexString(),active){colours[active]=l.toHex(),base_colours[active]=l.toHex(),updateColsFrom(active);const o=cols_ordered.indexOf(active);o>=0&&update_swatch(o),update_input(),redraw()}}function rgbToHsl(o,e,t){o/=255,e/=255,t/=255;let r=Math.min(o,e,t),l=Math.max(o,e,t),a=l-r,c=0,n=0,_=0;return c=0===a?0:l===o?(e-t)/a%6:l===e?(t-o)/a+2:(o-e)/a+4,c=Math.round(60*c),c<0&&(c+=360),_=(l+r)/2,n=0===a?0:a/(1-Math.abs(2*_-1)),n=+(100*n).toFixed(1),_=+(100*_).toFixed(1),[c,n,_]}spec_canvas.addEventListener("mousedown",(function(o){get_spec_color(o),spec_cursor.classList.add("dragging");const e=o=>get_spec_color(o),t=()=>{spec_cursor.classList.remove("dragging"),window.removeEventListener("mousemove",e),window.removeEventListener("mouseup",t)};window.addEventListener("mousemove",e),window.addEventListener("mouseup",t)})),hue_canvas.addEventListener("mousedown",(function(o){get_hue_colour(o),hue_cursor.classList.add("dragging");const e=o=>get_hue_colour(o),t=()=>{hue_cursor.classList.remove("dragging"),window.removeEventListener("mousemove",e),window.removeEventListener("mouseup",t)};window.addEventListener("mousemove",e),window.addEventListener("mouseup",t)}));const hslToRgb=(o,e,t)=>{t/=100;const r=e=>(e+o/30)%12,l=(e/=100)*Math.min(t,1-t),a=o=>t-l*Math.max(-1,Math.min(r(o)-3,Math.min(9-r(o),1)));return[Math.round(255*a(0)),Math.round(255*a(8)),Math.round(255*a(4))]};function stringToHsl(o){return rgbToHsl(parseInt(o.substr(0,2),16),parseInt(o.substr(2,2),16),parseInt(o.substr(4,2),16))}function hslToString(o,e,t){const[r,l,a]=hslToRgb(o,e,t);return(r<<16|l<<8|a).toString(16).padStart(6,"0")}function hueshift(o,e){const[t,r,l]=stringToHsl(o);return hslToString((t+e)%360,r,l)}function randcols(){for(const o of cols_ordered){colours[o]=Math.floor(16777216*Math.random()).toString(16).padStart(6,"0"),base_colours[o]=colours[o];const e=cols_ordered.indexOf(o);e>=0&&update_swatch(e)}update_input(),redraw()}document.getElementById("hueshifter").addEventListener("input",(o=>{const e=parseInt(o.target.value,10);for(const o of cols_ordered){colours[o]=hueshift(base_colours[o],e);const t=cols_ordered.indexOf(o);t>=0&&update_swatch(t)}update_input(),redraw()})),swatch_list.innerHTML="";for(let o=0;oselect_swatch(e),swatch_list.appendChild(t),swatch_list.appendChild(a)}const grad=hue_ctx.createLinearGradient(0,0,hue_canvas.width,0);grad.addColorStop(0,"hsl(0,100%,50%)"),grad.addColorStop(.17,"hsl(61.2,100%,50%)"),grad.addColorStop(.33,"hsl(118.8,100%,50%)"),grad.addColorStop(.5,"hsl(180,100%,50%)"),grad.addColorStop(.67,"hsl(241.2,100%,50%)"),grad.addColorStop(.83,"hsl(298.8,100%,50%)"),grad.addColorStop(1,"hsl(360,100%,50%)"),hue_ctx.fillStyle=grad,hue_ctx.fillRect(0,0,hue_canvas.width,hue_canvas.height),draw_spectrum(),loadDefCols(),document.getElementById("cb_lock").addEventListener("change",(o=>{lockcols=o.target.checked})); From e6593eef15ff89d19c9b5ad02ac485d08095838f Mon Sep 17 00:00:00 2001 From: prayerie Date: Tue, 11 Nov 2025 21:46:30 +0000 Subject: [PATCH 2/2] update to more appropriate license --- LICENSE | 628 ++++++++++++++++++-------------------------------------- 1 file changed, 201 insertions(+), 427 deletions(-) diff --git a/LICENSE b/LICENSE index 2d58298..d645695 100644 --- a/LICENSE +++ b/LICENSE @@ -1,428 +1,202 @@ -Attribution-ShareAlike 4.0 International - -======================================================================= - -Creative Commons Corporation ("Creative Commons") is not a law firm and -does not provide legal services or legal advice. Distribution of -Creative Commons public licenses does not create a lawyer-client or -other relationship. Creative Commons makes its licenses and related -information available on an "as-is" basis. Creative Commons gives no -warranties regarding its licenses, any material licensed under their -terms and conditions, or any related information. Creative Commons -disclaims all liability for damages resulting from their use to the -fullest extent possible. - -Using Creative Commons Public Licenses - -Creative Commons public licenses provide a standard set of terms and -conditions that creators and other rights holders may use to share -original works of authorship and other material subject to copyright -and certain other rights specified in the public license below. The -following considerations are for informational purposes only, are not -exhaustive, and do not form part of our licenses. - - Considerations for licensors: Our public licenses are - intended for use by those authorized to give the public - permission to use material in ways otherwise restricted by - copyright and certain other rights. Our licenses are - irrevocable. Licensors should read and understand the terms - and conditions of the license they choose before applying it. - Licensors should also secure all rights necessary before - applying our licenses so that the public can reuse the - material as expected. Licensors should clearly mark any - material not subject to the license. This includes other CC- - licensed material, or material used under an exception or - limitation to copyright. More considerations for licensors: - wiki.creativecommons.org/Considerations_for_licensors - - Considerations for the public: By using one of our public - licenses, a licensor grants the public permission to use the - licensed material under specified terms and conditions. If - the licensor's permission is not necessary for any reason--for - example, because of any applicable exception or limitation to - copyright--then that use is not regulated by the license. Our - licenses grant only permissions under copyright and certain - other rights that a licensor has authority to grant. Use of - the licensed material may still be restricted for other - reasons, including because others have copyright or other - rights in the material. A licensor may make special requests, - such as asking that all changes be marked or described. - Although not required by our licenses, you are encouraged to - respect those requests where reasonable. More considerations - for the public: - wiki.creativecommons.org/Considerations_for_licensees - -======================================================================= - -Creative Commons Attribution-ShareAlike 4.0 International Public -License - -By exercising the Licensed Rights (defined below), You accept and agree -to be bound by the terms and conditions of this Creative Commons -Attribution-ShareAlike 4.0 International Public License ("Public -License"). To the extent this Public License may be interpreted as a -contract, You are granted the Licensed Rights in consideration of Your -acceptance of these terms and conditions, and the Licensor grants You -such rights in consideration of benefits the Licensor receives from -making the Licensed Material available under these terms and -conditions. - - -Section 1 -- Definitions. - - a. Adapted Material means material subject to Copyright and Similar - Rights that is derived from or based upon the Licensed Material - and in which the Licensed Material is translated, altered, - arranged, transformed, or otherwise modified in a manner requiring - permission under the Copyright and Similar Rights held by the - Licensor. For purposes of this Public License, where the Licensed - Material is a musical work, performance, or sound recording, - Adapted Material is always produced where the Licensed Material is - synched in timed relation with a moving image. - - b. Adapter's License means the license You apply to Your Copyright - and Similar Rights in Your contributions to Adapted Material in - accordance with the terms and conditions of this Public License. - - c. BY-SA Compatible License means a license listed at - creativecommons.org/compatiblelicenses, approved by Creative - Commons as essentially the equivalent of this Public License. - - d. Copyright and Similar Rights means copyright and/or similar rights - closely related to copyright including, without limitation, - performance, broadcast, sound recording, and Sui Generis Database - Rights, without regard to how the rights are labeled or - categorized. For purposes of this Public License, the rights - specified in Section 2(b)(1)-(2) are not Copyright and Similar - Rights. - - e. Effective Technological Measures means those measures that, in the - absence of proper authority, may not be circumvented under laws - fulfilling obligations under Article 11 of the WIPO Copyright - Treaty adopted on December 20, 1996, and/or similar international - agreements. - - f. Exceptions and Limitations means fair use, fair dealing, and/or - any other exception or limitation to Copyright and Similar Rights - that applies to Your use of the Licensed Material. - - g. License Elements means the license attributes listed in the name - of a Creative Commons Public License. The License Elements of this - Public License are Attribution and ShareAlike. - - h. Licensed Material means the artistic or literary work, database, - or other material to which the Licensor applied this Public - License. - - i. Licensed Rights means the rights granted to You subject to the - terms and conditions of this Public License, which are limited to - all Copyright and Similar Rights that apply to Your use of the - Licensed Material and that the Licensor has authority to license. - - j. Licensor means the individual(s) or entity(ies) granting rights - under this Public License. - - k. Share means to provide material to the public by any means or - process that requires permission under the Licensed Rights, such - as reproduction, public display, public performance, distribution, - dissemination, communication, or importation, and to make material - available to the public including in ways that members of the - public may access the material from a place and at a time - individually chosen by them. - - l. Sui Generis Database Rights means rights other than copyright - resulting from Directive 96/9/EC of the European Parliament and of - the Council of 11 March 1996 on the legal protection of databases, - as amended and/or succeeded, as well as other essentially - equivalent rights anywhere in the world. - - m. You means the individual or entity exercising the Licensed Rights - under this Public License. Your has a corresponding meaning. - - -Section 2 -- Scope. - - a. License grant. - - 1. Subject to the terms and conditions of this Public License, - the Licensor hereby grants You a worldwide, royalty-free, - non-sublicensable, non-exclusive, irrevocable license to - exercise the Licensed Rights in the Licensed Material to: - - a. reproduce and Share the Licensed Material, in whole or - in part; and - - b. produce, reproduce, and Share Adapted Material. - - 2. Exceptions and Limitations. For the avoidance of doubt, where - Exceptions and Limitations apply to Your use, this Public - License does not apply, and You do not need to comply with - its terms and conditions. - - 3. Term. The term of this Public License is specified in Section - 6(a). - - 4. Media and formats; technical modifications allowed. The - Licensor authorizes You to exercise the Licensed Rights in - all media and formats whether now known or hereafter created, - and to make technical modifications necessary to do so. The - Licensor waives and/or agrees not to assert any right or - authority to forbid You from making technical modifications - necessary to exercise the Licensed Rights, including - technical modifications necessary to circumvent Effective - Technological Measures. For purposes of this Public License, - simply making modifications authorized by this Section 2(a) - (4) never produces Adapted Material. - - 5. Downstream recipients. - - a. Offer from the Licensor -- Licensed Material. Every - recipient of the Licensed Material automatically - receives an offer from the Licensor to exercise the - Licensed Rights under the terms and conditions of this - Public License. - - b. Additional offer from the Licensor -- Adapted Material. - Every recipient of Adapted Material from You - automatically receives an offer from the Licensor to - exercise the Licensed Rights in the Adapted Material - under the conditions of the Adapter's License You apply. - - c. No downstream restrictions. You may not offer or impose - any additional or different terms or conditions on, or - apply any Effective Technological Measures to, the - Licensed Material if doing so restricts exercise of the - Licensed Rights by any recipient of the Licensed - Material. - - 6. No endorsement. Nothing in this Public License constitutes or - may be construed as permission to assert or imply that You - are, or that Your use of the Licensed Material is, connected - with, or sponsored, endorsed, or granted official status by, - the Licensor or others designated to receive attribution as - provided in Section 3(a)(1)(A)(i). - - b. Other rights. - - 1. Moral rights, such as the right of integrity, are not - licensed under this Public License, nor are publicity, - privacy, and/or other similar personality rights; however, to - the extent possible, the Licensor waives and/or agrees not to - assert any such rights held by the Licensor to the limited - extent necessary to allow You to exercise the Licensed - Rights, but not otherwise. - - 2. Patent and trademark rights are not licensed under this - Public License. - - 3. To the extent possible, the Licensor waives any right to - collect royalties from You for the exercise of the Licensed - Rights, whether directly or through a collecting society - under any voluntary or waivable statutory or compulsory - licensing scheme. In all other cases the Licensor expressly - reserves any right to collect such royalties. - - -Section 3 -- License Conditions. - -Your exercise of the Licensed Rights is expressly made subject to the -following conditions. - - a. Attribution. - - 1. If You Share the Licensed Material (including in modified - form), You must: - - a. retain the following if it is supplied by the Licensor - with the Licensed Material: - - i. identification of the creator(s) of the Licensed - Material and any others designated to receive - attribution, in any reasonable manner requested by - the Licensor (including by pseudonym if - designated); - - ii. a copyright notice; - - iii. a notice that refers to this Public License; - - iv. a notice that refers to the disclaimer of - warranties; - - v. a URI or hyperlink to the Licensed Material to the - extent reasonably practicable; - - b. indicate if You modified the Licensed Material and - retain an indication of any previous modifications; and - - c. indicate the Licensed Material is licensed under this - Public License, and include the text of, or the URI or - hyperlink to, this Public License. - - 2. You may satisfy the conditions in Section 3(a)(1) in any - reasonable manner based on the medium, means, and context in - which You Share the Licensed Material. For example, it may be - reasonable to satisfy the conditions by providing a URI or - hyperlink to a resource that includes the required - information. - - 3. If requested by the Licensor, You must remove any of the - information required by Section 3(a)(1)(A) to the extent - reasonably practicable. - - b. ShareAlike. - - In addition to the conditions in Section 3(a), if You Share - Adapted Material You produce, the following conditions also apply. - - 1. The Adapter's License You apply must be a Creative Commons - license with the same License Elements, this version or - later, or a BY-SA Compatible License. - - 2. You must include the text of, or the URI or hyperlink to, the - Adapter's License You apply. You may satisfy this condition - in any reasonable manner based on the medium, means, and - context in which You Share Adapted Material. - - 3. You may not offer or impose any additional or different terms - or conditions on, or apply any Effective Technological - Measures to, Adapted Material that restrict exercise of the - rights granted under the Adapter's License You apply. - - -Section 4 -- Sui Generis Database Rights. - -Where the Licensed Rights include Sui Generis Database Rights that -apply to Your use of the Licensed Material: - - a. for the avoidance of doubt, Section 2(a)(1) grants You the right - to extract, reuse, reproduce, and Share all or a substantial - portion of the contents of the database; - - b. if You include all or a substantial portion of the database - contents in a database in which You have Sui Generis Database - Rights, then the database in which You have Sui Generis Database - Rights (but not its individual contents) is Adapted Material, - including for purposes of Section 3(b); and - - c. You must comply with the conditions in Section 3(a) if You Share - all or a substantial portion of the contents of the database. - -For the avoidance of doubt, this Section 4 supplements and does not -replace Your obligations under this Public License where the Licensed -Rights include other Copyright and Similar Rights. - - -Section 5 -- Disclaimer of Warranties and Limitation of Liability. - - a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE - EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS - AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF - ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, - IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, - WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR - PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, - ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT - KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT - ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. - - b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE - TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, - NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, - INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, - COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR - USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN - ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR - DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR - IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. - - c. The disclaimer of warranties and limitation of liability provided - above shall be interpreted in a manner that, to the extent - possible, most closely approximates an absolute disclaimer and - waiver of all liability. - - -Section 6 -- Term and Termination. - - a. This Public License applies for the term of the Copyright and - Similar Rights licensed here. However, if You fail to comply with - this Public License, then Your rights under this Public License - terminate automatically. - - b. Where Your right to use the Licensed Material has terminated under - Section 6(a), it reinstates: - - 1. automatically as of the date the violation is cured, provided - it is cured within 30 days of Your discovery of the - violation; or - - 2. upon express reinstatement by the Licensor. - - For the avoidance of doubt, this Section 6(b) does not affect any - right the Licensor may have to seek remedies for Your violations - of this Public License. - - c. For the avoidance of doubt, the Licensor may also offer the - Licensed Material under separate terms or conditions or stop - distributing the Licensed Material at any time; however, doing so - will not terminate this Public License. - - d. Sections 1, 5, 6, 7, and 8 survive termination of this Public - License. - - -Section 7 -- Other Terms and Conditions. - - a. The Licensor shall not be bound by any additional or different - terms or conditions communicated by You unless expressly agreed. - - b. Any arrangements, understandings, or agreements regarding the - Licensed Material not stated herein are separate from and - independent of the terms and conditions of this Public License. - - -Section 8 -- Interpretation. - - a. For the avoidance of doubt, this Public License does not, and - shall not be interpreted to, reduce, limit, restrict, or impose - conditions on any use of the Licensed Material that could lawfully - be made without permission under this Public License. - - b. To the extent possible, if any provision of this Public License is - deemed unenforceable, it shall be automatically reformed to the - minimum extent necessary to make it enforceable. If the provision - cannot be reformed, it shall be severed from this Public License - without affecting the enforceability of the remaining terms and - conditions. - - c. No term or condition of this Public License will be waived and no - failure to comply consented to unless expressly agreed to by the - Licensor. - - d. Nothing in this Public License constitutes or may be interpreted - as a limitation upon, or waiver of, any privileges and immunities - that apply to the Licensor or You, including from the legal - processes of any jurisdiction or authority. - - -======================================================================= - -Creative Commons is not a party to its public -licenses. Notwithstanding, Creative Commons may elect to apply one of -its public licenses to material it publishes and in those instances -will be considered the “Licensor.” The text of the Creative Commons -public licenses is dedicated to the public domain under the CC0 Public -Domain Dedication. Except for the limited purpose of indicating that -material is shared under a Creative Commons public license or as -otherwise permitted by the Creative Commons policies published at -creativecommons.org/policies, Creative Commons does not authorize the -use of the trademark "Creative Commons" or any other trademark or logo -of Creative Commons without its prior written consent including, -without limitation, in connection with any unauthorized modifications -to any of its public licenses or any other arrangements, -understandings, or agreements concerning use of licensed material. For -the avoidance of doubt, this paragraph does not form part of the -public licenses. - -Creative Commons may be contacted at creativecommons.org. + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License.