feat: implement Phosphor solid icons throughout UI

- Downloaded Phosphor Icons (Fill variant) - 7000+ solid icons
- Added 18 Phosphor solid icons to assets/icons/:
  - search, calculator, music, globe, camera, skills
  - close, check, settings, trash, file, external
  - mob (skull), ped (coins), loot (chest), weapon (crosshair)
  - armor (shield), esi (syringe), target

- Updated overlay_window.py with IconHelper class
- Plugin bar now uses Phosphor SVG icons with color accents
- Floating icon uses Phosphor target icon
- Icons are solid/filled style matching EU game aesthetic
- Automatic fallback to emojis if SVG not found

Icons sourced from: https://phosphoricons.com
License: MIT (free for commercial use)

To add more icons:
1. Browse https://phosphoricons.com
2. Click 'Fill' filter
3. Copy icon name (e.g., 'sword-fill')
4. Add to assets/icons/ folder
This commit is contained in:
LemonNexus 2026-02-13 14:00:07 +00:00
parent 3ea24f4989
commit 56a653bba6
21 changed files with 114 additions and 100 deletions

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" fill="currentColor"><path d="M224,56v56c0,52.72-25.52,84.67-46.93,102.19-23.06,18.86-46,25.27-47,25.53a8,8,0,0,1-4.2,0c-1-.26-23.91-6.67-47-25.53C57.52,196.67,32,164.72,32,112V56A16,16,0,0,1,48,40H208A16,16,0,0,1,224,56Z"/></svg>

After

Width:  |  Height:  |  Size: 291 B

View File

@ -1,7 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect x="4" y="2" width="16" height="20" rx="2"></rect>
<line x1="8" y1="6" x2="16" y2="6"></line>
<line x1="8" y1="10" x2="16" y2="10"></line>
<line x1="8" y1="14" x2="16" y2="14"></line>
<line x1="8" y1="18" x2="12" y2="18"></line>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" fill="currentColor"><path d="M200,24H56A16,16,0,0,0,40,40V216a16,16,0,0,0,16,16H200a16,16,0,0,0,16-16V40A16,16,0,0,0,200,24ZM88,200a12,12,0,1,1,12-12A12,12,0,0,1,88,200Zm0-40a12,12,0,1,1,12-12A12,12,0,0,1,88,160Zm40,40a12,12,0,1,1,12-12A12,12,0,0,1,128,200Zm0-40a12,12,0,1,1,12-12A12,12,0,0,1,128,160Zm40,40a12,12,0,1,1,12-12A12,12,0,0,1,168,200Zm0-40a12,12,0,1,1,12-12A12,12,0,0,1,168,160Zm16-56a8,8,0,0,1-8,8H80a8,8,0,0,1-8-8V64a8,8,0,0,1,8-8h96a8,8,0,0,1,8,8Z"/></svg>

Before

Width:  |  Height:  |  Size: 402 B

After

Width:  |  Height:  |  Size: 533 B

View File

@ -1,4 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z"></path>
<circle cx="12" cy="13" r="4"></circle>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" fill="currentColor"><path d="M208,56H180.28L166.65,35.56A8,8,0,0,0,160,32H96a8,8,0,0,0-6.65,3.56L75.71,56H48A24,24,0,0,0,24,80V192a24,24,0,0,0,24,24H208a24,24,0,0,0,24-24V80A24,24,0,0,0,208,56Zm-44,76a36,36,0,1,1-36-36A36,36,0,0,1,164,132Z"/></svg>

Before

Width:  |  Height:  |  Size: 302 B

After

Width:  |  Height:  |  Size: 310 B

View File

@ -1,3 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="20 6 9 17 4 12"></polyline>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" fill="currentColor"><path d="M216,40H40A16,16,0,0,0,24,56V200a16,16,0,0,0,16,16H216a16,16,0,0,0,16-16V56A16,16,0,0,0,216,40ZM205.66,85.66l-96,96a8,8,0,0,1-11.32,0l-40-40a8,8,0,0,1,11.32-11.32L104,164.69l90.34-90.35a8,8,0,0,1,11.32,11.32Z"/></svg>

