Mejora en la gestión de plots y enlaces interactivos. Se añade manejo de errores para la disponibilidad de Matplotlib y se optimiza la creación de plots con un fondo oscuro. Se implementa el cambio de cursor al pasar sobre enlaces en el editor de texto, mejorando la experiencia del usuario. Se añaden mensajes de depuración para el seguimiento de eventos de clic en enlaces.
This commit is contained in:
parent
8c84eb4195
commit
6bf43bf974
|
@ -1,19 +1 @@
|
||||||
|
|
||||||
salario=horas*tarifa
|
|
||||||
#salario=8000
|
|
||||||
#tarifa=36
|
|
||||||
|
|
||||||
horas=?
|
|
||||||
|
|
||||||
|
|
||||||
plot(sin(x), (x, 0, 1))
|
plot(sin(x), (x, 0, 1))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,7 @@ class EvaluationManager:
|
||||||
'custom_type': self._create_format("#4ec9b0"),
|
'custom_type': self._create_format("#4ec9b0"),
|
||||||
'plot': self._create_format("#569cd6", underline=True),
|
'plot': self._create_format("#569cd6", underline=True),
|
||||||
'type_indicator': self._create_format("#808080"),
|
'type_indicator': self._create_format("#808080"),
|
||||||
'clickable': self._create_format("#4fc3f7", underline=True),
|
'clickable': self._create_format("#4fc3f7", underline=True, bold=True),
|
||||||
'helper': self._create_format("#ffd700", italic=True)
|
'helper': self._create_format("#ffd700", italic=True)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,6 +254,7 @@ class EvaluationManager:
|
||||||
cursor.insertText(display_text, self.output_formats.get('clickable'))
|
cursor.insertText(display_text, self.output_formats.get('clickable'))
|
||||||
end_pos = cursor.position()
|
end_pos = cursor.position()
|
||||||
self.main_window.output_text.clickable_links[(start_pos, end_pos)] = (link_id, result_object)
|
self.main_window.output_text.clickable_links[(start_pos, end_pos)] = (link_id, result_object)
|
||||||
|
self.logger.debug(f"🔗 Link creado: {display_text} en posición {start_pos}-{end_pos}, ID: {link_id}")
|
||||||
|
|
||||||
elif len(part_data) >= 2:
|
elif len(part_data) >= 2:
|
||||||
tag, content = part_data[0], part_data[1]
|
tag, content = part_data[0], part_data[1]
|
||||||
|
|
|
@ -293,6 +293,7 @@ class HybridCalculatorPySide6(QMainWindow):
|
||||||
|
|
||||||
def _handle_output_link_click(self, link_id: str, result_object):
|
def _handle_output_link_click(self, link_id: str, result_object):
|
||||||
"""Maneja clicks en links del output"""
|
"""Maneja clicks en links del output"""
|
||||||
|
self.logger.debug(f"🖱️ Click en link recibido: {link_id}, objeto: {type(result_object).__name__}")
|
||||||
# Delegar al evaluation manager
|
# Delegar al evaluation manager
|
||||||
self.evaluation_manager.handle_output_link_click(link_id, result_object)
|
self.evaluation_manager.handle_output_link_click(link_id, result_object)
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,13 @@ from PySide6.QtGui import QFont, QTextCursor, QTextCharFormat, QColor
|
||||||
from PySide6.QtWebEngineWidgets import QWebEngineView
|
from PySide6.QtWebEngineWidgets import QWebEngineView
|
||||||
import sympy
|
import sympy
|
||||||
from typing import Any, Optional, Dict, List, Tuple
|
from typing import Any, Optional, Dict, List, Tuple
|
||||||
|
try:
|
||||||
import matplotlib.pyplot as plt
|
import matplotlib.pyplot as plt
|
||||||
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
|
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
|
||||||
|
MATPLOTLIB_AVAILABLE = True
|
||||||
|
except ImportError:
|
||||||
|
print("⚠️ Matplotlib no disponible - plots no funcionarán")
|
||||||
|
MATPLOTLIB_AVAILABLE = False
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
|
|
||||||
|
@ -127,11 +132,8 @@ class InteractiveResultManager(QWidget):
|
||||||
def handle_interactive_click(self, result: Any, is_mathjax_click: bool = False):
|
def handle_interactive_click(self, result: Any, is_mathjax_click: bool = False):
|
||||||
"""Maneja clicks en elementos interactivos"""
|
"""Maneja clicks en elementos interactivos"""
|
||||||
if isinstance(result, PlotResult):
|
if isinstance(result, PlotResult):
|
||||||
if not is_mathjax_click:
|
# Abrir ventana de plot directamente
|
||||||
# Primera vez: mostrar en MathJax
|
print(f"🖱️ Abriendo ventana de plot para: {result.plot_type}")
|
||||||
self.plot_requested.emit(result)
|
|
||||||
else:
|
|
||||||
# Click en MathJax: abrir ventana emergente
|
|
||||||
self._show_plot_window(result)
|
self._show_plot_window(result)
|
||||||
else:
|
else:
|
||||||
# Otros tipos siempre abren ventana
|
# Otros tipos siempre abren ventana
|
||||||
|
@ -303,7 +305,18 @@ class InteractiveResultManager(QWidget):
|
||||||
if not parent_frame.layout():
|
if not parent_frame.layout():
|
||||||
parent_frame.setLayout(QVBoxLayout())
|
parent_frame.setLayout(QVBoxLayout())
|
||||||
|
|
||||||
|
if not MATPLOTLIB_AVAILABLE:
|
||||||
|
error_label = QLabel("Matplotlib no está disponible.\nInstala con: pip install matplotlib")
|
||||||
|
error_label.setStyleSheet("color: #f44747; font-size: 12px;")
|
||||||
|
error_label.setWordWrap(True)
|
||||||
|
parent_frame.layout().addWidget(error_label)
|
||||||
|
return
|
||||||
|
|
||||||
|
print(f"📊 Creando plot {plot_result.plot_type} con args: {plot_result.args}")
|
||||||
|
|
||||||
fig, ax = plt.subplots(figsize=(8, 6))
|
fig, ax = plt.subplots(figsize=(8, 6))
|
||||||
|
fig.patch.set_facecolor('#1a1a1a') # Fondo oscuro
|
||||||
|
ax.set_facecolor('#1a1a1a')
|
||||||
|
|
||||||
if plot_result.plot_type == "plot":
|
if plot_result.plot_type == "plot":
|
||||||
self._create_2d_plot(fig, ax, plot_result.args, plot_result.kwargs)
|
self._create_2d_plot(fig, ax, plot_result.args, plot_result.kwargs)
|
||||||
|
@ -314,7 +327,13 @@ class InteractiveResultManager(QWidget):
|
||||||
canvas = FigureCanvasQTAgg(fig)
|
canvas = FigureCanvasQTAgg(fig)
|
||||||
parent_frame.layout().addWidget(canvas)
|
parent_frame.layout().addWidget(canvas)
|
||||||
|
|
||||||
|
print("✅ Plot creado exitosamente")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
print(f"❌ Error creando plot: {e}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
if not parent_frame.layout():
|
if not parent_frame.layout():
|
||||||
parent_frame.setLayout(QVBoxLayout())
|
parent_frame.setLayout(QVBoxLayout())
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,7 @@ class OutputTextEdit(QTextEdit):
|
||||||
self.setReadOnly(True)
|
self.setReadOnly(True)
|
||||||
self.setFont(QFont("Consolas", 11))
|
self.setFont(QFont("Consolas", 11))
|
||||||
self.clickable_links = {} # {(start, end): (link_id, object)}
|
self.clickable_links = {} # {(start, end): (link_id, object)}
|
||||||
|
self.setMouseTracking(True) # Habilitar tracking del mouse
|
||||||
|
|
||||||
def mousePressEvent(self, event):
|
def mousePressEvent(self, event):
|
||||||
"""Detecta clicks en links"""
|
"""Detecta clicks en links"""
|
||||||
|
@ -60,6 +61,26 @@ class OutputTextEdit(QTextEdit):
|
||||||
|
|
||||||
super().mousePressEvent(event)
|
super().mousePressEvent(event)
|
||||||
|
|
||||||
|
def mouseMoveEvent(self, event):
|
||||||
|
"""Cambia el cursor cuando está sobre un link"""
|
||||||
|
cursor = self.cursorForPosition(event.pos())
|
||||||
|
pos = cursor.position()
|
||||||
|
|
||||||
|
# Verificar si el mouse está sobre un link
|
||||||
|
over_link = False
|
||||||
|
for (start, end), (link_id, obj) in self.clickable_links.items():
|
||||||
|
if start <= pos <= end:
|
||||||
|
over_link = True
|
||||||
|
break
|
||||||
|
|
||||||
|
# Cambiar cursor
|
||||||
|
if over_link:
|
||||||
|
self.setCursor(Qt.PointingHandCursor)
|
||||||
|
else:
|
||||||
|
self.setCursor(Qt.ArrowCursor)
|
||||||
|
|
||||||
|
super().mouseMoveEvent(event)
|
||||||
|
|
||||||
|
|
||||||
class ExpandableLatexButton(QPushButton):
|
class ExpandableLatexButton(QPushButton):
|
||||||
"""Botón expandible para mostrar/ocultar panel LaTeX"""
|
"""Botón expandible para mostrar/ocultar panel LaTeX"""
|
||||||
|
|
Loading…
Reference in New Issue