Mejora del panel LaTeX y ajustes en la configuración de la interfaz. Se implementa un sistema para verificar la disponibilidad de MathJax y se optimiza la gestión de ecuaciones pendientes. Se actualizan estilos y se ajusta la geometría de la ventana. Se añade un wrapper para la función 'solve' que convierte cadenas a símbolos automáticamente, mejorando la resolución de ecuaciones.
This commit is contained in:
parent
b7e35d1ae3
commit
68bed8937a
|
@ -1,12 +1,20 @@
|
|||
|
||||
x=t**2+5/m
|
||||
t=?
|
||||
|
||||
m=3
|
||||
x=4
|
||||
|
||||
t=?
|
||||
|
||||
solve(t)
|
||||
form=solve(t)
|
||||
|
||||
|
||||
ip=IP4(10.1.1.1,20)
|
||||
ip.BroadcastAddress()
|
||||
|
||||
# Test LATEX
|
||||
$$Brix = \frac{Brix_{syrup} \cdot \delta_{syrup} + (Brix_{water} \cdot \delta_{water} \cdot Rateo)}{\delta_{syrup} + \delta_{water} \cdot Rateo}$$
|
||||
$$Brix = \frac{Solid_Weight}{Total_Weight}$$
|
||||
$$\delta = \frac{W}{V} \Rightarrow W = \delta \cdot V$$
|
||||
$$Brix_{Bev} = \frac{Brix_{syr} + Brix_{H_2O} \cdot R_M}{R_M + 1}$$
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
{
|
||||
"window_geometry": {
|
||||
"x": 732,
|
||||
"y": 205,
|
||||
"width": 741,
|
||||
"x": 332,
|
||||
"y": 170,
|
||||
"width": 1353,
|
||||
"height": 700
|
||||
},
|
||||
"debug_mode": false,
|
||||
"latex_panel_visible": true,
|
||||
"sash_pos_x": 450,
|
||||
"splitter_sizes": [
|
||||
210,
|
||||
155
|
||||
357,
|
||||
472
|
||||
]
|
||||
}
|
|
@ -116,8 +116,16 @@ class LatexPanel(QWidget):
|
|||
super().__init__(parent)
|
||||
self.equations = []
|
||||
self._webview_available = False
|
||||
self._mathjax_ready = False
|
||||
self._pending_equations = []
|
||||
self._parent_calculator = parent
|
||||
self._setup_ui()
|
||||
|
||||
# Timer para verificar si MathJax está listo
|
||||
self._mathjax_check_timer = QTimer()
|
||||
self._mathjax_check_timer.timeout.connect(self._check_mathjax_ready)
|
||||
self._mathjax_check_timer.start(500) # Verificar cada 500ms
|
||||
|
||||
def _setup_ui(self):
|
||||
"""Configura la UI del panel"""
|
||||
layout = QVBoxLayout(self)
|
||||
|
@ -212,8 +220,16 @@ class LatexPanel(QWidget):
|
|||
processEscapes: true
|
||||
},
|
||||
chtml: {
|
||||
scale: 1.1,
|
||||
scale: 0.9,
|
||||
minScale: 0.5
|
||||
},
|
||||
startup: {
|
||||
ready: function () {
|
||||
MathJax.startup.defaultReady();
|
||||
// Notificar que MathJax está listo
|
||||
window.mathJaxReady = true;
|
||||
console.log('MathJax completamente cargado');
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
@ -223,19 +239,18 @@ class LatexPanel(QWidget):
|
|||
color: #d4d4d4;
|
||||
font-family: 'Segoe UI', Arial, sans-serif;
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
line-height: 1.6;
|
||||
padding: 8px;
|
||||
line-height: 1.2;
|
||||
}
|
||||
.equation-block {
|
||||
background: rgba(45, 45, 48, 0.8);
|
||||
border-left: 4px solid;
|
||||
margin: 12px 0;
|
||||
padding: 15px 20px;
|
||||
border-radius: 8px;
|
||||
transition: all 0.2s ease;
|
||||
border-left: 3px solid;
|
||||
margin: 4px 0;
|
||||
padding: 6px 12px;
|
||||
border-radius: 4px;
|
||||
transition: all 0.1s ease;
|
||||
}
|
||||
.equation-block:hover {
|
||||
transform: translateY(-1px);
|
||||
background: rgba(45, 45, 48, 0.9);
|
||||
}
|
||||
.comment { border-left-color: #6a9955; }
|
||||
|
@ -243,35 +258,49 @@ class LatexPanel(QWidget):
|
|||
.equation { border-left-color: #c586c0; }
|
||||
.symbolic { border-left-color: #9cdcfe; }
|
||||
|
||||
.equation-type {
|
||||
font-size: 11px;
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
margin-bottom: 8px;
|
||||
opacity: 0.8;
|
||||
.math-content {
|
||||
margin: 2px 0;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.comment-text {
|
||||
font-style: italic;
|
||||
color: #6a9955;
|
||||
font-size: 12px;
|
||||
margin: 0;
|
||||
}
|
||||
.comment .equation-type { color: #6a9955; }
|
||||
.assignment .equation-type { color: #dcdcaa; }
|
||||
.equation .equation-type { color: #c586c0; }
|
||||
.symbolic .equation-type { color: #9cdcfe; }
|
||||
|
||||
.info-message {
|
||||
text-align: center;
|
||||
padding: 40px 20px;
|
||||
color: #888;
|
||||
font-style: italic;
|
||||
padding: 20px;
|
||||
color: #666;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* Reducir espaciado de MathJax */
|
||||
.MathJax {
|
||||
font-size: 0.9em !important;
|
||||
}
|
||||
|
||||
mjx-math {
|
||||
margin: 1px 0 !important;
|
||||
}
|
||||
|
||||
mjx-container {
|
||||
margin: 2px 0 !important;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="equations-container">
|
||||
<div class="info-message">
|
||||
📐 Panel de Ecuaciones LaTeX<br/>
|
||||
<small>Las ecuaciones aparecerán aquí automáticamente</small>
|
||||
Panel de Ecuaciones LaTeX
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
window.mathJaxReady = false;
|
||||
|
||||
function addEquation(type, content) {
|
||||
var container = document.getElementById('equations-container');
|
||||
|
||||
|
@ -282,25 +311,21 @@ class LatexPanel(QWidget):
|
|||
var equation = document.createElement('div');
|
||||
equation.className = 'equation-block ' + type;
|
||||
|
||||
var typeLabel = document.createElement('div');
|
||||
typeLabel.className = 'equation-type';
|
||||
typeLabel.textContent = type.charAt(0).toUpperCase() + type.slice(1);
|
||||
|
||||
var mathContent = document.createElement('div');
|
||||
mathContent.className = 'math-content';
|
||||
|
||||
if (type === 'comment') {
|
||||
mathContent.style.fontStyle = 'italic';
|
||||
mathContent.style.color = '#6a9955';
|
||||
mathContent.className = 'comment-text';
|
||||
mathContent.textContent = content;
|
||||
} else {
|
||||
mathContent.innerHTML = '$$' + content + '$$';
|
||||
}
|
||||
|
||||
equation.appendChild(typeLabel);
|
||||
equation.appendChild(mathContent);
|
||||
container.appendChild(equation);
|
||||
|
||||
// Re-renderizar MathJax
|
||||
if (window.MathJax && type !== 'comment') {
|
||||
// Re-renderizar MathJax solo si está listo
|
||||
if (window.MathJax && window.mathJaxReady && type !== 'comment') {
|
||||
MathJax.typesetPromise([equation]).catch(function(err) {
|
||||
console.error('MathJax error:', err);
|
||||
});
|
||||
|
@ -309,21 +334,67 @@ class LatexPanel(QWidget):
|
|||
|
||||
function clearEquations() {
|
||||
var container = document.getElementById('equations-container');
|
||||
container.innerHTML = '<div class="info-message">📐 Panel de Ecuaciones LaTeX<br/><small>Las ecuaciones aparecerán aquí automáticamente</small></div>';
|
||||
container.innerHTML = '<div class="info-message">Panel de Ecuaciones LaTeX</div>';
|
||||
}
|
||||
|
||||
// Función para notificar que está listo para renderizar
|
||||
function triggerInitialRender() {
|
||||
if (window.mathJaxReady) {
|
||||
// Notificar a Python que MathJax está listo
|
||||
console.log('MathJax listo para renderizado inicial');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>"""
|
||||
|
||||
def _check_mathjax_ready(self):
|
||||
"""Verifica si MathJax está listo y renderiza ecuaciones pendientes"""
|
||||
if not self._webview_available:
|
||||
return
|
||||
|
||||
# Verificar si MathJax está listo
|
||||
self.webview.page().runJavaScript(
|
||||
"window.mathJaxReady || false;",
|
||||
self._on_mathjax_ready_check
|
||||
)
|
||||
|
||||
def _on_mathjax_ready_check(self, ready):
|
||||
"""Callback cuando se verifica el estado de MathJax"""
|
||||
if ready and not self._mathjax_ready:
|
||||
self._mathjax_ready = True
|
||||
self._mathjax_check_timer.stop()
|
||||
logging.debug("✅ MathJax listo, procesando ecuaciones pendientes")
|
||||
|
||||
# Renderizar ecuaciones pendientes
|
||||
for eq in self._pending_equations:
|
||||
self._add_equation_to_webview(eq['type'], eq['content'])
|
||||
self._pending_equations.clear()
|
||||
|
||||
# Trigger initial render si hay un calculador padre
|
||||
if self._parent_calculator and hasattr(self._parent_calculator, '_trigger_initial_latex_render'):
|
||||
self._parent_calculator._trigger_initial_latex_render()
|
||||
|
||||
def _add_equation_to_webview(self, eq_type: str, content: str):
|
||||
"""Añade una ecuación directamente al webview"""
|
||||
if self._webview_available:
|
||||
escaped_content = content.replace('\\', '\\\\').replace("'", "\\'").replace('"', '\\"')
|
||||
js_code = f"addEquation('{eq_type}', '{escaped_content}');"
|
||||
self.webview.page().runJavaScript(js_code)
|
||||
|
||||
def add_equation(self, eq_type: str, content: str):
|
||||
"""Añade una ecuación al panel"""
|
||||
self.equations.append({'type': eq_type, 'content': content})
|
||||
|
||||
if self._webview_available:
|
||||
# Escapar contenido para JavaScript
|
||||
escaped_content = content.replace('\\', '\\\\').replace("'", "\\'").replace('"', '\\"')
|
||||
js_code = f"addEquation('{eq_type}', '{escaped_content}');"
|
||||
self.webview.page().runJavaScript(js_code)
|
||||
if self._mathjax_ready:
|
||||
# MathJax está listo, renderizar inmediatamente
|
||||
self._add_equation_to_webview(eq_type, content)
|
||||
else:
|
||||
# MathJax no está listo, guardar para después
|
||||
self._pending_equations.append({'type': eq_type, 'content': content})
|
||||
else:
|
||||
# Actualizar HTML en text browser
|
||||
self._update_text_browser()
|
||||
|
@ -331,6 +402,7 @@ class LatexPanel(QWidget):
|
|||
def clear_equations(self):
|
||||
"""Limpia todas las ecuaciones"""
|
||||
self.equations.clear()
|
||||
self._pending_equations.clear()
|
||||
|
||||
if self._webview_available:
|
||||
self.webview.page().runJavaScript("clearEquations();")
|
||||
|
@ -341,28 +413,49 @@ class LatexPanel(QWidget):
|
|||
"""Actualiza el contenido del text browser (fallback)"""
|
||||
html_parts = ["""
|
||||
<style>
|
||||
body { background-color: #1a1a1a; color: #d4d4d4; font-family: 'Consolas'; }
|
||||
.equation { margin: 10px 0; padding: 10px; background: #2d2d2d; border-left: 3px solid #80c7f7; border-radius: 3px; }
|
||||
.comment { border-left-color: #6a9955; font-style: italic; }
|
||||
body {
|
||||
background-color: #1a1a1a;
|
||||
color: #d4d4d4;
|
||||
font-family: 'Consolas';
|
||||
margin: 0;
|
||||
padding: 8px;
|
||||
line-height: 1.2;
|
||||
}
|
||||
.equation {
|
||||
margin: 4px 0;
|
||||
padding: 6px 12px;
|
||||
background: rgba(45, 45, 48, 0.8);
|
||||
border-left: 3px solid #80c7f7;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
}
|
||||
.comment {
|
||||
border-left-color: #6a9955;
|
||||
font-style: italic;
|
||||
color: #6a9955;
|
||||
font-size: 11px;
|
||||
}
|
||||
.assignment { border-left-color: #dcdcaa; }
|
||||
.equation-type { border-left-color: #c586c0; }
|
||||
.symbolic { border-left-color: #9cdcfe; }
|
||||
.type-label { font-size: 10px; color: #808080; margin-bottom: 5px; }
|
||||
code {
|
||||
font-family: 'Consolas';
|
||||
font-size: 11px;
|
||||
color: #d4d4d4;
|
||||
}
|
||||
</style>
|
||||
"""]
|
||||
|
||||
for eq in self.equations:
|
||||
eq_type = eq['type']
|
||||
content = eq['content']
|
||||
|
||||
type_label = eq_type.capitalize()
|
||||
css_class = eq_type
|
||||
|
||||
if eq_type == 'comment':
|
||||
html_parts.append(f'<div class="equation {css_class}"><div class="type-label">{type_label}</div>{content}</div>')
|
||||
html_parts.append(f'<div class="equation {css_class}">{content}</div>')
|
||||
else:
|
||||
# Para ecuaciones matemáticas, mostrar en formato de código
|
||||
html_parts.append(f'<div class="equation {css_class}"><div class="type-label">{type_label}</div><code>{content}</code></div>')
|
||||
html_parts.append(f'<div class="equation {css_class}"><code>{content}</code></div>')
|
||||
|
||||
self.text_browser.setHtml(''.join(html_parts))
|
||||
|
||||
|
@ -586,7 +679,7 @@ class HybridCalculatorPySide6(QMainWindow):
|
|||
main_layout.addWidget(self.latex_button)
|
||||
|
||||
# Panel LaTeX (inicialmente oculto)
|
||||
self.latex_panel = LatexPanel()
|
||||
self.latex_panel = LatexPanel(self)
|
||||
self.latex_panel.setMinimumWidth(300)
|
||||
self.latex_panel.setMaximumWidth(500)
|
||||
|
||||
|
@ -890,6 +983,17 @@ class HybridCalculatorPySide6(QMainWindow):
|
|||
except Exception as e:
|
||||
self._show_error(f"Error durante evaluación: {e}")
|
||||
|
||||
def _trigger_initial_latex_render(self):
|
||||
"""Activa el renderizado inicial del panel LaTeX cuando MathJax está listo"""
|
||||
try:
|
||||
# Solo hacer evaluación inicial si hay contenido en el input
|
||||
input_content = self.input_text.toPlainText()
|
||||
if input_content.strip():
|
||||
logging.debug("🎯 Activando renderizado inicial de LaTeX")
|
||||
self._evaluate_and_update()
|
||||
except Exception as e:
|
||||
logging.error(f"Error en renderizado inicial de LaTeX: {e}")
|
||||
|
||||
def _evaluate_lines(self, lines: List[str]):
|
||||
"""Evalúa múltiples líneas de código"""
|
||||
output_data = []
|
||||
|
|
|
@ -80,7 +80,6 @@ class PureAlgebraicEngine:
|
|||
'sqrt': sp.sqrt, 'abs': sp.Abs,
|
||||
'pi': sp.pi, 'e': sp.E, 'I': sp.I,
|
||||
'oo': sp.oo, 'inf': sp.oo,
|
||||
'solve': self._smart_solve,
|
||||
'Eq': sp.Eq, 'simplify': sp.simplify,
|
||||
'expand': sp.expand, 'factor': sp.factor,
|
||||
'diff': sp.diff, 'integrate': sp.integrate,
|
||||
|
@ -98,7 +97,55 @@ class PureAlgebraicEngine:
|
|||
# 2. TIPOS PERSONALIZADOS REGISTRADOS (CLAVE PARA INSTANCIACIÓN)
|
||||
registered_types = get_registered_base_context()
|
||||
|
||||
# 3. FUNCIONES DE PLOTTING (WRAPPED)
|
||||
# 3. FUNCIÓN SOLVE ESPECIAL que maneja cadenas como símbolos
|
||||
def solve_wrapper(*args, **kwargs):
|
||||
"""Wrapper para solve que convierte cadenas a símbolos automáticamente"""
|
||||
processed_args = []
|
||||
for arg in args:
|
||||
if isinstance(arg, str):
|
||||
# Si es una cadena, convertir a símbolo
|
||||
processed_args.append(sp.Symbol(arg))
|
||||
elif hasattr(arg, 'is_number') and arg.is_number:
|
||||
# Si es un valor numérico, buscar el símbolo correspondiente
|
||||
# en symbol_table y verificar contexto
|
||||
for var_name, var_value in self.symbol_table.items():
|
||||
if var_value == arg:
|
||||
# Encontramos una variable con este valor, usar el símbolo
|
||||
processed_args.append(sp.Symbol(var_name))
|
||||
break
|
||||
else:
|
||||
# Si no se encuentra, intentar usar _smart_solve directo
|
||||
# que puede manejar valores numéricos
|
||||
processed_args.append(arg)
|
||||
else:
|
||||
processed_args.append(arg)
|
||||
|
||||
result = self._smart_solve(*processed_args, **kwargs)
|
||||
|
||||
# Si el resultado está vacío, intentar un enfoque alternativo
|
||||
if hasattr(result, '__len__') and len(result) == 0:
|
||||
# Caso especial: si solve() devuelve lista vacía,
|
||||
# intentar resolver como si no hubiera valores asignados
|
||||
alt_args = []
|
||||
for arg in args:
|
||||
if hasattr(arg, 'is_number') and arg.is_number:
|
||||
# Buscar la variable que tiene este valor
|
||||
for var_name, var_value in self.symbol_table.items():
|
||||
if var_value == arg:
|
||||
alt_args.append(sp.Symbol(var_name))
|
||||
break
|
||||
else:
|
||||
alt_args.append(arg)
|
||||
else:
|
||||
alt_args.append(arg)
|
||||
|
||||
if alt_args != processed_args:
|
||||
# Si hay diferencia, reintentar
|
||||
return self._smart_solve(*alt_args, **kwargs)
|
||||
|
||||
return result
|
||||
|
||||
# 4. FUNCIONES DE PLOTTING (WRAPPED)
|
||||
# Wrappers para capturar llamadas de plot y devolver un objeto PlotResult
|
||||
def plot_wrapper(*args, **kwargs):
|
||||
# Intentar extraer la expresión original del primer argumento
|
||||
|
@ -127,14 +174,15 @@ class PureAlgebraicEngine:
|
|||
'plot3d_parametric_line': plot3d_parametric_line_wrapper,
|
||||
}
|
||||
|
||||
# 4. COMBINAR TODO EN CONTEXTO UNIFICADO
|
||||
# 5. COMBINAR TODO EN CONTEXTO UNIFICADO
|
||||
self.unified_context = {
|
||||
**sympy_functions,
|
||||
**registered_types, # IP4, FourBytes, IntBase, etc.
|
||||
**plotting_functions
|
||||
**plotting_functions,
|
||||
'solve': solve_wrapper
|
||||
}
|
||||
|
||||
# 5. VERIFICAR CARGA DE TIPOS PRINCIPALES
|
||||
# 6. VERIFICAR CARGA DE TIPOS PRINCIPALES
|
||||
required_classes = ['IP4', 'IP4Mask', 'FourBytes', 'IntBase', 'Hex', 'Bin', 'Dec', 'Chr', 'LaTeX']
|
||||
missing_classes = [cls for cls in required_classes if cls not in self.unified_context]
|
||||
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test final para verificar que el problema de solve(t) esté solucionado
|
||||
"""
|
||||
from main_evaluation_puro import PureAlgebraicEngine
|
||||
|
||||
def test_solve_issue():
|
||||
print("=== TEST FINAL: PROBLEMA SOLVE(T) ===")
|
||||
|
||||
engine = PureAlgebraicEngine()
|
||||
|
||||
# Secuencia original del usuario
|
||||
lines = [
|
||||
'x=t**2+5/m',
|
||||
'm=3',
|
||||
'x=4',
|
||||
't=?',
|
||||
'solve(t)',
|
||||
'form=solve(t)'
|
||||
]
|
||||
|
||||
print("Ejecutando secuencia del usuario:")
|
||||
for i, line in enumerate(lines, 1):
|
||||
result = engine.evaluate_line(line)
|
||||
status = "✅" if result.success else "❌"
|
||||
print(f"{i}. {line:<15} -> {result.output} {status}")
|
||||
|
||||
# Verificar específicamente el caso problemático
|
||||
if line == 'form=solve(t)':
|
||||
if result.output == 'form = []':
|
||||
print(" ❌ PROBLEMA PERSISTE: form está vacío")
|
||||
return False
|
||||
else:
|
||||
print(" ✅ PROBLEMA SOLUCIONADO: form contiene resultado")
|
||||
return True
|
||||
|
||||
return True
|
||||
|
||||
if __name__ == "__main__":
|
||||
success = test_solve_issue()
|
||||
if success:
|
||||
print("\n🎉 PROBLEMA SOLUCIONADO EXITOSAMENTE")
|
||||
else:
|
||||
print("\n💥 PROBLEMA PERSISTE")
|
Loading…
Reference in New Issue