Before

Width:  |  Height:  |  Size: 206 B

After

Width:  |  Height:  |  Size: 308 B

View File

@ -1,4 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<line x1="18" y1="6" x2="6" y2="18"></line>
<line x1="6" y1="6" x2="18" y2="18"></line>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" fill="currentColor"><path d="M208,32H48A16,16,0,0,0,32,48V208a16,16,0,0,0,16,16H208a16,16,0,0,0,16-16V48A16,16,0,0,0,208,32ZM181.66,170.34a8,8,0,0,1-11.32,11.32L128,139.31,85.66,181.66a8,8,0,0,1-11.32-11.32L116.69,128,74.34,85.66A8,8,0,0,1,85.66,74.34L128,116.69l42.34-42.35a8,8,0,0,1,11.32,11.32L139.31,128Z"/></svg>

Before

Width:  |  Height:  |  Size: 250 B

After

Width:  |  Height:  |  Size: 379 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" fill="currentColor"><path d="M237.66,77.6a8,8,0,0,1-11.32,0L208,59.25,179.3,88l34.35,34.35a8,8,0,0,1-11.32,11.32L196,127.27l-84,84A16,16,0,0,1,100.65,216H51.26L29.6,237.66a8,8,0,0,1-11.72-.43,8.21,8.21,0,0,1,.61-11.1l21.45-21.46V155.28A16,16,0,0,1,44.63,144l15.18-15.18a4,4,0,0,1,5.66,0L94.3,157.63a8,8,0,1,0,11.32-11.32L76.78,117.47a4,4,0,0,1,0-5.66l11-11a4,4,0,0,1,5.66,0l28.84,28.84a8,8,0,1,0,11.32-11.32L104.79,89.46a4,4,0,0,1,0-5.66l23.87-23.86-6.35-6.35a8,8,0,0,1,.18-11.49,8.22,8.22,0,0,1,11.37.41L168,76.63l28.69-28.7L178.33,29.58a8,8,0,0,1,.17-11.49,8.23,8.23,0,0,1,11.38.41l47.78,47.78A8,8,0,0,1,237.66,77.6Z"/></svg>

After

Width:  |  Height:  |  Size: 689 B

View File

@ -1,5 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>
<polyline points="15 3 21 3 21 9"></polyline>
<line x1="10" y1="14" x2="21" y2="3"></line>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" fill="currentColor"><path d="M192,136v72a16,16,0,0,1-16,16H48a16,16,0,0,1-16-16V80A16,16,0,0,1,48,64h72a8,8,0,0,1,0,16H48V208H176V136a8,8,0,0,1,16,0Zm32-96a8,8,0,0,0-8-8H152a8,8,0,0,0-5.66,13.66L172.69,72l-42.35,42.34a8,8,0,0,0,11.32,11.32L184,83.31l26.34,26.35A8,8,0,0,0,224,104Z"/></svg>

Before

Width:  |  Height:  |  Size: 330 B

After

Width:  |  Height:  |  Size: 351 B

View File

@ -1,7 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
<polyline points="14 2 14 8 20 8"></polyline>
<line x1="16" y1="13" x2="8" y2="13"></line>
<line x1="16" y1="17" x2="8" y2="17"></line>
<polyline points="10 9 9 9 8 9"></polyline>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" fill="currentColor"><path d="M213.66,82.34l-56-56A8,8,0,0,0,152,24H56A16,16,0,0,0,40,40V216a16,16,0,0,0,16,16H200a16,16,0,0,0,16-16V88A8,8,0,0,0,213.66,82.34ZM160,176H96a8,8,0,0,1,0-16h64a8,8,0,0,1,0,16Zm0-32H96a8,8,0,0,1,0-16h64a8,8,0,0,1,0,16Zm-8-56V44l44,44Z"/></svg>

Before

Width:  |  Height:  |  Size: 425 B

After

Width:  |  Height:  |  Size: 332 B

View File

