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
|
|
@ -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 |
|
|
@ -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 |
|
|
@ -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 |
|
|
@ -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 |
|
|
@ -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 |
|
|
@ -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 |
|
|
@ -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 |
|
|
@ -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 |
|
|
@ -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 |
|
|
@ -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 |
|
|
@ -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 |
|
|
@ -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 |
|
|
@ -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 |
|
|
@ -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 |
|
|
@ -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 |
|
|
@ -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 |
|
|
@ -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 |
|
|
@ -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 |
|
|
@ -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 |
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}}
|
||||
|
|
|
|||