diff --git a/data/material-icons.ttf b/data/material-icons.ttf new file mode 100644 index 0000000..9d09b0f Binary files /dev/null and b/data/material-icons.ttf differ diff --git a/main.py b/main.py index 1b639f1..0732b0d 100644 --- a/main.py +++ b/main.py @@ -22,7 +22,7 @@ import webbrowser import yaml from PyQt6.QtCore import QFileSystemWatcher, Qt, QTimer, QSize, QRegularExpression from PyQt6.QtGui import QAction, QStandardItem, QStandardItemModel, QIcon, QPalette, QSyntaxHighlighter, \ - QTextCharFormat, QColor, QFont + QTextCharFormat, QColor, QFont, QPainter, QPixmap, QFontDatabase from PyQt6.QtWebEngineCore import QWebEngineSettings from PyQt6.QtWebEngineWidgets import QWebEngineView from PyQt6.QtWidgets import QApplication, QMainWindow, QTextEdit, QWidget, QToolBar, QStatusBar, \ @@ -33,6 +33,37 @@ from markdown2 import markdown logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') +MATERIAL_ICONS_PATH = "data/material-icons.ttf" +MATERIAL_ICONS = { + "New": "\ue862", + "Open": "\ue2c7", + "Save": "\ue161", + "Undo": "\ue166", + "Redo": "\ue15a", + "Settings": "\ue8b8", + "Exit": "\ue879", + "Search": "\ue8b6", + "Help": "\ue8fd", + "About": "\ue88e", + "Folder": "\ue2c7", + "File": "\ue24d", + "Close": "\ue5cd", + "View": "\ue8f4", + "GitHub": "\ue86f", + "Minimize": "\ue921", +} +ICON_SIZE = 42 +ICON_COLOR = "#ccbbca" +DEFAULT_WINDOW_SIZE = (900, 700) + + +def load_material_icons(): + font_id = QFontDatabase.addApplicationFont(MATERIAL_ICONS_PATH) + if font_id == -1: + raise RuntimeError("Failed to load Material Icons font.") + return QFontDatabase.applicationFontFamilies(font_id)[0] + + class MarkdownEditor(QMainWindow): """ @@ -89,26 +120,16 @@ class MarkdownEditor(QMainWindow): def setup_ui(self): """ Sets up the minimal UI components necessary for initial display. """ self.setWindowTitle("Markdown Editor") - - # Basic window geometry width = self.config.get('window', {}).get('width', 800) height = self.config.get('window', {}).get('height', 600) self.setGeometry(100, 100, width, height) - - # Central widget and layout central_widget = QWidget() layout = QVBoxLayout(central_widget) layout.setContentsMargins(5, 5, 5, 5) - - # Placeholder for main content placeholder_label = QLabel("Loading...", alignment=Qt.AlignmentFlag.AlignCenter) layout.addWidget(placeholder_label) - - # Set the central widget central_widget.setLayout(layout) self.setCentralWidget(central_widget) - - # Status bar (optional) self.setStatusBar(QStatusBar(self)) def initialize_ui(self): @@ -134,30 +155,42 @@ class MarkdownEditor(QMainWindow): directory_layout = QVBoxLayout() directory_layout.addWidget(self.searchBox) directory_layout.addWidget(self.directoryTree) - - # Create a widget for directory layout directory_widget = QWidget() directory_widget.setLayout(directory_layout) - - # Initialize the splitters splitter_horizontal = QSplitter(Qt.Orientation.Horizontal) splitter_vertical = QSplitter(Qt.Orientation.Vertical) - - # Add widgets to horizontal splitter splitter_horizontal.addWidget(directory_widget) splitter_horizontal.addWidget(self.editor) - - # Add widgets to vertical splitter splitter_vertical.addWidget(splitter_horizontal) splitter_vertical.addWidget(self.preview) - - # Add the main splitter to the layout layout.addWidget(splitter_vertical) - central_widget.setLayout(layout) self.setCentralWidget(central_widget) self.setStatusBar(QStatusBar(self)) + def get_material_icon(self, unicode, size=ICON_SIZE, color=ICON_COLOR): + """Create a QIcon object from a Material Icon. + + Args: + unicode (str): The unicode character for the icon. + size (int, optional): Pixel size of the icon. Defaults to ICON_SIZE. + color (str, optional): Color of the icon. Defaults to ICON_COLOR. + + Returns: + QIcon: The generated icon object. + """ + font_family = load_material_icons() + font = QFont(font_family) + font.setPixelSize(int(size)) + pixmap = QPixmap(size, size) + pixmap.fill(Qt.GlobalColor.transparent) + painter = QPainter(pixmap) + painter.setFont(font) + painter.setPen(QColor(color)) + painter.drawText(pixmap.rect(), Qt.AlignmentFlag.AlignCenter, unicode) + painter.end() + return QIcon(pixmap) + def initialize_data_directory(self): """ Initializes the data directory and sets up the file system watcher. @@ -192,16 +225,14 @@ class MarkdownEditor(QMainWindow): toolbar = QToolBar() toolbar.setIconSize(QSize(16, 16)) toolbar.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextBesideIcon) - toolbar.addAction(self.create_action("New", QStyle.StandardPixmap.SP_FileIcon, self.new_file)) - toolbar.addAction(self.create_action("Open", QStyle.StandardPixmap.SP_DirOpenIcon, self.open_file)) - toolbar.addAction(self.create_action("Save", QStyle.StandardPixmap.SP_DialogSaveButton, self.save_entry)) + toolbar.addAction(self.create_action("New", MATERIAL_ICONS["New"], self.new_file)) + toolbar.addAction(self.create_action("Open", MATERIAL_ICONS["Open"], self.open_file)) + toolbar.addAction(self.create_action("Save", MATERIAL_ICONS["Save"], self.save_entry)) + toolbar.addAction(self.create_action("Open Data Directory", MATERIAL_ICONS["Folder"], self.open_data_directory)) toolbar.addAction( - self.create_action("Open Data Directory", QStyle.StandardPixmap.SP_DirIcon, self.open_data_directory)) - toolbar.addAction(self.create_action("Change Data Directory", QStyle.StandardPixmap.SP_FileDialogDetailedView, - self.change_data_directory)) - toolbar.addAction( - self.create_action("Settings", QStyle.StandardPixmap.SP_FileDialogInfoView, self.open_settings)) - toolbar.addAction(self.create_action("Exit", QStyle.StandardPixmap.SP_DialogCloseButton, self.close)) + self.create_action("Change Data Directory", MATERIAL_ICONS["Folder"], self.change_data_directory)) + toolbar.addAction(self.create_action("Settings", MATERIAL_ICONS["Settings"], self.open_settings)) + toolbar.addAction(self.create_action("Exit", MATERIAL_ICONS["Exit"], self.close)) return toolbar def create_edit_tab(self): @@ -209,8 +240,8 @@ class MarkdownEditor(QMainWindow): toolbar = QToolBar() toolbar.setIconSize(QSize(16, 16)) toolbar.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextBesideIcon) - toolbar.addAction(self.create_action("Undo", QStyle.StandardPixmap.SP_ArrowBack, self.undo_action)) - toolbar.addAction(self.create_action("Redo", QStyle.StandardPixmap.SP_ArrowForward, self.redo_action)) + toolbar.addAction(self.create_action("Undo", MATERIAL_ICONS["Undo"], self.undo_action)) + toolbar.addAction(self.create_action("Redo", MATERIAL_ICONS["Redo"], self.redo_action)) return toolbar def create_view_tab(self): @@ -218,8 +249,7 @@ class MarkdownEditor(QMainWindow): toolbar = QToolBar() toolbar.setIconSize(QSize(16, 16)) toolbar.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextBesideIcon) - toolbar.addAction(self.create_action("Toggle Split View", QStyle.StandardPixmap.SP_FileDialogListView, - self.toggle_split_view)) + toolbar.addAction(self.create_action("Toggle Split View", MATERIAL_ICONS["View"], self.toggle_split_view)) return toolbar def create_window_tab(self): @@ -227,9 +257,9 @@ class MarkdownEditor(QMainWindow): toolbar = QToolBar() toolbar.setIconSize(QSize(16, 16)) toolbar.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextBesideIcon) - toolbar.addAction(self.create_action("Close", QStyle.StandardPixmap.SP_DialogCloseButton, self.close)) - toolbar.addAction(self.create_action("Minimize", QStyle.StandardPixmap.SP_TitleBarMinButton, self.minimize)) - toolbar.addAction(self.create_action("Search", QStyle.StandardPixmap.SP_FileDialogContentsView, self.search)) + toolbar.addAction(self.create_action("Close", MATERIAL_ICONS["Close"], self.close)) + toolbar.addAction(self.create_action("Minimize", MATERIAL_ICONS["Minimize"], self.minimize)) + toolbar.addAction(self.create_action("Search", MATERIAL_ICONS["Search"], self.search)) return toolbar def create_help_tab(self): @@ -237,15 +267,15 @@ class MarkdownEditor(QMainWindow): toolbar = QToolBar() toolbar.setIconSize(QSize(16, 16)) toolbar.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextBesideIcon) - toolbar.addAction(self.create_action("About", QStyle.StandardPixmap.SP_MessageBoxInformation, self.about)) + toolbar.addAction(self.create_action("About", MATERIAL_ICONS["About"], self.about)) + toolbar.addAction(self.create_action("View Cheatsheet", MATERIAL_ICONS["Help"], self.view_cheatsheet)) toolbar.addAction( - self.create_action("View Cheatsheet", QStyle.StandardPixmap.SP_FileDialogInfoView, self.view_cheatsheet)) - toolbar.addAction(self.create_action("GitHub", QStyle.StandardPixmap.SP_DriveNetIcon, self.open_git_hub)) + self.create_action("GitHub", MATERIAL_ICONS["GitHub"], self.open_git_hub)) return toolbar - def create_action(self, text, icon, callback): + def create_action(self, text, icon_code, callback): """ Creates an action for the toolbar in the ribbon interface. """ - action = QAction(self.style().standardIcon(icon), text, self) + action = QAction(self.get_material_icon(icon_code), text, self) action.triggered.connect(callback) return action