@ -1,5 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="10"></circle>
<line x1="2" y1="12" x2="22" y2="12"></line>
<path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"></path>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" fill="currentColor"><path d="M128,24h0A104,104,0,1,0,232,128,104.12,104.12,0,0,0,128,24Zm78.36,64H170.71a135.28,135.28,0,0,0-22.3-45.6A88.29,88.29,0,0,1,206.37,88ZM216,128a87.61,87.61,0,0,1-3.33,24H174.16a157.44,157.44,0,0,0,0-48h38.51A87.61,87.61,0,0,1,216,128ZM128,43a115.27,115.27,0,0,1,26,45H102A115.11,115.11,0,0,1,128,43ZM102,168H154a115.11,115.11,0,0,1-26,45A115.27,115.27,0,0,1,102,168Zm-3.9-16a140.84,140.84,0,0,1,0-48h59.88a140.84,140.84,0,0,1,0,48Zm50.35,61.6a135.28,135.28,0,0,0,22.3-45.6h35.66A88.29,88.29,0,0,1,148.41,213.6Z"/></svg>

Before

Width:  |  Height:  |  Size: 359 B

After

Width:  |  Height:  |  Size: 609 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" fill="currentColor"><path d="M240,124v68a16,16,0,0,1-16,16H32a16,16,0,0,1-16-16V124a4,4,0,0,1,4-4H56v64a8,8,0,0,0,8.53,8A8.17,8.17,0,0,0,72,183.73V120h40v20a4,4,0,0,0,4,4h24a4,4,0,0,0,4-4V120h40v64a8,8,0,0,0,8.53,8,8.17,8.17,0,0,0,7.47-8.25V120h36A4,4,0,0,1,240,124ZM184,40H72A56,56,0,0,0,16,96v4a4,4,0,0,0,4,4H56V64.27A8.17,8.17,0,0,1,63.47,56,8,8,0,0,1,72,64v40h40V92a4,4,0,0,1,4-4h24a4,4,0,0,1,4,4v12h40V64.27A8.17,8.17,0,0,1,191.47,56,8,8,0,0,1,200,64v40h36a4,4,0,0,0,4-4V96A56,56,0,0,0,184,40Z"/></svg>

After

Width:  |  Height:  |  Size: 569 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" fill="currentColor"><path d="M128,16C70.65,16,24,60.86,24,116c0,34.1,18.27,66,48,84.28V216a16,16,0,0,0,16,16h8a4,4,0,0,0,4-4V200.27a8.17,8.17,0,0,1,7.47-8.25,8,8,0,0,1,8.53,8v28a4,4,0,0,0,4,4h16a4,4,0,0,0,4-4V200.27a8.17,8.17,0,0,1,7.47-8.25,8,8,0,0,1,8.53,8v28a4,4,0,0,0,4,4h8a16,16,0,0,0,16-16V200.28C213.73,182,232,150.1,232,116,232,60.86,185.35,16,128,16ZM92,152a20,20,0,1,1,20-20A20,20,0,0,1,92,152Zm72,0a20,20,0,1,1,20-20A20,20,0,0,1,164,152Z"/></svg>

After

Width:  |  Height:  |  Size: 519 B

View File

@ -1,5 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M9 18V5l12-2v13"></path>
<circle cx="6" cy="18" r="3"></circle>
<circle cx="18" cy="16" r="3"></circle>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" fill="currentColor"><path d="M212.92,17.71a7.89,7.89,0,0,0-6.86-1.46l-128,32A8,8,0,0,0,72,56V166.1A36,36,0,1,0,88,196V102.25l112-28V134.1A36,36,0,1,0,216,164V24A8,8,0,0,0,212.92,17.71Z"/></svg>

Before

Width:  |  Height:  |  Size: 277 B

After

