leviathan-ui 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- leviathan_ui-1.0.0/LICENSE +21 -0
- leviathan_ui-1.0.0/PKG-INFO +167 -0
- leviathan_ui-1.0.0/README.md +137 -0
- leviathan_ui-1.0.0/leviathan_ui/__init__.py +6 -0
- leviathan_ui-1.0.0/leviathan_ui/debug.py +52 -0
- leviathan_ui-1.0.0/leviathan_ui/dialogs.py +174 -0
- leviathan_ui-1.0.0/leviathan_ui/fixLights.py +21 -0
- leviathan_ui-1.0.0/leviathan_ui/inmojiTrx.py +148 -0
- leviathan_ui-1.0.0/leviathan_ui/lightsOff.py +62 -0
- leviathan_ui-1.0.0/leviathan_ui/splash.py +150 -0
- leviathan_ui-1.0.0/leviathan_ui/title_bar.py +112 -0
- leviathan_ui-1.0.0/leviathan_ui/wipeWindow.py +167 -0
- leviathan_ui-1.0.0/leviathan_ui.egg-info/PKG-INFO +167 -0
- leviathan_ui-1.0.0/leviathan_ui.egg-info/SOURCES.txt +17 -0
- leviathan_ui-1.0.0/leviathan_ui.egg-info/dependency_links.txt +1 -0
- leviathan_ui-1.0.0/leviathan_ui.egg-info/requires.txt +2 -0
- leviathan_ui-1.0.0/leviathan_ui.egg-info/top_level.txt +1 -0
- leviathan_ui-1.0.0/pyproject.toml +45 -0
- leviathan_ui-1.0.0/setup.cfg +4 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jesus Quijada
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: leviathan-ui
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Premium UI framework for PyQt5 with Windows 11 aesthetics, blur effects, and modern splash screens
|
|
5
|
+
Author-email: Jesus Quijada <jesusquijada.gh34@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/JesusQuijada34/leviathan-ui
|
|
8
|
+
Project-URL: Documentation, https://github.com/JesusQuijada34/leviathan-ui#readme
|
|
9
|
+
Project-URL: Repository, https://github.com/JesusQuijada34/leviathan-ui
|
|
10
|
+
Project-URL: Issues, https://github.com/JesusQuijada/leviathan-ui/issues
|
|
11
|
+
Keywords: pyqt5,ui,windows11,blur,splash,frameless,modern-ui
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
22
|
+
Classifier: Topic :: Software Development :: User Interfaces
|
|
23
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
24
|
+
Requires-Python: >=3.8
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
License-File: LICENSE
|
|
27
|
+
Requires-Dist: PyQt5>=5.15.0
|
|
28
|
+
Requires-Dist: Pillow>=9.0.0
|
|
29
|
+
Dynamic: license-file
|
|
30
|
+
|
|
31
|
+
# Leviathan UI
|
|
32
|
+
|
|
33
|
+
**Premium UI Framework for PyQt5 with Windows 11 Aesthetics**
|
|
34
|
+
|
|
35
|
+
A modern, feature-rich UI framework that brings Windows 11's beautiful design language to your PyQt5 applications.
|
|
36
|
+
|
|
37
|
+
## ✨ Features
|
|
38
|
+
|
|
39
|
+
- **🪟 WipeWindow**: Three stunning window modes
|
|
40
|
+
- `polished`: Solid background with shadows and rounded corners
|
|
41
|
+
- `ghost`: Fully transparent overlay mode
|
|
42
|
+
- `ghostBlur`: Acrylic/frosted glass blur effect (Windows 10/11)
|
|
43
|
+
|
|
44
|
+
- **🌊 InmersiveSplash**: Professional splash screen system
|
|
45
|
+
- Adaptive mode (respects taskbar) and fullscreen mode
|
|
46
|
+
- Custom phrases for startup and exit
|
|
47
|
+
- Smooth fade animations
|
|
48
|
+
- Automatic lifecycle management
|
|
49
|
+
|
|
50
|
+
- **🎨 CustomTitleBar**: Windows 11 style title bar
|
|
51
|
+
- Native SVG-drawn window controls
|
|
52
|
+
- System accent color integration
|
|
53
|
+
- Smooth drag and maximize/minimize
|
|
54
|
+
|
|
55
|
+
- **🎭 InmojiTrx**: High-quality icon generation
|
|
56
|
+
- Convert emojis to multi-resolution ICO files
|
|
57
|
+
- Support for PNG/ICO images
|
|
58
|
+
- Perfect taskbar rendering
|
|
59
|
+
|
|
60
|
+
## 📦 Installation
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
pip install leviathan-ui
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Or install from wheel:
|
|
67
|
+
```bash
|
|
68
|
+
pip install leviathan_ui-1.0.0-py3-none-any.whl
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## 🚀 Quick Start
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
from PyQt5.QtWidgets import QApplication, QWidget
|
|
75
|
+
from leviathan_ui import WipeWindow, InmersiveSplash, CustomTitleBar, InmojiTrx
|
|
76
|
+
|
|
77
|
+
app = QApplication([])
|
|
78
|
+
|
|
79
|
+
# Create your main window
|
|
80
|
+
window = QWidget()
|
|
81
|
+
window.resize(800, 600)
|
|
82
|
+
|
|
83
|
+
# Apply blur effect
|
|
84
|
+
WipeWindow.create()\
|
|
85
|
+
.set_mode("ghostBlur")\
|
|
86
|
+
.set_radius(15)\
|
|
87
|
+
.apply(window)
|
|
88
|
+
|
|
89
|
+
# Add custom title bar
|
|
90
|
+
title_bar = CustomTitleBar(window, title="My App")
|
|
91
|
+
|
|
92
|
+
# Set app icon
|
|
93
|
+
InmojiTrx("🚀").apply(app)
|
|
94
|
+
|
|
95
|
+
# Create splash screen
|
|
96
|
+
splash = InmersiveSplash.create()\
|
|
97
|
+
.set_mode("adaptive")\
|
|
98
|
+
.set_phrases(["Loading modules...", "Ready!"])\
|
|
99
|
+
.on_finish(window.show)\
|
|
100
|
+
.start()
|
|
101
|
+
|
|
102
|
+
app.exec_()
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## 📖 Documentation
|
|
106
|
+
|
|
107
|
+
### WipeWindow
|
|
108
|
+
|
|
109
|
+
```python
|
|
110
|
+
WipeWindow.create()\
|
|
111
|
+
.set_mode("polished") # "polished", "ghost", or "ghostBlur"
|
|
112
|
+
.set_background("auto") # "auto" or hex color "#RRGGBB"
|
|
113
|
+
.set_radius(20) # Corner radius in pixels
|
|
114
|
+
.set_blur(30) # Blur intensity (ghostBlur mode only)
|
|
115
|
+
.apply(widget)
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### InmersiveSplash
|
|
119
|
+
|
|
120
|
+
```python
|
|
121
|
+
InmersiveSplash.create()\
|
|
122
|
+
.set_mode("adaptive") # "adaptive" or "full"
|
|
123
|
+
.set_color("auto") # "auto" or hex color
|
|
124
|
+
.set_phrases([...]) # List of status messages
|
|
125
|
+
.on_finish(callback) # Function to call when done
|
|
126
|
+
.attach_to_window(win, exit_phrases=[...]) # Auto exit splash
|
|
127
|
+
.start()
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### CustomTitleBar
|
|
131
|
+
|
|
132
|
+
```python
|
|
133
|
+
title_bar = CustomTitleBar(
|
|
134
|
+
parent=window,
|
|
135
|
+
title="My Application",
|
|
136
|
+
icon="🎨"
|
|
137
|
+
)
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### InmojiTrx
|
|
141
|
+
|
|
142
|
+
```python
|
|
143
|
+
# From emoji
|
|
144
|
+
InmojiTrx("🐉").apply(app)
|
|
145
|
+
|
|
146
|
+
# From image file
|
|
147
|
+
InmojiTrx("icon.png").apply(app)
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## 🎯 Requirements
|
|
151
|
+
|
|
152
|
+
- Python 3.8+
|
|
153
|
+
- PyQt5 >= 5.15.0
|
|
154
|
+
- Pillow >= 9.0.0
|
|
155
|
+
- Windows 10/11 (for blur effects)
|
|
156
|
+
|
|
157
|
+
## 📄 License
|
|
158
|
+
|
|
159
|
+
MIT License - feel free to use in your projects!
|
|
160
|
+
|
|
161
|
+
## 🤝 Contributing
|
|
162
|
+
|
|
163
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
164
|
+
|
|
165
|
+
## ⭐ Credits
|
|
166
|
+
|
|
167
|
+
Created by Jesus Quijada
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# Leviathan UI
|
|
2
|
+
|
|
3
|
+
**Premium UI Framework for PyQt5 with Windows 11 Aesthetics**
|
|
4
|
+
|
|
5
|
+
A modern, feature-rich UI framework that brings Windows 11's beautiful design language to your PyQt5 applications.
|
|
6
|
+
|
|
7
|
+
## ✨ Features
|
|
8
|
+
|
|
9
|
+
- **🪟 WipeWindow**: Three stunning window modes
|
|
10
|
+
- `polished`: Solid background with shadows and rounded corners
|
|
11
|
+
- `ghost`: Fully transparent overlay mode
|
|
12
|
+
- `ghostBlur`: Acrylic/frosted glass blur effect (Windows 10/11)
|
|
13
|
+
|
|
14
|
+
- **🌊 InmersiveSplash**: Professional splash screen system
|
|
15
|
+
- Adaptive mode (respects taskbar) and fullscreen mode
|
|
16
|
+
- Custom phrases for startup and exit
|
|
17
|
+
- Smooth fade animations
|
|
18
|
+
- Automatic lifecycle management
|
|
19
|
+
|
|
20
|
+
- **🎨 CustomTitleBar**: Windows 11 style title bar
|
|
21
|
+
- Native SVG-drawn window controls
|
|
22
|
+
- System accent color integration
|
|
23
|
+
- Smooth drag and maximize/minimize
|
|
24
|
+
|
|
25
|
+
- **🎭 InmojiTrx**: High-quality icon generation
|
|
26
|
+
- Convert emojis to multi-resolution ICO files
|
|
27
|
+
- Support for PNG/ICO images
|
|
28
|
+
- Perfect taskbar rendering
|
|
29
|
+
|
|
30
|
+
## 📦 Installation
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pip install leviathan-ui
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Or install from wheel:
|
|
37
|
+
```bash
|
|
38
|
+
pip install leviathan_ui-1.0.0-py3-none-any.whl
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## 🚀 Quick Start
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
from PyQt5.QtWidgets import QApplication, QWidget
|
|
45
|
+
from leviathan_ui import WipeWindow, InmersiveSplash, CustomTitleBar, InmojiTrx
|
|
46
|
+
|
|
47
|
+
app = QApplication([])
|
|
48
|
+
|
|
49
|
+
# Create your main window
|
|
50
|
+
window = QWidget()
|
|
51
|
+
window.resize(800, 600)
|
|
52
|
+
|
|
53
|
+
# Apply blur effect
|
|
54
|
+
WipeWindow.create()\
|
|
55
|
+
.set_mode("ghostBlur")\
|
|
56
|
+
.set_radius(15)\
|
|
57
|
+
.apply(window)
|
|
58
|
+
|
|
59
|
+
# Add custom title bar
|
|
60
|
+
title_bar = CustomTitleBar(window, title="My App")
|
|
61
|
+
|
|
62
|
+
# Set app icon
|
|
63
|
+
InmojiTrx("🚀").apply(app)
|
|
64
|
+
|
|
65
|
+
# Create splash screen
|
|
66
|
+
splash = InmersiveSplash.create()\
|
|
67
|
+
.set_mode("adaptive")\
|
|
68
|
+
.set_phrases(["Loading modules...", "Ready!"])\
|
|
69
|
+
.on_finish(window.show)\
|
|
70
|
+
.start()
|
|
71
|
+
|
|
72
|
+
app.exec_()
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## 📖 Documentation
|
|
76
|
+
|
|
77
|
+
### WipeWindow
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
WipeWindow.create()\
|
|
81
|
+
.set_mode("polished") # "polished", "ghost", or "ghostBlur"
|
|
82
|
+
.set_background("auto") # "auto" or hex color "#RRGGBB"
|
|
83
|
+
.set_radius(20) # Corner radius in pixels
|
|
84
|
+
.set_blur(30) # Blur intensity (ghostBlur mode only)
|
|
85
|
+
.apply(widget)
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### InmersiveSplash
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
InmersiveSplash.create()\
|
|
92
|
+
.set_mode("adaptive") # "adaptive" or "full"
|
|
93
|
+
.set_color("auto") # "auto" or hex color
|
|
94
|
+
.set_phrases([...]) # List of status messages
|
|
95
|
+
.on_finish(callback) # Function to call when done
|
|
96
|
+
.attach_to_window(win, exit_phrases=[...]) # Auto exit splash
|
|
97
|
+
.start()
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### CustomTitleBar
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
title_bar = CustomTitleBar(
|
|
104
|
+
parent=window,
|
|
105
|
+
title="My Application",
|
|
106
|
+
icon="🎨"
|
|
107
|
+
)
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### InmojiTrx
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
# From emoji
|
|
114
|
+
InmojiTrx("🐉").apply(app)
|
|
115
|
+
|
|
116
|
+
# From image file
|
|
117
|
+
InmojiTrx("icon.png").apply(app)
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## 🎯 Requirements
|
|
121
|
+
|
|
122
|
+
- Python 3.8+
|
|
123
|
+
- PyQt5 >= 5.15.0
|
|
124
|
+
- Pillow >= 9.0.0
|
|
125
|
+
- Windows 10/11 (for blur effects)
|
|
126
|
+
|
|
127
|
+
## 📄 License
|
|
128
|
+
|
|
129
|
+
MIT License - feel free to use in your projects!
|
|
130
|
+
|
|
131
|
+
## 🤝 Contributing
|
|
132
|
+
|
|
133
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
134
|
+
|
|
135
|
+
## ⭐ Credits
|
|
136
|
+
|
|
137
|
+
Created by Jesus Quijada
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import traceback
|
|
3
|
+
import sys
|
|
4
|
+
import os
|
|
5
|
+
from datetime import datetime
|
|
6
|
+
|
|
7
|
+
class LeviathanDebugger:
|
|
8
|
+
"""
|
|
9
|
+
Herramienta de depuración robusta para Leviathan.
|
|
10
|
+
Captura errores inesperados y los muestra de forma legible.
|
|
11
|
+
"""
|
|
12
|
+
@staticmethod
|
|
13
|
+
def setup_logging(log_file="debug.log"):
|
|
14
|
+
try:
|
|
15
|
+
logging.basicConfig(
|
|
16
|
+
level=logging.DEBUG,
|
|
17
|
+
format='%(asctime)s [%(levelname)s] %(name)s: %(message)s',
|
|
18
|
+
handlers=[
|
|
19
|
+
logging.FileHandler(log_file, encoding='utf-8'),
|
|
20
|
+
logging.StreamHandler(sys.stdout)
|
|
21
|
+
]
|
|
22
|
+
)
|
|
23
|
+
except Exception as e:
|
|
24
|
+
print(f"⚠️ No se pudo iniciar el logging: {e}")
|
|
25
|
+
|
|
26
|
+
@staticmethod
|
|
27
|
+
def parse_error(e):
|
|
28
|
+
"""Devuelve un resumen formateado del error para la terminal."""
|
|
29
|
+
ts = datetime.now().strftime("%H:%M:%S")
|
|
30
|
+
error_type = type(e).__name__
|
|
31
|
+
msg = str(e)
|
|
32
|
+
tb = traceback.format_exc()
|
|
33
|
+
return f"\n{'='*50}\n[{ts}] ❌ ERROR ({error_type}): {msg}\n--- TRACEBACK ---\n{tb}{'='*50}\n"
|
|
34
|
+
|
|
35
|
+
def _handle_exception(exc_type, exc_value, exc_traceback):
|
|
36
|
+
"""Manejador global de excepciones no capturadas."""
|
|
37
|
+
if issubclass(exc_type, KeyboardInterrupt):
|
|
38
|
+
sys.__excepthook__(exc_type, exc_value, exc_traceback)
|
|
39
|
+
return
|
|
40
|
+
|
|
41
|
+
error_msg = LeviathanDebugger.parse_error(exc_value)
|
|
42
|
+
logging.critical("Excepción no capturada:", exc_info=(exc_type, exc_value, exc_traceback))
|
|
43
|
+
print(error_msg, file=sys.stderr)
|
|
44
|
+
|
|
45
|
+
def install_debugger(log_file="debug.log"):
|
|
46
|
+
"""
|
|
47
|
+
Instala el sistema de depuración global.
|
|
48
|
+
Llama a esto al principio de tu archivo principal.
|
|
49
|
+
"""
|
|
50
|
+
sys.excepthook = _handle_exception
|
|
51
|
+
LeviathanDebugger.setup_logging(log_file)
|
|
52
|
+
print("🚀 Depurador Leviathan Activado")
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from PyQt5.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QLabel,
|
|
3
|
+
QPushButton, QApplication, QFrame)
|
|
4
|
+
from PyQt5.QtCore import Qt, QPropertyAnimation, QEasingCurve, QRect, QPoint, QEvent
|
|
5
|
+
from PyQt5.QtGui import QFont, QColor
|
|
6
|
+
|
|
7
|
+
from .title_bar import CustomTitleBar, get_accent_color
|
|
8
|
+
from .wipeWindow import WipeWindow
|
|
9
|
+
from .lightsOff import LightsOff
|
|
10
|
+
|
|
11
|
+
class LeviathanDialog(QWidget):
|
|
12
|
+
"""
|
|
13
|
+
💠 LeviathanDialog: Reemplazo moderno para QMessageBox.
|
|
14
|
+
Integra Blur Overlay, TitleBar personalizada y efecto LightsOff.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
TYPES = {
|
|
18
|
+
"info": {"icon": "ℹ️", "color": "auto"},
|
|
19
|
+
"success": {"icon": "✅", "color": "#28a745"},
|
|
20
|
+
"warning": {"icon": "⚠️", "color": "#ffc107"},
|
|
21
|
+
"error": {"icon": "❌", "color": "#dc3545"}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
def __init__(self, parent, title, message, mode="info", buttons=None):
|
|
25
|
+
super().__init__(None) # Dialog flotante
|
|
26
|
+
self._parent_win = parent
|
|
27
|
+
self._mode_cfg = self.TYPES.get(mode, self.TYPES["info"])
|
|
28
|
+
self._accent = get_accent_color() if self._mode_cfg["color"] == "auto" else self._mode_cfg["color"]
|
|
29
|
+
self._buttons = buttons or ["ENTENDIDO"]
|
|
30
|
+
self._result = None
|
|
31
|
+
self._callback = None
|
|
32
|
+
|
|
33
|
+
self.setWindowTitle(title)
|
|
34
|
+
self.setFixedSize(450, 240)
|
|
35
|
+
self.setWindowModality(Qt.WindowModal if parent else Qt.NonModal)
|
|
36
|
+
self.setWindowFlags(self.windowFlags() | Qt.WindowStaysOnTopHint)
|
|
37
|
+
|
|
38
|
+
# 1. Overlay Blur (Cubre la ventana principal)
|
|
39
|
+
if self._parent_win:
|
|
40
|
+
self.overlay = QWidget(self._parent_win)
|
|
41
|
+
self.overlay.setGeometry(self._parent_win.rect())
|
|
42
|
+
# Nos aseguramos que el overlay redimensione con el padre
|
|
43
|
+
self._parent_win.installEventFilter(self)
|
|
44
|
+
WipeWindow.create().set_mode("ghostBlur").set_blur(40).apply(self.overlay)
|
|
45
|
+
self.overlay.show()
|
|
46
|
+
else:
|
|
47
|
+
self.overlay = None
|
|
48
|
+
|
|
49
|
+
# 2. Configuración de Ventana (WipeWindow)
|
|
50
|
+
WipeWindow.create()\
|
|
51
|
+
.set_mode("polished")\
|
|
52
|
+
.set_background("#181818")\
|
|
53
|
+
.set_radius(20)\
|
|
54
|
+
.apply(self)
|
|
55
|
+
|
|
56
|
+
# 3. Layout Principal
|
|
57
|
+
self.main_layout = QVBoxLayout(self)
|
|
58
|
+
self.main_layout.setContentsMargins(0, 0, 0, 0)
|
|
59
|
+
self.main_layout.setSpacing(0)
|
|
60
|
+
|
|
61
|
+
# Barra de Título
|
|
62
|
+
self.title_bar = CustomTitleBar(self, title=title, icon=self._mode_cfg["icon"])
|
|
63
|
+
self.main_layout.addWidget(self.title_bar)
|
|
64
|
+
|
|
65
|
+
# Contenido
|
|
66
|
+
content_frame = QFrame()
|
|
67
|
+
content_lay = QVBoxLayout(content_frame)
|
|
68
|
+
content_lay.setContentsMargins(30, 20, 30, 25)
|
|
69
|
+
content_lay.setSpacing(20)
|
|
70
|
+
|
|
71
|
+
msg_lay = QHBoxLayout()
|
|
72
|
+
icon_lbl = QLabel(self._mode_cfg["icon"])
|
|
73
|
+
icon_lbl.setFont(QFont("Segoe UI Emoji", 32))
|
|
74
|
+
icon_lbl.setStyleSheet("background: transparent;")
|
|
75
|
+
|
|
76
|
+
self.msg_lbl = QLabel(message)
|
|
77
|
+
self.msg_lbl.setWordWrap(True)
|
|
78
|
+
self.msg_lbl.setStyleSheet("color: #eeeeee; font-size: 14px; font-family: 'Segoe UI'; background: transparent;")
|
|
79
|
+
|
|
80
|
+
msg_lay.addWidget(icon_lbl)
|
|
81
|
+
msg_lay.addSpacing(15)
|
|
82
|
+
msg_lay.addWidget(self.msg_lbl, 1)
|
|
83
|
+
content_lay.addLayout(msg_lay)
|
|
84
|
+
|
|
85
|
+
# Botones Dinámicos
|
|
86
|
+
btn_container = QHBoxLayout()
|
|
87
|
+
btn_container.addStretch()
|
|
88
|
+
|
|
89
|
+
for btn_text in self._buttons:
|
|
90
|
+
btn = QPushButton(btn_text)
|
|
91
|
+
btn.setFixedSize(110, 36)
|
|
92
|
+
|
|
93
|
+
# Estilo basado en acento
|
|
94
|
+
is_main = btn_text == self._buttons[-1]
|
|
95
|
+
bg = self._accent if is_main else "transparent"
|
|
96
|
+
fg = "black" if is_main else "white"
|
|
97
|
+
border = f"2px solid {self._accent}"
|
|
98
|
+
|
|
99
|
+
btn.setStyleSheet(f"""
|
|
100
|
+
QPushButton {{
|
|
101
|
+
background-color: {bg};
|
|
102
|
+
color: {fg};
|
|
103
|
+
border: {border};
|
|
104
|
+
border-radius: 8px;
|
|
105
|
+
font-weight: bold;
|
|
106
|
+
font-family: 'Segoe UI';
|
|
107
|
+
}}
|
|
108
|
+
QPushButton:hover {{
|
|
109
|
+
background-color: white;
|
|
110
|
+
color: black;
|
|
111
|
+
border: 2px solid white;
|
|
112
|
+
}}
|
|
113
|
+
""")
|
|
114
|
+
|
|
115
|
+
# Efecto Glow
|
|
116
|
+
LightsOff.light_up(btn, color=self._accent if not is_main else "#ffffff", intensity=15)
|
|
117
|
+
|
|
118
|
+
btn.clicked.connect(lambda checked, t=btn_text: self._on_btn_clicked(t))
|
|
119
|
+
btn_container.addWidget(btn)
|
|
120
|
+
|
|
121
|
+
content_lay.addLayout(btn_container)
|
|
122
|
+
self.main_layout.addWidget(content_frame)
|
|
123
|
+
|
|
124
|
+
# Centrar respecto al padre
|
|
125
|
+
self._update_position()
|
|
126
|
+
|
|
127
|
+
# 5. Animaciones combinadas (Opacidad + Escala/Posición)
|
|
128
|
+
self.setWindowOpacity(0)
|
|
129
|
+
self.fade_anim = QPropertyAnimation(self, b"windowOpacity")
|
|
130
|
+
self.fade_anim.setDuration(350)
|
|
131
|
+
self.fade_anim.setStartValue(0)
|
|
132
|
+
self.fade_anim.setEndValue(1)
|
|
133
|
+
self.fade_anim.setEasingCurve(QEasingCurve.OutCubic)
|
|
134
|
+
|
|
135
|
+
def _update_position(self):
|
|
136
|
+
if self._parent_win:
|
|
137
|
+
center = self._parent_win.geometry().center()
|
|
138
|
+
self.move(center.x() - self.width() // 2, center.y() - self.height() // 2)
|
|
139
|
+
|
|
140
|
+
def eventFilter(self, obj, event):
|
|
141
|
+
# Sincronizar overlay con el padre si este cambia de tamaño
|
|
142
|
+
try:
|
|
143
|
+
if obj == self._parent_win and event.type() == QEvent.Resize:
|
|
144
|
+
if self.overlay:
|
|
145
|
+
self.overlay.setGeometry(self._parent_win.rect())
|
|
146
|
+
except: pass
|
|
147
|
+
return super().eventFilter(obj, event)
|
|
148
|
+
|
|
149
|
+
def _on_btn_clicked(self, text):
|
|
150
|
+
self._result = text
|
|
151
|
+
self.close()
|
|
152
|
+
# El callback se ejecuta DESPUÉS del close para que la UI esté limpia
|
|
153
|
+
if self._callback: self._callback(text)
|
|
154
|
+
|
|
155
|
+
def showEvent(self, event):
|
|
156
|
+
self.fade_anim.start()
|
|
157
|
+
super().showEvent(event)
|
|
158
|
+
|
|
159
|
+
def closeEvent(self, event):
|
|
160
|
+
# MUY IMPORTANTE: Remover el filtro antes de cerrar para evitar punteros rotos
|
|
161
|
+
if self._parent_win:
|
|
162
|
+
self._parent_win.removeEventFilter(self)
|
|
163
|
+
if self.overlay:
|
|
164
|
+
self.overlay.close()
|
|
165
|
+
self.overlay.deleteLater()
|
|
166
|
+
event.accept()
|
|
167
|
+
self.deleteLater() # Asegura que Python libere el objeto
|
|
168
|
+
|
|
169
|
+
@staticmethod
|
|
170
|
+
def launch(parent, title, message, mode="info", buttons=None, callback=None):
|
|
171
|
+
dlg = LeviathanDialog(parent, title, message, mode, buttons)
|
|
172
|
+
dlg._callback = callback
|
|
173
|
+
dlg.show()
|
|
174
|
+
return dlg
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
class FixLights:
|
|
2
|
+
"""
|
|
3
|
+
🛠️ fixLights: Debugger especializado para el sistema de iluminación.
|
|
4
|
+
Verifica si los widgets tienen efectos aplicados y si las animaciones están listas.
|
|
5
|
+
"""
|
|
6
|
+
@staticmethod
|
|
7
|
+
def audit(widget):
|
|
8
|
+
"""Revisa la salud visual de un widget."""
|
|
9
|
+
has_effect = widget.graphicsEffect() is not None
|
|
10
|
+
status = "✅ OK" if has_effect else "❌ NO LIGHTS"
|
|
11
|
+
print(f"Audit [{widget.objectName() or 'Widget'}]: {status}")
|
|
12
|
+
return has_effect
|
|
13
|
+
|
|
14
|
+
@staticmethod
|
|
15
|
+
def fix_all(app):
|
|
16
|
+
"""Intenta reaplicar efectos a todos los hijos de la app si fallan."""
|
|
17
|
+
from .lightsOff import light_up
|
|
18
|
+
for widget in app.allWidgets():
|
|
19
|
+
if not widget.graphicsEffect():
|
|
20
|
+
light_up(widget)
|
|
21
|
+
print("🛠️ fixLights: Iluminación restaurada en todos los controles.")
|