From 0de44569b77c7ed71feb333995862af0e65d24ef Mon Sep 17 00:00:00 2001 From: DanS Date: Tue, 18 Aug 2026 15:39:43 -0500 Subject: [PATCH] feat(mining): thread-count stepper, adaptive tiles, dropdown click-through fix, xmrig version state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mining-tab UI improvements: - Thread selector: a centered [-] N [+] stepper (top-aligned in the header) to pick an exact thread count — number centered, -/+ step by one (clamped to [1, cores]), still typeable (commits on Enter so it doesn't restart the miner mid-typing). - Thread tiles now render at an adaptive step (1/2/4/8 by core count) plus 1 and the max, so a high-core CPU (e.g. a 192-thread EPYC) shows ~25 tiles instead of one-per-thread and no longer overflows the card. Unchanged for <=24-core machines. - Fix: clicking the X (or a row) in an open saved-pools / payout-address dropdown no longer bleeds through to the thread tiles / Mine button — the custom drawlist hit-tests now gate on IsPopupOpen(AnyPopup). - xmrig update button: shows "xmrig releases" when installed >= latest (numeric version compare), else "Update "; the "Current: " text and the button are subtle green when up to date and subtle orange when an update is available (neutral when either version is unknown). New i18n keys back-filled across all 8 languages; CJK subset font rebuilt for the new glyphs. Verified across full-node, lite, and Windows builds; the stepper layout confirmed via the UI sweep. Co-Authored-By: Claude Opus 4.8 (1M context) --- res/fonts/NotoSansCJK-Subset.ttf | Bin 670108 -> 671092 bytes res/lang/de.json | 4 + res/lang/es.json | 4 + res/lang/fr.json | 4 + res/lang/ja.json | 4 + res/lang/ko.json | 4 + res/lang/pt.json | 4 + res/lang/ru.json | 4 + res/lang/zh.json | 4 + src/ui/windows/mining_controls.cpp | 144 ++++++++++++++++++++++++++--- src/util/i18n.cpp | 4 + 11 files changed, 165 insertions(+), 15 deletions(-) diff --git a/res/fonts/NotoSansCJK-Subset.ttf b/res/fonts/NotoSansCJK-Subset.ttf index 5d58ab03d7cd0603adec2441a3b2912a41fc222c..955157817d2cad9dfb6c0a8c38449b4cf8afbd6d 100644 GIT binary patch delta 16020 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 delta 15410 zcmd6ucYF=m|Nq~&oO9-!tM}-=*EB?y6l6Dvh!P>udrv`{aMcKFb*>e?vshLM(a9={ z=tL*BV8dFy=l7a>6MR08@AvWe{r>yO<9TQ1%sKCV&YhV%Uc9Th_<7A)C9G#|647nH z;I2$KLGcEXvkN%cukCV#c|bv!$!uP zZTPGJS;=sSsLqq25q)~OC*L_w)F}}{7Z2+d7isAqjJ}4>_~65P4eM8-iboZar_E^F z6&W#NWKI$}lRN{1sbY+-U|XfFr1B@@xM~a(B*hj#f#XfOd@`WbXyCK%Y{}|T(DNl3 zOb^gP`EG8V;im8Wxp6?i+=_j=3vI7Za|g5RCX!DO3uSn+ z{dT<(=DDpry@`(@h)sIgw1{6<6@{c zx2*39L;mdtd?y=<4z?Y#4Yv)p4YKvM^|IAkaCC9|xt&_wvK~pEpFA@;Avq>FIyo|V zcyjmTPRSjUTO~J6c26!kjoy-9kO^iR@XNq;2W zPP&A0lhalbA;_4`Tj|`90=7QOs#@EM^xzH^#J#@s4pGb$`^cQNuR zm5VAKRUoQBiau^NG76icNQg^F)sWI5B}0mb6bP||u#UfU{ITQ0j;%Yk=-9ZUYll}I zo_BcK;bDiP9e(Z*)xo1f;|{JJ>UQAmU$lST{&D*Y?MJsS)UHwR+FCx4tfxDFDN7ERM3f_!$B!Q zKL#xbni(`bC@E-C(8Qn#K@mY^gPej&1ew~rX!EempKY$Rx!h)Fo9%7Zw5ivocHpYO zp@IDZy99O)>=@V~uzg@~V9UVf0om4ohXJ<&E(V+nI1{idV0*w%0qX;j0wx8F_y6So z-v5pN1OFKR2!AjCZ~Q&{8~WGuyXAMoFVpXw-xV2!{t!+nSN4)z`7+uOH? zuQklKi?6@0mv22^i?8PM!RNit3!i^|uKQ&AT=qHR^P5k)&jz2hKC66I`YiUD<1^D| zoKH8OFdtu^20pcXs{54jDeY6lr=U+h@3-C$z3+IR_5RiSi1$J7P2L;4*LpAWPVt`a zo!}kkJ<2=Md${)i?|$CBy~Djjz1w-^czyJG=k?s`_0;Q;*Ez5KUW>dIdL?^J^eX06 z*sFk-vBmTjNi7mubZ*h9MTZuFEqt2y`KFlXJI}v8|MJZ8oas5;bFAkW&sfi@p2a;2 zH@nzuakB-@rZo%nxaD!h zZE~r}nkMs`eBUIoi8ZcCbd$bKDmN+GL~H!6acbjLjqACubYJGa*nOCLfA{Y0;qD>s z9&UfRop#&ow$W{=+d{W7Zn18WZiQW+xMsNyb?xWs?%Ke$tgDl23D<(I`CPfnbC*n) zT`ucf5?vx)hPec|G9IPY-|b8g|RSrQZ$caD$W$T0VOKzXA) zH@8w?)tYjP{>6~@Pp;PYCI{b~=a$R@h^@ z@B&}@_Os4&$G7cn}fBgmXSkIcU=CiAgd zWIj=j%qJ(4`BWJ)pI$@ej1FWzC&_$Xk@-SfGGDw&=F6?geB~*bGpCXH+Iliy|C`J= z$CCMWAerxMCG$O3GG_&l`99?SQIgDmUMBN{;beZ)natUB$ozOIng8iZR`b(~WPUc9 z%r8ce`PCLOzwssWJ1BdDPpV-F}|0WCWy)A#MD4ymMmiV zekGPajab2k#0s?`R@jSJkrl*>wIEjfdtxQd6Dt)=%xNaEGWm#=y+Evd3oEgTC5ct) zO|0^_#H!RIR<#(hY6XZ@F9P-us}Tm?5UYs+wKfo|9Y?HA5V5-GU#~bgOsqbXG(f+G zKN4#+mYDNIVlLx|xeg=d){B_?Z^W9w*ruz9dDJJ?jEH$QCiacB60zn@iM4>$UdxI3 zR3YY@N~~2WVy*8H`}Pho|3kzA;c=UCU^B5Gc+qw^vEZe|+C3uH0qq^H6YGRXgnlH} zc{;H!KE%TEgKNaX!-;jRMy#6#E)wg$o>-3##CmdK)}Akk^+Nc1-y+txCb51o#QLWb z8*rQ0AVg*`1`lx~HZ+phu%C!U)FKwSomg~vVk71g8~K*lD1~y%`CkWX*0&|L0m3$7`%^NpO|W(o25v@lenz4FoI-4CGh*8i zvTd;Zm$SsSW4mKHv7HgbcHvxVVPd;?5=(1CY%i4TFGK7AqIvKNu|vrF;do+4CJ{Tj zj9B_iV!uM~G3!)f$7c~cv6$G&HN<{HNKe6|)991|0cYXmd3b&ygV-e$(&bEIS9=i4 zgmKq~61xtsudgR|V>Ypy;lysCer{bQcKac*yGYSJoWHk^SQZrC??~)-c>YIyVt*oH zf5JKI1BCP;is8{jVt=o{cB=9710rf3IM~>u1E? zRwDMU0(egBJ?iBHJo-3?*e66G=Q(kM2XSL>;-*2w&Ao`TMB=;xanY5y_C0Y~o2*<_ zC2sK|o^KZM{2z%Ilwc|GLebzo@xtSX7wJg6Xk+5V+=&0*HIV310@D5^o7dT0JJ-`XzBc82O!vxPM*Z0ajQN_>6d)gT#ZD z5O2Gccra*pns|rG#5?*B4?*}k9VZ@oig@RJ#Jk)l9$tocS9sUG2Js$$5bxETc<(jD z`<5o&Zv*lEw}=mPB0dPl4xUeZ$a3OC(Qnvw+~2|T$YR8!+=yGFqll0Ak@!eh7}J$_ z>;U3%qlw2KCZ3Q@Jh1}tF`bByg@AF@iH~1Rd;*xbo%p2J#3z3uKBYYIWLM%-#}l7+ zi1>6I|A6q%fVZ=z6Q2Vk=M^D7ABNf5692Ir@kOtQFZMzHm%xi<2;p)FU(ta0%9g}e z^(DS~2=O(eh_9VMeBFNH>mh8zUE)8X&rdLB6KY};4A`7be9J82TQ%a_l8J9`N_;2w zcV-aZb%b~-9NANdcp6f?cL(u(h~9pr?;vC!x@jeT7&}K0wj=Q9XbSOk9RFIC_^~#` zj}y2^{6r7pClQI0zYzazBJopGiJwLxo#{e61IC`k{<%BEFVrD^5sqAfk(b93zk;!u z@cddB@#{#*O{DU6J>qvzq<4|_EGvZGe?$C_+rnh`(z_{5_)hp$GAgONf6$_;aR`poZWH38O1G zL&Ah((>@YrPjHTel|_;e{v>2i5~?-{izJb+B8mJ%NEC=7QE)nmLI+3`aUxN4EQw<8 zNR&t+QL+(uNTO6K38zgYN*^Ur<{*i(*GZH&kf<=4L`5j9)SpC^8YHR)lBl+wL=E(> z*$KQRQF{nkMV%WY>R~|r_9Pl~0V}{;5)C_oT_hTn1AB2P^eysiRKkRG&oJ7g#ujxjPWW7MuF!fyt@JP^+8B|j*;-K3VsA|qU9kHtq}578^FIL zT7L(AA>mgH!~^Rm65qB1J4k$29n2=-k7)RBB@qCR1Lgqq30w+ZkZ6NYwwXjC$O3%8 zaDea!eIU_xAXp3FX>b>S2({AyQrzw?iS|fy``siuv;-+28~N|pmqbV8EuP<@TL)l3I1CEM_^y5csq0oBY$nmY zFjxSPrXG;j<0Ofm-N8QOzgGhiy(dxOVPCZOT|}ZE^4f1TiT)+QbnrKc z0Z79D7%&iF9)$jb62S!$gFOK1X9$cO(iYfA3?&c@;N;McB!&foEhL6ZFxZL@SQ=3Z zz^e#&92o{qlZe7L3JRhgk%(>vaBf5pSO_kY7+Doe1n4`e5r_q6NW>r_FZ*`&Td3&j};c~SxF)d`Aoxh zZyB(N#6BmmpTvF$+m93-r~?qPgH6Fb5{EKK9BvP8kT`;IM^RKqF$<19C4nz6k^YRt zuX9NpGlB&02Z`gTgX0)?q9Zs@;v}}#lP^j9)(<=&aSGGwbS;1iKT{0MB9Q@w87Qc; zlferT=Y|7p&%?;`m`)cW0c2cU0MPGJUjX5kgTV+k?8_1lepFb93^pm zF!Fz+Fo_!wegl@@97f_66yMrM;t@l)&fNE*?11iU28jD1!L>>!QzB2Cl=%Sp3pA*A7Ph$c6X zrou?GlmTx@%Qu&_{MgUGfV2X2z&6qfRt3vQEA$I#MZP1gs0V4qx|3GCJ!vI;Nh`@o zD`g{f~K=l`-)rbOnNUK=|Yy@{mtCdVz?Lwd%z`5G+s!o2;6rfMt ziQqTV>eUC+!7%_?^~-@t0MV;|gR}<4fHeRggTN`$8Wsldt|5dr@&+?Vb1nf8X6FfD zKWQ$F07B_<0z4ZH)R3B`pp&6nj_cE$AE>TwI~V>kmij@ zdEX?>7lyU$Kw7J@q_sx7-(=FhO(X5Q5v2J;ZUAHk{DS-kwj-?#3M;4vX>HxXThfA0 zlh!VpwDw`7b*K(5lGbq;X(8|;6!j4bqdLzdtqZ&i^CT^tfybnEy+vBLC8TwSyzWS6 zPmJjWg}t|s)&~*nOQiKHO6ruOe+oI%z|pd>EoI97NV7Ey_q* zbSu(EbR=yg`iw$IV<0#V;}Qy!mS`bu47?wUd|Kh%xM`$KKoL(&AZ=1V(k3JSNqb3~ zvIEZ#5%#Grc$(-(+V_a~bU65f^=Hy%K)_6NnDw5tIj|nLO4|Hhq%D|4nr$;_KNcfx z5eBBfxFzVn4Cj|&ims?n+A2hC6$G#90uGb58WCCT1G<9A01;VJ4s-@MUUQzbwQy|h zBGT5GVD!3C*vTeseJRiqbO&+Z9cdd7+70k@!&Y#Qw2h4ca<>uT{OKTRn-HbVQQ$dg zTOel(4Ez~RZ2d&qFN(D7CBR40cEW&Nh*m1br^3rLAEsia+aK-#5t;5EFvjLuiKlXf+kw9I*=U4ysR>i~Fs z18c+0yQJN2P1>DQ((bMx?cPSxvY`C_QPO_LRQ#haX@A1tzuZWB&J0T9yHdjQVA zi6!kV3hr$W0MFmG0k24VkK^|zN&656UXu0^A^x<9w44}{6bIgtH0&U0Yzp3!G<5^m znwOHaGIU^XNb+qYg)d1hKlq8Hw1RAsY7R*Y2Ij+W&G|Nv%pVCLus{;Yg5QEaNfz2q zvTzx&i)0b}Y+Ph5$)Xrj^f}359w3!u@gXEj)BtHDOHLwLsuMUtR_TNjr3-`UB+K}a zEUUl`lI5Ks={Aidp6$xUIM)=OV+EDXoWMzvp78V=$ZswHBG&?Pyny!E`c zZO27fqv&CoE|1BVs<;}h|3aX~sfnpiAj!zma~8{Ew#rvzk22{w=#+!!kd!|sn+kxr zIT_O4YFm6o) z>KK+yCYlOG3*kY!EizLUcgd4ygmD=ZPvz}aWWtKfTwNLVmMpYnp+y(IJ5#oUXK9~J zw0EaAIj<<3isg2yc}=#;H75F+?2>EDxogrbcUN7PB5U)&39G}d zOfuM&7$MZ5&O}4uz%YB~Y*;oFgNNzf+vAdrq(mWx(O?Ap8EKED9@(gzOtfaAMfVF& zr9Zcf_^Q=F6Ch7ee%qDnvZzy@5xROfj*j}C9#rEES+A0#F^i0P5$GpAN9vVhfGzlj zbjo#i_zl^hq(gIl2-3?Y!frSGvhBDby$$KMS2tt|y6cs;;HDf@&!Hc8Dky_=3`wWm z7`6vIvsor=lHWo6TI_DQB`aZ9Z@uJb zwU_s8dv^5JuD4~K+z!)kOQ$M%g{+(6DEdsuz6P$_P0=g<#BF=g>AUZ4OWzK8InyVK z!~CoEzL1|=+j$md(WB1};f@0RGwik>qGEIyV4S0eZPp#>gyL{GsZS3_$E`5xi*UWp z^P?IIpt|(5=mu=H3w-EE6b!&4U9^5Nz;Q;;ayITB^3H66;kxonv^rvr9v%N<@FvvS z7qOXk)%FNMwPQ{@vVGOA+M!lAIs<|;a)oY1$P(|$ZY&)oam;r6u51J+v+c&{#yia1 z^f^Xf8;@3c@|9agI)aED1^P%wcpRZ|tQ=;#4X5sayWkmm80?l>&|44ER@w~zuG(hY zlO=O2VB{({Ozl^qIdSy zTNuoFE4C%T(#CPl@WOsBzg#KT$qn)+xmo@!x5@2tr%Y9o)Kv9-YQ^7WNrQEcnoFeS ztNCP9Hf1A|TBNp-S#8Jf@MTq+I!=|<8I?f|)j4&ZoYh5jkzCbfb(!2$rn*7y>XynP z50$MRlb8BOeIy?XS)8byrJSW44Y5?TRHmVpx|VtrVQFA#L{SzOOJf>oX=?GHc#Egi z(t<`?T3hgIADLwea<&+8S(1}x@z(=~mJGC{qh;&omQ1vyp=B*vw&F@8g=(TD3oY4d zJ51a`#neu)3tXgP2v;$?q;&K`U~|S|9DdD)?5)!Jb(5BBKqfk++ePJxNz=u^ASkn& z_&@bfYQMb~${k~C!UUz8@cGDYkX>yW4A}}DaMFsI!XPxyr!)-JRXJMqXxM#M$8)mn zt!A|7$}=qa&@aDU(RM%b+;Fn@Tbt`$UaNnOqeYje$0@_^j2;2&D>P-JDHBbZ_F;J~ zS!lszMJK&QPs*2JdQ$Y3gSkdI(xfLvPg9zGlpgN9H2r6bp4>Dt>6)z=qAS9;6clCU ziq)e~9<7cF&|7suj$yh%dH~m=We)nxu`AQ#r$s6#~`x{RJcQ%6h9x z&B;=`b6(+$J=(}WgzCQNb~>tZFKTlKQj3Ce3-$}-STik7c8k-|=$@I| zJtMcbBT;(qFR9C`5J$~B*=Ng_gnsF#o2{qVUW&T^dMC#u%&=Sbb>+AeE!l%!Wyc~ZS z>IkTlecF9VM_xZi?SDBkAOiTFhI@IFSYPlm$ZEjX2VPyuJ(0IweOWMcHI6Tu|L(Ka zo`5f_Wplf?S&nrLqx5t**3ZwSYgeh4wmvKDE3Oq!SHE7*%vc&=sYOFXq{5i@`OB3W#m)KegJbR?|SWUTvj8>KBzt(YO{$qd2u+9iVu1SRJO(DqWqVM0Hl3r3vc1 zxJ=?fZ`2!Fsy?U>v<%lv zM9VEki&;KvZb%3FI`1KG&~kMkFCMdnT)oKXL46x`AKO?s=_K+EmkYlTD4AXQ@hn3wO8#^ z2h|~UL>*NbxHP=1ZmN4KOZ}@}s(0#>#b8mEQkDvqN|rj7dX`4G=xbr|u>@J#Swb!0 zxw;Z3(k%3GRPT3TA=_I{)HR&Q;=FJ!ecOVk?m z+EU$8!&1|J+DHYkHL6qUv~AW4S+C$e`A`|vdzE8h7GbfZo_--sMj3}Y5&WrGTjncS z&buV;6IWuKS(W;{=k$56^yj@Y*jr`qSN8K>IepJo>a{Fa+##aU=kAsDJ)6IN$}y_? z=TSB6qY_`sW*B9}?N$K=o771B#lrlNwnsQ+7-_5iMmF$niMu|sy9dvSiucw(bB{S{ zSZ@`d+l*8QcQ+44R+w}U>EKbw%~qY6Yd;VVPZ^E->d2B2TYX7_?w|-s#&Q8-pWWrSwoC7%claTBn6BV~Qaa(D5l=a; z;dRr?bX`7|&*_GIDPPh}`C7iFTX;rQoNlX{?jz>8$@ zI5Nl!w#fIgT&-MfXwn~P;c*sLh_9lCnCoRS0ne~@y_ao_;WODBHjmlZBDRDrV=LGy zwuY@^8`&ndg>7ZOupKOwWw7(?BD>12v%BmM_JqA=Z`ntV*Vj11Y%R=-^YXkBufnVG z8oU;-$K7}n?!kR*!AupiMSjBL(q6nT@6QMF!F)K6;v;wrpU)Ta6uz8q;@kLkzLW3f z`}hHVm}l_w{4&qvH~4M-7yp|-;s5d%{0)E4bA(Yap^5yWkSHQb2q#faR1#H1O;JbG z6HP@k@s0RSbP{2ro9H3>hyh}d7%C#g2oY0L#EFSwikOOD;^&ApVuP4x9L`G`ju<^n z7V}#3uDnpCR?d-ajp4J{TsEIAWGQSZTh3Op)od+W&wgT?+0Sen+s<~f-Rvy8z%H>& zc7xqxf3klVUNdH&xPhBE=lOUMUV>NPm3dWOo!8{Gd42BAoAPGd*LF@*<*dDVKR$pD z;zM`@kLDwJEMLHX@4ENB#|tp z;f;j3Vy)OH=g9f0fpS(J>KhfH+I)W0i9#WxX`ErdZQpz8*A$;njKRNhokwJ=pP)il*nUZ#d7XXS0%Vp8Q?d`!bl zk){!*SW|*&oN0n-GXAEjmZl#}vrY3Rq7<0VxH(Sj~=4s~X=9%U>=K1Cn^9u87^E&fJ^JW!j8*5fBhPk#AA7we) zS*(fH`fQwP%O*2S5*6&2B&yxllSH-GCyDBiH%a6IeVRy{>iFMNMTPuNQ$;RxOcmae zx8~n+e;&w#crb6zJE~5+vz3SOt}0Y@&YL}|OWy2JVLU~J^G&MT*Rw};=jT-qo~e4O zUaGh1qx!0T{DtbT2B?8*ken@~8Y~K_A!?{7Ey}B5YPgEfXOEnxBEQTa6_q=KTs}`B z`6Fh~WHCiW%SDbE#7o-e&gYqfXFQAyhW)9fxe77%`oEt+SL}1>CcFLr=R9g4T>tmE z%~uEzA-|-SmdShR!QVprtYw)ZU*Zttdl8N8+T$o%(Un5 zK32mA>~E}y&)5t5n#j4tidYb9qLY0kY{-3iE8c_mwl9Bqi{DZ#ejBm)9ptC~uNFQ1 zKXH`l{dvu6D4em<^~D;euW<2Vv=}SKVUb(sSlsmAaFCeXUvS81I7WB%bQnAgeuiK} zf5T8ilp)#>Zy0BoVwhz}F)TN%GHfxVs)n`~`PBe}udQnV)lc?gp3IB2RzbGk3Sb$Z z!Db^lm%mESWA-mn^8u;RzDiA9q{bODJuf-Ka#OR=o|aTSG5j3A$glG2{1(5*AMwZh zDSysi@pt@_FbJ~{A|G;A{BzD~=sByIo3ugpl#M~k>zObrhn4KC| ZSh=Pk{{TDElkxxn diff --git a/res/lang/de.json b/res/lang/de.json index 450dbc1..e799578 100644 --- a/res/lang/de.json +++ b/res/lang/de.json @@ -949,6 +949,9 @@ "mining_syncing_tooltip": "Blockchain synchronisiert...", "mining_tag": " · Mining", "mining_threads": "Mining-Threads", + "mining_threads_input_tooltip": "Genaue Thread-Anzahl eingeben (Enter zum Übernehmen)", + "mining_threads_minus_tooltip": "Weniger Threads", + "mining_threads_plus_tooltip": "Mehr Threads", "mining_to_save": "zum Speichern", "mining_today": "Heute", "mining_uptime": "Laufzeit", @@ -1785,6 +1788,7 @@ "xmrig_loading_releases": "Releases werden geladen…", "xmrig_none": "keiner", "xmrig_reinstall": "Neu installieren", + "xmrig_releases": "xmrig-Releases", "xmrig_stop_mining_first": "Stoppen Sie das Mining, bevor Sie den Miner aktualisieren.", "xmrig_unavailable_body": "Für diese Plattform ist kein Miner-Build verfügbar.", "xmrig_unavailable_title": "Miner-Updates nicht verfügbar", diff --git a/res/lang/es.json b/res/lang/es.json index 4bf7d17..0b912d7 100644 --- a/res/lang/es.json +++ b/res/lang/es.json @@ -949,6 +949,9 @@ "mining_syncing_tooltip": "El blockchain está sincronizando...", "mining_tag": " · Minería", "mining_threads": "Hilos de Minería", + "mining_threads_input_tooltip": "Escribe un número exacto de hilos (pulsa Enter para aplicar)", + "mining_threads_minus_tooltip": "Menos hilos", + "mining_threads_plus_tooltip": "Más hilos", "mining_to_save": "para guardar", "mining_today": "Hoy", "mining_uptime": "Tiempo activo", @@ -1785,6 +1788,7 @@ "xmrig_loading_releases": "Cargando versiones…", "xmrig_none": "ninguno", "xmrig_reinstall": "Reinstalar", + "xmrig_releases": "versiones de xmrig", "xmrig_stop_mining_first": "Detén la minería antes de actualizar el minero.", "xmrig_unavailable_body": "No hay ninguna versión del minero disponible para esta plataforma.", "xmrig_unavailable_title": "Actualizaciones del minero no disponibles", diff --git a/res/lang/fr.json b/res/lang/fr.json index 2030811..f28389b 100644 --- a/res/lang/fr.json +++ b/res/lang/fr.json @@ -949,6 +949,9 @@ "mining_syncing_tooltip": "La blockchain se synchronise...", "mining_tag": " · Minage", "mining_threads": "Threads de minage", + "mining_threads_input_tooltip": "Saisissez un nombre exact de threads (Entrée pour appliquer)", + "mining_threads_minus_tooltip": "Moins de threads", + "mining_threads_plus_tooltip": "Plus de threads", "mining_to_save": "pour enregistrer", "mining_today": "Aujourd'hui", "mining_uptime": "Temps de fonctionnement", @@ -1785,6 +1788,7 @@ "xmrig_loading_releases": "Chargement des versions…", "xmrig_none": "aucun", "xmrig_reinstall": "Réinstaller", + "xmrig_releases": "versions de xmrig", "xmrig_stop_mining_first": "Arrêtez le minage avant de mettre à jour le mineur.", "xmrig_unavailable_body": "Aucune version du mineur n'est disponible pour cette plateforme.", "xmrig_unavailable_title": "Mises à jour du mineur indisponibles", diff --git a/res/lang/ja.json b/res/lang/ja.json index 72e5117..c02d619 100644 --- a/res/lang/ja.json +++ b/res/lang/ja.json @@ -949,6 +949,9 @@ "mining_syncing_tooltip": "ブロックチェーン同期中...", "mining_tag": " · マイニング", "mining_threads": "マイニングスレッド", + "mining_threads_input_tooltip": "正確なスレッド数を入力(Enter で適用)", + "mining_threads_minus_tooltip": "スレッドを減らす", + "mining_threads_plus_tooltip": "スレッドを増やす", "mining_to_save": "保存する", "mining_today": "今日", "mining_uptime": "稼働時間", @@ -1782,6 +1785,7 @@ "xmrig_loading_releases": "リリースを読み込み中…", "xmrig_none": "なし", "xmrig_reinstall": "再インストール", + "xmrig_releases": "xmrig リリース", "xmrig_stop_mining_first": "マイナーを更新する前にマイニングを停止してください。", "xmrig_unavailable_body": "このプラットフォーム向けのマイナービルドは利用できません。", "xmrig_unavailable_title": "マイナーの更新は利用できません", diff --git a/res/lang/ko.json b/res/lang/ko.json index 05aa546..3970d60 100644 --- a/res/lang/ko.json +++ b/res/lang/ko.json @@ -948,6 +948,9 @@ "mining_syncing_tooltip": "블록체인 동기화 중...", "mining_tag": " · 채굴", "mining_threads": "채굴 스레드", + "mining_threads_input_tooltip": "정확한 스레드 수 입력 (Enter로 적용)", + "mining_threads_minus_tooltip": "스레드 줄이기", + "mining_threads_plus_tooltip": "스레드 늘리기", "mining_to_save": "저장하려면", "mining_today": "오늘", "mining_uptime": "가동 시간", @@ -1784,6 +1787,7 @@ "xmrig_loading_releases": "릴리스를 불러오는 중…", "xmrig_none": "없음", "xmrig_reinstall": "재설치", + "xmrig_releases": "xmrig 릴리스", "xmrig_stop_mining_first": "채굴기를 업데이트하기 전에 채굴을 중지하세요.", "xmrig_unavailable_body": "이 플랫폼에서 사용 가능한 채굴기 빌드가 없습니다.", "xmrig_unavailable_title": "채굴기 업데이트를 사용할 수 없습니다", diff --git a/res/lang/pt.json b/res/lang/pt.json index 07bceae..1df6a8a 100644 --- a/res/lang/pt.json +++ b/res/lang/pt.json @@ -949,6 +949,9 @@ "mining_syncing_tooltip": "Blockchain está sincronizando...", "mining_tag": " · Mineração", "mining_threads": "Threads de Mineração", + "mining_threads_input_tooltip": "Digite um número exato de threads (Enter para aplicar)", + "mining_threads_minus_tooltip": "Menos threads", + "mining_threads_plus_tooltip": "Mais threads", "mining_to_save": "para salvar", "mining_today": "Hoje", "mining_uptime": "Tempo Ativo", @@ -1785,6 +1788,7 @@ "xmrig_loading_releases": "Carregando versões…", "xmrig_none": "nenhum", "xmrig_reinstall": "Reinstalar", + "xmrig_releases": "versões do xmrig", "xmrig_stop_mining_first": "Pare a mineração antes de atualizar o minerador.", "xmrig_unavailable_body": "Nenhuma versão do minerador está disponível para esta plataforma.", "xmrig_unavailable_title": "Atualizações do minerador indisponíveis", diff --git a/res/lang/ru.json b/res/lang/ru.json index b6842d2..195bd2d 100644 --- a/res/lang/ru.json +++ b/res/lang/ru.json @@ -949,6 +949,9 @@ "mining_syncing_tooltip": "Блокчейн синхронизируется...", "mining_tag": " · Майнинг", "mining_threads": "Потоки майнинга", + "mining_threads_input_tooltip": "Введите точное число потоков (Enter для применения)", + "mining_threads_minus_tooltip": "Меньше потоков", + "mining_threads_plus_tooltip": "Больше потоков", "mining_to_save": "для сохранения", "mining_today": "Сегодня", "mining_uptime": "Время работы", @@ -1785,6 +1788,7 @@ "xmrig_loading_releases": "Загрузка релизов…", "xmrig_none": "нет", "xmrig_reinstall": "Переустановить", + "xmrig_releases": "релизы xmrig", "xmrig_stop_mining_first": "Остановите майнинг перед обновлением майнера.", "xmrig_unavailable_body": "Для этой платформы нет доступной сборки майнера.", "xmrig_unavailable_title": "Обновления майнера недоступны", diff --git a/res/lang/zh.json b/res/lang/zh.json index 7c51509..21c4629 100644 --- a/res/lang/zh.json +++ b/res/lang/zh.json @@ -948,6 +948,9 @@ "mining_syncing_tooltip": "区块链同步中...", "mining_tag": " · 挖矿", "mining_threads": "挖矿线程", + "mining_threads_input_tooltip": "输入精确的线程数(按 Enter 应用)", + "mining_threads_minus_tooltip": "减少线程", + "mining_threads_plus_tooltip": "增加线程", "mining_to_save": "保存", "mining_today": "今天", "mining_uptime": "运行时间", @@ -1783,6 +1786,7 @@ "xmrig_loading_releases": "正在加载发行版…", "xmrig_none": "无", "xmrig_reinstall": "重新安装", + "xmrig_releases": "xmrig 版本", "xmrig_stop_mining_first": "更新矿工程序前请先停止挖矿。", "xmrig_unavailable_body": "此平台没有可用的矿工构建版本。", "xmrig_unavailable_title": "矿工更新不可用", diff --git a/src/ui/windows/mining_controls.cpp b/src/ui/windows/mining_controls.cpp index 8e25f47..a06aeeb 100644 --- a/src/ui/windows/mining_controls.cpp +++ b/src/ui/windows/mining_controls.cpp @@ -28,6 +28,7 @@ #include #include #include +#include // std::atoi (xmrig version compare) namespace dragonx { namespace ui { @@ -56,6 +57,25 @@ void RenderMiningControls(App* app, const WalletState& state, const MiningInfo& float miningBtnGap = gap; float miningBtnMaxW = availWidth * schema::UI().drawElement("tabs.mining", "btn-max-width-ratio").size; + // Thread-count tiles at an adaptive step (multiples of 1/2/4/8, chosen by core count) plus 1 and the + // max, so the tile row stays bounded (~<=24 tiles) instead of one tile per thread — a 192-thread + // EPYC would otherwise overflow the card. Exact in-between counts are settable via the input box. + int tileStep = 1; + if (max_threads > 96) tileStep = 8; + else if (max_threads > 48) tileStep = 4; + else if (max_threads > 24) tileStep = 2; + std::vector threadOptions; + threadOptions.push_back(1); + for (int v = tileStep; v < max_threads; v += tileStep) + if (v > 1) threadOptions.push_back(v); + if (max_threads > 1 && threadOptions.back() != max_threads) threadOptions.push_back(max_threads); + const int nOpts = (int)threadOptions.size(); + + // Custom drawlist hit-tests (the thread tiles + the Mine button) bypass ImGui's popup input capture, + // so a click on an open dropdown (saved pools / payout addresses) would ALSO fire them. Gate on this + // so clicking the dropdown's X (or a row) doesn't bleed through to the tiles/Mine button. + const bool anyPopupOpen = ImGui::IsPopupOpen("", ImGuiPopupFlags_AnyPopupId | ImGuiPopupFlags_AnyPopupLevel); + // --- Compute thread grid layout based on controls card width --- // Estimate controlsW first to compute cols correctly // The Mine button is square (= card height, which scales with DPI), so the width we @@ -65,8 +85,8 @@ void RenderMiningControls(App* app, const WalletState& state, const MiningInfo& float innerW = estControlsW - pad * 2; float cellSz = std::clamp(schema::UI().drawElement("tabs.mining", "cell-size").size * vs, schema::UI().drawElement("tabs.mining", "cell-min-size").size, schema::UI().drawElement("tabs.mining", "cell-max-size").sizeOr(42.0f)); float cellGap = std::max(schema::UI().drawElement("tabs.mining", "cell-gap-min").size, cellSz * schema::UI().drawElement("tabs.mining", "cell-gap-ratio").size); - int cols = std::max(1, std::min(max_threads, (int)(innerW / (cellSz + cellGap)))); - int rows = (max_threads + cols - 1) / cols; + int cols = std::max(1, std::min(nOpts, (int)(innerW / (cellSz + cellGap)))); + int rows = (nOpts + cols - 1) / cols; float gridW = cols * cellSz + (cols - 1) * cellGap; float gridH = rows * cellSz + (rows - 1) * cellGap; @@ -116,6 +136,67 @@ void RenderMiningControls(App* app, const WalletState& state, const MiningInfo& OnSurfaceDisabled(), buf); } + // Centered, top-aligned thread-count stepper: [-] centered editable number [+]. Lets a + // high-core CPU pick an EXACT count that isn't one of the tiles. The input commits on Enter + // (not per keystroke) so it doesn't restart the miner while the user is still typing. + { + auto applyThreads = [&](int tc) { + tc = std::clamp(tc, 1, max_threads); + if (tc == s_selected_threads) return; + s_selected_threads = tc; + app->settings()->setPoolThreads(tc); + app->settings()->save(); + if (mining.generate) app->startMining(tc); + if (s_pool_mode && state.pool_mining.xmrig_running) { + app->stopPoolMining(); + app->startPoolMining(tc); + } + }; + ImFont* stepFont = Type().iconSmall(); + const float fieldH = capFont->LegacySize + 6.0f * dp; + const float sideW = fieldH; // square -/+ buttons + const float fieldW = 46.0f * dp; + const float g = 2.0f * dp; + const float totalW = sideW + g + fieldW + g + sideW; + float sx = cardMin.x + (controlsW - totalW) * 0.5f; + const float sy = curY; + ImVec2 savedCur = ImGui::GetCursorScreenPos(); + + material::IconButtonStyle sideStyle; + sideStyle.color = OnSurfaceMedium(); + sideStyle.hoverBg = StateHover(); + + // "-" button + sideStyle.tooltip = TR("mining_threads_minus_tooltip"); + ImGui::SetCursorScreenPos(ImVec2(sx, sy)); + if (material::IconButton("##ThreadMinus", ICON_MD_REMOVE, stepFont, ImVec2(sideW, fieldH), sideStyle)) + applyThreads(s_selected_threads - 1); + sx += sideW + g; + + // Centered editable number: symmetric FramePadding pushes the digits to the field centre. + char tb[8]; snprintf(tb, sizeof(tb), "%d", s_selected_threads); + float basePad = ImGui::GetStyle().FramePadding.x; + float txtW = ImGui::CalcTextSize(tb).x; + float centerPad = std::max(basePad, (fieldW - txtW) * 0.5f); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(centerPad, ImGui::GetStyle().FramePadding.y)); + ImGui::SetCursorScreenPos(ImVec2(sx, sy)); + ImGui::SetNextItemWidth(fieldW); + int tc = s_selected_threads; + if (ImGui::InputInt("##ThreadCountInput", &tc, 0, 0, ImGuiInputTextFlags_EnterReturnsTrue)) + applyThreads(tc); + if (ImGui::IsItemHovered()) material::Tooltip("%s", TR("mining_threads_input_tooltip")); + ImGui::PopStyleVar(); + sx += fieldW + g; + + // "+" button + sideStyle.tooltip = TR("mining_threads_plus_tooltip"); + ImGui::SetCursorScreenPos(ImVec2(sx, sy)); + if (material::IconButton("##ThreadPlus", ICON_MD_ADD, stepFont, ImVec2(sideW, fieldH), sideStyle)) + applyThreads(s_selected_threads + 1); + + ImGui::SetCursorScreenPos(savedCur); + } + // Idle mining toggle (top-right corner of card) float idleRightEdge = cardMax.x - pad; { @@ -475,8 +556,39 @@ void RenderMiningControls(App* app, const WalletState& state, const MiningInfo& std::string curVer = s_live_miner_ver; if (curVer.empty()) curVer = app->poolMiningInstalledVersion(); if (curVer.empty()) curVer = app->settings()->getXmrigVersion(); + // Version state: subtle GREEN + "xmrig releases" when up to date, subtle ORANGE + + // "Update " when an update is available, neutral when either version is unknown. + auto verNum = [](std::string s) -> std::vector { + if (!s.empty() && (s[0] == 'v' || s[0] == 'V')) s.erase(0, 1); + s = s.substr(0, s.find('-')); // drop any -build suffix + std::vector v; size_t p = 0; + while (p <= s.size()) { + size_t q = s.find('.', p); + v.push_back(std::atoi(s.substr(p, q == std::string::npos ? std::string::npos : q - p).c_str())); + if (q == std::string::npos) break; + p = q + 1; + } + return v; + }; + const bool verKnown = !curVer.empty() && !s_xmrig_latest_tag.empty(); + bool upToDate = false; + if (verKnown) { + auto a = verNum(curVer), b = verNum(s_xmrig_latest_tag); + int cmp = 0; + for (size_t i = 0; i < std::max(a.size(), b.size()) && cmp == 0; ++i) { + int x = i < a.size() ? a[i] : 0, y = i < b.size() ? b[i] : 0; + if (x != y) cmp = x < y ? -1 : 1; + } + upToDate = (cmp >= 0); // installed >= latest + } + const bool outdated = verKnown && !upToDate; + const ImU32 subtleGreen = IM_COL32(120, 190, 130, 255); + const ImU32 subtleOrange = IM_COL32(214, 158, 74, 255); + char xbtn[64]; - if (!s_xmrig_latest_tag.empty()) + if (upToDate) + snprintf(xbtn, sizeof(xbtn), "%s", TR("xmrig_releases")); + else if (!s_xmrig_latest_tag.empty()) snprintf(xbtn, sizeof(xbtn), "%s %s", TR("xmrig_update_short"), s_xmrig_latest_tag.c_str()); else snprintf(xbtn, sizeof(xbtn), "%s", TR("xmrig_update_button")); @@ -499,7 +611,9 @@ void RenderMiningControls(App* app, const WalletState& state, const MiningInfo& xpill, xbtnH * 0.3f); dl->AddText(capFont, capFont->LegacySize, ImVec2(xbtnX + xpadX, xbtnY + (xbtnH - xlblSz.y) * 0.5f), - minerBusy ? OnSurfaceDisabled() : OnSurfaceMedium(), xbtn); + minerBusy ? OnSurfaceDisabled() + : (upToDate ? subtleGreen : outdated ? subtleOrange : OnSurfaceMedium()), + xbtn); if (xhov) { ImGui::SetMouseCursor(ImGuiMouseCursor_Hand); material::Tooltip("%s", minerBusy ? TR("xmrig_stop_mining_first") @@ -515,7 +629,7 @@ void RenderMiningControls(App* app, const WalletState& state, const MiningInfo& float xcurX = xbtnX - 6.0f * dp - xcurSz.x; dl->AddText(capFont, capFont->LegacySize, ImVec2(xcurX, curY + (headerH - xcurSz.y) * 0.5f), - OnSurfaceDisabled(), xcur); + upToDate ? subtleGreen : outdated ? subtleOrange : OnSurfaceDisabled(), xcur); idleRightEdge = xcurX - 8.0f * dp; } @@ -548,14 +662,14 @@ void RenderMiningControls(App* app, const WalletState& state, const MiningInfo& // Track which thread the mouse is currently over (-1 = none) int hovered_thread = -1; - // First pass: hit-test all cells to find hovered thread - for (int i = 0; i < max_threads; i++) { + // First pass: hit-test all cells to find the hovered thread-count option (its value, not index) + for (int i = 0; i < nOpts; i++) { int row = i / cols; int col = i % cols; float cx = gridX + col * (cellSz + cellGap); float cy = gridY + row * (cellSz + cellGap); if (material::IsRectHovered(ImVec2(cx, cy), ImVec2(cx + cellSz, cy + cellSz))) { - hovered_thread = i + 1; + hovered_thread = threadOptions[i]; break; } } @@ -566,8 +680,8 @@ void RenderMiningControls(App* app, const WalletState& state, const MiningInfo& if (hovered_thread > 0 && !benchActive) ImGui::SetMouseCursor(ImGuiMouseCursor_Hand); - // Drag-to-select logic (disabled during benchmark) - if (!benchActive && ImGui::IsMouseClicked(0) && hovered_thread > 0) { + // Drag-to-select logic (disabled during benchmark; ignored while a dropdown popup is open) + if (!benchActive && !anyPopupOpen && ImGui::IsMouseClicked(0) && hovered_thread > 0) { // Begin drag s_drag_active = true; s_drag_anchor_thread = hovered_thread; @@ -587,8 +701,8 @@ void RenderMiningControls(App* app, const WalletState& state, const MiningInfo& } } - // Render cells - for (int i = 0; i < max_threads; i++) { + // Render cells (one per discrete thread-count option) + for (int i = 0; i < nOpts; i++) { int row = i / cols; int col = i % cols; float cx = gridX + col * (cellSz + cellGap); @@ -596,8 +710,8 @@ void RenderMiningControls(App* app, const WalletState& state, const MiningInfo& ImVec2 cMin(cx, cy); ImVec2 cMax(cx + cellSz, cy + cellSz); - int threadNum = i + 1; - bool active = threadNum <= s_selected_threads; + int threadNum = threadOptions[i]; + bool active = threadNum <= s_selected_threads; // fill-up-to-selected heat metaphor bool hovered = (threadNum == hovered_thread); // Determine visual state @@ -674,7 +788,7 @@ void RenderMiningControls(App* app, const WalletState& state, const MiningInfo& ImVec2 bMin(btnX, btnY); ImVec2 bMax(btnX + miningBtnSz, btnY + cardH); - bool btnHovered = material::IsRectHovered(bMin, bMax); + bool btnHovered = !anyPopupOpen && material::IsRectHovered(bMin, bMax); // don't bleed through an open dropdown bool btnClicked = btnHovered && ImGui::IsMouseClicked(0); bool isSyncing = state.sync.syncing; bool poolBlockedBySolo = s_pool_mode && mining.generate && !state.pool_mining.xmrig_running; diff --git a/src/util/i18n.cpp b/src/util/i18n.cpp index d591196..9a126f4 100644 --- a/src/util/i18n.cpp +++ b/src/util/i18n.cpp @@ -1296,6 +1296,9 @@ void I18n::loadBuiltinEnglish() strings_["start_mining"] = "Start Mining"; strings_["stop_mining"] = "Stop Mining"; strings_["mining_threads"] = "Mining Threads"; + strings_["mining_threads_input_tooltip"] = "Type an exact thread count (press Enter to apply)"; + strings_["mining_threads_minus_tooltip"] = "Fewer threads"; + strings_["mining_threads_plus_tooltip"] = "More threads"; strings_["mining_statistics"] = "Mining Statistics"; strings_["local_hashrate"] = "Local Hashrate"; strings_["network_hashrate"] = "Network Hashrate"; @@ -1933,6 +1936,7 @@ void I18n::loadBuiltinEnglish() // --- Miner (xmrig) updater --- strings_["xmrig_update_button"] = "Update miner…"; strings_["xmrig_update_short"] = "Update"; + strings_["xmrig_releases"] = "xmrig releases"; strings_["xmrig_current"] = "Current:"; strings_["xmrig_none"] = "none"; strings_["xmrig_update_title"] = "Update Miner";