Width:  |  Height:  |  Size: 255 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" fill="currentColor"><path d="M184,89.57V84c0-25.08-37.83-44-88-44S8,58.92,8,84v40c0,20.89,26.25,37.49,64,42.46V172c0,25.08,37.83,44,88,44s88-18.92,88-44V132C248,111.3,222.58,94.68,184,89.57ZM56,146.87C36.41,141.4,24,132.39,24,124V109.93c8.16,5.78,19.09,10.44,32,13.57Zm80-23.37c12.91-3.13,23.84-7.79,32-13.57V124c0,8.39-12.41,17.4-32,22.87Zm-16,71.37C100.41,189.4,88,180.39,88,172v-4.17c2.63.1,5.29.17,8,.17,3.88,0,7.67-.13,11.39-.35A121.92,121.92,0,0,0,120,171.41Zm0-44.62A163,163,0,0,1,96,152a163,163,0,0,1-24-1.75V126.46A183.74,183.74,0,0,0,96,128a183.74,183.74,0,0,0,24-1.54Zm64,48a165.45,165.45,0,0,1-48,0V174.4a179.48,179.48,0,0,0,24,1.6,183.74,183.74,0,0,0,24-1.54ZM232,172c0,8.39-12.41,17.4-32,22.87V171.5c12.91-3.13,23.84-7.79,32-13.57Z"/></svg>

After

Width:  |  Height:  |  Size: 816 B

View File

@ -1,4 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="11" cy="11" r="8"></circle>
<line x1="21" y1="21" x2="16.65" y2="16.65"></line>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" fill="currentColor"><path d="M168,112a56,56,0,1,1-56-56A56,56,0,0,1,168,112Zm61.66,117.66a8,8,0,0,1-11.32,0l-50.06-50.07a88,88,0,1,1,11.32-11.31l50.06,50.06A8,8,0,0,1,229.66,229.66ZM112,184a72,72,0,1,0-72-72A72.08,72.08,0,0,0,112,184Z"/></svg>

Before

Width:  |  Height:  |  Size: 254 B

After

Width:  |  Height:  |  Size: 305 B

View File

@ -1,4 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="3"></circle>
<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" fill="currentColor"><path d="M216,130.16q.06-2.16,0-4.32l14.92-18.64a8,8,0,0,0,1.48-7.06,107.6,107.6,0,0,0-10.88-26.25,8,8,0,0,0-6-3.93l-23.72-2.64q-1.48-1.56-3-3L186,40.54a8,8,0,0,0-3.94-6,107.29,107.29,0,0,0-26.25-10.86,8,8,0,0,0-7.06,1.48L130.16,40Q128,40,125.84,40L107.2,25.11a8,8,0,0,0-7.06-1.48A107.6,107.6,0,0,0,73.89,34.51a8,8,0,0,0-3.93,6L67.32,64.27q-1.56,1.49-3,3L40.54,70a8,8,0,0,0-6,3.94,107.71,107.71,0,0,0-10.87,26.25,8,8,0,0,0,1.49,7.06L40,125.84Q40,128,40,130.16L25.11,148.8a8,8,0,0,0-1.48,7.06,107.6,107.6,0,0,0,10.88,26.25,8,8,0,0,0,6,3.93l23.72,2.64q1.49,1.56,3,3L70,215.46a8,8,0,0,0,3.94,6,107.71,107.71,0,0,0,26.25,10.87,8,8,0,0,0,7.06-1.49L125.84,216q2.16.06,4.32,0l18.64,14.92a8,8,0,0,0,7.06,1.48,107.21,107.21,0,0,0,26.25-10.88,8,8,0,0,0,3.93-6l2.64-23.72q1.56-1.48,3-3L215.46,186a8,8,0,0,0,6-3.94,107.71,107.71,0,0,0,10.87-26.25,8,8,0,0,0-1.49-7.06ZM128,168a40,40,0,1,1,40-40A40,40,0,0,1,128,168Z"/></svg>

Before

Width:  |  Height:  |  Size: 955 B

After

Width:  |  Height:  |  Size: 993 B

View File

@ -1,4 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M21.21 15.89A10 10 0 1 1 8 2.83"></path>
<path d="M22 12A10 10 0 0 0 12 2v10z"></path>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" fill="currentColor"><path d="M216,40H40A16,16,0,0,0,24,56V200a16,16,0,0,0,16,16H216a16,16,0,0,0,16-16V56A16,16,0,0,0,216,40ZM200,192H56a8,8,0,0,1-8-8V72a8,8,0,0,1,16,0v76.69l34.34-34.35a8,8,0,0,1,11.32,0L128,132.69,172.69,88H144a8,8,0,0,1,0-16h48a8,8,0,0,1,8,8v48a8,8,0,0,1-16,0V99.31l-50.34,50.35a8,8,0,0,1-11.32,0L104,131.31l-40,40V176H200a8,8,0,0,1,0,16Z"/></svg>

