diff --git a/src/main.py b/src/main.py index a3b0354..b8f2478 100644 --- a/src/main.py +++ b/src/main.py @@ -16,13 +16,13 @@ from PyQt5.QtWidgets import (QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QMessageBox, QSplitter, QTabWidget, QStatusBar, QToolBar, QPushButton, QLabel, QFrame, QApplication, QDesktopWidget, QStyleFactory, QStyle, QGroupBox, QProgressBar, - QScrollArea, QTextBrowser) + QScrollArea, QTextBrowser, QFontComboBox, QComboBox, QColorDialog) from PyQt5.QtCore import (Qt, QTimer, pyqtSignal, QThread, QObject, QUrl, QSettings, QPoint, QSize, QEvent, QPropertyAnimation, QEasingCurve, QRect) from PyQt5.QtGui import (QFont, QPalette, QColor, QIcon, QKeySequence, QTextCursor, QTextCharFormat, QPainter, QPixmap, - QFontDatabase, QSyntaxHighlighter, QTextDocument) + QFontDatabase, QSyntaxHighlighter, QTextDocument, QFontInfo) # 导入MagicWord现有功能 from services.network_service import NetworkService @@ -30,6 +30,7 @@ from file_manager.file_operations import FileManager from learning_mode_window import LearningModeWindow from ui.theme_manager import ThemeManager from ui.ai_chat_panel import AIChatPanel +from ui.snake_game import SnakeGameWindow class MarkTextEditor(QPlainTextEdit): @@ -44,6 +45,97 @@ class MarkTextEditor(QPlainTextEdit): self.current_file_path = None self.is_modified = False + def apply_format(self, format_type: str, value=None): + """应用文本格式""" + cursor = self.textCursor() + if not cursor.hasSelection(): + # 如果没有选中文本,设置默认格式供后续输入使用 + char_format = self.currentCharFormat() + + if format_type == "bold": + char_format.setFontWeight(QFont.Bold if value else QFont.Normal) + elif format_type == "italic": + char_format.setFontItalic(value) + elif format_type == "underline": + char_format.setFontUnderline(value) + elif format_type == "font_family": + char_format.setFontFamily(value) + elif format_type == "font_size": + char_format.setFontPointSize(value) + elif format_type == "color": + char_format.setForeground(QColor(value)) + elif format_type == "background_color": + char_format.setBackground(QColor(value)) + + self.setCurrentCharFormat(char_format) + return + + # 如果有选中文本,直接修改选中文本的格式 + char_format = cursor.charFormat() + + if format_type == "bold": + char_format.setFontWeight(QFont.Bold if value else QFont.Normal) + elif format_type == "italic": + char_format.setFontItalic(value) + elif format_type == "underline": + char_format.setFontUnderline(value) + elif format_type == "font_family": + char_format.setFontFamily(value) + elif format_type == "font_size": + char_format.setFontPointSize(value) + elif format_type == "color": + char_format.setForeground(QColor(value)) + elif format_type == "background_color": + char_format.setBackground(QColor(value)) + elif format_type == "strikethrough": + char_format.setFontStrikeOut(value) + elif format_type == "superscript": + char_format.setVerticalAlignment(QTextCharFormat.AlignSuperScript if value else QTextCharFormat.AlignNormal) + elif format_type == "subscript": + char_format.setVerticalAlignment(QTextCharFormat.AlignSubScript if value else QTextCharFormat.AlignNormal) + + cursor.setCharFormat(char_format) + + def apply_paragraph_format(self, format_type: str, value=None): + """应用段落格式""" + cursor = self.textCursor() + block_format = cursor.blockFormat() + + if format_type == "alignment": + block_format.setAlignment(value) + elif format_type == "line_spacing": + block_format.setLineHeight(value, QTextBlockFormat.ProportionalHeight) + elif format_type == "top_margin": + block_format.setTopMargin(value) + elif format_type == "bottom_margin": + block_format.setBottomMargin(value) + elif format_type == "left_margin": + block_format.setLeftMargin(value) + elif format_type == "right_margin": + block_format.setRightMargin(value) + elif format_type == "indent": + block_format.setIndent(value) + + cursor.setBlockFormat(block_format) + + + + def get_format_info(self): + """获取当前光标位置的格式信息""" + cursor = self.textCursor() + char_format = cursor.charFormat() + + return { + "font_family": char_format.fontFamily(), + "font_size": char_format.fontPointSize(), + "bold": char_format.fontWeight() == QFont.Bold, + "italic": char_format.fontItalic(), + "underline": char_format.fontUnderline(), + "strikethrough": char_format.fontStrikeOut(), + "color": char_format.foreground().color().name(), + "background_color": char_format.background().color().name() + } + def setup_editor(self): """设置编辑器样式和功能 - 深色主题""" # 设置字体 - 使用等宽字体,支持多平台 @@ -280,11 +372,13 @@ class MarkTextSideBar(QWidget): self.quote_btn = QPushButton("📖 每日名言") self.insert_weather_btn = QPushButton("🌈 插入天气") self.insert_quote_btn = QPushButton("✨ 插入名言") + self.snake_game_btn = QPushButton("🐍 贪吃蛇游戏") tools_layout.addWidget(self.weather_btn) tools_layout.addWidget(self.quote_btn) tools_layout.addWidget(self.insert_weather_btn) tools_layout.addWidget(self.insert_quote_btn) + tools_layout.addWidget(self.snake_game_btn) tools_group.setLayout(tools_layout) layout.addWidget(tools_group) @@ -306,6 +400,7 @@ class MarkTextSideBar(QWidget): self.quote_btn.clicked.connect(self.parent.show_quote_info) self.insert_weather_btn.clicked.connect(self.parent.insert_weather_to_editor) self.insert_quote_btn.clicked.connect(self.parent.insert_quote_to_editor) + self.snake_game_btn.clicked.connect(self.parent.open_snake_game) # 设置固定宽度 self.setFixedWidth(220) @@ -746,6 +841,33 @@ class MarkTextMainWindow(QMainWindow): select_all_action.triggered.connect(self.editor_select_all) edit_menu.addAction(select_all_action) + edit_menu.addSeparator() + + # 格式子菜单 + format_menu = edit_menu.addMenu('格式(&F)') + + italic_action = QAction('斜体(&I)', self) + italic_action.setShortcut('Ctrl+I') + italic_action.triggered.connect(self.on_italic_clicked) + format_menu.addAction(italic_action) + + underline_action = QAction('下划线(&U)', self) + underline_action.setShortcut('Ctrl+U') + underline_action.triggered.connect(self.on_underline_clicked) + format_menu.addAction(underline_action) + + format_menu.addSeparator() + + color_action = QAction('字体颜色(&C)...', self) + color_action.triggered.connect(self.on_color_clicked) + format_menu.addAction(color_action) + + bg_color_action = QAction('背景颜色(&G)...', self) + bg_color_action.triggered.connect(self.on_background_color_clicked) + format_menu.addAction(bg_color_action) + + + # 工具菜单 tools_menu = menubar.addMenu('工具(&T)') tools_menu.setStyleSheet(""" @@ -861,20 +983,77 @@ class MarkTextMainWindow(QMainWindow): QToolBar QToolButton:pressed { background-color: #1f6feb; } + QToolBar QComboBox { + background-color: #30363d; + color: #c9d1d9; + border: 1px solid #484f58; + border-radius: 3px; + padding: 5px; + min-width: 80px; + } + QToolBar QComboBox::drop-down { + border: none; + } + QToolBar QComboBox::down-arrow { + image: none; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-top: 5px solid #c9d1d9; + } """) - # 添加常用工具按钮 + # 文件操作按钮 toolbar.addAction("新建", self.new_file) toolbar.addAction("打开", self.open_file) toolbar.addAction("保存", self.save_file) toolbar.addSeparator() + + # 编辑操作按钮 toolbar.addAction("撤销", lambda: self.get_current_editor().undo() if self.get_current_editor() else None) toolbar.addAction("重做", lambda: self.get_current_editor().redo() if self.get_current_editor() else None) toolbar.addSeparator() + + # 剪切复制粘贴 toolbar.addAction("剪切", lambda: self.get_current_editor().cut() if self.get_current_editor() else None) toolbar.addAction("复制", lambda: self.get_current_editor().copy() if self.get_current_editor() else None) toolbar.addAction("粘贴", lambda: self.get_current_editor().paste() if self.get_current_editor() else None) toolbar.addSeparator() + + # 字体选择 + self.font_combo = QFontComboBox() + self.font_combo.setCurrentFont(QFont("Consolas")) + self.font_combo.currentFontChanged.connect(self.on_font_changed) + toolbar.addWidget(self.font_combo) + + # 字体大小选择 + self.font_size_combo = QComboBox() + self.font_size_combo.addItems(["8", "9", "10", "11", "12", "14", "16", "18", "20", "22", "24", "26", "28", "36", "48", "72"]) + self.font_size_combo.setCurrentText("14") + self.font_size_combo.currentTextChanged.connect(self.on_font_size_changed) + toolbar.addWidget(self.font_size_combo) + + toolbar.addSeparator() + + # 格式按钮 + italic_btn = QAction("斜体", self) + italic_btn.setCheckable(True) + italic_btn.triggered.connect(self.on_italic_clicked) + toolbar.addAction(italic_btn) + + underline_btn = QAction("下划线", self) + underline_btn.setCheckable(True) + underline_btn.triggered.connect(self.on_underline_clicked) + toolbar.addAction(underline_btn) + + color_btn = QAction("颜色", self) + color_btn.triggered.connect(self.on_color_clicked) + toolbar.addAction(color_btn) + + + + toolbar.addSeparator() + + # 学习模式相关 toolbar.addAction("学习模式", self.switch_to_learning_mode) toolbar.addAction("导入文件", self.import_file) toolbar.addSeparator() @@ -1323,25 +1502,86 @@ class MarkTextMainWindow(QMainWindow): try: weather_info = self.network_service.get_weather_info() if weather_info: - weather_text = f"\n\n🌤 今日天气: {weather_info['city']} {weather_info['temperature']}°C, {weather_info['description']}\n" - weather_text += f"湿度: {weather_info['humidity']}% | 风速: {weather_info['wind_speed']}m/s\n\n" + # 基础天气信息 + weather_text = f"\n【天气信息】\n{weather_info['city']}: {weather_info['temperature']}°C, {weather_info['description']}" + weather_text += f"\n湿度: {weather_info['humidity']}%" + weather_text += f"\n风速: {weather_info['wind_speed']}m/s" # 添加生活提示 lifetips = weather_info.get('lifetips', []) if lifetips: - weather_text += "🌟 生活提示:\n" + weather_text += "\n\n🌟 生活提示:" for tip in lifetips: - weather_text += f"• {tip}\n" - weather_text += "\n" + weather_text += f"\n• {tip}" + + weather_text += "\n" cursor = editor.textCursor() cursor.insertText(weather_text) + self.statusBar().showMessage("天气信息已插入到文档", 2000) else: QMessageBox.warning(self, "提示", "无法获取天气信息") except Exception as e: QMessageBox.critical(self, "错误", f"插入天气信息失败: {str(e)}") else: QMessageBox.warning(self, "提示", "请先打开一个文档") + + # 文本格式化功能函数 + def on_font_changed(self, font): + """字体选择变化""" + editor = self.get_current_editor() + if editor: + editor.apply_format("font_family", font.family()) + + def on_font_size_changed(self, size_text): + """字体大小选择变化""" + editor = self.get_current_editor() + if editor: + try: + size = int(size_text) + editor.apply_format("font_size", size) + except ValueError: + pass + + def on_italic_clicked(self): + """斜体按钮点击""" + editor = self.get_current_editor() + if editor: + current_format = editor.get_format_info() + editor.apply_format("italic", not current_format["italic"]) + + def on_underline_clicked(self): + """下划线按钮点击""" + editor = self.get_current_editor() + if editor: + current_format = editor.get_format_info() + editor.apply_format("underline", not current_format["underline"]) + + def on_color_clicked(self): + """颜色按钮点击""" + editor = self.get_current_editor() + if editor: + color = QColorDialog.getColor() + if color.isValid(): + editor.apply_format("color", color.name()) + + def on_background_color_clicked(self): + """背景颜色按钮点击""" + editor = self.get_current_editor() + if editor: + color = QColorDialog.getColor() + if color.isValid(): + editor.apply_format("background_color", color.name()) + + def open_snake_game(self): + """打开贪吃蛇游戏""" + try: + self.snake_game_window = SnakeGameWindow(self) + self.snake_game_window.show() + except Exception as e: + QMessageBox.critical(self, "错误", f"无法打开贪吃蛇游戏: {str(e)}") + + def insert_quote_to_editor(self): """将名言插入到编辑器 - 优化错误处理"""