Before

Width:  |  Height:  |  Size: 258 B

After

Width:  |  Height:  |  Size: 428 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" fill="currentColor"><path d="M176,136h23.54A72.11,72.11,0,0,1,136,199.54V176a8,8,0,0,0-16,0v23.54A72.11,72.11,0,0,1,56.46,136H80a8,8,0,0,0,0-16H56.46A72.11,72.11,0,0,1,120,56.46V80a8,8,0,0,0,16,0V56.46A72.11,72.11,0,0,1,199.54,120H176a8,8,0,0,0,0,16Zm56-8A104,104,0,1,1,128,24,104.11,104.11,0,0,1,232,128Zm-16,0a88,88,0,1,0-88,88A88.1,88.1,0,0,0,216,128Z"/></svg>

After

Width:  |  Height:  |  Size: 425 B

View File

@ -1,4 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="3 6 5 6 21 6"></polyline>
<path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" fill="currentColor"><path d="M216,48H176V40a24,24,0,0,0-24-24H104A24,24,0,0,0,80,40v8H40a8,8,0,0,0,0,16h8V208a16,16,0,0,0,16,16H192a16,16,0,0,0,16-16V64h8a8,8,0,0,0,0-16ZM112,168a8,8,0,0,1-16,0V104a8,8,0,0,1,16,0Zm48,0a8,8,0,0,1-16,0V104a8,8,0,0,1,16,0Zm0-120H96V40a8,8,0,0,1,8-8h48a8,8,0,0,1,8,8Z"/></svg>

Before

Width:  |  Height:  |  Size: 303 B

After

Width:  |  Height:  |  Size: 368 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" fill="currentColor"><path d="M232,120h-8.34A96.14,96.14,0,0,0,136,32.34V24a8,8,0,0,0-16,0v8.34A96.14,96.14,0,0,0,32.34,120H24a8,8,0,0,0,0,16h8.34A96.14,96.14,0,0,0,120,223.66V232a8,8,0,0,0,16,0v-8.34A96.14,96.14,0,0,0,223.66,136H232a8,8,0,0,0,0-16Zm-32,16h7.6A80.15,80.15,0,0,1,136,207.6V200a8,8,0,0,0-16,0v7.6A80.15,80.15,0,0,1,48.4,136H56a8,8,0,0,0,0-16H48.4A80.15,80.15,0,0,1,120,48.4V56a8,8,0,0,0,16,0V48.4A80.15,80.15,0,0,1,207.6,120H200a8,8,0,0,0,0,16Zm-32-8a40,40,0,1,1-40-40A40,40,0,0,1,168,128Z"/></svg>

After

Width:  |  Height:  |  Size: 574 B

View File

@ -1,24 +1,26 @@
"""
EU-Utility - Floating Icon
In-game floating button styled to match Entropia Universe UI.
Uses white/frosted icon style.
In-game floating button with Phosphor solid icons.
"""
from pathlib import Path
from PyQt6.QtWidgets import QWidget, QVBoxLayout, QLabel, QApplication
from PyQt6.QtCore import Qt, QPoint, pyqtSignal, QSize
from PyQt6.QtGui import QMouseEvent, QEnterEvent, QFont, QGraphicsDropShadowEffect, QColor
from PyQt6.QtGui import QMouseEvent, QEnterEvent, QFont, QGraphicsDropShadowEffect, QColor, QPixmap, QPainter
from PyQt6.QtSvg import QSvgRenderer
class FloatingIcon(QWidget):
"""Draggable floating icon that matches Entropia Universe UI."""
"""Draggable floating icon with Phosphor solid icon."""
clicked = pyqtSignal()
ICONS_DIR = Path(__file__).parent.parent / "assets" / "icons"
def __init__(self, parent=None):
super().__init__(parent)
# Frameless, always on top, click-through when not interacting
# Frameless, always on top
self.setWindowFlags(
Qt.WindowType.FramelessWindowHint |
Qt.WindowType.WindowStaysOnTopHint |
@ -28,43 +30,60 @@ class FloatingIcon(QWidget):
self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground)
self.setFixedSize(40, 40)
# Position - near top-left game icons (offset from corner)
# Position - near top-left game icons
screen = QApplication.primaryScreen().geometry()
# Position near other game UI elements (top left area)
self.move(250, 10)
self.dragging = False
self.drag_position = QPoint()
self.click_threshold = 5 # pixels
self.click_threshold = 5
self.click_start_pos = QPoint()
self._setup_ui()
def _load_svg_icon(self, name, size=24):
"""Load SVG icon as pixmap."""
svg_path = self.ICONS_DIR / f"{name}.svg"
if not svg_path.exists():
return None
renderer = QSvgRenderer(str(svg_path))
pixmap = QPixmap(size, size)
pixmap.fill(Qt.GlobalColor.transparent)
painter = QPainter(pixmap)
renderer.render(painter)
painter.end()
return pixmap
def _setup_ui(self):
"""Setup the floating icon with EU-style white/frosted look."""
"""Setup floating icon with Phosphor target icon."""
layout = QVBoxLayout(self)
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(0)
# Diamond shape - clean, sci-fi, white/frosted
self.icon_label = QLabel("")
self.icon_label = QLabel()
self.icon_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.icon_label.setFixedSize(40, 40)
# EU-style: frosted glass effect
# Dark background with subtle white border and glow
# Load Phosphor target icon
pixmap = self._load_svg_icon("target", size=22)
if pixmap:
self.icon_label.setPixmap(pixmap)
else:
self.icon_label.setText("")
# EU-style frosted glass
self.icon_label.setStyleSheet("""
QLabel {
font-size: 18px;
font-weight: bold;
color: rgba(255, 255, 255, 220);
background-color: rgba(25, 30, 40, 230);
border-radius: 10px;
border: 1.5px solid rgba(255, 255, 255, 40);
}
""")
# Add subtle glow effect
# Glow effect
shadow = QGraphicsDropShadowEffect()
shadow.setBlurRadius(15)
shadow.setColor(QColor(100, 150, 200, 80))
@ -74,7 +93,6 @@ class FloatingIcon(QWidget):
layout.addWidget(self.icon_label)
def mousePressEvent(self, event: QMouseEvent):
"""Handle mouse press."""
if event.button() == Qt.MouseButton.LeftButton:
self.dragging = True
self.click_start_pos = event.globalPosition().toPoint()
@ -82,48 +100,33 @@ class FloatingIcon(QWidget):
event.accept()
def mouseMoveEvent(self, event: QMouseEvent):
"""Handle mouse move for dragging."""
if self.dragging:
new_pos = event.globalPosition().toPoint() - self.drag_position
self.move(new_pos)
event.accept()
def mouseReleaseEvent(self, event: QMouseEvent):
"""Handle mouse release - detect click vs drag."""
if event.button() == Qt.MouseButton.LeftButton:
release_pos = event.globalPosition().toPoint()
distance = (release_pos - self.click_start_pos).manhattanLength()
self.dragging = False
# If moved less than threshold, treat as click
if distance < self.click_threshold:
self.clicked.emit()
event.accept()
def enterEvent(self, event: QEnterEvent):
"""Mouse entered - highlight with frosted effect."""
self.icon_label.setStyleSheet("""
QLabel {
font-size: 18px;
font-weight: bold;
color: white;
background-color: rgba(45, 60, 85, 250);
border-radius: 10px;
border: 1.5px solid rgba(120, 180, 255, 100);
}
""")
# Change cursor to indicate clickable
self.setCursor(Qt.CursorShape.PointingHandCursor)
def leaveEvent(self, event):
"""Mouse left - normal frosted look."""
self.icon_label.setStyleSheet("""
QLabel {
font-size: 18px;
font-weight: bold;
color: rgba(255, 255, 255, 220);
background-color: rgba(25, 30, 40, 230);
border-radius: 10px;
border: 1.5px solid rgba(255, 255, 255, 40);

View File

@ -1,7 +1,7 @@
"""
EU-Utility - Overlay Window
Spotlight-style overlay with frosted glass effect and custom icons.
Spotlight-style overlay with frosted glass effect and Phosphor icons.
"""
import sys
@ -15,19 +15,60 @@ try:
QMenu, QApplication, QFrame, QGraphicsDropShadowEffect
)
from PyQt6.QtCore import Qt, QTimer, pyqtSignal, QSize
from PyQt6.QtGui import QAction, QIcon, QColor, QFont
from PyQt6.QtGui import QAction, QIcon, QColor, QFont, QPixmap, QPainter
from PyQt6.QtSvg import QSvgRenderer
PYQT6_AVAILABLE = True
except ImportError:
PYQT6_AVAILABLE = False
print("PyQt6 not available. Install with: pip install PyQt6")
class IconHelper:
"""Helper to load and render SVG icons."""
ICONS_DIR = Path(__file__).parent.parent / "assets" / "icons"
@classmethod
def get_icon(cls, name, size=24, color="white"):
"""Get QIcon from SVG."""
svg_path = cls.ICONS_DIR / f"{name}.svg"
if not svg_path.exists():
return None
renderer = QSvgRenderer(str(svg_path))
pixmap = QPixmap(size, size)
pixmap.fill(Qt.GlobalColor.transparent)
painter = QPainter(pixmap)
renderer.render(painter)
painter.end()
return QIcon(pixmap)
@classmethod
def get_pixmap(cls, name, size=24):
"""Get QPixmap from SVG."""
svg_path = cls.ICONS_DIR / f"{name}.svg"
if not svg_path.exists():
return None
renderer = QSvgRenderer(str(svg_path))
pixmap = QPixmap(size, size)
pixmap.fill(Qt.GlobalColor.transparent)
painter = QPainter(pixmap)
renderer.render(painter)
painter.end()
return pixmap
class OverlayWindow(QMainWindow):
"""Spotlight-style overlay window."""
visibility_changed = pyqtSignal(bool)
# Plugin icon mapping - white/frosted style icons
# Plugin icon mapping - Phosphor solid icons
PLUGIN_ICONS = {
"Universal Search": ("search", "#4a9eff"),
"Calculator": ("calculator", "#9c27b0"),
@ -37,7 +78,7 @@ class OverlayWindow(QMainWindow):
"Skill Scanner": ("skills", "#00bcd4"),
}
# Emoji fallbacks for frosted look
# Emoji fallbacks
ICONS = {
'search': '🔍',
'calculator': '🧮',
@ -199,7 +240,7 @@ class OverlayWindow(QMainWindow):
layout.addWidget(self.container)
def _setup_plugin_bar(self, layout):
"""Setup circular plugin icon bar at bottom with frosted style."""
"""Setup circular plugin icon bar at bottom with Phosphor icons."""
bar = QWidget()
bar.setStyleSheet("""
QWidget {
@ -218,19 +259,26 @@ class OverlayWindow(QMainWindow):
btn = QPushButton()
# Get icon and color for this plugin
icon_key, accent_color = self.PLUGIN_ICONS.get(
icon_name, accent_color = self.PLUGIN_ICONS.get(
plugin.name,
("menu", "#4a9eff")
("target", "#4a9eff")
)
icon_emoji = self.ICONS.get(icon_key, '')
btn.setText(icon_emoji)
# Try to load SVG icon
icon = IconHelper.get_icon(icon_name, size=20)
if icon:
btn.setIcon(icon)
btn.setIconSize(QSize(20, 20))
btn.setText("") # No text, just icon
else:
# Fallback to emoji
emoji = self.ICONS.get(icon_name, '')
btn.setText(emoji)
btn.setFixedSize(40, 40)
btn.setStyleSheet(f"""
QPushButton {{
background-color: rgba(255, 255, 255, 12);
color: white;
font-size: 18px;
border: 1px solid rgba(255, 255, 255, 20);
border-radius: 20px;
}}