From be6aac620f2db5857632864a76936bfe48cd4a44 Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Wed, 11 Oct 2023 20:20:34 -0500 Subject: [PATCH 001/127] Update BuildUI.py --- Modules/BuildUI.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index 6b105a4..fec2cff 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -16,7 +16,7 @@ def build_ui(editor): #editor.statusBar = editor.statusBar() build_window(editor) build_menubar(editor) - #build_toolbar(editor) + build_toolbar(editor) # Application's main layout (grid) gridLayout = QGridLayout() @@ -67,11 +67,11 @@ def build_menubar(editor): file = editor.menuBar().addMenu('&File') plugins = editor.menuBar().addMenu('&Plugins') - new_file = build_action(editor, 'assets/icons/svg_file_open', 'New Notebook...', 'New Notebook', False) + new_file = build_action(editor, 'assets/icons/svg_file_open', 'New Notebook', 'New Notebook', False) new_file.setShortcut(QKeySequence.StandardKey.New) new_file.triggered.connect(lambda: new(editor)) - open_file = build_action(editor, 'assets/icons/svg_file_open', 'Open Notebook...', 'Open Notebook', False) + open_file = build_action(editor, 'assets/icons/svg_file_open', 'Open Notebook', 'Open Notebook', False) open_file.setShortcut(QKeySequence.StandardKey.Open) open_file.triggered.connect(lambda: load(editor)) From 54c595e311d1e344d19eb9173bc30e00515cabe7 Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Mon, 16 Oct 2023 21:35:53 -0500 Subject: [PATCH 002/127] Bug Fix Moving mouse away from draggable container no longer exits typing --- Models/DraggableContainer.py | 29 +++++++++++++------------- Modules/BuildUI.py | 30 +++++++++++++++++++++------ Views/EditorFrameView.py | 40 +++++++++++++++++++++--------------- Widgets/Textbox.py | 8 ++++---- 4 files changed, 66 insertions(+), 41 deletions(-) diff --git a/Models/DraggableContainer.py b/Models/DraggableContainer.py index 57b248d..978fa84 100644 --- a/Models/DraggableContainer.py +++ b/Models/DraggableContainer.py @@ -64,10 +64,10 @@ def setChildWidget(self, childWidget): self.vLayout.addWidget(childWidget) self.vLayout.setContentsMargins(0,0,0,0) - def eventFilter(self, obj, event): + def eventFilter(self, obj, e): # If child widget resized itsself, resize this drag container, not ideal bc child resizes on hover - if isinstance(event, QResizeEvent): + if isinstance(e, QResizeEvent): self.resize(self.childWidget.size()) return False @@ -80,7 +80,7 @@ def popupShow(self, pt: QPoint): def mousePressEvent(self, e: QMouseEvent): self.position = QPoint(e.globalX() - self.geometry().x(), e.globalY() - self.geometry().y()) - print("DC MOUSE PRESS") + print("Draggable Container MOUSE PRESS") # Undo related # self.old_x = e.globalX() @@ -93,7 +93,7 @@ def mousePressEvent(self, e: QMouseEvent): print("NOT EDIT") return if not e.buttons() and Qt.LeftButton: - print("DC GOT MOUSE PRESS") + print("Draggable Container GOT MOUSE PRESS") self.setCursorShape(e.pos()) return True if e.button() == Qt.RightButton: @@ -117,14 +117,15 @@ def leaveEvent(self, e: QMouseEvent): self.childWidget.setAttribute(Qt.WA_TransparentForMouseEvents, True) self.setStyleSheet("border: none;") - # Delete this DC if childWidget says it's empty - if hasattr(self.childWidget, "checkEmpty"): - if self.childWidget.checkEmpty(): - editorSignalsInstance.widgetRemoved.emit(self) - - # ??? - if self.childWidget.hasFocus(): - self.setFocus() + # Delete this Draggable Container if childWidget says it's empty + if not self.childWidget.hasFocus(): + if hasattr(self.childWidget, "checkEmpty"): + if self.childWidget.checkEmpty(): + editorSignalsInstance.widgetRemoved.emit(self) + + # If mouse leaves draggable container, set focus to the editor + #if self.childWidget.hasFocus(): + # self.setFocus()''' def buildDragContainerMenu(self): @@ -217,7 +218,7 @@ def setCursorShape(self, e_pos: QPoint): self.setCursor(QCursor(Qt.SizeVerCursor)) self.mode = Mode.RESIZEB else: - self.setCursor(QCursor(Qt. ArrowCursor)) + self.setCursor(QCursor(Qt.ArrowCursor)) self.mode = Mode.MOVE # Determine how to handle the mouse being moved inside the box @@ -281,7 +282,7 @@ def mouseMoveEvent(self, e: QMouseEvent): self.parentWidget().repaint() self.newGeometry.emit(self.geometry()) - # Pass the event to the child widget if this container is focuesd, and childwidget implements the method to receive it + # Pass the e to the child widget if this container is focuesd, and childwidget implements the method to receive it def widgetAttributeChanged(self, changedWidgetAttribute, value): cw = self.childWidget diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index fec2cff..8919244 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -85,9 +85,23 @@ def build_menubar(editor): file.addActions([new_file, open_file, save_file, save_fileAs]) +''' +def build_toolbar(editor): + toolbar = QToolBar("Main toolbar") + editor.addToolBar(Qt.ToolBarArea.TopToolBarArea, toolbar) + + button_action = QAction("Your button", editor) + button_action.setStatusTip("This is your button") + button_action.triggered.connect(action.onMyToolBarButtonClick) + button_action.setCheckable(True) + toolbar.addAction(button_action) +''' + + + def build_toolbar(editor): toolbar = QToolBar() - toolbar.setIconSize(QSize(15, 15)) + toolbar.setIconSize(QSize(16, 16)) toolbar.setMovable(False) editor.addToolBar(Qt.ToolBarArea.TopToolBarArea, toolbar) @@ -98,25 +112,28 @@ def build_toolbar(editor): size.addItems([str(fs) for fs in FONT_SIZES]) size.currentIndexChanged.connect(lambda x: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontSize, int(size.currentText()))) - fontColor = build_action(toolbar, 'assets/icons/svg_font_color', "Font Color", "Font Color", False) - fontColor.triggered.connect(lambda x: openGetColorDialog(purpose = "font")) - bgColor = build_action(toolbar, 'assets/icons/svg_font_bucket', "Text Box Color", "Text Box Color", False) bgColor.triggered.connect(lambda x: openGetColorDialog(purpose = "background")) + + fontColor = build_action(toolbar, 'assets/icons/svg_font_color', "Font Color", "Font Color", False) + fontColor.triggered.connect(lambda x: openGetColorDialog(purpose = "font")) bold = build_action(toolbar, 'assets/icons/bold', "Bold", "Bold", True) bold.triggered.connect(lambda x: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontBold, None)) + italic = build_action(toolbar, 'assets/icons/italic.svg', "Italic", "Italic", True) italic.triggered.connect(lambda x: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontItalic, None)) underline = build_action(toolbar, 'assets/icons/underline.svg', "Underline", "Underline", True) - underline.triggered.connect(lambda x: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontUnderline, None)) - + #underline.toggled.connect(lambda x: editor.childWidget. setFontUnderlineCustom(True if x else False)) + toolbar.addWidget(font) toolbar.addWidget(size) + toolbar.addActions([bgColor, fontColor, bold, italic, underline]) + def openGetColorDialog(purpose): color = QColorDialog.getColor() if color.isValid(): @@ -128,4 +145,5 @@ def openGetColorDialog(purpose): def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): action = QAction(QIcon(icon_path), action_name, parent) action.setStatusTip(set_status_tip) + action.setCheckable(set_checkable) return action diff --git a/Views/EditorFrameView.py b/Views/EditorFrameView.py index 5232ead..38b5f63 100644 --- a/Views/EditorFrameView.py +++ b/Views/EditorFrameView.py @@ -18,6 +18,7 @@ # Handles all widget display (could be called widget view, but so could draggablecontainer) class EditorFrameView(QWidget): + def __init__(self, editor): super(EditorFrameView, self).__init__() @@ -151,37 +152,43 @@ def mouseReleaseEvent(self, event): else: self.newWidgetOnSection(TextboxWidget, event.pos()) - def mousePressEvent(self, event): + def mousePressEvent(self, e): print("EDITORFRAME MOUSEPRESS") editor = self.editor # Open context menu on right click - if event.buttons() == Qt.RightButton: + if e.buttons() == Qt.RightButton: frame_menu = QMenu(self) + cut_action = QAction("Cut", self) + #add cut functionality + frame_menu.addAction(cut_action) + + paste = QAction("Paste", editor) + paste.triggered.connect(lambda: self.pasteWidget(e.pos())) + frame_menu.addAction(paste) + add_image = QAction("Add Image", self) - add_image.triggered.connect(lambda: self.newWidgetOnSection(ImageWidget, event.pos())) + add_image.triggered.connect(lambda: self.newWidgetOnSection(ImageWidget, e.pos())) frame_menu.addAction(add_image) add_table = QAction("Add Table", editor) - add_table.triggered.connect(lambda: self.newWidgetOnSection(TableWidget, event.pos())) + add_table.triggered.connect(lambda: self.newWidgetOnSection(TableWidget, e.pos())) frame_menu.addAction(add_table) - paste = QAction("Paste", editor) - paste.triggered.connect(lambda: self.pasteWidget(event.pos())) - frame_menu.addAction(paste) + take_screensnip = QAction("Snip Screen", editor) - take_screensnip.triggered.connect(lambda: self.snipScreen(event.pos())) + take_screensnip.triggered.connect(lambda: self.snipScreen(e.pos())) frame_menu.addAction(take_screensnip) add_custom_widget = QAction("Add Custom Widget", editor) - add_custom_widget.triggered.connect(lambda: self.addCustomWidget(event)) + add_custom_widget.triggered.connect(lambda: self.addCustomWidget(e)) frame_menu.addAction(add_custom_widget) - frame_menu.exec(event.globalPos()) + frame_menu.exec(e.globalPos()) - def addCustomWidget(self, event): + def addCustomWidget(self, e): def getCustomWidgets(): customWidgets = {} # dict where entries are {name: class} @@ -206,17 +213,16 @@ def getCustomWidgets(): item_action = QAction(customWidget[0], self) def tmp(c, pos): return lambda: self.newWidgetOnSection(c, pos) - item_action.triggered.connect(tmp(customWidget[1], event.pos())) + item_action.triggered.connect(tmp(customWidget[1], e.pos())) pluginMenu.addAction(item_action) - pluginMenu.exec(event.globalPos()) - - def mouseMoveEvent(self, event): # This event is only called after clicking down on the frame and dragging + pluginMenu.exec(e.globalPos()) + def mouseMoveEvent(self, e): # This event is only called after clicking down on the frame and dragging # Set up multi-select on first move of mouse drag if self.multiselector.mode != MultiselectMode.IS_DRAWING_AREA: - self.multiselector.beginDrawingArea(event) + self.multiselector.beginDrawingArea(e) # Resize multi-select widget on mouse every proceeding mouse movement (dragging) else: - self.multiselector.continueDrawingArea(event) + self.multiselector.continueDrawingArea(e) diff --git a/Widgets/Textbox.py b/Widgets/Textbox.py index 998d2fe..2c6c170 100644 --- a/Widgets/Textbox.py +++ b/Widgets/Textbox.py @@ -49,11 +49,11 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): return action toolbarTop = QToolBar() - toolbarTop.setIconSize(QSize(25, 25)) + toolbarTop.setIconSize(QSize(16, 16)) toolbarTop.setMovable(False) toolbarBottom = QToolBar() - toolbarBottom.setIconSize(QSize(25, 25)) + toolbarBottom.setIconSize(QSize(16, 16)) toolbarBottom.setMovable(False) font = QFontComboBox() @@ -73,10 +73,10 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): underline.toggled.connect(lambda x: self.setFontUnderlineCustom(True if x else False)) fontColor = build_action(toolbarBottom, 'assets/icons/svg_font_color', "Font Color", "Font Color", False) - fontColor.triggered.connect(lambda x: self.setTextColorCustom(QColorDialog.getColor())) + fontColor.triggered.connect(lambda: self.setTextColorCustom(QColorDialog.getColor())) bgColor = build_action(toolbarBottom, 'assets/icons/svg_font_bucket', "Text Box Color", "Text Box Color", False) - bgColor.triggered.connect(lambda x: self.setBackgroundColor(QColorDialog.getColor())) + bgColor.triggered.connect(lambda: self.setBackgroundColor(QColorDialog.getColor())) toolbarTop.addWidget(font) toolbarTop.addWidget(size) From cae2e7b9cb2c87afe8aad05ad85ae4e1927b0624 Mon Sep 17 00:00:00 2001 From: ldeltastreaml <70774713+ldeltastreaml@users.noreply.github.com> Date: Wed, 18 Oct 2023 22:40:18 -0500 Subject: [PATCH 003/127] Added Limit to Image Resize When resizing an image, the resize will be limited to being at least 1/8th of the original size. This is to prevent resizes where the images are too small to be interactable or viewable. --- Widgets/Image.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Widgets/Image.py b/Widgets/Image.py index 64971e1..6c207e7 100644 --- a/Widgets/Image.py +++ b/Widgets/Image.py @@ -28,6 +28,14 @@ def __init__(self, x, y, w, h, image_matrix): def newGeometryEvent(self, newGeometry): new_w = newGeometry.width() new_h = newGeometry.height() + + # Calculate minimum width and height as 1/8th (arbitrary) of the original image dimensions + min_width = max(1, self.w // 8) # Ensure that min_width is at least 1 + min_height = max(1, self.h // 8) # Ensure that min_height is at least 1 + + # Check if the new width/height is below the minimum and if it is limits the width/height to 1/8th the size + if (new_w < min_width) and (new_h < min_height): new_w, new_h = min_width, min_height + if (self.w != new_w) or (self.h != new_h): # Not exactly sure how object's width and height attribute gets updated but this works self.setPixmap(self.q_pixmap.scaled(new_w, new_h, Qt.KeepAspectRatio, Qt.SmoothTransformation)) From e91d38b0fdd5bb5ce68128b749444eb39746ca55 Mon Sep 17 00:00:00 2001 From: ldeltastreaml <70774713+ldeltastreaml@users.noreply.github.com> Date: Wed, 18 Oct 2023 22:51:04 -0500 Subject: [PATCH 004/127] Added Scrolling and Min Tab Size Adjusted This should allow for one to automatically get scrollbars when content exceeds the visible area. Adjustments to the size hint functions because I thought the size was really small. --- Views/SectionView.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Views/SectionView.py b/Views/SectionView.py index b26d198..e5fbb37 100644 --- a/Views/SectionView.py +++ b/Views/SectionView.py @@ -19,6 +19,11 @@ def __init__(self, sectionModels: List[SectionModel]): # The tabbed section widget self.tabs = QTabBar(self) + # Create a scroll area and set the SectionView as its widget + self.scroll_area = QScrollArea() + self.scroll_area.setWidgetResizable(True) + self.scroll_area.setWidget(self.tabs) + # Layout that holds this view layout = QVBoxLayout(self) layout.addWidget(self.tabs) @@ -41,10 +46,10 @@ def __init__(self, sectionModels: List[SectionModel]): print("BUILT SECTIONVIEW") def tabSizeHint(self, index): - return QSize(300, 35) + return QSize(600, 70) def minimumTabSizeHint(self, index): - return QSize(300, 35) + return QSize(600, 70) def widgetRemovedEvent(self, draggableContainer): try: From c726c6ae8bf7d76466cc563548363c0756a06bb5 Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Wed, 18 Oct 2023 23:38:53 -0500 Subject: [PATCH 005/127] Added icons to toolbar Included hyperlink, table, undo, and redo buttons --- Assets/icons/svg_hyperlink.svg | 11 ++++++++ Assets/icons/svg_redo.svg | 7 +++++ Assets/icons/svg_table.svg | 4 +++ Assets/icons/svg_undo.svg | 4 +++ Models/DraggableContainer.py | 2 ++ Modules/BuildUI.py | 49 ++++++++++++++++++++-------------- 6 files changed, 57 insertions(+), 20 deletions(-) create mode 100644 Assets/icons/svg_hyperlink.svg create mode 100644 Assets/icons/svg_redo.svg create mode 100644 Assets/icons/svg_table.svg create mode 100644 Assets/icons/svg_undo.svg diff --git a/Assets/icons/svg_hyperlink.svg b/Assets/icons/svg_hyperlink.svg new file mode 100644 index 0000000..930588a --- /dev/null +++ b/Assets/icons/svg_hyperlink.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/Assets/icons/svg_redo.svg b/Assets/icons/svg_redo.svg new file mode 100644 index 0000000..a96d7e5 --- /dev/null +++ b/Assets/icons/svg_redo.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/Assets/icons/svg_table.svg b/Assets/icons/svg_table.svg new file mode 100644 index 0000000..9c21ff1 --- /dev/null +++ b/Assets/icons/svg_table.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Assets/icons/svg_undo.svg b/Assets/icons/svg_undo.svg new file mode 100644 index 0000000..aced362 --- /dev/null +++ b/Assets/icons/svg_undo.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Models/DraggableContainer.py b/Models/DraggableContainer.py index 978fa84..e57bec6 100644 --- a/Models/DraggableContainer.py +++ b/Models/DraggableContainer.py @@ -118,6 +118,8 @@ def leaveEvent(self, e: QMouseEvent): self.setStyleSheet("border: none;") # Delete this Draggable Container if childWidget says it's empty + # current bug: draggable containers will still exist after creating a + # new textbox but after creating an additional textbox, the dc will remove itself. if not self.childWidget.hasFocus(): if hasattr(self.childWidget, "checkEmpty"): if self.childWidget.checkEmpty(): diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index 8919244..df94611 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -37,6 +37,9 @@ def build_ui(editor): leftSideLayout.setContentsMargins(0, 0, 0, 0) leftSideLayout.setSpacing(0) + + + # Right side of the app's layout rightSideLayout = QVBoxLayout() rightSideContainerWidget = QWidget() @@ -56,6 +59,10 @@ def build_ui(editor): gridLayout.addWidget(leftSideContainerWidget, 0, 0) gridLayout.addWidget(rightSideContainerWidget, 0, 1) + addSectionButton = QPushButton("Add Section") + #add functionality e.g. addSectionButton.clcicked.connect(editor.add_section_function) + leftSideLayout.addWidget(addSectionButton) + def build_window(editor): editor.setWindowTitle("OpenNote") editor.setWindowIcon(QIcon('./Assets/OpenNoteLogo.png')) @@ -85,26 +92,20 @@ def build_menubar(editor): file.addActions([new_file, open_file, save_file, save_fileAs]) -''' -def build_toolbar(editor): - toolbar = QToolBar("Main toolbar") - editor.addToolBar(Qt.ToolBarArea.TopToolBarArea, toolbar) - - button_action = QAction("Your button", editor) - button_action.setStatusTip("This is your button") - button_action.triggered.connect(action.onMyToolBarButtonClick) - button_action.setCheckable(True) - toolbar.addAction(button_action) -''' - - - def build_toolbar(editor): toolbar = QToolBar() toolbar.setIconSize(QSize(16, 16)) toolbar.setMovable(False) editor.addToolBar(Qt.ToolBarArea.TopToolBarArea, toolbar) + spacer = QWidget() + spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) + + undo = build_action(toolbar, 'assets/icons/svg_undo', "undo", "undo", False) + redo = build_action(toolbar, 'assets/icons/svg_redo', "redo", "redo", False) + + + font = QFontComboBox() font.currentFontChanged.connect(lambda x: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Font, font.currentFont())) @@ -113,25 +114,33 @@ def build_toolbar(editor): size.currentIndexChanged.connect(lambda x: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontSize, int(size.currentText()))) bgColor = build_action(toolbar, 'assets/icons/svg_font_bucket', "Text Box Color", "Text Box Color", False) - bgColor.triggered.connect(lambda x: openGetColorDialog(purpose = "background")) + bgColor.triggered.connect(lambda: openGetColorDialog(purpose = "background")) + + fontColor = build_action(toolbar, 'assets/icons/svg_font_color', "Font Color", "Font Color", False) - fontColor.triggered.connect(lambda x: openGetColorDialog(purpose = "font")) + fontColor.triggered.connect(lambda: openGetColorDialog(purpose = "font")) bold = build_action(toolbar, 'assets/icons/bold', "Bold", "Bold", True) - bold.triggered.connect(lambda x: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontBold, None)) + bold.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontBold, None)) italic = build_action(toolbar, 'assets/icons/italic.svg', "Italic", "Italic", True) - italic.triggered.connect(lambda x: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontItalic, None)) + #italic.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(setFontItalicCustom), None) underline = build_action(toolbar, 'assets/icons/underline.svg', "Underline", "Underline", True) #underline.toggled.connect(lambda x: editor.childWidget. setFontUnderlineCustom(True if x else False)) - + table = build_action(toolbar, 'assets/icons/svg_table', "Create Table", "Create Table", True) + hyperlink = build_action(toolbar, 'assets/icons/svg_hyperlink', "Hyperlink", "Hyperlink", True) + + toolbar.addActions([undo, redo]) + toolbar.addSeparator() toolbar.addWidget(font) toolbar.addWidget(size) - + toolbar.addSeparator() toolbar.addActions([bgColor, fontColor, bold, italic, underline]) + toolbar.addSeparator() + toolbar.addActions([table, hyperlink]) def openGetColorDialog(purpose): From 9e8ec6f0073e8ac94997bbdfaa28cf51292fb303 Mon Sep 17 00:00:00 2001 From: ldeltastreaml <70774713+ldeltastreaml@users.noreply.github.com> Date: Wed, 18 Oct 2023 23:47:43 -0500 Subject: [PATCH 006/127] Changed Section for Page "Section" and "page" are reversed on Opennote compared to Onenote, so for the sake of clarity i swapped the text visually. This is a bandage for the issue. --- Views/SectionView.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/Views/SectionView.py b/Views/SectionView.py index e5fbb37..66e2f12 100644 --- a/Views/SectionView.py +++ b/Views/SectionView.py @@ -102,38 +102,39 @@ def openMenu(self, position: QPoint): clickedSectionIndex = self.tabs.tabAt(position) sectionModel = self.tabs.tabData(clickedSectionIndex) + # Changed "section" to "page" for the sake of clarity between Opennote and Onenote menu = QMenu() - addSectionAction = menu.addAction(self.tr("Add Section")) + addSectionAction = menu.addAction(self.tr("Add Page")) addSectionAction.triggered.connect(partial(self.addSection, sectionModel, clickedSectionIndex)) - deleteSectionAction = menu.addAction(self.tr("Delete Section")) + deleteSectionAction = menu.addAction(self.tr("Delete Page")) deleteSectionAction.triggered.connect(partial(self.deleteSection, sectionModel, clickedSectionIndex)) - renameSectionAction = menu.addAction(self.tr("Rename Section")) + renameSectionAction = menu.addAction(self.tr("Rename Page")) renameSectionAction.triggered.connect(partial(self.renameSection, sectionModel, clickedSectionIndex)) menu.exec(self.tabs.mapToGlobal(position)) def addSection(self, sectionModel: SectionModel, clickedSectionIndex: int): - print("ADD SECTION") + print("ADD PAGE") - addedSectionIndex = self.tabs.addTab("New Section") # Add section to UI + addedSectionIndex = self.tabs.addTab("New Page") # Add section to UI rightOfClickedSectionIndex = clickedSectionIndex + 1 self.tabs.moveTab(addedSectionIndex, rightOfClickedSectionIndex) # Move to right of right clicked section - newSectionModel = SectionModel("New Section") # Create new SectionModel + newSectionModel = SectionModel("New Page") # Create new SectionModel self.tabs.setTabData(rightOfClickedSectionIndex, newSectionModel) # Set new SectionModel as section data self.sectionModels.insert(clickedSectionIndex + 1, newSectionModel) # Insert new SectionModel into list of section models def deleteSection(self, sectionModel: SectionModel, clickedSectionIndex: int): - print("DELETE SECTION") + print("DELETE PAGE") self.tabs.removeTab(clickedSectionIndex) # Remove section from UI self.sectionModels.pop(clickedSectionIndex) # Remove section from list of section models def renameSection(self, sectionModel: SectionModel, clickedSectionIndex: int): - print("RENAME SECTION") - newName, accept = QInputDialog.getText(self, 'Change Section Title', 'Enter new title of section: ') + print("RENAME PAGE") + newName, accept = QInputDialog.getText(self, 'Change Page Title', 'Enter new title of page: ') if accept: self.tabs.setTabText(clickedSectionIndex, newName) # Rename section in UI self.sectionModels[clickedSectionIndex].title = newName # Rename section in SectionModel @@ -142,7 +143,7 @@ def changeSection(self, sectionIndex: int): if self.isLoading: # Dont change sections while loading in new tabs (it will keep emitting the sectionChanged signal) return - print("CHANGED SECTION") + print("CHANGED PAGE") sectionModel = self.tabs.tabData(sectionIndex) editorSignalsInstance.sectionChanged.emit(sectionModel) # Notify editorframe that section has changed From a5dc75297638ce26f5bbd660ad73fe3f083e478f Mon Sep 17 00:00:00 2001 From: ldeltastreaml <70774713+ldeltastreaml@users.noreply.github.com> Date: Thu, 19 Oct 2023 00:31:53 -0500 Subject: [PATCH 007/127] Revert "Changed Section for Page" This reverts commit 9e8ec6f0073e8ac94997bbdfaa28cf51292fb303. --- Views/SectionView.py | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/Views/SectionView.py b/Views/SectionView.py index 66e2f12..e5fbb37 100644 --- a/Views/SectionView.py +++ b/Views/SectionView.py @@ -102,39 +102,38 @@ def openMenu(self, position: QPoint): clickedSectionIndex = self.tabs.tabAt(position) sectionModel = self.tabs.tabData(clickedSectionIndex) - # Changed "section" to "page" for the sake of clarity between Opennote and Onenote menu = QMenu() - addSectionAction = menu.addAction(self.tr("Add Page")) + addSectionAction = menu.addAction(self.tr("Add Section")) addSectionAction.triggered.connect(partial(self.addSection, sectionModel, clickedSectionIndex)) - deleteSectionAction = menu.addAction(self.tr("Delete Page")) + deleteSectionAction = menu.addAction(self.tr("Delete Section")) deleteSectionAction.triggered.connect(partial(self.deleteSection, sectionModel, clickedSectionIndex)) - renameSectionAction = menu.addAction(self.tr("Rename Page")) + renameSectionAction = menu.addAction(self.tr("Rename Section")) renameSectionAction.triggered.connect(partial(self.renameSection, sectionModel, clickedSectionIndex)) menu.exec(self.tabs.mapToGlobal(position)) def addSection(self, sectionModel: SectionModel, clickedSectionIndex: int): - print("ADD PAGE") + print("ADD SECTION") - addedSectionIndex = self.tabs.addTab("New Page") # Add section to UI + addedSectionIndex = self.tabs.addTab("New Section") # Add section to UI rightOfClickedSectionIndex = clickedSectionIndex + 1 self.tabs.moveTab(addedSectionIndex, rightOfClickedSectionIndex) # Move to right of right clicked section - newSectionModel = SectionModel("New Page") # Create new SectionModel + newSectionModel = SectionModel("New Section") # Create new SectionModel self.tabs.setTabData(rightOfClickedSectionIndex, newSectionModel) # Set new SectionModel as section data self.sectionModels.insert(clickedSectionIndex + 1, newSectionModel) # Insert new SectionModel into list of section models def deleteSection(self, sectionModel: SectionModel, clickedSectionIndex: int): - print("DELETE PAGE") + print("DELETE SECTION") self.tabs.removeTab(clickedSectionIndex) # Remove section from UI self.sectionModels.pop(clickedSectionIndex) # Remove section from list of section models def renameSection(self, sectionModel: SectionModel, clickedSectionIndex: int): - print("RENAME PAGE") - newName, accept = QInputDialog.getText(self, 'Change Page Title', 'Enter new title of page: ') + print("RENAME SECTION") + newName, accept = QInputDialog.getText(self, 'Change Section Title', 'Enter new title of section: ') if accept: self.tabs.setTabText(clickedSectionIndex, newName) # Rename section in UI self.sectionModels[clickedSectionIndex].title = newName # Rename section in SectionModel @@ -143,7 +142,7 @@ def changeSection(self, sectionIndex: int): if self.isLoading: # Dont change sections while loading in new tabs (it will keep emitting the sectionChanged signal) return - print("CHANGED PAGE") + print("CHANGED SECTION") sectionModel = self.tabs.tabData(sectionIndex) editorSignalsInstance.sectionChanged.emit(sectionModel) # Notify editorframe that section has changed From 7489316ef767b6a68dac63719ac42531ba548a03 Mon Sep 17 00:00:00 2001 From: ldeltastreaml <70774713+ldeltastreaml@users.noreply.github.com> Date: Thu, 19 Oct 2023 00:57:45 -0500 Subject: [PATCH 008/127] Pages can no longer be nested Pages used to be able to be nested under other pages. --- Views/PageView.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/Views/PageView.py b/Views/PageView.py index 65922c6..f8abc74 100644 --- a/Views/PageView.py +++ b/Views/PageView.py @@ -141,6 +141,19 @@ def eventFilter(self, source, event): return True return False + def addPage(self, level: int, clickedIndex: QModelIndex): + # New page added at the top level (root) + newPageModel = PageModel('New Page', 0) # Assuming 0 as the parent UUID for the root + newPage = QStandardItem(newPageModel.title) + newPage.setData(newPageModel) + newPage.setEditable(False) + root.appendRow([newPage]) # Add to UI + self.pageModels.append(newPageModel) # Add to array of PageModel + + self.tree.expandAll() + + # previous addPage would nest the page into the selected page (not a function in Onenote) + ''' def addPage(self, level: int, clickedIndex: QModelIndex): # New page added under parent (what the user right clicked on) @@ -155,7 +168,7 @@ def addPage(self, level: int, clickedIndex: QModelIndex): parentPage.appendRow([newPage]) # Add to UI self.pageModels.append(newPageModel) # Add to array of PageModel - self.tree.expand(clickedIndex) + self.tree.expand(clickedIndex) ''' def deletePage(self, page: QStandardItem): deletePages = [page] From bdc4365cc5661d944b95de61135226f3f6163bae Mon Sep 17 00:00:00 2001 From: ldeltastreaml <70774713+ldeltastreaml@users.noreply.github.com> Date: Thu, 19 Oct 2023 01:08:12 -0500 Subject: [PATCH 009/127] Added Merge Pages function Not sure if working but it should grab the sections of two pages and merge them into 1 page. --- Views/PageView.py | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/Views/PageView.py b/Views/PageView.py index f8abc74..cc8a634 100644 --- a/Views/PageView.py +++ b/Views/PageView.py @@ -222,3 +222,48 @@ def changePage(self, current: QModelIndex, previous: QModelIndex): print("CHANGED PAGE TO: " + newPage.data().title) editorSignalsInstance.pageChanged.emit(newPageModel) # Tell the sectionView that the page has changed + + # Not sure if working as intended + def mergePages(self): + # Prompt the user to select two pages + selectedIndexes = self.tree.selectedIndexes() + + # Check if exactly two pages are selected + if len(selectedIndexes) == 2: + # Retrieve the QStandardItem objects corresponding to the selected pages + page1Item = self.model.itemFromIndex(selectedIndexes[0]) + page2Item = self.model.itemFromIndex(selectedIndexes[1]) + + # Extract the PageModel objects from the selected QStandardItem objects + page1Model = page1Item.data() + page2Model = page2Item.data() + + # Merge the sections of the two pages into one page + mergedSections = page1Model.sections + page2Model.sections + newPageModel = PageModel('Merged Page', 0, mergedSections) # Assuming 0 as the parent UUID for the root + + # Create a new QStandardItem for the merged page + newPageItem = QStandardItem(newPageModel.title) + newPageItem.setData(newPageModel) + newPageItem.setEditable(False) + + # Insert the new merged page at the bottom of the children of the root + root = self.model.invisibleRootItem() + index = root.rowCount() # Get the last index + root.insertRow(index, [newPageItem]) + + # Remove the original two pages from the model + root.removeRow(page1Item.row()) + root.removeRow(page2Item.row()) + + # Update the pageModels list + self.pageModels.remove(page1Model) + self.pageModels.remove(page2Model) + self.pageModels.append(newPageModel) + + # Expand the tree to show the changes + self.tree.expandAll() + else: + # If not exactly two pages are selected, show a warning or message + QMessageBox.warning(self, 'Invalid Selection', 'Please select exactly two pages to merge.', QMessageBox.Ok) + From 760f061d6531684314e41c9e81f86e2f4661c050 Mon Sep 17 00:00:00 2001 From: Keido0208 <50084889+Keido0208@users.noreply.github.com> Date: Thu, 19 Oct 2023 01:45:41 -0500 Subject: [PATCH 010/127] Create add notebook function Create add notebook function which asks user to enter note name and create new notebook --- Modules/Load.py | 53 +++++++++++++++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/Modules/Load.py b/Modules/Load.py index b618271..5082bb3 100644 --- a/Modules/Load.py +++ b/Modules/Load.py @@ -1,5 +1,8 @@ import pickle import os +from tkinter import * +from tkinter import ttk +import pyautogui from Modules.Save import Autosaver @@ -9,28 +12,39 @@ from Models.NotebookModel import NotebookModel + # Creates a new notebook def new(editor): - print("RAN NEW") + print("New Note book is created") + window = Tk() + nb = ttk.Notebook(window) + nb.pack(fill=BOTH, expand=1) + + p = ttk.Frame(nb) + p.pack(fill=BOTH, expand=1) + + p_name = pyautogui.prompt("Enter Page Name") + + nb.add(p, text=p_name) + text_ar = Text(p, fg="black", bg="white", font=("segoe print", 15)) + text_ar.pack() destroy(editor) - editor.notebook = NotebookModel('Untitled') + editor.notebook = NotebookModel("Untitled") editor.notebookTitleView.setText(editor.notebook.title) editor.selected = None editor.autosaver = Autosaver(editor) - build(editor) # should we build here, or should above be in build? + build(editor) # should we build here, or should above be in build? + # Loads models.notebook.Notebook class from file def load(editor): print("LOADING") path, accept = QFileDialog.getOpenFileName( - editor, - 'Open Notebook', - '', - 'OpenNote (*.on *.ontemp)' + editor, "Open Notebook", "", "OpenNote (*.on *.ontemp)" ) if accept: - file = open(path, 'rb') + file = open(path, "rb") destroy(editor) editor.notebook = pickle.load(file) # for page in editor.notebook.pages: @@ -43,25 +57,25 @@ def load(editor): return build(editor) + # Try to find and open the most recent OpenNote related file def load_most_recent_notebook(editor): - print("LOAD RECENT RAN") files = [] - saves_directory = os.path.join(os.getcwd(), 'Saves') + saves_directory = os.path.join(os.getcwd(), "Saves") for file in os.listdir(saves_directory): - file_path = os.path.join(saves_directory, file) - if os.path.isfile(file_path): - files.append(file_path) - print(file_path) + file_path = os.path.join(saves_directory, file) + if os.path.isfile(file_path): + files.append(file_path) + print(file_path) - directory_files = reversed(sorted(files, key = os.path.getmtime)) + directory_files = reversed(sorted(files, key=os.path.getmtime)) for f in directory_files: - if (f.endswith(".on") or f.endswith(".ontemp")): + if f.endswith(".on") or f.endswith(".ontemp"): print("FOUND: " + str(f)) try: # prob need load from file function, dup functionality - file = open(os.path.join(os.getcwd() + "\\Saves", f), 'rb') + file = open(os.path.join(os.getcwd() + "\\Saves", f), "rb") destroy(editor) editor.notebook = pickle.load(file) build(editor) @@ -75,6 +89,7 @@ def load_most_recent_notebook(editor): except: continue + def build(editor): print("BUILDING FROM LOAD") @@ -99,8 +114,7 @@ def build(editor): print("RELOADED VIEWS ") - if len(editor.notebook.pages) > 0: # If pages exist - + if len(editor.notebook.pages) > 0: # If pages exist print("PAGES EXIST") # Show all Pages in Notebook # editor.pageView.loadPages(editor.notebook.pages) @@ -129,6 +143,7 @@ def build(editor): # editor.pageIndex = 0 # editor.sectionIndex = 0 + # Destroy all Widgets in the Current Notebook def destroy(editor): print("RAN DESTROY") From fb0d6144d5d3714124feb9144bb7fdcfbf0d9254 Mon Sep 17 00:00:00 2001 From: Keido0208 <50084889+Keido0208@users.noreply.github.com> Date: Thu, 19 Oct 2023 01:47:43 -0500 Subject: [PATCH 011/127] Create add notebook function Create add notebook function which asks user to enter note name and create new notebook --- Modules/Load.py | 53 +++++++++++++++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/Modules/Load.py b/Modules/Load.py index b618271..5082bb3 100644 --- a/Modules/Load.py +++ b/Modules/Load.py @@ -1,5 +1,8 @@ import pickle import os +from tkinter import * +from tkinter import ttk +import pyautogui from Modules.Save import Autosaver @@ -9,28 +12,39 @@ from Models.NotebookModel import NotebookModel + # Creates a new notebook def new(editor): - print("RAN NEW") + print("New Note book is created") + window = Tk() + nb = ttk.Notebook(window) + nb.pack(fill=BOTH, expand=1) + + p = ttk.Frame(nb) + p.pack(fill=BOTH, expand=1) + + p_name = pyautogui.prompt("Enter Page Name") + + nb.add(p, text=p_name) + text_ar = Text(p, fg="black", bg="white", font=("segoe print", 15)) + text_ar.pack() destroy(editor) - editor.notebook = NotebookModel('Untitled') + editor.notebook = NotebookModel("Untitled") editor.notebookTitleView.setText(editor.notebook.title) editor.selected = None editor.autosaver = Autosaver(editor) - build(editor) # should we build here, or should above be in build? + build(editor) # should we build here, or should above be in build? + # Loads models.notebook.Notebook class from file def load(editor): print("LOADING") path, accept = QFileDialog.getOpenFileName( - editor, - 'Open Notebook', - '', - 'OpenNote (*.on *.ontemp)' + editor, "Open Notebook", "", "OpenNote (*.on *.ontemp)" ) if accept: - file = open(path, 'rb') + file = open(path, "rb") destroy(editor) editor.notebook = pickle.load(file) # for page in editor.notebook.pages: @@ -43,25 +57,25 @@ def load(editor): return build(editor) + # Try to find and open the most recent OpenNote related file def load_most_recent_notebook(editor): - print("LOAD RECENT RAN") files = [] - saves_directory = os.path.join(os.getcwd(), 'Saves') + saves_directory = os.path.join(os.getcwd(), "Saves") for file in os.listdir(saves_directory): - file_path = os.path.join(saves_directory, file) - if os.path.isfile(file_path): - files.append(file_path) - print(file_path) + file_path = os.path.join(saves_directory, file) + if os.path.isfile(file_path): + files.append(file_path) + print(file_path) - directory_files = reversed(sorted(files, key = os.path.getmtime)) + directory_files = reversed(sorted(files, key=os.path.getmtime)) for f in directory_files: - if (f.endswith(".on") or f.endswith(".ontemp")): + if f.endswith(".on") or f.endswith(".ontemp"): print("FOUND: " + str(f)) try: # prob need load from file function, dup functionality - file = open(os.path.join(os.getcwd() + "\\Saves", f), 'rb') + file = open(os.path.join(os.getcwd() + "\\Saves", f), "rb") destroy(editor) editor.notebook = pickle.load(file) build(editor) @@ -75,6 +89,7 @@ def load_most_recent_notebook(editor): except: continue + def build(editor): print("BUILDING FROM LOAD") @@ -99,8 +114,7 @@ def build(editor): print("RELOADED VIEWS ") - if len(editor.notebook.pages) > 0: # If pages exist - + if len(editor.notebook.pages) > 0: # If pages exist print("PAGES EXIST") # Show all Pages in Notebook # editor.pageView.loadPages(editor.notebook.pages) @@ -129,6 +143,7 @@ def build(editor): # editor.pageIndex = 0 # editor.sectionIndex = 0 + # Destroy all Widgets in the Current Notebook def destroy(editor): print("RAN DESTROY") From 436b4453d26915f8e04b467bce6d6b8570936dbf Mon Sep 17 00:00:00 2001 From: sillypenguin77 <67487654+sillypenguin77@users.noreply.github.com> Date: Thu, 26 Oct 2023 12:39:26 -0500 Subject: [PATCH 012/127] Set default text to black --- Widgets/Textbox.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Widgets/Textbox.py b/Widgets/Textbox.py index 998d2fe..107702f 100644 --- a/Widgets/Textbox.py +++ b/Widgets/Textbox.py @@ -15,6 +15,7 @@ def __init__(self, x, y, w = 15, h = 30, t = ''): self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.textChanged.connect(self.textChangedEvent) self.setStyleSheet('background-color: rgba(0, 0, 0, 0);') + self.setTextColor('black') def textChangedEvent(self): if len(self.toPlainText()) < 2: From 148e5d727ff3bd7a8e053db20b38c8f8b89b9702 Mon Sep 17 00:00:00 2001 From: sillypenguin77 <67487654+sillypenguin77@users.noreply.github.com> Date: Thu, 26 Oct 2023 12:39:56 -0500 Subject: [PATCH 013/127] Added Link Widget Functionality --- Views/EditorFrameView.py | 8 +++++ Widgets/Link.py | 76 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 Widgets/Link.py diff --git a/Views/EditorFrameView.py b/Views/EditorFrameView.py index 5232ead..e316db2 100644 --- a/Views/EditorFrameView.py +++ b/Views/EditorFrameView.py @@ -15,6 +15,10 @@ from Widgets.Table import TableWidget from Modules.Clipboard import Clipboard from Modules.Undo import UndoHandler +from Widgets.Link import LinkWidget +from Widgets.Link import LinkDialog + + # Handles all widget display (could be called widget view, but so could draggablecontainer) class EditorFrameView(QWidget): @@ -179,6 +183,10 @@ def mousePressEvent(self, event): add_custom_widget.triggered.connect(lambda: self.addCustomWidget(event)) frame_menu.addAction(add_custom_widget) + insert_Link = QAction("Insert Link", editor) + insert_Link.triggered.connect(lambda: self.newWidgetOnSection(LinkWidget,event.pos())) + frame_menu.addAction(insert_Link) + frame_menu.exec(event.globalPos()) def addCustomWidget(self, event): diff --git a/Widgets/Link.py b/Widgets/Link.py new file mode 100644 index 0000000..a6c41b1 --- /dev/null +++ b/Widgets/Link.py @@ -0,0 +1,76 @@ +from PySide6.QtCore import * +from PySide6.QtGui import * +from PySide6.QtWidgets import * + + +FONT_SIZES = [7, 8, 9, 10, 11, 12, 13, 14, 18, 24, 36, 48, 64, 72, 96, 144, 288] + + +class LinkWidget(QLabel): + def __init__(self, x, y, l, d, w = 15, h = 30): + super().__init__() + + self.setGeometry(x, y, w, h) + self.setStyleSheet('font-size: 20px') + self.setOpenExternalLinks(True) + + + self.setText(f'{d}') + #self.setParent(parent) + + @staticmethod + def new(clickPos: QPoint): + dialog = LinkDialog() + + if dialog.exec_() == QDialog.Accepted: + link_address, display_text = dialog.get_link_data() + + print(link_address) + + return LinkWidget(clickPos.x(), clickPos.y(), link_address, display_text) + + def __getstate__(self): + data = {} + + data['geometry'] = self.parentWidget().geometry() + #data['content'] = self.toHtml() + data['stylesheet'] = self.styleSheet() + return data + + def __setstate__(self, data): + self.__init__(data['geometry'].x(), data['geometry'].y(), data['geometry'].width(), data['geometry'].height(), data['content']) + self.setStyleSheet(data['stylesheet']) + +class LinkDialog(QDialog): + def __init__(self): + super().__init__() + self.setWindowTitle("Insert Link") + layout = QVBoxLayout() + + self.link_label = QLabel("Link Address:") + self.link_textbox = QLineEdit() + self.display_label = QLabel("Display Text:") + self.display_textbox = QLineEdit() + + layout.addWidget(self.link_label) + layout.addWidget(self.link_textbox) + layout.addWidget(self.display_label) + layout.addWidget(self.display_textbox) + + ok_button = QPushButton("OK") + ok_button.clicked.connect(self.accept) + cancel_button = QPushButton("Cancel") + cancel_button.clicked.connect(self.reject) + + layout.addWidget(ok_button) + layout.addWidget(cancel_button) + + self.setLayout(layout) + + def get_link_data(self): + link_address = self.link_textbox.text() + display_text = self.display_textbox.text() + return link_address, display_text + + + From 8d2eac0551126b93b1098a8a51d9ddbd17502875 Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Wed, 1 Nov 2023 16:28:11 -0500 Subject: [PATCH 014/127] Added table edit --- Modules/BuildUI.py | 53 +++++++++++++++++++++++++++++++++++++++- Views/EditorFrameView.py | 9 ++++--- Widgets/Table.py | 48 ++++++++++++++++++++++++++++++++++++ 3 files changed, 105 insertions(+), 5 deletions(-) diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index df94611..2b456ef 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -5,6 +5,8 @@ from PySide6.QtGui import * from PySide6.QtWidgets import * +from Views.EditorFrameView import * +from Widgets.Table import * from Modules.EditorSignals import editorSignalsInstance, ChangedWidgetAttribute FONT_SIZES = [7, 8, 9, 10, 11, 12, 13, 14, 18, 24, 36, 48, 64, 72, 96, 144, 288] @@ -130,7 +132,9 @@ def build_toolbar(editor): underline = build_action(toolbar, 'assets/icons/underline.svg', "Underline", "Underline", True) #underline.toggled.connect(lambda x: editor.childWidget. setFontUnderlineCustom(True if x else False)) - table = build_action(toolbar, 'assets/icons/svg_table', "Create Table", "Create Table", True) + table = build_action(toolbar, 'assets/icons/svg_table', "Create Table", "Create Table", False) + table.triggered.connect(show_table_popup) + hyperlink = build_action(toolbar, 'assets/icons/svg_hyperlink', "Hyperlink", "Hyperlink", True) toolbar.addActions([undo, redo]) @@ -156,3 +160,50 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): action.setStatusTip(set_status_tip) action.setCheckable(set_checkable) return action + +def show_table_popup(self): + popup = TablePopupWindow() + popup.exec_() + #def undo_triggered(self): + # Call the EditorFrameView's triggerUndo method + #self.EditorFrameView.triggerUndo() + +class TablePopupWindow(QDialog): + def __init__(self): + super().__init__() + '''self.setWindowTitle("Popup Window") + layout = QVBoxLayout() + label = QLabel("This is a popup window.") + layout.addWidget(label) + self.setLayout(layout)''' + self.setWindowTitle("Table Configuration") + self.layout = QVBoxLayout() + + self.rows_input = QLineEdit(self) + self.rows_input.setPlaceholderText("Enter number of rows:") + self.layout.addWidget(self.rows_input) + + self.cols_input = QLineEdit(self) + colNum = self.cols_input.setPlaceholderText("Enter number of columns:") + self.layout.addWidget(self.cols_input) + + create_table_button = QPushButton("Create Table") + self.layout.addWidget(create_table_button) + create_table_button.clicked.connect(self.accept) + #create error message if no data is entered or if number of rows or columns are < 1 + + cancel_button = QPushButton("Cancel") + cancel_button.clicked.connect(self.reject) + self.setLayout(self.layout) + + def get_table_data(self): + rows_input = self.rows_input.text() + cols_input = self.cols_input.text() + return rows_input, cols_input + + def create_table(self): + print("table") + #row_num = int(self.rows_input.text()) + #col_num = int(self.cols_input.text()) + #self.EditorFrameView.add_table_action(row_num, col_num) + diff --git a/Views/EditorFrameView.py b/Views/EditorFrameView.py index 38b5f63..13d1846 100644 --- a/Views/EditorFrameView.py +++ b/Views/EditorFrameView.py @@ -160,10 +160,6 @@ def mousePressEvent(self, e): if e.buttons() == Qt.RightButton: frame_menu = QMenu(self) - cut_action = QAction("Cut", self) - #add cut functionality - frame_menu.addAction(cut_action) - paste = QAction("Paste", editor) paste.triggered.connect(lambda: self.pasteWidget(e.pos())) frame_menu.addAction(paste) @@ -226,3 +222,8 @@ def mouseMoveEvent(self, e): # This event is only called after clicking down on # Resize multi-select widget on mouse every proceeding mouse movement (dragging) else: self.multiselector.continueDrawingArea(e) + def add_table_action(self): + print("Add table action") + + self.newWidgetOnSection(TableWidget, 0) + \ No newline at end of file diff --git a/Widgets/Table.py b/Widgets/Table.py index 7f615ff..4b3fe13 100644 --- a/Widgets/Table.py +++ b/Widgets/Table.py @@ -2,6 +2,7 @@ from PySide6.QtGui import * from PySide6.QtWidgets import * + class TableWidget(QWidget): def __init__(self, x, y, w, h, rows, cols): super(TableWidget, self).__init__() @@ -42,6 +43,8 @@ def addCol(self): @staticmethod def new(clickPos: QPoint): + #dialog = table + #if return TableWidget(clickPos.x(), clickPos.y(), 200, 200, 2, 2) def customMenuItems(self): @@ -79,3 +82,48 @@ def __setstate__(self, state): for i in range(colCnt): for j in range(rowCnt): self.table.setItem(j, i, QTableWidgetItem(state['tableData'][i][j])) + +def show_table_popup(self): + popup = TablePopupWindow() + popup.exec_() + #def undo_triggered(self): + # Call the EditorFrameView's triggerUndo method + #self.EditorFrameView.triggerUndo() + +class TablePopupWindow(QDialog): + def __init__(self): + super().__init__() + '''self.setWindowTitle("Popup Window") + layout = QVBoxLayout() + label = QLabel("This is a popup window.") + layout.addWidget(label) + self.setLayout(layout)''' + self.setWindowTitle("Table Configuration") + self.layout = QVBoxLayout() + + self.rows_input = QLineEdit(self) + self.rows_input.setPlaceholderText("Enter number of rows:") + self.layout.addWidget(self.rows_input) + + self.cols_input = QLineEdit(self) + colNum = self.cols_input.setPlaceholderText("Enter number of columns:") + self.layout.addWidget(self.cols_input) + + create_table_button = QPushButton("Create Table", self) + self.layout.addWidget(self.create_button) + #create error message if no data is entered or if number of rows or columns are < 1 + create_table_button.clicked.connect(self.accept) + cancel_button = QPushButton("Cancel") + cancel_button.clicked.connect(self.reject) + self.setLayout(self.layout) + + def get_table_data(self): + rows_input = self.rows_input.text() + cols_input = self.cols_input.text() + return rows_input, cols_input + + def create_table(self): + print("table") + #row_num = int(self.rows_input.text()) + #col_num = int(self.cols_input.text()) + #self.EditorFrameView.add_table_action(row_num, col_num) \ No newline at end of file From 86d412f84986f84c5b37e62449a27b3affaf77cb Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Thu, 2 Nov 2023 15:24:02 -0500 Subject: [PATCH 015/127] added table functionality --- Modules/BuildUI.py | 87 +++++++++++++++++++++++++++++++++++----- Views/EditorFrameView.py | 52 +++++++++++++++++++----- Widgets/Textbox.py | 82 +++++++++++++++++++++---------------- 3 files changed, 168 insertions(+), 53 deletions(-) diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index 2b456ef..99d1d93 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -5,9 +5,14 @@ from PySide6.QtGui import * from PySide6.QtWidgets import * -from Views.EditorFrameView import * -from Widgets.Table import * +from Models.DraggableContainer import DraggableContainer +from Widgets.Textbox import * + from Modules.EditorSignals import editorSignalsInstance, ChangedWidgetAttribute +from Modules.Undo import UndoHandler +from Widgets.Table import * + +from Views.EditorFrameView import * FONT_SIZES = [7, 8, 9, 10, 11, 12, 13, 14, 18, 24, 36, 48, 64, 72, 96, 144, 288] @@ -15,10 +20,13 @@ def build_ui(editor): print("Building UI...") + + #editor.EditorFrameView = EditorFrameView(editor) #editor.statusBar = editor.statusBar() build_window(editor) build_menubar(editor) build_toolbar(editor) + #build_test_toolbar(editor) # Application's main layout (grid) gridLayout = QGridLayout() @@ -100,16 +108,20 @@ def build_toolbar(editor): toolbar.setMovable(False) editor.addToolBar(Qt.ToolBarArea.TopToolBarArea, toolbar) + #separates toolbar with a line break spacer = QWidget() spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) - undo = build_action(toolbar, 'assets/icons/svg_undo', "undo", "undo", False) + toolbar_undo = build_action(toolbar, 'assets/icons/svg_undo', "undo", "undo", False) + #toolbar_undo.triggered.connect(editor.frameView.triggerUndo) + + redo = build_action(toolbar, 'assets/icons/svg_redo', "redo", "redo", False) font = QFontComboBox() - font.currentFontChanged.connect(lambda x: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Font, font.currentFont())) + font.currentFontChanged.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Font, font.currentFont())) size = QComboBox() size.addItems([str(fs) for fs in FONT_SIZES]) @@ -124,8 +136,11 @@ def build_toolbar(editor): fontColor.triggered.connect(lambda: openGetColorDialog(purpose = "font")) bold = build_action(toolbar, 'assets/icons/bold', "Bold", "Bold", True) - bold.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontBold, None)) - + #bold.toggled.connect(editor.frameView.toggleBold) + #bold.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontBold, None)) + bold.triggered.connect(editor.frameView.add_table_action) + + #bold.toggled.connect(lambda x: editor.selected.setFontWeight(700 if x else 500)) italic = build_action(toolbar, 'assets/icons/italic.svg', "Italic", "Italic", True) #italic.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(setFontItalicCustom), None) @@ -133,11 +148,22 @@ def build_toolbar(editor): underline = build_action(toolbar, 'assets/icons/underline.svg', "Underline", "Underline", True) #underline.toggled.connect(lambda x: editor.childWidget. setFontUnderlineCustom(True if x else False)) table = build_action(toolbar, 'assets/icons/svg_table', "Create Table", "Create Table", False) - table.triggered.connect(show_table_popup) - + #table.triggered.connect(show_table_popup) + table.triggered.connect(EditorFrameView.add_table_action) hyperlink = build_action(toolbar, 'assets/icons/svg_hyperlink', "Hyperlink", "Hyperlink", True) - toolbar.addActions([undo, redo]) + editor.action1 = QAction('Action 1', editor) + #editor.action1.triggered.connect(EditorFrameView.slot_action1) + toolbar.addAction(editor.action1) + editor.action2 = QAction('Action 2', editor) + #editor.action2.triggered.connect(TextboxWidget.slot_action2) + #editor.action2.triggered.connect(show_popup) + toolbar.addAction(editor.action2) + #editor.button = QPushButton("Click Me", editor) + #editor.button.clicked.connect(editor.slot_button_click) + + + #toolbar.addActions([undo, redo]) toolbar.addSeparator() toolbar.addWidget(font) toolbar.addWidget(size) @@ -146,6 +172,10 @@ def build_toolbar(editor): toolbar.addSeparator() toolbar.addActions([table, hyperlink]) +def toggle_bold(self): + self.is_bold = not self.is_bold + + font =self.text_edit def openGetColorDialog(purpose): color = QColorDialog.getColor() @@ -161,6 +191,45 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): action.setCheckable(set_checkable) return action +def build_test_toolbar(self): + editorFrameViewInstance = EditorFrameView(self) + + toolbar = QToolBar(self) + self.addToolBar(toolbar) + + exitAct = QAction(QIcon('assets/icons/underline.svg'), 'Exit', self) + exitAct.setShortcut('Ctrl+Q') + exitAct.triggered.connect(QApplication.instance().quit) + + self.toolbar = self.addToolBar('Exit') + self.toolbar.addAction(exitAct) + + #font_change + font_combo = QFontComboBox(self) + toolbar.addWidget(font_combo) + + bold = build_action(toolbar, 'assets/icons/bold', "Bold", "Bold", True) + bold.setShortcut('Ctrl+B') + bold.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.connect(self.widgetAttributeChangedEvent)) + + + toolbar.addAction(bold) + + undo_action = QAction("Undo", self) + undo_action.triggered.connect(self.frameView.triggerUndo) + + toolbar.addAction(undo_action) + + + +def change_font(self): + selected_font = self.sender().parent().widgetForAction(self.sender()).currentFont() + + self.text_edit.setFont(selected_font) + +def widgetAttributeChangedEvent(self, draggableContainer): + editorSignalsInstance.widgetAttributeChanged.emit(draggableContainer) + def show_table_popup(self): popup = TablePopupWindow() popup.exec_() diff --git a/Views/EditorFrameView.py b/Views/EditorFrameView.py index 13d1846..e1434fe 100644 --- a/Views/EditorFrameView.py +++ b/Views/EditorFrameView.py @@ -12,7 +12,7 @@ from Modules.EditorSignals import editorSignalsInstance from Widgets.Image import ImageWidget from Modules.Screensnip import SnippingWidget -from Widgets.Table import TableWidget +from Widgets.Table import * from Modules.Clipboard import Clipboard from Modules.Undo import UndoHandler @@ -46,10 +46,14 @@ def __init__(self, editor): # Undo setup self.shortcut = QShortcut(QKeySequence("Ctrl+Z"), self) self.shortcut.setContext(Qt.ApplicationShortcut) - self.shortcut.activated.connect(self.undoHandler.undo) - self.undoHandler.undoWidgetDelete.connect(self.undoWidgetDeleteEvent) + self.shortcut.activated.connect(self.triggerUndo) print("BUILT FRAMEVIEW") + + def triggerUndo(self): + print("triggerUndo Called") + self.undoHandler.undo + self.undoHandler.undoWidgetDelete.connect(self.undoWidgetDeleteEvent) def pasteWidget(self, clickPos): widgetOnClipboard = self.clipboard.getWidgetToPaste() @@ -150,6 +154,7 @@ def mouseReleaseEvent(self, event): # Releasing the mouse after clicking to add text else: + print("CREATE DRAGGABLE CONTAINER") self.newWidgetOnSection(TextboxWidget, event.pos()) def mousePressEvent(self, e): @@ -170,10 +175,9 @@ def mousePressEvent(self, e): add_table = QAction("Add Table", editor) add_table.triggered.connect(lambda: self.newWidgetOnSection(TableWidget, e.pos())) + #add_table.triggered.connect(self.show_table_popup) frame_menu.addAction(add_table) - - take_screensnip = QAction("Snip Screen", editor) take_screensnip.triggered.connect(lambda: self.snipScreen(e.pos())) frame_menu.addAction(take_screensnip) @@ -184,6 +188,11 @@ def mousePressEvent(self, e): frame_menu.exec(e.globalPos()) + def add_table_action(self): + print("add_table_action pressed") + clickPos = QPoint(0, 0) + self.newWidgetOnSection(TableWidget, clickPos) + def addCustomWidget(self, e): def getCustomWidgets(): customWidgets = {} # dict where entries are {name: class} @@ -222,8 +231,31 @@ def mouseMoveEvent(self, e): # This event is only called after clicking down on # Resize multi-select widget on mouse every proceeding mouse movement (dragging) else: self.multiselector.continueDrawingArea(e) - def add_table_action(self): - print("Add table action") - - self.newWidgetOnSection(TableWidget, 0) - \ No newline at end of file + + def toggleBold(self): + print ("TOGGLE BOLD") + dc = DraggableContainer() + cw = dc.childWidget + if(dc.hasFocus()): + cw.changeFontBoldEvent() + #editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontBold, ) + + def slot_action1(self, item): + print("Action 1 triggered") + + +'''class PopupDialog(QDialog): + def __init__(self, name, parent): + super().__init__(parent) + self.resize(600, 300) + self.setWindowTitle("pop") + self.label = QLabel(name, self) + layout = QVBoxLayout() + layout.addWidget(QLabel("Test")) + ok_button = QPushButton("OK") + layout.addWidget(ok_button) + ok_button.clicked.connect(self.accept) + + self.setLayout(layout) + self.setWindowTitle("Table Creation") ''' + diff --git a/Widgets/Textbox.py b/Widgets/Textbox.py index 2c6c170..d0aedf9 100644 --- a/Widgets/Textbox.py +++ b/Widgets/Textbox.py @@ -1,6 +1,7 @@ from PySide6.QtCore import * from PySide6.QtGui import * from PySide6.QtWidgets import * +from Modules.EditorSignals import editorSignalsInstance FONT_SIZES = [7, 8, 9, 10, 11, 12, 13, 14, 18, 24, 36, 48, 64, 72, 96, 144, 288] @@ -42,54 +43,58 @@ def checkEmpty(self): return False def customMenuItems(self): - def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): - action = QAction(QIcon(icon_path), action_name, parent) - action.setStatusTip(set_status_tip) - action.setCheckable(set_checkable) - return action + def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): + action = QAction(QIcon(icon_path), action_name, parent) + action.setStatusTip(set_status_tip) + action.setCheckable(set_checkable) + return action - toolbarTop = QToolBar() - toolbarTop.setIconSize(QSize(16, 16)) - toolbarTop.setMovable(False) + toolbarTop = QToolBar() + toolbarTop.setIconSize(QSize(25, 25)) + toolbarTop.setMovable(False) - toolbarBottom = QToolBar() - toolbarBottom.setIconSize(QSize(16, 16)) - toolbarBottom.setMovable(False) + toolbarBottom = QToolBar() + toolbarBottom.setIconSize(QSize(25, 25)) + toolbarBottom.setMovable(False) - font = QFontComboBox() - font.currentFontChanged.connect(lambda x: self.setCurrentFontCustom(font.currentFont() if x else self.currentFont())) + font = QFontComboBox() + font.currentFontChanged.connect(lambda x: self.setCurrentFontCustom(font.currentFont() if x else self.currentFont())) - size = QComboBox() - size.addItems([str(fs) for fs in FONT_SIZES]) - size.currentIndexChanged.connect(lambda x: self.setFontPointSizeCustom(FONT_SIZES[x] if x else self.fontPointSize())) + size = QComboBox() + size.addItems([str(fs) for fs in FONT_SIZES]) + size.currentIndexChanged.connect(lambda x: self.setFontPointSizeCustom(FONT_SIZES[x] if x else self.fontPointSize())) - bold = build_action(toolbarBottom, 'assets/icons/svg_font_bold', "Bold", "Bold", True) - bold.toggled.connect(lambda x: self.setFontWeightCustom(700 if x else 500)) + bold = build_action(toolbarBottom, 'assets/icons/svg_font_bold', "Bold", "Bold", True) + bold.toggled.connect(lambda x: self.setFontWeightCustom(700 if x else 500)) - italic = build_action(toolbarBottom, 'assets/icons/svg_font_italic', "Italic", "Italic", True) - italic.toggled.connect(lambda x: self.setFontItalicCustom(True if x else False)) + italic = build_action(toolbarBottom, 'assets/icons/svg_font_italic', "Italic", "Italic", True) + def italicToggled(): + print("Italic Toggled") + italic.toggled.connect(lambda x: self.setFontItalicCustom(True if x else False)) + italicToggled() - underline = build_action(toolbarBottom, 'assets/icons/svg_font_underline', "Underline", "Underline", True) - underline.toggled.connect(lambda x: self.setFontUnderlineCustom(True if x else False)) + underline = build_action(toolbarBottom, 'assets/icons/svg_font_underline', "Underline", "Underline", True) + underline.toggled.connect(lambda x: self.setFontUnderlineCustom(True if x else False)) - fontColor = build_action(toolbarBottom, 'assets/icons/svg_font_color', "Font Color", "Font Color", False) - fontColor.triggered.connect(lambda: self.setTextColorCustom(QColorDialog.getColor())) + fontColor = build_action(toolbarBottom, 'assets/icons/svg_font_color', "Font Color", "Font Color", False) + fontColor.triggered.connect(lambda: self.setTextColorCustom(QColorDialog.getColor())) - bgColor = build_action(toolbarBottom, 'assets/icons/svg_font_bucket', "Text Box Color", "Text Box Color", False) - bgColor.triggered.connect(lambda: self.setBackgroundColor(QColorDialog.getColor())) + bgColor = build_action(toolbarBottom, 'assets/icons/svg_font_bucket', "Text Box Color", "Text Box Color", False) + bgColor.triggered.connect(lambda: self.setBackgroundColor(QColorDialog.getColor())) - toolbarTop.addWidget(font) - toolbarTop.addWidget(size) - toolbarBottom.addActions([bold, italic, underline, fontColor, bgColor]) - qwaTop = QWidgetAction(self) - qwaTop.setDefaultWidget(toolbarTop) - qwaBottom = QWidgetAction(self) - qwaBottom.setDefaultWidget(toolbarBottom) + toolbarTop.addWidget(font) + toolbarTop.addWidget(size) + toolbarBottom.addActions([bold, italic, underline, fontColor, bgColor]) + qwaTop = QWidgetAction(self) + qwaTop.setDefaultWidget(toolbarTop) + qwaBottom = QWidgetAction(self) + qwaBottom.setDefaultWidget(toolbarBottom) - return [qwaTop, qwaBottom] + return [qwaTop, qwaBottom] def setFontItalicCustom(self, italic: bool): if not self.applyToAllIfNoSelection(lambda: self.setFontItalic(italic)): + print("setFontItalicCustom Called") self.setFontItalic(italic) def setFontWeightCustom(self, weight: int): @@ -137,3 +142,12 @@ def applyToAllIfNoSelection(self, func): cursor.clearSelection() self.setTextCursor(cursor) return True + + def attributeChangedSlot(attribute, value): + if attribute == editorSignalsInstance.ChangedWidgetAttribute.FontBold: + print("Font Bold Signal") + def slot_action2(self): + print("Action 2 Triggered") + font = QFont() + font.setItalic(True) + self.setFont(font) From a9d70c4d46aad8902a88fe787449fb5790e0108c Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Thu, 2 Nov 2023 18:50:47 -0500 Subject: [PATCH 016/127] Allow custom table sizes --- Modules/BuildUI.py | 53 ++++------------------------------------------ Widgets/Table.py | 21 +++++++++++------- 2 files changed, 17 insertions(+), 57 deletions(-) diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index 99d1d93..d2152e1 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -148,9 +148,9 @@ def build_toolbar(editor): underline = build_action(toolbar, 'assets/icons/underline.svg', "Underline", "Underline", True) #underline.toggled.connect(lambda x: editor.childWidget. setFontUnderlineCustom(True if x else False)) table = build_action(toolbar, 'assets/icons/svg_table', "Create Table", "Create Table", False) - #table.triggered.connect(show_table_popup) table.triggered.connect(EditorFrameView.add_table_action) - hyperlink = build_action(toolbar, 'assets/icons/svg_hyperlink', "Hyperlink", "Hyperlink", True) + #table.triggered.connect(EditorFrameView.add_table_action) + hyperlink = build_action(toolbar, 'assets/icons/svg_hyperlink', "Hyperlink", "Hyperlink", False) editor.action1 = QAction('Action 1', editor) #editor.action1.triggered.connect(EditorFrameView.slot_action1) @@ -228,51 +228,6 @@ def change_font(self): self.text_edit.setFont(selected_font) def widgetAttributeChangedEvent(self, draggableContainer): - editorSignalsInstance.widgetAttributeChanged.emit(draggableContainer) - -def show_table_popup(self): - popup = TablePopupWindow() - popup.exec_() - #def undo_triggered(self): - # Call the EditorFrameView's triggerUndo method - #self.EditorFrameView.triggerUndo() - -class TablePopupWindow(QDialog): - def __init__(self): - super().__init__() - '''self.setWindowTitle("Popup Window") - layout = QVBoxLayout() - label = QLabel("This is a popup window.") - layout.addWidget(label) - self.setLayout(layout)''' - self.setWindowTitle("Table Configuration") - self.layout = QVBoxLayout() - - self.rows_input = QLineEdit(self) - self.rows_input.setPlaceholderText("Enter number of rows:") - self.layout.addWidget(self.rows_input) - - self.cols_input = QLineEdit(self) - colNum = self.cols_input.setPlaceholderText("Enter number of columns:") - self.layout.addWidget(self.cols_input) - - create_table_button = QPushButton("Create Table") - self.layout.addWidget(create_table_button) - create_table_button.clicked.connect(self.accept) - #create error message if no data is entered or if number of rows or columns are < 1 - - cancel_button = QPushButton("Cancel") - cancel_button.clicked.connect(self.reject) - self.setLayout(self.layout) - - def get_table_data(self): - rows_input = self.rows_input.text() - cols_input = self.cols_input.text() - return rows_input, cols_input - - def create_table(self): - print("table") - #row_num = int(self.rows_input.text()) - #col_num = int(self.cols_input.text()) - #self.EditorFrameView.add_table_action(row_num, col_num) + editorSignalsInstance.widgetAttributeChanged.emit(draggableContainer) + diff --git a/Widgets/Table.py b/Widgets/Table.py index 4b3fe13..4d7768f 100644 --- a/Widgets/Table.py +++ b/Widgets/Table.py @@ -2,7 +2,6 @@ from PySide6.QtGui import * from PySide6.QtWidgets import * - class TableWidget(QWidget): def __init__(self, x, y, w, h, rows, cols): super(TableWidget, self).__init__() @@ -43,9 +42,11 @@ def addCol(self): @staticmethod def new(clickPos: QPoint): - #dialog = table - #if - return TableWidget(clickPos.x(), clickPos.y(), 200, 200, 2, 2) + dialog = TablePopupWindow() + if dialog.exec_() == QDialog.Accepted: + rows_input, cols_input = dialog.get_table_data() + print(f"rows input is {rows_input} cols_input is {cols_input}") + return TableWidget(clickPos.x(), clickPos.y(), 200, 200, int(rows_input), int(cols_input)) def customMenuItems(self): addRow = QAction("Add Row", self) @@ -109,12 +110,16 @@ def __init__(self): colNum = self.cols_input.setPlaceholderText("Enter number of columns:") self.layout.addWidget(self.cols_input) - create_table_button = QPushButton("Create Table", self) - self.layout.addWidget(self.create_button) - #create error message if no data is entered or if number of rows or columns are < 1 + create_table_button = QPushButton("Create Table") + self.layout.addWidget(create_table_button) create_table_button.clicked.connect(self.accept) + #create error message if no data is entered or if number of rows or columns are < 1 + cancel_button = QPushButton("Cancel") + self.layout.addWidget(cancel_button) cancel_button.clicked.connect(self.reject) + + self.setLayout(self.layout) def get_table_data(self): @@ -126,4 +131,4 @@ def create_table(self): print("table") #row_num = int(self.rows_input.text()) #col_num = int(self.cols_input.text()) - #self.EditorFrameView.add_table_action(row_num, col_num) \ No newline at end of file + #self.EditorFrameView.add_table_action(row_num, col_num) From dcd5de27054d1eeb91c0eff27a90475010e611e4 Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Fri, 3 Nov 2023 12:45:01 -0500 Subject: [PATCH 017/127] Toolbar table functionality added Now you can create a table with a custom size. No error handling done yet --- Modules/BuildUI.py | 3 +-- Views/EditorFrameView.py | 6 +++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index d2152e1..a463195 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -148,8 +148,7 @@ def build_toolbar(editor): underline = build_action(toolbar, 'assets/icons/underline.svg', "Underline", "Underline", True) #underline.toggled.connect(lambda x: editor.childWidget. setFontUnderlineCustom(True if x else False)) table = build_action(toolbar, 'assets/icons/svg_table', "Create Table", "Create Table", False) - table.triggered.connect(EditorFrameView.add_table_action) - #table.triggered.connect(EditorFrameView.add_table_action) + table.triggered.connect(editor.frameView.add_table_action) hyperlink = build_action(toolbar, 'assets/icons/svg_hyperlink', "Hyperlink", "Hyperlink", False) editor.action1 = QAction('Action 1', editor) diff --git a/Views/EditorFrameView.py b/Views/EditorFrameView.py index e1434fe..0ef5c4d 100644 --- a/Views/EditorFrameView.py +++ b/Views/EditorFrameView.py @@ -44,9 +44,9 @@ def __init__(self, editor): self.installEventFilter(self.multiselector) # Undo setup - self.shortcut = QShortcut(QKeySequence("Ctrl+Z"), self) - self.shortcut.setContext(Qt.ApplicationShortcut) - self.shortcut.activated.connect(self.triggerUndo) + #self.shortcut = QShortcut(QKeySequence("Ctrl+Z"), self) + #self.shortcut.setContext(Qt.ApplicationShortcut) + #self.shortcut.activated.connect(self.triggerUndo) print("BUILT FRAMEVIEW") From c003263df66b40d866eda0a5fc7ea05fe0d7e2a5 Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Fri, 3 Nov 2023 14:10:38 -0500 Subject: [PATCH 018/127] Added bullets and italics italics currently selects all containers and italicize --- Assets/icons/svg_bullets.svg | 19 +++++++++++++++++++ Modules/BuildUI.py | 15 ++++++++++----- Views/EditorFrameView.py | 27 ++++++++++++++------------- Widgets/Textbox.py | 16 ++++++++++++---- 4 files changed, 55 insertions(+), 22 deletions(-) create mode 100644 Assets/icons/svg_bullets.svg diff --git a/Assets/icons/svg_bullets.svg b/Assets/icons/svg_bullets.svg new file mode 100644 index 0000000..fb527c0 --- /dev/null +++ b/Assets/icons/svg_bullets.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index a463195..bb12ef0 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -59,6 +59,7 @@ def build_ui(editor): rightSideLayout.setStretch(0, 0) rightSideLayout.setStretch(1, 1) + # Add appropriate widgets (ideally just view controllers) to their layouts leftSideLayout.addWidget(editor.notebookTitleView, 0) leftSideLayout.addWidget(editor.pageView, 1) # Page view has max stretch factor @@ -138,18 +139,22 @@ def build_toolbar(editor): bold = build_action(toolbar, 'assets/icons/bold', "Bold", "Bold", True) #bold.toggled.connect(editor.frameView.toggleBold) #bold.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontBold, None)) - bold.triggered.connect(editor.frameView.add_table_action) + #bold.triggered.connect(editor.frameView.add_table_action) #bold.toggled.connect(lambda x: editor.selected.setFontWeight(700 if x else 500)) italic = build_action(toolbar, 'assets/icons/italic.svg', "Italic", "Italic", True) - #italic.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(setFontItalicCustom), None) + italic.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontItalic, None)) underline = build_action(toolbar, 'assets/icons/underline.svg', "Underline", "Underline", True) #underline.toggled.connect(lambda x: editor.childWidget. setFontUnderlineCustom(True if x else False)) table = build_action(toolbar, 'assets/icons/svg_table', "Create Table", "Create Table", False) - table.triggered.connect(editor.frameView.add_table_action) + table.triggered.connect(editor.frameView.toolbar_table) hyperlink = build_action(toolbar, 'assets/icons/svg_hyperlink', "Hyperlink", "Hyperlink", False) + hyperlink.triggered.connect(editor.frameView.toolbar_hyperlink) + bullets = build_action(toolbar, 'assets/icons/svg_bullets', "Hyperlink", "Hyperlink", False) + + editor.action1 = QAction('Action 1', editor) #editor.action1.triggered.connect(EditorFrameView.slot_action1) @@ -160,7 +165,7 @@ def build_toolbar(editor): toolbar.addAction(editor.action2) #editor.button = QPushButton("Click Me", editor) #editor.button.clicked.connect(editor.slot_button_click) - + #toolbar.addActions([undo, redo]) toolbar.addSeparator() @@ -169,7 +174,7 @@ def build_toolbar(editor): toolbar.addSeparator() toolbar.addActions([bgColor, fontColor, bold, italic, underline]) toolbar.addSeparator() - toolbar.addActions([table, hyperlink]) + toolbar.addActions([table, hyperlink, bullets]) def toggle_bold(self): self.is_bold = not self.is_bold diff --git a/Views/EditorFrameView.py b/Views/EditorFrameView.py index 747bc13..ba88afe 100644 --- a/Views/EditorFrameView.py +++ b/Views/EditorFrameView.py @@ -161,50 +161,51 @@ def mouseReleaseEvent(self, event): print("CREATE DRAGGABLE CONTAINER") self.newWidgetOnSection(TextboxWidget, event.pos()) - def mousePressEvent(self, e): + def mousePressEvent(self, event): print("EDITORFRAME MOUSEPRESS") editor = self.editor # Open context menu on right click - if e.buttons() == Qt.RightButton: + if event.buttons() == Qt.RightButton: frame_menu = QMenu(self) paste = QAction("Paste", editor) - paste.triggered.connect(lambda: self.pasteWidget(e.pos())) + paste.triggered.connect(lambda: self.pasteWidget(event.pos())) frame_menu.addAction(paste) add_image = QAction("Add Image", self) - add_image.triggered.connect(lambda: self.newWidgetOnSection(ImageWidget, e.pos())) + add_image.triggered.connect(lambda: self.newWidgetOnSection(ImageWidget, event.pos())) frame_menu.addAction(add_image) add_table = QAction("Add Table", editor) - add_table.triggered.connect(lambda: self.newWidgetOnSection(TableWidget, e.pos())) + add_table.triggered.connect(lambda: self.newWidgetOnSection(TableWidget, event.pos())) #add_table.triggered.connect(self.show_table_popup) frame_menu.addAction(add_table) take_screensnip = QAction("Snip Screen", editor) - take_screensnip.triggered.connect(lambda: self.snipScreen(e.pos())) + take_screensnip.triggered.connect(lambda: self.snipScreen(event.pos())) frame_menu.addAction(take_screensnip) add_custom_widget = QAction("Add Custom Widget", editor) - add_custom_widget.triggered.connect(lambda: self.addCustomWidget(e)) + add_custom_widget.triggered.connect(lambda: self.addCustomWidget(event)) frame_menu.addAction(add_custom_widget) -<<<<<<< HEAD - frame_menu.exec(e.globalPos()) -======= insert_Link = QAction("Insert Link", editor) insert_Link.triggered.connect(lambda: self.newWidgetOnSection(LinkWidget,event.pos())) frame_menu.addAction(insert_Link) frame_menu.exec(event.globalPos()) ->>>>>>> main - def add_table_action(self): - print("add_table_action pressed") + def toolbar_table(self): + print("toolbar_table pressed") clickPos = QPoint(0, 0) self.newWidgetOnSection(TableWidget, clickPos) + def toolbar_hyperlink(self): + print("toolbar_hyperlink pressed") + clickPos = QPoint(0, 0) + self.newWidgetOnSection(LinkWidget, clickPos) + def addCustomWidget(self, e): def getCustomWidgets(): customWidgets = {} # dict where entries are {name: class} diff --git a/Widgets/Textbox.py b/Widgets/Textbox.py index 4c8e32e..fa83bf2 100644 --- a/Widgets/Textbox.py +++ b/Widgets/Textbox.py @@ -69,10 +69,9 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): bold.toggled.connect(lambda x: self.setFontWeightCustom(700 if x else 500)) italic = build_action(toolbarBottom, 'assets/icons/svg_font_italic', "Italic", "Italic", True) - def italicToggled(): - print("Italic Toggled") - italic.toggled.connect(lambda x: self.setFontItalicCustom(True if x else False)) - italicToggled() + print("Italic Toggled from right click context menu") + italic.toggled.connect(lambda x: self.setFontItalicCustom(True if x else False)) + underline = build_action(toolbarBottom, 'assets/icons/svg_font_underline', "Underline", "Underline", True) underline.toggled.connect(lambda x: self.setFontUnderlineCustom(True if x else False)) @@ -152,3 +151,12 @@ def slot_action2(self): font = QFont() font.setItalic(True) self.setFont(font) + + def changeFontSizeEvent(self, weight): + print("changeFontSizeEvent Called") + self.setFontWeightCustom(weight) + + def changeFontItalicEvent(self): + print("changeFontItalicEvent Called") + #somehow highlights all boxes + self.setFontItalicCustom(lambda x: True if x else False) \ No newline at end of file From 6993f2035105eb062e9c4ded972442485cd0a412 Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Sat, 4 Nov 2023 13:14:30 -0500 Subject: [PATCH 019/127] Bold, Italics, and Underline for Toolbar Added functionality to: -bold -underline -italics --- Models/DraggableContainer.py | 1 - Modules/BuildUI.py | 6 ++-- Widgets/Textbox.py | 54 ++++++++++++++++++++++++++++++++++-- 3 files changed, 54 insertions(+), 7 deletions(-) diff --git a/Models/DraggableContainer.py b/Models/DraggableContainer.py index e57bec6..f935762 100644 --- a/Models/DraggableContainer.py +++ b/Models/DraggableContainer.py @@ -309,4 +309,3 @@ def widgetAttributeChanged(self, changedWidgetAttribute, value): if hasattr(cw, "changeBackgroundColorEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.BackgroundColor): cw.changeBackgroundColorEvent(value) - diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index bb12ef0..692997a 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -137,8 +137,7 @@ def build_toolbar(editor): fontColor.triggered.connect(lambda: openGetColorDialog(purpose = "font")) bold = build_action(toolbar, 'assets/icons/bold', "Bold", "Bold", True) - #bold.toggled.connect(editor.frameView.toggleBold) - #bold.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontBold, None)) + bold.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontBold, None)) #bold.triggered.connect(editor.frameView.add_table_action) #bold.toggled.connect(lambda x: editor.selected.setFontWeight(700 if x else 500)) @@ -147,7 +146,8 @@ def build_toolbar(editor): italic.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontItalic, None)) underline = build_action(toolbar, 'assets/icons/underline.svg', "Underline", "Underline", True) - #underline.toggled.connect(lambda x: editor.childWidget. setFontUnderlineCustom(True if x else False)) + underline.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontUnderline, None)) + table = build_action(toolbar, 'assets/icons/svg_table', "Create Table", "Create Table", False) table.triggered.connect(editor.frameView.toolbar_table) hyperlink = build_action(toolbar, 'assets/icons/svg_hyperlink', "Hyperlink", "Hyperlink", False) diff --git a/Widgets/Textbox.py b/Widgets/Textbox.py index fa83bf2..a961f89 100644 --- a/Widgets/Textbox.py +++ b/Widgets/Textbox.py @@ -69,7 +69,6 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): bold.toggled.connect(lambda x: self.setFontWeightCustom(700 if x else 500)) italic = build_action(toolbarBottom, 'assets/icons/svg_font_italic', "Italic", "Italic", True) - print("Italic Toggled from right click context menu") italic.toggled.connect(lambda x: self.setFontItalicCustom(True if x else False)) @@ -156,7 +155,56 @@ def changeFontSizeEvent(self, weight): print("changeFontSizeEvent Called") self.setFontWeightCustom(weight) + #for communicating the signal editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontItalic, None) def changeFontItalicEvent(self): - print("changeFontItalicEvent Called") #somehow highlights all boxes - self.setFontItalicCustom(lambda x: True if x else False) \ No newline at end of file + cursor = self.textCursor() + current_format = cursor.charFormat() + + #Checks if currently selected text is italics + is_italic = current_format.fontItalic() + + #toggles the italics + current_format.setFontItalic(not is_italic) + + #Apply modified format to selected text + cursor.setCharFormat(current_format) + + #Update text cursor with modified format + self.setTextCursor(cursor) + + def changeFontBoldEvent(self): + #somehow highlights all boxes + cursor = self.textCursor() + current_format = cursor.charFormat() + + #Checks if currently selected text is bold + is_bold = current_format.fontWeight() == 700 + + #toggles the italics + if is_bold: + current_format.setFontWeight(500) + else: + current_format.setFontWeight(700) + #Apply modified format to selected text + cursor.setCharFormat(current_format) + + #Update text cursor with modified format + self.setTextCursor(cursor) + + def changeFontUnderlineEvent(self): + #somehow highlights all boxes + cursor = self.textCursor() + current_format = cursor.charFormat() + + #Checks if currently selected text is bold + is_underlined = current_format.fontUnderline() + + #toggles the underline + current_format.setFontUnderline(not is_underlined) + + #Apply modified format to selected text + cursor.setCharFormat(current_format) + + #Update text cursor with modified format + self.setTextCursor(cursor) \ No newline at end of file From 31c66821b2e61758319ebefb13ae1846a152e9f2 Mon Sep 17 00:00:00 2001 From: ldeltastreaml <70774713+ldeltastreaml@users.noreply.github.com> Date: Sat, 4 Nov 2023 15:29:47 -0500 Subject: [PATCH 020/127] Update requirements.txt --- requirements.txt | Bin 276 -> 142 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/requirements.txt b/requirements.txt index f573bd8c25c581a2732c014309842490ca55a622..fbba2f85904daaf9ee772d5c1ba077b2b5df161f 100644 GIT binary patch literal 142 zcmaFAdw*VOZb7A;t)ZTgiJmbpSAIciUUHdkL1jrsex9AJiJrNhfu6Y$FIPZjPELNg zovo#wsh$ClTN#|0l4@pWYlgztbxcXg&nw0db}cSW%`3@F%t1&MXJjVjXQ$>N%m4sR CcPZZh literal 276 zcma)%!3x4K5JcZu@KY*Uwc^2p2k!;HK&@a=Qz6yj&sQgN6cHJch0NRC$*T|CxpL#l zN}4btXQq3~kO7UHBY^`CGE*%ly#~{XTj-2kb9a=~T%?B1%u?RmOqy3}&sIdGsfGRG jho7+)S$SXlgWeFOl(*H6ol<=3iuys#UQ^FzKXbeRcKs<; From 8e5164e8ba52ba5c57fcde74f111eae93eac0f8e Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Sat, 4 Nov 2023 20:43:39 -0500 Subject: [PATCH 021/127] Toolbar Changes Added and included functionality to these things from toolbar: - background color - textbox color - font size - font family refactored right click context menu to use Change___Event functions. --- Assets/icons/svg_question.svg | 26 ++++++++++ Assets/icons/svg_textboxColor.svg | 14 ++++++ Models/DraggableContainer.py | 5 ++ Models/Editor.py | 1 - Modules/BuildUI.py | 77 +++++++--------------------- Modules/EditorSignals.py | 1 + Views/EditorFrameView.py | 26 +--------- Widgets/Textbox.py | 84 ++++++++++++++++++++++++++++--- 8 files changed, 143 insertions(+), 91 deletions(-) create mode 100644 Assets/icons/svg_question.svg create mode 100644 Assets/icons/svg_textboxColor.svg diff --git a/Assets/icons/svg_question.svg b/Assets/icons/svg_question.svg new file mode 100644 index 0000000..f0e4806 --- /dev/null +++ b/Assets/icons/svg_question.svg @@ -0,0 +1,26 @@ + + + + + + + + + + \ No newline at end of file diff --git a/Assets/icons/svg_textboxColor.svg b/Assets/icons/svg_textboxColor.svg new file mode 100644 index 0000000..1cc087a --- /dev/null +++ b/Assets/icons/svg_textboxColor.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/Models/DraggableContainer.py b/Models/DraggableContainer.py index f935762..a044722 100644 --- a/Models/DraggableContainer.py +++ b/Models/DraggableContainer.py @@ -54,6 +54,8 @@ def __init__(self, childWidget, editorFrame): if hasattr(self.childWidget, "newGeometryEvent"): self.newGeometry.connect(childWidget.newGeometryEvent) editorSignalsInstance.widgetAttributeChanged.connect(self.widgetAttributeChanged) + + def setChildWidget(self, childWidget): if childWidget: self.childWidget = childWidget @@ -309,3 +311,6 @@ def widgetAttributeChanged(self, changedWidgetAttribute, value): if hasattr(cw, "changeBackgroundColorEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.BackgroundColor): cw.changeBackgroundColorEvent(value) + + if hasattr(cw, "changeTextboxColorEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.TextboxColor): + cw.changeTextboxColorEvent(value) diff --git a/Models/Editor.py b/Models/Editor.py index 89101c8..fdac0ee 100644 --- a/Models/Editor.py +++ b/Models/Editor.py @@ -32,6 +32,5 @@ def __init__(self): self.setFocus() build_ui(self) - # def focusInEvent(self, event): # self.repaint() diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index 692997a..7efa84d 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -101,7 +101,10 @@ def build_menubar(editor): save_fileAs.setShortcut(QKeySequence.fromString('Ctrl+Shift+S')) save_fileAs.triggered.connect(lambda: saveAs(editor)) + add_widget = build_action(editor, 'assets/icons/svg_textboxColor', 'Add Custom Widget', 'Add Custom Widget', False) + file.addActions([new_file, open_file, save_file, save_fileAs]) + plugins.addActions([add_widget]) def build_toolbar(editor): toolbar = QToolBar() @@ -114,7 +117,7 @@ def build_toolbar(editor): spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) toolbar_undo = build_action(toolbar, 'assets/icons/svg_undo', "undo", "undo", False) - #toolbar_undo.triggered.connect(editor.frameView.triggerUndo) + toolbar_undo.triggered.connect(editor.frameView.triggerUndo) redo = build_action(toolbar, 'assets/icons/svg_redo', "redo", "redo", False) @@ -122,25 +125,25 @@ def build_toolbar(editor): font = QFontComboBox() - font.currentFontChanged.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Font, font.currentFont())) + font.currentFontChanged.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Font, font.currentFont().family())) size = QComboBox() size.addItems([str(fs) for fs in FONT_SIZES]) size.currentIndexChanged.connect(lambda x: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontSize, int(size.currentText()))) - bgColor = build_action(toolbar, 'assets/icons/svg_font_bucket', "Text Box Color", "Text Box Color", False) - bgColor.triggered.connect(lambda: openGetColorDialog(purpose = "background")) + bgColor = build_action(toolbar, 'assets/icons/svg_font_bucket', "Background Color", "Background Color", False) + #bgColor.triggered.connect(lambda: openGetColorDialog(purpose = "background")) + bgColor.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.BackgroundColor, QColorDialog.getColor())) + textboxColor = build_action(toolbar, 'assets/icons/svg_textboxColor', "Text Box Color", "Text Box Color", False) + textboxColor.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.TextboxColor, QColorDialog.getColor())) - + #defines font color icon appearance and settings fontColor = build_action(toolbar, 'assets/icons/svg_font_color', "Font Color", "Font Color", False) fontColor.triggered.connect(lambda: openGetColorDialog(purpose = "font")) bold = build_action(toolbar, 'assets/icons/bold', "Bold", "Bold", True) bold.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontBold, None)) - #bold.triggered.connect(editor.frameView.add_table_action) - - #bold.toggled.connect(lambda x: editor.selected.setFontWeight(700 if x else 500)) italic = build_action(toolbar, 'assets/icons/italic.svg', "Italic", "Italic", True) italic.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontItalic, None)) @@ -150,12 +153,14 @@ def build_toolbar(editor): table = build_action(toolbar, 'assets/icons/svg_table', "Create Table", "Create Table", False) table.triggered.connect(editor.frameView.toolbar_table) + hyperlink = build_action(toolbar, 'assets/icons/svg_hyperlink', "Hyperlink", "Hyperlink", False) hyperlink.triggered.connect(editor.frameView.toolbar_hyperlink) - bullets = build_action(toolbar, 'assets/icons/svg_bullets', "Hyperlink", "Hyperlink", False) + bullets = build_action(toolbar, 'assets/icons/svg_bullets', "Hyperlink", "Hyperlink", False) + ''' editor.action1 = QAction('Action 1', editor) #editor.action1.triggered.connect(EditorFrameView.slot_action1) toolbar.addAction(editor.action1) @@ -164,23 +169,18 @@ def build_toolbar(editor): #editor.action2.triggered.connect(show_popup) toolbar.addAction(editor.action2) #editor.button = QPushButton("Click Me", editor) - #editor.button.clicked.connect(editor.slot_button_click) + #editor.button.clicked.connect(editor.slot_button_click)''' - #toolbar.addActions([undo, redo]) + toolbar.addActions([toolbar_undo, redo]) toolbar.addSeparator() toolbar.addWidget(font) toolbar.addWidget(size) toolbar.addSeparator() - toolbar.addActions([bgColor, fontColor, bold, italic, underline]) + toolbar.addActions([bgColor, textboxColor, fontColor, bold, italic, underline]) toolbar.addSeparator() toolbar.addActions([table, hyperlink, bullets]) -def toggle_bold(self): - self.is_bold = not self.is_bold - - font =self.text_edit - def openGetColorDialog(purpose): color = QColorDialog.getColor() if color.isValid(): @@ -193,45 +193,4 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): action = QAction(QIcon(icon_path), action_name, parent) action.setStatusTip(set_status_tip) action.setCheckable(set_checkable) - return action - -def build_test_toolbar(self): - editorFrameViewInstance = EditorFrameView(self) - - toolbar = QToolBar(self) - self.addToolBar(toolbar) - - exitAct = QAction(QIcon('assets/icons/underline.svg'), 'Exit', self) - exitAct.setShortcut('Ctrl+Q') - exitAct.triggered.connect(QApplication.instance().quit) - - self.toolbar = self.addToolBar('Exit') - self.toolbar.addAction(exitAct) - - #font_change - font_combo = QFontComboBox(self) - toolbar.addWidget(font_combo) - - bold = build_action(toolbar, 'assets/icons/bold', "Bold", "Bold", True) - bold.setShortcut('Ctrl+B') - bold.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.connect(self.widgetAttributeChangedEvent)) - - - toolbar.addAction(bold) - - undo_action = QAction("Undo", self) - undo_action.triggered.connect(self.frameView.triggerUndo) - - toolbar.addAction(undo_action) - - - -def change_font(self): - selected_font = self.sender().parent().widgetForAction(self.sender()).currentFont() - - self.text_edit.setFont(selected_font) - -def widgetAttributeChangedEvent(self, draggableContainer): - editorSignalsInstance.widgetAttributeChanged.emit(draggableContainer) - - + return action \ No newline at end of file diff --git a/Modules/EditorSignals.py b/Modules/EditorSignals.py index 97d3873..800999d 100644 --- a/Modules/EditorSignals.py +++ b/Modules/EditorSignals.py @@ -10,6 +10,7 @@ class ChangedWidgetAttribute(Enum): FontBold = 4 FontItalic = 5 FontUnderline = 6 + TextboxColor = 7 # Cant be statically typed because importing the classes causes circular imports diff --git a/Views/EditorFrameView.py b/Views/EditorFrameView.py index ba88afe..87d9f20 100644 --- a/Views/EditorFrameView.py +++ b/Views/EditorFrameView.py @@ -53,7 +53,7 @@ def __init__(self, editor): #self.shortcut.activated.connect(self.triggerUndo) print("BUILT FRAMEVIEW") - + def triggerUndo(self): print("triggerUndo Called") self.undoHandler.undo @@ -245,30 +245,6 @@ def mouseMoveEvent(self, e): # This event is only called after clicking down on else: self.multiselector.continueDrawingArea(e) - def toggleBold(self): - print ("TOGGLE BOLD") - dc = DraggableContainer() - cw = dc.childWidget - if(dc.hasFocus()): - cw.changeFontBoldEvent() - #editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontBold, ) - def slot_action1(self, item): print("Action 1 triggered") - -'''class PopupDialog(QDialog): - def __init__(self, name, parent): - super().__init__(parent) - self.resize(600, 300) - self.setWindowTitle("pop") - self.label = QLabel(name, self) - layout = QVBoxLayout() - layout.addWidget(QLabel("Test")) - ok_button = QPushButton("OK") - layout.addWidget(ok_button) - ok_button.clicked.connect(self.accept) - - self.setLayout(layout) - self.setWindowTitle("Table Creation") ''' - diff --git a/Widgets/Textbox.py b/Widgets/Textbox.py index a961f89..a42349d 100644 --- a/Widgets/Textbox.py +++ b/Widgets/Textbox.py @@ -14,10 +14,23 @@ def __init__(self, x, y, w = 15, h = 30, t = ''): self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) + #self.setSizePolicy(QSizePolicy) self.textChanged.connect(self.textChangedEvent) self.setStyleSheet('background-color: rgba(0, 0, 0, 0);') self.setTextColor('black') + + def eventFilter(self, obj, event): + if event.type() == QEvent.MouseButtonPress: + # A click occurred outside the QTextEdit + self.clearFocus() + cursor = self.textCursor() + cursor.clearSelection() + self.setTextCursor(cursor) + + return super().eventFilter(obj, event) + + def textChangedEvent(self): if len(self.toPlainText()) < 2: self.resize(100, 100) @@ -78,12 +91,15 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): fontColor = build_action(toolbarBottom, 'assets/icons/svg_font_color', "Font Color", "Font Color", False) fontColor.triggered.connect(lambda: self.setTextColorCustom(QColorDialog.getColor())) - bgColor = build_action(toolbarBottom, 'assets/icons/svg_font_bucket', "Text Box Color", "Text Box Color", False) - bgColor.triggered.connect(lambda: self.setBackgroundColor(QColorDialog.getColor())) + bgColor = build_action(toolbarBottom, 'assets/icons/svg_font_bucket', "Background Color", "Background Color", False) + #bgColor.triggered.connect(lambda: self.setBackgroundColor(QColorDialog.getColor())) + bgColor.triggered.connect(lambda: self.changeBackgroundColorEvent(QColorDialog.getColor())) + textboxColor = build_action(toolbarBottom, 'assets/icons/svg_textboxColor', "Background Color", "Background Color", False) + textboxColor.triggered.connect(lambda: self.changeTextboxColorEvent(QColorDialog.getColor())) toolbarTop.addWidget(font) toolbarTop.addWidget(size) - toolbarBottom.addActions([bold, italic, underline, fontColor, bgColor]) + toolbarBottom.addActions([bold, italic, underline, fontColor, bgColor, textboxColor]) qwaTop = QWidgetAction(self) qwaTop.setDefaultWidget(toolbarTop) qwaBottom = QWidgetAction(self) @@ -121,7 +137,6 @@ def setBackgroundColor(self, color: QColor): rgb = color.getRgb() self.setStyleSheet(f'background-color: rgb({rgb[0]}, {rgb[1]}, {rgb[2]});') - # If no text is selected, apply to all, else apply to selection def applyToAllIfNoSelection(self, func): if len(self.textCursor().selectedText()) != 0: @@ -199,7 +214,7 @@ def changeFontUnderlineEvent(self): #Checks if currently selected text is bold is_underlined = current_format.fontUnderline() - + #toggles the underline current_format.setFontUnderline(not is_underlined) @@ -207,4 +222,61 @@ def changeFontUnderlineEvent(self): cursor.setCharFormat(current_format) #Update text cursor with modified format - self.setTextCursor(cursor) \ No newline at end of file + self.setTextCursor(cursor) + + def changeFontSizeEvent(self, value): + #todo: when textbox is in focus, font size on toolbar should match the font size of the text + + cursor = self.textCursor() + current_format = cursor.charFormat() + + current_format.setFontPointSize(value) + cursor.setCharFormat(current_format) + + self.setTextCursor(cursor) + + def changeFontEvent(self, font_style): + cursor = self.textCursor() + current_format = cursor.charFormat() + current_format.setFont(font_style) + + cursor.setCharFormat(current_format) + + + self.setTextCursor(cursor) + + def changeFontColorEvent(self, new_font_color): + cursor = self.textCursor() + current_format = cursor.charFormat() + + color = QColor(new_font_color) + current_format.setForeground(color) + + cursor.setCharFormat(current_format) + + #to not get stuck on highlighted text + self.deselectText() + + def changeBackgroundColorEvent(self, color: QColor): + rgb = color.getRgb() + self.setStyleSheet(f'background-color: rgb({rgb[0]}, {rgb[1]}, {rgb[2]});') + self.deselectText() + + def changeTextboxColorEvent(self, new_bg_color): + cursor = self.textCursor() + current_format = cursor.charFormat() + + color = QColor(new_bg_color) + current_format.setBackground(color) + + cursor.setCharFormat(current_format) + self.deselectText() + + #self.setTextCursor(cursor) + def deselectText(self): + cursor = self.textCursor() + cursor.clearSelection() + self.setTextCursor(cursor) + + + \ No newline at end of file From 2cb252e01af5a4c461bc8c9e2311332ccd5d0408 Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Sun, 5 Nov 2023 17:41:16 -0600 Subject: [PATCH 022/127] Included comments, toolbar bug fixes, and changed bullet list connection - Bullet list now uses signals - fixed background color connecting to all draggable containers - made draggable containers only pass to child if it is in focus - added comments in draggablecontainer.py with explanations on how to connect signals. - includes descriptions on toolbar functions in textbox --- Models/DraggableContainer.py | 44 +++++++++++++++++++++--------------- Modules/BuildUI.py | 31 ++++++++++++++----------- Modules/EditorSignals.py | 3 +++ Modules/Undo.py | 2 ++ Widgets/Textbox.py | 30 ++++++++++++++++-------- 5 files changed, 69 insertions(+), 41 deletions(-) diff --git a/Models/DraggableContainer.py b/Models/DraggableContainer.py index a044722..25f79a5 100644 --- a/Models/DraggableContainer.py +++ b/Models/DraggableContainer.py @@ -286,31 +286,39 @@ def mouseMoveEvent(self, e: QMouseEvent): self.parentWidget().repaint() self.newGeometry.emit(self.geometry()) - # Pass the e to the child widget if this container is focuesd, and childwidget implements the method to receive it + # Pass the e to the child widget if this container is focused, and childwidget implements the method to receive it + # Uses signals to pass to draggable container, which then checks if child has the function, then calls the function. + # Look at toolbar in BuildUI.py to see examples + # example signal that doesn't have a value: 'italic.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontItalic, None))' + # example signal with a value: 'font_family.currentFontChanged.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Font, font_family.currentFont().family()))' + # When adding a function to a child widget, use 'if self.hasFocus():' to ensure the function applies only to the focused widget. Else it will apply to all widgets of the same type def widgetAttributeChanged(self, changedWidgetAttribute, value): - cw = self.childWidget + child_widget = self.childWidget + if self.hasFocus() or child_widget.hasFocus(): + if hasattr(child_widget, "changeFontSizeEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.FontSize): + child_widget.changeFontSizeEvent(value) - if hasattr(cw, "changeFontSizeEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.FontSize): - cw.changeFontSizeEvent(value) + if hasattr(child_widget, "changeFontBoldEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.FontBold): + child_widget.changeFontBoldEvent() - if hasattr(cw, "changeFontBoldEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.FontBold): - cw.changeFontBoldEvent() + if hasattr(child_widget, "changeFontItalicEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.FontItalic): + child_widget.changeFontItalicEvent() - if hasattr(cw, "changeFontItalicEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.FontItalic): - cw.changeFontItalicEvent() + if hasattr(child_widget, "changeFontUnderlineEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.FontUnderline): + child_widget.changeFontUnderlineEvent() - if hasattr(cw, "changeFontUnderlineEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.FontUnderline): - cw.changeFontUnderlineEvent() + if hasattr(child_widget, "changeFontEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.Font): + child_widget.changeFontEvent(value) - if hasattr(cw, "changeFontEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.Font): - cw.changeFontEvent(value) + if hasattr(child_widget, "changeFontColorEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.FontColor): + child_widget.changeFontColorEvent(value) - if hasattr(cw, "changeFontColorEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.FontColor): - cw.changeFontColorEvent(value) + if hasattr(child_widget, "changeBackgroundColorEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.BackgroundColor): + child_widget.changeBackgroundColorEvent(value) - if hasattr(cw, "changeBackgroundColorEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.BackgroundColor): - cw.changeBackgroundColorEvent(value) + if hasattr(child_widget, "changeTextboxColorEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.TextboxColor): + child_widget.changeTextboxColorEvent(value) - if hasattr(cw, "changeTextboxColorEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.TextboxColor): - cw.changeTextboxColorEvent(value) + if hasattr(child_widget, "changeBulletEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.Bullet): + child_widget.changeBulletEvent() diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index 7efa84d..afd416c 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -101,7 +101,7 @@ def build_menubar(editor): save_fileAs.setShortcut(QKeySequence.fromString('Ctrl+Shift+S')) save_fileAs.triggered.connect(lambda: saveAs(editor)) - add_widget = build_action(editor, 'assets/icons/svg_textboxColor', 'Add Custom Widget', 'Add Custom Widget', False) + add_widget = build_action(editor, 'assets/icons/svg_question', 'Add Custom Widget', 'Add Custom Widget', False) file.addActions([new_file, open_file, save_file, save_fileAs]) plugins.addActions([add_widget]) @@ -124,19 +124,24 @@ def build_toolbar(editor): - font = QFontComboBox() - font.currentFontChanged.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Font, font.currentFont().family())) + font_family = QFontComboBox() + font_family.currentFontChanged.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Font, font_family.currentFont().family())) - size = QComboBox() - size.addItems([str(fs) for fs in FONT_SIZES]) - size.currentIndexChanged.connect(lambda x: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontSize, int(size.currentText()))) + font_size = QComboBox() + font_size.addItems([str(fs) for fs in FONT_SIZES]) + font_size.currentIndexChanged.connect(lambda x: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontSize, int(font_size.currentText()))) + + #current issues: + # - Alternates between working and not working + # - Textboxes do not remember settings like if font is toggled or current font size bgColor = build_action(toolbar, 'assets/icons/svg_font_bucket', "Background Color", "Background Color", False) #bgColor.triggered.connect(lambda: openGetColorDialog(purpose = "background")) + #current bug, alternates between activating and not working when using bgColor.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.BackgroundColor, QColorDialog.getColor())) - textboxColor = build_action(toolbar, 'assets/icons/svg_textboxColor', "Text Box Color", "Text Box Color", False) - textboxColor.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.TextboxColor, QColorDialog.getColor())) + textboxColor = build_action(toolbar, 'assets/icons/svg_textboxColor', "Text Box Color", "Text Box Color", True) + textboxColor.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.TextboxColor, QColorDialog.getColor())) #defines font color icon appearance and settings fontColor = build_action(toolbar, 'assets/icons/svg_font_color', "Font Color", "Font Color", False) @@ -157,8 +162,8 @@ def build_toolbar(editor): hyperlink = build_action(toolbar, 'assets/icons/svg_hyperlink', "Hyperlink", "Hyperlink", False) hyperlink.triggered.connect(editor.frameView.toolbar_hyperlink) - bullets = build_action(toolbar, 'assets/icons/svg_bullets', "Hyperlink", "Hyperlink", False) - + bullet = build_action(toolbar, 'assets/icons/svg_bullets', "Bullet List", "Bullet List", False) + bullet.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Bullet, None)) ''' editor.action1 = QAction('Action 1', editor) @@ -174,12 +179,12 @@ def build_toolbar(editor): toolbar.addActions([toolbar_undo, redo]) toolbar.addSeparator() - toolbar.addWidget(font) - toolbar.addWidget(size) + toolbar.addWidget(font_family) + toolbar.addWidget(font_size) toolbar.addSeparator() toolbar.addActions([bgColor, textboxColor, fontColor, bold, italic, underline]) toolbar.addSeparator() - toolbar.addActions([table, hyperlink, bullets]) + toolbar.addActions([table, hyperlink, bullet]) def openGetColorDialog(purpose): color = QColorDialog.getColor() diff --git a/Modules/EditorSignals.py b/Modules/EditorSignals.py index 800999d..885141d 100644 --- a/Modules/EditorSignals.py +++ b/Modules/EditorSignals.py @@ -3,6 +3,8 @@ from enum import Enum class ChangedWidgetAttribute(Enum): + # Used for unique signals + # Add variable to create a unique signal BackgroundColor = 0 FontColor = 1 Font = 2 @@ -11,6 +13,7 @@ class ChangedWidgetAttribute(Enum): FontItalic = 5 FontUnderline = 6 TextboxColor = 7 + Bullet = 8 # Cant be statically typed because importing the classes causes circular imports diff --git a/Modules/Undo.py b/Modules/Undo.py index d44eefc..51b7e55 100644 --- a/Modules/Undo.py +++ b/Modules/Undo.py @@ -4,6 +4,8 @@ from Modules.EditorSignals import editorSignalsInstance import os + +#current version of undo does not work. When using ctrl+z in textboxes, it uses the QTextEdit default settings for ctrl+z(undo) and ctrl+y(redo) to make it appear as if undo does work class UndoActionCreate: def __init__(self, draggableContainer): self.draggableContainer = draggableContainer diff --git a/Widgets/Textbox.py b/Widgets/Textbox.py index a42349d..f975ec1 100644 --- a/Widgets/Textbox.py +++ b/Widgets/Textbox.py @@ -14,7 +14,6 @@ def __init__(self, x, y, w = 15, h = 30, t = ''): self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) - #self.setSizePolicy(QSizePolicy) self.textChanged.connect(self.textChangedEvent) self.setStyleSheet('background-color: rgba(0, 0, 0, 0);') self.setTextColor('black') @@ -171,8 +170,11 @@ def changeFontSizeEvent(self, weight): self.setFontWeightCustom(weight) #for communicating the signal editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontItalic, None) + #current issue for Event Functions: Only affects highlighted + + def changeFontItalicEvent(self): - #somehow highlights all boxes + cursor = self.textCursor() current_format = cursor.charFormat() @@ -189,7 +191,6 @@ def changeFontItalicEvent(self): self.setTextCursor(cursor) def changeFontBoldEvent(self): - #somehow highlights all boxes cursor = self.textCursor() current_format = cursor.charFormat() @@ -208,7 +209,6 @@ def changeFontBoldEvent(self): self.setTextCursor(cursor) def changeFontUnderlineEvent(self): - #somehow highlights all boxes cursor = self.textCursor() current_format = cursor.charFormat() @@ -226,7 +226,6 @@ def changeFontUnderlineEvent(self): def changeFontSizeEvent(self, value): #todo: when textbox is in focus, font size on toolbar should match the font size of the text - cursor = self.textCursor() current_format = cursor.charFormat() @@ -245,7 +244,9 @@ def changeFontEvent(self, font_style): self.setTextCursor(cursor) + # Changes font text color def changeFontColorEvent(self, new_font_color): + cursor = self.textCursor() current_format = cursor.charFormat() @@ -256,12 +257,16 @@ def changeFontColorEvent(self, new_font_color): #to not get stuck on highlighted text self.deselectText() + #self.setTextCursor(cursor) + # Changes color of whole background def changeBackgroundColorEvent(self, color: QColor): + #if self.hasFocus(): rgb = color.getRgb() self.setStyleSheet(f'background-color: rgb({rgb[0]}, {rgb[1]}, {rgb[2]});') self.deselectText() - + + # Changes textbox background color def changeTextboxColorEvent(self, new_bg_color): cursor = self.textCursor() current_format = cursor.charFormat() @@ -272,11 +277,16 @@ def changeTextboxColorEvent(self, new_bg_color): cursor.setCharFormat(current_format) self.deselectText() - #self.setTextCursor(cursor) + #self.setTextCursor(cursor) + + # Used to remove text highlighting def deselectText(self): + cursor = self.textCursor() cursor.clearSelection() self.setTextCursor(cursor) - - - \ No newline at end of file + + # Adds bullet list to text + def changeBulletEvent(self): + #put bullet function here + print("bullet press") \ No newline at end of file From 7b0b3d8e0ad849e91720efeeeaa54167a5cab9e8 Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Mon, 6 Nov 2023 16:15:06 -0600 Subject: [PATCH 023/127] Editor QoL changes - clicking on textbox will immediately focus on textbox and put text cursor at mouse location - selecting from one textbox and selecting from a different textbox will now deselect from the previous textbox --- Assets/icons/svg_undo.svg | 11 +++++++---- Models/DraggableContainer.py | 8 +++++++- Modules/BuildUI.py | 2 ++ Widgets/Textbox.py | 21 +++++++++++---------- 4 files changed, 27 insertions(+), 15 deletions(-) diff --git a/Assets/icons/svg_undo.svg b/Assets/icons/svg_undo.svg index aced362..d463200 100644 --- a/Assets/icons/svg_undo.svg +++ b/Assets/icons/svg_undo.svg @@ -1,4 +1,7 @@ - - - - \ No newline at end of file + + + + + + + \ No newline at end of file diff --git a/Models/DraggableContainer.py b/Models/DraggableContainer.py index 25f79a5..5ddff3c 100644 --- a/Models/DraggableContainer.py +++ b/Models/DraggableContainer.py @@ -102,8 +102,14 @@ def mousePressEvent(self, e: QMouseEvent): self.popupShow(e.pos()) e.accept() + self.childWidget.setAttribute(Qt.WA_TransparentForMouseEvents, False) + self.childWidget.setFocus() + self.childWidget.setCursorPosition(e) + # need to add code for setting cursor to the end of the textbox + # On double click, focus on child and make mouse events pass through this container to child def mouseDoubleClickEvent(self, e: QMouseEvent): + print("MOUSEDOUBLECLICKEVENT FROM DRAGGABLE CONTAINER") self.childWidget.setAttribute(Qt.WA_TransparentForMouseEvents, False) self.childWidget.setFocus() return @@ -120,7 +126,7 @@ def leaveEvent(self, e: QMouseEvent): self.setStyleSheet("border: none;") # Delete this Draggable Container if childWidget says it's empty - # current bug: draggable containers will still exist after creating a + # current bug: Draggable Container will not delete itself if you use multiselect while the container is still in focus # new textbox but after creating an additional textbox, the dc will remove itself. if not self.childWidget.hasFocus(): if hasattr(self.childWidget, "checkEmpty"): diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index afd416c..00a2267 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -186,6 +186,8 @@ def build_toolbar(editor): toolbar.addSeparator() toolbar.addActions([table, hyperlink, bullet]) + #toolbar.setStyleSheet("QToolBar { background-color: #FFFFFF; }") + def openGetColorDialog(purpose): color = QColorDialog.getColor() if color.isValid(): diff --git a/Widgets/Textbox.py b/Widgets/Textbox.py index f975ec1..d98a801 100644 --- a/Widgets/Textbox.py +++ b/Widgets/Textbox.py @@ -17,18 +17,19 @@ def __init__(self, x, y, w = 15, h = 30, t = ''): self.textChanged.connect(self.textChangedEvent) self.setStyleSheet('background-color: rgba(0, 0, 0, 0);') self.setTextColor('black') - - def eventFilter(self, obj, event): - if event.type() == QEvent.MouseButtonPress: - # A click occurred outside the QTextEdit - self.clearFocus() - cursor = self.textCursor() - cursor.clearSelection() - self.setTextCursor(cursor) - return super().eventFilter(obj, event) + #upon clicking somewhere else, remove selection of highlighted text + def focusOutEvent(self, event): + super().focusOutEvent(event) + print("super().focusOutEvent occured") + cursor = self.textCursor() + cursor.clearSelection() + self.setTextCursor(cursor) - + def setCursorPosition(self, event): + print("SETCURSORPOSITION FUNCTION RAN") + cursor = self.cursorForPosition(event.pos()) + self.setTextCursor(cursor) def textChangedEvent(self): if len(self.toPlainText()) < 2: From 902347456db3d2d9f751a2ffce26e99b5c5b895f Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Mon, 6 Nov 2023 16:41:36 -0600 Subject: [PATCH 024/127] Page text color Can now change the page's text color through the right click context menu --- Views/PageView.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Views/PageView.py b/Views/PageView.py index 65922c6..38a0fb4 100644 --- a/Views/PageView.py +++ b/Views/PageView.py @@ -132,6 +132,9 @@ def openMenu(self, position: QModelIndex): renamePageAction = menu.addAction(self.tr("Rename Page")) renamePageAction.triggered.connect(partial(self.renamePage, page)) + + changeColorAction = menu.addAction(self.tr("Change Text Color")) + changeColorAction.triggered.connect(partial(self.changeTextColor, page)) menu.exec_(self.sender().viewport().mapToGlobal(position)) # Dont let the right click reach the viewport, context menu will still open but this will stop the page from being selected @@ -209,3 +212,7 @@ def changePage(self, current: QModelIndex, previous: QModelIndex): print("CHANGED PAGE TO: " + newPage.data().title) editorSignalsInstance.pageChanged.emit(newPageModel) # Tell the sectionView that the page has changed + def changeTextColor(self, page: QStandardItem): + color = QColorDialog.getColor() + if color.isValid(): + page.setForeground(color) \ No newline at end of file From 6fef18ae01c2fadb593c2ed813970c6bb71db881 Mon Sep 17 00:00:00 2001 From: Keido0208 <50084889+Keido0208@users.noreply.github.com> Date: Tue, 7 Nov 2023 11:05:12 -0600 Subject: [PATCH 025/127] Fix create new notebook Prompt user to enter notebook name and set notebook name on side bar --- Modules/Load.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/Load.py b/Modules/Load.py index b618271..3f2c60f 100644 --- a/Modules/Load.py +++ b/Modules/Load.py @@ -2,7 +2,7 @@ import os from Modules.Save import Autosaver - +import pyautogui from PySide6.QtWidgets import * from PySide6.QtCore import * from PySide6.QtGui import * @@ -13,8 +13,8 @@ def new(editor): print("RAN NEW") destroy(editor) - - editor.notebook = NotebookModel('Untitled') + p_name = pyautogui.prompt("Enter Page Name") + editor.notebook = NotebookModel(p_name) editor.notebookTitleView.setText(editor.notebook.title) editor.selected = None editor.autosaver = Autosaver(editor) From 6fe44f74ae5f6534ad383dcacc75d301c726da5f Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Tue, 7 Nov 2023 11:13:05 -0600 Subject: [PATCH 026/127] Highlights lose focus properly Signals made from editor to notify when the editor clicks anywhere that's not the currently in focus textbox. -new bug, font family and font size do not work --- Models/DraggableContainer.py | 6 +++++- Modules/EditorSignals.py | 4 ++++ Views/EditorFrameView.py | 8 +++++++- Views/PageView.py | 15 ++++++++++++--- Widgets/Textbox.py | 15 ++++++++++++--- 5 files changed, 40 insertions(+), 8 deletions(-) diff --git a/Models/DraggableContainer.py b/Models/DraggableContainer.py index 5ddff3c..156a6e3 100644 --- a/Models/DraggableContainer.py +++ b/Models/DraggableContainer.py @@ -303,8 +303,9 @@ def widgetAttributeChanged(self, changedWidgetAttribute, value): child_widget = self.childWidget if self.hasFocus() or child_widget.hasFocus(): if hasattr(child_widget, "changeFontSizeEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.FontSize): + print("Change Font Size Event Called") child_widget.changeFontSizeEvent(value) - + if hasattr(child_widget, "changeFontBoldEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.FontBold): child_widget.changeFontBoldEvent() @@ -328,3 +329,6 @@ def widgetAttributeChanged(self, changedWidgetAttribute, value): if hasattr(child_widget, "changeBulletEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.Bullet): child_widget.changeBulletEvent() + + if hasattr(child_widget, "clearSelectionSlot") and (changedWidgetAttribute == ChangedWidgetAttribute.LoseFocus): + child_widget.clearSelectionSlot() \ No newline at end of file diff --git a/Modules/EditorSignals.py b/Modules/EditorSignals.py index 885141d..9adf29f 100644 --- a/Modules/EditorSignals.py +++ b/Modules/EditorSignals.py @@ -14,6 +14,7 @@ class ChangedWidgetAttribute(Enum): FontUnderline = 6 TextboxColor = 7 Bullet = 8 + LoseFocus = 9 # Cant be statically typed because importing the classes causes circular imports @@ -37,4 +38,7 @@ class EditorSignals(QObject): # Recieves nothing, used by autosaver changeMade = Signal() + # Clear Selection + loseFocus = Signal() + editorSignalsInstance = EditorSignals() diff --git a/Views/EditorFrameView.py b/Views/EditorFrameView.py index 87d9f20..90b13e5 100644 --- a/Views/EditorFrameView.py +++ b/Views/EditorFrameView.py @@ -9,7 +9,7 @@ from Modules.Multiselect import Multiselector, MultiselectMode from Models.DraggableContainer import DraggableContainer from Widgets.Textbox import TextboxWidget -from Modules.EditorSignals import editorSignalsInstance +from Modules.EditorSignals import editorSignalsInstance,ChangedWidgetAttribute from Widgets.Image import ImageWidget from Modules.Screensnip import SnippingWidget from Widgets.Table import * @@ -165,6 +165,12 @@ def mousePressEvent(self, event): print("EDITORFRAME MOUSEPRESS") editor = self.editor + #calls textwidget's clearSelectionSignal + if event.button() == Qt.LeftButton: + if self.rect().contains(event.pos()): + editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.LoseFocus, None) + super().mousePressEvent(event) + # Open context menu on right click if event.buttons() == Qt.RightButton: frame_menu = QMenu(self) diff --git a/Views/PageView.py b/Views/PageView.py index 38a0fb4..7cfa544 100644 --- a/Views/PageView.py +++ b/Views/PageView.py @@ -133,8 +133,12 @@ def openMenu(self, position: QModelIndex): renamePageAction = menu.addAction(self.tr("Rename Page")) renamePageAction.triggered.connect(partial(self.renamePage, page)) - changeColorAction = menu.addAction(self.tr("Change Text Color")) - changeColorAction.triggered.connect(partial(self.changeTextColor, page)) + #Current Issue: settings do not save because autosave only saves editor state + changeTextColorAction = menu.addAction(self.tr("Change Text Color")) + changeTextColorAction.triggered.connect(partial(self.changeTextColor, page)) + + changeBackgroundColorAction = menu.addAction(self.tr("Change Background Color")) + changeBackgroundColorAction.triggered.connect(partial(self.changeBackgroundColor, page)) menu.exec_(self.sender().viewport().mapToGlobal(position)) # Dont let the right click reach the viewport, context menu will still open but this will stop the page from being selected @@ -215,4 +219,9 @@ def changePage(self, current: QModelIndex, previous: QModelIndex): def changeTextColor(self, page: QStandardItem): color = QColorDialog.getColor() if color.isValid(): - page.setForeground(color) \ No newline at end of file + page.setForeground(color) + + def changeBackgroundColor(self, page: QStandardItem): + color = QColorDialog.getColor() + if color.isValid(): + page.setBackground(color) \ No newline at end of file diff --git a/Widgets/Textbox.py b/Widgets/Textbox.py index d98a801..dac014b 100644 --- a/Widgets/Textbox.py +++ b/Widgets/Textbox.py @@ -19,15 +19,23 @@ def __init__(self, x, y, w = 15, h = 30, t = ''): self.setTextColor('black') #upon clicking somewhere else, remove selection of highlighted text - def focusOutEvent(self, event): + # Current issue: clicking on any toolbar button that creates a popup will activate this function, which prevents the toolbar button to work + '''def focusOutEvent(self, event): super().focusOutEvent(event) print("super().focusOutEvent occured") cursor = self.textCursor() cursor.clearSelection() + self.setTextCursor(cursor)''' + + def clearSelectionSlot(self): + print("clearSelectionSlot Called") + cursor = self.textCursor() + cursor.clearSelection() self.setTextCursor(cursor) + def setCursorPosition(self, event): - print("SETCURSORPOSITION FUNCTION RAN") + print("SET TEXT CURSOR POSITION TO MOUSE POSITION") cursor = self.cursorForPosition(event.pos()) self.setTextCursor(cursor) @@ -227,9 +235,10 @@ def changeFontUnderlineEvent(self): def changeFontSizeEvent(self, value): #todo: when textbox is in focus, font size on toolbar should match the font size of the text + print("Change Font Size Event Called") cursor = self.textCursor() current_format = cursor.charFormat() - + current_format.setFontPointSize(value) cursor.setCharFormat(current_format) From fa62c5ed3d8f9e44d9122de5b157211b5371baa5 Mon Sep 17 00:00:00 2001 From: Keido0208 <50084889+Keido0208@users.noreply.github.com> Date: Tue, 7 Nov 2023 11:18:20 -0600 Subject: [PATCH 027/127] Fix create new notebook Just a change from "Page" to "Notebook" --- Modules/Load.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/Load.py b/Modules/Load.py index 3f2c60f..bce98b7 100644 --- a/Modules/Load.py +++ b/Modules/Load.py @@ -13,7 +13,7 @@ def new(editor): print("RAN NEW") destroy(editor) - p_name = pyautogui.prompt("Enter Page Name") + p_name = pyautogui.prompt("Enter Notebook Name") editor.notebook = NotebookModel(p_name) editor.notebookTitleView.setText(editor.notebook.title) editor.selected = None From 95ed47c7f1b67e2e22869524649b2099d0a43426 Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Tue, 7 Nov 2023 13:39:59 -0600 Subject: [PATCH 028/127] Removed redundant code - Removed clearSelectionSlot because it works the same as deselectText() --- Models/DraggableContainer.py | 13 +++++++++++-- Modules/BuildUI.py | 2 +- Widgets/Textbox.py | 7 ++++--- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/Models/DraggableContainer.py b/Models/DraggableContainer.py index 156a6e3..1b93808 100644 --- a/Models/DraggableContainer.py +++ b/Models/DraggableContainer.py @@ -307,28 +307,37 @@ def widgetAttributeChanged(self, changedWidgetAttribute, value): child_widget.changeFontSizeEvent(value) if hasattr(child_widget, "changeFontBoldEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.FontBold): + print("Change Font Bold Event Called") child_widget.changeFontBoldEvent() if hasattr(child_widget, "changeFontItalicEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.FontItalic): + print("Change Font Italic Event Called") child_widget.changeFontItalicEvent() if hasattr(child_widget, "changeFontUnderlineEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.FontUnderline): + print("Change Font Underline Event Called") child_widget.changeFontUnderlineEvent() if hasattr(child_widget, "changeFontEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.Font): + print("Change Font Family Event Called") child_widget.changeFontEvent(value) if hasattr(child_widget, "changeFontColorEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.FontColor): + print("Change Font Color Event Called") child_widget.changeFontColorEvent(value) if hasattr(child_widget, "changeBackgroundColorEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.BackgroundColor): + print("Change Font Background Color Event Called") child_widget.changeBackgroundColorEvent(value) if hasattr(child_widget, "changeTextboxColorEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.TextboxColor): + print("Change Textbox Color Event Called") child_widget.changeTextboxColorEvent(value) if hasattr(child_widget, "changeBulletEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.Bullet): + print("Change Bullet Event Called") child_widget.changeBulletEvent() - if hasattr(child_widget, "clearSelectionSlot") and (changedWidgetAttribute == ChangedWidgetAttribute.LoseFocus): - child_widget.clearSelectionSlot() \ No newline at end of file + if hasattr(child_widget, "deselectText") and (changedWidgetAttribute == ChangedWidgetAttribute.LoseFocus): + print("Clear Selection Slot Called") + child_widget.deselectText() \ No newline at end of file diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index 00a2267..a2cb540 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -129,7 +129,7 @@ def build_toolbar(editor): font_size = QComboBox() font_size.addItems([str(fs) for fs in FONT_SIZES]) - font_size.currentIndexChanged.connect(lambda x: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontSize, int(font_size.currentText()))) + font_size.currentIndexChanged.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontSize, int(font_size.currentText()))) #current issues: # - Alternates between working and not working diff --git a/Widgets/Textbox.py b/Widgets/Textbox.py index dac014b..3e5f8f2 100644 --- a/Widgets/Textbox.py +++ b/Widgets/Textbox.py @@ -27,11 +27,12 @@ def __init__(self, x, y, w = 15, h = 30, t = ''): cursor.clearSelection() self.setTextCursor(cursor)''' - def clearSelectionSlot(self): + #deselect highlighted + '''def clearSelectionSlot(self): print("clearSelectionSlot Called") cursor = self.textCursor() cursor.clearSelection() - self.setTextCursor(cursor) + self.setTextCursor(cursor)''' def setCursorPosition(self, event): @@ -235,7 +236,7 @@ def changeFontUnderlineEvent(self): def changeFontSizeEvent(self, value): #todo: when textbox is in focus, font size on toolbar should match the font size of the text - print("Change Font Size Event Called") + cursor = self.textCursor() current_format = cursor.charFormat() From f1c9137468b930b7a810d31796403e6119efddfb Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Tue, 7 Nov 2023 14:01:04 -0600 Subject: [PATCH 029/127] Small comments added --- Models/DraggableContainer.py | 6 +++++- Widgets/Textbox.py | 10 ++-------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/Models/DraggableContainer.py b/Models/DraggableContainer.py index 1b93808..585a71e 100644 --- a/Models/DraggableContainer.py +++ b/Models/DraggableContainer.py @@ -299,9 +299,13 @@ def mouseMoveEvent(self, e: QMouseEvent): # example signal with a value: 'font_family.currentFontChanged.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Font, font_family.currentFont().family()))' # When adding a function to a child widget, use 'if self.hasFocus():' to ensure the function applies only to the focused widget. Else it will apply to all widgets of the same type def widgetAttributeChanged(self, changedWidgetAttribute, value): - + #print(f"changedWidgetAttribute is {changedWidgetAttribute} and value is {value}") child_widget = self.childWidget + if self.hasFocus() or child_widget.hasFocus(): + #only the focused container will print this line + print(f"changedWidgetAttribute is {changedWidgetAttribute} and value is {value}") + if hasattr(child_widget, "changeFontSizeEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.FontSize): print("Change Font Size Event Called") child_widget.changeFontSizeEvent(value) diff --git a/Widgets/Textbox.py b/Widgets/Textbox.py index 3e5f8f2..3ba131d 100644 --- a/Widgets/Textbox.py +++ b/Widgets/Textbox.py @@ -26,14 +26,6 @@ def __init__(self, x, y, w = 15, h = 30, t = ''): cursor = self.textCursor() cursor.clearSelection() self.setTextCursor(cursor)''' - - #deselect highlighted - '''def clearSelectionSlot(self): - print("clearSelectionSlot Called") - cursor = self.textCursor() - cursor.clearSelection() - self.setTextCursor(cursor)''' - def setCursorPosition(self, event): print("SET TEXT CURSOR POSITION TO MOUSE POSITION") @@ -245,6 +237,8 @@ def changeFontSizeEvent(self, value): self.setTextCursor(cursor) + + def changeFontEvent(self, font_style): cursor = self.textCursor() current_format = cursor.charFormat() From cbe1788be88187ddb0413f5a32fce30153f9bcb8 Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Tue, 7 Nov 2023 14:12:22 -0600 Subject: [PATCH 030/127] Fixed Font Family and Font Size Selecting a font family or size works again but bug still occurs where when selecting a font family, the size will change to match the toolbar setting --- Models/DraggableContainer.py | 85 ++++++++++++++++++------------------ 1 file changed, 43 insertions(+), 42 deletions(-) diff --git a/Models/DraggableContainer.py b/Models/DraggableContainer.py index 585a71e..3bfc071 100644 --- a/Models/DraggableContainer.py +++ b/Models/DraggableContainer.py @@ -302,46 +302,47 @@ def widgetAttributeChanged(self, changedWidgetAttribute, value): #print(f"changedWidgetAttribute is {changedWidgetAttribute} and value is {value}") child_widget = self.childWidget - if self.hasFocus() or child_widget.hasFocus(): + #this if statement is no longer needed because highlighted text deselects after clicking on an area in the editor thats not the in focus textbox + #if self.hasFocus() or child_widget.hasFocus(): #only the focused container will print this line - print(f"changedWidgetAttribute is {changedWidgetAttribute} and value is {value}") - - if hasattr(child_widget, "changeFontSizeEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.FontSize): - print("Change Font Size Event Called") - child_widget.changeFontSizeEvent(value) - - if hasattr(child_widget, "changeFontBoldEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.FontBold): - print("Change Font Bold Event Called") - child_widget.changeFontBoldEvent() - - if hasattr(child_widget, "changeFontItalicEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.FontItalic): - print("Change Font Italic Event Called") - child_widget.changeFontItalicEvent() - - if hasattr(child_widget, "changeFontUnderlineEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.FontUnderline): - print("Change Font Underline Event Called") - child_widget.changeFontUnderlineEvent() - - if hasattr(child_widget, "changeFontEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.Font): - print("Change Font Family Event Called") - child_widget.changeFontEvent(value) - - if hasattr(child_widget, "changeFontColorEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.FontColor): - print("Change Font Color Event Called") - child_widget.changeFontColorEvent(value) - - if hasattr(child_widget, "changeBackgroundColorEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.BackgroundColor): - print("Change Font Background Color Event Called") - child_widget.changeBackgroundColorEvent(value) - - if hasattr(child_widget, "changeTextboxColorEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.TextboxColor): - print("Change Textbox Color Event Called") - child_widget.changeTextboxColorEvent(value) - - if hasattr(child_widget, "changeBulletEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.Bullet): - print("Change Bullet Event Called") - child_widget.changeBulletEvent() - - if hasattr(child_widget, "deselectText") and (changedWidgetAttribute == ChangedWidgetAttribute.LoseFocus): - print("Clear Selection Slot Called") - child_widget.deselectText() \ No newline at end of file + print(f"changedWidgetAttribute is {changedWidgetAttribute} and value is {value}") + + if hasattr(child_widget, "changeFontSizeEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.FontSize): + print("Change Font Size Event Called") + child_widget.changeFontSizeEvent(value) + + if hasattr(child_widget, "changeFontBoldEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.FontBold): + print("Change Font Bold Event Called") + child_widget.changeFontBoldEvent() + + if hasattr(child_widget, "changeFontItalicEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.FontItalic): + print("Change Font Italic Event Called") + child_widget.changeFontItalicEvent() + + if hasattr(child_widget, "changeFontUnderlineEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.FontUnderline): + print("Change Font Underline Event Called") + child_widget.changeFontUnderlineEvent() + + if hasattr(child_widget, "changeFontEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.Font): + print("Change Font Family Event Called") + child_widget.changeFontEvent(value) + + if hasattr(child_widget, "changeFontColorEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.FontColor): + print("Change Font Color Event Called") + child_widget.changeFontColorEvent(value) + + if hasattr(child_widget, "changeBackgroundColorEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.BackgroundColor): + print("Change Font Background Color Event Called") + child_widget.changeBackgroundColorEvent(value) + + if hasattr(child_widget, "changeTextboxColorEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.TextboxColor): + print("Change Textbox Color Event Called") + child_widget.changeTextboxColorEvent(value) + + if hasattr(child_widget, "changeBulletEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.Bullet): + print("Change Bullet Event Called") + child_widget.changeBulletEvent() + + if hasattr(child_widget, "deselectText") and (changedWidgetAttribute == ChangedWidgetAttribute.LoseFocus): + print("Clear Selection Slot Called") + child_widget.deselectText() \ No newline at end of file From f51edd80bfef89b5480ad8be9cf6ade80fde64cd Mon Sep 17 00:00:00 2001 From: sillypenguin77 <67487654+sillypenguin77@users.noreply.github.com> Date: Tue, 7 Nov 2023 23:09:31 -0600 Subject: [PATCH 031/127] Added basic bullet point functionality This contains normal round bullet points and numbered bullet point functionality --- Assets/icons/svg_bullet_number.svg | 6 +++ Modules/BuildUI.py | 3 +- Widgets/Textbox.py | 72 +++++++++++++++++++++++++++++- 3 files changed, 79 insertions(+), 2 deletions(-) create mode 100644 Assets/icons/svg_bullet_number.svg diff --git a/Assets/icons/svg_bullet_number.svg b/Assets/icons/svg_bullet_number.svg new file mode 100644 index 0000000..610e2f1 --- /dev/null +++ b/Assets/icons/svg_bullet_number.svg @@ -0,0 +1,6 @@ + + + number-list-line + + + \ No newline at end of file diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index 692997a..754fea5 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -150,10 +150,11 @@ def build_toolbar(editor): table = build_action(toolbar, 'assets/icons/svg_table', "Create Table", "Create Table", False) table.triggered.connect(editor.frameView.toolbar_table) + hyperlink = build_action(toolbar, 'assets/icons/svg_hyperlink', "Hyperlink", "Hyperlink", False) hyperlink.triggered.connect(editor.frameView.toolbar_hyperlink) - bullets = build_action(toolbar, 'assets/icons/svg_bullets', "Hyperlink", "Hyperlink", False) + bullets = build_action(toolbar, 'assets/icons/svg_bullets', "Bullets", "Bullets", False) editor.action1 = QAction('Action 1', editor) diff --git a/Widgets/Textbox.py b/Widgets/Textbox.py index a961f89..9ddc562 100644 --- a/Widgets/Textbox.py +++ b/Widgets/Textbox.py @@ -18,6 +18,15 @@ def __init__(self, x, y, w = 15, h = 30, t = ''): self.setStyleSheet('background-color: rgba(0, 0, 0, 0);') self.setTextColor('black') + self.installEventFilter(self) + + def eventFilter(self, obj, event): + if event.type() == QEvent.KeyPress and event.key() == Qt.Key_Tab: + self.handleTabKey() + return True # To prevent the default Tab key behavior + + return super(TextboxWidget, self).eventFilter(obj, event) + def textChangedEvent(self): if len(self.toPlainText()) < 2: self.resize(100, 100) @@ -81,9 +90,15 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): bgColor = build_action(toolbarBottom, 'assets/icons/svg_font_bucket', "Text Box Color", "Text Box Color", False) bgColor.triggered.connect(lambda: self.setBackgroundColor(QColorDialog.getColor())) + bullets = build_action(toolbarBottom, 'assets/icons/svg_bullets', "Bullets", "Bullets", True) + bullets.toggled.connect(lambda: self.bullet_list("bulletReg")) + + bullets_num = build_action(toolbarBottom, 'assets/icons/svg_bullet_number', "Bullets Num", "Bullets Num", True) + bullets_num.toggled.connect(lambda: self.bullet_list("bulletNum")) + toolbarTop.addWidget(font) toolbarTop.addWidget(size) - toolbarBottom.addActions([bold, italic, underline, fontColor, bgColor]) + toolbarBottom.addActions([bold, italic, underline, fontColor, bgColor, bullets, bullets_num]) qwaTop = QWidgetAction(self) qwaTop.setDefaultWidget(toolbarTop) qwaBottom = QWidgetAction(self) @@ -207,4 +222,59 @@ def changeFontUnderlineEvent(self): cursor.setCharFormat(current_format) #Update text cursor with modified format + self.setTextCursor(cursor) + + def bullet_list(self, bulletType): + cursor = self.textCursor() + textList = cursor.currentList() + + if textList: + start = cursor.selectionStart() + end = cursor.selectionEnd() + removed = 0 + for i in range(textList.count()): + item = textList.item(i - removed) + if (item.position() <= end and + item.position() + item.length() > start): + textList.remove(item) + blockCursor = QTextCursor(item) + blockFormat = blockCursor.blockFormat() + blockFormat.setIndent(0) + blockCursor.mergeBlockFormat(blockFormat) + removed += 1 + + cursor = self.textCursor() + cursor.setBlockFormat(QTextBlockFormat()) # Clear any previous block format + + self.setTextCursor(cursor) + self.setFocus() + else: + listFormat = QTextListFormat() + + if bulletType == 'bulletNum': + style = QTextListFormat.ListDecimal + if bulletType == 'bulletReg': + style = QTextListFormat.ListDisc + + listFormat.setStyle(style) + cursor.createList(listFormat) + + self.setTextCursor(cursor) + self.setFocus() + + def handleTabKey(self): + cursor = self.textCursor() + textList = cursor.currentList() + + if textList: + # Check if there is a list at the current cursor position + current_block = cursor.block() # Get the current block + if cursor.atBlockStart() and current_block.text().strip() == '': + # Increase the indentation level for the current list item + blockFormat = current_block.blockFormat() + blockFormat.setIndent(blockFormat.indent() + 1) + cursor.setBlockFormat(blockFormat) + else: + pass + self.setTextCursor(cursor) \ No newline at end of file From ffab360cdfcd2c8d738c5a4ea202babb60747c43 Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Wed, 8 Nov 2023 17:44:04 -0600 Subject: [PATCH 032/127] Font Style fix and default setting for size Font Style no longer changes size when changing it through toolbar Font Size on toolbar is now default to 18 to match default size in editor --- Modules/BuildUI.py | 4 ++++ Widgets/Textbox.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index a2cb540..ce0786e 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -125,10 +125,14 @@ def build_toolbar(editor): font_family = QFontComboBox() + default_font = font_family.currentFont().family() + print(f"default font is {default_font}") font_family.currentFontChanged.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Font, font_family.currentFont().family())) font_size = QComboBox() font_size.addItems([str(fs) for fs in FONT_SIZES]) + default_font_size_index = 8 #default text size is 18 + font_size.setCurrentIndex(default_font_size_index) font_size.currentIndexChanged.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontSize, int(font_size.currentText()))) #current issues: diff --git a/Widgets/Textbox.py b/Widgets/Textbox.py index 3ba131d..7fedd6b 100644 --- a/Widgets/Textbox.py +++ b/Widgets/Textbox.py @@ -242,7 +242,7 @@ def changeFontSizeEvent(self, value): def changeFontEvent(self, font_style): cursor = self.textCursor() current_format = cursor.charFormat() - current_format.setFont(font_style) + current_format.setFontFamily(font_style) cursor.setCharFormat(current_format) From 6d441d44c6d2717f966ccf052e992696a5a682df Mon Sep 17 00:00:00 2001 From: ldeltastreaml <70774713+ldeltastreaml@users.noreply.github.com> Date: Wed, 8 Nov 2023 18:34:38 -0600 Subject: [PATCH 033/127] Update requirements.txt Updated requirements to better fit Linux installation of OpenNote --- requirements.txt | Bin 276 -> 276 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/requirements.txt b/requirements.txt index f573bd8c25c581a2732c014309842490ca55a622..98c8ac7be4006dde817f8f2053eb0385c267372e 100644 GIT binary patch delta 64 zcmbQjG=+)x|GzwjQifcH0)|QkyNSHIjCK>Pm4QUOJdmgdaqAT)o)ZDmkCplC7;G8L M81xuSf!Kfn0A(W(ssI20 delta 64 zcmbQjG=+)x|GzwjQifcH0)|Qk+ljoojJ6Z4m4QUOJdmgdaqAT)o)ZDmkCpjs8EhHM M81xuSf!Kfn0AxuJqW}N^ From 803b066126e620126bd6f94f14f61148be672d2e Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Wed, 8 Nov 2023 20:15:18 -0600 Subject: [PATCH 034/127] . --- Models/DraggableContainer.py | 29 ++++++++++++++++------------- Modules/BuildUI.py | 9 ++++++--- Modules/EditorSignals.py | 3 ++- 3 files changed, 24 insertions(+), 17 deletions(-) diff --git a/Models/DraggableContainer.py b/Models/DraggableContainer.py index 3bfc071..94045e2 100644 --- a/Models/DraggableContainer.py +++ b/Models/DraggableContainer.py @@ -311,38 +311,41 @@ def widgetAttributeChanged(self, changedWidgetAttribute, value): print("Change Font Size Event Called") child_widget.changeFontSizeEvent(value) - if hasattr(child_widget, "changeFontBoldEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.FontBold): + elif hasattr(child_widget, "changeFontBoldEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.FontBold): print("Change Font Bold Event Called") child_widget.changeFontBoldEvent() - if hasattr(child_widget, "changeFontItalicEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.FontItalic): + elif hasattr(child_widget, "changeFontItalicEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.FontItalic): print("Change Font Italic Event Called") child_widget.changeFontItalicEvent() - if hasattr(child_widget, "changeFontUnderlineEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.FontUnderline): + elif hasattr(child_widget, "changeFontUnderlineEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.FontUnderline): print("Change Font Underline Event Called") child_widget.changeFontUnderlineEvent() - if hasattr(child_widget, "changeFontEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.Font): + elif hasattr(child_widget, "changeFontEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.Font): print("Change Font Family Event Called") child_widget.changeFontEvent(value) - if hasattr(child_widget, "changeFontColorEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.FontColor): + elif hasattr(child_widget, "changeFontColorEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.FontColor): print("Change Font Color Event Called") child_widget.changeFontColorEvent(value) - if hasattr(child_widget, "changeBackgroundColorEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.BackgroundColor): + elif hasattr(child_widget, "changeBackgroundColorEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.BackgroundColor): print("Change Font Background Color Event Called") child_widget.changeBackgroundColorEvent(value) - if hasattr(child_widget, "changeTextboxColorEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.TextboxColor): + elif hasattr(child_widget, "changeTextboxColorEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.TextboxColor): print("Change Textbox Color Event Called") child_widget.changeTextboxColorEvent(value) - if hasattr(child_widget, "changeBulletEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.Bullet): - print("Change Bullet Event Called") - child_widget.changeBulletEvent() - - if hasattr(child_widget, "deselectText") and (changedWidgetAttribute == ChangedWidgetAttribute.LoseFocus): + elif hasattr(child_widget, "deselectText") and (changedWidgetAttribute == ChangedWidgetAttribute.LoseFocus): print("Clear Selection Slot Called") - child_widget.deselectText() \ No newline at end of file + child_widget.deselectText() + if self.hasFocus() or child_widget.hasFocus(): + if hasattr(child_widget, "changeBulletEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.Bullet): + print("Change Bullet Event Called") + child_widget.bullet_list("bulletReg") + elif hasattr(child_widget, "changeBulletEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.Bullet_Num): + print("Change Bullet Event Called") + child_widget.bullet_list("bulletNum") \ No newline at end of file diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index c733813..523040d 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -168,8 +168,11 @@ def build_toolbar(editor): bullets = build_action(toolbar, 'assets/icons/svg_bullets', "Bullets", "Bullets", False) - bullet = build_action(toolbar, 'assets/icons/svg_bullets', "Bullet List", "Bullet List", False) - bullet.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Bullet, None)) + bullet_reg = build_action(toolbar, 'assets/icons/svg_bullets', "Bullet List", "Bullet List", False) + bullet_reg.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Bullet, None)) + + bullet_num = build_action(toolbar, 'assets/icons/svg_bullet_number', "Bullet List", "Bullet List", False) + bullet_num.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Bullet_Num, None)) ''' editor.action1 = QAction('Action 1', editor) @@ -190,7 +193,7 @@ def build_toolbar(editor): toolbar.addSeparator() toolbar.addActions([bgColor, textboxColor, fontColor, bold, italic, underline]) toolbar.addSeparator() - toolbar.addActions([table, hyperlink, bullet]) + toolbar.addActions([table, hyperlink, bullet_reg, bullet_num]) #toolbar.setStyleSheet("QToolBar { background-color: #FFFFFF; }") diff --git a/Modules/EditorSignals.py b/Modules/EditorSignals.py index 9adf29f..b85e42f 100644 --- a/Modules/EditorSignals.py +++ b/Modules/EditorSignals.py @@ -14,7 +14,8 @@ class ChangedWidgetAttribute(Enum): FontUnderline = 6 TextboxColor = 7 Bullet = 8 - LoseFocus = 9 + Bullet_Num = 9 + LoseFocus = 10 # Cant be statically typed because importing the classes causes circular imports From f573aa88c5e85cc93caf04f246bc6eb3e47d6910 Mon Sep 17 00:00:00 2001 From: Keido0208 <50084889+Keido0208@users.noreply.github.com> Date: Thu, 9 Nov 2023 01:04:39 -0600 Subject: [PATCH 035/127] Attempting to create new notebook Write code to create new notebook but application crashed when "Add New Notebook" button is clicked. --- Models/Editor.py | 9 +- Models/PageModel.py | 8 +- Modules/BuildUI.py | 239 ++++++++++++++++++++++++++++++++++++++++---- Modules/Load.py | 19 ++++ Views/PageView.py | 61 ++++++----- 5 files changed, 289 insertions(+), 47 deletions(-) diff --git a/Models/Editor.py b/Models/Editor.py index 89101c8..d92c8a4 100644 --- a/Models/Editor.py +++ b/Models/Editor.py @@ -6,6 +6,7 @@ from Modules.Save import Autosaver from Modules.Screensnip import SnippingWidget from Models.NotebookModel import NotebookModel +from Models.PageModel import PageModel from Models.SectionModel import SectionModel from Modules.Undo import UndoHandler @@ -19,16 +20,18 @@ class Editor(QMainWindow): def __init__(self): super().__init__() # self.setWindowFlag(Qt.FramelessWindowHint) - self.notebook = NotebookModel('Untitled Notebook') # Current notebook object + self.notebook = NotebookModel("Untitled Notebook") # Current notebook object # self.selected = None # Selected object (for font attributes of TextBox) - + self.pagemodel = PageModel("Untitle Pages") # View-Controllers that let the user interact with the underlying models self.notebookTitleView = NotebookTitleView(self.notebook.title) self.frameView = EditorFrameView(self) self.pageView = PageView(self.notebook.pages) self.sectionView = SectionView(self.notebook.pages[0].sections) - self.autosaver = Autosaver(self) # Waits for change signals and saves the notebook + self.autosaver = Autosaver( + self + ) # Waits for change signals and saves the notebook self.setFocus() build_ui(self) diff --git a/Models/PageModel.py b/Models/PageModel.py index 2643010..1516e58 100644 --- a/Models/PageModel.py +++ b/Models/PageModel.py @@ -1,5 +1,6 @@ import uuid + class PageModel: def __init__(self, title: str, parentUuid: int = 0): self.title = title @@ -12,10 +13,15 @@ def __init__(self, title: str, parentUuid: int = 0): @staticmethod def newRootPage(): - rootPage = PageModel("Notebook Pages") + rootPage = PageModel("Notebook Pages Reloaded") rootPage.__uuid = 0 return rootPage + def createNewRootPage(): + this_root = PageModel("Notebook Pagesssss") + this_root.__uuid = 0 + return this_root + def isRoot(self): return self.__uuid == 0 diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index 6b105a4..0f24dac 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -1,6 +1,5 @@ from Modules.Save import save, saveAs -from Modules.Load import new, load - +from Modules.Load import new, load, add_new_notebook from PySide6.QtCore import * from PySide6.QtGui import * from PySide6.QtWidgets import * @@ -9,14 +8,24 @@ FONT_SIZES = [7, 8, 9, 10, 11, 12, 13, 14, 18, 24, 36, 48, 64, 72, 96, 144, 288] -#builds the application's UI + +# builds the application's UI def build_ui(editor): print("Building UI...") +<<<<<<< Updated upstream #editor.statusBar = editor.statusBar() build_window(editor) build_menubar(editor) #build_toolbar(editor) +======= + # editor.EditorFrameView = EditorFrameView(editor) + # editor.statusBar = editor.statusBar() + build_window(editor) + build_menubar(editor) + build_toolbar(editor) + # build_test_toolbar(editor) +>>>>>>> Stashed changes # Application's main layout (grid) gridLayout = QGridLayout() @@ -27,7 +36,9 @@ def build_ui(editor): gridLayout.setSpacing(3) gridLayout.setContentsMargins(6, 6, 0, 0) - gridLayout.setColumnStretch(0, 1) # The left side (index 0) will take up 1/7? of the space of the right + gridLayout.setColumnStretch( + 0, 1 + ) # The left side (index 0) will take up 1/7? of the space of the right gridLayout.setColumnStretch(1, 7) # Left side of the app's layout @@ -48,42 +59,82 @@ def build_ui(editor): # Add appropriate widgets (ideally just view controllers) to their layouts leftSideLayout.addWidget(editor.notebookTitleView, 0) - leftSideLayout.addWidget(editor.pageView, 1) # Page view has max stretch factor + leftSideLayout.addWidget(editor.pageView, 1) # Page view has max stretch factor rightSideLayout.addWidget(editor.sectionView, 0) - rightSideLayout.addWidget(editor.frameView, 1) # Frame view has max stretch factor + rightSideLayout.addWidget(editor.frameView, 1) # Frame view has max stretch factor # Add L+R container's widgets to the main grid gridLayout.addWidget(leftSideContainerWidget, 0, 0) gridLayout.addWidget(rightSideContainerWidget, 0, 1) +<<<<<<< Updated upstream +======= + addSectionButton = QPushButton("Add Section") + # add functionality e.g. addSectionButton.clcicked.connect(editor.add_section_function) + leftSideLayout.addWidget(addSectionButton) + + +>>>>>>> Stashed changes def build_window(editor): editor.setWindowTitle("OpenNote") - editor.setWindowIcon(QIcon('./Assets/OpenNoteLogo.png')) + editor.setWindowIcon(QIcon("./Assets/OpenNoteLogo.png")) editor.setAcceptDrops(True) - with open('./Styles/styles.qss',"r") as fh: + with open("./Styles/styles.qss", "r") as fh: editor.setStyleSheet(fh.read()) -def build_menubar(editor): - file = editor.menuBar().addMenu('&File') - plugins = editor.menuBar().addMenu('&Plugins') +<<<<<<< Updated upstream new_file = build_action(editor, 'assets/icons/svg_file_open', 'New Notebook...', 'New Notebook', False) new_file.setShortcut(QKeySequence.StandardKey.New) new_file.triggered.connect(lambda: new(editor)) open_file = build_action(editor, 'assets/icons/svg_file_open', 'Open Notebook...', 'Open Notebook', False) +======= +def build_menubar(editor): + file = editor.menuBar().addMenu("&File") + plugins = editor.menuBar().addMenu("&Plugins") + + new_file = build_action( + editor, "assets/icons/svg_file_open", "New Notebook", "New Notebook", False + ) + new_file.setShortcut(QKeySequence.StandardKey.New) + new_file.triggered.connect(lambda: new(editor)) + + add_new_file = build_action( + editor, + "assets/icons/svg_file_open", + "Add New Notebook", + "Add New Notebook", + False, + ) + add_new_file.setShortcut(QKeySequence.StandardKey.New) + add_new_file.triggered.connect(lambda: add_new_notebook(editor)) + + open_file = build_action( + editor, "assets/icons/svg_file_open", "Open Notebook", "Open Notebook", False + ) +>>>>>>> Stashed changes open_file.setShortcut(QKeySequence.StandardKey.Open) open_file.triggered.connect(lambda: load(editor)) - save_file = build_action(editor, 'assets/icons/svg_file_save', 'Save Notebook', 'Save Notebook', False) + save_file = build_action( + editor, "assets/icons/svg_file_save", "Save Notebook", "Save Notebook", False + ) save_file.setShortcut(QKeySequence.StandardKey.Save) save_file.triggered.connect(lambda: save(editor)) - save_fileAs = build_action(editor, 'assets/icons/svg_file_save', 'Save Notebook As...', 'Save Notebook As', False) - save_fileAs.setShortcut(QKeySequence.fromString('Ctrl+Shift+S')) + save_fileAs = build_action( + editor, + "assets/icons/svg_file_save", + "Save Notebook As...", + "Save Notebook As", + False, + ) + save_fileAs.setShortcut(QKeySequence.fromString("Ctrl+Shift+S")) save_fileAs.triggered.connect(lambda: saveAs(editor)) - file.addActions([new_file, open_file, save_file, save_fileAs]) + file.addActions([new_file, add_new_file, open_file, save_file, save_fileAs]) + def build_toolbar(editor): toolbar = QToolBar() @@ -91,13 +142,36 @@ def build_toolbar(editor): toolbar.setMovable(False) editor.addToolBar(Qt.ToolBarArea.TopToolBarArea, toolbar) +<<<<<<< Updated upstream font = QFontComboBox() font.currentFontChanged.connect(lambda x: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Font, font.currentFont())) +======= + # separates toolbar with a line break + spacer = QWidget() + spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) + + toolbar_undo = build_action(toolbar, "assets/icons/svg_undo", "undo", "undo", False) + # toolbar_undo.triggered.connect(editor.frameView.triggerUndo) + + redo = build_action(toolbar, "assets/icons/svg_redo", "redo", "redo", False) + + font = QFontComboBox() + font.currentFontChanged.connect( + lambda: editorSignalsInstance.widgetAttributeChanged.emit( + ChangedWidgetAttribute.Font, font.currentFont() + ) + ) +>>>>>>> Stashed changes size = QComboBox() size.addItems([str(fs) for fs in FONT_SIZES]) - size.currentIndexChanged.connect(lambda x: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontSize, int(size.currentText()))) + size.currentIndexChanged.connect( + lambda x: editorSignalsInstance.widgetAttributeChanged.emit( + ChangedWidgetAttribute.FontSize, int(size.currentText()) + ) + ) +<<<<<<< Updated upstream fontColor = build_action(toolbar, 'assets/icons/svg_font_color', "Font Color", "Font Color", False) fontColor.triggered.connect(lambda x: openGetColorDialog(purpose = "font")) @@ -113,19 +187,148 @@ def build_toolbar(editor): underline = build_action(toolbar, 'assets/icons/underline.svg', "Underline", "Underline", True) underline.triggered.connect(lambda x: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontUnderline, None)) +======= + bgColor = build_action( + toolbar, + "assets/icons/svg_font_bucket", + "Text Box Color", + "Text Box Color", + False, + ) + bgColor.triggered.connect(lambda: openGetColorDialog(purpose="background")) + + fontColor = build_action( + toolbar, "assets/icons/svg_font_color", "Font Color", "Font Color", False + ) + fontColor.triggered.connect(lambda: openGetColorDialog(purpose="font")) + + bold = build_action(toolbar, "assets/icons/bold", "Bold", "Bold", True) + bold.toggled.connect( + lambda: editorSignalsInstance.widgetAttributeChanged.emit( + ChangedWidgetAttribute.FontBold, None + ) + ) + # bold.triggered.connect(editor.frameView.add_table_action) + + # bold.toggled.connect(lambda x: editor.selected.setFontWeight(700 if x else 500)) + + italic = build_action(toolbar, "assets/icons/italic.svg", "Italic", "Italic", True) + italic.toggled.connect( + lambda: editorSignalsInstance.widgetAttributeChanged.emit( + ChangedWidgetAttribute.FontItalic, None + ) + ) + + underline = build_action( + toolbar, "assets/icons/underline.svg", "Underline", "Underline", True + ) + underline.toggled.connect( + lambda: editorSignalsInstance.widgetAttributeChanged.emit( + ChangedWidgetAttribute.FontUnderline, None + ) + ) + + table = build_action( + toolbar, "assets/icons/svg_table", "Create Table", "Create Table", False + ) + table.triggered.connect(editor.frameView.toolbar_table) + hyperlink = build_action( + toolbar, "assets/icons/svg_hyperlink", "Hyperlink", "Hyperlink", False + ) + hyperlink.triggered.connect(editor.frameView.toolbar_hyperlink) + bullets = build_action( + toolbar, "assets/icons/svg_bullets", "Hyperlink", "Hyperlink", False + ) + + editor.action1 = QAction("Action 1", editor) + # editor.action1.triggered.connect(EditorFrameView.slot_action1) + toolbar.addAction(editor.action1) + editor.action2 = QAction("Action 2", editor) + # editor.action2.triggered.connect(TextboxWidget.slot_action2) + # editor.action2.triggered.connect(show_popup) + toolbar.addAction(editor.action2) + # editor.button = QPushButton("Click Me", editor) + # editor.button.clicked.connect(editor.slot_button_click) + + # toolbar.addActions([undo, redo]) + toolbar.addSeparator() +>>>>>>> Stashed changes toolbar.addWidget(font) toolbar.addWidget(size) toolbar.addActions([bgColor, fontColor, bold, italic, underline]) +<<<<<<< Updated upstream +======= + toolbar.addSeparator() + toolbar.addActions([table, hyperlink, bullets]) + + +def toggle_bold(self): + self.is_bold = not self.is_bold + + font = self.text_edit + +>>>>>>> Stashed changes def openGetColorDialog(purpose): color = QColorDialog.getColor() if color.isValid(): if purpose == "font": - editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontColor, color) + editorSignalsInstance.widgetAttributeChanged.emit( + ChangedWidgetAttribute.FontColor, color + ) elif purpose == "background": - editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.BackgroundColor, color) + editorSignalsInstance.widgetAttributeChanged.emit( + ChangedWidgetAttribute.BackgroundColor, color + ) + def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): action = QAction(QIcon(icon_path), action_name, parent) action.setStatusTip(set_status_tip) return action +<<<<<<< Updated upstream +======= + + +def build_test_toolbar(self): + editorFrameViewInstance = EditorFrameView(self) + + toolbar = QToolBar(self) + self.addToolBar(toolbar) + + exitAct = QAction(QIcon("assets/icons/underline.svg"), "Exit", self) + exitAct.setShortcut("Ctrl+Q") + exitAct.triggered.connect(QApplication.instance().quit) + + self.toolbar = self.addToolBar("Exit") + self.toolbar.addAction(exitAct) + + # font_change + font_combo = QFontComboBox(self) + toolbar.addWidget(font_combo) + + bold = build_action(toolbar, "assets/icons/bold", "Bold", "Bold", True) + bold.setShortcut("Ctrl+B") + bold.triggered.connect( + lambda: editorSignalsInstance.widgetAttributeChanged.connect( + self.widgetAttributeChangedEvent + ) + ) + + toolbar.addAction(bold) + + undo_action = QAction("Undo", self) + undo_action.triggered.connect(self.frameView.triggerUndo) + + toolbar.addAction(undo_action) + + +def change_font(self): + selected_font = self.sender().parent().widgetForAction(self.sender()).currentFont() + + self.text_edit.setFont(selected_font) + + +def widgetAttributeChangedEvent(self, draggableContainer): + editorSignalsInstance.widgetAttributeChanged.emit(draggableContainer) +>>>>>>> Stashed changes diff --git a/Modules/Load.py b/Modules/Load.py index 5082bb3..0592cde 100644 --- a/Modules/Load.py +++ b/Modules/Load.py @@ -11,6 +11,9 @@ from PySide6.QtGui import * from Models.NotebookModel import NotebookModel +from Models.PageModel import PageModel +from Views.PageView import PageView + # Creates a new notebook @@ -36,6 +39,22 @@ def new(editor): editor.autosaver = Autosaver(editor) build(editor) # should we build here, or should above be in build? +<<<<<<< Updated upstream +======= + +def add_new_notebook(editor): + destroy(editor) + p_name = pyautogui.prompt("Enter Notebook Name") + editor.pagemodel = PageModel(p_name, 0) + page_models = [PageModel] + page_models.append(editor.pagemodel) + page_view = PageView(page_models) + editor.pageView(page_models) + editor.selected = None + editor.autosaver = Autosaver(editor) + build(editor) + +>>>>>>> Stashed changes # Loads models.notebook.Notebook class from file def load(editor): diff --git a/Views/PageView.py b/Views/PageView.py index 65922c6..9c4b193 100644 --- a/Views/PageView.py +++ b/Views/PageView.py @@ -9,12 +9,13 @@ from Modules.EditorSignals import editorSignalsInstance + # Page view and controller class PageView(QWidget): def __init__(self, pageModels: List[PageModel]): super(PageView, self).__init__() - self.pageModels: List[PageModel] # Reference to the array of page models + self.pageModels: List[PageModel] # Reference to the array of page models # The actual tree widget self.tree = QTreeView(self) @@ -57,28 +58,27 @@ def loadPages(self, pageModels: List[PageModel]): root.appendRow([rootPage]) # Create a first page - newPageModel = PageModel('New Page', 0) + newPageModel = PageModel("New Page", 0) newPage = QStandardItem(newPageModel.title) newPage.setData(newPageModel) newPage.setEditable(False) - rootPage.appendRow([newPage]) # Add to UI + rootPage.appendRow([newPage]) # Add to UI - pageModels.append(newPageModel) # Add to array of PageModel - self.pageModels = pageModels # Update reference to array of PageModel + pageModels.append(newPageModel) # Add to array of PageModel + self.pageModels = pageModels # Update reference to array of PageModel self.pageModels.append(rootPageModel) - self.tree.expandAll() # root.child(0).child(0).setBackground(QColor(193,220,243)) # Highlight first page (it's already selected) return seen: List[QStandardItemModel] = {} - values = deque(pageModels) # double ended queue[PageModel] + values = deque(pageModels) # double ended queue[PageModel] # Computer Science | Turn our pages with parent refs into a tree while values: value = values.popleft() - if value.isRoot(): # Add the root page, and make it unselectable + if value.isRoot(): # Add the root page, and make it unselectable parent = root unique_id = value.getUUID() @@ -91,10 +91,14 @@ def loadPages(self, pageModels: List[PageModel]): continue else: pid = value.getParentUUID() - if pid not in seen: # Add to the end of the list so we can add it when we know what its parent is + if ( + pid not in seen + ): # Add to the end of the list so we can add it when we know what its parent is values.append(value) continue - parent = seen[pid] # When we've seen a page's parent, add it to the correct location in the tree + parent = seen[ + pid + ] # When we've seen a page's parent, add it to the correct location in the tree unique_id = value.getUUID() newPage = QStandardItem(value.title) newPage.setData(value) @@ -103,8 +107,8 @@ def loadPages(self, pageModels: List[PageModel]): seen[unique_id] = parent.child(parent.rowCount() - 1) # root.child(0).child(0).setBackground(QColor(193,220,243)) # Highlight first page (its selected) - self.tree.expandAll() # Mb dont - self.pageModels = pageModels # Update the view's stored reference to the pageModels (in case we are loading new pages) + self.tree.expandAll() # Mb dont + self.pageModels = pageModels # Update the view's stored reference to the pageModels (in case we are loading new pages) def openMenu(self, position: QModelIndex): indexes = self.sender().selectedIndexes() @@ -126,7 +130,7 @@ def openMenu(self, position: QModelIndex): addChildAction = menu.addAction(self.tr("Add Page")) addChildAction.triggered.connect(partial(self.addPage, level, clickedIndex)) - if not page.data().isRoot(): # Dont delete the root page + if not page.data().isRoot(): # Dont delete the root page deletePageAction = menu.addAction(self.tr("Delete Page")) deletePageAction.triggered.connect(partial(self.deletePage, page)) @@ -137,22 +141,21 @@ def openMenu(self, position: QModelIndex): # Dont let the right click reach the viewport, context menu will still open but this will stop the page from being selected def eventFilter(self, source, event): if event.type() == QMouseEvent.MouseButtonPress: - if(event.button() == Qt.RightButton): + if event.button() == Qt.RightButton: return True return False def addPage(self, level: int, clickedIndex: QModelIndex): - # New page added under parent (what the user right clicked on) parentPage = self.model.itemFromIndex(clickedIndex) parentPageUUID = parentPage.data().getUUID() # Create a new page model, set that as the data for the new page - newPageModel = PageModel('New Page', parentPageUUID) + newPageModel = PageModel("New Page", parentPageUUID) newPage = QStandardItem(newPageModel.title) newPage.setData(newPageModel) newPage.setEditable(False) - parentPage.appendRow([newPage]) # Add to UI + parentPage.appendRow([newPage]) # Add to UI self.pageModels.append(newPageModel) # Add to array of PageModel self.tree.expand(clickedIndex) @@ -162,25 +165,31 @@ def deletePage(self, page: QStandardItem): deletePages += self.getPageChildren(page) for p in deletePages: pageModel = p.data() - self.pageModels.remove(pageModel) # Remove parent and all child PageModels - page.parent().removeRow(page.row()) # Remove from UI + self.pageModels.remove(pageModel) # Remove parent and all child PageModels + page.parent().removeRow(page.row()) # Remove from UI # Recursively build a list of all the given pages children def getPageChildren(self, page: QStandardItem): childPages = [] - for row in range(0, page.rowCount()): # mb doesnt need 0 (range(page.rowCount())) + for row in range( + 0, page.rowCount() + ): # mb doesnt need 0 (range(page.rowCount())) childPage = page.child(row) childPages.append(childPage) childPages += self.getPageChildren(childPage) return childPages def renamePage(self, page: QStandardItem): - newName, accept = QInputDialog.getText(self, 'Change Page Title', 'Enter new title of page: ') + newName, accept = QInputDialog.getText( + self, "Change Page Title", "Enter new title of page: " + ) if accept: - page.setText(newName) # Rename in UI + page.setText(newName) # Rename in UI pageModel = page.data() pageModelIndex = self.pageModels.index(pageModel) - self.pageModels[pageModelIndex].title = newName # Rename in array of PageModel + self.pageModels[ + pageModelIndex + ].title = newName # Rename in array of PageModel self.update() def changePage(self, current: QModelIndex, previous: QModelIndex): @@ -204,8 +213,10 @@ def changePage(self, current: QModelIndex, previous: QModelIndex): # prev.setBackground(QColor('white')) self.update() - newPage = self.model.itemFromIndex(current) # could save selected page + newPage = self.model.itemFromIndex(current) # could save selected page newPageModel = newPage.data() print("CHANGED PAGE TO: " + newPage.data().title) - editorSignalsInstance.pageChanged.emit(newPageModel) # Tell the sectionView that the page has changed + editorSignalsInstance.pageChanged.emit( + newPageModel + ) # Tell the sectionView that the page has changed From 75dd4beb8cdfe264577b54033e97c991e27ad322 Mon Sep 17 00:00:00 2001 From: ldeltastreaml <70774713+ldeltastreaml@users.noreply.github.com> Date: Thu, 9 Nov 2023 10:10:33 -0600 Subject: [PATCH 036/127] Revert "Pages can no longer be nested" This reverts commit 7489316ef767b6a68dac63719ac42531ba548a03. --- Views/PageView.py | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/Views/PageView.py b/Views/PageView.py index cc8a634..7176482 100644 --- a/Views/PageView.py +++ b/Views/PageView.py @@ -141,19 +141,6 @@ def eventFilter(self, source, event): return True return False - def addPage(self, level: int, clickedIndex: QModelIndex): - # New page added at the top level (root) - newPageModel = PageModel('New Page', 0) # Assuming 0 as the parent UUID for the root - newPage = QStandardItem(newPageModel.title) - newPage.setData(newPageModel) - newPage.setEditable(False) - root.appendRow([newPage]) # Add to UI - self.pageModels.append(newPageModel) # Add to array of PageModel - - self.tree.expandAll() - - # previous addPage would nest the page into the selected page (not a function in Onenote) - ''' def addPage(self, level: int, clickedIndex: QModelIndex): # New page added under parent (what the user right clicked on) @@ -168,7 +155,7 @@ def addPage(self, level: int, clickedIndex: QModelIndex): parentPage.appendRow([newPage]) # Add to UI self.pageModels.append(newPageModel) # Add to array of PageModel - self.tree.expand(clickedIndex) ''' + self.tree.expand(clickedIndex) def deletePage(self, page: QStandardItem): deletePages = [page] From cd6a86932213994edbd34ec6854d1582b6574e08 Mon Sep 17 00:00:00 2001 From: ldeltastreaml <70774713+ldeltastreaml@users.noreply.github.com> Date: Thu, 9 Nov 2023 10:11:31 -0600 Subject: [PATCH 037/127] Revert "Merge branch 'Test-Branch' of https://github.com/Jonathon-Doran/OpenNote into Test-Branch" This reverts commit 2ffe053f45b2ee3791e6f0230be33829f3c9191a, reversing changes made to 6d441d44c6d2717f966ccf052e992696a5a682df. --- Modules/Load.py | 53 ++++++++++++++++++------------------------------- 1 file changed, 19 insertions(+), 34 deletions(-) diff --git a/Modules/Load.py b/Modules/Load.py index 5082bb3..b618271 100644 --- a/Modules/Load.py +++ b/Modules/Load.py @@ -1,8 +1,5 @@ import pickle import os -from tkinter import * -from tkinter import ttk -import pyautogui from Modules.Save import Autosaver @@ -12,39 +9,28 @@ from Models.NotebookModel import NotebookModel - # Creates a new notebook def new(editor): - print("New Note book is created") - window = Tk() - nb = ttk.Notebook(window) - nb.pack(fill=BOTH, expand=1) - - p = ttk.Frame(nb) - p.pack(fill=BOTH, expand=1) - - p_name = pyautogui.prompt("Enter Page Name") - - nb.add(p, text=p_name) - text_ar = Text(p, fg="black", bg="white", font=("segoe print", 15)) - text_ar.pack() + print("RAN NEW") destroy(editor) - editor.notebook = NotebookModel("Untitled") + editor.notebook = NotebookModel('Untitled') editor.notebookTitleView.setText(editor.notebook.title) editor.selected = None editor.autosaver = Autosaver(editor) - build(editor) # should we build here, or should above be in build? - + build(editor) # should we build here, or should above be in build? # Loads models.notebook.Notebook class from file def load(editor): print("LOADING") path, accept = QFileDialog.getOpenFileName( - editor, "Open Notebook", "", "OpenNote (*.on *.ontemp)" + editor, + 'Open Notebook', + '', + 'OpenNote (*.on *.ontemp)' ) if accept: - file = open(path, "rb") + file = open(path, 'rb') destroy(editor) editor.notebook = pickle.load(file) # for page in editor.notebook.pages: @@ -57,25 +43,25 @@ def load(editor): return build(editor) - # Try to find and open the most recent OpenNote related file def load_most_recent_notebook(editor): + print("LOAD RECENT RAN") files = [] - saves_directory = os.path.join(os.getcwd(), "Saves") + saves_directory = os.path.join(os.getcwd(), 'Saves') for file in os.listdir(saves_directory): - file_path = os.path.join(saves_directory, file) - if os.path.isfile(file_path): - files.append(file_path) - print(file_path) + file_path = os.path.join(saves_directory, file) + if os.path.isfile(file_path): + files.append(file_path) + print(file_path) - directory_files = reversed(sorted(files, key=os.path.getmtime)) + directory_files = reversed(sorted(files, key = os.path.getmtime)) for f in directory_files: - if f.endswith(".on") or f.endswith(".ontemp"): + if (f.endswith(".on") or f.endswith(".ontemp")): print("FOUND: " + str(f)) try: # prob need load from file function, dup functionality - file = open(os.path.join(os.getcwd() + "\\Saves", f), "rb") + file = open(os.path.join(os.getcwd() + "\\Saves", f), 'rb') destroy(editor) editor.notebook = pickle.load(file) build(editor) @@ -89,7 +75,6 @@ def load_most_recent_notebook(editor): except: continue - def build(editor): print("BUILDING FROM LOAD") @@ -114,7 +99,8 @@ def build(editor): print("RELOADED VIEWS ") - if len(editor.notebook.pages) > 0: # If pages exist + if len(editor.notebook.pages) > 0: # If pages exist + print("PAGES EXIST") # Show all Pages in Notebook # editor.pageView.loadPages(editor.notebook.pages) @@ -143,7 +129,6 @@ def build(editor): # editor.pageIndex = 0 # editor.sectionIndex = 0 - # Destroy all Widgets in the Current Notebook def destroy(editor): print("RAN DESTROY") From 0e4db5d144eebcab25306faa7d9a2f898a1f6028 Mon Sep 17 00:00:00 2001 From: ldeltastreaml <70774713+ldeltastreaml@users.noreply.github.com> Date: Thu, 9 Nov 2023 10:17:49 -0600 Subject: [PATCH 038/127] Revert "Revert "Pages can no longer be nested"" This reverts commit 75dd4beb8cdfe264577b54033e97c991e27ad322. --- Views/PageView.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/Views/PageView.py b/Views/PageView.py index ae578d5..212486c 100644 --- a/Views/PageView.py +++ b/Views/PageView.py @@ -148,6 +148,19 @@ def eventFilter(self, source, event): return True return False + def addPage(self, level: int, clickedIndex: QModelIndex): + # New page added at the top level (root) + newPageModel = PageModel('New Page', 0) # Assuming 0 as the parent UUID for the root + newPage = QStandardItem(newPageModel.title) + newPage.setData(newPageModel) + newPage.setEditable(False) + root.appendRow([newPage]) # Add to UI + self.pageModels.append(newPageModel) # Add to array of PageModel + + self.tree.expandAll() + + # previous addPage would nest the page into the selected page (not a function in Onenote) + ''' def addPage(self, level: int, clickedIndex: QModelIndex): # New page added under parent (what the user right clicked on) @@ -162,7 +175,7 @@ def addPage(self, level: int, clickedIndex: QModelIndex): parentPage.appendRow([newPage]) # Add to UI self.pageModels.append(newPageModel) # Add to array of PageModel - self.tree.expand(clickedIndex) + self.tree.expand(clickedIndex) ''' def deletePage(self, page: QStandardItem): deletePages = [page] From 3f3dfbb5f8ff03830098f30eccca148869491d68 Mon Sep 17 00:00:00 2001 From: ldeltastreaml <70774713+ldeltastreaml@users.noreply.github.com> Date: Thu, 9 Nov 2023 10:18:51 -0600 Subject: [PATCH 039/127] Revert "Merge pull request #8 from Jonathon-Doran/Test-Branch" This reverts commit e89bd102c8912df4f57419b463406117788b37e3, reversing changes made to d583133bbdf48b11fdb24e56804e44aac78e867f. --- Modules/Load.py | 53 +++++++++++++------------------------ Views/PageView.py | 62 ++------------------------------------------ Views/SectionView.py | 9 ++----- Widgets/Image.py | 8 ------ requirements.txt | 2 +- 5 files changed, 23 insertions(+), 111 deletions(-) diff --git a/Modules/Load.py b/Modules/Load.py index a86b6d9..bce98b7 100644 --- a/Modules/Load.py +++ b/Modules/Load.py @@ -1,8 +1,5 @@ import pickle import os -from tkinter import * -from tkinter import ttk -import pyautogui from Modules.Save import Autosaver import pyautogui @@ -12,41 +9,28 @@ from Models.NotebookModel import NotebookModel - # Creates a new notebook def new(editor): - print("New Note book is created") - window = Tk() - nb = ttk.Notebook(window) - nb.pack(fill=BOTH, expand=1) - - p = ttk.Frame(nb) - p.pack(fill=BOTH, expand=1) - - p_name = pyautogui.prompt("Enter Page Name") - - nb.add(p, text=p_name) - text_ar = Text(p, fg="black", bg="white", font=("segoe print", 15)) - text_ar.pack() + print("RAN NEW") destroy(editor) - p_name = pyautogui.prompt("Enter Notebook Name") editor.notebook = NotebookModel(p_name) - editor.notebookTitleView.setText(editor.notebook.title) editor.selected = None editor.autosaver = Autosaver(editor) - build(editor) # should we build here, or should above be in build? - + build(editor) # should we build here, or should above be in build? # Loads models.notebook.Notebook class from file def load(editor): print("LOADING") path, accept = QFileDialog.getOpenFileName( - editor, "Open Notebook", "", "OpenNote (*.on *.ontemp)" + editor, + 'Open Notebook', + '', + 'OpenNote (*.on *.ontemp)' ) if accept: - file = open(path, "rb") + file = open(path, 'rb') destroy(editor) editor.notebook = pickle.load(file) # for page in editor.notebook.pages: @@ -59,25 +43,25 @@ def load(editor): return build(editor) - # Try to find and open the most recent OpenNote related file def load_most_recent_notebook(editor): + print("LOAD RECENT RAN") files = [] - saves_directory = os.path.join(os.getcwd(), "Saves") + saves_directory = os.path.join(os.getcwd(), 'Saves') for file in os.listdir(saves_directory): - file_path = os.path.join(saves_directory, file) - if os.path.isfile(file_path): - files.append(file_path) - print(file_path) + file_path = os.path.join(saves_directory, file) + if os.path.isfile(file_path): + files.append(file_path) + print(file_path) - directory_files = reversed(sorted(files, key=os.path.getmtime)) + directory_files = reversed(sorted(files, key = os.path.getmtime)) for f in directory_files: - if f.endswith(".on") or f.endswith(".ontemp"): + if (f.endswith(".on") or f.endswith(".ontemp")): print("FOUND: " + str(f)) try: # prob need load from file function, dup functionality - file = open(os.path.join(os.getcwd() + "\\Saves", f), "rb") + file = open(os.path.join(os.getcwd() + "\\Saves", f), 'rb') destroy(editor) editor.notebook = pickle.load(file) build(editor) @@ -91,7 +75,6 @@ def load_most_recent_notebook(editor): except: continue - def build(editor): print("BUILDING FROM LOAD") @@ -116,7 +99,8 @@ def build(editor): print("RELOADED VIEWS ") - if len(editor.notebook.pages) > 0: # If pages exist + if len(editor.notebook.pages) > 0: # If pages exist + print("PAGES EXIST") # Show all Pages in Notebook # editor.pageView.loadPages(editor.notebook.pages) @@ -145,7 +129,6 @@ def build(editor): # editor.pageIndex = 0 # editor.sectionIndex = 0 - # Destroy all Widgets in the Current Notebook def destroy(editor): print("RAN DESTROY") diff --git a/Views/PageView.py b/Views/PageView.py index 212486c..7cfa544 100644 --- a/Views/PageView.py +++ b/Views/PageView.py @@ -148,19 +148,6 @@ def eventFilter(self, source, event): return True return False - def addPage(self, level: int, clickedIndex: QModelIndex): - # New page added at the top level (root) - newPageModel = PageModel('New Page', 0) # Assuming 0 as the parent UUID for the root - newPage = QStandardItem(newPageModel.title) - newPage.setData(newPageModel) - newPage.setEditable(False) - root.appendRow([newPage]) # Add to UI - self.pageModels.append(newPageModel) # Add to array of PageModel - - self.tree.expandAll() - - # previous addPage would nest the page into the selected page (not a function in Onenote) - ''' def addPage(self, level: int, clickedIndex: QModelIndex): # New page added under parent (what the user right clicked on) @@ -175,7 +162,7 @@ def addPage(self, level: int, clickedIndex: QModelIndex): parentPage.appendRow([newPage]) # Add to UI self.pageModels.append(newPageModel) # Add to array of PageModel - self.tree.expand(clickedIndex) ''' + self.tree.expand(clickedIndex) def deletePage(self, page: QStandardItem): deletePages = [page] @@ -229,51 +216,6 @@ def changePage(self, current: QModelIndex, previous: QModelIndex): print("CHANGED PAGE TO: " + newPage.data().title) editorSignalsInstance.pageChanged.emit(newPageModel) # Tell the sectionView that the page has changed - - # Not sure if working as intended - def mergePages(self): - # Prompt the user to select two pages - selectedIndexes = self.tree.selectedIndexes() - - # Check if exactly two pages are selected - if len(selectedIndexes) == 2: - # Retrieve the QStandardItem objects corresponding to the selected pages - page1Item = self.model.itemFromIndex(selectedIndexes[0]) - page2Item = self.model.itemFromIndex(selectedIndexes[1]) - - # Extract the PageModel objects from the selected QStandardItem objects - page1Model = page1Item.data() - page2Model = page2Item.data() - - # Merge the sections of the two pages into one page - mergedSections = page1Model.sections + page2Model.sections - newPageModel = PageModel('Merged Page', 0, mergedSections) # Assuming 0 as the parent UUID for the root - - # Create a new QStandardItem for the merged page - newPageItem = QStandardItem(newPageModel.title) - newPageItem.setData(newPageModel) - newPageItem.setEditable(False) - - # Insert the new merged page at the bottom of the children of the root - root = self.model.invisibleRootItem() - index = root.rowCount() # Get the last index - root.insertRow(index, [newPageItem]) - - # Remove the original two pages from the model - root.removeRow(page1Item.row()) - root.removeRow(page2Item.row()) - - # Update the pageModels list - self.pageModels.remove(page1Model) - self.pageModels.remove(page2Model) - self.pageModels.append(newPageModel) - - # Expand the tree to show the changes - self.tree.expandAll() - else: - # If not exactly two pages are selected, show a warning or message - QMessageBox.warning(self, 'Invalid Selection', 'Please select exactly two pages to merge.', QMessageBox.Ok) - def changeTextColor(self, page: QStandardItem): color = QColorDialog.getColor() if color.isValid(): @@ -282,4 +224,4 @@ def changeTextColor(self, page: QStandardItem): def changeBackgroundColor(self, page: QStandardItem): color = QColorDialog.getColor() if color.isValid(): - page.setBackground(color) + page.setBackground(color) \ No newline at end of file diff --git a/Views/SectionView.py b/Views/SectionView.py index e5fbb37..b26d198 100644 --- a/Views/SectionView.py +++ b/Views/SectionView.py @@ -19,11 +19,6 @@ def __init__(self, sectionModels: List[SectionModel]): # The tabbed section widget self.tabs = QTabBar(self) - # Create a scroll area and set the SectionView as its widget - self.scroll_area = QScrollArea() - self.scroll_area.setWidgetResizable(True) - self.scroll_area.setWidget(self.tabs) - # Layout that holds this view layout = QVBoxLayout(self) layout.addWidget(self.tabs) @@ -46,10 +41,10 @@ def __init__(self, sectionModels: List[SectionModel]): print("BUILT SECTIONVIEW") def tabSizeHint(self, index): - return QSize(600, 70) + return QSize(300, 35) def minimumTabSizeHint(self, index): - return QSize(600, 70) + return QSize(300, 35) def widgetRemovedEvent(self, draggableContainer): try: diff --git a/Widgets/Image.py b/Widgets/Image.py index 6c207e7..64971e1 100644 --- a/Widgets/Image.py +++ b/Widgets/Image.py @@ -28,14 +28,6 @@ def __init__(self, x, y, w, h, image_matrix): def newGeometryEvent(self, newGeometry): new_w = newGeometry.width() new_h = newGeometry.height() - - # Calculate minimum width and height as 1/8th (arbitrary) of the original image dimensions - min_width = max(1, self.w // 8) # Ensure that min_width is at least 1 - min_height = max(1, self.h // 8) # Ensure that min_height is at least 1 - - # Check if the new width/height is below the minimum and if it is limits the width/height to 1/8th the size - if (new_w < min_width) and (new_h < min_height): new_w, new_h = min_width, min_height - if (self.w != new_w) or (self.h != new_h): # Not exactly sure how object's width and height attribute gets updated but this works self.setPixmap(self.q_pixmap.scaled(new_w, new_h, Qt.KeepAspectRatio, Qt.SmoothTransformation)) diff --git a/requirements.txt b/requirements.txt index 682e158..fbba2f8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -numpy>=1.24.3 +numpy>=1.24.3 opencv-python>=4.7.0.72 Pillow>=9.5.0 PySide6>=6.5.0 From 538785359d72ac086bdbde9ea5c863faaaa5ac7a Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Thu, 9 Nov 2023 17:13:13 -0600 Subject: [PATCH 040/127] Change background color fix --- Models/DraggableContainer.py | 9 ++++----- Widgets/Textbox.py | 4 ++-- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/Models/DraggableContainer.py b/Models/DraggableContainer.py index 94045e2..d290e59 100644 --- a/Models/DraggableContainer.py +++ b/Models/DraggableContainer.py @@ -331,10 +331,6 @@ def widgetAttributeChanged(self, changedWidgetAttribute, value): print("Change Font Color Event Called") child_widget.changeFontColorEvent(value) - elif hasattr(child_widget, "changeBackgroundColorEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.BackgroundColor): - print("Change Font Background Color Event Called") - child_widget.changeBackgroundColorEvent(value) - elif hasattr(child_widget, "changeTextboxColorEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.TextboxColor): print("Change Textbox Color Event Called") child_widget.changeTextboxColorEvent(value) @@ -348,4 +344,7 @@ def widgetAttributeChanged(self, changedWidgetAttribute, value): child_widget.bullet_list("bulletReg") elif hasattr(child_widget, "changeBulletEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.Bullet_Num): print("Change Bullet Event Called") - child_widget.bullet_list("bulletNum") \ No newline at end of file + child_widget.bullet_list("bulletNum") + elif hasattr(child_widget, "changeBackgroundColorEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.BackgroundColor): + print("Chang Background Color Event Called") + child_widget.changeBackgroundColorEvent(value) \ No newline at end of file diff --git a/Widgets/Textbox.py b/Widgets/Textbox.py index 52ec4a2..948b162 100644 --- a/Widgets/Textbox.py +++ b/Widgets/Textbox.py @@ -323,7 +323,7 @@ def changeFontColorEvent(self, new_font_color): cursor.setCharFormat(current_format) #to not get stuck on highlighted text - self.deselectText() + #self.deselectText() #self.setTextCursor(cursor) # Changes color of whole background @@ -342,7 +342,7 @@ def changeTextboxColorEvent(self, new_bg_color): current_format.setBackground(color) cursor.setCharFormat(current_format) - self.deselectText() + #self.deselectText() #self.setTextCursor(cursor) From 12bcde56720683cc5cf6b1afcd03d501ae807bf1 Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Thu, 9 Nov 2023 17:16:48 -0600 Subject: [PATCH 041/127] Empty containers properly delete --- Models/DraggableContainer.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/Models/DraggableContainer.py b/Models/DraggableContainer.py index d290e59..716462a 100644 --- a/Models/DraggableContainer.py +++ b/Models/DraggableContainer.py @@ -124,14 +124,6 @@ def mouseReleaseEvent(self, e: QMouseEvent): def leaveEvent(self, e: QMouseEvent): self.childWidget.setAttribute(Qt.WA_TransparentForMouseEvents, True) self.setStyleSheet("border: none;") - - # Delete this Draggable Container if childWidget says it's empty - # current bug: Draggable Container will not delete itself if you use multiselect while the container is still in focus - # new textbox but after creating an additional textbox, the dc will remove itself. - if not self.childWidget.hasFocus(): - if hasattr(self.childWidget, "checkEmpty"): - if self.childWidget.checkEmpty(): - editorSignalsInstance.widgetRemoved.emit(self) # If mouse leaves draggable container, set focus to the editor #if self.childWidget.hasFocus(): @@ -338,6 +330,10 @@ def widgetAttributeChanged(self, changedWidgetAttribute, value): elif hasattr(child_widget, "deselectText") and (changedWidgetAttribute == ChangedWidgetAttribute.LoseFocus): print("Clear Selection Slot Called") child_widget.deselectText() + if hasattr(self.childWidget, "checkEmpty"): + if self.childWidget.checkEmpty(): + print("Removing empty container") + editorSignalsInstance.widgetRemoved.emit(self) if self.hasFocus() or child_widget.hasFocus(): if hasattr(child_widget, "changeBulletEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.Bullet): print("Change Bullet Event Called") From b04842171c74034ba27e0b94ee0120e386e6aa7d Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Thu, 9 Nov 2023 20:01:53 -0600 Subject: [PATCH 042/127] Table toolbar button works again --- Models/DraggableContainer.py | 2 +- Modules/BuildUI.py | 2 +- Widgets/Textbox.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Models/DraggableContainer.py b/Models/DraggableContainer.py index 716462a..a68b8e6 100644 --- a/Models/DraggableContainer.py +++ b/Models/DraggableContainer.py @@ -330,7 +330,7 @@ def widgetAttributeChanged(self, changedWidgetAttribute, value): elif hasattr(child_widget, "deselectText") and (changedWidgetAttribute == ChangedWidgetAttribute.LoseFocus): print("Clear Selection Slot Called") child_widget.deselectText() - if hasattr(self.childWidget, "checkEmpty"): + if hasattr(self.childWidget, "checkEmpty") and isinstance(child_widget, QTextEdit): if self.childWidget.checkEmpty(): print("Removing empty container") editorSignalsInstance.widgetRemoved.emit(self) diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index 523040d..f6b4efd 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -73,7 +73,7 @@ def build_ui(editor): addSectionButton = QPushButton("Add Section") #add functionality e.g. addSectionButton.clcicked.connect(editor.add_section_function) leftSideLayout.addWidget(addSectionButton) - + def build_window(editor): editor.setWindowTitle("OpenNote") editor.setWindowIcon(QIcon('./Assets/OpenNoteLogo.png')) diff --git a/Widgets/Textbox.py b/Widgets/Textbox.py index 948b162..0f58a50 100644 --- a/Widgets/Textbox.py +++ b/Widgets/Textbox.py @@ -19,7 +19,7 @@ def __init__(self, x, y, w = 15, h = 30, t = ''): self.setTextColor('black') self.installEventFilter(self) - + def eventFilter(self, obj, event): if event.type() == QEvent.KeyPress and event.key() == Qt.Key_Tab: self.handleTabKey() From 2f168225e0c6aae6d0781e6e00755cf9d03e797b Mon Sep 17 00:00:00 2001 From: sillypenguin77 <67487654+sillypenguin77@users.noreply.github.com> Date: Sat, 11 Nov 2023 00:05:17 -0600 Subject: [PATCH 043/127] Updated Bullet Points - style cycling Updated bullet point list to cycle through styles when you hit tab for indentation --- Widgets/Textbox.py | 55 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 45 insertions(+), 10 deletions(-) diff --git a/Widgets/Textbox.py b/Widgets/Textbox.py index 143ed1d..adfb025 100644 --- a/Widgets/Textbox.py +++ b/Widgets/Textbox.py @@ -261,6 +261,7 @@ def bullet_list(self, bulletType): self.setTextCursor(cursor) self.setFocus() + else: listFormat = QTextListFormat() @@ -277,20 +278,54 @@ def bullet_list(self, bulletType): def handleTabKey(self): cursor = self.textCursor() + block = cursor.block() + block_format = block.blockFormat() textList = cursor.currentList() if textList: - # Check if there is a list at the current cursor position - current_block = cursor.block() # Get the current block - if cursor.atBlockStart() and current_block.text().strip() == '': - # Increase the indentation level for the current list item - blockFormat = current_block.blockFormat() - blockFormat.setIndent(blockFormat.indent() + 1) - cursor.setBlockFormat(blockFormat) - else: - pass - self.setTextCursor(cursor) + if cursor.atBlockStart() and block.text().strip() == '': + current_indent = block_format.indent() + + if current_indent == 0: + + block_format.setIndent(1) + cursor.setBlockFormat(block_format) + cursor.beginEditBlock() + list_format = QTextListFormat() + currentStyle = textList.format().style() + + if currentStyle == QTextListFormat.ListDisc: + list_format.setStyle(QTextListFormat.ListCircle) + if currentStyle == QTextListFormat.ListDecimal: + list_format.setStyle(QTextListFormat.ListLowerAlpha) + + cursor.createList(list_format) + cursor.endEditBlock() + + if current_indent == 1: + + block_format.setIndent(2) + cursor.setBlockFormat(block_format) + cursor.beginEditBlock() + list_format = QTextListFormat() + currentStyle = textList.format().style() + + if currentStyle == QTextListFormat.ListCircle: + list_format.setStyle(QTextListFormat.ListSquare) + if currentStyle == QTextListFormat.ListLowerAlpha: + list_format.setStyle(QTextListFormat.ListLowerRoman) + + cursor.createList(list_format) + cursor.endEditBlock() + + cursor.insertText('') + cursor.movePosition(QTextCursor.StartOfBlock) + self.setTextCursor(cursor) + + else: + #maybe add manual tab or diff functionality? + pass def changeFontSizeEvent(self, value): #todo: when textbox is in focus, font size on toolbar should match the font size of the text From 7410da521131d833c6cce1df2d9ff92cc1545a4b Mon Sep 17 00:00:00 2001 From: ldeltastreaml <70774713+ldeltastreaml@users.noreply.github.com> Date: Sat, 11 Nov 2023 12:15:02 -0600 Subject: [PATCH 044/127] Update PageView.py --- Views/PageView.py | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/Views/PageView.py b/Views/PageView.py index 212486c..29c1e3c 100644 --- a/Views/PageView.py +++ b/Views/PageView.py @@ -149,15 +149,26 @@ def eventFilter(self, source, event): return False def addPage(self, level: int, clickedIndex: QModelIndex): - # New page added at the top level (root) - newPageModel = PageModel('New Page', 0) # Assuming 0 as the parent UUID for the root + + # New page added under parent (what the user right clicked on) + parentPage = self.model.itemFromIndex(clickedIndex) + + # Check if the parent is a page + if isinstance(parentPage.data(), PageModel): + # Parent is a page, do not proceed + return + + parentPageUUID = parentPage.data().getUUID() + + # Create a new page model, set that as the data for the new page + newPageModel = PageModel('New Page', parentPageUUID) newPage = QStandardItem(newPageModel.title) newPage.setData(newPageModel) newPage.setEditable(False) - root.appendRow([newPage]) # Add to UI - self.pageModels.append(newPageModel) # Add to array of PageModel + parentPage.appendRow([newPage]) # Add to UI + self.pageModels.append(newPageModel) # Add to array of PageModel - self.tree.expandAll() + self.tree.expand(clickedIndex) # previous addPage would nest the page into the selected page (not a function in Onenote) ''' From 4181f67b8dd9cceccea59c15ac6c4e58abeb2611 Mon Sep 17 00:00:00 2001 From: ldeltastreaml <70774713+ldeltastreaml@users.noreply.github.com> Date: Sat, 11 Nov 2023 14:40:00 -0600 Subject: [PATCH 045/127] Correctly Implemented add page Add page now only adds pages under notebook. --- Views/PageView.py | 33 ++++++--------------------------- 1 file changed, 6 insertions(+), 27 deletions(-) diff --git a/Views/PageView.py b/Views/PageView.py index 29c1e3c..d5fe641 100644 --- a/Views/PageView.py +++ b/Views/PageView.py @@ -147,35 +147,14 @@ def eventFilter(self, source, event): if(event.button() == Qt.RightButton): return True return False - - def addPage(self, level: int, clickedIndex: QModelIndex): - - # New page added under parent (what the user right clicked on) - parentPage = self.model.itemFromIndex(clickedIndex) - - # Check if the parent is a page - if isinstance(parentPage.data(), PageModel): - # Parent is a page, do not proceed - return - - parentPageUUID = parentPage.data().getUUID() - - # Create a new page model, set that as the data for the new page - newPageModel = PageModel('New Page', parentPageUUID) - newPage = QStandardItem(newPageModel.title) - newPage.setData(newPageModel) - newPage.setEditable(False) - parentPage.appendRow([newPage]) # Add to UI - self.pageModels.append(newPageModel) # Add to array of PageModel - - self.tree.expand(clickedIndex) - - # previous addPage would nest the page into the selected page (not a function in Onenote) - ''' + def addPage(self, level: int, clickedIndex: QModelIndex): - # New page added under parent (what the user right clicked on) + # New page added to root + # will add functionallity for page groups which can be nested parentPage = self.model.itemFromIndex(clickedIndex) + while not parentPage.data().isRoot() + parentPage = parentPage.parent() parentPageUUID = parentPage.data().getUUID() # Create a new page model, set that as the data for the new page @@ -186,7 +165,7 @@ def addPage(self, level: int, clickedIndex: QModelIndex): parentPage.appendRow([newPage]) # Add to UI self.pageModels.append(newPageModel) # Add to array of PageModel - self.tree.expand(clickedIndex) ''' + self.tree.expand(clickedIndex) def deletePage(self, page: QStandardItem): deletePages = [page] From 7404047232f0e36a5c828e10aaf63a1a73788ad5 Mon Sep 17 00:00:00 2001 From: ldeltastreaml <70774713+ldeltastreaml@users.noreply.github.com> Date: Sat, 11 Nov 2023 16:25:34 -0600 Subject: [PATCH 046/127] Merge page function still in progress not finished or working hence why commented out --- Views/PageView.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Views/PageView.py b/Views/PageView.py index d5fe641..4f34ee3 100644 --- a/Views/PageView.py +++ b/Views/PageView.py @@ -134,6 +134,11 @@ def openMenu(self, position: QModelIndex): renamePageAction.triggered.connect(partial(self.renamePage, page)) #Current Issue: settings do not save because autosave only saves editor state + ''' + mergePageAction = menu.addAction(self.tr("Merge Pages")) + mergePageAction.triggered.connect(partial(self.mergePages, page)) + ''' + changeTextColorAction = menu.addAction(self.tr("Change Text Color")) changeTextColorAction.triggered.connect(partial(self.changeTextColor, page)) @@ -220,6 +225,7 @@ def changePage(self, current: QModelIndex, previous: QModelIndex): editorSignalsInstance.pageChanged.emit(newPageModel) # Tell the sectionView that the page has changed + ''' # Not sure if working as intended def mergePages(self): # Prompt the user to select two pages @@ -263,6 +269,7 @@ def mergePages(self): else: # If not exactly two pages are selected, show a warning or message QMessageBox.warning(self, 'Invalid Selection', 'Please select exactly two pages to merge.', QMessageBox.Ok) + ''' def changeTextColor(self, page: QStandardItem): color = QColorDialog.getColor() From 486e153a621433376d7aa8971aceb2ecb90d74ad Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Sat, 11 Nov 2023 16:32:01 -0600 Subject: [PATCH 047/127] link now adjusts size --- Widgets/Link.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Widgets/Link.py b/Widgets/Link.py index a6c41b1..48dc4ca 100644 --- a/Widgets/Link.py +++ b/Widgets/Link.py @@ -16,6 +16,7 @@ def __init__(self, x, y, l, d, w = 15, h = 30): self.setText(f'{d}') + self.adjustSize() #self.setParent(parent) @staticmethod From e0338c92a1fd39f4147a3c27acef5391e54a72a7 Mon Sep 17 00:00:00 2001 From: sillypenguin77 <67487654+sillypenguin77@users.noreply.github.com> Date: Wed, 15 Nov 2023 23:02:20 -0600 Subject: [PATCH 048/127] Hyperlink now part of textbox widget class Hyperlinks are no longer its own widget, instead they are part of the textbox widget class. This way we can still have text formatting on the textbox. --- Modules/BuildUI.py | 2 -- Views/EditorFrameView.py | 24 +++++++++++++++++++++--- Widgets/Link.py | 36 ------------------------------------ Widgets/Textbox.py | 14 +++++++++++++- 4 files changed, 34 insertions(+), 42 deletions(-) diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index 523040d..3d4821c 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -166,8 +166,6 @@ def build_toolbar(editor): hyperlink = build_action(toolbar, 'assets/icons/svg_hyperlink', "Hyperlink", "Hyperlink", False) hyperlink.triggered.connect(editor.frameView.toolbar_hyperlink) - bullets = build_action(toolbar, 'assets/icons/svg_bullets', "Bullets", "Bullets", False) - bullet_reg = build_action(toolbar, 'assets/icons/svg_bullets', "Bullet List", "Bullet List", False) bullet_reg.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Bullet, None)) diff --git a/Views/EditorFrameView.py b/Views/EditorFrameView.py index 90b13e5..e7537ae 100644 --- a/Views/EditorFrameView.py +++ b/Views/EditorFrameView.py @@ -15,7 +15,6 @@ from Widgets.Table import * from Modules.Clipboard import Clipboard from Modules.Undo import UndoHandler -from Widgets.Link import LinkWidget from Widgets.Link import LinkDialog @@ -100,6 +99,8 @@ def newWidgetOnSection(self, widgetClass, clickPos): editorSignalsInstance.changeMade.emit() dc.mouseDoubleClickEvent(None) # Enter the child widget after adding + return widget + except Exception as e: print("Error adding widget: ", e) @@ -197,11 +198,28 @@ def mousePressEvent(self, event): frame_menu.addAction(add_custom_widget) insert_Link = QAction("Insert Link", editor) - insert_Link.triggered.connect(lambda: self.newWidgetOnSection(LinkWidget,event.pos())) + insert_Link.triggered.connect(lambda: self.insertLink(event.pos())) frame_menu.addAction(insert_Link) frame_menu.exec(event.globalPos()) + def insertLink(self, clickPos): + link_dialog = LinkDialog() + result = link_dialog.exec_() + + if result == QDialog.Accepted: + link_address, display_text = link_dialog.get_link_data() + + textboxWidget = TextboxWidget.new(clickPos) + textboxWidget.insertTextLink(link_address, display_text) + + dc = DraggableContainer(textboxWidget, self) + dc.show() + + self.undoHandler.pushCreate(dc) + editorSignalsInstance.widgetAdded.emit(dc) + editorSignalsInstance.changeMade.emit() + def toolbar_table(self): print("toolbar_table pressed") clickPos = QPoint(0, 0) @@ -210,7 +228,7 @@ def toolbar_table(self): def toolbar_hyperlink(self): print("toolbar_hyperlink pressed") clickPos = QPoint(0, 0) - self.newWidgetOnSection(LinkWidget, clickPos) + self.insertLink(clickPos) def addCustomWidget(self, e): def getCustomWidgets(): diff --git a/Widgets/Link.py b/Widgets/Link.py index a6c41b1..0f5c4e3 100644 --- a/Widgets/Link.py +++ b/Widgets/Link.py @@ -5,42 +5,6 @@ FONT_SIZES = [7, 8, 9, 10, 11, 12, 13, 14, 18, 24, 36, 48, 64, 72, 96, 144, 288] - -class LinkWidget(QLabel): - def __init__(self, x, y, l, d, w = 15, h = 30): - super().__init__() - - self.setGeometry(x, y, w, h) - self.setStyleSheet('font-size: 20px') - self.setOpenExternalLinks(True) - - - self.setText(f'{d}') - #self.setParent(parent) - - @staticmethod - def new(clickPos: QPoint): - dialog = LinkDialog() - - if dialog.exec_() == QDialog.Accepted: - link_address, display_text = dialog.get_link_data() - - print(link_address) - - return LinkWidget(clickPos.x(), clickPos.y(), link_address, display_text) - - def __getstate__(self): - data = {} - - data['geometry'] = self.parentWidget().geometry() - #data['content'] = self.toHtml() - data['stylesheet'] = self.styleSheet() - return data - - def __setstate__(self, data): - self.__init__(data['geometry'].x(), data['geometry'].y(), data['geometry'].width(), data['geometry'].height(), data['content']) - self.setStyleSheet(data['stylesheet']) - class LinkDialog(QDialog): def __init__(self): super().__init__() diff --git a/Widgets/Textbox.py b/Widgets/Textbox.py index adfb025..287c5a4 100644 --- a/Widgets/Textbox.py +++ b/Widgets/Textbox.py @@ -3,9 +3,13 @@ from PySide6.QtWidgets import * from Modules.EditorSignals import editorSignalsInstance + +#from Widgets.Link import LinkWidget +from Widgets.Link import LinkDialog + FONT_SIZES = [7, 8, 9, 10, 11, 12, 13, 14, 18, 24, 36, 48, 64, 72, 96, 144, 288] -class TextboxWidget(QTextEdit): +class TextboxWidget(QTextBrowser): def __init__(self, x, y, w = 15, h = 30, t = ''): super().__init__() @@ -18,6 +22,7 @@ def __init__(self, x, y, w = 15, h = 30, t = ''): self.setStyleSheet('background-color: rgba(0, 0, 0, 0);') self.setTextColor('black') + self.setTextInteractionFlags(Qt.TextEditorInteraction | Qt.TextBrowserInteraction) self.installEventFilter(self) @@ -397,3 +402,10 @@ def changeBulletEvent(self): #put bullet function here print("bullet press") + def insertTextLink(self, link_address, display_text): + self.setOpenExternalLinks(True) + link_html = f'{display_text}' + cursor = self.textCursor() + cursor.insertHtml(link_html) + QDesktopServices.openUrl(link_html) + From de14f7a3e21955b844286fa53bc8000ad3c1107a Mon Sep 17 00:00:00 2001 From: ldeltastreaml <70774713+ldeltastreaml@users.noreply.github.com> Date: Thu, 16 Nov 2023 12:35:08 -0600 Subject: [PATCH 049/127] Changed File paths Changed File paths to work with linux --- Modules/BuildUI.py | 36 +++++++++++++++--------------- Widgets/Paint.py | 55 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 18 deletions(-) create mode 100644 Widgets/Paint.py diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index 523040d..f95a97e 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -85,23 +85,23 @@ def build_menubar(editor): file = editor.menuBar().addMenu('&File') plugins = editor.menuBar().addMenu('&Plugins') - new_file = build_action(editor, 'assets/icons/svg_file_open', 'New Notebook', 'New Notebook', False) + new_file = build_action(editor, './Assets/icons/svg_file_open', 'New Notebook', 'New Notebook', False) new_file.setShortcut(QKeySequence.StandardKey.New) new_file.triggered.connect(lambda: new(editor)) - open_file = build_action(editor, 'assets/icons/svg_file_open', 'Open Notebook', 'Open Notebook', False) + open_file = build_action(editor, './Assets/icons/svg_file_open', 'Open Notebook', 'Open Notebook', False) open_file.setShortcut(QKeySequence.StandardKey.Open) open_file.triggered.connect(lambda: load(editor)) - save_file = build_action(editor, 'assets/icons/svg_file_save', 'Save Notebook', 'Save Notebook', False) + save_file = build_action(editor, './Assets/icons/svg_file_save', 'Save Notebook', 'Save Notebook', False) save_file.setShortcut(QKeySequence.StandardKey.Save) save_file.triggered.connect(lambda: save(editor)) - save_fileAs = build_action(editor, 'assets/icons/svg_file_save', 'Save Notebook As...', 'Save Notebook As', False) + save_fileAs = build_action(editor, './Assets/icons/svg_file_save', 'Save Notebook As...', 'Save Notebook As', False) save_fileAs.setShortcut(QKeySequence.fromString('Ctrl+Shift+S')) save_fileAs.triggered.connect(lambda: saveAs(editor)) - add_widget = build_action(editor, 'assets/icons/svg_question', 'Add Custom Widget', 'Add Custom Widget', False) + add_widget = build_action(editor, './Assets/icons/svg_question', 'Add Custom Widget', 'Add Custom Widget', False) file.addActions([new_file, open_file, save_file, save_fileAs]) plugins.addActions([add_widget]) @@ -116,11 +116,11 @@ def build_toolbar(editor): spacer = QWidget() spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) - toolbar_undo = build_action(toolbar, 'assets/icons/svg_undo', "undo", "undo", False) + toolbar_undo = build_action(toolbar, './Assets/icons/svg_undo', "undo", "undo", False) toolbar_undo.triggered.connect(editor.frameView.triggerUndo) - redo = build_action(toolbar, 'assets/icons/svg_redo', "redo", "redo", False) + redo = build_action(toolbar, './Assets/icons/svg_redo', "redo", "redo", False) @@ -139,39 +139,39 @@ def build_toolbar(editor): # - Alternates between working and not working # - Textboxes do not remember settings like if font is toggled or current font size - bgColor = build_action(toolbar, 'assets/icons/svg_font_bucket', "Background Color", "Background Color", False) + bgColor = build_action(toolbar, './Assets/icons/svg_font_bucket', "Background Color", "Background Color", False) #bgColor.triggered.connect(lambda: openGetColorDialog(purpose = "background")) #current bug, alternates between activating and not working when using bgColor.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.BackgroundColor, QColorDialog.getColor())) - textboxColor = build_action(toolbar, 'assets/icons/svg_textboxColor', "Text Box Color", "Text Box Color", True) + textboxColor = build_action(toolbar, './Assets/icons/svg_textboxColor', "Text Box Color", "Text Box Color", True) textboxColor.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.TextboxColor, QColorDialog.getColor())) #defines font color icon appearance and settings - fontColor = build_action(toolbar, 'assets/icons/svg_font_color', "Font Color", "Font Color", False) + fontColor = build_action(toolbar, './Assets/icons/svg_font_color', "Font Color", "Font Color", False) fontColor.triggered.connect(lambda: openGetColorDialog(purpose = "font")) - bold = build_action(toolbar, 'assets/icons/bold', "Bold", "Bold", True) + bold = build_action(toolbar, './Assets/icons/bold', "Bold", "Bold", True) bold.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontBold, None)) - italic = build_action(toolbar, 'assets/icons/italic.svg', "Italic", "Italic", True) + italic = build_action(toolbar, './Assets/icons/italic.svg', "Italic", "Italic", True) italic.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontItalic, None)) - underline = build_action(toolbar, 'assets/icons/underline.svg', "Underline", "Underline", True) + underline = build_action(toolbar, './Assets/icons/underline.svg', "Underline", "Underline", True) underline.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontUnderline, None)) - table = build_action(toolbar, 'assets/icons/svg_table', "Create Table", "Create Table", False) + table = build_action(toolbar, './Assets/icons/svg_table', "Create Table", "Create Table", False) table.triggered.connect(editor.frameView.toolbar_table) - hyperlink = build_action(toolbar, 'assets/icons/svg_hyperlink', "Hyperlink", "Hyperlink", False) + hyperlink = build_action(toolbar, './Assets/icons/svg_hyperlink', "Hyperlink", "Hyperlink", False) hyperlink.triggered.connect(editor.frameView.toolbar_hyperlink) - bullets = build_action(toolbar, 'assets/icons/svg_bullets', "Bullets", "Bullets", False) + bullets = build_action(toolbar, './Assets/icons/svg_bullets', "Bullets", "Bullets", False) - bullet_reg = build_action(toolbar, 'assets/icons/svg_bullets', "Bullet List", "Bullet List", False) + bullet_reg = build_action(toolbar, './Assets/icons/svg_bullets', "Bullet List", "Bullet List", False) bullet_reg.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Bullet, None)) - bullet_num = build_action(toolbar, 'assets/icons/svg_bullet_number', "Bullet List", "Bullet List", False) + bullet_num = build_action(toolbar, './Assets/icons/svg_bullet_number', "Bullet List", "Bullet List", False) bullet_num.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Bullet_Num, None)) ''' diff --git a/Widgets/Paint.py b/Widgets/Paint.py new file mode 100644 index 0000000..ac4943a --- /dev/null +++ b/Widgets/Paint.py @@ -0,0 +1,55 @@ +from PySide6.QtCore import * +from PySide6.QtGui import * +from PySide6.QtWidgets import * +from Paint_UI import * + +COLORS = [# 17 undertones https://lospec.com/palette-list/17undertones +'#000000', '#141923', '#414168', '#3a7fa7', '#35e3e3', '#8fd970', '#5ebb49', +'#458352', '#dcd37b', '#fffee5', '#ffd035', '#cc9245', '#a15c3e', '#a42f3b', +'#f45b7a', '#c24998', '#81588d', '#bcb0c2', '#ffffff'] + +class Canvas(QtWidgets.QLabel): + + def __init__(self): + super().__init__() + pixmap = QtGui.QPixmap(600, 300) + pixmap.fill(Qt.GlobalColor.white) + self.setPixmap(canvas) + + self.last_x, self.last_y = None, None + self.pen_color = QtGui.QColor('#000000') + + def set_pen_color(self, c): + self.pen_color = QtGui.QColor(c) + + def mouseMoveEvent(self, e): + if self.last_x is None: # First event. + self.last_x = e.position().x() + self.last_y = e.position().y() + return # Ignore the first time. + + canvas = self.label.pixmap() + painter = QtGui.QPainter(canvas) + p = painter.pen() + p.setWidth(4) + p.setColor(self.pen_color) + painter.setPen(p) + painter.drawLine(self.last_x, self.last_y, e.position().x(), e.position().y()) + painter.end() + self.label.setPixmap(canvas) + + # Update the origin for next time. + self.last_x = e.position().x() + self.last_y = e.position().y() + + def mouseReleaseEvent(self, e): + self.last_x = None + self.last_y = None + +class QPaletteButton(QtWidgets.QPushButton): + + def __init__(self, color): + super().__init__() + self.setFixedSize(QtCore.QSize(24,24)) + self.color = color + self.setStyleSheet("background-color: %s;" % color) \ No newline at end of file From 177d2897b7ca808b21b83f3f2fcc61d76d3a16d1 Mon Sep 17 00:00:00 2001 From: ldeltastreaml <70774713+ldeltastreaml@users.noreply.github.com> Date: Thu, 16 Nov 2023 12:37:12 -0600 Subject: [PATCH 050/127] Changed icon file paths Changed file paths to work with linux --- Modules/BuildUI.py | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index f95a97e..523040d 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -85,23 +85,23 @@ def build_menubar(editor): file = editor.menuBar().addMenu('&File') plugins = editor.menuBar().addMenu('&Plugins') - new_file = build_action(editor, './Assets/icons/svg_file_open', 'New Notebook', 'New Notebook', False) + new_file = build_action(editor, 'assets/icons/svg_file_open', 'New Notebook', 'New Notebook', False) new_file.setShortcut(QKeySequence.StandardKey.New) new_file.triggered.connect(lambda: new(editor)) - open_file = build_action(editor, './Assets/icons/svg_file_open', 'Open Notebook', 'Open Notebook', False) + open_file = build_action(editor, 'assets/icons/svg_file_open', 'Open Notebook', 'Open Notebook', False) open_file.setShortcut(QKeySequence.StandardKey.Open) open_file.triggered.connect(lambda: load(editor)) - save_file = build_action(editor, './Assets/icons/svg_file_save', 'Save Notebook', 'Save Notebook', False) + save_file = build_action(editor, 'assets/icons/svg_file_save', 'Save Notebook', 'Save Notebook', False) save_file.setShortcut(QKeySequence.StandardKey.Save) save_file.triggered.connect(lambda: save(editor)) - save_fileAs = build_action(editor, './Assets/icons/svg_file_save', 'Save Notebook As...', 'Save Notebook As', False) + save_fileAs = build_action(editor, 'assets/icons/svg_file_save', 'Save Notebook As...', 'Save Notebook As', False) save_fileAs.setShortcut(QKeySequence.fromString('Ctrl+Shift+S')) save_fileAs.triggered.connect(lambda: saveAs(editor)) - add_widget = build_action(editor, './Assets/icons/svg_question', 'Add Custom Widget', 'Add Custom Widget', False) + add_widget = build_action(editor, 'assets/icons/svg_question', 'Add Custom Widget', 'Add Custom Widget', False) file.addActions([new_file, open_file, save_file, save_fileAs]) plugins.addActions([add_widget]) @@ -116,11 +116,11 @@ def build_toolbar(editor): spacer = QWidget() spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) - toolbar_undo = build_action(toolbar, './Assets/icons/svg_undo', "undo", "undo", False) + toolbar_undo = build_action(toolbar, 'assets/icons/svg_undo', "undo", "undo", False) toolbar_undo.triggered.connect(editor.frameView.triggerUndo) - redo = build_action(toolbar, './Assets/icons/svg_redo', "redo", "redo", False) + redo = build_action(toolbar, 'assets/icons/svg_redo', "redo", "redo", False) @@ -139,39 +139,39 @@ def build_toolbar(editor): # - Alternates between working and not working # - Textboxes do not remember settings like if font is toggled or current font size - bgColor = build_action(toolbar, './Assets/icons/svg_font_bucket', "Background Color", "Background Color", False) + bgColor = build_action(toolbar, 'assets/icons/svg_font_bucket', "Background Color", "Background Color", False) #bgColor.triggered.connect(lambda: openGetColorDialog(purpose = "background")) #current bug, alternates between activating and not working when using bgColor.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.BackgroundColor, QColorDialog.getColor())) - textboxColor = build_action(toolbar, './Assets/icons/svg_textboxColor', "Text Box Color", "Text Box Color", True) + textboxColor = build_action(toolbar, 'assets/icons/svg_textboxColor', "Text Box Color", "Text Box Color", True) textboxColor.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.TextboxColor, QColorDialog.getColor())) #defines font color icon appearance and settings - fontColor = build_action(toolbar, './Assets/icons/svg_font_color', "Font Color", "Font Color", False) + fontColor = build_action(toolbar, 'assets/icons/svg_font_color', "Font Color", "Font Color", False) fontColor.triggered.connect(lambda: openGetColorDialog(purpose = "font")) - bold = build_action(toolbar, './Assets/icons/bold', "Bold", "Bold", True) + bold = build_action(toolbar, 'assets/icons/bold', "Bold", "Bold", True) bold.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontBold, None)) - italic = build_action(toolbar, './Assets/icons/italic.svg', "Italic", "Italic", True) + italic = build_action(toolbar, 'assets/icons/italic.svg', "Italic", "Italic", True) italic.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontItalic, None)) - underline = build_action(toolbar, './Assets/icons/underline.svg', "Underline", "Underline", True) + underline = build_action(toolbar, 'assets/icons/underline.svg', "Underline", "Underline", True) underline.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontUnderline, None)) - table = build_action(toolbar, './Assets/icons/svg_table', "Create Table", "Create Table", False) + table = build_action(toolbar, 'assets/icons/svg_table', "Create Table", "Create Table", False) table.triggered.connect(editor.frameView.toolbar_table) - hyperlink = build_action(toolbar, './Assets/icons/svg_hyperlink', "Hyperlink", "Hyperlink", False) + hyperlink = build_action(toolbar, 'assets/icons/svg_hyperlink', "Hyperlink", "Hyperlink", False) hyperlink.triggered.connect(editor.frameView.toolbar_hyperlink) - bullets = build_action(toolbar, './Assets/icons/svg_bullets', "Bullets", "Bullets", False) + bullets = build_action(toolbar, 'assets/icons/svg_bullets', "Bullets", "Bullets", False) - bullet_reg = build_action(toolbar, './Assets/icons/svg_bullets', "Bullet List", "Bullet List", False) + bullet_reg = build_action(toolbar, 'assets/icons/svg_bullets', "Bullet List", "Bullet List", False) bullet_reg.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Bullet, None)) - bullet_num = build_action(toolbar, './Assets/icons/svg_bullet_number', "Bullet List", "Bullet List", False) + bullet_num = build_action(toolbar, 'assets/icons/svg_bullet_number', "Bullet List", "Bullet List", False) bullet_num.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Bullet_Num, None)) ''' From 18ed29eabd6c600487332f892d95d95efe76effb Mon Sep 17 00:00:00 2001 From: ldeltastreaml <70774713+ldeltastreaml@users.noreply.github.com> Date: Thu, 16 Nov 2023 12:45:14 -0600 Subject: [PATCH 051/127] Changed Icon File Path Changed to the correct one??? not sure why i pushed what it was before --- Modules/BuildUI.py | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index 523040d..f95a97e 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -85,23 +85,23 @@ def build_menubar(editor): file = editor.menuBar().addMenu('&File') plugins = editor.menuBar().addMenu('&Plugins') - new_file = build_action(editor, 'assets/icons/svg_file_open', 'New Notebook', 'New Notebook', False) + new_file = build_action(editor, './Assets/icons/svg_file_open', 'New Notebook', 'New Notebook', False) new_file.setShortcut(QKeySequence.StandardKey.New) new_file.triggered.connect(lambda: new(editor)) - open_file = build_action(editor, 'assets/icons/svg_file_open', 'Open Notebook', 'Open Notebook', False) + open_file = build_action(editor, './Assets/icons/svg_file_open', 'Open Notebook', 'Open Notebook', False) open_file.setShortcut(QKeySequence.StandardKey.Open) open_file.triggered.connect(lambda: load(editor)) - save_file = build_action(editor, 'assets/icons/svg_file_save', 'Save Notebook', 'Save Notebook', False) + save_file = build_action(editor, './Assets/icons/svg_file_save', 'Save Notebook', 'Save Notebook', False) save_file.setShortcut(QKeySequence.StandardKey.Save) save_file.triggered.connect(lambda: save(editor)) - save_fileAs = build_action(editor, 'assets/icons/svg_file_save', 'Save Notebook As...', 'Save Notebook As', False) + save_fileAs = build_action(editor, './Assets/icons/svg_file_save', 'Save Notebook As...', 'Save Notebook As', False) save_fileAs.setShortcut(QKeySequence.fromString('Ctrl+Shift+S')) save_fileAs.triggered.connect(lambda: saveAs(editor)) - add_widget = build_action(editor, 'assets/icons/svg_question', 'Add Custom Widget', 'Add Custom Widget', False) + add_widget = build_action(editor, './Assets/icons/svg_question', 'Add Custom Widget', 'Add Custom Widget', False) file.addActions([new_file, open_file, save_file, save_fileAs]) plugins.addActions([add_widget]) @@ -116,11 +116,11 @@ def build_toolbar(editor): spacer = QWidget() spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) - toolbar_undo = build_action(toolbar, 'assets/icons/svg_undo', "undo", "undo", False) + toolbar_undo = build_action(toolbar, './Assets/icons/svg_undo', "undo", "undo", False) toolbar_undo.triggered.connect(editor.frameView.triggerUndo) - redo = build_action(toolbar, 'assets/icons/svg_redo', "redo", "redo", False) + redo = build_action(toolbar, './Assets/icons/svg_redo', "redo", "redo", False) @@ -139,39 +139,39 @@ def build_toolbar(editor): # - Alternates between working and not working # - Textboxes do not remember settings like if font is toggled or current font size - bgColor = build_action(toolbar, 'assets/icons/svg_font_bucket', "Background Color", "Background Color", False) + bgColor = build_action(toolbar, './Assets/icons/svg_font_bucket', "Background Color", "Background Color", False) #bgColor.triggered.connect(lambda: openGetColorDialog(purpose = "background")) #current bug, alternates between activating and not working when using bgColor.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.BackgroundColor, QColorDialog.getColor())) - textboxColor = build_action(toolbar, 'assets/icons/svg_textboxColor', "Text Box Color", "Text Box Color", True) + textboxColor = build_action(toolbar, './Assets/icons/svg_textboxColor', "Text Box Color", "Text Box Color", True) textboxColor.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.TextboxColor, QColorDialog.getColor())) #defines font color icon appearance and settings - fontColor = build_action(toolbar, 'assets/icons/svg_font_color', "Font Color", "Font Color", False) + fontColor = build_action(toolbar, './Assets/icons/svg_font_color', "Font Color", "Font Color", False) fontColor.triggered.connect(lambda: openGetColorDialog(purpose = "font")) - bold = build_action(toolbar, 'assets/icons/bold', "Bold", "Bold", True) + bold = build_action(toolbar, './Assets/icons/bold', "Bold", "Bold", True) bold.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontBold, None)) - italic = build_action(toolbar, 'assets/icons/italic.svg', "Italic", "Italic", True) + italic = build_action(toolbar, './Assets/icons/italic.svg', "Italic", "Italic", True) italic.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontItalic, None)) - underline = build_action(toolbar, 'assets/icons/underline.svg', "Underline", "Underline", True) + underline = build_action(toolbar, './Assets/icons/underline.svg', "Underline", "Underline", True) underline.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontUnderline, None)) - table = build_action(toolbar, 'assets/icons/svg_table', "Create Table", "Create Table", False) + table = build_action(toolbar, './Assets/icons/svg_table', "Create Table", "Create Table", False) table.triggered.connect(editor.frameView.toolbar_table) - hyperlink = build_action(toolbar, 'assets/icons/svg_hyperlink', "Hyperlink", "Hyperlink", False) + hyperlink = build_action(toolbar, './Assets/icons/svg_hyperlink', "Hyperlink", "Hyperlink", False) hyperlink.triggered.connect(editor.frameView.toolbar_hyperlink) - bullets = build_action(toolbar, 'assets/icons/svg_bullets', "Bullets", "Bullets", False) + bullets = build_action(toolbar, './Assets/icons/svg_bullets', "Bullets", "Bullets", False) - bullet_reg = build_action(toolbar, 'assets/icons/svg_bullets', "Bullet List", "Bullet List", False) + bullet_reg = build_action(toolbar, './Assets/icons/svg_bullets', "Bullet List", "Bullet List", False) bullet_reg.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Bullet, None)) - bullet_num = build_action(toolbar, 'assets/icons/svg_bullet_number', "Bullet List", "Bullet List", False) + bullet_num = build_action(toolbar, './Assets/icons/svg_bullet_number', "Bullet List", "Bullet List", False) bullet_num.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Bullet_Num, None)) ''' From 1a65f6b980582779159282d57a0e2ae95591bf51 Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Fri, 1 Dec 2023 16:37:56 -0600 Subject: [PATCH 052/127] tables and images can be dragged again --- Models/DraggableContainer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Models/DraggableContainer.py b/Models/DraggableContainer.py index a68b8e6..cb87c3f 100644 --- a/Models/DraggableContainer.py +++ b/Models/DraggableContainer.py @@ -104,7 +104,7 @@ def mousePressEvent(self, e: QMouseEvent): self.childWidget.setAttribute(Qt.WA_TransparentForMouseEvents, False) self.childWidget.setFocus() - self.childWidget.setCursorPosition(e) + #self.childWidget.setCursorPosition(e) # need to add code for setting cursor to the end of the textbox # On double click, focus on child and make mouse events pass through this container to child @@ -343,4 +343,4 @@ def widgetAttributeChanged(self, changedWidgetAttribute, value): child_widget.bullet_list("bulletNum") elif hasattr(child_widget, "changeBackgroundColorEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.BackgroundColor): print("Chang Background Color Event Called") - child_widget.changeBackgroundColorEvent(value) \ No newline at end of file + child_widget.changeBackgroundColorEvent(value) From 3f06bf6ff4189ce60597410e375386854d9d3af2 Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Mon, 4 Dec 2023 19:22:26 -0600 Subject: [PATCH 053/127] Rotate left and right along with flip added --- Assets/icons/svg_crop.svg | 4 ++ Assets/icons/svg_flip_horizontal.svg | 6 +++ Assets/icons/svg_flip_vertical.svg | 6 +++ Assets/icons/svg_rotate_left.svg | 4 ++ Assets/icons/svg_rotate_right.svg | 4 ++ Models/DraggableContainer.py | 14 ++++++- Views/PageView.py | 2 +- Widgets/Image.py | 61 ++++++++++++++++++++++++++++ Widgets/Table.py | 2 +- 9 files changed, 100 insertions(+), 3 deletions(-) create mode 100644 Assets/icons/svg_crop.svg create mode 100644 Assets/icons/svg_flip_horizontal.svg create mode 100644 Assets/icons/svg_flip_vertical.svg create mode 100644 Assets/icons/svg_rotate_left.svg create mode 100644 Assets/icons/svg_rotate_right.svg diff --git a/Assets/icons/svg_crop.svg b/Assets/icons/svg_crop.svg new file mode 100644 index 0000000..5c0d05f --- /dev/null +++ b/Assets/icons/svg_crop.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Assets/icons/svg_flip_horizontal.svg b/Assets/icons/svg_flip_horizontal.svg new file mode 100644 index 0000000..f58662e --- /dev/null +++ b/Assets/icons/svg_flip_horizontal.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Assets/icons/svg_flip_vertical.svg b/Assets/icons/svg_flip_vertical.svg new file mode 100644 index 0000000..f43b4d0 --- /dev/null +++ b/Assets/icons/svg_flip_vertical.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Assets/icons/svg_rotate_left.svg b/Assets/icons/svg_rotate_left.svg new file mode 100644 index 0000000..1999b02 --- /dev/null +++ b/Assets/icons/svg_rotate_left.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Assets/icons/svg_rotate_right.svg b/Assets/icons/svg_rotate_right.svg new file mode 100644 index 0000000..f87f18a --- /dev/null +++ b/Assets/icons/svg_rotate_right.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Models/DraggableContainer.py b/Models/DraggableContainer.py index cb87c3f..66d460b 100644 --- a/Models/DraggableContainer.py +++ b/Models/DraggableContainer.py @@ -104,7 +104,13 @@ def mousePressEvent(self, e: QMouseEvent): self.childWidget.setAttribute(Qt.WA_TransparentForMouseEvents, False) self.childWidget.setFocus() - #self.childWidget.setCursorPosition(e) + + #brings text cursor to cursor position but causes exception + '''if isinstance(self.childWidget, TextboxWidget): + self.childWidget.setCursorPosition(e) + else: + # Handle the case where self.childWidget is not a TextBox + pass''' # need to add code for setting cursor to the end of the textbox # On double click, focus on child and make mouse events pass through this container to child @@ -344,3 +350,9 @@ def widgetAttributeChanged(self, changedWidgetAttribute, value): elif hasattr(child_widget, "changeBackgroundColorEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.BackgroundColor): print("Chang Background Color Event Called") child_widget.changeBackgroundColorEvent(value) + def connectTableSignals(self, tableWidget): + tableWidget.rowAdded.connect(self.resizeTable) + def resizeTable(self): + self.resize(self.childWidget.size()) + self.newGeometry.emit(self.geometry()) + self.parentWidget().repaint() diff --git a/Views/PageView.py b/Views/PageView.py index d807da0..5531397 100644 --- a/Views/PageView.py +++ b/Views/PageView.py @@ -160,7 +160,7 @@ def addPage(self, level: int, clickedIndex: QModelIndex): # will add functionallity for page groups which can be nested parentPage = self.model.itemFromIndex(clickedIndex) - while not parentPage.data().isRoot() + while not parentPage.data().isRoot(): parentPage = parentPage.parent() parentPageUUID = parentPage.data().getUUID() diff --git a/Widgets/Image.py b/Widgets/Image.py index 64971e1..beeb6c5 100644 --- a/Widgets/Image.py +++ b/Widgets/Image.py @@ -70,3 +70,64 @@ def __getstate__(self): def __setstate__(self, state): self.__init__(state['geometry'].x(), state['geometry'].y(), state['geometry'].width(), state['geometry'].height(), state['image_matrix']) + + def customMenuItems(self): + def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): + action = QAction(QIcon(icon_path), action_name, parent) + action.setStatusTip(set_status_tip) + action.setCheckable(set_checkable) + return action + + + toolbarBottom = QToolBar() + toolbarBottom.setIconSize(QSize(16, 16)) + toolbarBottom.setMovable(False) + + #crop = build_action(toolbarTop, 'assets/icons/svg_crop', "Crop", "Crop", False) + + flipHorizontal = build_action(toolbarBottom, 'assets/icons/svg_flip_horizontal', "Horizontal Flip", "Horizontal Flip", False) + flipHorizontal.triggered.connect(self.flipHorizontal) + flipVertical = build_action(toolbarBottom, 'assets/icons/svg_flip_vertical', "Vertical Flip", "Vertical Flip", False) + flipVertical.triggered.connect(self.flipVertical) + + rotateLeftAction = build_action(toolbarBottom, 'assets/icons/svg_rotate_left', "Rotate 90 degrees Left", "Rotate 90 degrees Left", False) + rotateLeftAction.triggered.connect(self.rotate90Left) + rotateRightAction = build_action(toolbarBottom, 'assets/icons/svg_rotate_right', "Rotate 90 degrees Right", "Rotate 90 degrees Right", False) + rotateRightAction.triggered.connect(self.rotate90Right) + + + toolbarBottom.addActions([rotateLeftAction, rotateRightAction, flipHorizontal, flipVertical]) + + qwaBottom = QWidgetAction(self) + qwaBottom.setDefaultWidget(toolbarBottom) + + return [qwaBottom] + + def flipVertical(self): + # Flip the image matrix vertically using OpenCV + self.image_matrix = cv2.flip(self.image_matrix, 0) + self.updatePixmap() + + def flipHorizontal(self): + # Flip the image matrix horizontally using OpenCV + self.image_matrix = cv2.flip(self.image_matrix, 1) + self.updatePixmap() + + def rotate90Left(self): + # Rotate the image matrix 90 degrees to the left using OpenCV + self.image_matrix = cv2.rotate(self.image_matrix, cv2.ROTATE_90_COUNTERCLOCKWISE) + self.updatePixmap() + def rotate90Right(self): + # Rotate the image matrix 90 degrees to the right using OpenCV + self.image_matrix = cv2.rotate(self.image_matrix, cv2.ROTATE_90_CLOCKWISE) + self.updatePixmap() + + def updatePixmap(self): + # Update the QImage and QPixmap + matrix_height, matrix_width, _ = self.image_matrix.shape + bytes_per_line = 3 * matrix_width + q_image = QImage(self.image_matrix.data, matrix_width, matrix_height, bytes_per_line, QImage.Format_BGR888) + self.q_pixmap = QPixmap(q_image) + + # Update the displayed pixmap + self.setPixmap(self.q_pixmap.scaled(self.w, self.h, Qt.KeepAspectRatio, Qt.SmoothTransformation)) \ No newline at end of file diff --git a/Widgets/Table.py b/Widgets/Table.py index 4d7768f..30907aa 100644 --- a/Widgets/Table.py +++ b/Widgets/Table.py @@ -53,7 +53,7 @@ def customMenuItems(self): addRow.triggered.connect(self.addRow) addCol = QAction("Add Column", self) - addCol.triggered.connect(self.addCol) + addCol.triggered.connect(self.addCol) return [addRow, addCol] From e038f9d90d81b06bee2e8a8460f42045298d6c4f Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Mon, 4 Dec 2023 21:16:26 -0600 Subject: [PATCH 054/127] link and table update links and tables now move to center of screen upon creation --- Models/DraggableContainer.py | 1 + Views/EditorFrameView.py | 16 ++++++++++++++-- Widgets/Table.py | 4 +++- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/Models/DraggableContainer.py b/Models/DraggableContainer.py index 66d460b..b35bb5e 100644 --- a/Models/DraggableContainer.py +++ b/Models/DraggableContainer.py @@ -70,6 +70,7 @@ def eventFilter(self, obj, e): # If child widget resized itsself, resize this drag container, not ideal bc child resizes on hover if isinstance(e, QResizeEvent): + print("resize event for draggable container") self.resize(self.childWidget.size()) return False diff --git a/Views/EditorFrameView.py b/Views/EditorFrameView.py index 90b13e5..4856759 100644 --- a/Views/EditorFrameView.py +++ b/Views/EditorFrameView.py @@ -202,14 +202,26 @@ def mousePressEvent(self, event): frame_menu.exec(event.globalPos()) + def center_of_screen(self): + editor_frame_geometry = self.editorFrame.geometry() + print(f"editor_frame_geometry.width() is {editor_frame_geometry.width()}") + print(f"editor_frame_geometry.height() is {editor_frame_geometry.height()}") + center_x = (editor_frame_geometry.width() - 200) // 2 + center_y = (editor_frame_geometry.height() - 200) // 2 + return center_x, center_y + + + def toolbar_table(self): print("toolbar_table pressed") - clickPos = QPoint(0, 0) + center_x, center_y = self.center_of_screen() + clickPos = QPoint(center_x, center_y) self.newWidgetOnSection(TableWidget, clickPos) def toolbar_hyperlink(self): print("toolbar_hyperlink pressed") - clickPos = QPoint(0, 0) + center_x, center_y = self.center_of_screen() + clickPos = QPoint(center_x, center_y) self.newWidgetOnSection(LinkWidget, clickPos) def addCustomWidget(self, e): diff --git a/Widgets/Table.py b/Widgets/Table.py index 30907aa..82921a1 100644 --- a/Widgets/Table.py +++ b/Widgets/Table.py @@ -46,7 +46,9 @@ def new(clickPos: QPoint): if dialog.exec_() == QDialog.Accepted: rows_input, cols_input = dialog.get_table_data() print(f"rows input is {rows_input} cols_input is {cols_input}") - return TableWidget(clickPos.x(), clickPos.y(), 200, 200, int(rows_input), int(cols_input)) + table_widget = TableWidget(clickPos.x(), clickPos.y(), 200, 200, int(rows_input), int(cols_input)) + + return table_widget def customMenuItems(self): addRow = QAction("Add Row", self) From 2496c2b541bbf2628fca56b2f42fcc1610cdca99 Mon Sep 17 00:00:00 2001 From: ldeltastreaml <70774713+ldeltastreaml@users.noreply.github.com> Date: Tue, 5 Dec 2023 14:42:35 -0600 Subject: [PATCH 055/127] Paint.py deletion from branch Paint.py is not ready for release, and i want to remove it from main --- Widgets/Paint.py | 55 ------------------------------------------------ 1 file changed, 55 deletions(-) delete mode 100644 Widgets/Paint.py diff --git a/Widgets/Paint.py b/Widgets/Paint.py deleted file mode 100644 index ac4943a..0000000 --- a/Widgets/Paint.py +++ /dev/null @@ -1,55 +0,0 @@ -from PySide6.QtCore import * -from PySide6.QtGui import * -from PySide6.QtWidgets import * -from Paint_UI import * - -COLORS = [# 17 undertones https://lospec.com/palette-list/17undertones -'#000000', '#141923', '#414168', '#3a7fa7', '#35e3e3', '#8fd970', '#5ebb49', -'#458352', '#dcd37b', '#fffee5', '#ffd035', '#cc9245', '#a15c3e', '#a42f3b', -'#f45b7a', '#c24998', '#81588d', '#bcb0c2', '#ffffff'] - -class Canvas(QtWidgets.QLabel): - - def __init__(self): - super().__init__() - pixmap = QtGui.QPixmap(600, 300) - pixmap.fill(Qt.GlobalColor.white) - self.setPixmap(canvas) - - self.last_x, self.last_y = None, None - self.pen_color = QtGui.QColor('#000000') - - def set_pen_color(self, c): - self.pen_color = QtGui.QColor(c) - - def mouseMoveEvent(self, e): - if self.last_x is None: # First event. - self.last_x = e.position().x() - self.last_y = e.position().y() - return # Ignore the first time. - - canvas = self.label.pixmap() - painter = QtGui.QPainter(canvas) - p = painter.pen() - p.setWidth(4) - p.setColor(self.pen_color) - painter.setPen(p) - painter.drawLine(self.last_x, self.last_y, e.position().x(), e.position().y()) - painter.end() - self.label.setPixmap(canvas) - - # Update the origin for next time. - self.last_x = e.position().x() - self.last_y = e.position().y() - - def mouseReleaseEvent(self, e): - self.last_x = None - self.last_y = None - -class QPaletteButton(QtWidgets.QPushButton): - - def __init__(self, color): - super().__init__() - self.setFixedSize(QtCore.QSize(24,24)) - self.color = color - self.setStyleSheet("background-color: %s;" % color) \ No newline at end of file From fddb8e917a491787da2c0db86a97faced57ee905 Mon Sep 17 00:00:00 2001 From: ldeltastreaml <70774713+ldeltastreaml@users.noreply.github.com> Date: Tue, 5 Dec 2023 23:32:54 -0600 Subject: [PATCH 056/127] Screensnip fix for Linux systems Added error messages for screensnip.py as well as bugfixing its functionality in ubuntu --- Modules/Screensnip.py | 74 ++++++++++++++++++++++------------------ Views/EditorFrameView.py | 1 + 2 files changed, 41 insertions(+), 34 deletions(-) diff --git a/Modules/Screensnip.py b/Modules/Screensnip.py index 86950eb..c316e58 100644 --- a/Modules/Screensnip.py +++ b/Modules/Screensnip.py @@ -13,76 +13,82 @@ class SnippingWidget(QWidget): def __init__(self): super(SnippingWidget, self).__init__() - self.setWindowFlags(Qt.WindowStaysOnTopHint) + self.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.FramelessWindowHint) self.parent = None self.screen = QApplication.instance().primaryScreen() self.setGeometry(0, 0, self.screen.size().width(), self.screen.size().height()) - self.begin = QPoint() - self.end = QPoint() + self.begin = self.end = QPoint() self.onSnippingCompleted = None self.event_pos = None def start(self, event_pos): print("SnippingWidget.start") SnippingWidget.is_snipping = True - self.setWindowOpacity(0.3) QApplication.setOverrideCursor(QCursor(Qt.CrossCursor)) self.event_pos = event_pos self.show() print("SnippingWidget.start done") def paintEvent(self, event): + qp = QPainter(self) if SnippingWidget.is_snipping: brush_color = (128, 128, 255, 100) lw = 3 - opacity = 0.3 - else: - self.begin = QPoint() - self.end = QPoint() - brush_color = (0, 0, 0, 0) - lw = 0 - opacity = 0 - - self.setWindowOpacity(opacity) - qp = QPainter(self) - qp.setPen(QPen(QColor('black'), lw)) - qp.setBrush(QColor(*brush_color)) - rect = QRectF(self.begin, self.end) - qp.drawRect(rect) + qp.setPen(QPen(QColor('black'), lw)) + qp.setBrush(QColor(*brush_color)) + rect = QRectF(self.begin, self.end) + qp.drawRect(rect) def mousePressEvent(self, event): - self.begin = event.pos() - self.end = self.begin - self.update() + try: + self.begin = event.pos() + self.end = self.begin + self.update() + except Exception as e: + print(f"Error handling mouse press event: {e}") def mouseMoveEvent(self, event): - self.end = event.pos() - self.update() + try: + self.end = event.pos() + self.update() + except Exception as e: + print(f"Error handling mouse move event: {e}") def mouseReleaseEvent(self, event): SnippingWidget.is_snipping = False QApplication.restoreOverrideCursor() - x1 = min(self.begin.x(), self.end.x()) - y1 = min(self.begin.y(), self.end.y()) - x2 = max(self.begin.x(), self.end.x()) - y2 = max(self.begin.y(), self.end.y()) + x1, y1, x2, y2 = self.getSnipCoordinates() self.repaint() QApplication.processEvents() - - if platform == "darwin": - img = ImageGrab.grab(bbox=( (x1 ) * 2, (y1 + 55 ) * 2, (x2 ) * 2, (y2 + 55) * 2)) - else: - img = ImageGrab.grab(bbox=(x1 + 10, y1 + 30, x2 + 10, y2 + 40)) - - + + try: + if platform == "darwin": + img = ImageGrab.grab(bbox=( (x1 ) * 2, (y1 + 55 ) * 2, (x2 ) * 2, (y2 + 55) * 2)) + else: + img = ImageGrab.grab(bbox=(x1 + 10, y1 + 30, x2 + 10, y2 + 40)) + except Exception as e: + print(f"Error grabbing screenshot: {e}") + img = None try: img = cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR) except: + print(f"Error converting screenshot to NumPy array: {e}") img = None if self.onSnippingCompleted is not None: self.onSnippingCompleted(img) self.close() + + def getSnipCoordinates(self): + try: + x1 = min(self.begin.x(), self.end.x()) + y1 = min(self.begin.y(), self.end.y()) + x2 = max(self.begin.x(), self.end.x()) + y2 = max(self.begin.y(), self.end.y()) + return x1, y1, x2, y2 + except Exception as e: + print(f"Error getting snip coordinates {e}") + return 0, 0, 0, 0 \ No newline at end of file diff --git a/Views/EditorFrameView.py b/Views/EditorFrameView.py index 90b13e5..2731632 100644 --- a/Views/EditorFrameView.py +++ b/Views/EditorFrameView.py @@ -72,6 +72,7 @@ def pasteWidget(self, clickPos): def snipScreen(self, clickPos): def onSnippingCompleted(imageMatrix): # Called after screensnipper gets image self.editor.setWindowState(Qt.WindowActive) + self.editor.setWindowFlags(QT.WindowStaysOnTopHint) self.editor.showMaximized() if imageMatrix is None: return From de46c31dc7e9df3967c1ba64830e8065ed429b10 Mon Sep 17 00:00:00 2001 From: ldeltastreaml <70774713+ldeltastreaml@users.noreply.github.com> Date: Tue, 5 Dec 2023 23:55:06 -0600 Subject: [PATCH 057/127] Miss spellings Spelling mistakes and forgot a line of code --- Modules/Screensnip.py | 1 + Views/EditorFrameView.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Modules/Screensnip.py b/Modules/Screensnip.py index c316e58..e52c194 100644 --- a/Modules/Screensnip.py +++ b/Modules/Screensnip.py @@ -14,6 +14,7 @@ class SnippingWidget(QWidget): def __init__(self): super(SnippingWidget, self).__init__() self.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.FramelessWindowHint) + self.setAttribute(Qt.WA_TranslucentBackground) self.parent = None self.screen = QApplication.instance().primaryScreen() self.setGeometry(0, 0, self.screen.size().width(), self.screen.size().height()) diff --git a/Views/EditorFrameView.py b/Views/EditorFrameView.py index 2731632..b3ccb09 100644 --- a/Views/EditorFrameView.py +++ b/Views/EditorFrameView.py @@ -72,7 +72,7 @@ def pasteWidget(self, clickPos): def snipScreen(self, clickPos): def onSnippingCompleted(imageMatrix): # Called after screensnipper gets image self.editor.setWindowState(Qt.WindowActive) - self.editor.setWindowFlags(QT.WindowStaysOnTopHint) + self.editor.setWindowFlags(Qt.WindowStaysOnTopHint) self.editor.showMaximized() if imageMatrix is None: return From 2aee33f54a1c6cff7f6167f994af77be3e43faf7 Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Wed, 6 Dec 2023 10:08:12 -0600 Subject: [PATCH 058/127] Added alignment with right click context menu --- Assets/icons/svg_align_center.svg | 4 + Assets/icons/svg_align_left.svg | 4 + Assets/icons/svg_align_right.svg | 4 + Widgets/Textbox.py | 257 ++++++++++++++++++++---------- 4 files changed, 183 insertions(+), 86 deletions(-) create mode 100644 Assets/icons/svg_align_center.svg create mode 100644 Assets/icons/svg_align_left.svg create mode 100644 Assets/icons/svg_align_right.svg diff --git a/Assets/icons/svg_align_center.svg b/Assets/icons/svg_align_center.svg new file mode 100644 index 0000000..92d15d7 --- /dev/null +++ b/Assets/icons/svg_align_center.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Assets/icons/svg_align_left.svg b/Assets/icons/svg_align_left.svg new file mode 100644 index 0000000..a04bce0 --- /dev/null +++ b/Assets/icons/svg_align_left.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Assets/icons/svg_align_right.svg b/Assets/icons/svg_align_right.svg new file mode 100644 index 0000000..79600b9 --- /dev/null +++ b/Assets/icons/svg_align_right.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Widgets/Textbox.py b/Widgets/Textbox.py index c3fe81e..c97f2c0 100644 --- a/Widgets/Textbox.py +++ b/Widgets/Textbox.py @@ -5,22 +5,22 @@ FONT_SIZES = [7, 8, 9, 10, 11, 12, 13, 14, 18, 24, 36, 48, 64, 72, 96, 144, 288] + class TextboxWidget(QTextEdit): - def __init__(self, x, y, w = 15, h = 30, t = ''): + def __init__(self, x, y, w=15, h=30, t=""): super().__init__() - self.setGeometry(x, y, w, h) # This sets geometry of DraggableObject + self.setGeometry(x, y, w, h) # This sets geometry of DraggableObject self.setText(t) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.textChanged.connect(self.textChangedEvent) - self.setStyleSheet('background-color: rgba(0, 0, 0, 0);') - self.setTextColor('black') - + self.setStyleSheet("background-color: rgba(0, 0, 0, 0);") + self.setTextColor("black") self.installEventFilter(self) - + def eventFilter(self, obj, event): if event.type() == QEvent.KeyPress and event.key() == Qt.Key_Tab: self.handleTabKey() @@ -28,12 +28,11 @@ def eventFilter(self, obj, event): return super(TextboxWidget, self).eventFilter(obj, event) - #upon clicking somewhere else, remove selection of highlighted text + # upon clicking somewhere else, remove selection of highlighted text def setCursorPosition(self, event): print("SET TEXT CURSOR POSITION TO MOUSE POSITION") cursor = self.cursorForPosition(event.pos()) self.setTextCursor(cursor) - def textChangedEvent(self): if len(self.toPlainText()) < 2: @@ -46,14 +45,20 @@ def new(clickPos: QPoint): def __getstate__(self): data = {} - data['geometry'] = self.parentWidget().geometry() - data['content'] = self.toHtml() - data['stylesheet'] = self.styleSheet() + data["geometry"] = self.parentWidget().geometry() + data["content"] = self.toHtml() + data["stylesheet"] = self.styleSheet() return data def __setstate__(self, data): - self.__init__(data['geometry'].x(), data['geometry'].y(), data['geometry'].width(), data['geometry'].height(), data['content']) - self.setStyleSheet(data['stylesheet']) + self.__init__( + data["geometry"].x(), + data["geometry"].y(), + data["geometry"].width(), + data["geometry"].height(), + data["content"], + ) + self.setStyleSheet(data["stylesheet"]) def checkEmpty(self): if len(self.toPlainText()) < 1: @@ -76,41 +81,132 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): toolbarBottom.setMovable(False) font = QFontComboBox() - font.currentFontChanged.connect(lambda x: self.setCurrentFontCustom(font.currentFont() if x else self.currentFont())) + font.currentFontChanged.connect( + lambda x: self.setCurrentFontCustom( + font.currentFont() if x else self.currentFont() + ) + ) size = QComboBox() size.addItems([str(fs) for fs in FONT_SIZES]) - size.currentIndexChanged.connect(lambda x: self.setFontPointSizeCustom(FONT_SIZES[x] if x else self.fontPointSize())) - - bold = build_action(toolbarBottom, 'assets/icons/svg_font_bold', "Bold", "Bold", True) + size.currentIndexChanged.connect( + lambda x: self.setFontPointSizeCustom( + FONT_SIZES[x] if x else self.fontPointSize() + ) + ) + + align_left = build_action( + toolbarBottom, + "assets/icons/svg_align_left", + "Align Left", + "Align Left", + True, + ) + align_left.triggered.connect(lambda x: self.setAlignment(Qt.AlignLeft)) + + align_center = build_action( + toolbarBottom, + "assets/icons/svg_align_center", + "Align Center", + "Align Center", + True, + ) + align_center.triggered.connect(lambda x: self.setAlignment(Qt.AlignCenter)) + + align_right = build_action( + toolbarBottom, + "assets/icons/svg_align_right", + "Align Right", + "Align Right", + True, + ) + align_right.triggered.connect(lambda x: self.setAlignment(Qt.AlignRight)) + + bold = build_action( + toolbarBottom, "assets/icons/svg_font_bold", "Bold", "Bold", True + ) bold.toggled.connect(lambda x: self.setFontWeightCustom(700 if x else 500)) - italic = build_action(toolbarBottom, 'assets/icons/svg_font_italic', "Italic", "Italic", True) + italic = build_action( + toolbarBottom, "assets/icons/svg_font_italic", "Italic", "Italic", True + ) italic.toggled.connect(lambda x: self.setFontItalicCustom(True if x else False)) - - - underline = build_action(toolbarBottom, 'assets/icons/svg_font_underline', "Underline", "Underline", True) - underline.toggled.connect(lambda x: self.setFontUnderlineCustom(True if x else False)) - - fontColor = build_action(toolbarBottom, 'assets/icons/svg_font_color', "Font Color", "Font Color", False) - fontColor.triggered.connect(lambda: self.setTextColorCustom(QColorDialog.getColor())) - bgColor = build_action(toolbarBottom, 'assets/icons/svg_font_bucket', "Background Color", "Background Color", False) - #bgColor.triggered.connect(lambda: self.setBackgroundColor(QColorDialog.getColor())) - bgColor.triggered.connect(lambda: self.changeBackgroundColorEvent(QColorDialog.getColor())) - textboxColor = build_action(toolbarBottom, 'assets/icons/svg_textboxColor', "Background Color", "Background Color", False) - textboxColor.triggered.connect(lambda: self.changeTextboxColorEvent(QColorDialog.getColor())) - - bullets = build_action(toolbarBottom, 'assets/icons/svg_bullets', "Bullets", "Bullets", True) + underline = build_action( + toolbarBottom, + "assets/icons/svg_font_underline", + "Underline", + "Underline", + True, + ) + underline.toggled.connect( + lambda x: self.setFontUnderlineCustom(True if x else False) + ) + + fontColor = build_action( + toolbarBottom, + "assets/icons/svg_font_color", + "Font Color", + "Font Color", + False, + ) + fontColor.triggered.connect( + lambda: self.setTextColorCustom(QColorDialog.getColor()) + ) + + bgColor = build_action( + toolbarBottom, + "assets/icons/svg_font_bucket", + "Background Color", + "Background Color", + False, + ) + # bgColor.triggered.connect(lambda: self.setBackgroundColor(QColorDialog.getColor())) + bgColor.triggered.connect( + lambda: self.changeBackgroundColorEvent(QColorDialog.getColor()) + ) + textboxColor = build_action( + toolbarBottom, + "assets/icons/svg_textboxColor", + "Background Color", + "Background Color", + False, + ) + textboxColor.triggered.connect( + lambda: self.changeTextboxColorEvent(QColorDialog.getColor()) + ) + + bullets = build_action( + toolbarBottom, "assets/icons/svg_bullets", "Bullets", "Bullets", True + ) bullets.toggled.connect(lambda: self.bullet_list("bulletReg")) - bullets_num = build_action(toolbarBottom, 'assets/icons/svg_bullet_number', "Bullets Num", "Bullets Num", True) + bullets_num = build_action( + toolbarBottom, + "assets/icons/svg_bullet_number", + "Bullets Num", + "Bullets Num", + True, + ) bullets_num.toggled.connect(lambda: self.bullet_list("bulletNum")) toolbarTop.addWidget(font) toolbarTop.addWidget(size) - toolbarBottom.addActions([bold, italic, underline, fontColor, bgColor, bullets, bullets_num]) + toolbarBottom.addActions( + [ + align_left, + align_center, + align_right, + bold, + italic, + underline, + fontColor, + bgColor, + bullets, + bullets_num, + ] + ) qwaTop = QWidgetAction(self) qwaTop.setDefaultWidget(toolbarTop) @@ -147,7 +243,7 @@ def setTextColorCustom(self, color): def setBackgroundColor(self, color: QColor): rgb = color.getRgb() - self.setStyleSheet(f'background-color: rgb({rgb[0]}, {rgb[1]}, {rgb[2]});') + self.setStyleSheet(f"background-color: rgb({rgb[0]}, {rgb[1]}, {rgb[2]});") # If no text is selected, apply to all, else apply to selection def applyToAllIfNoSelection(self, func): @@ -172,6 +268,7 @@ def applyToAllIfNoSelection(self, func): def attributeChangedSlot(attribute, value): if attribute == editorSignalsInstance.ChangedWidgetAttribute.FontBold: print("Font Bold Signal") + def slot_action2(self): print("Action 2 Triggered") font = QFont() @@ -181,60 +278,58 @@ def slot_action2(self): def changeFontSizeEvent(self, weight): print("changeFontSizeEvent Called") self.setFontWeightCustom(weight) - - #for communicating the signal editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontItalic, None) - #current issue for Event Functions: Only affects highlighted + # for communicating the signal editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontItalic, None) + # current issue for Event Functions: Only affects highlighted def changeFontItalicEvent(self): - cursor = self.textCursor() current_format = cursor.charFormat() - - #Checks if currently selected text is italics + + # Checks if currently selected text is italics is_italic = current_format.fontItalic() - - #toggles the italics + + # toggles the italics current_format.setFontItalic(not is_italic) - #Apply modified format to selected text + # Apply modified format to selected text cursor.setCharFormat(current_format) - #Update text cursor with modified format + # Update text cursor with modified format self.setTextCursor(cursor) def changeFontBoldEvent(self): cursor = self.textCursor() current_format = cursor.charFormat() - - #Checks if currently selected text is bold + + # Checks if currently selected text is bold is_bold = current_format.fontWeight() == 700 - - #toggles the italics + + # toggles the italics if is_bold: current_format.setFontWeight(500) else: current_format.setFontWeight(700) - #Apply modified format to selected text + # Apply modified format to selected text cursor.setCharFormat(current_format) - #Update text cursor with modified format + # Update text cursor with modified format self.setTextCursor(cursor) def changeFontUnderlineEvent(self): cursor = self.textCursor() current_format = cursor.charFormat() - - #Checks if currently selected text is bold + + # Checks if currently selected text is bold is_underlined = current_format.fontUnderline() - #toggles the underline + # toggles the underline current_format.setFontUnderline(not is_underlined) - #Apply modified format to selected text + # Apply modified format to selected text cursor.setCharFormat(current_format) - #Update text cursor with modified format + # Update text cursor with modified format self.setTextCursor(cursor) def bullet_list(self, bulletType): @@ -247,8 +342,7 @@ def bullet_list(self, bulletType): removed = 0 for i in range(textList.count()): item = textList.item(i - removed) - if (item.position() <= end and - item.position() + item.length() > start): + if item.position() <= end and item.position() + item.length() > start: textList.remove(item) blockCursor = QTextCursor(item) blockFormat = blockCursor.blockFormat() @@ -265,9 +359,9 @@ def bullet_list(self, bulletType): else: listFormat = QTextListFormat() - if bulletType == 'bulletNum': + if bulletType == "bulletNum": style = QTextListFormat.ListDecimal - if bulletType == 'bulletReg': + if bulletType == "bulletReg": style = QTextListFormat.ListDisc listFormat.setStyle(style) @@ -283,12 +377,10 @@ def handleTabKey(self): textList = cursor.currentList() if textList: - - if cursor.atBlockStart() and block.text().strip() == '': + if cursor.atBlockStart() and block.text().strip() == "": current_indent = block_format.indent() if current_indent == 0: - block_format.setIndent(1) cursor.setBlockFormat(block_format) cursor.beginEditBlock() @@ -304,7 +396,6 @@ def handleTabKey(self): cursor.endEditBlock() if current_indent == 1: - block_format.setIndent(2) cursor.setBlockFormat(block_format) cursor.beginEditBlock() @@ -319,27 +410,25 @@ def handleTabKey(self): cursor.createList(list_format) cursor.endEditBlock() - cursor.insertText('') + cursor.insertText("") cursor.movePosition(QTextCursor.StartOfBlock) self.setTextCursor(cursor) else: - #maybe add manual tab or diff functionality? + # maybe add manual tab or diff functionality? pass def changeFontSizeEvent(self, value): - #todo: when textbox is in focus, font size on toolbar should match the font size of the text + # todo: when textbox is in focus, font size on toolbar should match the font size of the text cursor = self.textCursor() current_format = cursor.charFormat() - + current_format.setFontPointSize(value) cursor.setCharFormat(current_format) self.setTextCursor(cursor) - - def changeFontEvent(self, font_style): cursor = self.textCursor() current_format = cursor.charFormat() @@ -347,12 +436,10 @@ def changeFontEvent(self, font_style): cursor.setCharFormat(current_format) - self.setTextCursor(cursor) - # Changes font text color + # Changes font text color def changeFontColorEvent(self, new_font_color): - cursor = self.textCursor() current_format = cursor.charFormat() @@ -360,18 +447,18 @@ def changeFontColorEvent(self, new_font_color): current_format.setForeground(color) cursor.setCharFormat(current_format) - - #to not get stuck on highlighted text - #self.deselectText() - #self.setTextCursor(cursor) + + # to not get stuck on highlighted text + # self.deselectText() + # self.setTextCursor(cursor) # Changes color of whole background def changeBackgroundColorEvent(self, color: QColor): - #if self.hasFocus(): + # if self.hasFocus(): rgb = color.getRgb() - self.setStyleSheet(f'background-color: rgb({rgb[0]}, {rgb[1]}, {rgb[2]});') + self.setStyleSheet(f"background-color: rgb({rgb[0]}, {rgb[1]}, {rgb[2]});") self.deselectText() - + # Changes textbox background color def changeTextboxColorEvent(self, new_bg_color): cursor = self.textCursor() @@ -381,19 +468,17 @@ def changeTextboxColorEvent(self, new_bg_color): current_format.setBackground(color) cursor.setCharFormat(current_format) - #self.deselectText() + # self.deselectText() - #self.setTextCursor(cursor) + # self.setTextCursor(cursor) # Used to remove text highlighting def deselectText(self): - cursor = self.textCursor() cursor.clearSelection() self.setTextCursor(cursor) - + # Adds bullet list to text def changeBulletEvent(self): - #put bullet function here + # put bullet function here print("bullet press") - From 443302c5d5b29f20596a328be4c9a1b39884a7c6 Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Wed, 6 Dec 2023 10:32:52 -0600 Subject: [PATCH 059/127] Revert "Text alignment functionality" This reverts commit 9781e5b4d94f93c5531ce7c6534df65df94acb9c, reversing changes made to f573aa88c5e85cc93caf04f246bc6eb3e47d6910. --- Assets/icons/svg_align_center.svg | 4 - Assets/icons/svg_align_left.svg | 4 - Assets/icons/svg_align_right.svg | 4 - Assets/icons/svg_bullet_number.svg | 6 - Assets/icons/svg_bullets.svg | 19 -- Assets/icons/svg_crop.svg | 4 - Assets/icons/svg_flip_horizontal.svg | 6 - Assets/icons/svg_flip_vertical.svg | 6 - Assets/icons/svg_hyperlink.svg | 11 - Assets/icons/svg_question.svg | 26 -- Assets/icons/svg_redo.svg | 7 - Assets/icons/svg_rotate_left.svg | 4 - Assets/icons/svg_rotate_right.svg | 4 - Assets/icons/svg_table.svg | 4 - Assets/icons/svg_textboxColor.svg | 14 - Assets/icons/svg_undo.svg | 7 - Models/DraggableContainer.py | 128 +++----- Models/Editor.py | 1 + Modules/BuildUI.py | 149 +-------- Modules/EditorSignals.py | 9 - Modules/Load.py | 7 +- Modules/Screensnip.py | 75 ++--- Modules/Undo.py | 2 - Views/EditorFrameView.py | 81 +---- Views/PageView.py | 86 +---- Widgets/Image.py | 61 ---- Widgets/Link.py | 77 ----- Widgets/Table.py | 59 +--- Widgets/Textbox.py | 455 ++++----------------------- requirements.txt | Bin 135 -> 276 bytes 30 files changed, 159 insertions(+), 1161 deletions(-) delete mode 100644 Assets/icons/svg_align_center.svg delete mode 100644 Assets/icons/svg_align_left.svg delete mode 100644 Assets/icons/svg_align_right.svg delete mode 100644 Assets/icons/svg_bullet_number.svg delete mode 100644 Assets/icons/svg_bullets.svg delete mode 100644 Assets/icons/svg_crop.svg delete mode 100644 Assets/icons/svg_flip_horizontal.svg delete mode 100644 Assets/icons/svg_flip_vertical.svg delete mode 100644 Assets/icons/svg_hyperlink.svg delete mode 100644 Assets/icons/svg_question.svg delete mode 100644 Assets/icons/svg_redo.svg delete mode 100644 Assets/icons/svg_rotate_left.svg delete mode 100644 Assets/icons/svg_rotate_right.svg delete mode 100644 Assets/icons/svg_table.svg delete mode 100644 Assets/icons/svg_textboxColor.svg delete mode 100644 Assets/icons/svg_undo.svg delete mode 100644 Widgets/Link.py diff --git a/Assets/icons/svg_align_center.svg b/Assets/icons/svg_align_center.svg deleted file mode 100644 index 92d15d7..0000000 --- a/Assets/icons/svg_align_center.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/Assets/icons/svg_align_left.svg b/Assets/icons/svg_align_left.svg deleted file mode 100644 index a04bce0..0000000 --- a/Assets/icons/svg_align_left.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/Assets/icons/svg_align_right.svg b/Assets/icons/svg_align_right.svg deleted file mode 100644 index 79600b9..0000000 --- a/Assets/icons/svg_align_right.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/Assets/icons/svg_bullet_number.svg b/Assets/icons/svg_bullet_number.svg deleted file mode 100644 index 610e2f1..0000000 --- a/Assets/icons/svg_bullet_number.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - number-list-line - - - \ No newline at end of file diff --git a/Assets/icons/svg_bullets.svg b/Assets/icons/svg_bullets.svg deleted file mode 100644 index fb527c0..0000000 --- a/Assets/icons/svg_bullets.svg +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/Assets/icons/svg_crop.svg b/Assets/icons/svg_crop.svg deleted file mode 100644 index 5c0d05f..0000000 --- a/Assets/icons/svg_crop.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/Assets/icons/svg_flip_horizontal.svg b/Assets/icons/svg_flip_horizontal.svg deleted file mode 100644 index f58662e..0000000 --- a/Assets/icons/svg_flip_horizontal.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/Assets/icons/svg_flip_vertical.svg b/Assets/icons/svg_flip_vertical.svg deleted file mode 100644 index f43b4d0..0000000 --- a/Assets/icons/svg_flip_vertical.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/Assets/icons/svg_hyperlink.svg b/Assets/icons/svg_hyperlink.svg deleted file mode 100644 index 930588a..0000000 --- a/Assets/icons/svg_hyperlink.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/Assets/icons/svg_question.svg b/Assets/icons/svg_question.svg deleted file mode 100644 index f0e4806..0000000 --- a/Assets/icons/svg_question.svg +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/Assets/icons/svg_redo.svg b/Assets/icons/svg_redo.svg deleted file mode 100644 index a96d7e5..0000000 --- a/Assets/icons/svg_redo.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/Assets/icons/svg_rotate_left.svg b/Assets/icons/svg_rotate_left.svg deleted file mode 100644 index 1999b02..0000000 --- a/Assets/icons/svg_rotate_left.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/Assets/icons/svg_rotate_right.svg b/Assets/icons/svg_rotate_right.svg deleted file mode 100644 index f87f18a..0000000 --- a/Assets/icons/svg_rotate_right.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/Assets/icons/svg_table.svg b/Assets/icons/svg_table.svg deleted file mode 100644 index 9c21ff1..0000000 --- a/Assets/icons/svg_table.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/Assets/icons/svg_textboxColor.svg b/Assets/icons/svg_textboxColor.svg deleted file mode 100644 index 1cc087a..0000000 --- a/Assets/icons/svg_textboxColor.svg +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/Assets/icons/svg_undo.svg b/Assets/icons/svg_undo.svg deleted file mode 100644 index d463200..0000000 --- a/Assets/icons/svg_undo.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/Models/DraggableContainer.py b/Models/DraggableContainer.py index b35bb5e..57b248d 100644 --- a/Models/DraggableContainer.py +++ b/Models/DraggableContainer.py @@ -54,8 +54,6 @@ def __init__(self, childWidget, editorFrame): if hasattr(self.childWidget, "newGeometryEvent"): self.newGeometry.connect(childWidget.newGeometryEvent) editorSignalsInstance.widgetAttributeChanged.connect(self.widgetAttributeChanged) - - def setChildWidget(self, childWidget): if childWidget: self.childWidget = childWidget @@ -66,11 +64,10 @@ def setChildWidget(self, childWidget): self.vLayout.addWidget(childWidget) self.vLayout.setContentsMargins(0,0,0,0) - def eventFilter(self, obj, e): + def eventFilter(self, obj, event): # If child widget resized itsself, resize this drag container, not ideal bc child resizes on hover - if isinstance(e, QResizeEvent): - print("resize event for draggable container") + if isinstance(event, QResizeEvent): self.resize(self.childWidget.size()) return False @@ -83,7 +80,7 @@ def popupShow(self, pt: QPoint): def mousePressEvent(self, e: QMouseEvent): self.position = QPoint(e.globalX() - self.geometry().x(), e.globalY() - self.geometry().y()) - print("Draggable Container MOUSE PRESS") + print("DC MOUSE PRESS") # Undo related # self.old_x = e.globalX() @@ -96,27 +93,15 @@ def mousePressEvent(self, e: QMouseEvent): print("NOT EDIT") return if not e.buttons() and Qt.LeftButton: - print("Draggable Container GOT MOUSE PRESS") + print("DC GOT MOUSE PRESS") self.setCursorShape(e.pos()) return True if e.button() == Qt.RightButton: self.popupShow(e.pos()) e.accept() - self.childWidget.setAttribute(Qt.WA_TransparentForMouseEvents, False) - self.childWidget.setFocus() - - #brings text cursor to cursor position but causes exception - '''if isinstance(self.childWidget, TextboxWidget): - self.childWidget.setCursorPosition(e) - else: - # Handle the case where self.childWidget is not a TextBox - pass''' - # need to add code for setting cursor to the end of the textbox - # On double click, focus on child and make mouse events pass through this container to child def mouseDoubleClickEvent(self, e: QMouseEvent): - print("MOUSEDOUBLECLICKEVENT FROM DRAGGABLE CONTAINER") self.childWidget.setAttribute(Qt.WA_TransparentForMouseEvents, False) self.childWidget.setFocus() return @@ -131,10 +116,15 @@ def mouseReleaseEvent(self, e: QMouseEvent): def leaveEvent(self, e: QMouseEvent): self.childWidget.setAttribute(Qt.WA_TransparentForMouseEvents, True) self.setStyleSheet("border: none;") - - # If mouse leaves draggable container, set focus to the editor - #if self.childWidget.hasFocus(): - # self.setFocus()''' + + # Delete this DC if childWidget says it's empty + if hasattr(self.childWidget, "checkEmpty"): + if self.childWidget.checkEmpty(): + editorSignalsInstance.widgetRemoved.emit(self) + + # ??? + if self.childWidget.hasFocus(): + self.setFocus() def buildDragContainerMenu(self): @@ -227,7 +217,7 @@ def setCursorShape(self, e_pos: QPoint): self.setCursor(QCursor(Qt.SizeVerCursor)) self.mode = Mode.RESIZEB else: - self.setCursor(QCursor(Qt.ArrowCursor)) + self.setCursor(QCursor(Qt. ArrowCursor)) self.mode = Mode.MOVE # Determine how to handle the mouse being moved inside the box @@ -291,69 +281,29 @@ def mouseMoveEvent(self, e: QMouseEvent): self.parentWidget().repaint() self.newGeometry.emit(self.geometry()) - # Pass the e to the child widget if this container is focused, and childwidget implements the method to receive it - # Uses signals to pass to draggable container, which then checks if child has the function, then calls the function. - # Look at toolbar in BuildUI.py to see examples - # example signal that doesn't have a value: 'italic.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontItalic, None))' - # example signal with a value: 'font_family.currentFontChanged.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Font, font_family.currentFont().family()))' - # When adding a function to a child widget, use 'if self.hasFocus():' to ensure the function applies only to the focused widget. Else it will apply to all widgets of the same type + # Pass the event to the child widget if this container is focuesd, and childwidget implements the method to receive it def widgetAttributeChanged(self, changedWidgetAttribute, value): - #print(f"changedWidgetAttribute is {changedWidgetAttribute} and value is {value}") - child_widget = self.childWidget - - #this if statement is no longer needed because highlighted text deselects after clicking on an area in the editor thats not the in focus textbox - #if self.hasFocus() or child_widget.hasFocus(): - #only the focused container will print this line - print(f"changedWidgetAttribute is {changedWidgetAttribute} and value is {value}") - - if hasattr(child_widget, "changeFontSizeEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.FontSize): - print("Change Font Size Event Called") - child_widget.changeFontSizeEvent(value) - - elif hasattr(child_widget, "changeFontBoldEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.FontBold): - print("Change Font Bold Event Called") - child_widget.changeFontBoldEvent() - - elif hasattr(child_widget, "changeFontItalicEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.FontItalic): - print("Change Font Italic Event Called") - child_widget.changeFontItalicEvent() - - elif hasattr(child_widget, "changeFontUnderlineEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.FontUnderline): - print("Change Font Underline Event Called") - child_widget.changeFontUnderlineEvent() - - elif hasattr(child_widget, "changeFontEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.Font): - print("Change Font Family Event Called") - child_widget.changeFontEvent(value) - - elif hasattr(child_widget, "changeFontColorEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.FontColor): - print("Change Font Color Event Called") - child_widget.changeFontColorEvent(value) - - elif hasattr(child_widget, "changeTextboxColorEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.TextboxColor): - print("Change Textbox Color Event Called") - child_widget.changeTextboxColorEvent(value) - - elif hasattr(child_widget, "deselectText") and (changedWidgetAttribute == ChangedWidgetAttribute.LoseFocus): - print("Clear Selection Slot Called") - child_widget.deselectText() - if hasattr(self.childWidget, "checkEmpty") and isinstance(child_widget, QTextEdit): - if self.childWidget.checkEmpty(): - print("Removing empty container") - editorSignalsInstance.widgetRemoved.emit(self) - if self.hasFocus() or child_widget.hasFocus(): - if hasattr(child_widget, "changeBulletEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.Bullet): - print("Change Bullet Event Called") - child_widget.bullet_list("bulletReg") - elif hasattr(child_widget, "changeBulletEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.Bullet_Num): - print("Change Bullet Event Called") - child_widget.bullet_list("bulletNum") - elif hasattr(child_widget, "changeBackgroundColorEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.BackgroundColor): - print("Chang Background Color Event Called") - child_widget.changeBackgroundColorEvent(value) - def connectTableSignals(self, tableWidget): - tableWidget.rowAdded.connect(self.resizeTable) - def resizeTable(self): - self.resize(self.childWidget.size()) - self.newGeometry.emit(self.geometry()) - self.parentWidget().repaint() + + cw = self.childWidget + + if hasattr(cw, "changeFontSizeEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.FontSize): + cw.changeFontSizeEvent(value) + + if hasattr(cw, "changeFontBoldEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.FontBold): + cw.changeFontBoldEvent() + + if hasattr(cw, "changeFontItalicEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.FontItalic): + cw.changeFontItalicEvent() + + if hasattr(cw, "changeFontUnderlineEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.FontUnderline): + cw.changeFontUnderlineEvent() + + if hasattr(cw, "changeFontEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.Font): + cw.changeFontEvent(value) + + if hasattr(cw, "changeFontColorEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.FontColor): + cw.changeFontColorEvent(value) + + if hasattr(cw, "changeBackgroundColorEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.BackgroundColor): + cw.changeBackgroundColorEvent(value) + diff --git a/Models/Editor.py b/Models/Editor.py index c89b055..d92c8a4 100644 --- a/Models/Editor.py +++ b/Models/Editor.py @@ -35,5 +35,6 @@ def __init__(self): self.setFocus() build_ui(self) + # def focusInEvent(self, event): # self.repaint() diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index 6b7ddd5..0f24dac 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -4,14 +4,7 @@ from PySide6.QtGui import * from PySide6.QtWidgets import * -from Models.DraggableContainer import DraggableContainer -from Widgets.Textbox import * - from Modules.EditorSignals import editorSignalsInstance, ChangedWidgetAttribute -from Modules.Undo import UndoHandler -from Widgets.Table import * - -from Views.EditorFrameView import * FONT_SIZES = [7, 8, 9, 10, 11, 12, 13, 14, 18, 24, 36, 48, 64, 72, 96, 144, 288] @@ -20,7 +13,6 @@ def build_ui(editor): print("Building UI...") -<<<<<<< HEAD <<<<<<< Updated upstream #editor.statusBar = editor.statusBar() build_window(editor) @@ -34,15 +26,6 @@ def build_ui(editor): build_toolbar(editor) # build_test_toolbar(editor) >>>>>>> Stashed changes -======= - - #editor.EditorFrameView = EditorFrameView(editor) - #editor.statusBar = editor.statusBar() - build_window(editor) - build_menubar(editor) - build_toolbar(editor) - #build_test_toolbar(editor) ->>>>>>> 5b2a7e0a68ed735cf55aee09f0f246d28a28586a # Application's main layout (grid) gridLayout = QGridLayout() @@ -65,9 +48,6 @@ def build_ui(editor): leftSideLayout.setContentsMargins(0, 0, 0, 0) leftSideLayout.setSpacing(0) - - - # Right side of the app's layout rightSideLayout = QVBoxLayout() rightSideContainerWidget = QWidget() @@ -77,7 +57,6 @@ def build_ui(editor): rightSideLayout.setStretch(0, 0) rightSideLayout.setStretch(1, 1) - # Add appropriate widgets (ideally just view controllers) to their layouts leftSideLayout.addWidget(editor.notebookTitleView, 0) leftSideLayout.addWidget(editor.pageView, 1) # Page view has max stretch factor @@ -88,7 +67,6 @@ def build_ui(editor): gridLayout.addWidget(leftSideContainerWidget, 0, 0) gridLayout.addWidget(rightSideContainerWidget, 0, 1) -<<<<<<< HEAD <<<<<<< Updated upstream ======= addSectionButton = QPushButton("Add Section") @@ -97,12 +75,6 @@ def build_ui(editor): >>>>>>> Stashed changes -======= - addSectionButton = QPushButton("Add Section") - #add functionality e.g. addSectionButton.clcicked.connect(editor.add_section_function) - leftSideLayout.addWidget(addSectionButton) - ->>>>>>> 5b2a7e0a68ed735cf55aee09f0f246d28a28586a def build_window(editor): editor.setWindowTitle("OpenNote") editor.setWindowIcon(QIcon("./Assets/OpenNoteLogo.png")) @@ -111,7 +83,6 @@ def build_window(editor): editor.setStyleSheet(fh.read()) -<<<<<<< HEAD <<<<<<< Updated upstream new_file = build_action(editor, 'assets/icons/svg_file_open', 'New Notebook...', 'New Notebook', False) new_file.setShortcut(QKeySequence.StandardKey.New) @@ -164,28 +135,6 @@ def build_menubar(editor): file.addActions([new_file, add_new_file, open_file, save_file, save_fileAs]) -======= - new_file = build_action(editor, './Assets/icons/svg_file_open', 'New Notebook', 'New Notebook', False) - new_file.setShortcut(QKeySequence.StandardKey.New) - new_file.triggered.connect(lambda: new(editor)) - - open_file = build_action(editor, './Assets/icons/svg_file_open', 'Open Notebook', 'Open Notebook', False) - open_file.setShortcut(QKeySequence.StandardKey.Open) - open_file.triggered.connect(lambda: load(editor)) - - save_file = build_action(editor, './Assets/icons/svg_file_save', 'Save Notebook', 'Save Notebook', False) - save_file.setShortcut(QKeySequence.StandardKey.Save) - save_file.triggered.connect(lambda: save(editor)) - - save_fileAs = build_action(editor, './Assets/icons/svg_file_save', 'Save Notebook As...', 'Save Notebook As', False) - save_fileAs.setShortcut(QKeySequence.fromString('Ctrl+Shift+S')) - save_fileAs.triggered.connect(lambda: saveAs(editor)) - - add_widget = build_action(editor, './Assets/icons/svg_question', 'Add Custom Widget', 'Add Custom Widget', False) - - file.addActions([new_file, open_file, save_file, save_fileAs]) - plugins.addActions([add_widget]) ->>>>>>> 5b2a7e0a68ed735cf55aee09f0f246d28a28586a def build_toolbar(editor): toolbar = QToolBar() @@ -193,7 +142,6 @@ def build_toolbar(editor): toolbar.setMovable(False) editor.addToolBar(Qt.ToolBarArea.TopToolBarArea, toolbar) -<<<<<<< HEAD <<<<<<< Updated upstream font = QFontComboBox() font.currentFontChanged.connect(lambda x: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Font, font.currentFont())) @@ -226,32 +174,19 @@ def build_toolbar(editor): <<<<<<< Updated upstream fontColor = build_action(toolbar, 'assets/icons/svg_font_color', "Font Color", "Font Color", False) fontColor.triggered.connect(lambda x: openGetColorDialog(purpose = "font")) -======= - #separates toolbar with a line break - spacer = QWidget() - spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) - - toolbar_undo = build_action(toolbar, './Assets/icons/svg_undo', "undo", "undo", False) - toolbar_undo.triggered.connect(editor.frameView.triggerUndo) ->>>>>>> 5b2a7e0a68ed735cf55aee09f0f246d28a28586a + bgColor = build_action(toolbar, 'assets/icons/svg_font_bucket', "Text Box Color", "Text Box Color", False) + bgColor.triggered.connect(lambda x: openGetColorDialog(purpose = "background")) - redo = build_action(toolbar, './Assets/icons/svg_redo', "redo", "redo", False) - + bold = build_action(toolbar, 'assets/icons/bold', "Bold", "Bold", True) + bold.triggered.connect(lambda x: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontBold, None)) + italic = build_action(toolbar, 'assets/icons/italic.svg', "Italic", "Italic", True) + italic.triggered.connect(lambda x: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontItalic, None)) - font_family = QFontComboBox() - default_font = font_family.currentFont().family() - print(f"default font is {default_font}") - font_family.currentFontChanged.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Font, font_family.currentFont().family())) + underline = build_action(toolbar, 'assets/icons/underline.svg', "Underline", "Underline", True) + underline.triggered.connect(lambda x: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontUnderline, None)) - font_size = QComboBox() - font_size.addItems([str(fs) for fs in FONT_SIZES]) - default_font_size_index = 8 #default text size is 18 - font_size.setCurrentIndex(default_font_size_index) - font_size.currentIndexChanged.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontSize, int(font_size.currentText()))) - -<<<<<<< HEAD ======= bgColor = build_action( toolbar, @@ -333,69 +268,6 @@ def toggle_bold(self): font = self.text_edit >>>>>>> Stashed changes -======= - #current issues: - # - Alternates between working and not working - # - Textboxes do not remember settings like if font is toggled or current font size - - bgColor = build_action(toolbar, './Assets/icons/svg_font_bucket', "Background Color", "Background Color", False) - #bgColor.triggered.connect(lambda: openGetColorDialog(purpose = "background")) - #current bug, alternates between activating and not working when using - bgColor.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.BackgroundColor, QColorDialog.getColor())) - - textboxColor = build_action(toolbar, './Assets/icons/svg_textboxColor', "Text Box Color", "Text Box Color", True) - textboxColor.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.TextboxColor, QColorDialog.getColor())) - - #defines font color icon appearance and settings - fontColor = build_action(toolbar, './Assets/icons/svg_font_color', "Font Color", "Font Color", False) - fontColor.triggered.connect(lambda: openGetColorDialog(purpose = "font")) - - bold = build_action(toolbar, './Assets/icons/bold', "Bold", "Bold", True) - bold.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontBold, None)) - - italic = build_action(toolbar, './Assets/icons/italic.svg', "Italic", "Italic", True) - italic.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontItalic, None)) - - underline = build_action(toolbar, './Assets/icons/underline.svg', "Underline", "Underline", True) - underline.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontUnderline, None)) - - table = build_action(toolbar, './Assets/icons/svg_table', "Create Table", "Create Table", False) - table.triggered.connect(editor.frameView.toolbar_table) - - hyperlink = build_action(toolbar, './Assets/icons/svg_hyperlink', "Hyperlink", "Hyperlink", False) - hyperlink.triggered.connect(editor.frameView.toolbar_hyperlink) - - bullets = build_action(toolbar, './Assets/icons/svg_bullets', "Bullets", "Bullets", False) - - bullet_reg = build_action(toolbar, './Assets/icons/svg_bullets', "Bullet List", "Bullet List", False) - bullet_reg.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Bullet, None)) - - bullet_num = build_action(toolbar, './Assets/icons/svg_bullet_number', "Bullet List", "Bullet List", False) - bullet_num.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Bullet_Num, None)) - - ''' - editor.action1 = QAction('Action 1', editor) - #editor.action1.triggered.connect(EditorFrameView.slot_action1) - toolbar.addAction(editor.action1) - editor.action2 = QAction('Action 2', editor) - #editor.action2.triggered.connect(TextboxWidget.slot_action2) - #editor.action2.triggered.connect(show_popup) - toolbar.addAction(editor.action2) - #editor.button = QPushButton("Click Me", editor) - #editor.button.clicked.connect(editor.slot_button_click)''' - - - toolbar.addActions([toolbar_undo, redo]) - toolbar.addSeparator() - toolbar.addWidget(font_family) - toolbar.addWidget(font_size) - toolbar.addSeparator() - toolbar.addActions([bgColor, textboxColor, fontColor, bold, italic, underline]) - toolbar.addSeparator() - toolbar.addActions([table, hyperlink, bullet_reg, bullet_num]) - - #toolbar.setStyleSheet("QToolBar { background-color: #FFFFFF; }") ->>>>>>> 5b2a7e0a68ed735cf55aee09f0f246d28a28586a def openGetColorDialog(purpose): color = QColorDialog.getColor() @@ -413,7 +285,6 @@ def openGetColorDialog(purpose): def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): action = QAction(QIcon(icon_path), action_name, parent) action.setStatusTip(set_status_tip) -<<<<<<< HEAD return action <<<<<<< Updated upstream ======= @@ -461,7 +332,3 @@ def change_font(self): def widgetAttributeChangedEvent(self, draggableContainer): editorSignalsInstance.widgetAttributeChanged.emit(draggableContainer) >>>>>>> Stashed changes -======= - action.setCheckable(set_checkable) - return action ->>>>>>> 5b2a7e0a68ed735cf55aee09f0f246d28a28586a diff --git a/Modules/EditorSignals.py b/Modules/EditorSignals.py index b85e42f..97d3873 100644 --- a/Modules/EditorSignals.py +++ b/Modules/EditorSignals.py @@ -3,8 +3,6 @@ from enum import Enum class ChangedWidgetAttribute(Enum): - # Used for unique signals - # Add variable to create a unique signal BackgroundColor = 0 FontColor = 1 Font = 2 @@ -12,10 +10,6 @@ class ChangedWidgetAttribute(Enum): FontBold = 4 FontItalic = 5 FontUnderline = 6 - TextboxColor = 7 - Bullet = 8 - Bullet_Num = 9 - LoseFocus = 10 # Cant be statically typed because importing the classes causes circular imports @@ -39,7 +33,4 @@ class EditorSignals(QObject): # Recieves nothing, used by autosaver changeMade = Signal() - # Clear Selection - loseFocus = Signal() - editorSignalsInstance = EditorSignals() diff --git a/Modules/Load.py b/Modules/Load.py index 7bf4b8f..0592cde 100644 --- a/Modules/Load.py +++ b/Modules/Load.py @@ -5,7 +5,7 @@ import pyautogui from Modules.Save import Autosaver -import pyautogui + from PySide6.QtWidgets import * from PySide6.QtCore import * from PySide6.QtGui import * @@ -32,13 +32,8 @@ def new(editor): text_ar = Text(p, fg="black", bg="white", font=("segoe print", 15)) text_ar.pack() destroy(editor) -<<<<<<< HEAD editor.notebook = NotebookModel("Untitled") -======= - p_name = pyautogui.prompt("Enter Notebook Name") - editor.notebook = NotebookModel(p_name) ->>>>>>> 5b2a7e0a68ed735cf55aee09f0f246d28a28586a editor.notebookTitleView.setText(editor.notebook.title) editor.selected = None editor.autosaver = Autosaver(editor) diff --git a/Modules/Screensnip.py b/Modules/Screensnip.py index e52c194..86950eb 100644 --- a/Modules/Screensnip.py +++ b/Modules/Screensnip.py @@ -13,83 +13,76 @@ class SnippingWidget(QWidget): def __init__(self): super(SnippingWidget, self).__init__() - self.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.FramelessWindowHint) - self.setAttribute(Qt.WA_TranslucentBackground) + self.setWindowFlags(Qt.WindowStaysOnTopHint) self.parent = None self.screen = QApplication.instance().primaryScreen() self.setGeometry(0, 0, self.screen.size().width(), self.screen.size().height()) - self.begin = self.end = QPoint() + self.begin = QPoint() + self.end = QPoint() self.onSnippingCompleted = None self.event_pos = None def start(self, event_pos): print("SnippingWidget.start") SnippingWidget.is_snipping = True + self.setWindowOpacity(0.3) QApplication.setOverrideCursor(QCursor(Qt.CrossCursor)) self.event_pos = event_pos self.show() print("SnippingWidget.start done") def paintEvent(self, event): - qp = QPainter(self) if SnippingWidget.is_snipping: brush_color = (128, 128, 255, 100) lw = 3 - qp.setPen(QPen(QColor('black'), lw)) - qp.setBrush(QColor(*brush_color)) - rect = QRectF(self.begin, self.end) - qp.drawRect(rect) + opacity = 0.3 + else: + self.begin = QPoint() + self.end = QPoint() + brush_color = (0, 0, 0, 0) + lw = 0 + opacity = 0 + + self.setWindowOpacity(opacity) + qp = QPainter(self) + qp.setPen(QPen(QColor('black'), lw)) + qp.setBrush(QColor(*brush_color)) + rect = QRectF(self.begin, self.end) + qp.drawRect(rect) def mousePressEvent(self, event): - try: - self.begin = event.pos() - self.end = self.begin - self.update() - except Exception as e: - print(f"Error handling mouse press event: {e}") + self.begin = event.pos() + self.end = self.begin + self.update() def mouseMoveEvent(self, event): - try: - self.end = event.pos() - self.update() - except Exception as e: - print(f"Error handling mouse move event: {e}") + self.end = event.pos() + self.update() def mouseReleaseEvent(self, event): SnippingWidget.is_snipping = False QApplication.restoreOverrideCursor() - x1, y1, x2, y2 = self.getSnipCoordinates() + x1 = min(self.begin.x(), self.end.x()) + y1 = min(self.begin.y(), self.end.y()) + x2 = max(self.begin.x(), self.end.x()) + y2 = max(self.begin.y(), self.end.y()) self.repaint() QApplication.processEvents() - - try: - if platform == "darwin": - img = ImageGrab.grab(bbox=( (x1 ) * 2, (y1 + 55 ) * 2, (x2 ) * 2, (y2 + 55) * 2)) - else: - img = ImageGrab.grab(bbox=(x1 + 10, y1 + 30, x2 + 10, y2 + 40)) - except Exception as e: - print(f"Error grabbing screenshot: {e}") - img = None + + if platform == "darwin": + img = ImageGrab.grab(bbox=( (x1 ) * 2, (y1 + 55 ) * 2, (x2 ) * 2, (y2 + 55) * 2)) + else: + img = ImageGrab.grab(bbox=(x1 + 10, y1 + 30, x2 + 10, y2 + 40)) + + try: img = cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR) except: - print(f"Error converting screenshot to NumPy array: {e}") img = None if self.onSnippingCompleted is not None: self.onSnippingCompleted(img) self.close() - - def getSnipCoordinates(self): - try: - x1 = min(self.begin.x(), self.end.x()) - y1 = min(self.begin.y(), self.end.y()) - x2 = max(self.begin.x(), self.end.x()) - y2 = max(self.begin.y(), self.end.y()) - return x1, y1, x2, y2 - except Exception as e: - print(f"Error getting snip coordinates {e}") - return 0, 0, 0, 0 \ No newline at end of file diff --git a/Modules/Undo.py b/Modules/Undo.py index 51b7e55..d44eefc 100644 --- a/Modules/Undo.py +++ b/Modules/Undo.py @@ -4,8 +4,6 @@ from Modules.EditorSignals import editorSignalsInstance import os - -#current version of undo does not work. When using ctrl+z in textboxes, it uses the QTextEdit default settings for ctrl+z(undo) and ctrl+y(redo) to make it appear as if undo does work class UndoActionCreate: def __init__(self, draggableContainer): self.draggableContainer = draggableContainer diff --git a/Views/EditorFrameView.py b/Views/EditorFrameView.py index 624d543..5232ead 100644 --- a/Views/EditorFrameView.py +++ b/Views/EditorFrameView.py @@ -9,20 +9,15 @@ from Modules.Multiselect import Multiselector, MultiselectMode from Models.DraggableContainer import DraggableContainer from Widgets.Textbox import TextboxWidget -from Modules.EditorSignals import editorSignalsInstance,ChangedWidgetAttribute +from Modules.EditorSignals import editorSignalsInstance from Widgets.Image import ImageWidget from Modules.Screensnip import SnippingWidget -from Widgets.Table import * +from Widgets.Table import TableWidget from Modules.Clipboard import Clipboard from Modules.Undo import UndoHandler -from Widgets.Link import LinkWidget -from Widgets.Link import LinkDialog - - # Handles all widget display (could be called widget view, but so could draggablecontainer) class EditorFrameView(QWidget): - def __init__(self, editor): super(EditorFrameView, self).__init__() @@ -48,16 +43,12 @@ def __init__(self, editor): self.installEventFilter(self.multiselector) # Undo setup - #self.shortcut = QShortcut(QKeySequence("Ctrl+Z"), self) - #self.shortcut.setContext(Qt.ApplicationShortcut) - #self.shortcut.activated.connect(self.triggerUndo) + self.shortcut = QShortcut(QKeySequence("Ctrl+Z"), self) + self.shortcut.setContext(Qt.ApplicationShortcut) + self.shortcut.activated.connect(self.undoHandler.undo) + self.undoHandler.undoWidgetDelete.connect(self.undoWidgetDeleteEvent) print("BUILT FRAMEVIEW") - - def triggerUndo(self): - print("triggerUndo Called") - self.undoHandler.undo - self.undoHandler.undoWidgetDelete.connect(self.undoWidgetDeleteEvent) def pasteWidget(self, clickPos): widgetOnClipboard = self.clipboard.getWidgetToPaste() @@ -72,7 +63,6 @@ def pasteWidget(self, clickPos): def snipScreen(self, clickPos): def onSnippingCompleted(imageMatrix): # Called after screensnipper gets image self.editor.setWindowState(Qt.WindowActive) - self.editor.setWindowFlags(Qt.WindowStaysOnTopHint) self.editor.showMaximized() if imageMatrix is None: return @@ -159,36 +149,28 @@ def mouseReleaseEvent(self, event): # Releasing the mouse after clicking to add text else: - print("CREATE DRAGGABLE CONTAINER") self.newWidgetOnSection(TextboxWidget, event.pos()) def mousePressEvent(self, event): print("EDITORFRAME MOUSEPRESS") editor = self.editor - #calls textwidget's clearSelectionSignal - if event.button() == Qt.LeftButton: - if self.rect().contains(event.pos()): - editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.LoseFocus, None) - super().mousePressEvent(event) - # Open context menu on right click if event.buttons() == Qt.RightButton: frame_menu = QMenu(self) - paste = QAction("Paste", editor) - paste.triggered.connect(lambda: self.pasteWidget(event.pos())) - frame_menu.addAction(paste) - add_image = QAction("Add Image", self) add_image.triggered.connect(lambda: self.newWidgetOnSection(ImageWidget, event.pos())) frame_menu.addAction(add_image) add_table = QAction("Add Table", editor) add_table.triggered.connect(lambda: self.newWidgetOnSection(TableWidget, event.pos())) - #add_table.triggered.connect(self.show_table_popup) frame_menu.addAction(add_table) + paste = QAction("Paste", editor) + paste.triggered.connect(lambda: self.pasteWidget(event.pos())) + frame_menu.addAction(paste) + take_screensnip = QAction("Snip Screen", editor) take_screensnip.triggered.connect(lambda: self.snipScreen(event.pos())) frame_menu.addAction(take_screensnip) @@ -197,35 +179,9 @@ def mousePressEvent(self, event): add_custom_widget.triggered.connect(lambda: self.addCustomWidget(event)) frame_menu.addAction(add_custom_widget) - insert_Link = QAction("Insert Link", editor) - insert_Link.triggered.connect(lambda: self.newWidgetOnSection(LinkWidget,event.pos())) - frame_menu.addAction(insert_Link) - frame_menu.exec(event.globalPos()) - def center_of_screen(self): - editor_frame_geometry = self.editorFrame.geometry() - print(f"editor_frame_geometry.width() is {editor_frame_geometry.width()}") - print(f"editor_frame_geometry.height() is {editor_frame_geometry.height()}") - center_x = (editor_frame_geometry.width() - 200) // 2 - center_y = (editor_frame_geometry.height() - 200) // 2 - return center_x, center_y - - - - def toolbar_table(self): - print("toolbar_table pressed") - center_x, center_y = self.center_of_screen() - clickPos = QPoint(center_x, center_y) - self.newWidgetOnSection(TableWidget, clickPos) - - def toolbar_hyperlink(self): - print("toolbar_hyperlink pressed") - center_x, center_y = self.center_of_screen() - clickPos = QPoint(center_x, center_y) - self.newWidgetOnSection(LinkWidget, clickPos) - - def addCustomWidget(self, e): + def addCustomWidget(self, event): def getCustomWidgets(): customWidgets = {} # dict where entries are {name: class} @@ -250,20 +206,17 @@ def getCustomWidgets(): item_action = QAction(customWidget[0], self) def tmp(c, pos): return lambda: self.newWidgetOnSection(c, pos) - item_action.triggered.connect(tmp(customWidget[1], e.pos())) + item_action.triggered.connect(tmp(customWidget[1], event.pos())) pluginMenu.addAction(item_action) - pluginMenu.exec(e.globalPos()) + pluginMenu.exec(event.globalPos()) + + def mouseMoveEvent(self, event): # This event is only called after clicking down on the frame and dragging - def mouseMoveEvent(self, e): # This event is only called after clicking down on the frame and dragging # Set up multi-select on first move of mouse drag if self.multiselector.mode != MultiselectMode.IS_DRAWING_AREA: - self.multiselector.beginDrawingArea(e) + self.multiselector.beginDrawingArea(event) # Resize multi-select widget on mouse every proceeding mouse movement (dragging) else: - self.multiselector.continueDrawingArea(e) - - def slot_action1(self, item): - print("Action 1 triggered") - + self.multiselector.continueDrawingArea(event) diff --git a/Views/PageView.py b/Views/PageView.py index 261a9e1..9c4b193 100644 --- a/Views/PageView.py +++ b/Views/PageView.py @@ -136,18 +136,6 @@ def openMenu(self, position: QModelIndex): renamePageAction = menu.addAction(self.tr("Rename Page")) renamePageAction.triggered.connect(partial(self.renamePage, page)) - - #Current Issue: settings do not save because autosave only saves editor state - ''' - mergePageAction = menu.addAction(self.tr("Merge Pages")) - mergePageAction.triggered.connect(partial(self.mergePages, page)) - ''' - - changeTextColorAction = menu.addAction(self.tr("Change Text Color")) - changeTextColorAction.triggered.connect(partial(self.changeTextColor, page)) - - changeBackgroundColorAction = menu.addAction(self.tr("Change Background Color")) - changeBackgroundColorAction.triggered.connect(partial(self.changeBackgroundColor, page)) menu.exec_(self.sender().viewport().mapToGlobal(position)) # Dont let the right click reach the viewport, context menu will still open but this will stop the page from being selected @@ -156,20 +144,10 @@ def eventFilter(self, source, event): if event.button() == Qt.RightButton: return True return False - + def addPage(self, level: int, clickedIndex: QModelIndex): -<<<<<<< HEAD # New page added under parent (what the user right clicked on) -======= - - - # New page added to root - # will add functionallity for page groups which can be nested - ->>>>>>> 5b2a7e0a68ed735cf55aee09f0f246d28a28586a parentPage = self.model.itemFromIndex(clickedIndex) - while not parentPage.data().isRoot(): - parentPage = parentPage.parent() parentPageUUID = parentPage.data().getUUID() # Create a new page model, set that as the data for the new page @@ -180,7 +158,7 @@ def addPage(self, level: int, clickedIndex: QModelIndex): parentPage.appendRow([newPage]) # Add to UI self.pageModels.append(newPageModel) # Add to array of PageModel - self.tree.expand(clickedIndex) + self.tree.expand(clickedIndex) def deletePage(self, page: QStandardItem): deletePages = [page] @@ -239,66 +217,6 @@ def changePage(self, current: QModelIndex, previous: QModelIndex): newPageModel = newPage.data() print("CHANGED PAGE TO: " + newPage.data().title) -<<<<<<< HEAD editorSignalsInstance.pageChanged.emit( newPageModel ) # Tell the sectionView that the page has changed -======= - editorSignalsInstance.pageChanged.emit(newPageModel) # Tell the sectionView that the page has changed - - ''' - # Not sure if working as intended - def mergePages(self): - # Prompt the user to select two pages - selectedIndexes = self.tree.selectedIndexes() - - # Check if exactly two pages are selected - if len(selectedIndexes) == 2: - # Retrieve the QStandardItem objects corresponding to the selected pages - page1Item = self.model.itemFromIndex(selectedIndexes[0]) - page2Item = self.model.itemFromIndex(selectedIndexes[1]) - - # Extract the PageModel objects from the selected QStandardItem objects - page1Model = page1Item.data() - page2Model = page2Item.data() - - # Merge the sections of the two pages into one page - mergedSections = page1Model.sections + page2Model.sections - newPageModel = PageModel('Merged Page', 0, mergedSections) # Assuming 0 as the parent UUID for the root - - # Create a new QStandardItem for the merged page - newPageItem = QStandardItem(newPageModel.title) - newPageItem.setData(newPageModel) - newPageItem.setEditable(False) - - # Insert the new merged page at the bottom of the children of the root - root = self.model.invisibleRootItem() - index = root.rowCount() # Get the last index - root.insertRow(index, [newPageItem]) - - # Remove the original two pages from the model - root.removeRow(page1Item.row()) - root.removeRow(page2Item.row()) - - # Update the pageModels list - self.pageModels.remove(page1Model) - self.pageModels.remove(page2Model) - self.pageModels.append(newPageModel) - - # Expand the tree to show the changes - self.tree.expandAll() - else: - # If not exactly two pages are selected, show a warning or message - QMessageBox.warning(self, 'Invalid Selection', 'Please select exactly two pages to merge.', QMessageBox.Ok) - ''' - - def changeTextColor(self, page: QStandardItem): - color = QColorDialog.getColor() - if color.isValid(): - page.setForeground(color) - - def changeBackgroundColor(self, page: QStandardItem): - color = QColorDialog.getColor() - if color.isValid(): - page.setBackground(color) ->>>>>>> 5b2a7e0a68ed735cf55aee09f0f246d28a28586a diff --git a/Widgets/Image.py b/Widgets/Image.py index beeb6c5..64971e1 100644 --- a/Widgets/Image.py +++ b/Widgets/Image.py @@ -70,64 +70,3 @@ def __getstate__(self): def __setstate__(self, state): self.__init__(state['geometry'].x(), state['geometry'].y(), state['geometry'].width(), state['geometry'].height(), state['image_matrix']) - - def customMenuItems(self): - def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): - action = QAction(QIcon(icon_path), action_name, parent) - action.setStatusTip(set_status_tip) - action.setCheckable(set_checkable) - return action - - - toolbarBottom = QToolBar() - toolbarBottom.setIconSize(QSize(16, 16)) - toolbarBottom.setMovable(False) - - #crop = build_action(toolbarTop, 'assets/icons/svg_crop', "Crop", "Crop", False) - - flipHorizontal = build_action(toolbarBottom, 'assets/icons/svg_flip_horizontal', "Horizontal Flip", "Horizontal Flip", False) - flipHorizontal.triggered.connect(self.flipHorizontal) - flipVertical = build_action(toolbarBottom, 'assets/icons/svg_flip_vertical', "Vertical Flip", "Vertical Flip", False) - flipVertical.triggered.connect(self.flipVertical) - - rotateLeftAction = build_action(toolbarBottom, 'assets/icons/svg_rotate_left', "Rotate 90 degrees Left", "Rotate 90 degrees Left", False) - rotateLeftAction.triggered.connect(self.rotate90Left) - rotateRightAction = build_action(toolbarBottom, 'assets/icons/svg_rotate_right', "Rotate 90 degrees Right", "Rotate 90 degrees Right", False) - rotateRightAction.triggered.connect(self.rotate90Right) - - - toolbarBottom.addActions([rotateLeftAction, rotateRightAction, flipHorizontal, flipVertical]) - - qwaBottom = QWidgetAction(self) - qwaBottom.setDefaultWidget(toolbarBottom) - - return [qwaBottom] - - def flipVertical(self): - # Flip the image matrix vertically using OpenCV - self.image_matrix = cv2.flip(self.image_matrix, 0) - self.updatePixmap() - - def flipHorizontal(self): - # Flip the image matrix horizontally using OpenCV - self.image_matrix = cv2.flip(self.image_matrix, 1) - self.updatePixmap() - - def rotate90Left(self): - # Rotate the image matrix 90 degrees to the left using OpenCV - self.image_matrix = cv2.rotate(self.image_matrix, cv2.ROTATE_90_COUNTERCLOCKWISE) - self.updatePixmap() - def rotate90Right(self): - # Rotate the image matrix 90 degrees to the right using OpenCV - self.image_matrix = cv2.rotate(self.image_matrix, cv2.ROTATE_90_CLOCKWISE) - self.updatePixmap() - - def updatePixmap(self): - # Update the QImage and QPixmap - matrix_height, matrix_width, _ = self.image_matrix.shape - bytes_per_line = 3 * matrix_width - q_image = QImage(self.image_matrix.data, matrix_width, matrix_height, bytes_per_line, QImage.Format_BGR888) - self.q_pixmap = QPixmap(q_image) - - # Update the displayed pixmap - self.setPixmap(self.q_pixmap.scaled(self.w, self.h, Qt.KeepAspectRatio, Qt.SmoothTransformation)) \ No newline at end of file diff --git a/Widgets/Link.py b/Widgets/Link.py deleted file mode 100644 index 48dc4ca..0000000 --- a/Widgets/Link.py +++ /dev/null @@ -1,77 +0,0 @@ -from PySide6.QtCore import * -from PySide6.QtGui import * -from PySide6.QtWidgets import * - - -FONT_SIZES = [7, 8, 9, 10, 11, 12, 13, 14, 18, 24, 36, 48, 64, 72, 96, 144, 288] - - -class LinkWidget(QLabel): - def __init__(self, x, y, l, d, w = 15, h = 30): - super().__init__() - - self.setGeometry(x, y, w, h) - self.setStyleSheet('font-size: 20px') - self.setOpenExternalLinks(True) - - - self.setText(f'{d}') - self.adjustSize() - #self.setParent(parent) - - @staticmethod - def new(clickPos: QPoint): - dialog = LinkDialog() - - if dialog.exec_() == QDialog.Accepted: - link_address, display_text = dialog.get_link_data() - - print(link_address) - - return LinkWidget(clickPos.x(), clickPos.y(), link_address, display_text) - - def __getstate__(self): - data = {} - - data['geometry'] = self.parentWidget().geometry() - #data['content'] = self.toHtml() - data['stylesheet'] = self.styleSheet() - return data - - def __setstate__(self, data): - self.__init__(data['geometry'].x(), data['geometry'].y(), data['geometry'].width(), data['geometry'].height(), data['content']) - self.setStyleSheet(data['stylesheet']) - -class LinkDialog(QDialog): - def __init__(self): - super().__init__() - self.setWindowTitle("Insert Link") - layout = QVBoxLayout() - - self.link_label = QLabel("Link Address:") - self.link_textbox = QLineEdit() - self.display_label = QLabel("Display Text:") - self.display_textbox = QLineEdit() - - layout.addWidget(self.link_label) - layout.addWidget(self.link_textbox) - layout.addWidget(self.display_label) - layout.addWidget(self.display_textbox) - - ok_button = QPushButton("OK") - ok_button.clicked.connect(self.accept) - cancel_button = QPushButton("Cancel") - cancel_button.clicked.connect(self.reject) - - layout.addWidget(ok_button) - layout.addWidget(cancel_button) - - self.setLayout(layout) - - def get_link_data(self): - link_address = self.link_textbox.text() - display_text = self.display_textbox.text() - return link_address, display_text - - - diff --git a/Widgets/Table.py b/Widgets/Table.py index 82921a1..7f615ff 100644 --- a/Widgets/Table.py +++ b/Widgets/Table.py @@ -42,20 +42,14 @@ def addCol(self): @staticmethod def new(clickPos: QPoint): - dialog = TablePopupWindow() - if dialog.exec_() == QDialog.Accepted: - rows_input, cols_input = dialog.get_table_data() - print(f"rows input is {rows_input} cols_input is {cols_input}") - table_widget = TableWidget(clickPos.x(), clickPos.y(), 200, 200, int(rows_input), int(cols_input)) - - return table_widget + return TableWidget(clickPos.x(), clickPos.y(), 200, 200, 2, 2) def customMenuItems(self): addRow = QAction("Add Row", self) addRow.triggered.connect(self.addRow) addCol = QAction("Add Column", self) - addCol.triggered.connect(self.addCol) + addCol.triggered.connect(self.addCol) return [addRow, addCol] @@ -85,52 +79,3 @@ def __setstate__(self, state): for i in range(colCnt): for j in range(rowCnt): self.table.setItem(j, i, QTableWidgetItem(state['tableData'][i][j])) - -def show_table_popup(self): - popup = TablePopupWindow() - popup.exec_() - #def undo_triggered(self): - # Call the EditorFrameView's triggerUndo method - #self.EditorFrameView.triggerUndo() - -class TablePopupWindow(QDialog): - def __init__(self): - super().__init__() - '''self.setWindowTitle("Popup Window") - layout = QVBoxLayout() - label = QLabel("This is a popup window.") - layout.addWidget(label) - self.setLayout(layout)''' - self.setWindowTitle("Table Configuration") - self.layout = QVBoxLayout() - - self.rows_input = QLineEdit(self) - self.rows_input.setPlaceholderText("Enter number of rows:") - self.layout.addWidget(self.rows_input) - - self.cols_input = QLineEdit(self) - colNum = self.cols_input.setPlaceholderText("Enter number of columns:") - self.layout.addWidget(self.cols_input) - - create_table_button = QPushButton("Create Table") - self.layout.addWidget(create_table_button) - create_table_button.clicked.connect(self.accept) - #create error message if no data is entered or if number of rows or columns are < 1 - - cancel_button = QPushButton("Cancel") - self.layout.addWidget(cancel_button) - cancel_button.clicked.connect(self.reject) - - - self.setLayout(self.layout) - - def get_table_data(self): - rows_input = self.rows_input.text() - cols_input = self.cols_input.text() - return rows_input, cols_input - - def create_table(self): - print("table") - #row_num = int(self.rows_input.text()) - #col_num = int(self.cols_input.text()) - #self.EditorFrameView.add_table_action(row_num, col_num) diff --git a/Widgets/Textbox.py b/Widgets/Textbox.py index c97f2c0..998d2fe 100644 --- a/Widgets/Textbox.py +++ b/Widgets/Textbox.py @@ -1,38 +1,20 @@ from PySide6.QtCore import * from PySide6.QtGui import * from PySide6.QtWidgets import * -from Modules.EditorSignals import editorSignalsInstance FONT_SIZES = [7, 8, 9, 10, 11, 12, 13, 14, 18, 24, 36, 48, 64, 72, 96, 144, 288] - class TextboxWidget(QTextEdit): - def __init__(self, x, y, w=15, h=30, t=""): + def __init__(self, x, y, w = 15, h = 30, t = ''): super().__init__() - self.setGeometry(x, y, w, h) # This sets geometry of DraggableObject + self.setGeometry(x, y, w, h) # This sets geometry of DraggableObject self.setText(t) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.textChanged.connect(self.textChangedEvent) - self.setStyleSheet("background-color: rgba(0, 0, 0, 0);") - self.setTextColor("black") - - self.installEventFilter(self) - - def eventFilter(self, obj, event): - if event.type() == QEvent.KeyPress and event.key() == Qt.Key_Tab: - self.handleTabKey() - return True # To prevent the default Tab key behavior - - return super(TextboxWidget, self).eventFilter(obj, event) - - # upon clicking somewhere else, remove selection of highlighted text - def setCursorPosition(self, event): - print("SET TEXT CURSOR POSITION TO MOUSE POSITION") - cursor = self.cursorForPosition(event.pos()) - self.setTextCursor(cursor) + self.setStyleSheet('background-color: rgba(0, 0, 0, 0);') def textChangedEvent(self): if len(self.toPlainText()) < 2: @@ -45,20 +27,14 @@ def new(clickPos: QPoint): def __getstate__(self): data = {} - data["geometry"] = self.parentWidget().geometry() - data["content"] = self.toHtml() - data["stylesheet"] = self.styleSheet() + data['geometry'] = self.parentWidget().geometry() + data['content'] = self.toHtml() + data['stylesheet'] = self.styleSheet() return data def __setstate__(self, data): - self.__init__( - data["geometry"].x(), - data["geometry"].y(), - data["geometry"].width(), - data["geometry"].height(), - data["content"], - ) - self.setStyleSheet(data["stylesheet"]) + self.__init__(data['geometry'].x(), data['geometry'].y(), data['geometry'].width(), data['geometry'].height(), data['content']) + self.setStyleSheet(data['stylesheet']) def checkEmpty(self): if len(self.toPlainText()) < 1: @@ -66,158 +42,54 @@ def checkEmpty(self): return False def customMenuItems(self): - def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): - action = QAction(QIcon(icon_path), action_name, parent) - action.setStatusTip(set_status_tip) - action.setCheckable(set_checkable) - return action - - toolbarTop = QToolBar() - toolbarTop.setIconSize(QSize(25, 25)) - toolbarTop.setMovable(False) - - toolbarBottom = QToolBar() - toolbarBottom.setIconSize(QSize(25, 25)) - toolbarBottom.setMovable(False) - - font = QFontComboBox() - font.currentFontChanged.connect( - lambda x: self.setCurrentFontCustom( - font.currentFont() if x else self.currentFont() - ) - ) - - size = QComboBox() - size.addItems([str(fs) for fs in FONT_SIZES]) - size.currentIndexChanged.connect( - lambda x: self.setFontPointSizeCustom( - FONT_SIZES[x] if x else self.fontPointSize() - ) - ) - - align_left = build_action( - toolbarBottom, - "assets/icons/svg_align_left", - "Align Left", - "Align Left", - True, - ) - align_left.triggered.connect(lambda x: self.setAlignment(Qt.AlignLeft)) - - align_center = build_action( - toolbarBottom, - "assets/icons/svg_align_center", - "Align Center", - "Align Center", - True, - ) - align_center.triggered.connect(lambda x: self.setAlignment(Qt.AlignCenter)) - - align_right = build_action( - toolbarBottom, - "assets/icons/svg_align_right", - "Align Right", - "Align Right", - True, - ) - align_right.triggered.connect(lambda x: self.setAlignment(Qt.AlignRight)) - - bold = build_action( - toolbarBottom, "assets/icons/svg_font_bold", "Bold", "Bold", True - ) - bold.toggled.connect(lambda x: self.setFontWeightCustom(700 if x else 500)) - - italic = build_action( - toolbarBottom, "assets/icons/svg_font_italic", "Italic", "Italic", True - ) - italic.toggled.connect(lambda x: self.setFontItalicCustom(True if x else False)) - - underline = build_action( - toolbarBottom, - "assets/icons/svg_font_underline", - "Underline", - "Underline", - True, - ) - underline.toggled.connect( - lambda x: self.setFontUnderlineCustom(True if x else False) - ) - - fontColor = build_action( - toolbarBottom, - "assets/icons/svg_font_color", - "Font Color", - "Font Color", - False, - ) - fontColor.triggered.connect( - lambda: self.setTextColorCustom(QColorDialog.getColor()) - ) - - bgColor = build_action( - toolbarBottom, - "assets/icons/svg_font_bucket", - "Background Color", - "Background Color", - False, - ) - # bgColor.triggered.connect(lambda: self.setBackgroundColor(QColorDialog.getColor())) - bgColor.triggered.connect( - lambda: self.changeBackgroundColorEvent(QColorDialog.getColor()) - ) - textboxColor = build_action( - toolbarBottom, - "assets/icons/svg_textboxColor", - "Background Color", - "Background Color", - False, - ) - textboxColor.triggered.connect( - lambda: self.changeTextboxColorEvent(QColorDialog.getColor()) - ) - - bullets = build_action( - toolbarBottom, "assets/icons/svg_bullets", "Bullets", "Bullets", True - ) - bullets.toggled.connect(lambda: self.bullet_list("bulletReg")) - - bullets_num = build_action( - toolbarBottom, - "assets/icons/svg_bullet_number", - "Bullets Num", - "Bullets Num", - True, - ) - bullets_num.toggled.connect(lambda: self.bullet_list("bulletNum")) - - toolbarTop.addWidget(font) - toolbarTop.addWidget(size) - - toolbarBottom.addActions( - [ - align_left, - align_center, - align_right, - bold, - italic, - underline, - fontColor, - bgColor, - bullets, - bullets_num, - ] - ) - - qwaTop = QWidgetAction(self) - qwaTop.setDefaultWidget(toolbarTop) - qwaBottom = QWidgetAction(self) - qwaBottom.setDefaultWidget(toolbarBottom) - - return [qwaTop, qwaBottom] + def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): + action = QAction(QIcon(icon_path), action_name, parent) + action.setStatusTip(set_status_tip) + action.setCheckable(set_checkable) + return action + + toolbarTop = QToolBar() + toolbarTop.setIconSize(QSize(25, 25)) + toolbarTop.setMovable(False) + + toolbarBottom = QToolBar() + toolbarBottom.setIconSize(QSize(25, 25)) + toolbarBottom.setMovable(False) + + font = QFontComboBox() + font.currentFontChanged.connect(lambda x: self.setCurrentFontCustom(font.currentFont() if x else self.currentFont())) + + size = QComboBox() + size.addItems([str(fs) for fs in FONT_SIZES]) + size.currentIndexChanged.connect(lambda x: self.setFontPointSizeCustom(FONT_SIZES[x] if x else self.fontPointSize())) + + bold = build_action(toolbarBottom, 'assets/icons/svg_font_bold', "Bold", "Bold", True) + bold.toggled.connect(lambda x: self.setFontWeightCustom(700 if x else 500)) + + italic = build_action(toolbarBottom, 'assets/icons/svg_font_italic', "Italic", "Italic", True) + italic.toggled.connect(lambda x: self.setFontItalicCustom(True if x else False)) + + underline = build_action(toolbarBottom, 'assets/icons/svg_font_underline', "Underline", "Underline", True) + underline.toggled.connect(lambda x: self.setFontUnderlineCustom(True if x else False)) + + fontColor = build_action(toolbarBottom, 'assets/icons/svg_font_color', "Font Color", "Font Color", False) + fontColor.triggered.connect(lambda x: self.setTextColorCustom(QColorDialog.getColor())) + + bgColor = build_action(toolbarBottom, 'assets/icons/svg_font_bucket', "Text Box Color", "Text Box Color", False) + bgColor.triggered.connect(lambda x: self.setBackgroundColor(QColorDialog.getColor())) + + toolbarTop.addWidget(font) + toolbarTop.addWidget(size) + toolbarBottom.addActions([bold, italic, underline, fontColor, bgColor]) + qwaTop = QWidgetAction(self) + qwaTop.setDefaultWidget(toolbarTop) + qwaBottom = QWidgetAction(self) + qwaBottom.setDefaultWidget(toolbarBottom) + + return [qwaTop, qwaBottom] def setFontItalicCustom(self, italic: bool): if not self.applyToAllIfNoSelection(lambda: self.setFontItalic(italic)): - print("setFontItalicCustom Called") self.setFontItalic(italic) def setFontWeightCustom(self, weight: int): @@ -243,7 +115,8 @@ def setTextColorCustom(self, color): def setBackgroundColor(self, color: QColor): rgb = color.getRgb() - self.setStyleSheet(f"background-color: rgb({rgb[0]}, {rgb[1]}, {rgb[2]});") + self.setStyleSheet(f'background-color: rgb({rgb[0]}, {rgb[1]}, {rgb[2]});') + # If no text is selected, apply to all, else apply to selection def applyToAllIfNoSelection(self, func): @@ -264,221 +137,3 @@ def applyToAllIfNoSelection(self, func): cursor.clearSelection() self.setTextCursor(cursor) return True - - def attributeChangedSlot(attribute, value): - if attribute == editorSignalsInstance.ChangedWidgetAttribute.FontBold: - print("Font Bold Signal") - - def slot_action2(self): - print("Action 2 Triggered") - font = QFont() - font.setItalic(True) - self.setFont(font) - - def changeFontSizeEvent(self, weight): - print("changeFontSizeEvent Called") - self.setFontWeightCustom(weight) - - # for communicating the signal editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontItalic, None) - # current issue for Event Functions: Only affects highlighted - - def changeFontItalicEvent(self): - cursor = self.textCursor() - current_format = cursor.charFormat() - - # Checks if currently selected text is italics - is_italic = current_format.fontItalic() - - # toggles the italics - current_format.setFontItalic(not is_italic) - - # Apply modified format to selected text - cursor.setCharFormat(current_format) - - # Update text cursor with modified format - self.setTextCursor(cursor) - - def changeFontBoldEvent(self): - cursor = self.textCursor() - current_format = cursor.charFormat() - - # Checks if currently selected text is bold - is_bold = current_format.fontWeight() == 700 - - # toggles the italics - if is_bold: - current_format.setFontWeight(500) - else: - current_format.setFontWeight(700) - # Apply modified format to selected text - cursor.setCharFormat(current_format) - - # Update text cursor with modified format - self.setTextCursor(cursor) - - def changeFontUnderlineEvent(self): - cursor = self.textCursor() - current_format = cursor.charFormat() - - # Checks if currently selected text is bold - is_underlined = current_format.fontUnderline() - - # toggles the underline - current_format.setFontUnderline(not is_underlined) - - # Apply modified format to selected text - cursor.setCharFormat(current_format) - - # Update text cursor with modified format - self.setTextCursor(cursor) - - def bullet_list(self, bulletType): - cursor = self.textCursor() - textList = cursor.currentList() - - if textList: - start = cursor.selectionStart() - end = cursor.selectionEnd() - removed = 0 - for i in range(textList.count()): - item = textList.item(i - removed) - if item.position() <= end and item.position() + item.length() > start: - textList.remove(item) - blockCursor = QTextCursor(item) - blockFormat = blockCursor.blockFormat() - blockFormat.setIndent(0) - blockCursor.mergeBlockFormat(blockFormat) - removed += 1 - - cursor = self.textCursor() - cursor.setBlockFormat(QTextBlockFormat()) # Clear any previous block format - - self.setTextCursor(cursor) - self.setFocus() - - else: - listFormat = QTextListFormat() - - if bulletType == "bulletNum": - style = QTextListFormat.ListDecimal - if bulletType == "bulletReg": - style = QTextListFormat.ListDisc - - listFormat.setStyle(style) - cursor.createList(listFormat) - - self.setTextCursor(cursor) - self.setFocus() - - def handleTabKey(self): - cursor = self.textCursor() - block = cursor.block() - block_format = block.blockFormat() - textList = cursor.currentList() - - if textList: - if cursor.atBlockStart() and block.text().strip() == "": - current_indent = block_format.indent() - - if current_indent == 0: - block_format.setIndent(1) - cursor.setBlockFormat(block_format) - cursor.beginEditBlock() - list_format = QTextListFormat() - currentStyle = textList.format().style() - - if currentStyle == QTextListFormat.ListDisc: - list_format.setStyle(QTextListFormat.ListCircle) - if currentStyle == QTextListFormat.ListDecimal: - list_format.setStyle(QTextListFormat.ListLowerAlpha) - - cursor.createList(list_format) - cursor.endEditBlock() - - if current_indent == 1: - block_format.setIndent(2) - cursor.setBlockFormat(block_format) - cursor.beginEditBlock() - list_format = QTextListFormat() - currentStyle = textList.format().style() - - if currentStyle == QTextListFormat.ListCircle: - list_format.setStyle(QTextListFormat.ListSquare) - if currentStyle == QTextListFormat.ListLowerAlpha: - list_format.setStyle(QTextListFormat.ListLowerRoman) - - cursor.createList(list_format) - cursor.endEditBlock() - - cursor.insertText("") - cursor.movePosition(QTextCursor.StartOfBlock) - self.setTextCursor(cursor) - - else: - # maybe add manual tab or diff functionality? - pass - - def changeFontSizeEvent(self, value): - # todo: when textbox is in focus, font size on toolbar should match the font size of the text - - cursor = self.textCursor() - current_format = cursor.charFormat() - - current_format.setFontPointSize(value) - cursor.setCharFormat(current_format) - - self.setTextCursor(cursor) - - def changeFontEvent(self, font_style): - cursor = self.textCursor() - current_format = cursor.charFormat() - current_format.setFont(font_style) - - cursor.setCharFormat(current_format) - - self.setTextCursor(cursor) - - # Changes font text color - def changeFontColorEvent(self, new_font_color): - cursor = self.textCursor() - current_format = cursor.charFormat() - - color = QColor(new_font_color) - current_format.setForeground(color) - - cursor.setCharFormat(current_format) - - # to not get stuck on highlighted text - # self.deselectText() - # self.setTextCursor(cursor) - - # Changes color of whole background - def changeBackgroundColorEvent(self, color: QColor): - # if self.hasFocus(): - rgb = color.getRgb() - self.setStyleSheet(f"background-color: rgb({rgb[0]}, {rgb[1]}, {rgb[2]});") - self.deselectText() - - # Changes textbox background color - def changeTextboxColorEvent(self, new_bg_color): - cursor = self.textCursor() - current_format = cursor.charFormat() - - color = QColor(new_bg_color) - current_format.setBackground(color) - - cursor.setCharFormat(current_format) - # self.deselectText() - - # self.setTextCursor(cursor) - - # Used to remove text highlighting - def deselectText(self): - cursor = self.textCursor() - cursor.clearSelection() - self.setTextCursor(cursor) - - # Adds bullet list to text - def changeBulletEvent(self): - # put bullet function here - print("bullet press") diff --git a/requirements.txt b/requirements.txt index 014744bc855bf85048072fabb05657b935994c80..f573bd8c25c581a2732c014309842490ca55a622 100644 GIT binary patch literal 276 zcma)%!3x4K5JcZu@KY*Uwc^2p2k!;HK&@a=Qz6yj&sQgN6cHJch0NRC$*T|CxpL#l zN}4btXQq3~kO7UHBY^`CGE*%ly#~{XTj-2kb9a=~T%?B1%u?RmOqy3}&sIdGsfGRG jho7+)S$SXlgWeFOl(*H6ol<=3iuys#UQ^FzKXbeRcKs<; literal 135 zcmaFAdw*VOZb7A;t)ZTgiJmc6enDzpa+z*HWl2VUo}I0Up1GcZp1BcMKxR%(ez~2k zrJkvt0arj}aAr!XnVqc}GFR6zB_%(v7+uu0xHvVhBr`DwE>oP5nUtTMng=%k0Fo6c Aga7~l From e247b96e056f8fccf9d5b30d44fb2596faa89e08 Mon Sep 17 00:00:00 2001 From: ldeltastreaml <70774713+ldeltastreaml@users.noreply.github.com> Date: Wed, 6 Dec 2023 13:32:25 -0600 Subject: [PATCH 060/127] Merge two versions of screensnip added functionality between the various versions. --- Modules/Screensnip.py | 44 +++++++++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/Modules/Screensnip.py b/Modules/Screensnip.py index 86950eb..4aed07c 100644 --- a/Modules/Screensnip.py +++ b/Modules/Screensnip.py @@ -13,19 +13,26 @@ class SnippingWidget(QWidget): def __init__(self): super(SnippingWidget, self).__init__() - self.setWindowFlags(Qt.WindowStaysOnTopHint) + + if platform == "linux": + self.setWindowFlags(Qt.FramelessWindowHint) + self.setAttributes(Qt.WA_TranslucentBackground) + + self.setWindowFlags(Qt.WindowStaysOnTopHint) self.parent = None self.screen = QApplication.instance().primaryScreen() self.setGeometry(0, 0, self.screen.size().width(), self.screen.size().height()) - self.begin = QPoint() - self.end = QPoint() + self.begin = self.end = QPoint() self.onSnippingCompleted = None self.event_pos = None def start(self, event_pos): print("SnippingWidget.start") SnippingWidget.is_snipping = True - self.setWindowOpacity(0.3) + + if platform != "linux": + self.setWindowOpacity(0.3) + QApplication.setOverrideCursor(QCursor(Qt.CrossCursor)) self.event_pos = event_pos self.show() @@ -36,6 +43,15 @@ def paintEvent(self, event): brush_color = (128, 128, 255, 100) lw = 3 opacity = 0.3 + + if platform != "linux": + self.setWindowOpacity(opacity) + + qp = QPainter(self) + qp.setPen(QPen(QColor('black'), lw)) + qp.setBrush(QColor(*brush_color)) + rect = QRectF(self.begin, self.end) + qp.drawRect(rect) else: self.begin = QPoint() self.end = QPoint() @@ -43,13 +59,6 @@ def paintEvent(self, event): lw = 0 opacity = 0 - self.setWindowOpacity(opacity) - qp = QPainter(self) - qp.setPen(QPen(QColor('black'), lw)) - qp.setBrush(QColor(*brush_color)) - rect = QRectF(self.begin, self.end) - qp.drawRect(rect) - def mousePressEvent(self, event): self.begin = event.pos() self.end = self.begin @@ -70,11 +79,14 @@ def mouseReleaseEvent(self, event): self.repaint() QApplication.processEvents() - if platform == "darwin": - img = ImageGrab.grab(bbox=( (x1 ) * 2, (y1 + 55 ) * 2, (x2 ) * 2, (y2 + 55) * 2)) - else: - img = ImageGrab.grab(bbox=(x1 + 10, y1 + 30, x2 + 10, y2 + 40)) - + try: + if platform == "darwin": + img = ImageGrab.grab(bbox=( (x1 ) * 2, (y1 + 55 ) * 2, (x2 ) * 2, (y2 + 55) * 2)) + else: + img = ImageGrab.grab(bbox=(x1 + 10, y1 + 30, x2 + 10, y2 + 40)) + except Exception as e: + print(f"Error grabbing screenshot: {e}") + img = None try: From 3be6ae9b35801a00b0a1ecc4c50e01523e51f814 Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Wed, 6 Dec 2023 15:22:39 -0600 Subject: [PATCH 061/127] Fixing issues --- Modules/BuildUI.py | 47 ---------------------------------------- Modules/EditorSignals.py | 9 ++++++++ Modules/Load.py | 3 --- Modules/Undo.py | 1 + 4 files changed, 10 insertions(+), 50 deletions(-) diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index 0f24dac..d282782 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -13,19 +13,12 @@ def build_ui(editor): print("Building UI...") -<<<<<<< Updated upstream - #editor.statusBar = editor.statusBar() - build_window(editor) - build_menubar(editor) - #build_toolbar(editor) -======= # editor.EditorFrameView = EditorFrameView(editor) # editor.statusBar = editor.statusBar() build_window(editor) build_menubar(editor) build_toolbar(editor) # build_test_toolbar(editor) ->>>>>>> Stashed changes # Application's main layout (grid) gridLayout = QGridLayout() @@ -67,14 +60,11 @@ def build_ui(editor): gridLayout.addWidget(leftSideContainerWidget, 0, 0) gridLayout.addWidget(rightSideContainerWidget, 0, 1) -<<<<<<< Updated upstream -======= addSectionButton = QPushButton("Add Section") # add functionality e.g. addSectionButton.clcicked.connect(editor.add_section_function) leftSideLayout.addWidget(addSectionButton) ->>>>>>> Stashed changes def build_window(editor): editor.setWindowTitle("OpenNote") editor.setWindowIcon(QIcon("./Assets/OpenNoteLogo.png")) @@ -83,13 +73,6 @@ def build_window(editor): editor.setStyleSheet(fh.read()) -<<<<<<< Updated upstream - new_file = build_action(editor, 'assets/icons/svg_file_open', 'New Notebook...', 'New Notebook', False) - new_file.setShortcut(QKeySequence.StandardKey.New) - new_file.triggered.connect(lambda: new(editor)) - - open_file = build_action(editor, 'assets/icons/svg_file_open', 'Open Notebook...', 'Open Notebook', False) -======= def build_menubar(editor): file = editor.menuBar().addMenu("&File") plugins = editor.menuBar().addMenu("&Plugins") @@ -113,7 +96,6 @@ def build_menubar(editor): open_file = build_action( editor, "assets/icons/svg_file_open", "Open Notebook", "Open Notebook", False ) ->>>>>>> Stashed changes open_file.setShortcut(QKeySequence.StandardKey.Open) open_file.triggered.connect(lambda: load(editor)) @@ -142,10 +124,6 @@ def build_toolbar(editor): toolbar.setMovable(False) editor.addToolBar(Qt.ToolBarArea.TopToolBarArea, toolbar) -<<<<<<< Updated upstream - font = QFontComboBox() - font.currentFontChanged.connect(lambda x: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Font, font.currentFont())) -======= # separates toolbar with a line break spacer = QWidget() spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) @@ -161,7 +139,6 @@ def build_toolbar(editor): ChangedWidgetAttribute.Font, font.currentFont() ) ) ->>>>>>> Stashed changes size = QComboBox() size.addItems([str(fs) for fs in FONT_SIZES]) @@ -171,23 +148,6 @@ def build_toolbar(editor): ) ) -<<<<<<< Updated upstream - fontColor = build_action(toolbar, 'assets/icons/svg_font_color', "Font Color", "Font Color", False) - fontColor.triggered.connect(lambda x: openGetColorDialog(purpose = "font")) - - bgColor = build_action(toolbar, 'assets/icons/svg_font_bucket', "Text Box Color", "Text Box Color", False) - bgColor.triggered.connect(lambda x: openGetColorDialog(purpose = "background")) - - bold = build_action(toolbar, 'assets/icons/bold', "Bold", "Bold", True) - bold.triggered.connect(lambda x: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontBold, None)) - - italic = build_action(toolbar, 'assets/icons/italic.svg', "Italic", "Italic", True) - italic.triggered.connect(lambda x: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontItalic, None)) - - underline = build_action(toolbar, 'assets/icons/underline.svg', "Underline", "Underline", True) - underline.triggered.connect(lambda x: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontUnderline, None)) - -======= bgColor = build_action( toolbar, "assets/icons/svg_font_bucket", @@ -252,12 +212,9 @@ def build_toolbar(editor): # toolbar.addActions([undo, redo]) toolbar.addSeparator() ->>>>>>> Stashed changes toolbar.addWidget(font) toolbar.addWidget(size) toolbar.addActions([bgColor, fontColor, bold, italic, underline]) -<<<<<<< Updated upstream -======= toolbar.addSeparator() toolbar.addActions([table, hyperlink, bullets]) @@ -267,7 +224,6 @@ def toggle_bold(self): font = self.text_edit ->>>>>>> Stashed changes def openGetColorDialog(purpose): color = QColorDialog.getColor() @@ -286,8 +242,6 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): action = QAction(QIcon(icon_path), action_name, parent) action.setStatusTip(set_status_tip) return action -<<<<<<< Updated upstream -======= def build_test_toolbar(self): @@ -331,4 +285,3 @@ def change_font(self): def widgetAttributeChangedEvent(self, draggableContainer): editorSignalsInstance.widgetAttributeChanged.emit(draggableContainer) ->>>>>>> Stashed changes diff --git a/Modules/EditorSignals.py b/Modules/EditorSignals.py index 97d3873..b85e42f 100644 --- a/Modules/EditorSignals.py +++ b/Modules/EditorSignals.py @@ -3,6 +3,8 @@ from enum import Enum class ChangedWidgetAttribute(Enum): + # Used for unique signals + # Add variable to create a unique signal BackgroundColor = 0 FontColor = 1 Font = 2 @@ -10,6 +12,10 @@ class ChangedWidgetAttribute(Enum): FontBold = 4 FontItalic = 5 FontUnderline = 6 + TextboxColor = 7 + Bullet = 8 + Bullet_Num = 9 + LoseFocus = 10 # Cant be statically typed because importing the classes causes circular imports @@ -33,4 +39,7 @@ class EditorSignals(QObject): # Recieves nothing, used by autosaver changeMade = Signal() + # Clear Selection + loseFocus = Signal() + editorSignalsInstance = EditorSignals() diff --git a/Modules/Load.py b/Modules/Load.py index 0592cde..5e3e3a5 100644 --- a/Modules/Load.py +++ b/Modules/Load.py @@ -39,8 +39,6 @@ def new(editor): editor.autosaver = Autosaver(editor) build(editor) # should we build here, or should above be in build? -<<<<<<< Updated upstream -======= def add_new_notebook(editor): destroy(editor) @@ -54,7 +52,6 @@ def add_new_notebook(editor): editor.autosaver = Autosaver(editor) build(editor) ->>>>>>> Stashed changes # Loads models.notebook.Notebook class from file def load(editor): diff --git a/Modules/Undo.py b/Modules/Undo.py index d44eefc..fe67575 100644 --- a/Modules/Undo.py +++ b/Modules/Undo.py @@ -4,6 +4,7 @@ from Modules.EditorSignals import editorSignalsInstance import os + class UndoActionCreate: def __init__(self, draggableContainer): self.draggableContainer = draggableContainer From 54a46ff54e5fd361d231c2b943ecbcf2b92bb92f Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Wed, 6 Dec 2023 15:56:21 -0600 Subject: [PATCH 062/127] Update snipping tool --- Modules/Screensnip.py | 61 +++++++++++++++++++++++-------------------- 1 file changed, 33 insertions(+), 28 deletions(-) diff --git a/Modules/Screensnip.py b/Modules/Screensnip.py index e52c194..4aed07c 100644 --- a/Modules/Screensnip.py +++ b/Modules/Screensnip.py @@ -13,8 +13,12 @@ class SnippingWidget(QWidget): def __init__(self): super(SnippingWidget, self).__init__() - self.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.FramelessWindowHint) - self.setAttribute(Qt.WA_TranslucentBackground) + + if platform == "linux": + self.setWindowFlags(Qt.FramelessWindowHint) + self.setAttributes(Qt.WA_TranslucentBackground) + + self.setWindowFlags(Qt.WindowStaysOnTopHint) self.parent = None self.screen = QApplication.instance().primaryScreen() self.setGeometry(0, 0, self.screen.size().width(), self.screen.size().height()) @@ -25,44 +29,56 @@ def __init__(self): def start(self, event_pos): print("SnippingWidget.start") SnippingWidget.is_snipping = True + + if platform != "linux": + self.setWindowOpacity(0.3) + QApplication.setOverrideCursor(QCursor(Qt.CrossCursor)) self.event_pos = event_pos self.show() print("SnippingWidget.start done") def paintEvent(self, event): - qp = QPainter(self) if SnippingWidget.is_snipping: brush_color = (128, 128, 255, 100) lw = 3 + opacity = 0.3 + + if platform != "linux": + self.setWindowOpacity(opacity) + + qp = QPainter(self) qp.setPen(QPen(QColor('black'), lw)) qp.setBrush(QColor(*brush_color)) rect = QRectF(self.begin, self.end) qp.drawRect(rect) + else: + self.begin = QPoint() + self.end = QPoint() + brush_color = (0, 0, 0, 0) + lw = 0 + opacity = 0 def mousePressEvent(self, event): - try: - self.begin = event.pos() - self.end = self.begin - self.update() - except Exception as e: - print(f"Error handling mouse press event: {e}") + self.begin = event.pos() + self.end = self.begin + self.update() def mouseMoveEvent(self, event): - try: - self.end = event.pos() - self.update() - except Exception as e: - print(f"Error handling mouse move event: {e}") + self.end = event.pos() + self.update() def mouseReleaseEvent(self, event): SnippingWidget.is_snipping = False QApplication.restoreOverrideCursor() - x1, y1, x2, y2 = self.getSnipCoordinates() + x1 = min(self.begin.x(), self.end.x()) + y1 = min(self.begin.y(), self.end.y()) + x2 = max(self.begin.x(), self.end.x()) + y2 = max(self.begin.y(), self.end.y()) self.repaint() QApplication.processEvents() - + try: if platform == "darwin": img = ImageGrab.grab(bbox=( (x1 ) * 2, (y1 + 55 ) * 2, (x2 ) * 2, (y2 + 55) * 2)) @@ -72,24 +88,13 @@ def mouseReleaseEvent(self, event): print(f"Error grabbing screenshot: {e}") img = None + try: img = cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR) except: - print(f"Error converting screenshot to NumPy array: {e}") img = None if self.onSnippingCompleted is not None: self.onSnippingCompleted(img) self.close() - - def getSnipCoordinates(self): - try: - x1 = min(self.begin.x(), self.end.x()) - y1 = min(self.begin.y(), self.end.y()) - x2 = max(self.begin.x(), self.end.x()) - y2 = max(self.begin.y(), self.end.y()) - return x1, y1, x2, y2 - except Exception as e: - print(f"Error getting snip coordinates {e}") - return 0, 0, 0, 0 \ No newline at end of file From 50ca9b72f60692ce8c2745f42c030826166840e9 Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Wed, 6 Dec 2023 15:58:49 -0600 Subject: [PATCH 063/127] removed message --- Models/DraggableContainer.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Models/DraggableContainer.py b/Models/DraggableContainer.py index b35bb5e..66d460b 100644 --- a/Models/DraggableContainer.py +++ b/Models/DraggableContainer.py @@ -70,7 +70,6 @@ def eventFilter(self, obj, e): # If child widget resized itsself, resize this drag container, not ideal bc child resizes on hover if isinstance(e, QResizeEvent): - print("resize event for draggable container") self.resize(self.childWidget.size()) return False From 61dbd956840545dc955a39805ae50a4403ecb2f8 Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Wed, 6 Dec 2023 16:13:29 -0600 Subject: [PATCH 064/127] Expand and shrink images Bug: expanding passed a certain point will stop expanding the border but the image will continue to expand. --- Assets/icons/svg_expand.svg | 7 +++++++ Assets/icons/svg_shrink.svg | 7 +++++++ Widgets/Image.py | 23 ++++++++++++++++++++++- 3 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 Assets/icons/svg_expand.svg create mode 100644 Assets/icons/svg_shrink.svg diff --git a/Assets/icons/svg_expand.svg b/Assets/icons/svg_expand.svg new file mode 100644 index 0000000..e93075a --- /dev/null +++ b/Assets/icons/svg_expand.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/Assets/icons/svg_shrink.svg b/Assets/icons/svg_shrink.svg new file mode 100644 index 0000000..60f9607 --- /dev/null +++ b/Assets/icons/svg_shrink.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/Widgets/Image.py b/Widgets/Image.py index beeb6c5..12ee0d0 100644 --- a/Widgets/Image.py +++ b/Widgets/Image.py @@ -95,8 +95,13 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): rotateRightAction = build_action(toolbarBottom, 'assets/icons/svg_rotate_right', "Rotate 90 degrees Right", "Rotate 90 degrees Right", False) rotateRightAction.triggered.connect(self.rotate90Right) + shrinkImageAction = build_action(toolbarBottom, 'assets/icons/svg_shrink', "Rotate 90 degrees Right", "Rotate 90 degrees Right", False) + shrinkImageAction.triggered.connect(self.shrinkImage) + expandImageAction = build_action(toolbarBottom, 'assets/icons/svg_expand', "Rotate 90 degrees Right", "Rotate 90 degrees Right", False) + expandImageAction.triggered.connect(self.expandImage) - toolbarBottom.addActions([rotateLeftAction, rotateRightAction, flipHorizontal, flipVertical]) + + toolbarBottom.addActions([rotateLeftAction, rotateRightAction, flipHorizontal, flipVertical, shrinkImageAction, expandImageAction]) qwaBottom = QWidgetAction(self) qwaBottom.setDefaultWidget(toolbarBottom) @@ -122,6 +127,22 @@ def rotate90Right(self): self.image_matrix = cv2.rotate(self.image_matrix, cv2.ROTATE_90_CLOCKWISE) self.updatePixmap() + def shrinkImage(self): + # Decrease image size by 10% + self.w = int(self.w * 0.9) + self.h = int(self.h * 0.9) + self.updateImageSize() + + def expandImage(self): + # Increase image size by 10% + self.w = int(self.w * 1.1) + self.h = int(self.h * 1.1) + self.updateImageSize() + + def updateImageSize(self): + # Update the displayed pixmap with the new size + self.setPixmap(self.q_pixmap.scaled(self.w, self.h, Qt.KeepAspectRatio, Qt.SmoothTransformation)) + def updatePixmap(self): # Update the QImage and QPixmap matrix_height, matrix_width, _ = self.image_matrix.shape From 6b5828c7f3886ac0e3d06beacf354aa5b1f36241 Mon Sep 17 00:00:00 2001 From: sillypenguin77 <67487654+sillypenguin77@users.noreply.github.com> Date: Wed, 6 Dec 2023 18:06:55 -0600 Subject: [PATCH 065/127] Deleted unnecessary line --- Views/EditorFrameView.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Views/EditorFrameView.py b/Views/EditorFrameView.py index 624d543..24890b3 100644 --- a/Views/EditorFrameView.py +++ b/Views/EditorFrameView.py @@ -15,7 +15,6 @@ from Widgets.Table import * from Modules.Clipboard import Clipboard from Modules.Undo import UndoHandler -from Widgets.Link import LinkWidget from Widgets.Link import LinkDialog From 196f8d7f909482580e4e14582484b6e4f7965674 Mon Sep 17 00:00:00 2001 From: sillypenguin77 <67487654+sillypenguin77@users.noreply.github.com> Date: Wed, 6 Dec 2023 18:40:17 -0600 Subject: [PATCH 066/127] Hyperlink now part of textbox widget class Hyperlink is no longer its own widget, but it is instead part of the textbox widget class --- Views/EditorFrameView.py | 17 +++++++++++++++-- Widgets/Textbox.py | 11 ++++++++++- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/Views/EditorFrameView.py b/Views/EditorFrameView.py index 24890b3..c10a455 100644 --- a/Views/EditorFrameView.py +++ b/Views/EditorFrameView.py @@ -197,11 +197,24 @@ def mousePressEvent(self, event): frame_menu.addAction(add_custom_widget) insert_Link = QAction("Insert Link", editor) - insert_Link.triggered.connect(lambda: self.newWidgetOnSection(LinkWidget,event.pos())) + insert_Link.triggered.connect(lambda: self.insertLink(event.pos())) frame_menu.addAction(insert_Link) frame_menu.exec(event.globalPos()) + def insertLink(self, clickPos): + link_dialog = LinkDialog() + result = link_dialog.exec_() + if result == QDialog.Accepted: + link_address, display_text = link_dialog.get_link_data() + textboxWidget = TextboxWidget.new(clickPos) + textboxWidget.insertTextLink(link_address, display_text) + dc = DraggableContainer(textboxWidget, self) + dc.show() + self.undoHandler.pushCreate(dc) + editorSignalsInstance.widgetAdded.emit(dc) + editorSignalsInstance.changeMade.emit() + def center_of_screen(self): editor_frame_geometry = self.editorFrame.geometry() print(f"editor_frame_geometry.width() is {editor_frame_geometry.width()}") @@ -222,7 +235,7 @@ def toolbar_hyperlink(self): print("toolbar_hyperlink pressed") center_x, center_y = self.center_of_screen() clickPos = QPoint(center_x, center_y) - self.newWidgetOnSection(LinkWidget, clickPos) + self.insertLink(clickPos) def addCustomWidget(self, e): def getCustomWidgets(): diff --git a/Widgets/Textbox.py b/Widgets/Textbox.py index c97f2c0..6e6b727 100644 --- a/Widgets/Textbox.py +++ b/Widgets/Textbox.py @@ -6,7 +6,7 @@ FONT_SIZES = [7, 8, 9, 10, 11, 12, 13, 14, 18, 24, 36, 48, 64, 72, 96, 144, 288] -class TextboxWidget(QTextEdit): +class TextboxWidget(QTextBrowser): def __init__(self, x, y, w=15, h=30, t=""): super().__init__() @@ -19,6 +19,8 @@ def __init__(self, x, y, w=15, h=30, t=""): self.setStyleSheet("background-color: rgba(0, 0, 0, 0);") self.setTextColor("black") + self.setTextInteractionFlags(Qt.TextEditorInteraction | Qt.TextBrowserInteraction) + self.installEventFilter(self) def eventFilter(self, obj, event): @@ -418,6 +420,13 @@ def handleTabKey(self): # maybe add manual tab or diff functionality? pass + def insertTextLink(self, link_address, display_text): + self.setOpenExternalLinks(True) + link_html = f'{display_text}' + cursor = self.textCursor() + cursor.insertHtml(link_html) + QDesktopServices.openUrl(link_html) + def changeFontSizeEvent(self, value): # todo: when textbox is in focus, font size on toolbar should match the font size of the text From c9454b562c849813c382c4b0d563e0fe9f8d6d77 Mon Sep 17 00:00:00 2001 From: sillypenguin77 <67487654+sillypenguin77@users.noreply.github.com> Date: Wed, 6 Dec 2023 18:58:24 -0600 Subject: [PATCH 067/127] Added manual tab indent This works on regular plain text --- Views/EditorFrameView.py | 2 -- Widgets/Textbox.py | 5 +++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Views/EditorFrameView.py b/Views/EditorFrameView.py index c10a455..3ec1fa1 100644 --- a/Views/EditorFrameView.py +++ b/Views/EditorFrameView.py @@ -223,8 +223,6 @@ def center_of_screen(self): center_y = (editor_frame_geometry.height() - 200) // 2 return center_x, center_y - - def toolbar_table(self): print("toolbar_table pressed") center_x, center_y = self.center_of_screen() diff --git a/Widgets/Textbox.py b/Widgets/Textbox.py index 6e6b727..1623eda 100644 --- a/Widgets/Textbox.py +++ b/Widgets/Textbox.py @@ -417,7 +417,8 @@ def handleTabKey(self): self.setTextCursor(cursor) else: - # maybe add manual tab or diff functionality? + cursor.insertText(" ") + self.setTextCursor(cursor) pass def insertTextLink(self, link_address, display_text): @@ -426,7 +427,7 @@ def insertTextLink(self, link_address, display_text): cursor = self.textCursor() cursor.insertHtml(link_html) QDesktopServices.openUrl(link_html) - + def changeFontSizeEvent(self, value): # todo: when textbox is in focus, font size on toolbar should match the font size of the text From 421124e705a5ac0fe611ccf9e652bcdf94892dff Mon Sep 17 00:00:00 2001 From: sillypenguin77 <67487654+sillypenguin77@users.noreply.github.com> Date: Wed, 6 Dec 2023 19:27:45 -0600 Subject: [PATCH 068/127] Updated bullets to stop at 12 nested cycles This makes it you can have a total of 12 nested bullets per list --- Widgets/Textbox.py | 81 ++++++++++++++++++++++++++++------------------ 1 file changed, 49 insertions(+), 32 deletions(-) diff --git a/Widgets/Textbox.py b/Widgets/Textbox.py index 1623eda..b6c0c58 100644 --- a/Widgets/Textbox.py +++ b/Widgets/Textbox.py @@ -382,38 +382,55 @@ def handleTabKey(self): if cursor.atBlockStart() and block.text().strip() == "": current_indent = block_format.indent() - if current_indent == 0: - block_format.setIndent(1) - cursor.setBlockFormat(block_format) - cursor.beginEditBlock() - list_format = QTextListFormat() - currentStyle = textList.format().style() - - if currentStyle == QTextListFormat.ListDisc: - list_format.setStyle(QTextListFormat.ListCircle) - if currentStyle == QTextListFormat.ListDecimal: - list_format.setStyle(QTextListFormat.ListLowerAlpha) - - cursor.createList(list_format) - cursor.endEditBlock() - - if current_indent == 1: - block_format.setIndent(2) - cursor.setBlockFormat(block_format) - cursor.beginEditBlock() - list_format = QTextListFormat() - currentStyle = textList.format().style() - - if currentStyle == QTextListFormat.ListCircle: - list_format.setStyle(QTextListFormat.ListSquare) - if currentStyle == QTextListFormat.ListLowerAlpha: - list_format.setStyle(QTextListFormat.ListLowerRoman) - - cursor.createList(list_format) - cursor.endEditBlock() - - cursor.insertText("") - cursor.movePosition(QTextCursor.StartOfBlock) + if current_indent < 11: + + if current_indent % 3 == 0: + block_format.setIndent(current_indent + 1) + cursor.setBlockFormat(block_format) + cursor.beginEditBlock() + list_format = QTextListFormat() + currentStyle = textList.format().style() + + if currentStyle == QTextListFormat.ListDisc: + list_format.setStyle(QTextListFormat.ListCircle) + if currentStyle == QTextListFormat.ListDecimal: + list_format.setStyle(QTextListFormat.ListLowerAlpha) + + cursor.createList(list_format) + cursor.endEditBlock() + + if current_indent % 3 == 1: + block_format.setIndent(current_indent + 1) + cursor.setBlockFormat(block_format) + cursor.beginEditBlock() + list_format = QTextListFormat() + currentStyle = textList.format().style() + + if currentStyle == QTextListFormat.ListCircle: + list_format.setStyle(QTextListFormat.ListSquare) + if currentStyle == QTextListFormat.ListLowerAlpha: + list_format.setStyle(QTextListFormat.ListLowerRoman) + + cursor.createList(list_format) + cursor.endEditBlock() + + if current_indent % 3 == 2: + block_format.setIndent(current_indent + 1) + cursor.setBlockFormat(block_format) + cursor.beginEditBlock() + list_format = QTextListFormat() + currentStyle = textList.format().style() + + if currentStyle == QTextListFormat.ListSquare: + list_format.setStyle(QTextListFormat.ListDisc) + if currentStyle == QTextListFormat.ListLowerRoman: + list_format.setStyle(QTextListFormat.ListDecimal) + + cursor.createList(list_format) + cursor.endEditBlock() + + cursor.insertText("") + cursor.movePosition(QTextCursor.StartOfBlock) self.setTextCursor(cursor) else: From 385b7c85be138374c7e9fa82e7d68ca8e0d8e3d9 Mon Sep 17 00:00:00 2001 From: sillypenguin77 <67487654+sillypenguin77@users.noreply.github.com> Date: Wed, 6 Dec 2023 21:40:00 -0600 Subject: [PATCH 069/127] Added extra bullet point styles Added a dropdown menu to the main and lower toolbar for extra bullet point styles. --- Assets/icons/svg_arrow.svg | 4 ++++ Assets/icons/svg_bulletUA.svg | 4 ++++ Assets/icons/svg_bulletUR.svg | 4 ++++ Modules/BuildUI.py | 18 ++++++++++++++++ Widgets/Textbox.py | 40 +++++++++++++++++++++++++++++++++++ 5 files changed, 70 insertions(+) create mode 100644 Assets/icons/svg_arrow.svg create mode 100644 Assets/icons/svg_bulletUA.svg create mode 100644 Assets/icons/svg_bulletUR.svg diff --git a/Assets/icons/svg_arrow.svg b/Assets/icons/svg_arrow.svg new file mode 100644 index 0000000..9d990ed --- /dev/null +++ b/Assets/icons/svg_arrow.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Assets/icons/svg_bulletUA.svg b/Assets/icons/svg_bulletUA.svg new file mode 100644 index 0000000..74a1694 --- /dev/null +++ b/Assets/icons/svg_bulletUA.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Assets/icons/svg_bulletUR.svg b/Assets/icons/svg_bulletUR.svg new file mode 100644 index 0000000..7aee439 --- /dev/null +++ b/Assets/icons/svg_bulletUR.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index 76b1ef6..17501b6 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -195,6 +195,24 @@ def build_toolbar(editor): toolbar.addSeparator() toolbar.addActions([table, hyperlink, bullet_reg, bullet_num]) + bullets_menu = QMenu(editor) + + bulletUpperA = build_action(bullets_menu, './Assets/icons/svg_bulletUA', "", "", False) + bulletUpperA.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.bulletUpperA, None)) + + bulletUpperR = build_action(bullets_menu, './Assets/icons/svg_bulletUR', "", "", False) + bulletUpperR.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.bulletUpperR, None)) + + bullets_menu.addAction(bulletUpperA) + bullets_menu.addAction(bulletUpperR) + + bullets = QToolButton(editor) + bullets.setIcon(QIcon('./Assets/icons/svg_bullets')) + bullets.setPopupMode(QToolButton.InstantPopup) + bullets.setMenu(bullets_menu) + + toolbar.addWidget(bullets) + #toolbar.setStyleSheet("QToolBar { background-color: #FFFFFF; }") def openGetColorDialog(purpose): diff --git a/Widgets/Textbox.py b/Widgets/Textbox.py index b6c0c58..2ca2046 100644 --- a/Widgets/Textbox.py +++ b/Widgets/Textbox.py @@ -192,6 +192,7 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): ) bullets_num.toggled.connect(lambda: self.bullet_list("bulletNum")) + toolbarTop.addWidget(font) toolbarTop.addWidget(size) @@ -210,6 +211,21 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): ] ) + menu = QMenu(self) + bulletUpperA = menu.addAction(QIcon("assets/icons/svg_bulletUA"), "") + bulletUpperR = menu.addAction(QIcon("assets/icons/svg_bulletUR"), "") + + bulletUpperA.triggered.connect(lambda: self.bullet_list("bulletUpperA")) + bulletUpperR.triggered.connect(lambda: self.bullet_list("bulletUpperR")) + + + menu_button = QToolButton(self) + menu_button.setPopupMode(QToolButton.InstantPopup) + menu_button.setIcon(QIcon("assets/icons/svg_bullets")) + menu_button.setMenu(menu) + + toolbarBottom.addWidget(menu_button) + qwaTop = QWidgetAction(self) qwaTop.setDefaultWidget(toolbarTop) qwaBottom = QWidgetAction(self) @@ -365,6 +381,14 @@ def bullet_list(self, bulletType): style = QTextListFormat.ListDecimal if bulletType == "bulletReg": style = QTextListFormat.ListDisc + if bulletType == "bulletLowerA": + style = QTextListFormat.ListLowerAlpha + if bulletType == "bulletLowerR": + style = QTextListFormat.ListLowerRoman + if bulletType == "bulletUpperA": + style = QTextListFormat.ListUpperAlpha + if bulletType == "bulletUpperR": + style = QTextListFormat.ListUpperRoman listFormat.setStyle(style) cursor.createList(listFormat) @@ -395,6 +419,14 @@ def handleTabKey(self): list_format.setStyle(QTextListFormat.ListCircle) if currentStyle == QTextListFormat.ListDecimal: list_format.setStyle(QTextListFormat.ListLowerAlpha) + if currentStyle == QTextListFormat.ListLowerAlpha: + list_format.setStyle(QTextListFormat.ListLowerRoman) + if currentStyle == QTextListFormat.ListLowerRoman: + list_format.setStyle(QTextListFormat.ListDecimal) + if currentStyle == QTextListFormat.ListUpperAlpha: + list_format.setStyle(QTextListFormat.ListLowerAlpha) + if currentStyle == QTextListFormat.ListUpperRoman: + list_format.setStyle(QTextListFormat.ListLowerAlpha) cursor.createList(list_format) cursor.endEditBlock() @@ -410,6 +442,10 @@ def handleTabKey(self): list_format.setStyle(QTextListFormat.ListSquare) if currentStyle == QTextListFormat.ListLowerAlpha: list_format.setStyle(QTextListFormat.ListLowerRoman) + if currentStyle == QTextListFormat.ListLowerRoman: + list_format.setStyle(QTextListFormat.ListDecimal) + if currentStyle == QTextListFormat.ListDecimal: + list_format.setStyle(QTextListFormat.ListLowerAlpha) cursor.createList(list_format) cursor.endEditBlock() @@ -425,6 +461,10 @@ def handleTabKey(self): list_format.setStyle(QTextListFormat.ListDisc) if currentStyle == QTextListFormat.ListLowerRoman: list_format.setStyle(QTextListFormat.ListDecimal) + if currentStyle == QTextListFormat.ListDecimal: + list_format.setStyle(QTextListFormat.ListLowerAlpha) + if currentStyle == QTextListFormat.ListLowerAlpha: + list_format.setStyle(QTextListFormat.ListLowerRoman) cursor.createList(list_format) cursor.endEditBlock() From 9baac0337078e3751dff500babec43b4bd0b1242 Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Wed, 6 Dec 2023 22:50:01 -0600 Subject: [PATCH 070/127] Added signals --- Modules/EditorSignals.py | 3 +++ Widgets/Image.py | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/Modules/EditorSignals.py b/Modules/EditorSignals.py index b85e42f..e95b486 100644 --- a/Modules/EditorSignals.py +++ b/Modules/EditorSignals.py @@ -16,6 +16,9 @@ class ChangedWidgetAttribute(Enum): Bullet = 8 Bullet_Num = 9 LoseFocus = 10 + BulletUA = 11 + BulletUR = 12 + # Cant be statically typed because importing the classes causes circular imports diff --git a/Widgets/Image.py b/Widgets/Image.py index 12ee0d0..1265843 100644 --- a/Widgets/Image.py +++ b/Widgets/Image.py @@ -120,10 +120,13 @@ def flipHorizontal(self): def rotate90Left(self): # Rotate the image matrix 90 degrees to the left using OpenCV + self.w, self.h = self.h, self.w + self.image_matrix = cv2.rotate(self.image_matrix, cv2.ROTATE_90_COUNTERCLOCKWISE) self.updatePixmap() def rotate90Right(self): # Rotate the image matrix 90 degrees to the right using OpenCV + self.w, self.h = self.h, self.w self.image_matrix = cv2.rotate(self.image_matrix, cv2.ROTATE_90_CLOCKWISE) self.updatePixmap() @@ -142,6 +145,7 @@ def expandImage(self): def updateImageSize(self): # Update the displayed pixmap with the new size self.setPixmap(self.q_pixmap.scaled(self.w, self.h, Qt.KeepAspectRatio, Qt.SmoothTransformation)) + self.sizeChanged.emit(QSize(self.w, self.h)) def updatePixmap(self): # Update the QImage and QPixmap From 947a0a8b4b7c626d6b3e98703b2b6d15ae7a15ac Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Wed, 6 Dec 2023 23:22:52 -0600 Subject: [PATCH 071/127] BulletUpperA and bulletUpperR to toolbar --- Models/DraggableContainer.py | 6 ++++++ Modules/BuildUI.py | 16 ++-------------- Modules/EditorSignals.py | 2 ++ 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/Models/DraggableContainer.py b/Models/DraggableContainer.py index 66d460b..fc0c617 100644 --- a/Models/DraggableContainer.py +++ b/Models/DraggableContainer.py @@ -347,6 +347,12 @@ def widgetAttributeChanged(self, changedWidgetAttribute, value): elif hasattr(child_widget, "changeBulletEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.Bullet_Num): print("Change Bullet Event Called") child_widget.bullet_list("bulletNum") + elif hasattr(child_widget, "changeBulletEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.BulletUA): + print("Change Bullet Event Called") + child_widget.bullet_list("bulletUpperA") + elif hasattr(child_widget, "changeBulletEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.BulletUR): + print("Change Bullet Event Called") + child_widget.bullet_list("bulletUpperR") elif hasattr(child_widget, "changeBackgroundColorEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.BackgroundColor): print("Chang Background Color Event Called") child_widget.changeBackgroundColorEvent(value) diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index 17501b6..edc622c 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -174,18 +174,6 @@ def build_toolbar(editor): bullet_num = build_action(toolbar, './Assets/icons/svg_bullet_number', "Bullet List", "Bullet List", False) bullet_num.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Bullet_Num, None)) - ''' - editor.action1 = QAction('Action 1', editor) - #editor.action1.triggered.connect(EditorFrameView.slot_action1) - toolbar.addAction(editor.action1) - editor.action2 = QAction('Action 2', editor) - #editor.action2.triggered.connect(TextboxWidget.slot_action2) - #editor.action2.triggered.connect(show_popup) - toolbar.addAction(editor.action2) - #editor.button = QPushButton("Click Me", editor) - #editor.button.clicked.connect(editor.slot_button_click)''' - - toolbar.addActions([toolbar_undo, redo]) toolbar.addSeparator() toolbar.addWidget(font_family) @@ -198,10 +186,10 @@ def build_toolbar(editor): bullets_menu = QMenu(editor) bulletUpperA = build_action(bullets_menu, './Assets/icons/svg_bulletUA', "", "", False) - bulletUpperA.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.bulletUpperA, None)) + bulletUpperA.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.BulletUA, None)) bulletUpperR = build_action(bullets_menu, './Assets/icons/svg_bulletUR', "", "", False) - bulletUpperR.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.bulletUpperR, None)) + bulletUpperR.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.BulletUR, None)) bullets_menu.addAction(bulletUpperA) bullets_menu.addAction(bulletUpperR) diff --git a/Modules/EditorSignals.py b/Modules/EditorSignals.py index b85e42f..72af273 100644 --- a/Modules/EditorSignals.py +++ b/Modules/EditorSignals.py @@ -16,6 +16,8 @@ class ChangedWidgetAttribute(Enum): Bullet = 8 Bullet_Num = 9 LoseFocus = 10 + BulletUR = 11 + BulletUA = 12 # Cant be statically typed because importing the classes causes circular imports From f09f3efb67f141ae6581f6242269ca7f4874dfe5 Mon Sep 17 00:00:00 2001 From: ldeltastreaml <70774713+ldeltastreaml@users.noreply.github.com> Date: Thu, 7 Dec 2023 11:32:56 -0600 Subject: [PATCH 072/127] Update Screensnip.py --- Modules/Screensnip.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/Screensnip.py b/Modules/Screensnip.py index 4aed07c..a279497 100644 --- a/Modules/Screensnip.py +++ b/Modules/Screensnip.py @@ -16,7 +16,7 @@ def __init__(self): if platform == "linux": self.setWindowFlags(Qt.FramelessWindowHint) - self.setAttributes(Qt.WA_TranslucentBackground) + self.setAttribute(Qt.WA_TranslucentBackground) self.setWindowFlags(Qt.WindowStaysOnTopHint) self.parent = None From d53f4d80b2a75f2d3098068f56c47dc4a6233dce Mon Sep 17 00:00:00 2001 From: ldeltastreaml <70774713+ldeltastreaml@users.noreply.github.com> Date: Wed, 7 Feb 2024 16:58:42 -0600 Subject: [PATCH 073/127] asset location fixed Properly set location of assets to accommodate Linux --- Widgets/Image.py | 12 ++++++------ Widgets/Textbox.py | 28 ++++++++++++++-------------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/Widgets/Image.py b/Widgets/Image.py index beeb6c5..cb8a633 100644 --- a/Widgets/Image.py +++ b/Widgets/Image.py @@ -83,16 +83,16 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): toolbarBottom.setIconSize(QSize(16, 16)) toolbarBottom.setMovable(False) - #crop = build_action(toolbarTop, 'assets/icons/svg_crop', "Crop", "Crop", False) + #crop = build_action(toolbarTop, './Assets/icons/svg_crop', "Crop", "Crop", False) - flipHorizontal = build_action(toolbarBottom, 'assets/icons/svg_flip_horizontal', "Horizontal Flip", "Horizontal Flip", False) + flipHorizontal = build_action(toolbarBottom, './Assets/icons/svg_flip_horizontal', "Horizontal Flip", "Horizontal Flip", False) flipHorizontal.triggered.connect(self.flipHorizontal) - flipVertical = build_action(toolbarBottom, 'assets/icons/svg_flip_vertical', "Vertical Flip", "Vertical Flip", False) + flipVertical = build_action(toolbarBottom, './Assets/icons/svg_flip_vertical', "Vertical Flip", "Vertical Flip", False) flipVertical.triggered.connect(self.flipVertical) - rotateLeftAction = build_action(toolbarBottom, 'assets/icons/svg_rotate_left', "Rotate 90 degrees Left", "Rotate 90 degrees Left", False) + rotateLeftAction = build_action(toolbarBottom, './Assets/icons/svg_rotate_left', "Rotate 90 degrees Left", "Rotate 90 degrees Left", False) rotateLeftAction.triggered.connect(self.rotate90Left) - rotateRightAction = build_action(toolbarBottom, 'assets/icons/svg_rotate_right', "Rotate 90 degrees Right", "Rotate 90 degrees Right", False) + rotateRightAction = build_action(toolbarBottom, './Assets/icons/svg_rotate_right', "Rotate 90 degrees Right", "Rotate 90 degrees Right", False) rotateRightAction.triggered.connect(self.rotate90Right) @@ -130,4 +130,4 @@ def updatePixmap(self): self.q_pixmap = QPixmap(q_image) # Update the displayed pixmap - self.setPixmap(self.q_pixmap.scaled(self.w, self.h, Qt.KeepAspectRatio, Qt.SmoothTransformation)) \ No newline at end of file + self.setPixmap(self.q_pixmap.scaled(self.w, self.h, Qt.KeepAspectRatio, Qt.SmoothTransformation)) diff --git a/Widgets/Textbox.py b/Widgets/Textbox.py index 2ca2046..1728750 100644 --- a/Widgets/Textbox.py +++ b/Widgets/Textbox.py @@ -99,7 +99,7 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): align_left = build_action( toolbarBottom, - "assets/icons/svg_align_left", + "./Assets/icons/svg_align_left", "Align Left", "Align Left", True, @@ -108,7 +108,7 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): align_center = build_action( toolbarBottom, - "assets/icons/svg_align_center", + "./Assets/icons/svg_align_center", "Align Center", "Align Center", True, @@ -117,7 +117,7 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): align_right = build_action( toolbarBottom, - "assets/icons/svg_align_right", + "./Assets/icons/svg_align_right", "Align Right", "Align Right", True, @@ -125,18 +125,18 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): align_right.triggered.connect(lambda x: self.setAlignment(Qt.AlignRight)) bold = build_action( - toolbarBottom, "assets/icons/svg_font_bold", "Bold", "Bold", True + toolbarBottom, "./Assets/icons/svg_font_bold", "Bold", "Bold", True ) bold.toggled.connect(lambda x: self.setFontWeightCustom(700 if x else 500)) italic = build_action( - toolbarBottom, "assets/icons/svg_font_italic", "Italic", "Italic", True + toolbarBottom, "./Assets/icons/svg_font_italic", "Italic", "Italic", True ) italic.toggled.connect(lambda x: self.setFontItalicCustom(True if x else False)) underline = build_action( toolbarBottom, - "assets/icons/svg_font_underline", + "./Assets/icons/svg_font_underline", "Underline", "Underline", True, @@ -147,7 +147,7 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): fontColor = build_action( toolbarBottom, - "assets/icons/svg_font_color", + "./Assets/icons/svg_font_color", "Font Color", "Font Color", False, @@ -158,7 +158,7 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): bgColor = build_action( toolbarBottom, - "assets/icons/svg_font_bucket", + "./Assets/icons/svg_font_bucket", "Background Color", "Background Color", False, @@ -169,7 +169,7 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): ) textboxColor = build_action( toolbarBottom, - "assets/icons/svg_textboxColor", + "./Assets/icons/svg_textboxColor", "Background Color", "Background Color", False, @@ -179,13 +179,13 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): ) bullets = build_action( - toolbarBottom, "assets/icons/svg_bullets", "Bullets", "Bullets", True + toolbarBottom, "./Assets/icons/svg_bullets", "Bullets", "Bullets", True ) bullets.toggled.connect(lambda: self.bullet_list("bulletReg")) bullets_num = build_action( toolbarBottom, - "assets/icons/svg_bullet_number", + "./Assets/icons/svg_bullet_number", "Bullets Num", "Bullets Num", True, @@ -212,8 +212,8 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): ) menu = QMenu(self) - bulletUpperA = menu.addAction(QIcon("assets/icons/svg_bulletUA"), "") - bulletUpperR = menu.addAction(QIcon("assets/icons/svg_bulletUR"), "") + bulletUpperA = menu.addAction(QIcon("./Assets/icons/svg_bulletUA"), "") + bulletUpperR = menu.addAction(QIcon("./Assets/icons/svg_bulletUR"), "") bulletUpperA.triggered.connect(lambda: self.bullet_list("bulletUpperA")) bulletUpperR.triggered.connect(lambda: self.bullet_list("bulletUpperR")) @@ -221,7 +221,7 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): menu_button = QToolButton(self) menu_button.setPopupMode(QToolButton.InstantPopup) - menu_button.setIcon(QIcon("assets/icons/svg_bullets")) + menu_button.setIcon(QIcon("./Assets/icons/svg_bullets")) menu_button.setMenu(menu) toolbarBottom.addWidget(menu_button) From 26032ff33e0f75a0ad945d114949f7601b62ff34 Mon Sep 17 00:00:00 2001 From: ldeltastreaml <70774713+ldeltastreaml@users.noreply.github.com> Date: Wed, 7 Feb 2024 17:18:40 -0600 Subject: [PATCH 074/127] Rearrenging toolbar Rearranges order of toolbar and changes the name of textboxColor to textHighlightColor --- .../{svg_textboxColor.svg => svg_textHighlightColor.svg} | 0 Modules/BuildUI.py | 8 ++++---- 2 files changed, 4 insertions(+), 4 deletions(-) rename Assets/icons/{svg_textboxColor.svg => svg_textHighlightColor.svg} (100%) diff --git a/Assets/icons/svg_textboxColor.svg b/Assets/icons/svg_textHighlightColor.svg similarity index 100% rename from Assets/icons/svg_textboxColor.svg rename to Assets/icons/svg_textHighlightColor.svg diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index edc622c..0a20357 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -144,8 +144,8 @@ def build_toolbar(editor): #current bug, alternates between activating and not working when using bgColor.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.BackgroundColor, QColorDialog.getColor())) - textboxColor = build_action(toolbar, './Assets/icons/svg_textboxColor', "Text Box Color", "Text Box Color", True) - textboxColor.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.TextboxColor, QColorDialog.getColor())) + textHighlightColor = build_action(toolbar, './Assets/icons/svg_textHighlightColor', "Text Highlight Color", "Text Highlight Color", True) + textHighlightColor.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.textHighlightColor, QColorDialog.getColor())) #defines font color icon appearance and settings fontColor = build_action(toolbar, './Assets/icons/svg_font_color', "Font Color", "Font Color", False) @@ -179,7 +179,7 @@ def build_toolbar(editor): toolbar.addWidget(font_family) toolbar.addWidget(font_size) toolbar.addSeparator() - toolbar.addActions([bgColor, textboxColor, fontColor, bold, italic, underline]) + toolbar.addActions([bold, italic, underline, fontColor, textHighlightColor, bgColor]) toolbar.addSeparator() toolbar.addActions([table, hyperlink, bullet_reg, bullet_num]) @@ -215,4 +215,4 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): action = QAction(QIcon(icon_path), action_name, parent) action.setStatusTip(set_status_tip) action.setCheckable(set_checkable) - return action \ No newline at end of file + return action From 2259faf774ad6924e4b417b5cf4134e61b4677d2 Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Mon, 12 Feb 2024 16:32:43 -0600 Subject: [PATCH 075/127] Allow adjusting image size Image size allowed. Shrink and expanding functionality added draggable container size matches images --- Assets/icons/svg_expand.svg | 33 +++++++-- Assets/icons/svg_shrink.svg | 33 +++++++-- Models/DraggableContainer.py | 8 +- Modules/BuildUI.py | 139 ++++++++++++++++++++++++++--------- Widgets/Image.py | 63 +++++++++++++--- Widgets/Textbox.py | 28 +++++-- 6 files changed, 239 insertions(+), 65 deletions(-) diff --git a/Assets/icons/svg_expand.svg b/Assets/icons/svg_expand.svg index e93075a..7084297 100644 --- a/Assets/icons/svg_expand.svg +++ b/Assets/icons/svg_expand.svg @@ -1,7 +1,28 @@ - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Assets/icons/svg_shrink.svg b/Assets/icons/svg_shrink.svg index 60f9607..ed75d69 100644 --- a/Assets/icons/svg_shrink.svg +++ b/Assets/icons/svg_shrink.svg @@ -1,7 +1,28 @@ - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Models/DraggableContainer.py b/Models/DraggableContainer.py index b35bb5e..e4f5e33 100644 --- a/Models/DraggableContainer.py +++ b/Models/DraggableContainer.py @@ -256,6 +256,7 @@ def mouseMoveEvent(self, e: QMouseEvent): # debt: To make images resize better, ImageWidget should probaly implement this and setCursorShape # So that it can make the cursor move with the corners of pixmap and not corners of this container if (self.mode != Mode.MOVE) and e.buttons() and Qt.LeftButton: + child_widget = self.childWidget if self.mode == Mode.RESIZETL: # Left - Top newwidth = e.globalX() - self.position.x() - self.geometry().x() newheight = e.globalY() - self.position.y() - self.geometry().y() @@ -287,7 +288,12 @@ def mouseMoveEvent(self, e: QMouseEvent): elif self.mode == Mode.RESIZER: # Right self.resize(e.x(), self.height()) elif self.mode == Mode.RESIZEBR:# Right - Bottom - self.resize(e.x(), e.y()) + #if child is a image, resize differently + if isinstance(child_widget, QLabel): + #change this to where resizing corners works like onenote + self.resize(e.x(), e.y()) + else: + self.resize(e.x(), e.y()) self.parentWidget().repaint() self.newGeometry.emit(self.geometry()) diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index 76b1ef6..674d0f3 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -17,21 +17,21 @@ FONT_SIZES = [7, 8, 9, 10, 11, 12, 13, 14, 18, 24, 36, 48, 64, 72, 96, 144, 288] #builds the application's UI -def build_ui(editor): +def build_ui(self): print("Building UI...") - #editor.EditorFrameView = EditorFrameView(editor) - #editor.statusBar = editor.statusBar() - build_window(editor) - build_menubar(editor) - build_toolbar(editor) - #build_test_toolbar(editor) + #self.selfFrameView = selfFrameView(self) + #self.statusBar = self.statusBar() + build_window(self) + build_menubar(self) + build_toolbar(self) + #build_test_toolbar(self) # Application's main layout (grid) gridLayout = QGridLayout() gridContainerWidget = QWidget() - editor.setCentralWidget(gridContainerWidget) + self.setCentralWidget(gridContainerWidget) gridContainerWidget.setLayout(gridLayout) gridLayout.setSpacing(3) @@ -61,63 +61,90 @@ def build_ui(editor): # Add appropriate widgets (ideally just view controllers) to their layouts - leftSideLayout.addWidget(editor.notebookTitleView, 0) - leftSideLayout.addWidget(editor.pageView, 1) # Page view has max stretch factor - rightSideLayout.addWidget(editor.sectionView, 0) - rightSideLayout.addWidget(editor.frameView, 1) # Frame view has max stretch factor + leftSideLayout.addWidget(self.notebookTitleView, 0) + leftSideLayout.addWidget(self.pageView, 1) # Page view has max stretch factor + rightSideLayout.addWidget(self.sectionView, 0) + rightSideLayout.addWidget(self.frameView, 1) # Frame view has max stretch factor # Add L+R container's widgets to the main grid gridLayout.addWidget(leftSideContainerWidget, 0, 0) gridLayout.addWidget(rightSideContainerWidget, 0, 1) addSectionButton = QPushButton("Add Section") - #add functionality e.g. addSectionButton.clcicked.connect(editor.add_section_function) + #add functionality e.g. addSectionButton.clcicked.connect(self.add_section_function) leftSideLayout.addWidget(addSectionButton) + + -def build_window(editor): - editor.setWindowTitle("OpenNote") - editor.setWindowIcon(QIcon('./Assets/OpenNoteLogo.png')) - editor.setAcceptDrops(True) +def build_window(self): + self.setWindowTitle("OpenNote") + self.setWindowIcon(QIcon('./Assets/OpenNoteLogo.png')) + self.setAcceptDrops(True) with open('./Styles/styles.qss',"r") as fh: - editor.setStyleSheet(fh.read()) + self.setStyleSheet(fh.read()) -def build_menubar(editor): - file = editor.menuBar().addMenu('&File') - plugins = editor.menuBar().addMenu('&Plugins') +def build_menubar(self): + file = self.menuBar().addMenu('&File') + plugins = self.menuBar().addMenu('&Plugins') - new_file = build_action(editor, './Assets/icons/svg_file_open', 'New Notebook', 'New Notebook', False) + new_file = build_action(self, './Assets/icons/svg_file_open', 'New Notebook', 'New Notebook', False) new_file.setShortcut(QKeySequence.StandardKey.New) - new_file.triggered.connect(lambda: new(editor)) + new_file.triggered.connect(lambda: new(self)) - open_file = build_action(editor, './Assets/icons/svg_file_open', 'Open Notebook', 'Open Notebook', False) + open_file = build_action(self, './Assets/icons/svg_file_open', 'Open Notebook', 'Open Notebook', False) open_file.setShortcut(QKeySequence.StandardKey.Open) - open_file.triggered.connect(lambda: load(editor)) + open_file.triggered.connect(lambda: load(self)) - save_file = build_action(editor, './Assets/icons/svg_file_save', 'Save Notebook', 'Save Notebook', False) + save_file = build_action(self, './Assets/icons/svg_file_save', 'Save Notebook', 'Save Notebook', False) save_file.setShortcut(QKeySequence.StandardKey.Save) - save_file.triggered.connect(lambda: save(editor)) + save_file.triggered.connect(lambda: save(self)) - save_fileAs = build_action(editor, './Assets/icons/svg_file_save', 'Save Notebook As...', 'Save Notebook As', False) + save_fileAs = build_action(self, './Assets/icons/svg_file_save', 'Save Notebook As...', 'Save Notebook As', False) save_fileAs.setShortcut(QKeySequence.fromString('Ctrl+Shift+S')) - save_fileAs.triggered.connect(lambda: saveAs(editor)) + save_fileAs.triggered.connect(lambda: saveAs(self)) - add_widget = build_action(editor, './Assets/icons/svg_question', 'Add Custom Widget', 'Add Custom Widget', False) + add_widget = build_action(self, './Assets/icons/svg_question', 'Add Custom Widget', 'Add Custom Widget', False) file.addActions([new_file, open_file, save_file, save_fileAs]) plugins.addActions([add_widget]) -def build_toolbar(editor): +def build_toolbar(self): toolbar = QToolBar() toolbar.setIconSize(QSize(16, 16)) toolbar.setMovable(False) - editor.addToolBar(Qt.ToolBarArea.TopToolBarArea, toolbar) + self.addToolBar(Qt.ToolBarArea.TopToolBarArea, toolbar) + + ''' + tabs = QTabWidget() + tabs.addTab(self.homeTabUI(), "Home") + layout.addWidget(tabs) + ''' + #create tab bar + tab_bar = QTabBar(self) + toolbar.addWidget(tab_bar) + + #create tabs + home_tab = tab_bar.addTab("Home") + insert_tab = tab_bar.addTab("Insert") + draw_tab = tab_bar.addTab("Draw") + view_tab = tab_bar.addTab("View") + + '''centralWidget = QWidget(self) + self.setCentralWidget(centralWidget) + layout = QVBoxLayout(centralWidget) + layout.addWidget(tab_bar) + + home_toolbar = QToolBar("Home Toolbar", self) + home_toolbar.addAction("Action 1") + + layout.addWidget(home_toolbar) ''' #separates toolbar with a line break spacer = QWidget() spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) toolbar_undo = build_action(toolbar, './Assets/icons/svg_undo', "undo", "undo", False) - toolbar_undo.triggered.connect(editor.frameView.triggerUndo) + toolbar_undo.triggered.connect(self.frameView.triggerUndo) redo = build_action(toolbar, './Assets/icons/svg_redo', "redo", "redo", False) @@ -161,10 +188,10 @@ def build_toolbar(editor): underline.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontUnderline, None)) table = build_action(toolbar, './Assets/icons/svg_table', "Create Table", "Create Table", False) - table.triggered.connect(editor.frameView.toolbar_table) + table.triggered.connect(self.frameView.toolbar_table) hyperlink = build_action(toolbar, './Assets/icons/svg_hyperlink', "Hyperlink", "Hyperlink", False) - hyperlink.triggered.connect(editor.frameView.toolbar_hyperlink) + hyperlink.triggered.connect(self.frameView.toolbar_hyperlink) bullets = build_action(toolbar, './Assets/icons/svg_bullets', "Bullets", "Bullets", False) @@ -195,8 +222,50 @@ def build_toolbar(editor): toolbar.addSeparator() toolbar.addActions([table, hyperlink, bullet_reg, bullet_num]) + #-------- BG Color ----------- + bgColor = build_action(toolbar, './Assets/icons/svg_bullets', "Bullets", "Bullets", False) + + bgColor_menu = QMenu(self) + + bgColor = QToolButton(self) + bgColor.setIcon(QIcon('./Assets/icons/svg_font_bucket')) + bgColor.setPopupMode(QToolButton.InstantPopup) + bgColor.setMenu(bgColor_menu) + presetColors = ['blue', '#ffcc00', '#66ff66', '#3399ff'] + for color in presetColors: + presetAction = QAction(color, self) + bgColor_menu.addAction(presetAction) + toolbar.addWidget(bgColor) + + #----------------------------- + bullets_menu = QMenu(self) + + bulletUpperA = build_action(bullets_menu, './Assets/icons/svg_bulletUA', "", "", False) + bulletUpperA.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.BulletUA, None)) + + bulletUpperR = build_action(bullets_menu, './Assets/icons/svg_bulletUR', "", "", False) + bulletUpperR.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.BulletUR, None)) + + bullets_menu.addAction(bulletUpperA) + bullets_menu.addAction(bulletUpperR) + + bullets = QToolButton(self) + bullets.setIcon(QIcon('./Assets/icons/svg_bullets')) + bullets.setPopupMode(QToolButton.InstantPopup) + bullets.setMenu(bullets_menu) + + toolbar.addWidget(bullets) + #toolbar.setStyleSheet("QToolBar { background-color: #FFFFFF; }") +def homeTabUI(self): + homeTab = QWidget() + layout = QVBoxLayout() + layout.addWidget(QCheckBox("General Option 1")) + layout.addWidget(QCheckBox("General Option 2")) + homeTab.setLayout(layout) + return homeTab + def openGetColorDialog(purpose): color = QColorDialog.getColor() if color.isValid(): diff --git a/Widgets/Image.py b/Widgets/Image.py index 1265843..80e540c 100644 --- a/Widgets/Image.py +++ b/Widgets/Image.py @@ -19,7 +19,7 @@ def __init__(self, x, y, w, h, image_matrix): bytes_per_line = 3 * matrix_width q_image = QImage(image_matrix.data, matrix_width, matrix_height, bytes_per_line, QImage.Format_BGR888) self.q_pixmap = QPixmap(q_image) - self.setPixmap(self.q_pixmap.scaled(w, h, Qt.KeepAspectRatio, Qt.SmoothTransformation)) # Scale to widget geometry + self.setPixmap(self.q_pixmap.scaled(w, h, Qt.IgnoreAspectRatio, Qt.SmoothTransformation)) # Scale to widget geometry self.setGeometry(x, y, w, h) # this should get fixed self.persistantGeometry = self.geometry() @@ -29,7 +29,7 @@ def newGeometryEvent(self, newGeometry): new_w = newGeometry.width() new_h = newGeometry.height() if (self.w != new_w) or (self.h != new_h): # Not exactly sure how object's width and height attribute gets updated but this works - self.setPixmap(self.q_pixmap.scaled(new_w, new_h, Qt.KeepAspectRatio, Qt.SmoothTransformation)) + self.setPixmap(self.q_pixmap.scaled(new_w, new_h, Qt.IgnoreAspectRatio, Qt.SmoothTransformation)) pixmap_rect = self.pixmap().rect() w = pixmap_rect.width() @@ -85,19 +85,19 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): #crop = build_action(toolbarTop, 'assets/icons/svg_crop', "Crop", "Crop", False) - flipHorizontal = build_action(toolbarBottom, 'assets/icons/svg_flip_horizontal', "Horizontal Flip", "Horizontal Flip", False) + flipHorizontal = build_action(toolbarBottom, 'Assets/icons/svg_flip_horizontal', "Horizontal Flip", "Horizontal Flip", False) flipHorizontal.triggered.connect(self.flipHorizontal) - flipVertical = build_action(toolbarBottom, 'assets/icons/svg_flip_vertical', "Vertical Flip", "Vertical Flip", False) + flipVertical = build_action(toolbarBottom, 'Assets/icons/svg_flip_vertical', "Vertical Flip", "Vertical Flip", False) flipVertical.triggered.connect(self.flipVertical) - rotateLeftAction = build_action(toolbarBottom, 'assets/icons/svg_rotate_left', "Rotate 90 degrees Left", "Rotate 90 degrees Left", False) + rotateLeftAction = build_action(toolbarBottom, 'Assets/icons/svg_rotate_left', "Rotate 90 degrees Left", "Rotate 90 degrees Left", False) rotateLeftAction.triggered.connect(self.rotate90Left) - rotateRightAction = build_action(toolbarBottom, 'assets/icons/svg_rotate_right', "Rotate 90 degrees Right", "Rotate 90 degrees Right", False) + rotateRightAction = build_action(toolbarBottom, 'Assets/icons/svg_rotate_right', "Rotate 90 degrees Right", "Rotate 90 degrees Right", False) rotateRightAction.triggered.connect(self.rotate90Right) - shrinkImageAction = build_action(toolbarBottom, 'assets/icons/svg_shrink', "Rotate 90 degrees Right", "Rotate 90 degrees Right", False) + shrinkImageAction = build_action(toolbarBottom, 'Assets/icons/svg_shrink', "Rotate 90 degrees Right", "Rotate 90 degrees Right", False) shrinkImageAction.triggered.connect(self.shrinkImage) - expandImageAction = build_action(toolbarBottom, 'assets/icons/svg_expand', "Rotate 90 degrees Right", "Rotate 90 degrees Right", False) + expandImageAction = build_action(toolbarBottom, 'Assets/icons/svg_expand', "Rotate 90 degrees Right", "Rotate 90 degrees Right", False) expandImageAction.triggered.connect(self.expandImage) @@ -110,23 +110,52 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): def flipVertical(self): # Flip the image matrix vertically using OpenCV + parent_widget = self.parentWidget() + if parent_widget: + newX, newY = parent_widget.x(), parent_widget.y() + new_width, new_height = parent_widget.height(), parent_widget.width() + parent_widget.setGeometry(newX, newY, new_width, new_height) + self.image_matrix = cv2.flip(self.image_matrix, 0) self.updatePixmap() + def flipHorizontal(self): # Flip the image matrix horizontally using OpenCV + + parent_widget = self.parentWidget() + if parent_widget: + newX, newY = parent_widget.x(), parent_widget.y() + new_width, new_height = parent_widget.height(), parent_widget.width() + parent_widget.setGeometry(newX, newY, new_width, new_height) + self.image_matrix = cv2.flip(self.image_matrix, 1) self.updatePixmap() + def rotate90Left(self): # Rotate the image matrix 90 degrees to the left using OpenCV self.w, self.h = self.h, self.w - + + parent_widget = self.parentWidget() + if parent_widget: + newX, newY = parent_widget.x(), parent_widget.y() + new_width, new_height = parent_widget.height(), parent_widget.width() + parent_widget.setGeometry(newX, newY, new_width, new_height) self.image_matrix = cv2.rotate(self.image_matrix, cv2.ROTATE_90_COUNTERCLOCKWISE) + self.updatePixmap() def rotate90Right(self): # Rotate the image matrix 90 degrees to the right using OpenCV self.w, self.h = self.h, self.w + + # Access parent and update geometry + parent_widget = self.parentWidget() + if parent_widget: + newX, newY = parent_widget.x(), parent_widget.y() + new_width, new_height = parent_widget.height(), parent_widget.width() + parent_widget.setGeometry(newX, newY, new_width, new_height) + self.image_matrix = cv2.rotate(self.image_matrix, cv2.ROTATE_90_CLOCKWISE) self.updatePixmap() @@ -134,18 +163,28 @@ def shrinkImage(self): # Decrease image size by 10% self.w = int(self.w * 0.9) self.h = int(self.h * 0.9) + parent_widget = self.parentWidget() + if parent_widget: + newX, newY = parent_widget.x(), parent_widget.y() + new_width, new_height = self.w, self.h + parent_widget.setGeometry(newX, newY, new_width, new_height) self.updateImageSize() def expandImage(self): # Increase image size by 10% self.w = int(self.w * 1.1) self.h = int(self.h * 1.1) + parent_widget = self.parentWidget() + if parent_widget: + newX, newY = parent_widget.x(), parent_widget.y() + new_width, new_height = self.w, self.h + parent_widget.setGeometry(newX, newY, new_width, new_height) self.updateImageSize() def updateImageSize(self): # Update the displayed pixmap with the new size self.setPixmap(self.q_pixmap.scaled(self.w, self.h, Qt.KeepAspectRatio, Qt.SmoothTransformation)) - self.sizeChanged.emit(QSize(self.w, self.h)) + def updatePixmap(self): # Update the QImage and QPixmap @@ -155,4 +194,6 @@ def updatePixmap(self): self.q_pixmap = QPixmap(q_image) # Update the displayed pixmap - self.setPixmap(self.q_pixmap.scaled(self.w, self.h, Qt.KeepAspectRatio, Qt.SmoothTransformation)) \ No newline at end of file + self.setPixmap(self.q_pixmap.scaled(self.w, self.h, Qt.KeepAspectRatio, Qt.SmoothTransformation)) + + \ No newline at end of file diff --git a/Widgets/Textbox.py b/Widgets/Textbox.py index c97f2c0..63d18d0 100644 --- a/Widgets/Textbox.py +++ b/Widgets/Textbox.py @@ -208,13 +208,29 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): ] ) + menu = QMenu(self) + #menu.setStyleSheet("color:white") + bulletUpperA = menu.addAction(QIcon("assets/icons/svg_bulletUA"), "") + bulletUpperR = menu.addAction(QIcon("assets/icons/svg_bulletUR"), "") + + bulletUpperA.triggered.connect(lambda: self.bullet_list("bulletUpperA")) + bulletUpperR.triggered.connect(lambda: self.bullet_list("bulletUpperR")) + + + menu_button = QToolButton(self) + menu_button.setPopupMode(QToolButton.InstantPopup) + menu_button.setIcon(QIcon("assets/icons/svg_bullets")) + menu_button.setMenu(menu) + + toolbarBottom.addWidget(menu_button) + qwaTop = QWidgetAction(self) qwaTop.setDefaultWidget(toolbarTop) qwaBottom = QWidgetAction(self) qwaBottom.setDefaultWidget(toolbarBottom) return [qwaTop, qwaBottom] - + def setFontItalicCustom(self, italic: bool): if not self.applyToAllIfNoSelection(lambda: self.setFontItalic(italic)): print("setFontItalicCustom Called") @@ -244,7 +260,7 @@ def setTextColorCustom(self, color): def setBackgroundColor(self, color: QColor): rgb = color.getRgb() self.setStyleSheet(f"background-color: rgb({rgb[0]}, {rgb[1]}, {rgb[2]});") - + # If no text is selected, apply to all, else apply to selection def applyToAllIfNoSelection(self, func): if len(self.textCursor().selectedText()) != 0: @@ -454,10 +470,10 @@ def changeFontColorEvent(self, new_font_color): # Changes color of whole background def changeBackgroundColorEvent(self, color: QColor): - # if self.hasFocus(): - rgb = color.getRgb() - self.setStyleSheet(f"background-color: rgb({rgb[0]}, {rgb[1]}, {rgb[2]});") - self.deselectText() + if self.hasFocus: + rgb = color.getRgb() + self.setStyleSheet(f"background-color: rgb({rgb[0]}, {rgb[1]}, {rgb[2]});") + self.deselectText() # Changes textbox background color def changeTextboxColorEvent(self, new_bg_color): From 94ed785e455f897c0d4461c5fb9e0403aeacda56 Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Mon, 12 Feb 2024 19:07:15 -0600 Subject: [PATCH 076/127] Textboxes no longer change color to black color is checked when qcolordialog is canceled and doesn't change the color if invalid --- Widgets/Textbox.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Widgets/Textbox.py b/Widgets/Textbox.py index 1728750..c270d45 100644 --- a/Widgets/Textbox.py +++ b/Widgets/Textbox.py @@ -521,9 +521,13 @@ def changeFontColorEvent(self, new_font_color): # Changes color of whole background def changeBackgroundColorEvent(self, color: QColor): - # if self.hasFocus(): - rgb = color.getRgb() - self.setStyleSheet(f"background-color: rgb({rgb[0]}, {rgb[1]}, {rgb[2]});") + print("CHANGE BACKGROUND COLOR EVENT") + if color.isValid(): + rgb = color.getRgb() + self.setStyleSheet(f"background-color: rgb({rgb[0]}, {rgb[1]}, {rgb[2]});") + else: + print("INVALID COLOR") + #self.setStyleSheet("background-color: transparent;") self.deselectText() # Changes textbox background color From 88f727f92289b5c66424c1ce2166e801cf9af738 Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Mon, 12 Feb 2024 23:28:49 -0600 Subject: [PATCH 077/127] Fixed texthighlightcolor and foreground color When color dialog is cancelled, will now check if the color is valid before applying the color. Fixed variable names to make texthighlightcolor work again --- Models/DraggableContainer.py | 4 ++-- Modules/BuildUI.py | 2 +- Modules/EditorSignals.py | 2 +- Widgets/Textbox.py | 21 ++++++++++++--------- 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/Models/DraggableContainer.py b/Models/DraggableContainer.py index fc0c617..a724dd6 100644 --- a/Models/DraggableContainer.py +++ b/Models/DraggableContainer.py @@ -329,9 +329,9 @@ def widgetAttributeChanged(self, changedWidgetAttribute, value): print("Change Font Color Event Called") child_widget.changeFontColorEvent(value) - elif hasattr(child_widget, "changeTextboxColorEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.TextboxColor): + elif hasattr(child_widget, "changeTextHighlightColorEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.TextHighlightColor): print("Change Textbox Color Event Called") - child_widget.changeTextboxColorEvent(value) + child_widget.changeTextHighlightColorEvent(value) elif hasattr(child_widget, "deselectText") and (changedWidgetAttribute == ChangedWidgetAttribute.LoseFocus): print("Clear Selection Slot Called") diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index 0a20357..2281a3b 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -145,7 +145,7 @@ def build_toolbar(editor): bgColor.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.BackgroundColor, QColorDialog.getColor())) textHighlightColor = build_action(toolbar, './Assets/icons/svg_textHighlightColor', "Text Highlight Color", "Text Highlight Color", True) - textHighlightColor.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.textHighlightColor, QColorDialog.getColor())) + textHighlightColor.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.TextHighlightColor, QColorDialog.getColor())) #defines font color icon appearance and settings fontColor = build_action(toolbar, './Assets/icons/svg_font_color', "Font Color", "Font Color", False) diff --git a/Modules/EditorSignals.py b/Modules/EditorSignals.py index 72af273..a6933ed 100644 --- a/Modules/EditorSignals.py +++ b/Modules/EditorSignals.py @@ -12,7 +12,7 @@ class ChangedWidgetAttribute(Enum): FontBold = 4 FontItalic = 5 FontUnderline = 6 - TextboxColor = 7 + TextHighlightColor = 7 Bullet = 8 Bullet_Num = 9 LoseFocus = 10 diff --git a/Widgets/Textbox.py b/Widgets/Textbox.py index c270d45..c838cb1 100644 --- a/Widgets/Textbox.py +++ b/Widgets/Textbox.py @@ -167,15 +167,15 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): bgColor.triggered.connect( lambda: self.changeBackgroundColorEvent(QColorDialog.getColor()) ) - textboxColor = build_action( + textHighlightColor = build_action( toolbarBottom, - "./Assets/icons/svg_textboxColor", + "./Assets/icons/svg_textHighlightColor", "Background Color", "Background Color", False, ) - textboxColor.triggered.connect( - lambda: self.changeTextboxColorEvent(QColorDialog.getColor()) + textHighlightColor.triggered.connect( + lambda: self.changeTextHighlightColorEvent(QColorDialog.getColor()) ) bullets = build_action( @@ -204,7 +204,8 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): bold, italic, underline, - fontColor, + fontColor, + textHighlightColor, bgColor, bullets, bullets_num, @@ -511,7 +512,8 @@ def changeFontColorEvent(self, new_font_color): current_format = cursor.charFormat() color = QColor(new_font_color) - current_format.setForeground(color) + if color.isValid(): + current_format.setForeground(color) cursor.setCharFormat(current_format) @@ -531,12 +533,13 @@ def changeBackgroundColorEvent(self, color: QColor): self.deselectText() # Changes textbox background color - def changeTextboxColorEvent(self, new_bg_color): + def changeTextHighlightColorEvent(self, new_highlight_color): cursor = self.textCursor() current_format = cursor.charFormat() - color = QColor(new_bg_color) - current_format.setBackground(color) + color = QColor(new_highlight_color) + if color.isValid(): + current_format.setBackground(color) cursor.setCharFormat(current_format) # self.deselectText() From 3e1a716b0581e6e963a1e70b1018193a09f8e18f Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Tue, 13 Feb 2024 21:04:41 -0600 Subject: [PATCH 078/127] Got rid of temporary tabs --- Modules/BuildUI.py | 24 ------ Widgets/Textbox.py | 183 ++++++++++++++++++++++++++++++--------------- 2 files changed, 121 insertions(+), 86 deletions(-) diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index 674d0f3..959077a 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -114,30 +114,6 @@ def build_toolbar(self): toolbar.setMovable(False) self.addToolBar(Qt.ToolBarArea.TopToolBarArea, toolbar) - ''' - tabs = QTabWidget() - tabs.addTab(self.homeTabUI(), "Home") - layout.addWidget(tabs) - ''' - #create tab bar - tab_bar = QTabBar(self) - toolbar.addWidget(tab_bar) - - #create tabs - home_tab = tab_bar.addTab("Home") - insert_tab = tab_bar.addTab("Insert") - draw_tab = tab_bar.addTab("Draw") - view_tab = tab_bar.addTab("View") - - '''centralWidget = QWidget(self) - self.setCentralWidget(centralWidget) - layout = QVBoxLayout(centralWidget) - layout.addWidget(tab_bar) - - home_toolbar = QToolBar("Home Toolbar", self) - home_toolbar.addAction("Action 1") - - layout.addWidget(home_toolbar) ''' #separates toolbar with a line break spacer = QWidget() diff --git a/Widgets/Textbox.py b/Widgets/Textbox.py index 63d18d0..a32bf03 100644 --- a/Widgets/Textbox.py +++ b/Widgets/Textbox.py @@ -6,7 +6,7 @@ FONT_SIZES = [7, 8, 9, 10, 11, 12, 13, 14, 18, 24, 36, 48, 64, 72, 96, 144, 288] -class TextboxWidget(QTextEdit): +class TextboxWidget(QTextBrowser): def __init__(self, x, y, w=15, h=30, t=""): super().__init__() @@ -19,6 +19,8 @@ def __init__(self, x, y, w=15, h=30, t=""): self.setStyleSheet("background-color: rgba(0, 0, 0, 0);") self.setTextColor("black") + self.setTextInteractionFlags(Qt.TextEditorInteraction | Qt.TextBrowserInteraction) + self.installEventFilter(self) def eventFilter(self, obj, event): @@ -97,7 +99,7 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): align_left = build_action( toolbarBottom, - "assets/icons/svg_align_left", + "./Assets/icons/svg_align_left", "Align Left", "Align Left", True, @@ -106,7 +108,7 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): align_center = build_action( toolbarBottom, - "assets/icons/svg_align_center", + "./Assets/icons/svg_align_center", "Align Center", "Align Center", True, @@ -115,7 +117,7 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): align_right = build_action( toolbarBottom, - "assets/icons/svg_align_right", + "./Assets/icons/svg_align_right", "Align Right", "Align Right", True, @@ -123,18 +125,18 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): align_right.triggered.connect(lambda x: self.setAlignment(Qt.AlignRight)) bold = build_action( - toolbarBottom, "assets/icons/svg_font_bold", "Bold", "Bold", True + toolbarBottom, "./Assets/icons/svg_font_bold", "Bold", "Bold", True ) bold.toggled.connect(lambda x: self.setFontWeightCustom(700 if x else 500)) italic = build_action( - toolbarBottom, "assets/icons/svg_font_italic", "Italic", "Italic", True + toolbarBottom, "./Assets/icons/svg_font_italic", "Italic", "Italic", True ) italic.toggled.connect(lambda x: self.setFontItalicCustom(True if x else False)) underline = build_action( toolbarBottom, - "assets/icons/svg_font_underline", + "./Assets/icons/svg_font_underline", "Underline", "Underline", True, @@ -145,7 +147,7 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): fontColor = build_action( toolbarBottom, - "assets/icons/svg_font_color", + "./Assets/icons/svg_font_color", "Font Color", "Font Color", False, @@ -156,7 +158,7 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): bgColor = build_action( toolbarBottom, - "assets/icons/svg_font_bucket", + "./Assets/icons/svg_font_bucket", "Background Color", "Background Color", False, @@ -165,31 +167,32 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): bgColor.triggered.connect( lambda: self.changeBackgroundColorEvent(QColorDialog.getColor()) ) - textboxColor = build_action( + textHighlightColor = build_action( toolbarBottom, - "assets/icons/svg_textboxColor", + "./Assets/icons/svg_textHighlightColor", "Background Color", "Background Color", False, ) - textboxColor.triggered.connect( - lambda: self.changeTextboxColorEvent(QColorDialog.getColor()) + textHighlightColor.triggered.connect( + lambda: self.changeTextHighlightColorEvent(QColorDialog.getColor()) ) bullets = build_action( - toolbarBottom, "assets/icons/svg_bullets", "Bullets", "Bullets", True + toolbarBottom, "./Assets/icons/svg_bullets", "Bullets", "Bullets", True ) bullets.toggled.connect(lambda: self.bullet_list("bulletReg")) bullets_num = build_action( toolbarBottom, - "assets/icons/svg_bullet_number", + "./Assets/icons/svg_bullet_number", "Bullets Num", "Bullets Num", True, ) bullets_num.toggled.connect(lambda: self.bullet_list("bulletNum")) + toolbarTop.addWidget(font) toolbarTop.addWidget(size) @@ -201,7 +204,8 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): bold, italic, underline, - fontColor, + fontColor, + textHighlightColor, bgColor, bullets, bullets_num, @@ -209,9 +213,8 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): ) menu = QMenu(self) - #menu.setStyleSheet("color:white") - bulletUpperA = menu.addAction(QIcon("assets/icons/svg_bulletUA"), "") - bulletUpperR = menu.addAction(QIcon("assets/icons/svg_bulletUR"), "") + bulletUpperA = menu.addAction(QIcon("./Assets/icons/svg_bulletUA"), "") + bulletUpperR = menu.addAction(QIcon("./Assets/icons/svg_bulletUR"), "") bulletUpperA.triggered.connect(lambda: self.bullet_list("bulletUpperA")) bulletUpperR.triggered.connect(lambda: self.bullet_list("bulletUpperR")) @@ -219,8 +222,9 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): menu_button = QToolButton(self) menu_button.setPopupMode(QToolButton.InstantPopup) - menu_button.setIcon(QIcon("assets/icons/svg_bullets")) - menu_button.setMenu(menu) + menu_button.setIcon(QIcon("./Assets/icons/svg_bullets")) + menu_button.setMenu(menu) + toolbarBottom.addWidget(menu_button) @@ -230,7 +234,7 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): qwaBottom.setDefaultWidget(toolbarBottom) return [qwaTop, qwaBottom] - + def setFontItalicCustom(self, italic: bool): if not self.applyToAllIfNoSelection(lambda: self.setFontItalic(italic)): print("setFontItalicCustom Called") @@ -260,7 +264,7 @@ def setTextColorCustom(self, color): def setBackgroundColor(self, color: QColor): rgb = color.getRgb() self.setStyleSheet(f"background-color: rgb({rgb[0]}, {rgb[1]}, {rgb[2]});") - + # If no text is selected, apply to all, else apply to selection def applyToAllIfNoSelection(self, func): if len(self.textCursor().selectedText()) != 0: @@ -379,6 +383,14 @@ def bullet_list(self, bulletType): style = QTextListFormat.ListDecimal if bulletType == "bulletReg": style = QTextListFormat.ListDisc + if bulletType == "bulletLowerA": + style = QTextListFormat.ListLowerAlpha + if bulletType == "bulletLowerR": + style = QTextListFormat.ListLowerRoman + if bulletType == "bulletUpperA": + style = QTextListFormat.ListUpperAlpha + if bulletType == "bulletUpperR": + style = QTextListFormat.ListUpperRoman listFormat.setStyle(style) cursor.createList(listFormat) @@ -396,44 +408,85 @@ def handleTabKey(self): if cursor.atBlockStart() and block.text().strip() == "": current_indent = block_format.indent() - if current_indent == 0: - block_format.setIndent(1) - cursor.setBlockFormat(block_format) - cursor.beginEditBlock() - list_format = QTextListFormat() - currentStyle = textList.format().style() - - if currentStyle == QTextListFormat.ListDisc: - list_format.setStyle(QTextListFormat.ListCircle) - if currentStyle == QTextListFormat.ListDecimal: - list_format.setStyle(QTextListFormat.ListLowerAlpha) - - cursor.createList(list_format) - cursor.endEditBlock() - - if current_indent == 1: - block_format.setIndent(2) - cursor.setBlockFormat(block_format) - cursor.beginEditBlock() - list_format = QTextListFormat() - currentStyle = textList.format().style() - - if currentStyle == QTextListFormat.ListCircle: - list_format.setStyle(QTextListFormat.ListSquare) - if currentStyle == QTextListFormat.ListLowerAlpha: - list_format.setStyle(QTextListFormat.ListLowerRoman) - - cursor.createList(list_format) - cursor.endEditBlock() - - cursor.insertText("") - cursor.movePosition(QTextCursor.StartOfBlock) + if current_indent < 11: + + if current_indent % 3 == 0: + block_format.setIndent(current_indent + 1) + cursor.setBlockFormat(block_format) + cursor.beginEditBlock() + list_format = QTextListFormat() + currentStyle = textList.format().style() + + if currentStyle == QTextListFormat.ListDisc: + list_format.setStyle(QTextListFormat.ListCircle) + if currentStyle == QTextListFormat.ListDecimal: + list_format.setStyle(QTextListFormat.ListLowerAlpha) + if currentStyle == QTextListFormat.ListLowerAlpha: + list_format.setStyle(QTextListFormat.ListLowerRoman) + if currentStyle == QTextListFormat.ListLowerRoman: + list_format.setStyle(QTextListFormat.ListDecimal) + if currentStyle == QTextListFormat.ListUpperAlpha: + list_format.setStyle(QTextListFormat.ListLowerAlpha) + if currentStyle == QTextListFormat.ListUpperRoman: + list_format.setStyle(QTextListFormat.ListLowerAlpha) + + cursor.createList(list_format) + cursor.endEditBlock() + + if current_indent % 3 == 1: + block_format.setIndent(current_indent + 1) + cursor.setBlockFormat(block_format) + cursor.beginEditBlock() + list_format = QTextListFormat() + currentStyle = textList.format().style() + + if currentStyle == QTextListFormat.ListCircle: + list_format.setStyle(QTextListFormat.ListSquare) + if currentStyle == QTextListFormat.ListLowerAlpha: + list_format.setStyle(QTextListFormat.ListLowerRoman) + if currentStyle == QTextListFormat.ListLowerRoman: + list_format.setStyle(QTextListFormat.ListDecimal) + if currentStyle == QTextListFormat.ListDecimal: + list_format.setStyle(QTextListFormat.ListLowerAlpha) + + cursor.createList(list_format) + cursor.endEditBlock() + + if current_indent % 3 == 2: + block_format.setIndent(current_indent + 1) + cursor.setBlockFormat(block_format) + cursor.beginEditBlock() + list_format = QTextListFormat() + currentStyle = textList.format().style() + + if currentStyle == QTextListFormat.ListSquare: + list_format.setStyle(QTextListFormat.ListDisc) + if currentStyle == QTextListFormat.ListLowerRoman: + list_format.setStyle(QTextListFormat.ListDecimal) + if currentStyle == QTextListFormat.ListDecimal: + list_format.setStyle(QTextListFormat.ListLowerAlpha) + if currentStyle == QTextListFormat.ListLowerAlpha: + list_format.setStyle(QTextListFormat.ListLowerRoman) + + cursor.createList(list_format) + cursor.endEditBlock() + + cursor.insertText("") + cursor.movePosition(QTextCursor.StartOfBlock) self.setTextCursor(cursor) else: - # maybe add manual tab or diff functionality? + cursor.insertText(" ") + self.setTextCursor(cursor) pass + def insertTextLink(self, link_address, display_text): + self.setOpenExternalLinks(True) + link_html = f'{display_text}' + cursor = self.textCursor() + cursor.insertHtml(link_html) + QDesktopServices.openUrl(link_html) + def changeFontSizeEvent(self, value): # todo: when textbox is in focus, font size on toolbar should match the font size of the text @@ -460,7 +513,8 @@ def changeFontColorEvent(self, new_font_color): current_format = cursor.charFormat() color = QColor(new_font_color) - current_format.setForeground(color) + if color.isValid(): + current_format.setForeground(color) cursor.setCharFormat(current_format) @@ -470,18 +524,23 @@ def changeFontColorEvent(self, new_font_color): # Changes color of whole background def changeBackgroundColorEvent(self, color: QColor): - if self.hasFocus: + print("CHANGE BACKGROUND COLOR EVENT") + if color.isValid(): rgb = color.getRgb() self.setStyleSheet(f"background-color: rgb({rgb[0]}, {rgb[1]}, {rgb[2]});") - self.deselectText() + else: + print("INVALID COLOR") + #self.setStyleSheet("background-color: transparent;") + self.deselectText() # Changes textbox background color - def changeTextboxColorEvent(self, new_bg_color): + def changeTextHighlightColorEvent(self, new_highlight_color): cursor = self.textCursor() current_format = cursor.charFormat() - color = QColor(new_bg_color) - current_format.setBackground(color) + color = QColor(new_highlight_color) + if color.isValid(): + current_format.setBackground(color) cursor.setCharFormat(current_format) # self.deselectText() From a1eb5ddd30e0e4df310fda7fd66fd823d5961070 Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Tue, 13 Feb 2024 21:20:38 -0600 Subject: [PATCH 079/127] Fix merge conflicts --- Assets/icons/svg_textHighlightColor.svg | 14 +++ Modules/BuildUI.py | 121 ++++++++---------------- 2 files changed, 55 insertions(+), 80 deletions(-) create mode 100644 Assets/icons/svg_textHighlightColor.svg diff --git a/Assets/icons/svg_textHighlightColor.svg b/Assets/icons/svg_textHighlightColor.svg new file mode 100644 index 0000000..1cc087a --- /dev/null +++ b/Assets/icons/svg_textHighlightColor.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index 959077a..0a20357 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -17,21 +17,21 @@ FONT_SIZES = [7, 8, 9, 10, 11, 12, 13, 14, 18, 24, 36, 48, 64, 72, 96, 144, 288] #builds the application's UI -def build_ui(self): +def build_ui(editor): print("Building UI...") - #self.selfFrameView = selfFrameView(self) - #self.statusBar = self.statusBar() - build_window(self) - build_menubar(self) - build_toolbar(self) - #build_test_toolbar(self) + #editor.EditorFrameView = EditorFrameView(editor) + #editor.statusBar = editor.statusBar() + build_window(editor) + build_menubar(editor) + build_toolbar(editor) + #build_test_toolbar(editor) # Application's main layout (grid) gridLayout = QGridLayout() gridContainerWidget = QWidget() - self.setCentralWidget(gridContainerWidget) + editor.setCentralWidget(gridContainerWidget) gridContainerWidget.setLayout(gridLayout) gridLayout.setSpacing(3) @@ -61,66 +61,63 @@ def build_ui(self): # Add appropriate widgets (ideally just view controllers) to their layouts - leftSideLayout.addWidget(self.notebookTitleView, 0) - leftSideLayout.addWidget(self.pageView, 1) # Page view has max stretch factor - rightSideLayout.addWidget(self.sectionView, 0) - rightSideLayout.addWidget(self.frameView, 1) # Frame view has max stretch factor + leftSideLayout.addWidget(editor.notebookTitleView, 0) + leftSideLayout.addWidget(editor.pageView, 1) # Page view has max stretch factor + rightSideLayout.addWidget(editor.sectionView, 0) + rightSideLayout.addWidget(editor.frameView, 1) # Frame view has max stretch factor # Add L+R container's widgets to the main grid gridLayout.addWidget(leftSideContainerWidget, 0, 0) gridLayout.addWidget(rightSideContainerWidget, 0, 1) addSectionButton = QPushButton("Add Section") - #add functionality e.g. addSectionButton.clcicked.connect(self.add_section_function) + #add functionality e.g. addSectionButton.clcicked.connect(editor.add_section_function) leftSideLayout.addWidget(addSectionButton) - - -def build_window(self): - self.setWindowTitle("OpenNote") - self.setWindowIcon(QIcon('./Assets/OpenNoteLogo.png')) - self.setAcceptDrops(True) +def build_window(editor): + editor.setWindowTitle("OpenNote") + editor.setWindowIcon(QIcon('./Assets/OpenNoteLogo.png')) + editor.setAcceptDrops(True) with open('./Styles/styles.qss',"r") as fh: - self.setStyleSheet(fh.read()) + editor.setStyleSheet(fh.read()) -def build_menubar(self): - file = self.menuBar().addMenu('&File') - plugins = self.menuBar().addMenu('&Plugins') +def build_menubar(editor): + file = editor.menuBar().addMenu('&File') + plugins = editor.menuBar().addMenu('&Plugins') - new_file = build_action(self, './Assets/icons/svg_file_open', 'New Notebook', 'New Notebook', False) + new_file = build_action(editor, './Assets/icons/svg_file_open', 'New Notebook', 'New Notebook', False) new_file.setShortcut(QKeySequence.StandardKey.New) - new_file.triggered.connect(lambda: new(self)) + new_file.triggered.connect(lambda: new(editor)) - open_file = build_action(self, './Assets/icons/svg_file_open', 'Open Notebook', 'Open Notebook', False) + open_file = build_action(editor, './Assets/icons/svg_file_open', 'Open Notebook', 'Open Notebook', False) open_file.setShortcut(QKeySequence.StandardKey.Open) - open_file.triggered.connect(lambda: load(self)) + open_file.triggered.connect(lambda: load(editor)) - save_file = build_action(self, './Assets/icons/svg_file_save', 'Save Notebook', 'Save Notebook', False) + save_file = build_action(editor, './Assets/icons/svg_file_save', 'Save Notebook', 'Save Notebook', False) save_file.setShortcut(QKeySequence.StandardKey.Save) - save_file.triggered.connect(lambda: save(self)) + save_file.triggered.connect(lambda: save(editor)) - save_fileAs = build_action(self, './Assets/icons/svg_file_save', 'Save Notebook As...', 'Save Notebook As', False) + save_fileAs = build_action(editor, './Assets/icons/svg_file_save', 'Save Notebook As...', 'Save Notebook As', False) save_fileAs.setShortcut(QKeySequence.fromString('Ctrl+Shift+S')) - save_fileAs.triggered.connect(lambda: saveAs(self)) + save_fileAs.triggered.connect(lambda: saveAs(editor)) - add_widget = build_action(self, './Assets/icons/svg_question', 'Add Custom Widget', 'Add Custom Widget', False) + add_widget = build_action(editor, './Assets/icons/svg_question', 'Add Custom Widget', 'Add Custom Widget', False) file.addActions([new_file, open_file, save_file, save_fileAs]) plugins.addActions([add_widget]) -def build_toolbar(self): +def build_toolbar(editor): toolbar = QToolBar() toolbar.setIconSize(QSize(16, 16)) toolbar.setMovable(False) - self.addToolBar(Qt.ToolBarArea.TopToolBarArea, toolbar) - + editor.addToolBar(Qt.ToolBarArea.TopToolBarArea, toolbar) #separates toolbar with a line break spacer = QWidget() spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) toolbar_undo = build_action(toolbar, './Assets/icons/svg_undo', "undo", "undo", False) - toolbar_undo.triggered.connect(self.frameView.triggerUndo) + toolbar_undo.triggered.connect(editor.frameView.triggerUndo) redo = build_action(toolbar, './Assets/icons/svg_redo', "redo", "redo", False) @@ -147,8 +144,8 @@ def build_toolbar(self): #current bug, alternates between activating and not working when using bgColor.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.BackgroundColor, QColorDialog.getColor())) - textboxColor = build_action(toolbar, './Assets/icons/svg_textboxColor', "Text Box Color", "Text Box Color", True) - textboxColor.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.TextboxColor, QColorDialog.getColor())) + textHighlightColor = build_action(toolbar, './Assets/icons/svg_textHighlightColor', "Text Highlight Color", "Text Highlight Color", True) + textHighlightColor.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.textHighlightColor, QColorDialog.getColor())) #defines font color icon appearance and settings fontColor = build_action(toolbar, './Assets/icons/svg_font_color', "Font Color", "Font Color", False) @@ -164,10 +161,10 @@ def build_toolbar(self): underline.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontUnderline, None)) table = build_action(toolbar, './Assets/icons/svg_table', "Create Table", "Create Table", False) - table.triggered.connect(self.frameView.toolbar_table) + table.triggered.connect(editor.frameView.toolbar_table) hyperlink = build_action(toolbar, './Assets/icons/svg_hyperlink', "Hyperlink", "Hyperlink", False) - hyperlink.triggered.connect(self.frameView.toolbar_hyperlink) + hyperlink.triggered.connect(editor.frameView.toolbar_hyperlink) bullets = build_action(toolbar, './Assets/icons/svg_bullets', "Bullets", "Bullets", False) @@ -177,44 +174,16 @@ def build_toolbar(self): bullet_num = build_action(toolbar, './Assets/icons/svg_bullet_number', "Bullet List", "Bullet List", False) bullet_num.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Bullet_Num, None)) - ''' - editor.action1 = QAction('Action 1', editor) - #editor.action1.triggered.connect(EditorFrameView.slot_action1) - toolbar.addAction(editor.action1) - editor.action2 = QAction('Action 2', editor) - #editor.action2.triggered.connect(TextboxWidget.slot_action2) - #editor.action2.triggered.connect(show_popup) - toolbar.addAction(editor.action2) - #editor.button = QPushButton("Click Me", editor) - #editor.button.clicked.connect(editor.slot_button_click)''' - - toolbar.addActions([toolbar_undo, redo]) toolbar.addSeparator() toolbar.addWidget(font_family) toolbar.addWidget(font_size) toolbar.addSeparator() - toolbar.addActions([bgColor, textboxColor, fontColor, bold, italic, underline]) + toolbar.addActions([bold, italic, underline, fontColor, textHighlightColor, bgColor]) toolbar.addSeparator() toolbar.addActions([table, hyperlink, bullet_reg, bullet_num]) - #-------- BG Color ----------- - bgColor = build_action(toolbar, './Assets/icons/svg_bullets', "Bullets", "Bullets", False) - - bgColor_menu = QMenu(self) - - bgColor = QToolButton(self) - bgColor.setIcon(QIcon('./Assets/icons/svg_font_bucket')) - bgColor.setPopupMode(QToolButton.InstantPopup) - bgColor.setMenu(bgColor_menu) - presetColors = ['blue', '#ffcc00', '#66ff66', '#3399ff'] - for color in presetColors: - presetAction = QAction(color, self) - bgColor_menu.addAction(presetAction) - toolbar.addWidget(bgColor) - - #----------------------------- - bullets_menu = QMenu(self) + bullets_menu = QMenu(editor) bulletUpperA = build_action(bullets_menu, './Assets/icons/svg_bulletUA', "", "", False) bulletUpperA.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.BulletUA, None)) @@ -225,7 +194,7 @@ def build_toolbar(self): bullets_menu.addAction(bulletUpperA) bullets_menu.addAction(bulletUpperR) - bullets = QToolButton(self) + bullets = QToolButton(editor) bullets.setIcon(QIcon('./Assets/icons/svg_bullets')) bullets.setPopupMode(QToolButton.InstantPopup) bullets.setMenu(bullets_menu) @@ -234,14 +203,6 @@ def build_toolbar(self): #toolbar.setStyleSheet("QToolBar { background-color: #FFFFFF; }") -def homeTabUI(self): - homeTab = QWidget() - layout = QVBoxLayout() - layout.addWidget(QCheckBox("General Option 1")) - layout.addWidget(QCheckBox("General Option 2")) - homeTab.setLayout(layout) - return homeTab - def openGetColorDialog(purpose): color = QColorDialog.getColor() if color.isValid(): @@ -254,4 +215,4 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): action = QAction(QIcon(icon_path), action_name, parent) action.setStatusTip(set_status_tip) action.setCheckable(set_checkable) - return action \ No newline at end of file + return action From 60848e08d55c0690380851ad95f8e200786cd617 Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Tue, 13 Feb 2024 22:30:16 -0600 Subject: [PATCH 080/127] Small fix for merging t wasn't capitalized --- Modules/BuildUI.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index 4d4112e..3887de3 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -146,7 +146,7 @@ def build_toolbar(editor): textHighlightColor = build_action(toolbar, './Assets/icons/svg_textHighlightColor', "Text Highlight Color", "Text Highlight Color", True) - textHighlightColor.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.textHighlightColor, QColorDialog.getColor())) + textHighlightColor.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.TextHighlightColor, QColorDialog.getColor())) #defines font color icon appearance and settings fontColor = build_action(toolbar, './Assets/icons/svg_font_color', "Font Color", "Font Color", False) From 16cf383b0e590966f10792dac17328342714369a Mon Sep 17 00:00:00 2001 From: ldeltastreaml <70774713+ldeltastreaml@users.noreply.github.com> Date: Thu, 15 Feb 2024 02:05:23 -0600 Subject: [PATCH 081/127] Reorganized/Renaming menubar,toolbar, and right click menu Added Home and Insert menu buttons. Home allows the user to toggle the toolbar, and Insert is currently a placeholder for when adding more "insert" features. Reorganized order of toolbar/right click to better mirror OneNote. Which included moving all numbered lists into list dropdown. Right Click dropdown is currently spitting out an error message but still functioning properly. --- Modules/BuildUI.py | 92 +++++++++++++++++++++++++++++++--------------- Widgets/Textbox.py | 60 +++++++++++++++--------------- 2 files changed, 93 insertions(+), 59 deletions(-) diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index 3887de3..05c6740 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -83,6 +83,8 @@ def build_window(editor): def build_menubar(editor): file = editor.menuBar().addMenu('&File') + home = editor.menuBar().addMenu('&Home') + insert = editor.menuBar().addMenu('&Insert') plugins = editor.menuBar().addMenu('&Plugins') new_file = build_action(editor, './Assets/icons/svg_file_open', 'New Notebook', 'New Notebook', False) @@ -101,11 +103,25 @@ def build_menubar(editor): save_fileAs.setShortcut(QKeySequence.fromString('Ctrl+Shift+S')) save_fileAs.triggered.connect(lambda: saveAs(editor)) + toggle_home_toolbar = build_action(editor, '', 'Toggle Home Toolbar', 'Toggle Home Toolbar', False) + toggle_home_toolbar.triggered.connect(lambda: set_toolbar_visibility(editor)) + + toggle_insert_toolbar = build_action(editor, '', 'Toggle Insert Toolbar', 'Toggle Insert Toolbar', False) + #toggle_insert_toolbar.triggered.connect(lambda: set_toolbar_visibility(insert)) + add_widget = build_action(editor, './Assets/icons/svg_question', 'Add Custom Widget', 'Add Custom Widget', False) file.addActions([new_file, open_file, save_file, save_fileAs]) + home.addActions([toggle_home_toolbar]) + insert.addActions([toggle_insert_toolbar]) plugins.addActions([add_widget]) +def set_toolbar_visibility(editor): + toolbar = editor.findChild(QToolBar) + if toolbar: + print("toolbar visibility change") + toolbar.setVisible(not toolbar.isVisible()) + def build_toolbar(editor): toolbar = QToolBar() toolbar.setIconSize(QSize(16, 16)) @@ -116,12 +132,11 @@ def build_toolbar(editor): spacer = QWidget() spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) - toolbar_undo = build_action(toolbar, './Assets/icons/svg_undo', "undo", "undo", False) - toolbar_undo.triggered.connect(editor.frameView.triggerUndo) - + undo = build_action(toolbar, './Assets/icons/svg_undo', "undo", "undo", False) + undo.triggered.connect(editor.frameView.triggerUndo) redo = build_action(toolbar, './Assets/icons/svg_redo', "redo", "redo", False) - + # redo.triggered.connect(editor.frameView.triggerRedo) font_family = QFontComboBox() @@ -166,43 +181,62 @@ def build_toolbar(editor): hyperlink = build_action(toolbar, './Assets/icons/svg_hyperlink', "Hyperlink", "Hyperlink", False) hyperlink.triggered.connect(editor.frameView.toolbar_hyperlink) + + # Bullets with placeholder for more bullet options + bullet = build_action(toolbar, './Assets/icons/svg_bullets', "Bullets", "Bullets", False) + bullet.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Bullet, None)) + - bullets = build_action(toolbar, './Assets/icons/svg_bullets', "Bullets", "Bullets", False) - - bullet_reg = build_action(toolbar, './Assets/icons/svg_bullets', "Bullet List", "Bullet List", False) - bullet_reg.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Bullet, None)) - - bullet_num = build_action(toolbar, './Assets/icons/svg_bullet_number', "Bullet List", "Bullet List", False) - bullet_num.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Bullet_Num, None)) - - toolbar.addActions([toolbar_undo, redo]) + toolbar.addActions([undo, redo]) + toolbar.addSeparator() + toolbar.addWidget(font_family) toolbar.addWidget(font_size) + toolbar.addSeparator() + toolbar.addActions([bold, italic, underline, fontColor, textHighlightColor, bgColor]) - toolbar.addSeparator() - toolbar.addActions([table, hyperlink, bullet_reg, bullet_num]) + + toolbar.addActions([bullet]) - bullets_menu = QMenu(editor) + # numbering menu start + numbering_menu = QMenu(editor) + + bullet_num = build_action(numbering_menu, './Assets/icons/svg_bullet_number', "", "", False) + bullet_num.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Bullet_Num, None)) - bulletUpperA = build_action(bullets_menu, './Assets/icons/svg_bulletUA', "", "", False) + bulletUpperA = build_action(numbering_menu, './Assets/icons/svg_bulletUA', "", "", False) bulletUpperA.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.BulletUA, None)) - bulletUpperR = build_action(bullets_menu, './Assets/icons/svg_bulletUR', "", "", False) + bulletUpperR = build_action(numbering_menu, './Assets/icons/svg_bulletUR', "", "", False) bulletUpperR.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.BulletUR, None)) - bullets_menu.addAction(bulletUpperA) - bullets_menu.addAction(bulletUpperR) - - bullets = QToolButton(editor) - bullets.setIcon(QIcon('./Assets/icons/svg_bullets')) - bullets.setPopupMode(QToolButton.InstantPopup) - bullets.setMenu(bullets_menu) - - toolbar.addWidget(bullets) - - #toolbar.setStyleSheet("QToolBar { background-color: #FFFFFF; }") + numbering_menu.addAction(bullet_num) + numbering_menu.addAction(bulletUpperA) + numbering_menu.addAction(bulletUpperR) + + # cant directly add numbering menu to toolbar so this is required + numbering = QToolButton(editor) + numbering.setIcon(QIcon('./Assets/icons/svg_bullet_number')) + numbering.setPopupMode(QToolButton.MenuButtonPopup) + numbering.setMenu(numbering_menu) + + toolbar.addWidget(numbering) + + align_left = build_action(toolbar,"./Assets/icons/svg_align_left","Align Left","Align Left",False) + align_left.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.AlignLeft, None)) + + align_center = build_action(toolbar,"./Assets/icons/svg_align_center","Align Center","Align Center",False) + align_center.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.AlignCenter, None)) + align_right = build_action(toolbar, "./Assets/icons/svg_align_right", "Align Right", "Align Right", False) + align_right.triggered.connect(lambda x: self.setAlignment(Qt.AlignRight)) + + toolbar.addActions([align_left, align_center, align_right]) + + toolbar.addSeparator() + + toolbar.addActions([table, hyperlink]) def openGetColorDialog(purpose): color = QColorDialog.getColor() diff --git a/Widgets/Textbox.py b/Widgets/Textbox.py index aedbe5b..e816f4e 100644 --- a/Widgets/Textbox.py +++ b/Widgets/Textbox.py @@ -170,8 +170,8 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): textHighlightColor = build_action( toolbarBottom, "./Assets/icons/svg_textHighlightColor", - "Background Color", - "Background Color", + "Text Highlight Color", + "Text Highlight Color", False, ) textHighlightColor.triggered.connect( @@ -183,50 +183,50 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): ) bullets.toggled.connect(lambda: self.bullet_list("bulletReg")) - bullets_num = build_action( - toolbarBottom, - "./Assets/icons/svg_bullet_number", - "Bullets Num", - "Bullets Num", - True, - ) - bullets_num.toggled.connect(lambda: self.bullet_list("bulletNum")) - - toolbarTop.addWidget(font) toolbarTop.addWidget(size) toolbarBottom.addActions( - [ - align_left, - align_center, - align_right, + [ bold, italic, underline, fontColor, textHighlightColor, - bgColor, - bullets, - bullets_num, - ] + bullets + ] ) - - menu = QMenu(self) - bulletUpperA = menu.addAction(QIcon("./Assets/icons/svg_bulletUA"), "") - bulletUpperR = menu.addAction(QIcon("./Assets/icons/svg_bulletUR"), "") - + + # numbering menu has to be added inbetween + numbering_menu = QMenu(self) + bullets_num = numbering_menu.addAction(QIcon("./Assets/icons/svg_bullet_number"), "") + bulletUpperA = numbering_menu.addAction(QIcon("./Assets/icons/svg_bulletUA"), "") + bulletUpperR = numbering_menu.addAction(QIcon("./Assets/icons/svg_bulletUR"), "") + + bullets_num.triggered.connect(lambda: self.bullet_list("bulletNum")) bulletUpperA.triggered.connect(lambda: self.bullet_list("bulletUpperA")) bulletUpperR.triggered.connect(lambda: self.bullet_list("bulletUpperR")) - menu_button = QToolButton(self) - menu_button.setPopupMode(QToolButton.InstantPopup) - menu_button.setIcon(QIcon("./Assets/icons/svg_bullets")) + numbering = QToolButton(self) + numbering.setPopupMode(QToolButton.MenuButtonPopup) + numbering.setIcon(QIcon("./Assets/icons/svg_bullet_number")) - menu_button.setMenu(menu) + # This code would fix an error on the command line but it also makes it not look good soooo + #numbering_menu.setParent(numbering) + + numbering.setMenu(numbering_menu) - toolbarBottom.addWidget(menu_button) + toolbarBottom.addWidget(numbering) + + toolbarBottom.addActions( + [ + bgColor, + align_left, + align_center, + align_right + ] + ) qwaTop = QWidgetAction(self) qwaTop.setDefaultWidget(toolbarTop) From 9526ced810d3752f48769186db7ff8931d5b3a2f Mon Sep 17 00:00:00 2001 From: ldeltastreaml <70774713+ldeltastreaml@users.noreply.github.com> Date: Thu, 15 Feb 2024 02:20:49 -0600 Subject: [PATCH 082/127] Compressed code Added bullet to the previous statement --- Modules/BuildUI.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index 05c6740..1e4c6f3 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -196,9 +196,7 @@ def build_toolbar(editor): toolbar.addSeparator() - toolbar.addActions([bold, italic, underline, fontColor, textHighlightColor, bgColor]) - - toolbar.addActions([bullet]) + toolbar.addActions([bold, italic, underline, fontColor, textHighlightColor, bgColor, bullet]) # numbering menu start numbering_menu = QMenu(editor) From d3024be4ae5394fa1d113d71716918bb4ab86a7d Mon Sep 17 00:00:00 2001 From: ldeltastreaml <70774713+ldeltastreaml@users.noreply.github.com> Date: Fri, 16 Feb 2024 01:46:34 -0600 Subject: [PATCH 083/127] Addition of Alignment in toolbar and Removal from Right Click Menui Additionally commented out the inclusion of textbox color change in right click menu. Its not originally present in One Note so I decided to just remove it for now. --- Models/DraggableContainer.py | 11 +++++++ Modules/BuildUI.py | 12 +++---- Modules/EditorSignals.py | 3 ++ Widgets/Textbox.py | 61 ++++++++++++++++++------------------ 4 files changed, 49 insertions(+), 38 deletions(-) diff --git a/Models/DraggableContainer.py b/Models/DraggableContainer.py index 0396347..eb6a446 100644 --- a/Models/DraggableContainer.py +++ b/Models/DraggableContainer.py @@ -359,6 +359,17 @@ def widgetAttributeChanged(self, changedWidgetAttribute, value): elif hasattr(child_widget, "changeBulletEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.BulletUR): print("Change Bullet Event Called") child_widget.bullet_list("bulletUpperR") + + elif hasattr(child_widget, "changeAlignmentEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.AlignLeft): + print("Change Alignment Event Called") + child_widget.changeAlignmentEvent("alignLeft") + elif hasattr(child_widget, "changeAlignmentEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.AlignCenter): + print("Change Alignment Event Called") + child_widget.changeAlignmentEvent("alignCenter") + elif hasattr(child_widget, "changeAlignmentEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.AlignRight): + print("Change Alignment Event Called") + child_widget.changeAlignmentEvent("alignRight") + elif hasattr(child_widget, "changeBackgroundColorEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.BackgroundColor): print("Chang Background Color Event Called") child_widget.changeBackgroundColorEvent(value) diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index 1e4c6f3..9e8ce12 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -203,16 +203,15 @@ def build_toolbar(editor): bullet_num = build_action(numbering_menu, './Assets/icons/svg_bullet_number', "", "", False) bullet_num.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Bullet_Num, None)) - + + bullet_num = build_action(numbering_menu, './Assets/icons/svg_bullet_number', "", "", False) + bullet_num.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Bullet_Num, None)) bulletUpperA = build_action(numbering_menu, './Assets/icons/svg_bulletUA', "", "", False) bulletUpperA.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.BulletUA, None)) - bulletUpperR = build_action(numbering_menu, './Assets/icons/svg_bulletUR', "", "", False) bulletUpperR.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.BulletUR, None)) - numbering_menu.addAction(bullet_num) - numbering_menu.addAction(bulletUpperA) - numbering_menu.addAction(bulletUpperR) + numbering_menu.addActions([bullet_num, bulletUpperA, bulletUpperR]) # cant directly add numbering menu to toolbar so this is required numbering = QToolButton(editor) @@ -224,11 +223,10 @@ def build_toolbar(editor): align_left = build_action(toolbar,"./Assets/icons/svg_align_left","Align Left","Align Left",False) align_left.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.AlignLeft, None)) - align_center = build_action(toolbar,"./Assets/icons/svg_align_center","Align Center","Align Center",False) align_center.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.AlignCenter, None)) align_right = build_action(toolbar, "./Assets/icons/svg_align_right", "Align Right", "Align Right", False) - align_right.triggered.connect(lambda x: self.setAlignment(Qt.AlignRight)) + align_right.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.AlignRight, None)) toolbar.addActions([align_left, align_center, align_right]) diff --git a/Modules/EditorSignals.py b/Modules/EditorSignals.py index b72c62c..a6f8e25 100644 --- a/Modules/EditorSignals.py +++ b/Modules/EditorSignals.py @@ -19,6 +19,9 @@ class ChangedWidgetAttribute(Enum): BulletUR = 11 BulletUA = 12 + AlignLeft = 13 + AlignCenter = 14 + AlignRight = 15 # Cant be statically typed because importing the classes causes circular imports diff --git a/Widgets/Textbox.py b/Widgets/Textbox.py index e816f4e..d9ec76d 100644 --- a/Widgets/Textbox.py +++ b/Widgets/Textbox.py @@ -75,14 +75,15 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): return action toolbarTop = QToolBar() - toolbarTop.setIconSize(QSize(25, 25)) + toolbarTop.setIconSize(QSize(16, 16)) toolbarTop.setMovable(False) toolbarBottom = QToolBar() - toolbarBottom.setIconSize(QSize(25, 25)) + toolbarBottom.setIconSize(QSize(16, 16)) toolbarBottom.setMovable(False) font = QFontComboBox() + font.setFixedWidth(150) font.currentFontChanged.connect( lambda x: self.setCurrentFontCustom( font.currentFont() if x else self.currentFont() @@ -96,32 +97,14 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): FONT_SIZES[x] if x else self.fontPointSize() ) ) - - align_left = build_action( - toolbarBottom, - "./Assets/icons/svg_align_left", - "Align Left", - "Align Left", - True, - ) + + align_left = build_action(toolbarBottom, "./Assets/icons/svg_align_left", "Align Left", "Align Left", False) align_left.triggered.connect(lambda x: self.setAlignment(Qt.AlignLeft)) - align_center = build_action( - toolbarBottom, - "./Assets/icons/svg_align_center", - "Align Center", - "Align Center", - True, - ) + align_center = build_action(toolbarBottom, "./Assets/icons/svg_align_center", "Align Center", "Align Center", False) align_center.triggered.connect(lambda x: self.setAlignment(Qt.AlignCenter)) - align_right = build_action( - toolbarBottom, - "./Assets/icons/svg_align_right", - "Align Right", - "Align Right", - True, - ) + align_right = build_action(toolbarBottom, "./Assets/icons/svg_align_right", "Align Right", "Align Right", False) align_right.triggered.connect(lambda x: self.setAlignment(Qt.AlignRight)) bold = build_action( @@ -191,8 +174,8 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): bold, italic, underline, - fontColor, textHighlightColor, + fontColor, bullets ] ) @@ -209,16 +192,17 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): numbering = QToolButton(self) - numbering.setPopupMode(QToolButton.MenuButtonPopup) numbering.setIcon(QIcon("./Assets/icons/svg_bullet_number")) - + numbering.setPopupMode(QToolButton.MenuButtonPopup) + numbering.setMenu(numbering_menu) + # This code would fix an error on the command line but it also makes it not look good soooo - #numbering_menu.setParent(numbering) + numbering.setParent(numbering_menu) - numbering.setMenu(numbering_menu) - toolbarBottom.addWidget(numbering) + # not required for right-click menu as they arent originally present in OneNote + ''' toolbarBottom.addActions( [ bgColor, @@ -227,7 +211,7 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): align_right ] ) - + ''' qwaTop = QWidgetAction(self) qwaTop.setDefaultWidget(toolbarTop) qwaBottom = QWidgetAction(self) @@ -397,6 +381,21 @@ def bullet_list(self, bulletType): self.setTextCursor(cursor) self.setFocus() + def changeAlignmentEvent(self, alignmentType): + print("Alignment Event Called") + cursor = self.textCursor() + blockFormat = cursor.blockFormat() + + if alignmentType == "alignLeft": + blockFormat.setAlignment(Qt.AlignLeft) + elif alignmentType == "alignCenter": + blockFormat.setAlignment(Qt.AlignCenter) + elif alignmentType == "alignRight": + blockFormat.setAlignment(Qt.AlignRight) + + cursor.setBlockFormat(blockFormat) + self.setTextCursor(cursor) + self.setFocus() def handleTabKey(self): cursor = self.textCursor() From 22ff736489da574969d50ee425f2f684d52b8648 Mon Sep 17 00:00:00 2001 From: ldeltastreaml <70774713+ldeltastreaml@users.noreply.github.com> Date: Fri, 16 Feb 2024 02:45:32 -0600 Subject: [PATCH 084/127] Fixed a few screensnip issues Screen snip on linux takes into account the geometry of the screen. Made brush stroke clear because it would change the color of the snip. Changed the bounding box numbers to better fit the screensnip. --- Modules/Screensnip.py | 14 ++++++++------ requirements.txt | 1 + 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Modules/Screensnip.py b/Modules/Screensnip.py index a279497..9df1c83 100644 --- a/Modules/Screensnip.py +++ b/Modules/Screensnip.py @@ -40,7 +40,8 @@ def start(self, event_pos): def paintEvent(self, event): if SnippingWidget.is_snipping: - brush_color = (128, 128, 255, 100) + #brush_color = (128, 128, 255, 100) + brush_color = (0, 0, 0, 0) lw = 3 opacity = 0.3 @@ -71,10 +72,11 @@ def mouseMoveEvent(self, event): def mouseReleaseEvent(self, event): SnippingWidget.is_snipping = False QApplication.restoreOverrideCursor() - x1 = min(self.begin.x(), self.end.x()) - y1 = min(self.begin.y(), self.end.y()) - x2 = max(self.begin.x(), self.end.x()) - y2 = max(self.begin.y(), self.end.y()) + rect = self.geometry() + x1 = min(self.begin.x(), self.end.x()) + rect.left() + y1 = min(self.begin.y(), self.end.y()) + rect.top() + x2 = max(self.begin.x(), self.end.x()) + rect.left() + y2 = max(self.begin.y(), self.end.y()) + rect.top() self.repaint() QApplication.processEvents() @@ -83,7 +85,7 @@ def mouseReleaseEvent(self, event): if platform == "darwin": img = ImageGrab.grab(bbox=( (x1 ) * 2, (y1 + 55 ) * 2, (x2 ) * 2, (y2 + 55) * 2)) else: - img = ImageGrab.grab(bbox=(x1 + 10, y1 + 30, x2 + 10, y2 + 40)) + img = ImageGrab.grab(bbox=(x1 + 2, y1 + 2, x2 - 1, y2 - 1)) except Exception as e: print(f"Error grabbing screenshot: {e}") img = None diff --git a/requirements.txt b/requirements.txt index fbba2f8..8c8e968 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,3 +5,4 @@ PySide6>=6.5.0 PySide6-Addons>=6.5.0 PySide6-Essentials>=6.5.0 shiboken6>=6.5.0 +libxcb-cursor0>= 0.1.0 From a27c63f8b98bdb39d2dbf2d8bc4693627f3f8854 Mon Sep 17 00:00:00 2001 From: ldeltastreaml <70774713+ldeltastreaml@users.noreply.github.com> Date: Fri, 16 Feb 2024 03:17:08 -0600 Subject: [PATCH 085/127] Getting code ready for right click menu I want to add link and table functionality to right click menu but dont fully know how to do it yet (its different from the top RCM toolbar) will uncomment once I know. --- Models/DraggableContainer.py | 26 ++++++++++++++++++-------- Modules/EditorSignals.py | 7 ++++++- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/Models/DraggableContainer.py b/Models/DraggableContainer.py index eb6a446..0e5760d 100644 --- a/Models/DraggableContainer.py +++ b/Models/DraggableContainer.py @@ -151,17 +151,27 @@ def buildDragContainerMenu(self): menu.addAction(item) # Add standard menu actions - delete = QAction("Delete", self) - delete.triggered.connect(lambda: editorSignalsInstance.widgetRemoved.emit(self)) - menu.addAction(delete) + cut = QAction("Cut", self) + cut.triggered.connect(lambda: editorSignalsInstance.widgetCut.emit(self)) copy = QAction("Copy", self) copy.triggered.connect(lambda: editorSignalsInstance.widgetCopied.emit(self)) - menu.addAction(copy) - - cut = QAction("Cut", self) - cut.triggered.connect(lambda: editorSignalsInstance.widgetCut.emit(self)) - menu.addAction(cut) + + delete = QAction("Delete", self) + delete.triggered.connect(lambda: editorSignalsInstance.widgetRemoved.emit(self)) + + # Ready for deployment when code is ready + ''' + link = QAction("Link", self) + link.triggered.connect(lambda: editorSignalsInstance.widgetLink.emit(self)) + + table = QAction("Table", self) + table.triggered.connect(lambda: editorSignalsInstance.widgetTable.emit(self)) + + menu.addActions([cut, copy, delete, link, table]) + ''' + + menu.addActions([cut, copy, delete]) # Add any non-widget type menu actions from child for item in customMenuItems: diff --git a/Modules/EditorSignals.py b/Modules/EditorSignals.py index a6f8e25..912c6be 100644 --- a/Modules/EditorSignals.py +++ b/Modules/EditorSignals.py @@ -35,7 +35,12 @@ class EditorSignals(QObject): widgetRemoved = Signal(object) widgetCopied = Signal(object) widgetCut = Signal(object) - + + # Ready for deployment once code is ready + ''' + widgetLink = Signal(object) + widgetTable = Signal(object) + ''' # Recieves any widget model, and the section model to add the instance of DraggableContainer to widgetShouldLoad = Signal(object, object) From 4ce3961396ac4ecb0e4e6f4f4b542aa7550ac0e7 Mon Sep 17 00:00:00 2001 From: ldeltastreaml <70774713+ldeltastreaml@users.noreply.github.com> Date: Fri, 16 Feb 2024 14:05:57 -0600 Subject: [PATCH 086/127] Added svg's for copy and cut --- Assets/icons/svg_copy.svg | 2 ++ Assets/icons/svg_cut.svg | 4 ++++ 2 files changed, 6 insertions(+) create mode 100644 Assets/icons/svg_copy.svg create mode 100644 Assets/icons/svg_cut.svg diff --git a/Assets/icons/svg_copy.svg b/Assets/icons/svg_copy.svg new file mode 100644 index 0000000..4bd7a9a --- /dev/null +++ b/Assets/icons/svg_copy.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Assets/icons/svg_cut.svg b/Assets/icons/svg_cut.svg new file mode 100644 index 0000000..f915297 --- /dev/null +++ b/Assets/icons/svg_cut.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file From 634ed744f27d1e05f58b38e94791468436e96be1 Mon Sep 17 00:00:00 2001 From: ldeltastreaml <70774713+ldeltastreaml@users.noreply.github.com> Date: Fri, 16 Feb 2024 14:11:01 -0600 Subject: [PATCH 087/127] Added Cut and Copy to toolbar + etc Both buttons arent fully functional yet, but I added them to the toolbar anyways. Also shortened the length of the font name selection menu for asthetics. --- Modules/BuildUI.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index 9e8ce12..bd088f0 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -138,8 +138,15 @@ def build_toolbar(editor): redo = build_action(toolbar, './Assets/icons/svg_redo', "redo", "redo", False) # redo.triggered.connect(editor.frameView.triggerRedo) + cut = build_action(toolbar, './Assets/icons/svg_cut', "cut", "cut", False) + cut.triggered.connect(editor.frameView.cutWidgetEvent) + + copy = build_action(toolbar, './Assets/icons/svg_copy', "copy", "copy", False) + copy.triggered.connect(editor.frameView.copyWidgetEvent) + font_family = QFontComboBox() + font_family.setFixedWidth(150) default_font = font_family.currentFont().family() print(f"default font is {default_font}") font_family.currentFontChanged.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Font, font_family.currentFont().family())) @@ -187,7 +194,7 @@ def build_toolbar(editor): bullet.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Bullet, None)) - toolbar.addActions([undo, redo]) + toolbar.addActions([undo, redo, cut, copy]) toolbar.addSeparator() From ff34ea61e59c664fb438e4fbba5b70f901a57658 Mon Sep 17 00:00:00 2001 From: sillypenguin77 <67487654+sillypenguin77@users.noreply.github.com> Date: Fri, 16 Feb 2024 21:12:47 -0600 Subject: [PATCH 088/127] Mac dark mode detection/change page color button Added ability for mac detection of dark mode and set dark mode settings. Also added a button to change page colors. --- Assets/icons/svg_paper.svg | 6 ++++ Models/DraggableContainer.py | 3 ++ Modules/BuildUI.py | 9 ++++++ Modules/EditorSignals.py | 1 + Views/EditorFrameView.py | 54 ++++++++++++++++++++++++++++++++++-- Widgets/Textbox.py | 47 ++++++++++++++++++++++++++++--- 6 files changed, 113 insertions(+), 7 deletions(-) create mode 100644 Assets/icons/svg_paper.svg diff --git a/Assets/icons/svg_paper.svg b/Assets/icons/svg_paper.svg new file mode 100644 index 0000000..3a7d0d5 --- /dev/null +++ b/Assets/icons/svg_paper.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Models/DraggableContainer.py b/Models/DraggableContainer.py index fc0c617..7ad4615 100644 --- a/Models/DraggableContainer.py +++ b/Models/DraggableContainer.py @@ -356,6 +356,9 @@ def widgetAttributeChanged(self, changedWidgetAttribute, value): elif hasattr(child_widget, "changeBackgroundColorEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.BackgroundColor): print("Chang Background Color Event Called") child_widget.changeBackgroundColorEvent(value) + elif hasattr(child_widget, "paperColor") and (changedWidgetAttribute == ChangedWidgetAttribute.PaperColor): + print("Change Page Color Event Called") + child_widget.paperColor(value) def connectTableSignals(self, tableWidget): tableWidget.rowAdded.connect(self.resizeTable) def resizeTable(self): diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index edc622c..0f96683 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -14,6 +14,8 @@ from Views.EditorFrameView import * +import subprocess + FONT_SIZES = [7, 8, 9, 10, 11, 12, 13, 14, 18, 24, 36, 48, 64, 72, 96, 144, 288] #builds the application's UI @@ -174,6 +176,10 @@ def build_toolbar(editor): bullet_num = build_action(toolbar, './Assets/icons/svg_bullet_number', "Bullet List", "Bullet List", False) bullet_num.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Bullet_Num, None)) + paperColor= build_action(toolbar, './Assets/icons/svg_paper', "Paper Color", "Paper Color", False) + paperColor.triggered.connect(lambda: editor.frameView.pageColor(QColorDialog.getColor())) + + toolbar.addActions([toolbar_undo, redo]) toolbar.addSeparator() toolbar.addWidget(font_family) @@ -200,6 +206,9 @@ def build_toolbar(editor): bullets.setMenu(bullets_menu) toolbar.addWidget(bullets) + toolbar.addActions([paperColor]) + + #toolbar.setStyleSheet("QToolBar { background-color: #FFFFFF; }") diff --git a/Modules/EditorSignals.py b/Modules/EditorSignals.py index 72af273..632f799 100644 --- a/Modules/EditorSignals.py +++ b/Modules/EditorSignals.py @@ -18,6 +18,7 @@ class ChangedWidgetAttribute(Enum): LoseFocus = 10 BulletUR = 11 BulletUA = 12 + PaperColor = 13 # Cant be statically typed because importing the classes causes circular imports diff --git a/Views/EditorFrameView.py b/Views/EditorFrameView.py index 3ec1fa1..e950933 100644 --- a/Views/EditorFrameView.py +++ b/Views/EditorFrameView.py @@ -17,17 +17,44 @@ from Modules.Undo import UndoHandler from Widgets.Link import LinkDialog +import subprocess # Handles all widget display (could be called widget view, but so could draggablecontainer) class EditorFrameView(QWidget): + SETTINGS_KEY = "BackgroundColor" def __init__(self, editor): super(EditorFrameView, self).__init__() + + def check_appearance(): + """Checks DARK/LIGHT mode of macos.""" + cmd = 'defaults read -g AppleInterfaceStyle' + p = subprocess.Popen(cmd, stdout=subprocess.PIPE, + stderr=subprocess.PIPE, shell=True) + return bool(p.communicate()[0]) + self.editor = editor # Store reference to the editor (QMainWindow) self.editorFrame = QFrame(editor) - self.editorFrame.setStyleSheet("background-color: white;") + + #Default + self.currentBackgroundColor = self.loadBackgroundColor() or QColor(255, 255, 255) + + is_dark_mode = check_appearance() + white = QColor("white") + + #background page color + if is_dark_mode and (self.currentBackgroundColor == white or self.currentBackgroundColor == QColor(255, 255, 255)): + self.setStyleSheet(f"background-color: rgb(31, 31, 30);") + print("In dark mode, use dark mode color because the background is white or pciked white") + elif not is_dark_mode: + self.setStyleSheet(f"background-color: {self.currentBackgroundColor.name()};") + print("Set background color based on saved color in light mode") + else: + self.setStyleSheet(f"background-color: {self.currentBackgroundColor.name()};") + self.saveBackgroundColor() + print("Saving non-white color as the current background color") # Layout for the editor frame layout = QVBoxLayout(self) @@ -51,8 +78,8 @@ def __init__(self, editor): #self.shortcut.setContext(Qt.ApplicationShortcut) #self.shortcut.activated.connect(self.triggerUndo) - print("BUILT FRAMEVIEW") - + print("BUILT FRAMEVIEW") + def triggerUndo(self): print("triggerUndo Called") self.undoHandler.undo @@ -277,3 +304,24 @@ def mouseMoveEvent(self, e): # This event is only called after clicking down on def slot_action1(self, item): print("Action 1 triggered") + def pageColor(self, color: QColor): + print("CHANGE BACKGROUND COLOR EVENT") + if color.isValid(): + self.currentBackgroundColor = color + self.editorFrame.setStyleSheet(f"background-color: {color.name()};") + self.saveBackgroundColor() + + def loadBackgroundColor(self): + settings = QSettings() + color = settings.value(self.SETTINGS_KEY, type=QColor) + return color + + def saveBackgroundColor(self): + settings = QSettings() + settings.setValue(self.SETTINGS_KEY, self.currentBackgroundColor) + + def getCurrentBackgroundColor(self): + return self.currentBackgroundColor + + + diff --git a/Widgets/Textbox.py b/Widgets/Textbox.py index 2ca2046..0bd4b8f 100644 --- a/Widgets/Textbox.py +++ b/Widgets/Textbox.py @@ -3,6 +3,8 @@ from PySide6.QtWidgets import * from Modules.EditorSignals import editorSignalsInstance +import subprocess + FONT_SIZES = [7, 8, 9, 10, 11, 12, 13, 14, 18, 24, 36, 48, 64, 72, 96, 144, 288] @@ -10,14 +12,31 @@ class TextboxWidget(QTextBrowser): def __init__(self, x, y, w=15, h=30, t=""): super().__init__() + def check_appearance(): + """Checks DARK/LIGHT mode of macos.""" + cmd = 'defaults read -g AppleInterfaceStyle' + p = subprocess.Popen(cmd, stdout=subprocess.PIPE, + stderr=subprocess.PIPE, shell=True) + return bool(p.communicate()[0]) + self.setGeometry(x, y, w, h) # This sets geometry of DraggableObject self.setText(t) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.textChanged.connect(self.textChangedEvent) - self.setStyleSheet("background-color: rgba(0, 0, 0, 0);") - self.setTextColor("black") + + if check_appearance() == True: + self.setStyleSheet("background-color: rgba(31,31,30,255);") + #self.changeBackgroundColorEvent(31, 31, 30) + self.setTextColor("white") + self.changeAllTextColors("white") + + else: + self.setStyleSheet("background-color: rgba(0, 0, 0, 0);") + #self.changeBackgroundColorEvent(0,0,0) + self.setTextColor("black") + self.changeAllTextColors("black") self.setTextInteractionFlags(Qt.TextEditorInteraction | Qt.TextBrowserInteraction) @@ -520,9 +539,14 @@ def changeFontColorEvent(self, new_font_color): # self.setTextCursor(cursor) # Changes color of whole background - def changeBackgroundColorEvent(self, color: QColor): + def changeBackgroundColorEvent(self, color: QColor or int, g: int = None, b: int = None): # if self.hasFocus(): - rgb = color.getRgb() + + if isinstance(color, QColor): + rgb = color.getRgb() + else: + rgb = (color, g, b) + self.setStyleSheet(f"background-color: rgb({rgb[0]}, {rgb[1]}, {rgb[2]});") self.deselectText() @@ -549,3 +573,18 @@ def deselectText(self): def changeBulletEvent(self): # put bullet function here print("bullet press") + + def changeAllTextColors(self, new_color): + cursor = self.textCursor() + cursor.movePosition(QTextCursor.Start) + + while not cursor.atEnd(): + cursor.movePosition(QTextCursor.NextCharacter, QTextCursor.KeepAnchor) + char_format = cursor.charFormat() + + if char_format.foreground().color() == Qt.black or Qt.white: + char_format.setForeground(QColor(new_color)) + cursor.setCharFormat(char_format) + + cursor.movePosition(QTextCursor.Start) + self.setTextCursor(cursor) \ No newline at end of file From 86dfa4288ac2541da4a6d4776ccb35e62b2a7009 Mon Sep 17 00:00:00 2001 From: sillypenguin77 <67487654+sillypenguin77@users.noreply.github.com> Date: Fri, 16 Feb 2024 21:34:47 -0600 Subject: [PATCH 089/127] update mac dark mode visuals Updated side bar and toolbar colors to closer match OneNote dark mode colors. --- Modules/BuildUI.py | 17 ++++++++-- Styles/stylesDark.qss | 73 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 2 deletions(-) create mode 100644 Styles/stylesDark.qss diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index 0f96683..989f48d 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -75,13 +75,26 @@ def build_ui(editor): addSectionButton = QPushButton("Add Section") #add functionality e.g. addSectionButton.clcicked.connect(editor.add_section_function) leftSideLayout.addWidget(addSectionButton) + +def check_appearance(): + """Checks DARK/LIGHT mode of macos.""" + cmd = 'defaults read -g AppleInterfaceStyle' + p = subprocess.Popen(cmd, stdout=subprocess.PIPE, + stderr=subprocess.PIPE, shell=True) + return bool(p.communicate()[0]) + def build_window(editor): editor.setWindowTitle("OpenNote") editor.setWindowIcon(QIcon('./Assets/OpenNoteLogo.png')) editor.setAcceptDrops(True) - with open('./Styles/styles.qss',"r") as fh: - editor.setStyleSheet(fh.read()) + + if check_appearance() == False: + with open('./Styles/styles.qss',"r") as fh: + editor.setStyleSheet(fh.read()) + else: + with open('./Styles/stylesDark.qss',"r") as fh: + editor.setStyleSheet(fh.read()) def build_menubar(editor): file = editor.menuBar().addMenu('&File') diff --git a/Styles/stylesDark.qss b/Styles/stylesDark.qss new file mode 100644 index 0000000..07765b1 --- /dev/null +++ b/Styles/stylesDark.qss @@ -0,0 +1,73 @@ +* { + border: none; + padding: 0; + margin: 0; + font-family: "Segoe UI"; + font-size: 16pt; +} + +QMenuBar { + background-color: rgb(40, 20, 60); +} + +QMenuBar::item:selected { + background-color: rgb(60, 20, 60); +} + +QToolBar { + margin: 10px, 10px, 0, 0; +} + +QComboBox { + width: 50px; +} + +QToolButton { + width: 25px; + height: 25px; +} + +QPushButton#font_color { + width: 30px; + height: 20px; +} + +QToolButton::hover, QPushButton#font_color::hover { + background-color: #393939; +} + +QToolButton::checked { + background-color: #272727; +} + +QToolButton::checked::hover { + background-color: #1f1f1f; +} + +QTreeView { + background-color: #292929; +} + +QPushButton { + padding: 5px, 5px, 0, 0; +} + +QLabel#notebook_title { + padding: 5px, 5px, 0, 0; + text-align: center; + background-color: #333333; +} + +QLabel#pages_title { + padding: 5px, 5px, 5px, 0; + background-color: #292929; +} + +QPushButton#addPage { + padding-bottom: 5px; + background-color: #333333; +} + +QPushButton#addPage::hover { + background-color: #393939; +} From 6c90c52f094c56da145c0cee515e4bc6f2510626 Mon Sep 17 00:00:00 2001 From: sillypenguin77 <67487654+sillypenguin77@users.noreply.github.com> Date: Fri, 16 Feb 2024 22:03:00 -0600 Subject: [PATCH 090/127] merge commit --- Assets/icons/svg_copy.svg | 2 + Assets/icons/svg_cut.svg | 4 + Assets/icons/svg_expand.svg | 28 ++++ Assets/icons/svg_shrink.svg | 28 ++++ ...oxColor.svg => svg_textHighlightColor.svg} | 0 Models/DraggableContainer.py | 49 ++++-- Modules/BuildUI.py | 93 ++++++++---- Modules/EditorSignals.py | 16 +- Modules/Screensnip.py | 16 +- Widgets/Image.py | 83 ++++++++-- Widgets/Textbox.py | 143 +++++++++--------- requirements.txt | 1 + 12 files changed, 335 insertions(+), 128 deletions(-) create mode 100644 Assets/icons/svg_copy.svg create mode 100644 Assets/icons/svg_cut.svg create mode 100644 Assets/icons/svg_expand.svg create mode 100644 Assets/icons/svg_shrink.svg rename Assets/icons/{svg_textboxColor.svg => svg_textHighlightColor.svg} (100%) diff --git a/Assets/icons/svg_copy.svg b/Assets/icons/svg_copy.svg new file mode 100644 index 0000000..4bd7a9a --- /dev/null +++ b/Assets/icons/svg_copy.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Assets/icons/svg_cut.svg b/Assets/icons/svg_cut.svg new file mode 100644 index 0000000..f915297 --- /dev/null +++ b/Assets/icons/svg_cut.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Assets/icons/svg_expand.svg b/Assets/icons/svg_expand.svg new file mode 100644 index 0000000..7084297 --- /dev/null +++ b/Assets/icons/svg_expand.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Assets/icons/svg_shrink.svg b/Assets/icons/svg_shrink.svg new file mode 100644 index 0000000..ed75d69 --- /dev/null +++ b/Assets/icons/svg_shrink.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Assets/icons/svg_textboxColor.svg b/Assets/icons/svg_textHighlightColor.svg similarity index 100% rename from Assets/icons/svg_textboxColor.svg rename to Assets/icons/svg_textHighlightColor.svg diff --git a/Models/DraggableContainer.py b/Models/DraggableContainer.py index 7ad4615..72db364 100644 --- a/Models/DraggableContainer.py +++ b/Models/DraggableContainer.py @@ -151,17 +151,27 @@ def buildDragContainerMenu(self): menu.addAction(item) # Add standard menu actions - delete = QAction("Delete", self) - delete.triggered.connect(lambda: editorSignalsInstance.widgetRemoved.emit(self)) - menu.addAction(delete) + cut = QAction("Cut", self) + cut.triggered.connect(lambda: editorSignalsInstance.widgetCut.emit(self)) copy = QAction("Copy", self) copy.triggered.connect(lambda: editorSignalsInstance.widgetCopied.emit(self)) - menu.addAction(copy) - - cut = QAction("Cut", self) - cut.triggered.connect(lambda: editorSignalsInstance.widgetCut.emit(self)) - menu.addAction(cut) + + delete = QAction("Delete", self) + delete.triggered.connect(lambda: editorSignalsInstance.widgetRemoved.emit(self)) + + # Ready for deployment when code is ready + ''' + link = QAction("Link", self) + link.triggered.connect(lambda: editorSignalsInstance.widgetLink.emit(self)) + + table = QAction("Table", self) + table.triggered.connect(lambda: editorSignalsInstance.widgetTable.emit(self)) + + menu.addActions([cut, copy, delete, link, table]) + ''' + + menu.addActions([cut, copy, delete]) # Add any non-widget type menu actions from child for item in customMenuItems: @@ -255,6 +265,7 @@ def mouseMoveEvent(self, e: QMouseEvent): # debt: To make images resize better, ImageWidget should probaly implement this and setCursorShape # So that it can make the cursor move with the corners of pixmap and not corners of this container if (self.mode != Mode.MOVE) and e.buttons() and Qt.LeftButton: + child_widget = self.childWidget if self.mode == Mode.RESIZETL: # Left - Top newwidth = e.globalX() - self.position.x() - self.geometry().x() newheight = e.globalY() - self.position.y() - self.geometry().y() @@ -286,7 +297,12 @@ def mouseMoveEvent(self, e: QMouseEvent): elif self.mode == Mode.RESIZER: # Right self.resize(e.x(), self.height()) elif self.mode == Mode.RESIZEBR:# Right - Bottom - self.resize(e.x(), e.y()) + #if child is a image, resize differently + if isinstance(child_widget, QLabel): + #change this to where resizing corners works like onenote + self.resize(e.x(), e.y()) + else: + self.resize(e.x(), e.y()) self.parentWidget().repaint() self.newGeometry.emit(self.geometry()) @@ -329,9 +345,9 @@ def widgetAttributeChanged(self, changedWidgetAttribute, value): print("Change Font Color Event Called") child_widget.changeFontColorEvent(value) - elif hasattr(child_widget, "changeTextboxColorEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.TextboxColor): + elif hasattr(child_widget, "changeTextHighlightColorEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.TextHighlightColor): print("Change Textbox Color Event Called") - child_widget.changeTextboxColorEvent(value) + child_widget.changeTextHighlightColorEvent(value) elif hasattr(child_widget, "deselectText") and (changedWidgetAttribute == ChangedWidgetAttribute.LoseFocus): print("Clear Selection Slot Called") @@ -353,6 +369,17 @@ def widgetAttributeChanged(self, changedWidgetAttribute, value): elif hasattr(child_widget, "changeBulletEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.BulletUR): print("Change Bullet Event Called") child_widget.bullet_list("bulletUpperR") + + elif hasattr(child_widget, "changeAlignmentEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.AlignLeft): + print("Change Alignment Event Called") + child_widget.changeAlignmentEvent("alignLeft") + elif hasattr(child_widget, "changeAlignmentEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.AlignCenter): + print("Change Alignment Event Called") + child_widget.changeAlignmentEvent("alignCenter") + elif hasattr(child_widget, "changeAlignmentEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.AlignRight): + print("Change Alignment Event Called") + child_widget.changeAlignmentEvent("alignRight") + elif hasattr(child_widget, "changeBackgroundColorEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.BackgroundColor): print("Chang Background Color Event Called") child_widget.changeBackgroundColorEvent(value) diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index 989f48d..850ccb2 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -98,6 +98,8 @@ def build_window(editor): def build_menubar(editor): file = editor.menuBar().addMenu('&File') + home = editor.menuBar().addMenu('&Home') + insert = editor.menuBar().addMenu('&Insert') plugins = editor.menuBar().addMenu('&Plugins') new_file = build_action(editor, './Assets/icons/svg_file_open', 'New Notebook', 'New Notebook', False) @@ -116,11 +118,25 @@ def build_menubar(editor): save_fileAs.setShortcut(QKeySequence.fromString('Ctrl+Shift+S')) save_fileAs.triggered.connect(lambda: saveAs(editor)) + toggle_home_toolbar = build_action(editor, '', 'Toggle Home Toolbar', 'Toggle Home Toolbar', False) + toggle_home_toolbar.triggered.connect(lambda: set_toolbar_visibility(editor)) + + toggle_insert_toolbar = build_action(editor, '', 'Toggle Insert Toolbar', 'Toggle Insert Toolbar', False) + #toggle_insert_toolbar.triggered.connect(lambda: set_toolbar_visibility(insert)) + add_widget = build_action(editor, './Assets/icons/svg_question', 'Add Custom Widget', 'Add Custom Widget', False) file.addActions([new_file, open_file, save_file, save_fileAs]) + home.addActions([toggle_home_toolbar]) + insert.addActions([toggle_insert_toolbar]) plugins.addActions([add_widget]) +def set_toolbar_visibility(editor): + toolbar = editor.findChild(QToolBar) + if toolbar: + print("toolbar visibility change") + toolbar.setVisible(not toolbar.isVisible()) + def build_toolbar(editor): toolbar = QToolBar() toolbar.setIconSize(QSize(16, 16)) @@ -131,15 +147,21 @@ def build_toolbar(editor): spacer = QWidget() spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) - toolbar_undo = build_action(toolbar, './Assets/icons/svg_undo', "undo", "undo", False) - toolbar_undo.triggered.connect(editor.frameView.triggerUndo) - + undo = build_action(toolbar, './Assets/icons/svg_undo', "undo", "undo", False) + undo.triggered.connect(editor.frameView.triggerUndo) redo = build_action(toolbar, './Assets/icons/svg_redo', "redo", "redo", False) + # redo.triggered.connect(editor.frameView.triggerRedo) + + cut = build_action(toolbar, './Assets/icons/svg_cut', "cut", "cut", False) + cut.triggered.connect(editor.frameView.cutWidgetEvent) + copy = build_action(toolbar, './Assets/icons/svg_copy', "copy", "copy", False) + copy.triggered.connect(editor.frameView.copyWidgetEvent) font_family = QFontComboBox() + font_family.setFixedWidth(150) default_font = font_family.currentFont().family() print(f"default font is {default_font}") font_family.currentFontChanged.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Font, font_family.currentFont().family())) @@ -159,8 +181,9 @@ def build_toolbar(editor): #current bug, alternates between activating and not working when using bgColor.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.BackgroundColor, QColorDialog.getColor())) - textboxColor = build_action(toolbar, './Assets/icons/svg_textboxColor', "Text Box Color", "Text Box Color", True) - textboxColor.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.TextboxColor, QColorDialog.getColor())) + textHighlightColor = build_action(toolbar, './Assets/icons/svg_textHighlightColor', "Text Highlight Color", "Text Highlight Color", True) + + textHighlightColor.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.TextHighlightColor, QColorDialog.getColor())) #defines font color icon appearance and settings fontColor = build_action(toolbar, './Assets/icons/svg_font_color', "Font Color", "Font Color", False) @@ -195,35 +218,49 @@ def build_toolbar(editor): toolbar.addActions([toolbar_undo, redo]) toolbar.addSeparator() + toolbar.addWidget(font_family) toolbar.addWidget(font_size) + toolbar.addSeparator() - toolbar.addActions([bgColor, textboxColor, fontColor, bold, italic, underline]) - toolbar.addSeparator() - toolbar.addActions([table, hyperlink, bullet_reg, bullet_num]) - - bullets_menu = QMenu(editor) + + toolbar.addActions([bold, italic, underline, fontColor, textHighlightColor, bgColor, bullet]) - bulletUpperA = build_action(bullets_menu, './Assets/icons/svg_bulletUA', "", "", False) + # numbering menu start + numbering_menu = QMenu(editor) + + bullet_num = build_action(numbering_menu, './Assets/icons/svg_bullet_number', "", "", False) + bullet_num.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Bullet_Num, None)) + + bullet_num = build_action(numbering_menu, './Assets/icons/svg_bullet_number', "", "", False) + bullet_num.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Bullet_Num, None)) + bulletUpperA = build_action(numbering_menu, './Assets/icons/svg_bulletUA', "", "", False) bulletUpperA.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.BulletUA, None)) - - bulletUpperR = build_action(bullets_menu, './Assets/icons/svg_bulletUR', "", "", False) + bulletUpperR = build_action(numbering_menu, './Assets/icons/svg_bulletUR', "", "", False) bulletUpperR.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.BulletUR, None)) - bullets_menu.addAction(bulletUpperA) - bullets_menu.addAction(bulletUpperR) - - bullets = QToolButton(editor) - bullets.setIcon(QIcon('./Assets/icons/svg_bullets')) - bullets.setPopupMode(QToolButton.InstantPopup) - bullets.setMenu(bullets_menu) - - toolbar.addWidget(bullets) - toolbar.addActions([paperColor]) - - - - #toolbar.setStyleSheet("QToolBar { background-color: #FFFFFF; }") + numbering_menu.addActions([bullet_num, bulletUpperA, bulletUpperR]) + + # cant directly add numbering menu to toolbar so this is required + numbering = QToolButton(editor) + numbering.setIcon(QIcon('./Assets/icons/svg_bullet_number')) + numbering.setPopupMode(QToolButton.MenuButtonPopup) + numbering.setMenu(numbering_menu) + + toolbar.addWidget(numbering) + + align_left = build_action(toolbar,"./Assets/icons/svg_align_left","Align Left","Align Left",False) + align_left.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.AlignLeft, None)) + align_center = build_action(toolbar,"./Assets/icons/svg_align_center","Align Center","Align Center",False) + align_center.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.AlignCenter, None)) + align_right = build_action(toolbar, "./Assets/icons/svg_align_right", "Align Right", "Align Right", False) + align_right.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.AlignRight, None)) + + toolbar.addActions([align_left, align_center, align_right]) + + toolbar.addSeparator() + + toolbar.addActions([table, hyperlink]) def openGetColorDialog(purpose): color = QColorDialog.getColor() @@ -237,4 +274,4 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): action = QAction(QIcon(icon_path), action_name, parent) action.setStatusTip(set_status_tip) action.setCheckable(set_checkable) - return action \ No newline at end of file + return action diff --git a/Modules/EditorSignals.py b/Modules/EditorSignals.py index 632f799..df1b4bb 100644 --- a/Modules/EditorSignals.py +++ b/Modules/EditorSignals.py @@ -12,13 +12,18 @@ class ChangedWidgetAttribute(Enum): FontBold = 4 FontItalic = 5 FontUnderline = 6 - TextboxColor = 7 + TextHighlightColor = 7 Bullet = 8 Bullet_Num = 9 LoseFocus = 10 + BulletUR = 11 BulletUA = 12 - PaperColor = 13 + AlignLeft = 13 + AlignCenter = 14 + AlignRight = 15 + PaperColor = 16 + # Cant be statically typed because importing the classes causes circular imports @@ -32,7 +37,12 @@ class EditorSignals(QObject): widgetRemoved = Signal(object) widgetCopied = Signal(object) widgetCut = Signal(object) - + + # Ready for deployment once code is ready + ''' + widgetLink = Signal(object) + widgetTable = Signal(object) + ''' # Recieves any widget model, and the section model to add the instance of DraggableContainer to widgetShouldLoad = Signal(object, object) diff --git a/Modules/Screensnip.py b/Modules/Screensnip.py index 4aed07c..9df1c83 100644 --- a/Modules/Screensnip.py +++ b/Modules/Screensnip.py @@ -16,7 +16,7 @@ def __init__(self): if platform == "linux": self.setWindowFlags(Qt.FramelessWindowHint) - self.setAttributes(Qt.WA_TranslucentBackground) + self.setAttribute(Qt.WA_TranslucentBackground) self.setWindowFlags(Qt.WindowStaysOnTopHint) self.parent = None @@ -40,7 +40,8 @@ def start(self, event_pos): def paintEvent(self, event): if SnippingWidget.is_snipping: - brush_color = (128, 128, 255, 100) + #brush_color = (128, 128, 255, 100) + brush_color = (0, 0, 0, 0) lw = 3 opacity = 0.3 @@ -71,10 +72,11 @@ def mouseMoveEvent(self, event): def mouseReleaseEvent(self, event): SnippingWidget.is_snipping = False QApplication.restoreOverrideCursor() - x1 = min(self.begin.x(), self.end.x()) - y1 = min(self.begin.y(), self.end.y()) - x2 = max(self.begin.x(), self.end.x()) - y2 = max(self.begin.y(), self.end.y()) + rect = self.geometry() + x1 = min(self.begin.x(), self.end.x()) + rect.left() + y1 = min(self.begin.y(), self.end.y()) + rect.top() + x2 = max(self.begin.x(), self.end.x()) + rect.left() + y2 = max(self.begin.y(), self.end.y()) + rect.top() self.repaint() QApplication.processEvents() @@ -83,7 +85,7 @@ def mouseReleaseEvent(self, event): if platform == "darwin": img = ImageGrab.grab(bbox=( (x1 ) * 2, (y1 + 55 ) * 2, (x2 ) * 2, (y2 + 55) * 2)) else: - img = ImageGrab.grab(bbox=(x1 + 10, y1 + 30, x2 + 10, y2 + 40)) + img = ImageGrab.grab(bbox=(x1 + 2, y1 + 2, x2 - 1, y2 - 1)) except Exception as e: print(f"Error grabbing screenshot: {e}") img = None diff --git a/Widgets/Image.py b/Widgets/Image.py index beeb6c5..bc45a09 100644 --- a/Widgets/Image.py +++ b/Widgets/Image.py @@ -19,7 +19,7 @@ def __init__(self, x, y, w, h, image_matrix): bytes_per_line = 3 * matrix_width q_image = QImage(image_matrix.data, matrix_width, matrix_height, bytes_per_line, QImage.Format_BGR888) self.q_pixmap = QPixmap(q_image) - self.setPixmap(self.q_pixmap.scaled(w, h, Qt.KeepAspectRatio, Qt.SmoothTransformation)) # Scale to widget geometry + self.setPixmap(self.q_pixmap.scaled(w, h, Qt.IgnoreAspectRatio, Qt.SmoothTransformation)) # Scale to widget geometry self.setGeometry(x, y, w, h) # this should get fixed self.persistantGeometry = self.geometry() @@ -29,7 +29,7 @@ def newGeometryEvent(self, newGeometry): new_w = newGeometry.width() new_h = newGeometry.height() if (self.w != new_w) or (self.h != new_h): # Not exactly sure how object's width and height attribute gets updated but this works - self.setPixmap(self.q_pixmap.scaled(new_w, new_h, Qt.KeepAspectRatio, Qt.SmoothTransformation)) + self.setPixmap(self.q_pixmap.scaled(new_w, new_h, Qt.IgnoreAspectRatio, Qt.SmoothTransformation)) pixmap_rect = self.pixmap().rect() w = pixmap_rect.width() @@ -83,20 +83,26 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): toolbarBottom.setIconSize(QSize(16, 16)) toolbarBottom.setMovable(False) - #crop = build_action(toolbarTop, 'assets/icons/svg_crop', "Crop", "Crop", False) + #crop = build_action(toolbarTop, './Assets/icons/svg_crop', "Crop", "Crop", False) - flipHorizontal = build_action(toolbarBottom, 'assets/icons/svg_flip_horizontal', "Horizontal Flip", "Horizontal Flip", False) + flipHorizontal = build_action(toolbarBottom, './Assets/icons/svg_flip_horizontal', "Horizontal Flip", "Horizontal Flip", False) flipHorizontal.triggered.connect(self.flipHorizontal) - flipVertical = build_action(toolbarBottom, 'assets/icons/svg_flip_vertical', "Vertical Flip", "Vertical Flip", False) + flipVertical = build_action(toolbarBottom, './Assets/icons/svg_flip_vertical', "Vertical Flip", "Vertical Flip", False) flipVertical.triggered.connect(self.flipVertical) - rotateLeftAction = build_action(toolbarBottom, 'assets/icons/svg_rotate_left', "Rotate 90 degrees Left", "Rotate 90 degrees Left", False) + rotateLeftAction = build_action(toolbarBottom, './Assets/icons/svg_rotate_left', "Rotate 90 degrees Left", "Rotate 90 degrees Left", False) rotateLeftAction.triggered.connect(self.rotate90Left) - rotateRightAction = build_action(toolbarBottom, 'assets/icons/svg_rotate_right', "Rotate 90 degrees Right", "Rotate 90 degrees Right", False) + rotateRightAction = build_action(toolbarBottom, './Assets/icons/svg_rotate_right', "Rotate 90 degrees Right", "Rotate 90 degrees Right", False) + rotateRightAction.triggered.connect(self.rotate90Right) + shrinkImageAction = build_action(toolbarBottom, 'Assets/icons/svg_shrink', "Rotate 90 degrees Right", "Rotate 90 degrees Right", False) + shrinkImageAction.triggered.connect(self.shrinkImage) + expandImageAction = build_action(toolbarBottom, 'Assets/icons/svg_expand', "Rotate 90 degrees Right", "Rotate 90 degrees Right", False) + expandImageAction.triggered.connect(self.expandImage) + - toolbarBottom.addActions([rotateLeftAction, rotateRightAction, flipHorizontal, flipVertical]) + toolbarBottom.addActions([rotateLeftAction, rotateRightAction, flipHorizontal, flipVertical, shrinkImageAction, expandImageAction]) qwaBottom = QWidgetAction(self) qwaBottom.setDefaultWidget(toolbarBottom) @@ -105,23 +111,82 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): def flipVertical(self): # Flip the image matrix vertically using OpenCV + parent_widget = self.parentWidget() + if parent_widget: + newX, newY = parent_widget.x(), parent_widget.y() + new_width, new_height = parent_widget.height(), parent_widget.width() + parent_widget.setGeometry(newX, newY, new_width, new_height) + self.image_matrix = cv2.flip(self.image_matrix, 0) self.updatePixmap() + def flipHorizontal(self): # Flip the image matrix horizontally using OpenCV + + parent_widget = self.parentWidget() + if parent_widget: + newX, newY = parent_widget.x(), parent_widget.y() + new_width, new_height = parent_widget.height(), parent_widget.width() + parent_widget.setGeometry(newX, newY, new_width, new_height) + self.image_matrix = cv2.flip(self.image_matrix, 1) self.updatePixmap() + def rotate90Left(self): # Rotate the image matrix 90 degrees to the left using OpenCV + self.w, self.h = self.h, self.w + + parent_widget = self.parentWidget() + if parent_widget: + newX, newY = parent_widget.x(), parent_widget.y() + new_width, new_height = parent_widget.height(), parent_widget.width() + parent_widget.setGeometry(newX, newY, new_width, new_height) self.image_matrix = cv2.rotate(self.image_matrix, cv2.ROTATE_90_COUNTERCLOCKWISE) + self.updatePixmap() def rotate90Right(self): # Rotate the image matrix 90 degrees to the right using OpenCV + self.w, self.h = self.h, self.w + + # Access parent and update geometry + parent_widget = self.parentWidget() + if parent_widget: + newX, newY = parent_widget.x(), parent_widget.y() + new_width, new_height = parent_widget.height(), parent_widget.width() + parent_widget.setGeometry(newX, newY, new_width, new_height) + self.image_matrix = cv2.rotate(self.image_matrix, cv2.ROTATE_90_CLOCKWISE) self.updatePixmap() + def shrinkImage(self): + # Decrease image size by 10% + self.w = int(self.w * 0.9) + self.h = int(self.h * 0.9) + parent_widget = self.parentWidget() + if parent_widget: + newX, newY = parent_widget.x(), parent_widget.y() + new_width, new_height = self.w, self.h + parent_widget.setGeometry(newX, newY, new_width, new_height) + self.updateImageSize() + + def expandImage(self): + # Increase image size by 10% + self.w = int(self.w * 1.1) + self.h = int(self.h * 1.1) + parent_widget = self.parentWidget() + if parent_widget: + newX, newY = parent_widget.x(), parent_widget.y() + new_width, new_height = self.w, self.h + parent_widget.setGeometry(newX, newY, new_width, new_height) + self.updateImageSize() + + def updateImageSize(self): + # Update the displayed pixmap with the new size + self.setPixmap(self.q_pixmap.scaled(self.w, self.h, Qt.KeepAspectRatio, Qt.SmoothTransformation)) + + def updatePixmap(self): # Update the QImage and QPixmap matrix_height, matrix_width, _ = self.image_matrix.shape @@ -130,4 +195,4 @@ def updatePixmap(self): self.q_pixmap = QPixmap(q_image) # Update the displayed pixmap - self.setPixmap(self.q_pixmap.scaled(self.w, self.h, Qt.KeepAspectRatio, Qt.SmoothTransformation)) \ No newline at end of file + self.setPixmap(self.q_pixmap.scaled(self.w, self.h, Qt.KeepAspectRatio, Qt.SmoothTransformation)) diff --git a/Widgets/Textbox.py b/Widgets/Textbox.py index 0bd4b8f..44488d6 100644 --- a/Widgets/Textbox.py +++ b/Widgets/Textbox.py @@ -94,14 +94,15 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): return action toolbarTop = QToolBar() - toolbarTop.setIconSize(QSize(25, 25)) + toolbarTop.setIconSize(QSize(16, 16)) toolbarTop.setMovable(False) toolbarBottom = QToolBar() - toolbarBottom.setIconSize(QSize(25, 25)) + toolbarBottom.setIconSize(QSize(16, 16)) toolbarBottom.setMovable(False) font = QFontComboBox() + font.setFixedWidth(150) font.currentFontChanged.connect( lambda x: self.setCurrentFontCustom( font.currentFont() if x else self.currentFont() @@ -115,47 +116,29 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): FONT_SIZES[x] if x else self.fontPointSize() ) ) - - align_left = build_action( - toolbarBottom, - "assets/icons/svg_align_left", - "Align Left", - "Align Left", - True, - ) + + align_left = build_action(toolbarBottom, "./Assets/icons/svg_align_left", "Align Left", "Align Left", False) align_left.triggered.connect(lambda x: self.setAlignment(Qt.AlignLeft)) - align_center = build_action( - toolbarBottom, - "assets/icons/svg_align_center", - "Align Center", - "Align Center", - True, - ) + align_center = build_action(toolbarBottom, "./Assets/icons/svg_align_center", "Align Center", "Align Center", False) align_center.triggered.connect(lambda x: self.setAlignment(Qt.AlignCenter)) - align_right = build_action( - toolbarBottom, - "assets/icons/svg_align_right", - "Align Right", - "Align Right", - True, - ) + align_right = build_action(toolbarBottom, "./Assets/icons/svg_align_right", "Align Right", "Align Right", False) align_right.triggered.connect(lambda x: self.setAlignment(Qt.AlignRight)) bold = build_action( - toolbarBottom, "assets/icons/svg_font_bold", "Bold", "Bold", True + toolbarBottom, "./Assets/icons/svg_font_bold", "Bold", "Bold", True ) bold.toggled.connect(lambda x: self.setFontWeightCustom(700 if x else 500)) italic = build_action( - toolbarBottom, "assets/icons/svg_font_italic", "Italic", "Italic", True + toolbarBottom, "./Assets/icons/svg_font_italic", "Italic", "Italic", True ) italic.toggled.connect(lambda x: self.setFontItalicCustom(True if x else False)) underline = build_action( toolbarBottom, - "assets/icons/svg_font_underline", + "./Assets/icons/svg_font_underline", "Underline", "Underline", True, @@ -166,7 +149,7 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): fontColor = build_action( toolbarBottom, - "assets/icons/svg_font_color", + "./Assets/icons/svg_font_color", "Font Color", "Font Color", False, @@ -177,7 +160,7 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): bgColor = build_action( toolbarBottom, - "assets/icons/svg_font_bucket", + "./Assets/icons/svg_font_bucket", "Background Color", "Background Color", False, @@ -186,65 +169,68 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): bgColor.triggered.connect( lambda: self.changeBackgroundColorEvent(QColorDialog.getColor()) ) - textboxColor = build_action( + textHighlightColor = build_action( toolbarBottom, - "assets/icons/svg_textboxColor", - "Background Color", - "Background Color", + "./Assets/icons/svg_textHighlightColor", + "Text Highlight Color", + "Text Highlight Color", False, ) - textboxColor.triggered.connect( - lambda: self.changeTextboxColorEvent(QColorDialog.getColor()) + textHighlightColor.triggered.connect( + lambda: self.changeTextHighlightColorEvent(QColorDialog.getColor()) ) bullets = build_action( - toolbarBottom, "assets/icons/svg_bullets", "Bullets", "Bullets", True + toolbarBottom, "./Assets/icons/svg_bullets", "Bullets", "Bullets", True ) bullets.toggled.connect(lambda: self.bullet_list("bulletReg")) - bullets_num = build_action( - toolbarBottom, - "assets/icons/svg_bullet_number", - "Bullets Num", - "Bullets Num", - True, - ) - bullets_num.toggled.connect(lambda: self.bullet_list("bulletNum")) - - toolbarTop.addWidget(font) toolbarTop.addWidget(size) toolbarBottom.addActions( - [ - align_left, - align_center, - align_right, + [ bold, italic, underline, - fontColor, - bgColor, - bullets, - bullets_num, - ] + textHighlightColor, + fontColor, + bullets + ] ) - - menu = QMenu(self) - bulletUpperA = menu.addAction(QIcon("assets/icons/svg_bulletUA"), "") - bulletUpperR = menu.addAction(QIcon("assets/icons/svg_bulletUR"), "") - + + # numbering menu has to be added inbetween + numbering_menu = QMenu(self) + bullets_num = numbering_menu.addAction(QIcon("./Assets/icons/svg_bullet_number"), "") + bulletUpperA = numbering_menu.addAction(QIcon("./Assets/icons/svg_bulletUA"), "") + bulletUpperR = numbering_menu.addAction(QIcon("./Assets/icons/svg_bulletUR"), "") + + bullets_num.triggered.connect(lambda: self.bullet_list("bulletNum")) bulletUpperA.triggered.connect(lambda: self.bullet_list("bulletUpperA")) bulletUpperR.triggered.connect(lambda: self.bullet_list("bulletUpperR")) - menu_button = QToolButton(self) - menu_button.setPopupMode(QToolButton.InstantPopup) - menu_button.setIcon(QIcon("assets/icons/svg_bullets")) - menu_button.setMenu(menu) - - toolbarBottom.addWidget(menu_button) + numbering = QToolButton(self) + numbering.setIcon(QIcon("./Assets/icons/svg_bullet_number")) + numbering.setPopupMode(QToolButton.MenuButtonPopup) + numbering.setMenu(numbering_menu) + + # This code would fix an error on the command line but it also makes it not look good soooo + numbering.setParent(numbering_menu) + + toolbarBottom.addWidget(numbering) + # not required for right-click menu as they arent originally present in OneNote + ''' + toolbarBottom.addActions( + [ + bgColor, + align_left, + align_center, + align_right + ] + ) + ''' qwaTop = QWidgetAction(self) qwaTop.setDefaultWidget(toolbarTop) qwaBottom = QWidgetAction(self) @@ -414,6 +400,21 @@ def bullet_list(self, bulletType): self.setTextCursor(cursor) self.setFocus() + def changeAlignmentEvent(self, alignmentType): + print("Alignment Event Called") + cursor = self.textCursor() + blockFormat = cursor.blockFormat() + + if alignmentType == "alignLeft": + blockFormat.setAlignment(Qt.AlignLeft) + elif alignmentType == "alignCenter": + blockFormat.setAlignment(Qt.AlignCenter) + elif alignmentType == "alignRight": + blockFormat.setAlignment(Qt.AlignRight) + + cursor.setBlockFormat(blockFormat) + self.setTextCursor(cursor) + self.setFocus() def handleTabKey(self): cursor = self.textCursor() @@ -530,7 +531,8 @@ def changeFontColorEvent(self, new_font_color): current_format = cursor.charFormat() color = QColor(new_font_color) - current_format.setForeground(color) + if color.isValid(): + current_format.setForeground(color) cursor.setCharFormat(current_format) @@ -551,12 +553,13 @@ def changeBackgroundColorEvent(self, color: QColor or int, g: int = None, b: int self.deselectText() # Changes textbox background color - def changeTextboxColorEvent(self, new_bg_color): + def changeTextHighlightColorEvent(self, new_highlight_color): cursor = self.textCursor() current_format = cursor.charFormat() - color = QColor(new_bg_color) - current_format.setBackground(color) + color = QColor(new_highlight_color) + if color.isValid(): + current_format.setBackground(color) cursor.setCharFormat(current_format) # self.deselectText() diff --git a/requirements.txt b/requirements.txt index fbba2f8..8c8e968 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,3 +5,4 @@ PySide6>=6.5.0 PySide6-Addons>=6.5.0 PySide6-Essentials>=6.5.0 shiboken6>=6.5.0 +libxcb-cursor0>= 0.1.0 From 4e6b1690cf6148110001550fddb48e6ec37f2044 Mon Sep 17 00:00:00 2001 From: Jettorix <109848112+Jettorix@users.noreply.github.com> Date: Sat, 17 Feb 2024 10:21:16 -0600 Subject: [PATCH 091/127] Changed dropdown to medium gray, few minor style changes --- Styles/styles.qss | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Styles/styles.qss b/Styles/styles.qss index 247ef03..8ebd0b1 100644 --- a/Styles/styles.qss +++ b/Styles/styles.qss @@ -71,3 +71,8 @@ QPushButton#addPage { QPushButton#addPage::hover { background-color: #cecece; } + +QToolBar { + background-color: #808080; /* This sets the background to medium gray */ + +} From f27d1d341271ddab80212683896133e9446ed680 Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Tue, 20 Feb 2024 14:15:16 -0600 Subject: [PATCH 092/127] Update Minor update from main --- Models/DraggableContainer.py | 2 +- Modules/BuildUI.py | 4 ++-- Widgets/Image.py | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Models/DraggableContainer.py b/Models/DraggableContainer.py index 0396347..a79f505 100644 --- a/Models/DraggableContainer.py +++ b/Models/DraggableContainer.py @@ -342,7 +342,7 @@ def widgetAttributeChanged(self, changedWidgetAttribute, value): elif hasattr(child_widget, "deselectText") and (changedWidgetAttribute == ChangedWidgetAttribute.LoseFocus): print("Clear Selection Slot Called") child_widget.deselectText() - if hasattr(self.childWidget, "checkEmpty") and isinstance(child_widget, QTextEdit): + if hasattr(self.childWidget, "checkEmpty") and isinstance(child_widget, QTextBrowser): if self.childWidget.checkEmpty(): print("Removing empty container") editorSignalsInstance.widgetRemoved.emit(self) diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index 1e4c6f3..56ff800 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -119,8 +119,8 @@ def build_menubar(editor): def set_toolbar_visibility(editor): toolbar = editor.findChild(QToolBar) if toolbar: - print("toolbar visibility change") - toolbar.setVisible(not toolbar.isVisible()) + print("toolbar visibility change") + toolbar.setVisible(not toolbar.isVisible()) def build_toolbar(editor): toolbar = QToolBar() diff --git a/Widgets/Image.py b/Widgets/Image.py index bc45a09..e0505fb 100644 --- a/Widgets/Image.py +++ b/Widgets/Image.py @@ -96,9 +96,9 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): rotateRightAction.triggered.connect(self.rotate90Right) - shrinkImageAction = build_action(toolbarBottom, 'Assets/icons/svg_shrink', "Rotate 90 degrees Right", "Rotate 90 degrees Right", False) + shrinkImageAction = build_action(toolbarBottom, 'Assets/icons/svg_shrink', "Shrink", "Shrink", False) shrinkImageAction.triggered.connect(self.shrinkImage) - expandImageAction = build_action(toolbarBottom, 'Assets/icons/svg_expand', "Rotate 90 degrees Right", "Rotate 90 degrees Right", False) + expandImageAction = build_action(toolbarBottom, 'Assets/icons/svg_expand', "Expand", "Expand", False) expandImageAction.triggered.connect(self.expandImage) From 1ce39012f5390b45f0bb9e7965e090f38977b5da Mon Sep 17 00:00:00 2001 From: ldeltastreaml <70774713+ldeltastreaml@users.noreply.github.com> Date: Thu, 22 Feb 2024 09:23:28 -0600 Subject: [PATCH 093/127] Big Luis Upload - added svgs for bullet_number, insert_space, pictures, and screensnip - reorganized DraggableContainer.py - Renamed toolbar to homeToolbar and added a toolbar for the new insertToolbar and drawToolbar - removed unnecessary commented out code (it was mine) - Edited styles.qss to make the window look more akin to One Note - reorganized EditorFrameView and added new def toolbar_table and toolbar_pictures - commented out menu code for image.py (not necessary and it was moved to a different location) - commented out menu code for table.py (not necessary and it was moved to a different location) - set length of font size combo box in textbox.py --- Assets/icons/svg_bullet_number.svg | 8 +- Assets/icons/svg_insert_space.svg | 17 +++ Assets/icons/svg_pictures.svg | 6 + Assets/icons/svg_screensnip.svg | 8 ++ Models/DraggableContainer.py | 117 +++++++++++++++--- Modules/BuildUI.py | 183 +++++++++++++++++++++-------- Modules/Clipboard.py | 2 +- Modules/EditorSignals.py | 5 - Styles/styles.qss | 22 ++-- Views/EditorFrameView.py | 65 +++++++--- Widgets/Image.py | 6 +- Widgets/Table.py | 9 +- Widgets/Textbox.py | 1 + 13 files changed, 344 insertions(+), 105 deletions(-) create mode 100644 Assets/icons/svg_insert_space.svg create mode 100644 Assets/icons/svg_pictures.svg create mode 100644 Assets/icons/svg_screensnip.svg diff --git a/Assets/icons/svg_bullet_number.svg b/Assets/icons/svg_bullet_number.svg index 610e2f1..ab2ddca 100644 --- a/Assets/icons/svg_bullet_number.svg +++ b/Assets/icons/svg_bullet_number.svg @@ -1,6 +1,4 @@ - - - number-list-line - - + + + \ No newline at end of file diff --git a/Assets/icons/svg_insert_space.svg b/Assets/icons/svg_insert_space.svg new file mode 100644 index 0000000..455ddfe --- /dev/null +++ b/Assets/icons/svg_insert_space.svg @@ -0,0 +1,17 @@ + + + + + \ No newline at end of file diff --git a/Assets/icons/svg_pictures.svg b/Assets/icons/svg_pictures.svg new file mode 100644 index 0000000..c51204f --- /dev/null +++ b/Assets/icons/svg_pictures.svg @@ -0,0 +1,6 @@ + + + +picture + + \ No newline at end of file diff --git a/Assets/icons/svg_screensnip.svg b/Assets/icons/svg_screensnip.svg new file mode 100644 index 0000000..4584889 --- /dev/null +++ b/Assets/icons/svg_screensnip.svg @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/Models/DraggableContainer.py b/Models/DraggableContainer.py index 0e5760d..f7a159e 100644 --- a/Models/DraggableContainer.py +++ b/Models/DraggableContainer.py @@ -68,7 +68,7 @@ def setChildWidget(self, childWidget): def eventFilter(self, obj, e): - # If child widget resized itsself, resize this drag container, not ideal bc child resizes on hover + # If child widget resized itself, resize this drag container, not ideal bc child resizes on hover if isinstance(e, QResizeEvent): self.resize(self.childWidget.size()) return False @@ -78,7 +78,7 @@ def popupShow(self, pt: QPoint): self.m_showMenu = True self.menu.exec(global_) self.m_showMenu = False - + def mousePressEvent(self, e: QMouseEvent): self.position = QPoint(e.globalX() - self.geometry().x(), e.globalY() - self.geometry().y()) @@ -151,27 +151,105 @@ def buildDragContainerMenu(self): menu.addAction(item) # Add standard menu actions - cut = QAction("Cut", self) + cut = QAction("Cu&t", self) cut.triggered.connect(lambda: editorSignalsInstance.widgetCut.emit(self)) - copy = QAction("Copy", self) + copy = QAction("&Copy", self) copy.triggered.connect(lambda: editorSignalsInstance.widgetCopied.emit(self)) - delete = QAction("Delete", self) + paste = QAction("&Paste", self) + paste.triggered.connect(lambda: self.pasteWidget(event.pos())) + + delete = QAction("&Delete", self) delete.triggered.connect(lambda: editorSignalsInstance.widgetRemoved.emit(self)) - # Ready for deployment when code is ready - ''' - link = QAction("Link", self) - link.triggered.connect(lambda: editorSignalsInstance.widgetLink.emit(self)) + menu.addActions([cut, copy, paste, delete]) + + menu.addSeparator() + + link = QAction("&Link", self) + # link.triggered.connect(lambda: self.insertLink(event.pos())) + + menu.addAction(link) + + menu.addSeparator() - table = QAction("Table", self) - table.triggered.connect(lambda: editorSignalsInstance.widgetTable.emit(self)) + orderMenu = QMenu("&Order", self) - menu.addActions([cut, copy, delete, link, table]) - ''' + bringForwards = QAction("Bring &Forwards", self) + bringForwards.triggered.connect(self.childWidget.raise_()) - menu.addActions([cut, copy, delete]) + orderMenu.addAction(bringForwards) + + menu.addMenu(orderMenu) + + # text boxes + if isinstance(self.childWidget, QTextBrowser): + table = QAction("&Table", self) + # table.triggered.connect(lambda: self.newWidgetOnSection(TableWidget, event.pos())) + + menu.addAction(table) + + menu.addSeparator() + + # images + elif isinstance(self.childWidget, QLabel): + # Create submenus for rotate and resize + rotateMenu = QMenu("R&otate", self) + rotateMenu.setStyleSheet("font-size: 11pt;") + + resizeMenu = QMenu("&Resize", self) + resizeMenu.setStyleSheet("font-size: 11pt;") + + # Create actions for rotate submenu + rotateRightAction = QAction("Rotate &Right 90°", self) + rotateRightAction.triggered.connect(self.childWidget.rotate90Right) + rotateRightAction.setIcon(QIcon('./Assets/icons/svg_rotate_right')) + + rotateLeftAction = QAction("Rotate &Left 90°", self) + rotateLeftAction.triggered.connect(self.childWidget.rotate90Left) + rotateLeftAction.setIcon(QIcon('./Assets/icons/svg_rotate_left')) + + flipHorizontal = QAction("Flip &Horizontal", self) + flipHorizontal.triggered.connect(self.childWidget.flipHorizontal) + flipHorizontal.setIcon(QIcon('./Assets/icons/svg_flip_horizontal')) + + flipVertical = QAction("Flip &Vertical", self) + flipVertical.triggered.connect(self.childWidget.flipVertical) + flipVertical.setIcon(QIcon('./Assets/icons/svg_flip_vertical')) + + # Add actions to rotate submenu + rotateMenu.addActions([rotateLeftAction, rotateRightAction, flipHorizontal, flipVertical]) + + # Create actions for resize submenu + shrinkImageAction = QAction("&Shrink Image", self) + shrinkImageAction.triggered.connect(self.childWidget.shrinkImage) + shrinkImageAction.setIcon(QIcon('./Assets/icons/svg_shrink')) + + expandImageAction = QAction("&Expand Image", self) + expandImageAction.triggered.connect(self.childWidget.expandImage) + expandImageAction.setIcon(QIcon('./Assets/icons/svg_expand')) + + # Add actions to resize submenu + resizeMenu.addActions([shrinkImageAction, expandImageAction]) + + # Add submenus to the main menu + menu.addMenu(rotateMenu) + menu.addMenu(resizeMenu) + + # tables + elif isinstance(self.childWidget, QWidget): + tableMenu = QMenu("&Table", self) + tableMenu.setStyleSheet("font-size: 11pt;") + + addRow = QAction("Add Row", self) + addRow.triggered.connect(self.childWidget.addRow) + + addCol = QAction("Add Column", self) + addCol.triggered.connect(self.childWidget.addCol) + + tableMenu.addActions([addRow, addCol]) + menu.addMenu(tableMenu) # Add any non-widget type menu actions from child for item in customMenuItems: @@ -383,9 +461,20 @@ def widgetAttributeChanged(self, changedWidgetAttribute, value): elif hasattr(child_widget, "changeBackgroundColorEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.BackgroundColor): print("Chang Background Color Event Called") child_widget.changeBackgroundColorEvent(value) + def connectTableSignals(self, tableWidget): tableWidget.rowAdded.connect(self.resizeTable) def resizeTable(self): self.resize(self.childWidget.size()) self.newGeometry.emit(self.geometry()) self.parentWidget().repaint() + + def pasteWidget(self, clickPos): + widgetOnClipboard = self.clipboard.getWidgetToPaste() + + dc = DraggableContainer(widgetOnClipboard, self) + self.undoHandler.pushCreate(dc) + editorSignalsInstance.widgetAdded.emit(dc) # Notify section that widget was added + editorSignalsInstance.changeMade.emit() + dc.move(clickPos.x(), clickPos.y()) + dc.show() diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index bd088f0..3607b37 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -19,7 +19,6 @@ #builds the application's UI def build_ui(editor): print("Building UI...") - #editor.EditorFrameView = EditorFrameView(editor) #editor.statusBar = editor.statusBar() @@ -78,6 +77,8 @@ def build_window(editor): editor.setWindowTitle("OpenNote") editor.setWindowIcon(QIcon('./Assets/OpenNoteLogo.png')) editor.setAcceptDrops(True) + # for when we make custom titlebar + # editor.setWindowFlags(Qt.FramelessWindowHint) with open('./Styles/styles.qss',"r") as fh: editor.setStyleSheet(fh.read()) @@ -85,6 +86,7 @@ def build_menubar(editor): file = editor.menuBar().addMenu('&File') home = editor.menuBar().addMenu('&Home') insert = editor.menuBar().addMenu('&Insert') + draw = editor.menuBar().addMenu('&Draw') plugins = editor.menuBar().addMenu('&Plugins') new_file = build_action(editor, './Assets/icons/svg_file_open', 'New Notebook', 'New Notebook', False) @@ -104,44 +106,57 @@ def build_menubar(editor): save_fileAs.triggered.connect(lambda: saveAs(editor)) toggle_home_toolbar = build_action(editor, '', 'Toggle Home Toolbar', 'Toggle Home Toolbar', False) - toggle_home_toolbar.triggered.connect(lambda: set_toolbar_visibility(editor)) + toggle_home_toolbar.triggered.connect(lambda: set_toolbar_visibility(editor, 'homeToolbar')) toggle_insert_toolbar = build_action(editor, '', 'Toggle Insert Toolbar', 'Toggle Insert Toolbar', False) - #toggle_insert_toolbar.triggered.connect(lambda: set_toolbar_visibility(insert)) + toggle_insert_toolbar.triggered.connect(lambda: set_toolbar_visibility(editor, 'insertToolbar')) + + toggle_draw_toolbar = build_action(editor, '', 'Toggle Draw Toolbar', 'Toggle Draw Toolbar', False) + toggle_draw_toolbar.triggered.connect(lambda: set_toolbar_visibility(editor, 'drawToolbar')) add_widget = build_action(editor, './Assets/icons/svg_question', 'Add Custom Widget', 'Add Custom Widget', False) file.addActions([new_file, open_file, save_file, save_fileAs]) + home.addActions([toggle_home_toolbar]) + insert.addActions([toggle_insert_toolbar]) + + draw.addActions([toggle_draw_toolbar]) + plugins.addActions([add_widget]) -def set_toolbar_visibility(editor): - toolbar = editor.findChild(QToolBar) - if toolbar: - print("toolbar visibility change") - toolbar.setVisible(not toolbar.isVisible()) +def set_toolbar_visibility(editor, triggered_toolbar): + # Find all toolbars in the editor + toolbars = editor.findChildren(QToolBar) + + # Iterate over each toolbar + for toolbar in toolbars: + if toolbar.objectName() == triggered_toolbar: + # Toggle the visibility of the triggered toolbar + print(toolbar.objectName(),"visibility change") + toolbar.setVisible(not toolbar.isVisible()) + else: + # Hide all other toolbars + toolbar.setVisible(False) def build_toolbar(editor): - toolbar = QToolBar() - toolbar.setIconSize(QSize(16, 16)) - toolbar.setMovable(False) - editor.addToolBar(Qt.ToolBarArea.TopToolBarArea, toolbar) + # homeToolbar code + homeToolbar = QToolBar() + homeToolbar.setObjectName('homeToolbar') + homeToolbar.setIconSize(QSize(16, 16)) + homeToolbar.setMovable(False) + homeToolbar.setStyleSheet('font-size: 10pt;') + editor.addToolBar(Qt.ToolBarArea.TopToolBarArea, homeToolbar) #separates toolbar with a line break spacer = QWidget() spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) - undo = build_action(toolbar, './Assets/icons/svg_undo', "undo", "undo", False) - undo.triggered.connect(editor.frameView.triggerUndo) - - redo = build_action(toolbar, './Assets/icons/svg_redo', "redo", "redo", False) - # redo.triggered.connect(editor.frameView.triggerRedo) - - cut = build_action(toolbar, './Assets/icons/svg_cut', "cut", "cut", False) + cut = build_action(homeToolbar, './Assets/icons/svg_cut', "cut", "cut", False) cut.triggered.connect(editor.frameView.cutWidgetEvent) - copy = build_action(toolbar, './Assets/icons/svg_copy', "copy", "copy", False) + copy = build_action(homeToolbar, './Assets/icons/svg_copy', "copy", "copy", False) copy.triggered.connect(editor.frameView.copyWidgetEvent) @@ -152,8 +167,10 @@ def build_toolbar(editor): font_family.currentFontChanged.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Font, font_family.currentFont().family())) font_size = QComboBox() + font_size.setFixedWidth(50) font_size.addItems([str(fs) for fs in FONT_SIZES]) - default_font_size_index = 8 #default text size is 18 + # default text size is 11 + default_font_size_index = 4 font_size.setCurrentIndex(default_font_size_index) font_size.currentIndexChanged.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontSize, int(font_size.currentText()))) @@ -161,49 +178,42 @@ def build_toolbar(editor): # - Alternates between working and not working # - Textboxes do not remember settings like if font is toggled or current font size - bgColor = build_action(toolbar, './Assets/icons/svg_font_bucket', "Background Color", "Background Color", False) + bgColor = build_action(homeToolbar, './Assets/icons/svg_font_bucket', "Background Color", "Background Color", False) #bgColor.triggered.connect(lambda: openGetColorDialog(purpose = "background")) #current bug, alternates between activating and not working when using bgColor.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.BackgroundColor, QColorDialog.getColor())) - textHighlightColor = build_action(toolbar, './Assets/icons/svg_textHighlightColor', "Text Highlight Color", "Text Highlight Color", True) + textHighlightColor = build_action(homeToolbar, './Assets/icons/svg_textHighlightColor', "Text Highlight Color", "Text Highlight Color", True) textHighlightColor.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.TextHighlightColor, QColorDialog.getColor())) #defines font color icon appearance and settings - fontColor = build_action(toolbar, './Assets/icons/svg_font_color', "Font Color", "Font Color", False) + fontColor = build_action(homeToolbar, './Assets/icons/svg_font_color', "Font Color", "Font Color", False) fontColor.triggered.connect(lambda: openGetColorDialog(purpose = "font")) - bold = build_action(toolbar, './Assets/icons/bold', "Bold", "Bold", True) + bold = build_action(homeToolbar, './Assets/icons/bold', "Bold", "Bold", True) bold.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontBold, None)) - italic = build_action(toolbar, './Assets/icons/italic.svg', "Italic", "Italic", True) + italic = build_action(homeToolbar, './Assets/icons/italic.svg', "Italic", "Italic", True) italic.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontItalic, None)) - underline = build_action(toolbar, './Assets/icons/underline.svg', "Underline", "Underline", True) + underline = build_action(homeToolbar, './Assets/icons/underline.svg', "Underline", "Underline", True) underline.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontUnderline, None)) - - table = build_action(toolbar, './Assets/icons/svg_table', "Create Table", "Create Table", False) - table.triggered.connect(editor.frameView.toolbar_table) - - hyperlink = build_action(toolbar, './Assets/icons/svg_hyperlink', "Hyperlink", "Hyperlink", False) - hyperlink.triggered.connect(editor.frameView.toolbar_hyperlink) # Bullets with placeholder for more bullet options - bullet = build_action(toolbar, './Assets/icons/svg_bullets', "Bullets", "Bullets", False) + bullet = build_action(homeToolbar, './Assets/icons/svg_bullets', "Bullets", "Bullets", False) bullet.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Bullet, None)) - - toolbar.addActions([undo, redo, cut, copy]) + homeToolbar.addActions([cut, copy]) - toolbar.addSeparator() + homeToolbar.addSeparator() - toolbar.addWidget(font_family) - toolbar.addWidget(font_size) + homeToolbar.addWidget(font_family) + homeToolbar.addWidget(font_size) - toolbar.addSeparator() + homeToolbar.addSeparator() - toolbar.addActions([bold, italic, underline, fontColor, textHighlightColor, bgColor, bullet]) + homeToolbar.addActions([bold, italic, underline, fontColor, textHighlightColor, bgColor, bullet]) # numbering menu start numbering_menu = QMenu(editor) @@ -220,26 +230,89 @@ def build_toolbar(editor): numbering_menu.addActions([bullet_num, bulletUpperA, bulletUpperR]) - # cant directly add numbering menu to toolbar so this is required + # cant directly add numbering menu to homeToolbar so this is required numbering = QToolButton(editor) numbering.setIcon(QIcon('./Assets/icons/svg_bullet_number')) + numbering.setIconSize(QSize(16,16)) numbering.setPopupMode(QToolButton.MenuButtonPopup) numbering.setMenu(numbering_menu) - - toolbar.addWidget(numbering) - - align_left = build_action(toolbar,"./Assets/icons/svg_align_left","Align Left","Align Left",False) + + homeToolbar.addWidget(numbering) + + # QActionGroup used to display that only one can be toggled at a time + align_group = QActionGroup(homeToolbar) + + align_left = build_action(align_group,"./Assets/icons/svg_align_left","Align Left","Align Left", True) align_left.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.AlignLeft, None)) - align_center = build_action(toolbar,"./Assets/icons/svg_align_center","Align Center","Align Center",False) + align_center = build_action(align_group,"./Assets/icons/svg_align_center","Align Center","Align Center", True) align_center.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.AlignCenter, None)) - align_right = build_action(toolbar, "./Assets/icons/svg_align_right", "Align Right", "Align Right", False) + align_right = build_action(align_group, "./Assets/icons/svg_align_right", "Align Right", "Align Right", True) align_right.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.AlignRight, None)) - toolbar.addActions([align_left, align_center, align_right]) + align_group.addAction(align_left) + align_group.addAction(align_center) + align_group.addAction(align_right) + homeToolbar.addActions(align_group.actions()) + + homeToolbar.addSeparator() + - toolbar.addSeparator() + # insertToolbar code + insertToolbar = QToolBar() + insertToolbar.setObjectName('insertToolbar') + insertToolbar.setIconSize(QSize(16,16)) + insertToolbar.setStyleSheet('font-size: 10pt;') + insertToolbar.setMovable(False) + insertToolbar.setVisible(False) + editor.addToolBar(Qt.ToolBarArea.TopToolBarArea, insertToolbar) - toolbar.addActions([table, hyperlink]) + table = build_button(insertToolbar, './Assets/icons/svg_table', " Table ", "Add a Table", False) + table.clicked.connect(editor.frameView.toolbar_table) + + insertSpace = build_button(insertToolbar, './Assets/icons/svg_insert_space', "Insert Space", "Insert Space", False) + + screensnip = build_button(insertToolbar, './Assets/icons/svg_screensnip', " Screensnip ", "Screensnip", False) + screensnip.clicked.connect(editor.frameView.toolbar_snipScreen) + + pictures = build_button(insertToolbar, './Assets/icons/svg_pictures', " Pictures ", "Pictures", False) + pictures.clicked.connect(editor.frameView.toolbar_pictures) + + hyperlink = build_button(insertToolbar, './Assets/icons/svg_hyperlink', " Hyperlink ", "Hyperlink", False) + hyperlink.clicked.connect(editor.frameView.toolbar_hyperlink) + + insertToolbar.addWidget(table) + + insertToolbar.addSeparator() + + insertToolbar.addWidget(insertSpace) + + insertToolbar.addSeparator() + + insertToolbar.addWidget(screensnip) + insertToolbar.addWidget(pictures) + + insertToolbar.addSeparator() + + insertToolbar.addWidget(hyperlink) + insertToolbar.addSeparator() + + # drawToolbar code + drawToolbar = QToolBar() + drawToolbar.setObjectName('drawToolbar') + drawToolbar.setIconSize(QSize(16, 16)) + drawToolbar.setMovable(False) + drawToolbar.setVisible(False) + editor.addToolBar(Qt.ToolBarArea.TopToolBarArea, drawToolbar) + + undo = build_action(drawToolbar, './Assets/icons/svg_undo', "undo", "undo", False) + undo.triggered.connect(editor.frameView.triggerUndo) + + redo = build_action(drawToolbar, './Assets/icons/svg_redo', "redo", "redo", False) + # redo.triggered.connect(editor.frameView.triggerRedo) + + drawToolbar.addActions([undo, redo]) + + drawToolbar.addSeparator() def openGetColorDialog(purpose): color = QColorDialog.getColor() @@ -254,3 +327,11 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): action.setStatusTip(set_status_tip) action.setCheckable(set_checkable) return action + +def build_button(parent, icon_path, text, tooltip, checkable): + button = QPushButton(parent) + button.setIcon(QIcon(icon_path)) + button.setText(text) + button.setToolTip(tooltip) + button.setCheckable(checkable) + return button diff --git a/Modules/Clipboard.py b/Modules/Clipboard.py index e67c7d9..91e2f07 100644 --- a/Modules/Clipboard.py +++ b/Modules/Clipboard.py @@ -9,7 +9,7 @@ def __init__(self): def copyWidgetEvent(self, draggableContainer): widget = draggableContainer.childWidget - + print("copy widget") self.copiedWidgetClass = type(widget) self.copiedWidgetState = widget.__getstate__() diff --git a/Modules/EditorSignals.py b/Modules/EditorSignals.py index 912c6be..1dce1f4 100644 --- a/Modules/EditorSignals.py +++ b/Modules/EditorSignals.py @@ -36,11 +36,6 @@ class EditorSignals(QObject): widgetCopied = Signal(object) widgetCut = Signal(object) - # Ready for deployment once code is ready - ''' - widgetLink = Signal(object) - widgetTable = Signal(object) - ''' # Recieves any widget model, and the section model to add the instance of DraggableContainer to widgetShouldLoad = Signal(object, object) diff --git a/Styles/styles.qss b/Styles/styles.qss index 8ebd0b1..76a3716 100644 --- a/Styles/styles.qss +++ b/Styles/styles.qss @@ -6,8 +6,19 @@ font-size: 16pt; } +QMainWindow { + background-color: rgb(230, 230, 236); +} + QMenuBar { - background-color: rgb(169, 101, 255); + background-color: rgb(119, 25, 170); + padding: 5px, 20px; + font-size: 10pt; + font-color: rgb(255, 255, 255); +} + +QMenuBar::item { + font-size: 10pt; } QMenuBar::item:selected { @@ -15,7 +26,9 @@ QMenuBar::item:selected { } QToolBar { - margin: 10px, 10px, 0, 0; + font-size: 10pt; + padding: 10px, 30px; + background-color: rgb(255, 255, 255); } QComboBox { @@ -71,8 +84,3 @@ QPushButton#addPage { QPushButton#addPage::hover { background-color: #cecece; } - -QToolBar { - background-color: #808080; /* This sets the background to medium gray */ - -} diff --git a/Views/EditorFrameView.py b/Views/EditorFrameView.py index 3ec1fa1..fe40414 100644 --- a/Views/EditorFrameView.py +++ b/Views/EditorFrameView.py @@ -7,18 +7,19 @@ import sys from Modules.Multiselect import Multiselector, MultiselectMode +from Modules.Clipboard import Clipboard +from Modules.EditorSignals import editorSignalsInstance, ChangedWidgetAttribute +from Modules.Undo import UndoHandler +from Modules.Screensnip import SnippingWidget from Models.DraggableContainer import DraggableContainer from Widgets.Textbox import TextboxWidget -from Modules.EditorSignals import editorSignalsInstance,ChangedWidgetAttribute from Widgets.Image import ImageWidget -from Modules.Screensnip import SnippingWidget from Widgets.Table import * -from Modules.Clipboard import Clipboard -from Modules.Undo import UndoHandler from Widgets.Link import LinkDialog + # Handles all widget display (could be called widget view, but so could draggablecontainer) class EditorFrameView(QWidget): @@ -127,6 +128,9 @@ def removeWidgetEvent(self, draggableContainer): def cutWidgetEvent(self, draggableContainer): editorSignalsInstance.widgetCopied.emit(draggableContainer) editorSignalsInstance.widgetRemoved.emit(draggableContainer) + + def copyWidgetEvent(self, draggableContainer): + editorSignalsInstance.widgetCopied.emit(draggableContainer) # Loading a preexisting (saved) widget into the frame inside a DraggableContainer # Then add that DC instance reference to the sectionModel's widgets[] for runtime @@ -174,32 +178,46 @@ def mousePressEvent(self, event): # Open context menu on right click if event.buttons() == Qt.RightButton: frame_menu = QMenu(self) + frame_menu.setStyleSheet("font-size: 11pt;") paste = QAction("Paste", editor) paste.triggered.connect(lambda: self.pasteWidget(event.pos())) - frame_menu.addAction(paste) - - add_image = QAction("Add Image", self) - add_image.triggered.connect(lambda: self.newWidgetOnSection(ImageWidget, event.pos())) - frame_menu.addAction(add_image) + + insert_Link = QAction("Insert Link", editor) + insert_Link.triggered.connect(lambda: self.insertLink(event.pos())) add_table = QAction("Add Table", editor) add_table.triggered.connect(lambda: self.newWidgetOnSection(TableWidget, event.pos())) #add_table.triggered.connect(self.show_table_popup) - frame_menu.addAction(add_table) - + + # not necessary + ''' + add_image = QAction("Add Image", self) + add_image.triggered.connect(lambda: self.newWidgetOnSection(ImageWidget, event.pos())) + take_screensnip = QAction("Snip Screen", editor) take_screensnip.triggered.connect(lambda: self.snipScreen(event.pos())) - frame_menu.addAction(take_screensnip) add_custom_widget = QAction("Add Custom Widget", editor) add_custom_widget.triggered.connect(lambda: self.addCustomWidget(event)) - frame_menu.addAction(add_custom_widget) - - insert_Link = QAction("Insert Link", editor) - insert_Link.triggered.connect(lambda: self.insertLink(event.pos())) + ''' + + frame_menu.addAction(paste) + + frame_menu.addSeparator() + frame_menu.addAction(insert_Link) - + + frame_menu.addSeparator() + + frame_menu.addAction(add_table) + + ''' + frame_menu.addSeparator() + + frame_menu.addActions([add_image, take_screensnip, add_custom_widget]) + ''' + frame_menu.exec(event.globalPos()) def insertLink(self, clickPos): @@ -223,12 +241,25 @@ def center_of_screen(self): center_y = (editor_frame_geometry.height() - 200) // 2 return center_x, center_y + # Used for calling functions in toolbar def toolbar_table(self): print("toolbar_table pressed") center_x, center_y = self.center_of_screen() clickPos = QPoint(center_x, center_y) self.newWidgetOnSection(TableWidget, clickPos) + def toolbar_snipScreen(self): + print("toolbar_snipScreen pressed") + center_x, center_y = self.center_of_screen() + clickPos = QPoint(center_x, center_y) + self.snipScreen(clickPos) + + def toolbar_pictures(self): + print("toolbar_pictures pressed") + center_x, center_y = self.center_of_screen() + clickPos = QPoint(center_x, center_y) + self.newWidgetOnSection(ImageWidget, clickPos) + def toolbar_hyperlink(self): print("toolbar_hyperlink pressed") center_x, center_y = self.center_of_screen() diff --git a/Widgets/Image.py b/Widgets/Image.py index bc45a09..97bd4f1 100644 --- a/Widgets/Image.py +++ b/Widgets/Image.py @@ -71,6 +71,8 @@ def __getstate__(self): def __setstate__(self, state): self.__init__(state['geometry'].x(), state['geometry'].y(), state['geometry'].width(), state['geometry'].height(), state['image_matrix']) + # not necessary to have a top toolbar for image + ''' def customMenuItems(self): def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): action = QAction(QIcon(icon_path), action_name, parent) @@ -96,7 +98,7 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): rotateRightAction.triggered.connect(self.rotate90Right) - shrinkImageAction = build_action(toolbarBottom, 'Assets/icons/svg_shrink', "Rotate 90 degrees Right", "Rotate 90 degrees Right", False) + shrinkImageAction = build_action(toolbarBottom, './Assets/icons/svg_shrink', "Rotate 90 degrees Right", "Rotate 90 degrees Right", False) shrinkImageAction.triggered.connect(self.shrinkImage) expandImageAction = build_action(toolbarBottom, 'Assets/icons/svg_expand', "Rotate 90 degrees Right", "Rotate 90 degrees Right", False) expandImageAction.triggered.connect(self.expandImage) @@ -108,7 +110,7 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): qwaBottom.setDefaultWidget(toolbarBottom) return [qwaBottom] - + ''' def flipVertical(self): # Flip the image matrix vertically using OpenCV parent_widget = self.parentWidget() diff --git a/Widgets/Table.py b/Widgets/Table.py index 82921a1..1df2a26 100644 --- a/Widgets/Table.py +++ b/Widgets/Table.py @@ -8,7 +8,8 @@ def __init__(self, x, y, w, h, rows, cols): # The actual table widget self.table = QTableWidget(rows, cols, self) - # Hide the horizontal and vertical headers + # Hides the horizontal and vertical headers + # These actually look really cool tho self.table.horizontalHeader().setVisible(False) self.table.verticalHeader().setVisible(False) @@ -49,7 +50,8 @@ def new(clickPos: QPoint): table_widget = TableWidget(clickPos.x(), clickPos.y(), 200, 200, int(rows_input), int(cols_input)) return table_widget - + # Moved to DraggableContainer.py + ''' def customMenuItems(self): addRow = QAction("Add Row", self) addRow.triggered.connect(self.addRow) @@ -58,7 +60,8 @@ def customMenuItems(self): addCol.triggered.connect(self.addCol) return [addRow, addCol] - + ''' + def __getstate__(self): state = {} diff --git a/Widgets/Textbox.py b/Widgets/Textbox.py index d9ec76d..5c05698 100644 --- a/Widgets/Textbox.py +++ b/Widgets/Textbox.py @@ -91,6 +91,7 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): ) size = QComboBox() + size.setFixedWidth(50) size.addItems([str(fs) for fs in FONT_SIZES]) size.currentIndexChanged.connect( lambda x: self.setFontPointSizeCustom( From 2f5ae252ddf46a9c07b5b7df968d5fb52f438caa Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Thu, 22 Feb 2024 14:13:42 -0600 Subject: [PATCH 094/127] Background only text widget Changing background color does not affect right click context menu anymore --- Widgets/Textbox.py | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/Widgets/Textbox.py b/Widgets/Textbox.py index e816f4e..87ccd99 100644 --- a/Widgets/Textbox.py +++ b/Widgets/Textbox.py @@ -285,16 +285,6 @@ def applyToAllIfNoSelection(self, func): self.setTextCursor(cursor) return True - def attributeChangedSlot(attribute, value): - if attribute == editorSignalsInstance.ChangedWidgetAttribute.FontBold: - print("Font Bold Signal") - - def slot_action2(self): - print("Action 2 Triggered") - font = QFont() - font.setItalic(True) - self.setFont(font) - def changeFontSizeEvent(self, weight): print("changeFontSizeEvent Called") self.setFontWeightCustom(weight) @@ -525,9 +515,10 @@ def changeFontColorEvent(self, new_font_color): # Changes color of whole background def changeBackgroundColorEvent(self, color: QColor): print("CHANGE BACKGROUND COLOR EVENT") + if color.isValid(): rgb = color.getRgb() - self.setStyleSheet(f"background-color: rgb({rgb[0]}, {rgb[1]}, {rgb[2]});") + self.setStyleSheet(f"QTextBrowser {{background-color: rgb({rgb[0]}, {rgb[1]}, {rgb[2]}); }}") else: print("INVALID COLOR") #self.setStyleSheet("background-color: transparent;") From 5a59f49719a7d61fc41b3d338a7637353256828c Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Tue, 27 Feb 2024 14:47:14 -0600 Subject: [PATCH 095/127] Fixed shrink and expand image resizing --- Widgets/Image.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Widgets/Image.py b/Widgets/Image.py index bc45a09..9645934 100644 --- a/Widgets/Image.py +++ b/Widgets/Image.py @@ -22,7 +22,7 @@ def __init__(self, x, y, w, h, image_matrix): self.setPixmap(self.q_pixmap.scaled(w, h, Qt.IgnoreAspectRatio, Qt.SmoothTransformation)) # Scale to widget geometry self.setGeometry(x, y, w, h) # this should get fixed - self.persistantGeometry = self.geometry() + self.persistantGeometry = self.geometry() # Handle resize def newGeometryEvent(self, newGeometry): @@ -96,9 +96,9 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): rotateRightAction.triggered.connect(self.rotate90Right) - shrinkImageAction = build_action(toolbarBottom, 'Assets/icons/svg_shrink', "Rotate 90 degrees Right", "Rotate 90 degrees Right", False) + shrinkImageAction = build_action(toolbarBottom, 'Assets/icons/svg_shrink', "Shrink", "Shrink", False) shrinkImageAction.triggered.connect(self.shrinkImage) - expandImageAction = build_action(toolbarBottom, 'Assets/icons/svg_expand', "Rotate 90 degrees Right", "Rotate 90 degrees Right", False) + expandImageAction = build_action(toolbarBottom, 'Assets/icons/svg_expand', "Expand", "Expand", False) expandImageAction.triggered.connect(self.expandImage) @@ -169,7 +169,7 @@ def shrinkImage(self): newX, newY = parent_widget.x(), parent_widget.y() new_width, new_height = self.w, self.h parent_widget.setGeometry(newX, newY, new_width, new_height) - self.updateImageSize() + self.setPixmap(self.q_pixmap.scaled(self.w, self.h, Qt.IgnoreAspectRatio, Qt.SmoothTransformation)) def expandImage(self): # Increase image size by 10% @@ -180,8 +180,9 @@ def expandImage(self): newX, newY = parent_widget.x(), parent_widget.y() new_width, new_height = self.w, self.h parent_widget.setGeometry(newX, newY, new_width, new_height) - self.updateImageSize() + self.setPixmap(self.q_pixmap.scaled(self.w, self.h, Qt.IgnoreAspectRatio, Qt.SmoothTransformation)) + # Updates display. Note: Keeps Aspect Ratio def updateImageSize(self): # Update the displayed pixmap with the new size self.setPixmap(self.q_pixmap.scaled(self.w, self.h, Qt.KeepAspectRatio, Qt.SmoothTransformation)) From 3b9b2c140c37e4e30ef06aaf20b9758156b646ba Mon Sep 17 00:00:00 2001 From: ldeltastreaml <70774713+ldeltastreaml@users.noreply.github.com> Date: Tue, 27 Feb 2024 20:56:37 -0600 Subject: [PATCH 096/127] Wrong toolbar assignment new buttons set to "toolbar" instead of "homeToolbar" --- Modules/BuildUI.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index 366183a..9acebea 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -217,7 +217,7 @@ def build_toolbar(editor): bullet = build_action(homeToolbar, './Assets/icons/svg_bullets', "Bullets", "Bullets", False) bullet.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Bullet, None)) - paperColor= build_action(toolbar, './Assets/icons/svg_paper', "Paper Color", "Paper Color", False) + paperColor= build_action(homeToolbar, './Assets/icons/svg_paper', "Paper Color", "Paper Color", False) paperColor.triggered.connect(lambda: editor.frameView.pageColor(QColorDialog.getColor())) homeToolbar.addActions([cut, copy]) @@ -229,7 +229,7 @@ def build_toolbar(editor): homeToolbar.addSeparator() - toolbar.addActions([bold, italic, underline, fontColor, textHighlightColor, bgColor, paperColor, bullet]) + homeToolbar.addActions([bold, italic, underline, fontColor, textHighlightColor, bgColor, paperColor, bullet]) # numbering menu start From 653a1becc7a36672c4ae736faeb8f36e709dd3c8 Mon Sep 17 00:00:00 2001 From: sillypenguin77 <67487654+sillypenguin77@users.noreply.github.com> Date: Wed, 28 Feb 2024 20:20:37 -0600 Subject: [PATCH 097/127] Fixed screensnip bug for mac fixed bounding issue for mac version 14.1.2, commented out original as it might be needed for different mac versions --- Modules/Screensnip.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Modules/Screensnip.py b/Modules/Screensnip.py index 9df1c83..5ef9e48 100644 --- a/Modules/Screensnip.py +++ b/Modules/Screensnip.py @@ -83,9 +83,11 @@ def mouseReleaseEvent(self, event): try: if platform == "darwin": - img = ImageGrab.grab(bbox=( (x1 ) * 2, (y1 + 55 ) * 2, (x2 ) * 2, (y2 + 55) * 2)) + #img = ImageGrab.grab(bbox=( (x1 ) * 2, (y1 + 55 ) * 2, (x2 ) * 2, (y2 + 55) * 2)) [may be needed for different mac version - testing in progress] + img = ImageGrab.grab(bbox=(x1, y1 + 55, x2, y2 + 55)) # For mac version 14.1.2 else: img = ImageGrab.grab(bbox=(x1 + 2, y1 + 2, x2 - 1, y2 - 1)) + except Exception as e: print(f"Error grabbing screenshot: {e}") img = None From 84aecab0e5008b6addbd495c5dae2f73d9cb46ed Mon Sep 17 00:00:00 2001 From: sillypenguin77 <67487654+sillypenguin77@users.noreply.github.com> Date: Fri, 1 Mar 2024 13:48:31 -0600 Subject: [PATCH 098/127] Added Window Restoration --- Models/Editor.py | 20 ++++++++++++++++++++ Modules/BuildUI.py | 5 +++++ 2 files changed, 25 insertions(+) diff --git a/Models/Editor.py b/Models/Editor.py index fdac0ee..0518fe8 100644 --- a/Models/Editor.py +++ b/Models/Editor.py @@ -31,6 +31,26 @@ def __init__(self): self.autosaver = Autosaver(self) # Waits for change signals and saves the notebook self.setFocus() + self.settings = QSettings("UNT - Team Olive", "OpenNote") + build_ui(self) + + def closeEvent(self, event): + # Save window size and position before exiting + + print("Window closing event triggered") + + self.settings.setValue("geometry", self.saveGeometry()) + self.settings.setValue("windowState", self.saveState()) + super().closeEvent(event) + + def showEvent(self, event): + # Restores window size and position + + print("Window showing event triggered") + + self.restoreGeometry(self.settings.value("geometry", self.saveGeometry())) + self.restoreState(self.settings.value("windowState", self.saveState())) + super().showEvent(event) # def focusInEvent(self, event): # self.repaint() diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index 9acebea..9962292 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -75,6 +75,11 @@ def build_ui(editor): #add functionality e.g. addSectionButton.clcicked.connect(editor.add_section_function) leftSideLayout.addWidget(addSectionButton) + #Saves window size + #editor.restoreGeometry(editor.settings.value("geometry", editor.saveGeometry())) + #editor.restoreState(editor.settings.value("windowState", editor.saveState())) + + def check_appearance(): """Checks DARK/LIGHT mode of macos.""" cmd = 'defaults read -g AppleInterfaceStyle' From 0f55abc890c92d201cdf670da247df4cf276de80 Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Wed, 6 Mar 2024 12:27:41 -0600 Subject: [PATCH 099/127] Pop up menus and mutliselect Pop up menus close when clicking off of the menu. Table has new right click menu for cells but theres an issue where the right click will alternate between the cell menu and the default table right click menu each time you right click. Multiselect allows cut and multiselecting in any direction. --- Models/DraggableContainer.py | 17 ++++++- Modules/Multiselect.py | 90 ++++++++++++++++++++++++++++-------- Widgets/Image.py | 29 +++++++++++- Widgets/Link.py | 7 ++- Widgets/Table.py | 28 +++++++---- 5 files changed, 139 insertions(+), 32 deletions(-) diff --git a/Models/DraggableContainer.py b/Models/DraggableContainer.py index 0396347..616e161 100644 --- a/Models/DraggableContainer.py +++ b/Models/DraggableContainer.py @@ -1,5 +1,6 @@ from PySide6.QtCore import * from PySide6.QtGui import * +from PySide6.QtGui import QKeyEvent from PySide6.QtWidgets import * from Modules.Enums import * from Modules.EditorSignals import editorSignalsInstance, ChangedWidgetAttribute @@ -267,6 +268,8 @@ def mouseMoveEvent(self, e: QMouseEvent): toMove = e.globalPos() - self.position self.resize(e.x(), self.geometry().height() - newheight) self.move(self.x(), toMove.y()) + '''if hasattr(self.childWidget, "newGeometryEvent"): + self.newGeometry.connect(self.childWidget.newGeometryEvent)''' elif self.mode== Mode.RESIZEBL: # Left - Bottom newwidth = e.globalX() - self.position.x() - self.geometry().x() toMove = e.globalPos() - self.position @@ -289,7 +292,7 @@ def mouseMoveEvent(self, e: QMouseEvent): elif self.mode == Mode.RESIZEBR:# Right - Bottom #if child is a image, resize differently if isinstance(child_widget, QLabel): - #change this to where resizing corners works like onenote + # change this self.resize(e.x(), e.y()) else: self.resize(e.x(), e.y()) @@ -368,3 +371,15 @@ def resizeTable(self): self.resize(self.childWidget.size()) self.newGeometry.emit(self.geometry()) self.parentWidget().repaint() + def keyPressEvent(self, event: QKeyEvent) -> None: + if event.key() == Qt.Key_Shift: + print("SHIFT PRESSED") + self.shift_pressed = True + else: + super().keyPressEvent(event) + def keyReleaseEvent(self, event: QKeyEvent) -> None: + if event.key() == Qt.Key_Shift: + print("SHIFT RELEASED") + self.shift_pressed = False + else: + super().keyReleaseEvent(event) \ No newline at end of file diff --git a/Modules/Multiselect.py b/Modules/Multiselect.py index 3d656da..ca6a45a 100644 --- a/Modules/Multiselect.py +++ b/Modules/Multiselect.py @@ -5,6 +5,7 @@ from PySide6.QtGui import * from PySide6.QtWidgets import * from Models.DraggableContainer import DraggableContainer +from Modules.EditorSignals import editorSignalsInstance,ChangedWidgetAttribute class MultiselectMode(Enum): NONE = 0, @@ -26,6 +27,15 @@ def __init__(self, editorFrame): self.dragInitEventPos = None # Position of the event that started the dragging self.dragOffset = None # Offset of object that is used to drag the others from the first object in the editors list + # for handling deselect + self.installEventFilter() + + editorSignalsInstance.widgetCut.connect(self.cutWidgetEvent) + + # install event filter to editorframe + def installEventFilter(self): + self.editorFrame.installEventFilter(self) + def eventFilter(self, obj, event): multiselector = self @@ -55,8 +65,31 @@ def eventFilter(self, obj, event): multiselector.focusObjectIfInMultiselect() return False + + # Handle click outside the selected objects to deselect + if event.type() == QEvent.MouseButtonPress and event.button() == Qt.LeftButton: + if multiselector.mode == MultiselectMode.HAS_SELECTED_OBJECTS: + multiselector.deselectIfClickOutsideObjects(event) + print("DESELECT") + return False + # check if clicked outside + def deselectIfClickOutsideObjects(self, event): + # Check if the click is outside any selected objects + clickPos = event.globalPos() + for o in self.selectedObjects: + o_tl_pos = o.mapToGlobal(QPoint(0, 0)) + o_br_pos = o_tl_pos + QPoint(o.width(), o.height()) + + if o_tl_pos.x() <= clickPos.x() <= o_br_pos.x() and o_tl_pos.y() <= clickPos.y() <= o_br_pos.y(): + # Click is inside a selected object, do not deselect' + print("Click is inside a selected object, do not deselect") + return + + # Click is outside all selected objects, deselect + self.finishDraggingObjects() + def beginDrawingArea(self, event): self.mode = MultiselectMode.IS_DRAWING_AREA self.drawingWidget.setStyleSheet(TextBoxStyles.INFOCUS.value) @@ -66,38 +99,43 @@ def beginDrawingArea(self, event): self.drawAreaStartGlobalPos = event.globalPos() def continueDrawingArea(self, event): - width = event.pos().x() - self.drawAreaStartLocalPos.x() - height = event.pos().y() - self.drawAreaStartLocalPos.y() + start_x = self.drawAreaStartLocalPos.x() + start_y = self.drawAreaStartLocalPos.y() - self.drawingWidget.resize(width, height) + end_x = event.pos().x() + end_y = event.pos().y() + width = abs(end_x - start_x) + height = abs(end_y - start_y) + + # Calculate the x and y for setting the geometry + x = min(start_x, end_x) + y = min(start_y, end_y) + + # Adjust the geometry of the drawingWidget + self.drawingWidget.setGeometry(x, y, width, height) def finishDrawingArea(self, event): editor = self.editorFrame.editor - # Throw away if the area of the selection is negative (user dragged from bottom right to top left) - if self.drawAreaStartGlobalPos.x() > event.globalPos().x() or self.drawAreaStartGlobalPos.y() > event.globalPos().y(): - self.drawingWidget.hide() - self.finishDraggingObjects() - # You could probably switch around the coordinates in here and modify drawing logic to support other drag directions - return + # Get the coordinates of the top-left corner of the selection area + start_x = min(self.drawAreaStartGlobalPos.x(), event.globalPos().x()) + start_y = min(self.drawAreaStartGlobalPos.y(), event.globalPos().y()) - # Get all DraggableContainers in the selection + # Get the coordinates of the bottom-right corner of the selection area + end_x = max(self.drawAreaStartGlobalPos.x(), event.globalPos().x()) + end_y = max(self.drawAreaStartGlobalPos.y(), event.globalPos().y()) + + # Iterate through objects and check if they are inside the selection area sectionView = self.editorFrame.editor.sectionView currentSectionIndex = sectionView.tabs.currentIndex() currentSectionModel = sectionView.sectionModels[currentSectionIndex] currentSectionModelWidgets = currentSectionModel.widgets - for o in currentSectionModelWidgets: - print(o) - # Map all positions to global for correct coord checks - ob_tl_pos = o.mapToGlobal(QPoint(0, 0)) # Object top left corner - start_pos = self.drawAreaStartGlobalPos - end_pos = event.globalPos() + for o in currentSectionModelWidgets: + ob_tl_pos = o.mapToGlobal(QPoint(0, 0)) - # If object x + width is between start and end x, and object y + height is between start and end y - if ob_tl_pos.x() > start_pos.x() and ob_tl_pos.x() + o.width() < end_pos.x(): - if ob_tl_pos.y() > start_pos.y() and ob_tl_pos.y() + o.height() < end_pos.y(): - self.selectedObjects.append(o) + if start_x <= ob_tl_pos.x() <= end_x and start_y <= ob_tl_pos.y() <= end_y: + self.selectedObjects.append(o) if len(self.selectedObjects) > 0: self.mode = MultiselectMode.HAS_SELECTED_OBJECTS @@ -179,3 +217,15 @@ def focusObjectIfInMultiselect(self): o.setStyleSheet(TextBoxStyles.INFOCUS.value) except: self.finishDraggingObjects() + # Allow removing all selected objects + def removeWidgetEvent(self): + for obj in self.selectedObjects: + editorSignalsInstance.changeMade.emit(obj) + + # Allow cutting all selected objects + def cutWidgetEvent(self): + for obj in self.selectedObjects: + editorSignalsInstance.widgetCopied.emit(obj) + editorSignalsInstance.widgetRemoved.emit(obj) + + # Paste works from clipboard, meaning have to store all objects to clipboard \ No newline at end of file diff --git a/Widgets/Image.py b/Widgets/Image.py index 9645934..cf3e7ab 100644 --- a/Widgets/Image.py +++ b/Widgets/Image.py @@ -1,6 +1,8 @@ from PySide6.QtCore import * from PySide6.QtGui import * from PySide6.QtWidgets import * +from PySide6.QtWidgets import QFileDialog + from Modules.Enums import WidgetType @@ -38,7 +40,7 @@ def newGeometryEvent(self, newGeometry): self.persistantGeometry = newGeometry - @staticmethod + '''@staticmethod def new(clickPos): # Get path from user @@ -54,6 +56,31 @@ def new(clickPos): image = ImageWidget(clickPos.x(), clickPos.y(), w, h, image_matrix) # Note: the editorframe will apply pos based on event return image + ''' + # uses inbuilt qt file dialog + @staticmethod + def new(clickPos): + # Create a dummy parent widget for the file dialog + dummy_parent = QWidget() + + # Get path from user + options = QFileDialog.Options() + options |= QFileDialog.DontUseNativeDialog # Use Qt's built-in dialog instead of the native platform dialog + path, _ = QFileDialog.getOpenFileName(dummy_parent, 'Add Image', '', 'Images (*.png *.xpm *.jpg *.bmp *.jpeg);;All Files (*)', options=options) + + # Check if the user selected a file + if path: + # Get image size + image_matrix = cv2.imread(path) + h, w, _ = image_matrix.shape + + # Create image and add to notebook + image = ImageWidget(clickPos.x(), clickPos.y(), w, h, image_matrix) + return image + + # Return None or handle the case where the user cancels the dialog + return None + @staticmethod # Special staticmethod that screensnip uses def newFromMatrix(clickPos, imageMatrix): diff --git a/Widgets/Link.py b/Widgets/Link.py index e4ae1a6..40560f7 100644 --- a/Widgets/Link.py +++ b/Widgets/Link.py @@ -30,10 +30,15 @@ def __init__(self): self.setLayout(layout) + self.setModal(False) + def get_link_data(self): link_address = self.link_textbox.text() display_text = self.display_textbox.text() return link_address, display_text - + def mousePressEvent(self, event): + # Check if the mouse click is outside the dialog + if event.button() == Qt.LeftButton and not self.rect().contains(event.globalPos()): + self.close() diff --git a/Widgets/Table.py b/Widgets/Table.py index 82921a1..78022e3 100644 --- a/Widgets/Table.py +++ b/Widgets/Table.py @@ -50,12 +50,19 @@ def new(clickPos: QPoint): return table_widget + # override contextmenuevent + def contextMenuEvent(self, event: QContextMenuEvent): + menu = QMenu(self) + menu.addActions(self.customMenuItems()) + menu.exec_(event.globalPos()) + def customMenuItems(self): addRow = QAction("Add Row", self) addRow.triggered.connect(self.addRow) addCol = QAction("Add Column", self) - addCol.triggered.connect(self.addCol) + addCol.triggered.connect(self.addCol) + return [addRow, addCol] @@ -96,11 +103,10 @@ def show_table_popup(self): class TablePopupWindow(QDialog): def __init__(self): super().__init__() - '''self.setWindowTitle("Popup Window") - layout = QVBoxLayout() - label = QLabel("This is a popup window.") - layout.addWidget(label) - self.setLayout(layout)''' + + # to stay on top of application + self.setWindowFlag(Qt.WindowStaysOnTopHint) + self.setWindowTitle("Table Configuration") self.layout = QVBoxLayout() @@ -123,6 +129,8 @@ def __init__(self): self.setLayout(self.layout) + + self.setModal(False) def get_table_data(self): rows_input = self.rows_input.text() @@ -131,6 +139,8 @@ def get_table_data(self): def create_table(self): print("table") - #row_num = int(self.rows_input.text()) - #col_num = int(self.cols_input.text()) - #self.EditorFrameView.add_table_action(row_num, col_num) + + def mousePressEvent(self, event): + # Check if the mouse click is outside the dialog + if event.button() == Qt.LeftButton and not self.rect().contains(event.globalPos()): + self.close() From 65e6b37edcee54b0f43a63642eb06472a9f5ca14 Mon Sep 17 00:00:00 2001 From: sillypenguin77 <67487654+sillypenguin77@users.noreply.github.com> Date: Wed, 6 Mar 2024 23:55:44 -0600 Subject: [PATCH 100/127] Added strikethrough functionality Implemented strikethrough functionality and connected it to home toolbar and textbox toolbar. *Icons need to be updated to match other icon style* --- Assets/icons/svg_strikethrough.svg | 6 ++++++ Models/DraggableContainer.py | 4 ++++ Modules/BuildUI.py | 5 ++++- Modules/EditorSignals.py | 2 ++ Widgets/Textbox.py | 25 ++++++++++++++++++++++++- 5 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 Assets/icons/svg_strikethrough.svg diff --git a/Assets/icons/svg_strikethrough.svg b/Assets/icons/svg_strikethrough.svg new file mode 100644 index 0000000..7da4dad --- /dev/null +++ b/Assets/icons/svg_strikethrough.svg @@ -0,0 +1,6 @@ + + + strikethrough-line + + + \ No newline at end of file diff --git a/Models/DraggableContainer.py b/Models/DraggableContainer.py index 63ed374..dd34603 100644 --- a/Models/DraggableContainer.py +++ b/Models/DraggableContainer.py @@ -415,6 +415,10 @@ def widgetAttributeChanged(self, changedWidgetAttribute, value): print("Change Font Underline Event Called") child_widget.changeFontUnderlineEvent() + elif hasattr(child_widget, "setStrikeOut") and (changedWidgetAttribute == ChangedWidgetAttribute.Strikethrough): + print("Change strikethroughEvent called") + child_widget.setStrikeOut() + elif hasattr(child_widget, "changeFontEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.Font): print("Change Font Family Event Called") child_widget.changeFontEvent(value) diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index 9962292..0d13ebd 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -217,6 +217,9 @@ def build_toolbar(editor): underline = build_action(homeToolbar, './Assets/icons/underline.svg', "Underline", "Underline", True) underline.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontUnderline, None)) + + strikethrough = build_action(homeToolbar, './Assets/icons/svg_strikethrough.svg', "Strikethrough", "Strikethrough", True) + strikethrough.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Strikethrough, None)) # Bullets with placeholder for more bullet options bullet = build_action(homeToolbar, './Assets/icons/svg_bullets', "Bullets", "Bullets", False) @@ -234,7 +237,7 @@ def build_toolbar(editor): homeToolbar.addSeparator() - homeToolbar.addActions([bold, italic, underline, fontColor, textHighlightColor, bgColor, paperColor, bullet]) + homeToolbar.addActions([bold, italic, underline, strikethrough, fontColor, textHighlightColor, bgColor, paperColor, bullet]) # numbering menu start diff --git a/Modules/EditorSignals.py b/Modules/EditorSignals.py index d8a4516..b97220a 100644 --- a/Modules/EditorSignals.py +++ b/Modules/EditorSignals.py @@ -24,6 +24,8 @@ class ChangedWidgetAttribute(Enum): AlignRight = 15 PaperColor = 16 + Strikethrough = 17 + # Cant be statically typed because importing the classes causes circular imports diff --git a/Widgets/Textbox.py b/Widgets/Textbox.py index f815a3f..7a4cd2e 100644 --- a/Widgets/Textbox.py +++ b/Widgets/Textbox.py @@ -148,6 +148,12 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): lambda x: self.setFontUnderlineCustom(True if x else False) ) + strikethrough = build_action( + toolbarBottom,"./Assets/icons/svg_strikethrough", "Srikethrough", "Srikethrough", True + ) + strikethrough.toggled.connect(lambda: self.setStrikeOut()) + + fontColor = build_action( toolbarBottom, "./Assets/icons/svg_font_color", @@ -194,6 +200,7 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): bold, italic, underline, + strikethrough, textHighlightColor, fontColor, bullets @@ -583,4 +590,20 @@ def changeAllTextColors(self, new_color): cursor.setCharFormat(char_format) cursor.movePosition(QTextCursor.Start) - self.setTextCursor(cursor) \ No newline at end of file + self.setTextCursor(cursor) + + def setStrikeOut(self): + print("strikeout event") + cursor = self.textCursor() + format = cursor.charFormat() + + # Toggle strikethrough + format.setFontStrikeOut(not format.fontStrikeOut()) + + # Apply the new format to the selected text + #cursor.mergeCharFormat(format) + cursor.setCharFormat(format) + + #cursor.movePosition(QTextCursor.End) + self.setTextCursor(cursor) + #self.setFocus() \ No newline at end of file From 79c88b6f9ca30eb9a1b6ee31aecd182bd5dc1874 Mon Sep 17 00:00:00 2001 From: ldeltastreaml <70774713+ldeltastreaml@users.noreply.github.com> Date: Thu, 7 Mar 2024 02:38:23 -0600 Subject: [PATCH 101/127] BuildUI Overhaul + Custom Title Bar - bars should look more like OneNote equivalent - addition of a custom titlebar (a bit buggy but completely functional) - new grid layout code - asthetically closer to OneNote --- Models/Editor.py | 29 +++- Modules/BuildUI.py | 363 ++++++++++++++++++++++++--------------- Styles/styles.qss | 21 +-- Views/EditorFrameView.py | 2 +- 4 files changed, 260 insertions(+), 155 deletions(-) diff --git a/Models/Editor.py b/Models/Editor.py index fdac0ee..05fd1b2 100644 --- a/Models/Editor.py +++ b/Models/Editor.py @@ -18,7 +18,7 @@ class Editor(QMainWindow): def __init__(self): super().__init__() - # self.setWindowFlag(Qt.FramelessWindowHint) + self.setWindowFlag(Qt.WindowType.FramelessWindowHint) self.notebook = NotebookModel('Untitled Notebook') # Current notebook object # self.selected = None # Selected object (for font attributes of TextBox) @@ -34,3 +34,30 @@ def __init__(self): build_ui(self) # def focusInEvent(self, event): # self.repaint() + + def changeEvent(self, event): + if event.type() == QEvent.Type.WindowStateChange: + self.titlebar.window_state_changed(self.windowState()) + super().changeEvent(event) + event.accept() + + def mousePressEvent(self, event): + if event.button() == Qt.MouseButton.LeftButton: + self.initial_pos = event.position().toPoint() + super().mousePressEvent(event) + event.accept() + + def mouseMoveEvent(self, event): + if self.initial_pos is not None: + delta = event.position().toPoint() - self.initial_pos + self.window().move( + self.window().x() + delta.x(), + self.window().y() + delta.y(), + ) + super().mouseMoveEvent(event) + event.accept() + + def mouseReleaseEvent(self, event): + self.initial_pos = None + super().mouseReleaseEvent(event) + event.accept() diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index 9acebea..8d52a2d 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -18,89 +18,166 @@ FONT_SIZES = [7, 8, 9, 10, 11, 12, 13, 14, 18, 24, 36, 48, 64, 72, 96, 144, 288] -#builds the application's UI def build_ui(editor): - print("Building UI...") - - #editor.EditorFrameView = EditorFrameView(editor) - #editor.statusBar = editor.statusBar() - build_window(editor) + print("Building UI") + editor.setWindowTitle("OpenNote") + editor.setWindowIcon(QIcon('./Assets/OpenNoteLogo.png')) + editor.resize(800, 450) + editor.setAcceptDrops(True) + + if check_appearance() == False: + with open('./Styles/styles.qss',"r") as fh: + editor.setStyleSheet(fh.read()) + else: + with open('./Styles/stylesDark.qss',"r") as fh: + editor.setStyleSheet(fh.read()) + + editor.titlebar = build_titlebar(editor) build_menubar(editor) build_toolbar(editor) - #build_test_toolbar(editor) - # Application's main layout (grid) + # Main layout of the app gridLayout = QGridLayout() - gridContainerWidget = QWidget() - editor.setCentralWidget(gridContainerWidget) - gridContainerWidget.setLayout(gridLayout) - gridLayout.setSpacing(3) gridLayout.setContentsMargins(6, 6, 0, 0) - - gridLayout.setColumnStretch(0, 1) # The left side (index 0) will take up 1/7? of the space of the right gridLayout.setColumnStretch(1, 7) - # Left side of the app's layout + centralWidget = QWidget() + centralWidget.setLayout(gridLayout) + + # Sets up layout of each bar + topSideLayout = QVBoxLayout() + topSideContainerWidget = QWidget() + topSideContainerWidget.setLayout(topSideLayout) + topSideLayout.setContentsMargins(0, 0, 0, 0) + topSideLayout.setSpacing(0) + + topSideLayout.addWidget(editor.titlebar, 0) + topSideLayout.addWidget(editor.menubar, 1) + topSideLayout.addWidget(editor.homeToolbar, 2) + topSideLayout.addWidget(editor.insertToolbar, 2) + topSideLayout.addWidget(editor.drawToolbar, 2) + + # Sets up left side notebook view leftSideLayout = QVBoxLayout() leftSideContainerWidget = QWidget() leftSideContainerWidget.setLayout(leftSideLayout) leftSideLayout.setContentsMargins(0, 0, 0, 0) leftSideLayout.setSpacing(0) + leftSideLayout.addWidget(editor.notebookTitleView, 0) + leftSideLayout.addWidget(editor.pageView, 1) - - - # Right side of the app's layout + # Sets up right side section view rightSideLayout = QVBoxLayout() rightSideContainerWidget = QWidget() rightSideContainerWidget.setLayout(rightSideLayout) rightSideLayout.setContentsMargins(0, 0, 0, 0) rightSideLayout.setSpacing(0) - rightSideLayout.setStretch(0, 0) - rightSideLayout.setStretch(1, 1) - - # Add appropriate widgets (ideally just view controllers) to their layouts - leftSideLayout.addWidget(editor.notebookTitleView, 0) - leftSideLayout.addWidget(editor.pageView, 1) # Page view has max stretch factor rightSideLayout.addWidget(editor.sectionView, 0) - rightSideLayout.addWidget(editor.frameView, 1) # Frame view has max stretch factor - - # Add L+R container's widgets to the main grid - gridLayout.addWidget(leftSideContainerWidget, 0, 0) - gridLayout.addWidget(rightSideContainerWidget, 0, 1) - - addSectionButton = QPushButton("Add Section") - #add functionality e.g. addSectionButton.clcicked.connect(editor.add_section_function) - leftSideLayout.addWidget(addSectionButton) - -def check_appearance(): - """Checks DARK/LIGHT mode of macos.""" - cmd = 'defaults read -g AppleInterfaceStyle' - p = subprocess.Popen(cmd, stdout=subprocess.PIPE, - stderr=subprocess.PIPE, shell=True) - return bool(p.communicate()[0]) - - -def build_window(editor): - editor.setWindowTitle("OpenNote") - editor.setWindowIcon(QIcon('./Assets/OpenNoteLogo.png')) - editor.setAcceptDrops(True) - - if check_appearance() == False: - with open('./Styles/styles.qss',"r") as fh: - editor.setStyleSheet(fh.read()) - else: - with open('./Styles/stylesDark.qss',"r") as fh: - editor.setStyleSheet(fh.read()) + rightSideLayout.addWidget(editor.frameView, 1) + + gridLayout.addWidget(topSideContainerWidget, 0, 0, 1, 2, alignment = Qt.AlignmentFlag.AlignTop) + gridLayout.addWidget(leftSideContainerWidget, 1, 0, 1, 1) + gridLayout.addWidget(rightSideContainerWidget, 1, 1, 1, 2) + + editor.setCentralWidget(centralWidget) + +class build_titlebar(QWidget): + def __init__(self, parent): + super().__init__(parent) + self.setAutoFillBackground(True) + self.setBackgroundRole(QPalette.ColorRole.Highlight) + self.setStyleSheet( + """ + background-color: rgb(119, 25, 170); + height: 50px; + """ + ) + self.initial_pos = None + + title_bar_layout = QHBoxLayout(self) + title_bar_layout.setContentsMargins(0, 0, 0, 0) + title_bar_layout.setSpacing(0) + + self.title = QLabel(f"{self.__class__.__name__}", self) + self.title.setStyleSheet( + """ + color: white; + """ + ) + self.title.setAlignment(Qt.AlignmentFlag.AlignCenter) + if title := parent.windowTitle(): + self.title.setText(title) + title_bar_layout.addWidget(self.title) + + # Min button + self.min_button = QToolButton(self) + min_icon = self.style().standardIcon( + QStyle.StandardPixmap.SP_TitleBarMinButton + ) + self.min_button.setIcon(min_icon) + self.min_button.clicked.connect(self.window().showMinimized) + + # Max button + self.max_button = QToolButton(self) + max_icon = self.style().standardIcon( + QStyle.StandardPixmap.SP_TitleBarMaxButton + ) + self.max_button.setIcon(max_icon) + self.max_button.clicked.connect(self.window().showMaximized) + + # Close button + self.close_button = QToolButton(self) + close_icon = self.style().standardIcon( + QStyle.StandardPixmap.SP_TitleBarCloseButton + ) + self.close_button.setIcon(close_icon) + self.close_button.clicked.connect(self.window().close) + + # Normal button + self.normal_button = QToolButton(self) + normal_icon = self.style().standardIcon( + QStyle.StandardPixmap.SP_TitleBarNormalButton + ) + self.normal_button.setIcon(normal_icon) + self.normal_button.clicked.connect(self.window().showNormal) + self.normal_button.setVisible(False) + + # Add buttons + buttons = [ + self.min_button, + self.normal_button, + self.max_button, + self.close_button, + ] + for button in buttons: + button.setFocusPolicy(Qt.FocusPolicy.NoFocus) + button.setFixedSize(QSize(28, 28)) + button.setStyleSheet( + """QToolButton { color: white; + } + """ + ) + title_bar_layout.addWidget(button) + + def window_state_changed(self, state): + if state == Qt.WindowMaximized: + self.normal_button.setVisible(True) + self.max_button.setVisible(False) + else: + self.normal_button.setVisible(False) + self.max_button.setVisible(True) def build_menubar(editor): - file = editor.menuBar().addMenu('&File') - home = editor.menuBar().addMenu('&Home') - insert = editor.menuBar().addMenu('&Insert') - draw = editor.menuBar().addMenu('&Draw') - plugins = editor.menuBar().addMenu('&Plugins') + editor.menubar = editor.menuBar() + + file = editor.menubar.addMenu('&File') + home = editor.menubar.addMenu('&Home') + insert = editor.menubar.addMenu('&Insert') + draw = editor.menubar.addMenu('&Draw') + plugins = editor.menubar.addMenu('&Plugins') new_file = build_action(editor, './Assets/icons/svg_file_open', 'New Notebook', 'New Notebook', False) new_file.setShortcut(QKeySequence.StandardKey.New) @@ -130,46 +207,28 @@ def build_menubar(editor): add_widget = build_action(editor, './Assets/icons/svg_question', 'Add Custom Widget', 'Add Custom Widget', False) file.addActions([new_file, open_file, save_file, save_fileAs]) - - home.addActions([toggle_home_toolbar]) - - insert.addActions([toggle_insert_toolbar]) - - draw.addActions([toggle_draw_toolbar]) - - plugins.addActions([add_widget]) - -def set_toolbar_visibility(editor, triggered_toolbar): - # Find all toolbars in the editor - toolbars = editor.findChildren(QToolBar) - - # Iterate over each toolbar - for toolbar in toolbars: - if toolbar.objectName() == triggered_toolbar: - # Toggle the visibility of the triggered toolbar - print(toolbar.objectName(),"visibility change") - toolbar.setVisible(not toolbar.isVisible()) - else: - # Hide all other toolbars - toolbar.setVisible(False) + home.addAction(toggle_home_toolbar) + insert.addAction(toggle_insert_toolbar) + draw.addAction(toggle_draw_toolbar) + plugins.addAction(add_widget) def build_toolbar(editor): # homeToolbar code - homeToolbar = QToolBar() - homeToolbar.setObjectName('homeToolbar') - homeToolbar.setIconSize(QSize(16, 16)) - homeToolbar.setMovable(False) - homeToolbar.setStyleSheet('font-size: 10pt;') - editor.addToolBar(Qt.ToolBarArea.TopToolBarArea, homeToolbar) + editor.homeToolbar = QToolBar() + editor.homeToolbar.setObjectName('homeToolbar') + editor.homeToolbar.setIconSize(QSize(18, 18)) + editor.homeToolbar.setMovable(False) + editor.homeToolbar.setStyleSheet('height: 40px; spacing: 10px;') + editor.addToolBar(Qt.ToolBarArea.TopToolBarArea, editor.homeToolbar) #separates toolbar with a line break spacer = QWidget() spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) - cut = build_action(homeToolbar, './Assets/icons/svg_cut', "cut", "cut", False) + cut = build_action(editor.homeToolbar, './Assets/icons/svg_cut', "cut", "cut", False) cut.triggered.connect(editor.frameView.cutWidgetEvent) - copy = build_action(homeToolbar, './Assets/icons/svg_copy', "copy", "copy", False) + copy = build_action(editor.homeToolbar, './Assets/icons/svg_copy', "copy", "copy", False) copy.triggered.connect(editor.frameView.copyWidgetEvent) @@ -191,45 +250,45 @@ def build_toolbar(editor): # - Alternates between working and not working # - Textboxes do not remember settings like if font is toggled or current font size - bgColor = build_action(homeToolbar, './Assets/icons/svg_font_bucket', "Background Color", "Background Color", False) + bgColor = build_action(editor.homeToolbar, './Assets/icons/svg_font_bucket', "Background Color", "Background Color", False) #bgColor.triggered.connect(lambda: openGetColorDialog(purpose = "background")) #current bug, alternates between activating and not working when using bgColor.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.BackgroundColor, QColorDialog.getColor())) - textHighlightColor = build_action(homeToolbar, './Assets/icons/svg_textHighlightColor', "Text Highlight Color", "Text Highlight Color", True) + textHighlightColor = build_action(editor.homeToolbar, './Assets/icons/svg_textHighlightColor', "Text Highlight Color", "Text Highlight Color", True) textHighlightColor.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.TextHighlightColor, QColorDialog.getColor())) #defines font color icon appearance and settings - fontColor = build_action(homeToolbar, './Assets/icons/svg_font_color', "Font Color", "Font Color", False) + fontColor = build_action(editor.homeToolbar, './Assets/icons/svg_font_color', "Font Color", "Font Color", False) fontColor.triggered.connect(lambda: openGetColorDialog(purpose = "font")) - bold = build_action(homeToolbar, './Assets/icons/bold', "Bold", "Bold", True) + bold = build_action(editor.homeToolbar, './Assets/icons/bold', "Bold", "Bold", True) bold.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontBold, None)) - italic = build_action(homeToolbar, './Assets/icons/italic.svg', "Italic", "Italic", True) + italic = build_action(editor.homeToolbar, './Assets/icons/italic.svg', "Italic", "Italic", True) italic.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontItalic, None)) - underline = build_action(homeToolbar, './Assets/icons/underline.svg', "Underline", "Underline", True) + underline = build_action(editor.homeToolbar, './Assets/icons/underline.svg', "Underline", "Underline", True) underline.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontUnderline, None)) # Bullets with placeholder for more bullet options - bullet = build_action(homeToolbar, './Assets/icons/svg_bullets', "Bullets", "Bullets", False) + bullet = build_action(editor.homeToolbar, './Assets/icons/svg_bullets', "Bullets", "Bullets", False) bullet.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Bullet, None)) - paperColor= build_action(homeToolbar, './Assets/icons/svg_paper', "Paper Color", "Paper Color", False) + paperColor= build_action(editor.homeToolbar, './Assets/icons/svg_paper', "Paper Color", "Paper Color", False) paperColor.triggered.connect(lambda: editor.frameView.pageColor(QColorDialog.getColor())) - homeToolbar.addActions([cut, copy]) + editor.homeToolbar.addActions([cut, copy]) - homeToolbar.addSeparator() + editor.homeToolbar.addSeparator() - homeToolbar.addWidget(font_family) - homeToolbar.addWidget(font_size) + editor.homeToolbar.addWidget(font_family) + editor.homeToolbar.addWidget(font_size) - homeToolbar.addSeparator() + editor.homeToolbar.addSeparator() - homeToolbar.addActions([bold, italic, underline, fontColor, textHighlightColor, bgColor, paperColor, bullet]) + editor.homeToolbar.addActions([bold, italic, underline, fontColor, textHighlightColor, bgColor, paperColor, bullet]) # numbering menu start @@ -250,14 +309,14 @@ def build_toolbar(editor): # cant directly add numbering menu to homeToolbar so this is required numbering = QToolButton(editor) numbering.setIcon(QIcon('./Assets/icons/svg_bullet_number')) - numbering.setIconSize(QSize(16,16)) - numbering.setPopupMode(QToolButton.MenuButtonPopup) + numbering.setIconSize(QSize(18,18)) + numbering.setPopupMode(QToolButton.InstantPopup) numbering.setMenu(numbering_menu) - homeToolbar.addWidget(numbering) + editor.homeToolbar.addWidget(numbering) # QActionGroup used to display that only one can be toggled at a time - align_group = QActionGroup(homeToolbar) + align_group = QActionGroup(editor.homeToolbar) align_left = build_action(align_group,"./Assets/icons/svg_align_left","Align Left","Align Left", True) align_left.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.AlignLeft, None)) @@ -269,67 +328,89 @@ def build_toolbar(editor): align_group.addAction(align_left) align_group.addAction(align_center) align_group.addAction(align_right) - homeToolbar.addActions(align_group.actions()) + editor.homeToolbar.addActions(align_group.actions()) - homeToolbar.addSeparator() + editor.homeToolbar.addSeparator() # insertToolbar code - insertToolbar = QToolBar() - insertToolbar.setObjectName('insertToolbar') - insertToolbar.setIconSize(QSize(16,16)) - insertToolbar.setStyleSheet('font-size: 10pt;') - insertToolbar.setMovable(False) - insertToolbar.setVisible(False) - editor.addToolBar(Qt.ToolBarArea.TopToolBarArea, insertToolbar) - - table = build_button(insertToolbar, './Assets/icons/svg_table', " Table ", "Add a Table", False) + editor.insertToolbar = QToolBar() + editor.insertToolbar.setObjectName('insertToolbar') + editor.insertToolbar.setIconSize(QSize(18,18)) + editor.insertToolbar.setStyleSheet('height: 40px; spacing: 10px;') + editor.insertToolbar.setMovable(False) + editor.insertToolbar.setVisible(False) + editor.addToolBar(Qt.ToolBarArea.TopToolBarArea, editor.insertToolbar) + + table = build_button(editor.insertToolbar, './Assets/icons/svg_table', " Table ", "Add a Table", False) table.clicked.connect(editor.frameView.toolbar_table) - insertSpace = build_button(insertToolbar, './Assets/icons/svg_insert_space', "Insert Space", "Insert Space", False) + insertSpace = build_button(editor.insertToolbar, './Assets/icons/svg_insert_space', "Insert Space", "Insert Space", False) - screensnip = build_button(insertToolbar, './Assets/icons/svg_screensnip', " Screensnip ", "Screensnip", False) + screensnip = build_button(editor.insertToolbar, './Assets/icons/svg_screensnip', " Screensnip ", "Screensnip", False) screensnip.clicked.connect(editor.frameView.toolbar_snipScreen) - pictures = build_button(insertToolbar, './Assets/icons/svg_pictures', " Pictures ", "Pictures", False) + pictures = build_button(editor.insertToolbar, './Assets/icons/svg_pictures', " Pictures ", "Pictures", False) pictures.clicked.connect(editor.frameView.toolbar_pictures) - hyperlink = build_button(insertToolbar, './Assets/icons/svg_hyperlink', " Hyperlink ", "Hyperlink", False) + hyperlink = build_button(editor.insertToolbar, './Assets/icons/svg_hyperlink', " Hyperlink ", "Hyperlink", False) hyperlink.clicked.connect(editor.frameView.toolbar_hyperlink) - insertToolbar.addWidget(table) + editor.insertToolbar.addWidget(table) - insertToolbar.addSeparator() + editor.insertToolbar.addSeparator() - insertToolbar.addWidget(insertSpace) + editor.insertToolbar.addWidget(insertSpace) - insertToolbar.addSeparator() + editor.insertToolbar.addSeparator() - insertToolbar.addWidget(screensnip) - insertToolbar.addWidget(pictures) + editor.insertToolbar.addWidget(screensnip) + editor.insertToolbar.addWidget(pictures) - insertToolbar.addSeparator() + editor.insertToolbar.addSeparator() - insertToolbar.addWidget(hyperlink) - insertToolbar.addSeparator() + editor.insertToolbar.addWidget(hyperlink) + editor.insertToolbar.addSeparator() # drawToolbar code - drawToolbar = QToolBar() - drawToolbar.setObjectName('drawToolbar') - drawToolbar.setIconSize(QSize(16, 16)) - drawToolbar.setMovable(False) - drawToolbar.setVisible(False) - editor.addToolBar(Qt.ToolBarArea.TopToolBarArea, drawToolbar) - - undo = build_action(drawToolbar, './Assets/icons/svg_undo', "undo", "undo", False) + editor.drawToolbar = QToolBar() + editor.drawToolbar.setObjectName('drawToolbar') + editor.drawToolbar.setIconSize(QSize(18, 18)) + editor.drawToolbar.setStyleSheet('height: 40px; spacing: 10px;') + editor.drawToolbar.setMovable(False) + editor.drawToolbar.setVisible(False) + editor.addToolBar(Qt.ToolBarArea.TopToolBarArea, editor.drawToolbar) + + undo = build_action(editor.drawToolbar, './Assets/icons/svg_undo', "undo", "undo", False) undo.triggered.connect(editor.frameView.triggerUndo) - redo = build_action(drawToolbar, './Assets/icons/svg_redo', "redo", "redo", False) + redo = build_action(editor.drawToolbar, './Assets/icons/svg_redo', "redo", "redo", False) # redo.triggered.connect(editor.frameView.triggerRedo) - drawToolbar.addActions([undo, redo]) + editor.drawToolbar.addActions([undo, redo]) - drawToolbar.addSeparator() + editor.drawToolbar.addSeparator() + +def check_appearance(): + """Checks DARK/LIGHT mode of macos.""" + cmd = 'defaults read -g AppleInterfaceStyle' + p = subprocess.Popen(cmd, stdout=subprocess.PIPE, + stderr=subprocess.PIPE, shell=True) + return bool(p.communicate()[0]) + +def set_toolbar_visibility(editor, triggered_toolbar): + # Find all toolbars in the editor + toolbars = editor.findChildren(QToolBar) + + # Iterate over each toolbar + for toolbar in toolbars: + if toolbar.objectName() == triggered_toolbar: + # Toggle the visibility of the triggered toolbar + print(toolbar.objectName(),"visibility change") + toolbar.setVisible(not toolbar.isVisible()) + else: + # Hide all other toolbars + toolbar.setVisible(False) def openGetColorDialog(purpose): color = QColorDialog.getColor() diff --git a/Styles/styles.qss b/Styles/styles.qss index 76a3716..7e6a35b 100644 --- a/Styles/styles.qss +++ b/Styles/styles.qss @@ -1,24 +1,20 @@ +User * { border: none; padding: 0; margin: 0; - font-family: "Segoe UI"; - font-size: 16pt; + font-family: calibri, sans-serif; + font-size: 12pt; } QMainWindow { - background-color: rgb(230, 230, 236); + background-color: rgb(230,229,235); } QMenuBar { - background-color: rgb(119, 25, 170); + background-color: rgb(230,229,235); padding: 5px, 20px; - font-size: 10pt; - font-color: rgb(255, 255, 255); -} - -QMenuBar::item { - font-size: 10pt; + color: rgb(0, 0, 0); } QMenuBar::item:selected { @@ -26,8 +22,8 @@ QMenuBar::item:selected { } QToolBar { - font-size: 10pt; - padding: 10px, 30px; + + border-radius: 8px; background-color: rgb(255, 255, 255); } @@ -84,3 +80,4 @@ QPushButton#addPage { QPushButton#addPage::hover { background-color: #cecece; } + diff --git a/Views/EditorFrameView.py b/Views/EditorFrameView.py index b22ffb4..af2e2d3 100644 --- a/Views/EditorFrameView.py +++ b/Views/EditorFrameView.py @@ -205,7 +205,7 @@ def mousePressEvent(self, event): # Open context menu on right click if event.buttons() == Qt.RightButton: frame_menu = QMenu(self) - frame_menu.setStyleSheet("font-size: 11pt;") + # frame_menu.setStyleSheet("font-size: 11pt;") paste = QAction("Paste", editor) paste.triggered.connect(lambda: self.pasteWidget(event.pos())) From f204d234ae4f42f7d9c3c58e90d7e2d9b8010f04 Mon Sep 17 00:00:00 2001 From: ldeltastreaml <70774713+ldeltastreaml@users.noreply.github.com> Date: Sat, 9 Mar 2024 21:36:25 -0600 Subject: [PATCH 102/127] Date and Time button added + removed unnecessary buttons - Date & Time is a menu which makes a draggable container of the current date or time - strikethrough removed from right-click menu (not an intended button) - order menu removed as it is not fleshed out or working atm (commented out the addition of it to the rc menu) --- Assets/icons/svg_date.svg | 4 ++++ Assets/icons/svg_dateTime.svg | 4 ++++ Assets/icons/svg_time.svg | 15 +++++++++++++++ Models/DraggableContainer.py | 3 ++- Modules/BuildUI.py | 20 ++++++++++++++++++++ Views/EditorFrameView.py | 32 ++++++++++++++++++++++++++++++++ Widgets/Textbox.py | 4 ++-- 7 files changed, 79 insertions(+), 3 deletions(-) create mode 100644 Assets/icons/svg_date.svg create mode 100644 Assets/icons/svg_dateTime.svg create mode 100644 Assets/icons/svg_time.svg diff --git a/Assets/icons/svg_date.svg b/Assets/icons/svg_date.svg new file mode 100644 index 0000000..ec709e1 --- /dev/null +++ b/Assets/icons/svg_date.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Assets/icons/svg_dateTime.svg b/Assets/icons/svg_dateTime.svg new file mode 100644 index 0000000..8c47144 --- /dev/null +++ b/Assets/icons/svg_dateTime.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Assets/icons/svg_time.svg b/Assets/icons/svg_time.svg new file mode 100644 index 0000000..bfd356a --- /dev/null +++ b/Assets/icons/svg_time.svg @@ -0,0 +1,15 @@ + + + + time / 18 - time, clock, date, time icon + + + + + + + + + + + \ No newline at end of file diff --git a/Models/DraggableContainer.py b/Models/DraggableContainer.py index bd26695..653ad86 100644 --- a/Models/DraggableContainer.py +++ b/Models/DraggableContainer.py @@ -182,7 +182,8 @@ def buildDragContainerMenu(self): orderMenu.addAction(bringForwards) - menu.addMenu(orderMenu) + # not ready for deployment + # menu.addMenu(orderMenu) # text boxes if isinstance(self.childWidget, QTextBrowser): diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index 59613fc..57807fd 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -363,6 +363,24 @@ def build_toolbar(editor): hyperlink = build_button(editor.insertToolbar, './Assets/icons/svg_hyperlink', " Hyperlink ", "Hyperlink", False) hyperlink.clicked.connect(editor.frameView.toolbar_hyperlink) + + # date and time menu start + dateTime_menu = QMenu(editor) + + date = build_action(dateTime_menu, './Assets/icons/svg_date', "Date", "Date", False) + date.triggered.connect(editor.frameView.toolbar_date) + + time = build_action(dateTime_menu, './Assets/icons/svg_time', "Time", "Time", False) + time.triggered.connect(editor.frameView.toolbar_time) + + dateTime_menu.addActions([date, time]) + + # cant directly add numbering menu to homeToolbar so this is required + dateTime = QToolButton(editor) + dateTime.setIcon(QIcon('./Assets/icons/svg_dateTime')) + dateTime.setIconSize(QSize(18,18)) + dateTime.setPopupMode(QToolButton.InstantPopup) + dateTime.setMenu(dateTime_menu) editor.insertToolbar.addWidget(table) @@ -379,6 +397,8 @@ def build_toolbar(editor): editor.insertToolbar.addWidget(hyperlink) editor.insertToolbar.addSeparator() + + editor.insertToolbar.addWidget(dateTime) # drawToolbar code editor.drawToolbar = QToolBar() diff --git a/Views/EditorFrameView.py b/Views/EditorFrameView.py index af2e2d3..336d37e 100644 --- a/Views/EditorFrameView.py +++ b/Views/EditorFrameView.py @@ -260,6 +260,26 @@ def insertLink(self, clickPos): editorSignalsInstance.widgetAdded.emit(dc) editorSignalsInstance.changeMade.emit() + def insertDate(self, clickPos): + current_date = QDateTime.currentDateTime().toString("M/d/yyyy") + textboxWidget = TextboxWidget.new(clickPos) + textboxWidget.insertPlainText(current_date) + dc = DraggableContainer(textboxWidget, self) + dc.show() + self.undoHandler.pushCreate(dc) + editorSignalsInstance.widgetAdded.emit(dc) + editorSignalsInstance.changeMade.emit() + + def insertTime(self, clickPos): + current_time = QDateTime.currentDateTime().toString("h:mm AP") + textboxWidget = TextboxWidget.new(clickPos) + textboxWidget.insertPlainText(current_time) + dc = DraggableContainer(textboxWidget, self) + dc.show() + self.undoHandler.pushCreate(dc) + editorSignalsInstance.widgetAdded.emit(dc) + editorSignalsInstance.changeMade.emit() + def center_of_screen(self): editor_frame_geometry = self.editorFrame.geometry() print(f"editor_frame_geometry.width() is {editor_frame_geometry.width()}") @@ -293,6 +313,18 @@ def toolbar_hyperlink(self): clickPos = QPoint(center_x, center_y) self.insertLink(clickPos) + def toolbar_date(self): + print("toolbar_date pressed") + center_x, center_y = self.center_of_screen() + clickPos = QPoint(center_x, center_y) + self.insertDate(clickPos) + + def toolbar_time(self): + print("toolbar_time pressed") + center_x, center_y = self.center_of_screen() + clickPos = QPoint(center_x, center_y) + self.insertTime(clickPos) + def addCustomWidget(self, e): def getCustomWidgets(): customWidgets = {} # dict where entries are {name: class} diff --git a/Widgets/Textbox.py b/Widgets/Textbox.py index 7a4cd2e..1ed926e 100644 --- a/Widgets/Textbox.py +++ b/Widgets/Textbox.py @@ -149,7 +149,7 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): ) strikethrough = build_action( - toolbarBottom,"./Assets/icons/svg_strikethrough", "Srikethrough", "Srikethrough", True + toolbarBottom,"./Assets/icons/svg_strikethrough", "Strikethrough", "Strikethrough", True ) strikethrough.toggled.connect(lambda: self.setStrikeOut()) @@ -200,7 +200,7 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): bold, italic, underline, - strikethrough, + # strikethrough, textHighlightColor, fontColor, bullets From ec432db37be732a53ff5bdf7472f9b5b677e5240 Mon Sep 17 00:00:00 2001 From: ldeltastreaml <70774713+ldeltastreaml@users.noreply.github.com> Date: Sat, 9 Mar 2024 22:32:12 -0600 Subject: [PATCH 103/127] Reworked Titlebar UI + New build def - Titlebar UI reworked again (I know...) - Added build_menubutton and build_titlebutton for quick and easy assignments for both (still need text to show up on the right of menubutton icon) --- Assets/White-OpenNoteLogo.svg | 14 ++++ Assets/icons/svg_close.svg | 7 ++ Assets/icons/svg_fullscreen.svg | 1 + Assets/icons/svg_tray.svg | 7 ++ Assets/icons/svg_windowed.svg | 7 ++ Modules/BuildUI.py | 126 +++++++++++++------------------- 6 files changed, 86 insertions(+), 76 deletions(-) create mode 100644 Assets/White-OpenNoteLogo.svg create mode 100644 Assets/icons/svg_close.svg create mode 100644 Assets/icons/svg_fullscreen.svg create mode 100644 Assets/icons/svg_tray.svg create mode 100644 Assets/icons/svg_windowed.svg diff --git a/Assets/White-OpenNoteLogo.svg b/Assets/White-OpenNoteLogo.svg new file mode 100644 index 0000000..591dcf6 --- /dev/null +++ b/Assets/White-OpenNoteLogo.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/Assets/icons/svg_close.svg b/Assets/icons/svg_close.svg new file mode 100644 index 0000000..e25249d --- /dev/null +++ b/Assets/icons/svg_close.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/Assets/icons/svg_fullscreen.svg b/Assets/icons/svg_fullscreen.svg new file mode 100644 index 0000000..85586d2 --- /dev/null +++ b/Assets/icons/svg_fullscreen.svg @@ -0,0 +1 @@ + diff --git a/Assets/icons/svg_tray.svg b/Assets/icons/svg_tray.svg new file mode 100644 index 0000000..d4b9c8f --- /dev/null +++ b/Assets/icons/svg_tray.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/Assets/icons/svg_windowed.svg b/Assets/icons/svg_windowed.svg new file mode 100644 index 0000000..3a39a6c --- /dev/null +++ b/Assets/icons/svg_windowed.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index 57807fd..087ba03 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -88,7 +88,6 @@ def build_ui(editor): #editor.restoreGeometry(editor.settings.value("geometry", editor.saveGeometry())) #editor.restoreState(editor.settings.value("windowState", editor.saveState())) - class build_titlebar(QWidget): def __init__(self, parent): super().__init__(parent) @@ -97,14 +96,16 @@ def __init__(self, parent): self.setStyleSheet( """ background-color: rgb(119, 25, 170); - height: 50px; """ ) self.initial_pos = None - title_bar_layout = QHBoxLayout(self) - title_bar_layout.setContentsMargins(0, 0, 0, 0) - title_bar_layout.setSpacing(0) + titlebarLayout = QHBoxLayout(self) + titlebarLayout.setContentsMargins(0, 0, 0, 0) + titlebarLayout.setSpacing(0) + + self.logo = build_titlebutton('./Assets/White-OpenNoteLogo', None) + titlebarLayout.addWidget(self.logo) self.title = QLabel(f"{self.__class__.__name__}", self) self.title.setStyleSheet( @@ -115,65 +116,27 @@ def __init__(self, parent): self.title.setAlignment(Qt.AlignmentFlag.AlignCenter) if title := parent.windowTitle(): self.title.setText(title) - title_bar_layout.addWidget(self.title) - - # Min button - self.min_button = QToolButton(self) - min_icon = self.style().standardIcon( - QStyle.StandardPixmap.SP_TitleBarMinButton - ) - self.min_button.setIcon(min_icon) - self.min_button.clicked.connect(self.window().showMinimized) - - # Max button - self.max_button = QToolButton(self) - max_icon = self.style().standardIcon( - QStyle.StandardPixmap.SP_TitleBarMaxButton - ) - self.max_button.setIcon(max_icon) - self.max_button.clicked.connect(self.window().showMaximized) - - # Close button - self.close_button = QToolButton(self) - close_icon = self.style().standardIcon( - QStyle.StandardPixmap.SP_TitleBarCloseButton - ) - self.close_button.setIcon(close_icon) - self.close_button.clicked.connect(self.window().close) + titlebarLayout.addWidget(self.title) - # Normal button - self.normal_button = QToolButton(self) - normal_icon = self.style().standardIcon( - QStyle.StandardPixmap.SP_TitleBarNormalButton - ) - self.normal_button.setIcon(normal_icon) - self.normal_button.clicked.connect(self.window().showNormal) - self.normal_button.setVisible(False) + self.tray = build_titlebutton('./Assets/icons/svg_tray', self.window().showMinimized) + self.windowed = build_titlebutton('./Assets/icons/svg_windowed', self.window().showMaximized) + self.close = build_titlebutton('./Assets/icons/svg_close', self.window().close) + self.fullscreen = build_titlebutton('./Assets/icons/svg_fullscreen', self.window().showNormal) + self.fullscreen.setVisible(False) + + titlebarLayout.addWidget(self.tray) + titlebarLayout.addWidget(self.fullscreen) + titlebarLayout.addWidget(self.windowed) + titlebarLayout.addWidget(self.close) - # Add buttons - buttons = [ - self.min_button, - self.normal_button, - self.max_button, - self.close_button, - ] - for button in buttons: - button.setFocusPolicy(Qt.FocusPolicy.NoFocus) - button.setFixedSize(QSize(28, 28)) - button.setStyleSheet( - """QToolButton { color: white; - } - """ - ) - title_bar_layout.addWidget(button) - def window_state_changed(self, state): if state == Qt.WindowMaximized: - self.normal_button.setVisible(True) - self.max_button.setVisible(False) + self.fullscreen.setVisible(True) + self.windowed.setVisible(False) else: - self.normal_button.setVisible(False) - self.max_button.setVisible(True) + self.fullscreen.setVisible(False) + self.windowed.setVisible(True) + def build_menubar(editor): editor.menubar = editor.menuBar() @@ -313,14 +276,9 @@ def build_toolbar(editor): bulletUpperR.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.BulletUR, None)) numbering_menu.addActions([bullet_num, bulletUpperA, bulletUpperR]) - - # cant directly add numbering menu to homeToolbar so this is required - numbering = QToolButton(editor) - numbering.setIcon(QIcon('./Assets/icons/svg_bullet_number')) - numbering.setIconSize(QSize(18,18)) - numbering.setPopupMode(QToolButton.InstantPopup) - numbering.setMenu(numbering_menu) + numbering = build_menubutton(editor, './Assets/icons/svg_bullet_number', "", "Numbering", numbering_menu) + editor.homeToolbar.addWidget(numbering) # QActionGroup used to display that only one can be toggled at a time @@ -374,13 +332,9 @@ def build_toolbar(editor): time.triggered.connect(editor.frameView.toolbar_time) dateTime_menu.addActions([date, time]) - - # cant directly add numbering menu to homeToolbar so this is required - dateTime = QToolButton(editor) - dateTime.setIcon(QIcon('./Assets/icons/svg_dateTime')) - dateTime.setIconSize(QSize(18,18)) - dateTime.setPopupMode(QToolButton.InstantPopup) - dateTime.setMenu(dateTime_menu) + + dateTime = build_menubutton(editor, './Assets/icons/svg_dateTime', "Date & Time", "Date & Time", dateTime_menu) + editor.insertToolbar.addWidget(table) @@ -448,10 +402,10 @@ def openGetColorDialog(purpose): elif purpose == "background": editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.BackgroundColor, color) -def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): +def build_action(parent, icon_path, action_name, tooltip, checkable): action = QAction(QIcon(icon_path), action_name, parent) - action.setStatusTip(set_status_tip) - action.setCheckable(set_checkable) + action.setStatusTip(tooltip) + action.setCheckable(checkable) return action def build_button(parent, icon_path, text, tooltip, checkable): @@ -461,3 +415,23 @@ def build_button(parent, icon_path, text, tooltip, checkable): button.setToolTip(tooltip) button.setCheckable(checkable) return button + +def build_menubutton(parent, icon_path, text, tooltip, menu): + button = QToolButton(parent) + button.setIcon(QIcon(icon_path)) + button.setIconSize(QSize(18,18)) + button.setToolButtonStyle(Qt.ToolButtonTextBesideIcon) + button.setText(text) + button.setToolTip(tooltip) + button.setPopupMode(QToolButton.InstantPopup) + button.setMenu(menu) + return button + +def build_titlebutton(icon_path, on_click): + button = QToolButton() + button.setIcon(QIcon(icon_path)) + button.clicked.connect(on_click) + button.setFocusPolicy(Qt.FocusPolicy.NoFocus) + button.setFixedSize(QSize(42, 42)) + button.setStyleSheet("QToolButton { border: none; padding: 0px;}") + return button From a59ed262d8c58851a4abc12346588dc1b22d37d6 Mon Sep 17 00:00:00 2001 From: ldeltastreaml <70774713+ldeltastreaml@users.noreply.github.com> Date: Sat, 9 Mar 2024 23:35:34 -0600 Subject: [PATCH 104/127] Added style to menubutton - allows menubuttons be styled when build_menubutton is called (also fixed numbering and Date & Time sizing!) --- Modules/BuildUI.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index 087ba03..baa97c2 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -277,7 +277,7 @@ def build_toolbar(editor): numbering_menu.addActions([bullet_num, bulletUpperA, bulletUpperR]) - numbering = build_menubutton(editor, './Assets/icons/svg_bullet_number', "", "Numbering", numbering_menu) + numbering = build_menubutton(editor, './Assets/icons/svg_bullet_number', "", "Numbering", "width:35px;", numbering_menu) editor.homeToolbar.addWidget(numbering) @@ -333,8 +333,7 @@ def build_toolbar(editor): dateTime_menu.addActions([date, time]) - dateTime = build_menubutton(editor, './Assets/icons/svg_dateTime', "Date & Time", "Date & Time", dateTime_menu) - + dateTime = build_menubutton(editor, './Assets/icons/svg_dateTime', "Date && Time", "Date & Time", "width:120px;", dateTime_menu) editor.insertToolbar.addWidget(table) @@ -416,14 +415,15 @@ def build_button(parent, icon_path, text, tooltip, checkable): button.setCheckable(checkable) return button -def build_menubutton(parent, icon_path, text, tooltip, menu): +def build_menubutton(parent, icon_path, text, tooltip, style, menu): button = QToolButton(parent) - button.setIcon(QIcon(icon_path)) button.setIconSize(QSize(18,18)) button.setToolButtonStyle(Qt.ToolButtonTextBesideIcon) + button.setPopupMode(QToolButton.MenuButtonPopup) + button.setIcon(QIcon(icon_path)) button.setText(text) button.setToolTip(tooltip) - button.setPopupMode(QToolButton.InstantPopup) + button.setStyleSheet(style) button.setMenu(menu) return button From ac5a314d1cfb220a2a561924742f94a3f02b7968 Mon Sep 17 00:00:00 2001 From: ldeltastreaml <70774713+ldeltastreaml@users.noreply.github.com> Date: Fri, 15 Mar 2024 01:57:04 -0500 Subject: [PATCH 105/127] Fleshed Out Titlebar and More - Really clean titlebar with search bar that is more or less centered ;-; - qss restyling - all buttons that benefit from icons should have them now --- Assets/icons/svg_add_page.svg | 11 +++ Assets/icons/svg_delete.svg | 7 ++ Assets/icons/svg_fullscreen.svg | 8 +- Assets/icons/svg_rename.svg | 2 + Assets/icons/svg_search.svg | 1 + Assets/icons/svg_windowed.svg | 8 +- Models/Editor.py | 46 ++++++---- Models/PageModel.py | 2 +- Modules/BuildUI.py | 158 +++++++++++++------------------- Modules/Titlebar.py | 147 +++++++++++++++++++++++++++++ Styles/styles.qss | 76 +++++++++++---- Views/PageView.py | 60 +++++++----- Views/SectionView.py | 11 ++- 13 files changed, 377 insertions(+), 160 deletions(-) create mode 100644 Assets/icons/svg_add_page.svg create mode 100644 Assets/icons/svg_delete.svg create mode 100644 Assets/icons/svg_rename.svg create mode 100644 Assets/icons/svg_search.svg create mode 100644 Modules/Titlebar.py diff --git a/Assets/icons/svg_add_page.svg b/Assets/icons/svg_add_page.svg new file mode 100644 index 0000000..548f706 --- /dev/null +++ b/Assets/icons/svg_add_page.svg @@ -0,0 +1,11 @@ + + + + + + + + + + \ No newline at end of file diff --git a/Assets/icons/svg_delete.svg b/Assets/icons/svg_delete.svg new file mode 100644 index 0000000..dec5ed3 --- /dev/null +++ b/Assets/icons/svg_delete.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/Assets/icons/svg_fullscreen.svg b/Assets/icons/svg_fullscreen.svg index 85586d2..3a39a6c 100644 --- a/Assets/icons/svg_fullscreen.svg +++ b/Assets/icons/svg_fullscreen.svg @@ -1 +1,7 @@ - + + + + + + + \ No newline at end of file diff --git a/Assets/icons/svg_rename.svg b/Assets/icons/svg_rename.svg new file mode 100644 index 0000000..f64df38 --- /dev/null +++ b/Assets/icons/svg_rename.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Assets/icons/svg_search.svg b/Assets/icons/svg_search.svg new file mode 100644 index 0000000..a19fb2a --- /dev/null +++ b/Assets/icons/svg_search.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Assets/icons/svg_windowed.svg b/Assets/icons/svg_windowed.svg index 3a39a6c..6bde8f2 100644 --- a/Assets/icons/svg_windowed.svg +++ b/Assets/icons/svg_windowed.svg @@ -1,7 +1 @@ - - - - - - - \ No newline at end of file + diff --git a/Models/Editor.py b/Models/Editor.py index dca2f8e..b99263b 100644 --- a/Models/Editor.py +++ b/Models/Editor.py @@ -13,6 +13,7 @@ from Views.EditorFrameView import EditorFrameView from Views.NotebookTitleView import NotebookTitleView from Views.SectionView import SectionView +from Modules.Titlebar import Build_titlebar class Editor(QMainWindow): @@ -23,6 +24,7 @@ def __init__(self): # self.selected = None # Selected object (for font attributes of TextBox) # View-Controllers that let the user interact with the underlying models + self.titlebar = Build_titlebar(self) self.notebookTitleView = NotebookTitleView(self.notebook.title) self.frameView = EditorFrameView(self) self.pageView = PageView(self.notebook.pages) @@ -34,6 +36,8 @@ def __init__(self): self.settings = QSettings("UNT - Team Olive", "OpenNote") build_ui(self) + action_names = self.save_toolbar_actions([self.homeToolbar, self.insertToolbar, self.drawToolbar]) + self.titlebar.set_action_names(action_names) def closeEvent(self, event): # Save window size and position before exiting @@ -52,9 +56,9 @@ def showEvent(self, event): self.restoreGeometry(self.settings.value("geometry", self.saveGeometry())) self.restoreState(self.settings.value("windowState", self.saveState())) super().showEvent(event) + # def focusInEvent(self, event): # self.repaint() - def changeEvent(self, event): if event.type() == QEvent.Type.WindowStateChange: self.titlebar.window_state_changed(self.windowState()) @@ -62,22 +66,28 @@ def changeEvent(self, event): event.accept() def mousePressEvent(self, event): - if event.button() == Qt.MouseButton.LeftButton: - self.initial_pos = event.position().toPoint() - super().mousePressEvent(event) - event.accept() + if event.button() == Qt.LeftButton: + self.moveFlag = True + self.movePosition = event.globalPos() - self.pos() + event.accept() def mouseMoveEvent(self, event): - if self.initial_pos is not None: - delta = event.position().toPoint() - self.initial_pos - self.window().move( - self.window().x() + delta.x(), - self.window().y() + delta.y(), - ) - super().mouseMoveEvent(event) - event.accept() - - def mouseReleaseEvent(self, event): - self.initial_pos = None - super().mouseReleaseEvent(event) - event.accept() + if Qt.LeftButton and self.moveFlag: + self.move(event.globalPos() - self.movePosition) + event.accept() + + def mouseReleaseEvent(self, QMouseEvent): + self.moveFlag = False + + def save_toolbar_actions(self, toolbars): + action_names = [] + for toolbar in toolbars: + for action in toolbar.actions(): + if action.objectName(): + action_names.append(action.objectName()) + + for widget in toolbar.findChildren(QPushButton) + toolbar.findChildren(QToolButton) + toolbar.findChildren(QComboBox): + if widget.objectName() and widget.objectName() != "qt_toolbar_ext_button": + action_names.append(widget.objectName()) + + return action_names \ No newline at end of file diff --git a/Models/PageModel.py b/Models/PageModel.py index 2643010..06b426d 100644 --- a/Models/PageModel.py +++ b/Models/PageModel.py @@ -12,7 +12,7 @@ def __init__(self, title: str, parentUuid: int = 0): @staticmethod def newRootPage(): - rootPage = PageModel("Notebook Pages") + rootPage = PageModel("Notebook") rootPage.__uuid = 0 return rootPage diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index baa97c2..268d8fe 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -3,6 +3,7 @@ from PySide6.QtCore import * from PySide6.QtGui import * +from PySide6.QtSvg import * from PySide6.QtWidgets import * from Models.DraggableContainer import DraggableContainer @@ -32,14 +33,13 @@ def build_ui(editor): with open('./Styles/stylesDark.qss',"r") as fh: editor.setStyleSheet(fh.read()) - editor.titlebar = build_titlebar(editor) build_menubar(editor) build_toolbar(editor) # Main layout of the app gridLayout = QGridLayout() - gridLayout.setSpacing(3) - gridLayout.setContentsMargins(6, 6, 0, 0) + gridLayout.setSpacing(0) + gridLayout.setContentsMargins(0, 0, 0, 0) gridLayout.setColumnStretch(1, 7) centralWidget = QWidget() @@ -52,11 +52,23 @@ def build_ui(editor): topSideLayout.setContentsMargins(0, 0, 0, 0) topSideLayout.setSpacing(0) + barsLayout = QVBoxLayout() + barsLayoutContainerWidget = QWidget() + barsLayoutContainerWidget.setLayout(barsLayout) + barsLayout.setContentsMargins(7, 0, 7, 0) + barsLayout.setSpacing(0) + + # Add the bars to the layout with individual margins + barsLayout.addWidget(editor.menubar) + barsLayout.addWidget(editor.homeToolbar) + barsLayout.addWidget(editor.insertToolbar) + barsLayout.addWidget(editor.drawToolbar) + topSideLayout.addWidget(editor.titlebar, 0) - topSideLayout.addWidget(editor.menubar, 1) - topSideLayout.addWidget(editor.homeToolbar, 2) - topSideLayout.addWidget(editor.insertToolbar, 2) - topSideLayout.addWidget(editor.drawToolbar, 2) + topSideLayout.addWidget(barsLayoutContainerWidget, 1) + # topSideLayout.addWidget(editor.homeToolbar, 2) + # topSideLayout.addWidget(editor.insertToolbar, 2) + # topSideLayout.addWidget(editor.drawToolbar, 2) # Sets up left side notebook view leftSideLayout = QVBoxLayout() @@ -88,56 +100,6 @@ def build_ui(editor): #editor.restoreGeometry(editor.settings.value("geometry", editor.saveGeometry())) #editor.restoreState(editor.settings.value("windowState", editor.saveState())) -class build_titlebar(QWidget): - def __init__(self, parent): - super().__init__(parent) - self.setAutoFillBackground(True) - self.setBackgroundRole(QPalette.ColorRole.Highlight) - self.setStyleSheet( - """ - background-color: rgb(119, 25, 170); - """ - ) - self.initial_pos = None - - titlebarLayout = QHBoxLayout(self) - titlebarLayout.setContentsMargins(0, 0, 0, 0) - titlebarLayout.setSpacing(0) - - self.logo = build_titlebutton('./Assets/White-OpenNoteLogo', None) - titlebarLayout.addWidget(self.logo) - - self.title = QLabel(f"{self.__class__.__name__}", self) - self.title.setStyleSheet( - """ - color: white; - """ - ) - self.title.setAlignment(Qt.AlignmentFlag.AlignCenter) - if title := parent.windowTitle(): - self.title.setText(title) - titlebarLayout.addWidget(self.title) - - self.tray = build_titlebutton('./Assets/icons/svg_tray', self.window().showMinimized) - self.windowed = build_titlebutton('./Assets/icons/svg_windowed', self.window().showMaximized) - self.close = build_titlebutton('./Assets/icons/svg_close', self.window().close) - self.fullscreen = build_titlebutton('./Assets/icons/svg_fullscreen', self.window().showNormal) - self.fullscreen.setVisible(False) - - titlebarLayout.addWidget(self.tray) - titlebarLayout.addWidget(self.fullscreen) - titlebarLayout.addWidget(self.windowed) - titlebarLayout.addWidget(self.close) - - def window_state_changed(self, state): - if state == Qt.WindowMaximized: - self.fullscreen.setVisible(True) - self.windowed.setVisible(False) - else: - self.fullscreen.setVisible(False) - self.windowed.setVisible(True) - - def build_menubar(editor): editor.menubar = editor.menuBar() @@ -186,27 +148,37 @@ def build_toolbar(editor): editor.homeToolbar.setObjectName('homeToolbar') editor.homeToolbar.setIconSize(QSize(18, 18)) editor.homeToolbar.setMovable(False) - editor.homeToolbar.setStyleSheet('height: 40px; spacing: 10px;') + editor.homeToolbar.setFixedHeight(40) editor.addToolBar(Qt.ToolBarArea.TopToolBarArea, editor.homeToolbar) - #separates toolbar with a line break - spacer = QWidget() - spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) + # For adding space to the left the first button added to a toolbar + spacer1 = QWidget() + spacer1.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) + spacer1.setFixedWidth(3) + + spacer2 = QWidget() + spacer2.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) + spacer2.setFixedWidth(7) + + spacer3 = QWidget() + spacer3.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) + spacer3.setFixedWidth(3) - cut = build_action(editor.homeToolbar, './Assets/icons/svg_cut', "cut", "cut", False) - cut.triggered.connect(editor.frameView.cutWidgetEvent) + cut = build_action(editor.homeToolbar, './Assets/icons/svg_cut', "Cut", "Cut", False) + cut.triggered.connect(lambda: editorSignalsInstance.widgetCut.emit(DraggableContainer)) - copy = build_action(editor.homeToolbar, './Assets/icons/svg_copy', "copy", "copy", False) - copy.triggered.connect(editor.frameView.copyWidgetEvent) - + copy = build_action(editor.homeToolbar, './Assets/icons/svg_copy', "Copy", "Copy", False) + copy.triggered.connect(lambda: editorSignalsInstance.widgetCopied.emit()) font_family = QFontComboBox() + font_family.setObjectName("Font") font_family.setFixedWidth(150) default_font = font_family.currentFont().family() print(f"default font is {default_font}") font_family.currentFontChanged.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Font, font_family.currentFont().family())) font_size = QComboBox() + font_size.setObjectName("Font Size") font_size.setFixedWidth(50) font_size.addItems([str(fs) for fs in FONT_SIZES]) # default text size is 11 @@ -243,13 +215,14 @@ def build_toolbar(editor): strikethrough = build_action(editor.homeToolbar, './Assets/icons/svg_strikethrough.svg', "Strikethrough", "Strikethrough", True) strikethrough.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Strikethrough, None)) + delete = build_action(editor.homeToolbar, './Assets/icons/svg_delete', "Delete", "Delete", False) + delete.triggered.connect(lambda: editorSignalsInstance.widgetRemoved.emit(DraggableContainer)) + # Bullets with placeholder for more bullet options bullet = build_action(editor.homeToolbar, './Assets/icons/svg_bullets', "Bullets", "Bullets", False) bullet.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Bullet, None)) - paperColor= build_action(editor.homeToolbar, './Assets/icons/svg_paper', "Paper Color", "Paper Color", False) - paperColor.triggered.connect(lambda: editor.frameView.pageColor(QColorDialog.getColor())) - + editor.homeToolbar.addWidget(spacer1) editor.homeToolbar.addActions([cut, copy]) editor.homeToolbar.addSeparator() @@ -259,8 +232,7 @@ def build_toolbar(editor): editor.homeToolbar.addSeparator() - editor.homeToolbar.addActions([bold, italic, underline, strikethrough, fontColor, textHighlightColor, bgColor, paperColor, bullet]) - + editor.homeToolbar.addActions([bold, italic, underline, strikethrough, fontColor, textHighlightColor, bgColor, delete, bullet]) # numbering menu start numbering_menu = QMenu(editor) @@ -298,28 +270,27 @@ def build_toolbar(editor): editor.homeToolbar.addSeparator() - # insertToolbar code editor.insertToolbar = QToolBar() editor.insertToolbar.setObjectName('insertToolbar') editor.insertToolbar.setIconSize(QSize(18,18)) - editor.insertToolbar.setStyleSheet('height: 40px; spacing: 10px;') + editor.insertToolbar.setFixedHeight(40) editor.insertToolbar.setMovable(False) editor.insertToolbar.setVisible(False) editor.addToolBar(Qt.ToolBarArea.TopToolBarArea, editor.insertToolbar) - - table = build_button(editor.insertToolbar, './Assets/icons/svg_table', " Table ", "Add a Table", False) + + table = build_button(editor.insertToolbar, './Assets/icons/svg_table', "Table", "Add a Table", False) table.clicked.connect(editor.frameView.toolbar_table) insertSpace = build_button(editor.insertToolbar, './Assets/icons/svg_insert_space', "Insert Space", "Insert Space", False) - screensnip = build_button(editor.insertToolbar, './Assets/icons/svg_screensnip', " Screensnip ", "Screensnip", False) + screensnip = build_button(editor.insertToolbar, './Assets/icons/svg_screensnip', "Screensnip", "Screensnip", False) screensnip.clicked.connect(editor.frameView.toolbar_snipScreen) - pictures = build_button(editor.insertToolbar, './Assets/icons/svg_pictures', " Pictures ", "Pictures", False) + pictures = build_button(editor.insertToolbar, './Assets/icons/svg_pictures', "Pictures" , "Pictures", False) pictures.clicked.connect(editor.frameView.toolbar_pictures) - hyperlink = build_button(editor.insertToolbar, './Assets/icons/svg_hyperlink', " Hyperlink ", "Hyperlink", False) + hyperlink = build_button(editor.insertToolbar, './Assets/icons/svg_hyperlink', "Hyperlink", "Hyperlink", False) hyperlink.clicked.connect(editor.frameView.toolbar_hyperlink) # date and time menu start @@ -335,6 +306,8 @@ def build_toolbar(editor): dateTime = build_menubutton(editor, './Assets/icons/svg_dateTime', "Date && Time", "Date & Time", "width:120px;", dateTime_menu) + editor.insertToolbar.addWidget(spacer2) + editor.insertToolbar.addWidget(table) editor.insertToolbar.addSeparator() @@ -349,6 +322,7 @@ def build_toolbar(editor): editor.insertToolbar.addSeparator() editor.insertToolbar.addWidget(hyperlink) + editor.insertToolbar.addSeparator() editor.insertToolbar.addWidget(dateTime) @@ -357,21 +331,27 @@ def build_toolbar(editor): editor.drawToolbar = QToolBar() editor.drawToolbar.setObjectName('drawToolbar') editor.drawToolbar.setIconSize(QSize(18, 18)) - editor.drawToolbar.setStyleSheet('height: 40px; spacing: 10px;') + editor.drawToolbar.setFixedHeight(40) editor.drawToolbar.setMovable(False) editor.drawToolbar.setVisible(False) editor.addToolBar(Qt.ToolBarArea.TopToolBarArea, editor.drawToolbar) - undo = build_action(editor.drawToolbar, './Assets/icons/svg_undo', "undo", "undo", False) + undo = build_action(editor.drawToolbar, './Assets/icons/svg_undo', "Undo", "Undo", False) undo.triggered.connect(editor.frameView.triggerUndo) - redo = build_action(editor.drawToolbar, './Assets/icons/svg_redo', "redo", "redo", False) + redo = build_action(editor.drawToolbar, './Assets/icons/svg_redo', "Redo", "Redo", False) # redo.triggered.connect(editor.frameView.triggerRedo) - + + paperColor= build_action(editor.drawToolbar, './Assets/icons/svg_paper', "Paper Color", "Paper Color", False) + paperColor.triggered.connect(lambda: editor.frameView.pageColor(QColorDialog.getColor())) + + editor.drawToolbar.addWidget(spacer3) editor.drawToolbar.addActions([undo, redo]) editor.drawToolbar.addSeparator() + editor.drawToolbar.addAction(paperColor) + def check_appearance(): """Checks DARK/LIGHT mode of macos.""" cmd = 'defaults read -g AppleInterfaceStyle' @@ -403,6 +383,7 @@ def openGetColorDialog(purpose): def build_action(parent, icon_path, action_name, tooltip, checkable): action = QAction(QIcon(icon_path), action_name, parent) + action.setObjectName(action_name) action.setStatusTip(tooltip) action.setCheckable(checkable) return action @@ -410,6 +391,7 @@ def build_action(parent, icon_path, action_name, tooltip, checkable): def build_button(parent, icon_path, text, tooltip, checkable): button = QPushButton(parent) button.setIcon(QIcon(icon_path)) + button.setObjectName(text) button.setText(text) button.setToolTip(tooltip) button.setCheckable(checkable) @@ -423,15 +405,7 @@ def build_menubutton(parent, icon_path, text, tooltip, style, menu): button.setIcon(QIcon(icon_path)) button.setText(text) button.setToolTip(tooltip) + button.setObjectName(tooltip) button.setStyleSheet(style) button.setMenu(menu) - return button - -def build_titlebutton(icon_path, on_click): - button = QToolButton() - button.setIcon(QIcon(icon_path)) - button.clicked.connect(on_click) - button.setFocusPolicy(Qt.FocusPolicy.NoFocus) - button.setFixedSize(QSize(42, 42)) - button.setStyleSheet("QToolButton { border: none; padding: 0px;}") - return button + return button \ No newline at end of file diff --git a/Modules/Titlebar.py b/Modules/Titlebar.py new file mode 100644 index 0000000..383c218 --- /dev/null +++ b/Modules/Titlebar.py @@ -0,0 +1,147 @@ +from PySide6.QtCore import * +from PySide6.QtGui import * +from PySide6.QtSvg import * +from PySide6.QtWidgets import * + +from Models.DraggableContainer import DraggableContainer +from Widgets.Textbox import * + +from Modules.BuildUI import * +from Modules.EditorSignals import editorSignalsInstance, ChangedWidgetAttribute +from Modules.Undo import UndoHandler + +from Views.EditorFrameView import * + +class Build_titlebar(QWidget): + def __init__(self, parent): + super().__init__(parent) + print("Building Titlebar") + self.setAutoFillBackground(True) + self.setBackgroundRole(QPalette.ColorRole.Highlight) + self.setFixedHeight(49) + self.setObjectName("titlebar") + # self.setStyleSheet("background-color: rgb(119, 25, 170);") + self.initial_pos = None + + titlebarLayout = QHBoxLayout(self) + titlebarLayout.setContentsMargins(0, 0, 0, 0) + titlebarLayout.setSpacing(0) + + self.logo = build_titlebutton('./Assets/White-OpenNoteLogo', "logo", None) + self.logo.setFixedSize(QSize(49, 49)) + + self.title = QLabel("OpenNote", self) + self.title.setStyleSheet("color: white;") + self.title.setAlignment(Qt.AlignmentFlag.AlignCenter) + self.title.setMaximumWidth(parent.width() // 5.5) + if title := parent.windowTitle(): + self.title.setText(title) + + self.leftSpacer = QWidget(self) + self.leftSpacer.setMinimumWidth(parent.width() // 5.5) + + # Search bar + self.searchbarWidget = QWidget(self) + self.searchbarLayout = QVBoxLayout() + self.searchbarWidget.setLayout(self.searchbarLayout) + self.searchbarWidget.setObjectName("searchbarWidget") + self.searchbarLayout.setAlignment(Qt.AlignmentFlag.AlignCenter) + + self.searchbar = QLineEdit(self) + self.searchbar.setClearButtonEnabled(True) + self.searchbar.addAction(QIcon("./Assets/Icons/svg_search"), QLineEdit.LeadingPosition) + self.searchbar.setMaximumWidth(parent.width() // 2) + self.searchbar.setPlaceholderText("Search") + self.searchbar.returnPressed.connect(self.perform_search) + self.searchbarLayout.addWidget(self.searchbar) + + self.rightSpacer = QWidget(self) + self.rightSpacer.setMinimumWidth(parent.width() // 6) + + # the names for windowed and fullscreen might be swapped, but it works how it should so 👍 + self.tray = build_titlebutton('./Assets/icons/svg_tray', "tray", self.window().showMinimized) + # self.windowed = build_titlebutton('./Assets/icons/svg_windowed', "windowed", self.windowed_window) + # self.fullscreen = build_titlebutton('./Assets/icons/svg_fullscreen', "fullscreen", self.fullscreen_window) + self.windowed = build_titlebutton('./Assets/icons/svg_windowed', "windowed", self.window().showNormal) + self.fullscreen = build_titlebutton('./Assets/icons/svg_fullscreen', "fullscreen", self.window().showMaximized) + + self.close = build_titlebutton('./Assets/icons/svg_close', "close", self.window().close) + + titlebarLayout.addWidget(self.logo) + + titlebarLayout.addWidget(self.title) + + titlebarLayout.addWidget(self.leftSpacer) + + titlebarLayout.addWidget(self.searchbarWidget) + + titlebarLayout.addWidget(self.rightSpacer) + + titlebarLayout.addWidget(self.tray) + titlebarLayout.addWidget(self.windowed) + titlebarLayout.addWidget(self.fullscreen) + titlebarLayout.addWidget(self.close) + + def window_state_changed(self, state): + self.windowed.setVisible(state != Qt.WindowState.WindowNoState) + self.fullscreen.setVisible(state == Qt.WindowState.WindowNoState) + + def set_action_names(self, action_names): + # Populate the completer with search suggestions + self.search_suggestions = action_names + completer = QCompleter(self.search_suggestions) + completer.setCaseSensitivity(Qt.CaseInsensitive) + self.searchbar.setCompleter(completer) + + def perform_search(self): + search_text = self.searchbar.text().lower() + + # Dictionary mapping search keywords to corresponding actions + actions = { + "cut": lambda: None, + "copy": lambda: None, + "paste": lambda: None, + "font": lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Font, font_family.currentFont().family()), + "font size": lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontSize, int(font_size.currentText())), + "bold": lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontBold, None), + "italic": lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontItalic, None), + "underline": lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontUnderline, None), + "font color": lambda: openGetColorDialog(purpose = "font"), + "text highlight color": lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.TextHighlightColor, QColorDialog.getColor()), + "strikethrough": lambda: lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Strikethrough, None), + "background color": lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.BackgroundColor, QColorDialog.getColor()), + "delete": lambda: None, + "bullets": lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Bullet, None), + "numbering": None, # QMenu lambda call??? + "align left": lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.AlignLeft, None), + "align center": lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.AlignCenter, None), + "align right": lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.AlignRight, None), + "table": None, # editor.frameView.toolbar_table + "insert space": None, + "screensnip": None, # editor.frameView.toolbar_snipScreen + "pictures": None, # editor.frameView.toolbar_pictures + "hyperlink": None, # editor.frameView.toolbar_hyperlink + "date & time": None, # also qmenu + "undo": lambda: None, + "redo": lambda: None, + "paper color": lambda: None #editor.frameView.pageColor(QColorDialog.getColor()), + } + + # Check if the search_text corresponds to a known action, and execute it if found + action = actions.get(search_text) + if action: + action() + else: + # Handle unknown action + pass + +def build_titlebutton(icon_path, object_name, on_click): + button = QToolButton() + button.setIcon(QIcon(icon_path)) + button.setObjectName(object_name) + button.clicked.connect(on_click) + button.setFocusPolicy(Qt.FocusPolicy.NoFocus) + button.setFixedSize(QSize(49, 49)) + button.setStyleSheet("QToolButton { border: none; padding: 0px;}") + return button + \ No newline at end of file diff --git a/Styles/styles.qss b/Styles/styles.qss index 7e6a35b..023d70e 100644 --- a/Styles/styles.qss +++ b/Styles/styles.qss @@ -1,30 +1,61 @@ -User * { border: none; padding: 0; margin: 0; - font-family: calibri, sans-serif; + font-family: "calibri", sans-serif; font-size: 12pt; } -QMainWindow { - background-color: rgb(230,229,235); +QMainWindow { + background-color: rgb(230, 229, 235); } QMenuBar { - background-color: rgb(230,229,235); - padding: 5px, 20px; + background-color: rgb(230, 229, 235); + padding: 5px 10px; color: rgb(0, 0, 0); } +QWidget#titlebar { + background-color: rgb(119, 25, 170); +} + +QWidget#titlebar QToolButton, +QWidget#titlebar QWidget, +QWidget#searchbarWidget { + background-color: rgb(119, 25, 170); +} + +QWidget#searchbarWidget QLineEdit { + border-radius: 3px; + background-color: rgb(225,209,235); + color: rgb(119, 25, 170); + height: 60px; +} + +QWidget#searchbarWidget QLineEdit::hover, +QWidget#searchbarWidget QLineEdit::focus { + background-color: white; +} + +QToolButton#tray::hover, +QToolButton#windowed::hover, +QToolButton#fullscreen::hover { + background-color: rgb(108, 23, 154); +} + +QToolButton#close::hover { + background-color: rgb(232, 17, 35); +} + QMenuBar::item:selected { background-color: rgb(200, 101, 255); } QToolBar { - border-radius: 8px; - background-color: rgb(255, 255, 255); + spacing: 10px; + background-color: white; } QComboBox { @@ -41,7 +72,8 @@ QPushButton#font_color { height: 20px; } -QToolButton::hover, QPushButton#font_color::hover { +QToolBar QToolButton::hover, +QToolBar QPushButton#font_color::hover { background-color: #cecece; } @@ -49,35 +81,47 @@ QToolButton::checked { background-color: #b1b1b1; } -QToolButton::checked::hover { +QToolBar QToolButton::checked::hover { background-color: #9b9b9b; } QTreeView { - background-color: #c2c2c2; + background-color: rgb(230, 229, 235); } QPushButton { - padding: 5px, 5px, 0, 0; + padding: 5px 0; } QLabel#notebook_title { - padding: 5px, 5px, 0, 0; + padding: 5px; text-align: center; background-color: #d9d9d9; } +QLabel#notebook_title::hover { + padding: 5px; + text-align: center; + border-radius: 3px; + background-color: white; +} + QLabel#pages_title { - padding: 5px, 5px, 5px, 0; + padding: 5px; background-color: #c2c2c2; } +QLabel#pages_title::hover { + padding: 5px; + border-radius: 3px; + background-color: white; +} + QPushButton#addPage { padding-bottom: 5px; background-color: #d9d9d9; } QPushButton#addPage::hover { - background-color: #cecece; + background-color: red; } - diff --git a/Views/PageView.py b/Views/PageView.py index 5531397..427d3de 100644 --- a/Views/PageView.py +++ b/Views/PageView.py @@ -11,6 +11,9 @@ # Page view and controller class PageView(QWidget): + # Class variable to keep track of page count + pageCount = 1 + def __init__(self, pageModels: List[PageModel]): super(PageView, self).__init__() @@ -57,7 +60,7 @@ def loadPages(self, pageModels: List[PageModel]): root.appendRow([rootPage]) # Create a first page - newPageModel = PageModel('New Page', 0) + newPageModel = PageModel(f'New Page {self.pageCount}', 0) newPage = QStandardItem(newPageModel.title) newPage.setData(newPageModel) newPage.setEditable(False) @@ -123,27 +126,31 @@ def openMenu(self, position: QModelIndex): level = 0 menu = QMenu() - addChildAction = menu.addAction(self.tr("Add Page")) - addChildAction.triggered.connect(partial(self.addPage, level, clickedIndex)) - if not page.data().isRoot(): # Dont delete the root page + renamePageAction = menu.addAction(self.tr("Rename Page")) + renamePageAction.setIcon(QIcon('./Assets/icons/svg_rename')) + renamePageAction.triggered.connect(partial(self.renamePage, page)) + deletePageAction = menu.addAction(self.tr("Delete Page")) + deletePageAction.setIcon(QIcon('./Assets/icons/svg_delete')) deletePageAction.triggered.connect(partial(self.deletePage, page)) - renamePageAction = menu.addAction(self.tr("Rename Page")) - renamePageAction.triggered.connect(partial(self.renamePage, page)) + addChildAction = menu.addAction(self.tr("New Page")) + addChildAction.setIcon(QIcon('./Assets/icons/svg_add_page')) + addChildAction.triggered.connect(partial(self.addPage, level, clickedIndex)) + #Current Issue: settings do not save because autosave only saves editor state ''' mergePageAction = menu.addAction(self.tr("Merge Pages")) mergePageAction.triggered.connect(partial(self.mergePages, page)) ''' - - changeTextColorAction = menu.addAction(self.tr("Change Text Color")) - changeTextColorAction.triggered.connect(partial(self.changeTextColor, page)) + # Why even have this??? + # changeTextColorAction = menu.addAction(self.tr("Change Text Color")) + # changeTextColorAction.triggered.connect(partial(self.changeTextColor, page)) - changeBackgroundColorAction = menu.addAction(self.tr("Change Background Color")) - changeBackgroundColorAction.triggered.connect(partial(self.changeBackgroundColor, page)) + PageColorAction = menu.addAction(self.tr("Page Color")) + PageColorAction.triggered.connect(partial(self.PageColor, page)) menu.exec_(self.sender().viewport().mapToGlobal(position)) # Dont let the right click reach the viewport, context menu will still open but this will stop the page from being selected @@ -165,7 +172,8 @@ def addPage(self, level: int, clickedIndex: QModelIndex): parentPageUUID = parentPage.data().getUUID() # Create a new page model, set that as the data for the new page - newPageModel = PageModel('New Page', parentPageUUID) + self.pageCount += 1 + newPageModel = PageModel(f'New Page {self.pageCount}', parentPageUUID) newPage = QStandardItem(newPageModel.title) newPage.setData(newPageModel) newPage.setEditable(False) @@ -227,15 +235,13 @@ def changePage(self, current: QModelIndex, previous: QModelIndex): editorSignalsInstance.pageChanged.emit(newPageModel) # Tell the sectionView that the page has changed - ''' + # Not sure if working as intended - def mergePages(self): - # Prompt the user to select two pages + ''' + def mergePages(self, page: QStandardItem): selectedIndexes = self.tree.selectedIndexes() - # Check if exactly two pages are selected if len(selectedIndexes) == 2: - # Retrieve the QStandardItem objects corresponding to the selected pages page1Item = self.model.itemFromIndex(selectedIndexes[0]) page2Item = self.model.itemFromIndex(selectedIndexes[1]) @@ -243,9 +249,23 @@ def mergePages(self): page1Model = page1Item.data() page2Model = page2Item.data() + # Prompt the user for the name of the page to merge into the second page + name, ok = QInputDialog.getText(self, 'Merge Pages', f'Enter the name of the page to merge into "{page2Model.title}":') + if not ok: + return + + if name != page1Model.title: + QMessageBox.warning(self, 'Invalid Page Name', 'The entered page name does not match the selected page.', QMessageBox.Ok) + return + + # Confirm the merge operation + reply = QMessageBox.question(self, 'Confirm Merge', 'This action cannot be undone. Are you sure you want to merge the pages?', QMessageBox.Yes | QMessageBox.No, QMessageBox.No) + if reply == QMessageBox.No: + return + # Merge the sections of the two pages into one page mergedSections = page1Model.sections + page2Model.sections - newPageModel = PageModel('Merged Page', 0, mergedSections) # Assuming 0 as the parent UUID for the root + newPageModel = PageModel(page2Model.title, page2Model.getParentUUID(), mergedSections) # Create a new QStandardItem for the merged page newPageItem = QStandardItem(newPageModel.title) @@ -269,16 +289,14 @@ def mergePages(self): # Expand the tree to show the changes self.tree.expandAll() else: - # If not exactly two pages are selected, show a warning or message QMessageBox.warning(self, 'Invalid Selection', 'Please select exactly two pages to merge.', QMessageBox.Ok) ''' - def changeTextColor(self, page: QStandardItem): color = QColorDialog.getColor() if color.isValid(): page.setForeground(color) - def changeBackgroundColor(self, page: QStandardItem): + def PageColor(self, page: QStandardItem): color = QColorDialog.getColor() if color.isValid(): page.setBackground(color) \ No newline at end of file diff --git a/Views/SectionView.py b/Views/SectionView.py index b26d198..eb6eb24 100644 --- a/Views/SectionView.py +++ b/Views/SectionView.py @@ -98,14 +98,17 @@ def openMenu(self, position: QPoint): sectionModel = self.tabs.tabData(clickedSectionIndex) menu = QMenu() - addSectionAction = menu.addAction(self.tr("Add Section")) - addSectionAction.triggered.connect(partial(self.addSection, sectionModel, clickedSectionIndex)) + renameSectionAction = menu.addAction(self.tr("Rename Section")) + renameSectionAction.setIcon(QIcon('./Assets/icons/svg_rename')) + renameSectionAction.triggered.connect(partial(self.renameSection, sectionModel, clickedSectionIndex)) deleteSectionAction = menu.addAction(self.tr("Delete Section")) + deleteSectionAction.setIcon(QIcon('./Assets/icons/svg_delete')) deleteSectionAction.triggered.connect(partial(self.deleteSection, sectionModel, clickedSectionIndex)) - renameSectionAction = menu.addAction(self.tr("Rename Section")) - renameSectionAction.triggered.connect(partial(self.renameSection, sectionModel, clickedSectionIndex)) + addSectionAction = menu.addAction(self.tr("Add Section")) + addSectionAction.setIcon(QIcon('./Assets/icons/svg_add_page')) + addSectionAction.triggered.connect(partial(self.addSection, sectionModel, clickedSectionIndex)) menu.exec(self.tabs.mapToGlobal(position)) From 7514f6b9e9b75af9f0a89a5f3dad065cdf6f4af9 Mon Sep 17 00:00:00 2001 From: ldeltastreaml <70774713+ldeltastreaml@users.noreply.github.com> Date: Thu, 21 Mar 2024 11:54:19 -0500 Subject: [PATCH 106/127] Mouse Moving the Window change - When dragging the titlebar in order to reposition the window, the program makes sure to set the window to Qt.WindowNoState before dragging to prevent errors --- Models/Editor.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Models/Editor.py b/Models/Editor.py index b99263b..cc06222 100644 --- a/Models/Editor.py +++ b/Models/Editor.py @@ -73,6 +73,7 @@ def mousePressEvent(self, event): def mouseMoveEvent(self, event): if Qt.LeftButton and self.moveFlag: + self.setWindowState(Qt.WindowNoState) self.move(event.globalPos() - self.movePosition) event.accept() From a25db5a8e295d64872c3f9480e1dc238b412a4d1 Mon Sep 17 00:00:00 2001 From: ldeltastreaml <70774713+ldeltastreaml@users.noreply.github.com> Date: Sat, 23 Mar 2024 16:27:40 -0500 Subject: [PATCH 107/127] Added Paste button to toolbar --- Assets/icons/svg_paste.svg | 13 +++++++++++++ Modules/BuildUI.py | 17 ++++++++++++++++- Modules/Titlebar.py | 1 + Views/EditorFrameView.py | 6 ++++++ 4 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 Assets/icons/svg_paste.svg diff --git a/Assets/icons/svg_paste.svg b/Assets/icons/svg_paste.svg new file mode 100644 index 0000000..9376c18 --- /dev/null +++ b/Assets/icons/svg_paste.svg @@ -0,0 +1,13 @@ + + + + + + + + + + \ No newline at end of file diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index 268d8fe..422c84e 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -164,6 +164,9 @@ def build_toolbar(editor): spacer3.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) spacer3.setFixedWidth(3) + paste = build_action(editor.homeToolbar, './Assets/icons/svg_paste', "Paste", "Paste", False) + paste.triggered.connect(editor.frameView.toolbar_paste) + cut = build_action(editor.homeToolbar, './Assets/icons/svg_cut', "Cut", "Cut", False) cut.triggered.connect(lambda: editorSignalsInstance.widgetCut.emit(DraggableContainer)) @@ -223,7 +226,7 @@ def build_toolbar(editor): bullet.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Bullet, None)) editor.homeToolbar.addWidget(spacer1) - editor.homeToolbar.addActions([cut, copy]) + editor.homeToolbar.addActions([paste, cut, copy]) editor.homeToolbar.addSeparator() @@ -269,6 +272,18 @@ def build_toolbar(editor): editor.homeToolbar.addActions(align_group.actions()) editor.homeToolbar.addSeparator() + + + # Classic Home Toolbar + editor.classicToolbar = QToolBar() + editor.classicToolbar.setObjectName('classicHomeToolbar') + editor.classicToolbar.setIconSize(QSize(18,18)) + editor.classicToolbar.setFixedHeight(40) + editor.classicToolbar.setMovable(False) + editor.classicToolbar.setVisible(False) + editor.addToolBar(Qt.ToolBarArea.TopToolBarArea, editor.classicToolbar) + + # insertToolbar code editor.insertToolbar = QToolBar() diff --git a/Modules/Titlebar.py b/Modules/Titlebar.py index 383c218..dace464 100644 --- a/Modules/Titlebar.py +++ b/Modules/Titlebar.py @@ -98,6 +98,7 @@ def perform_search(self): # Dictionary mapping search keywords to corresponding actions actions = { + "paste": lambda: None, # editor.frameView.toolbar_paste "cut": lambda: None, "copy": lambda: None, "paste": lambda: None, diff --git a/Views/EditorFrameView.py b/Views/EditorFrameView.py index 336d37e..6a6e520 100644 --- a/Views/EditorFrameView.py +++ b/Views/EditorFrameView.py @@ -289,6 +289,12 @@ def center_of_screen(self): return center_x, center_y # Used for calling functions in toolbar + def toolbar_paste(self): + print("toolbar_paste pressed") + center_x, center_y = self.center_of_screen() + clickPos = QPoint(center_x, center_y) + self.pasteWidget(clickPos) + def toolbar_table(self): print("toolbar_table pressed") center_x, center_y = self.center_of_screen() From c1dcbb265c6ca1ce71b21a9e3db9eab85cfb2245 Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Sun, 31 Mar 2024 21:56:02 -0500 Subject: [PATCH 108/127] Multiselect and toolbar functions - multiselect will now select all text - toolbar functions now moved to textbox directly rather than calling draggable container --- Models/DraggableContainer.py | 46 +++------------------ Models/Editor.py | 4 +- Modules/BuildUI.py | 14 ++++++- Modules/EditorSignals.py | 7 +++- Modules/Multiselect.py | 22 +++++++++-- Widgets/Image.py | 59 ++++++++++++++++++++++++++- Widgets/Link.py | 3 ++ Widgets/Textbox.py | 77 +++++++++++++++++++++++++++++++++++- 8 files changed, 181 insertions(+), 51 deletions(-) diff --git a/Models/DraggableContainer.py b/Models/DraggableContainer.py index 653ad86..77973b0 100644 --- a/Models/DraggableContainer.py +++ b/Models/DraggableContainer.py @@ -98,6 +98,10 @@ def mousePressEvent(self, e: QMouseEvent): if not e.buttons() and Qt.LeftButton: print("Draggable Container GOT MOUSE PRESS") self.setCursorShape(e.pos()) + + if (self.hasFocus == False and isinstance(self.childWidget, QTextBrowser)): + print("Deselecting text") + self.childWidget.deselectText() return True if e.button() == Qt.RightButton: self.popupShow(e.pos()) @@ -402,46 +406,8 @@ def widgetAttributeChanged(self, changedWidgetAttribute, value): #if self.hasFocus() or child_widget.hasFocus(): #only the focused container will print this line print(f"changedWidgetAttribute is {changedWidgetAttribute} and value is {value}") - - if hasattr(child_widget, "changeFontSizeEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.FontSize): - print("Change Font Size Event Called") - child_widget.changeFontSizeEvent(value) - - elif hasattr(child_widget, "changeFontBoldEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.FontBold): - print("Change Font Bold Event Called") - child_widget.changeFontBoldEvent() - - elif hasattr(child_widget, "changeFontItalicEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.FontItalic): - print("Change Font Italic Event Called") - child_widget.changeFontItalicEvent() - - elif hasattr(child_widget, "changeFontUnderlineEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.FontUnderline): - print("Change Font Underline Event Called") - child_widget.changeFontUnderlineEvent() - - elif hasattr(child_widget, "setStrikeOut") and (changedWidgetAttribute == ChangedWidgetAttribute.Strikethrough): - print("Change strikethroughEvent called") - child_widget.setStrikeOut() - - elif hasattr(child_widget, "changeFontEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.Font): - print("Change Font Family Event Called") - child_widget.changeFontEvent(value) - - elif hasattr(child_widget, "changeFontColorEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.FontColor): - print("Change Font Color Event Called") - child_widget.changeFontColorEvent(value) - - elif hasattr(child_widget, "changeTextHighlightColorEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.TextHighlightColor): - print("Change Textbox Color Event Called") - child_widget.changeTextHighlightColorEvent(value) - - elif hasattr(child_widget, "deselectText") and (changedWidgetAttribute == ChangedWidgetAttribute.LoseFocus): - print("Clear Selection Slot Called") - child_widget.deselectText() - if hasattr(self.childWidget, "checkEmpty") and isinstance(child_widget, QTextBrowser): - if self.childWidget.checkEmpty(): - print("Removing empty container") - editorSignalsInstance.widgetRemoved.emit(self) + if (self.hasFocus() and changedWidgetAttribute == ChangedWidgetAttribute.LoseFocus): + child_widget.removeWidget() if self.hasFocus() or child_widget.hasFocus(): if hasattr(child_widget, "changeBulletEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.Bullet): print("Change Bullet Event Called") diff --git a/Models/Editor.py b/Models/Editor.py index cc06222..599c331 100644 --- a/Models/Editor.py +++ b/Models/Editor.py @@ -19,7 +19,8 @@ class Editor(QMainWindow): def __init__(self): super().__init__() - self.setWindowFlag(Qt.WindowType.FramelessWindowHint) + # self.setWindowFlags(Qt.WindowType.FramelessWindowHint) + # self.setWindowFlags(Qt.WindowType.Window | Qt.WindowType.CustomizeWindowHint) self.notebook = NotebookModel('Untitled Notebook') # Current notebook object # self.selected = None # Selected object (for font attributes of TextBox) @@ -39,6 +40,7 @@ def __init__(self): action_names = self.save_toolbar_actions([self.homeToolbar, self.insertToolbar, self.drawToolbar]) self.titlebar.set_action_names(action_names) + def closeEvent(self, event): # Save window size and position before exiting diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index 422c84e..71ba521 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -9,7 +9,7 @@ from Models.DraggableContainer import DraggableContainer from Widgets.Textbox import * -from Modules.EditorSignals import editorSignalsInstance, ChangedWidgetAttribute +from Modules.EditorSignals import editorSignalsInstance, ChangedWidgetAttribute, CheckSignal from Modules.Undo import UndoHandler from Widgets.Table import * @@ -143,6 +143,10 @@ def build_menubar(editor): plugins.addAction(add_widget) def build_toolbar(editor): + def handleCheck(action): + action.setChecked(True) + #editorSignalsInstance.checkMade.connect(editor.checkMade) + # homeToolbar code editor.homeToolbar = QToolBar() editor.homeToolbar.setObjectName('homeToolbar') @@ -208,15 +212,21 @@ def build_toolbar(editor): bold = build_action(editor.homeToolbar, './Assets/icons/bold', "Bold", "Bold", True) bold.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontBold, None)) + #if(checkMade == CheckSignal.BoldCheck): + # handleCheck(bold) italic = build_action(editor.homeToolbar, './Assets/icons/italic.svg', "Italic", "Italic", True) italic.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontItalic, None)) + italic.setChecked(True) underline = build_action(editor.homeToolbar, './Assets/icons/underline.svg', "Underline", "Underline", True) underline.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontUnderline, None)) strikethrough = build_action(editor.homeToolbar, './Assets/icons/svg_strikethrough.svg', "Strikethrough", "Strikethrough", True) strikethrough.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Strikethrough, None)) + + refactor = build_action(editor.homeToolbar, './Assets/icons/bold', "Bold", "Bold", True) + refactor.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Refactor, None)) delete = build_action(editor.homeToolbar, './Assets/icons/svg_delete', "Delete", "Delete", False) delete.triggered.connect(lambda: editorSignalsInstance.widgetRemoved.emit(DraggableContainer)) @@ -235,7 +245,7 @@ def build_toolbar(editor): editor.homeToolbar.addSeparator() - editor.homeToolbar.addActions([bold, italic, underline, strikethrough, fontColor, textHighlightColor, bgColor, delete, bullet]) + editor.homeToolbar.addActions([bold, italic, underline, strikethrough, refactor, fontColor, textHighlightColor, bgColor, delete, bullet]) # numbering menu start numbering_menu = QMenu(editor) diff --git a/Modules/EditorSignals.py b/Modules/EditorSignals.py index b97220a..65dd164 100644 --- a/Modules/EditorSignals.py +++ b/Modules/EditorSignals.py @@ -25,8 +25,10 @@ class ChangedWidgetAttribute(Enum): PaperColor = 16 Strikethrough = 17 + Refactor = 18 - +class CheckSignal(Enum): + BoldCheck = 0 # Cant be statically typed because importing the classes causes circular imports class EditorSignals(QObject): @@ -52,4 +54,7 @@ class EditorSignals(QObject): # Clear Selection loseFocus = Signal() + # used for checking if a toggle should be toggled off + checkMade = Signal() + editorSignalsInstance = EditorSignals() diff --git a/Modules/Multiselect.py b/Modules/Multiselect.py index ca6a45a..77d905f 100644 --- a/Modules/Multiselect.py +++ b/Modules/Multiselect.py @@ -27,11 +27,20 @@ def __init__(self, editorFrame): self.dragInitEventPos = None # Position of the event that started the dragging self.dragOffset = None # Offset of object that is used to drag the others from the first object in the editors list + # for handling deselect self.installEventFilter() - + # Connect signal for widget removal + editorSignalsInstance.widgetRemoved.connect(self.removeWidgetFromList) + editorSignalsInstance.widgetCut.connect(self.cutWidgetEvent) + # Slot to remove widget from object list + @Slot(QWidget) + def removeWidgetFromList(self, widget): + if widget in self.selectedObjects: + self.selectedObjects.remove(widget) + # install event filter to editorframe def installEventFilter(self): self.editorFrame.installEventFilter(self) @@ -70,7 +79,7 @@ def eventFilter(self, obj, event): if event.type() == QEvent.MouseButtonPress and event.button() == Qt.LeftButton: if multiselector.mode == MultiselectMode.HAS_SELECTED_OBJECTS: multiselector.deselectIfClickOutsideObjects(event) - print("DESELECT") + print("DESELECT from multiselect") return False @@ -144,6 +153,13 @@ def finishDrawingArea(self, event): print("SELECTION COUNT: ", len(self.selectedObjects)) + # highlight all text for textwidgets + for o in self.selectedObjects: + # Checks if child is textwidget + if (isinstance(o.childWidget, QTextBrowser)): + print("TEXT WIDGET FOUND. HIGHLIGHTING") + # Call function in textwidget to highlight all text in their textbox + o.childWidget.selectAllText() # Hide selection area self.drawingWidget.hide() @@ -158,7 +174,7 @@ def dragObjects(self, event): # Get the position that each object would move to objectPositions = [] - for o in reversed(self.selectedObjects): # fuck it, reversed + for o in reversed(self.selectedObjects): # fuck it, reversed # You have to know this, focus # Position of the first (in the reversed array) object's top left corner + the offset of the click inside the selected object - the position of the object to move diff --git a/Widgets/Image.py b/Widgets/Image.py index aa1ac77..04b159d 100644 --- a/Widgets/Image.py +++ b/Widgets/Image.py @@ -40,9 +40,28 @@ def newGeometryEvent(self, newGeometry): self.persistantGeometry = newGeometry + '''@staticmethod + def new(clickPos): + + # Get path from user + path, _ = QFileDialog.getOpenFileName(QWidget(), 'Add Image') + if path == "": return + + # Get image size + image_matrix = cv2.imread(path) + h, w, _ = image_matrix.shape + + # Create image and add to notebook + h, w, _ = image_matrix.shape + image = ImageWidget(clickPos.x(), clickPos.y(), w, h, image_matrix) # Note: the editorframe will apply pos based on event + + return image + ''' # uses inbuilt qt file dialog @staticmethod def new(clickPos): + + # Create a dummy parent widget for the file dialog dummy_parent = QWidget() @@ -81,8 +100,44 @@ def __getstate__(self): def __setstate__(self, state): self.__init__(state['geometry'].x(), state['geometry'].y(), state['geometry'].width(), state['geometry'].height(), state['image_matrix']) - # not necessary to have a top toolbar for image - + def customMenuItems(self): + def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): + action = QAction(QIcon(icon_path), action_name, parent) + action.setStatusTip(set_status_tip) + action.setCheckable(set_checkable) + return action + + + toolbarBottom = QToolBar() + toolbarBottom.setIconSize(QSize(16, 16)) + toolbarBottom.setMovable(False) + + #crop = build_action(toolbarTop, './Assets/icons/svg_crop', "Crop", "Crop", False) + + flipHorizontal = build_action(toolbarBottom, './Assets/icons/svg_flip_horizontal', "Horizontal Flip", "Horizontal Flip", False) + flipHorizontal.triggered.connect(self.flipHorizontal) + flipVertical = build_action(toolbarBottom, './Assets/icons/svg_flip_vertical', "Vertical Flip", "Vertical Flip", False) + flipVertical.triggered.connect(self.flipVertical) + + rotateLeftAction = build_action(toolbarBottom, './Assets/icons/svg_rotate_left', "Rotate 90 degrees Left", "Rotate 90 degrees Left", False) + rotateLeftAction.triggered.connect(self.rotate90Left) + rotateRightAction = build_action(toolbarBottom, './Assets/icons/svg_rotate_right', "Rotate 90 degrees Right", "Rotate 90 degrees Right", False) + + rotateRightAction.triggered.connect(self.rotate90Right) + + shrinkImageAction = build_action(toolbarBottom, 'Assets/icons/svg_shrink', "Shrink", "Shrink", False) + shrinkImageAction.triggered.connect(self.shrinkImage) + expandImageAction = build_action(toolbarBottom, 'Assets/icons/svg_expand', "Expand", "Expand", False) + expandImageAction.triggered.connect(self.expandImage) + + + toolbarBottom.addActions([rotateLeftAction, rotateRightAction, flipHorizontal, flipVertical, shrinkImageAction, expandImageAction]) + + qwaBottom = QWidgetAction(self) + qwaBottom.setDefaultWidget(toolbarBottom) + + return [qwaBottom] + def flipVertical(self): # Flip the image matrix vertically using OpenCV parent_widget = self.parentWidget() diff --git a/Widgets/Link.py b/Widgets/Link.py index 40560f7..7258efe 100644 --- a/Widgets/Link.py +++ b/Widgets/Link.py @@ -10,6 +10,9 @@ def __init__(self): self.setWindowTitle("Insert Link") layout = QVBoxLayout() + # to stay on top of application + self.setWindowFlag(Qt.WindowStaysOnTopHint) + self.link_label = QLabel("Link Address:") self.link_textbox = QLineEdit() self.display_label = QLabel("Display Text:") diff --git a/Widgets/Textbox.py b/Widgets/Textbox.py index 1ed926e..36db394 100644 --- a/Widgets/Textbox.py +++ b/Widgets/Textbox.py @@ -1,7 +1,7 @@ from PySide6.QtCore import * from PySide6.QtGui import * from PySide6.QtWidgets import * -from Modules.EditorSignals import editorSignalsInstance +from Modules.EditorSignals import editorSignalsInstance, ChangedWidgetAttribute, CheckSignal import subprocess @@ -25,6 +25,8 @@ def check_appearance(): self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.textChanged.connect(self.textChangedEvent) + editorSignalsInstance.widgetAttributeChanged.connect(self.widgetAttributeChanged) + if check_appearance() == True: self.setStyleSheet("background-color: rgba(31,31,30,255);") @@ -46,6 +48,11 @@ def eventFilter(self, obj, event): if event.type() == QEvent.KeyPress and event.key() == Qt.Key_Tab: self.handleTabKey() return True # To prevent the default Tab key behavior + '''if event.type() == QEvent.FocusOut: + if self.checkEmpty(): + parent = self.parent() + if parent is not None: + parent.deleteLater()''' return super(TextboxWidget, self).eventFilter(obj, event) @@ -606,4 +613,70 @@ def setStrikeOut(self): #cursor.movePosition(QTextCursor.End) self.setTextCursor(cursor) - #self.setFocus() \ No newline at end of file + #self.setFocus() + + # Handles events from any toolbar button + def widgetAttributeChanged(self, changedWidgetAttribute, value): + #if (self.hasFocus and changedWidgetAttribute == ChangedWidgetAttribute.LoseFocus): + #self.emptyWidget() + # test function for refactoring code + if (self.hasFocus and changedWidgetAttribute == ChangedWidgetAttribute.Refactor): + print("REFACTOR TEST WORKED") + editorSignalsInstance.checkMade.emit(CheckSignal.BoldCheck, None) + # self.refactorTest() + # Font Size function + elif (self.hasFocus and changedWidgetAttribute == ChangedWidgetAttribute.FontSize): + self.changeFontSizeEvent(value) + # Bold function + elif (self.hasFocus and changedWidgetAttribute == ChangedWidgetAttribute.FontBold): + self.changeFontBoldEvent() + # Italics function + elif (self.hasFocus and changedWidgetAttribute == ChangedWidgetAttribute.FontItalic): + self.changeFontItalicEvent() + # Underline function + elif (self.hasFocus and changedWidgetAttribute == ChangedWidgetAttribute.FontUnderline): + self.changeFontUnderlineEvent() + # + elif (self.hasFocus and changedWidgetAttribute == ChangedWidgetAttribute.FontUnderline): + self.changeFontUnderlineEvent() + elif (self.hasFocus and changedWidgetAttribute == ChangedWidgetAttribute.Strikethrough): + self.setStrikeOut() + elif (self.hasFocus and changedWidgetAttribute == ChangedWidgetAttribute.Font): + self.changeFontEvent(value) + elif (self.hasFocus and changedWidgetAttribute == ChangedWidgetAttribute.FontColor): + self.changeFontColorEvent(value) + elif (self.hasFocus and changedWidgetAttribute == ChangedWidgetAttribute.TextHighlightColor): + self.changeTextHighlightColorEvent(value) + # elif (self.hasFocus and changedWidgetAttribute == ChangedWidgetAttribute.FontUnderline): + def refactorTest(self): + cursor = self.textCursor() + current_format = cursor.charFormat() + + # Checks if currently selected text is bold + is_bold = current_format.fontWeight() == 700 + + # toggles the italics + if is_bold: + current_format.setFontWeight(500) + else: + current_format.setFontWeight(700) + # Apply modified format to selected text + cursor.setCharFormat(current_format) + cursor.mergeCharFormat(format) + # Emit signal if no text is bold to toggle bold off + if not is_bold: + editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontBold, None) + # Update text cursor with modified format + self.setTextCursor(cursor) + + def selectAllText(self): + print("Select All Text function from textwidget called") + cursor = self.textCursor() + cursor.setPosition(0) + cursor.movePosition(QTextCursor.End, QTextCursor.KeepAnchor) + self.setTextCursor(cursor) + + def removeWidget(self): + if(self.checkEmpty()): + print("removing widget") + editorSignalsInstance.widgetRemoved.emit(self) \ No newline at end of file From 8da248d24c2d7b64f2dc6a83b200694bda6f7328 Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Mon, 1 Apr 2024 12:10:43 -0500 Subject: [PATCH 109/127] Empty widgets get remved again --- Models/DraggableContainer.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Models/DraggableContainer.py b/Models/DraggableContainer.py index 77973b0..d21986c 100644 --- a/Models/DraggableContainer.py +++ b/Models/DraggableContainer.py @@ -406,8 +406,13 @@ def widgetAttributeChanged(self, changedWidgetAttribute, value): #if self.hasFocus() or child_widget.hasFocus(): #only the focused container will print this line print(f"changedWidgetAttribute is {changedWidgetAttribute} and value is {value}") - if (self.hasFocus() and changedWidgetAttribute == ChangedWidgetAttribute.LoseFocus): - child_widget.removeWidget() + if hasattr(child_widget, "deselectText") and (changedWidgetAttribute == ChangedWidgetAttribute.LoseFocus): + print("Clear Selection Slot Called") + child_widget.deselectText() + if hasattr(self.childWidget, "checkEmpty") and isinstance(child_widget, QTextBrowser): + if self.childWidget.checkEmpty(): + print("Removing empty container") + editorSignalsInstance.widgetRemoved.emit(self) if self.hasFocus() or child_widget.hasFocus(): if hasattr(child_widget, "changeBulletEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.Bullet): print("Change Bullet Event Called") From 1bd83ad19a3855240137f68469c263ecd2510122 Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Mon, 1 Apr 2024 16:33:33 -0500 Subject: [PATCH 110/127] Selection bg color and moving functions around - Most functions from draggable container that signals toolbar for toolbar moved to textbox - changed names of functions and added comments for clarity - changed highlighting text color to gray - changed qtextbrowser to qtextedit since textedit is more appropriate --- Models/DraggableContainer.py | 66 ++++++----------------- Modules/Multiselect.py | 2 +- Styles/styles.qss | 5 ++ Widgets/Textbox.py | 102 +++++++++++++++++++---------------- 4 files changed, 79 insertions(+), 96 deletions(-) diff --git a/Models/DraggableContainer.py b/Models/DraggableContainer.py index d21986c..651753b 100644 --- a/Models/DraggableContainer.py +++ b/Models/DraggableContainer.py @@ -53,7 +53,7 @@ def __init__(self, childWidget, editorFrame): self.menu = self.buildDragContainerMenu() if hasattr(self.childWidget, "newGeometryEvent"): self.newGeometry.connect(childWidget.newGeometryEvent) - editorSignalsInstance.widgetAttributeChanged.connect(self.widgetAttributeChanged) + editorSignalsInstance.widgetAttributeChanged.connect(self.deselect) @@ -99,9 +99,7 @@ def mousePressEvent(self, e: QMouseEvent): print("Draggable Container GOT MOUSE PRESS") self.setCursorShape(e.pos()) - if (self.hasFocus == False and isinstance(self.childWidget, QTextBrowser)): - print("Deselecting text") - self.childWidget.deselectText() + return True if e.button() == Qt.RightButton: self.popupShow(e.pos()) @@ -109,6 +107,12 @@ def mousePressEvent(self, e: QMouseEvent): self.childWidget.setAttribute(Qt.WA_TransparentForMouseEvents, False) self.childWidget.setFocus() + # checks if the child is a textbox + if (isinstance(self.childWidget, QTextEdit)): + # sets cursor position to where mouse is upon clicking + self.childWidget.setCursorPosition(e) + # check settings at cursor and match the visual of the toolbar toggle with the current cursor setting + #brings text cursor to cursor position but causes exception '''if isinstance(self.childWidget, TextboxWidget): @@ -190,7 +194,7 @@ def buildDragContainerMenu(self): # menu.addMenu(orderMenu) # text boxes - if isinstance(self.childWidget, QTextBrowser): + if isinstance(self.childWidget, QTextEdit): table = QAction("&Table", self) # table.triggered.connect(lambda: self.newWidgetOnSection(TableWidget, event.pos())) @@ -391,58 +395,20 @@ def mouseMoveEvent(self, e: QMouseEvent): self.resize(e.x(), e.y()) self.parentWidget().repaint() self.newGeometry.emit(self.geometry()) - - # Pass the e to the child widget if this container is focused, and childwidget implements the method to receive it - # Uses signals to pass to draggable container, which then checks if child has the function, then calls the function. - # Look at toolbar in BuildUI.py to see examples - # example signal that doesn't have a value: 'italic.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontItalic, None))' - # example signal with a value: 'font_family.currentFontChanged.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Font, font_family.currentFont().family()))' - # When adding a function to a child widget, use 'if self.hasFocus():' to ensure the function applies only to the focused widget. Else it will apply to all widgets of the same type - def widgetAttributeChanged(self, changedWidgetAttribute, value): + + # Used for deselecting text and removing container if empty + def deselect(self, changedWidgetAttribute): #print(f"changedWidgetAttribute is {changedWidgetAttribute} and value is {value}") child_widget = self.childWidget - - #this if statement is no longer needed because highlighted text deselects after clicking on an area in the editor thats not the in focus textbox - #if self.hasFocus() or child_widget.hasFocus(): - #only the focused container will print this line - print(f"changedWidgetAttribute is {changedWidgetAttribute} and value is {value}") + + # If clicking on no object, deselect text if hasattr(child_widget, "deselectText") and (changedWidgetAttribute == ChangedWidgetAttribute.LoseFocus): - print("Clear Selection Slot Called") child_widget.deselectText() - if hasattr(self.childWidget, "checkEmpty") and isinstance(child_widget, QTextBrowser): + # remove the widget if empty + if hasattr(self.childWidget, "checkEmpty") and isinstance(child_widget, QTextEdit): if self.childWidget.checkEmpty(): print("Removing empty container") editorSignalsInstance.widgetRemoved.emit(self) - if self.hasFocus() or child_widget.hasFocus(): - if hasattr(child_widget, "changeBulletEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.Bullet): - print("Change Bullet Event Called") - child_widget.bullet_list("bulletReg") - elif hasattr(child_widget, "changeBulletEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.Bullet_Num): - print("Change Bullet Event Called") - child_widget.bullet_list("bulletNum") - elif hasattr(child_widget, "changeBulletEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.BulletUA): - print("Change Bullet Event Called") - child_widget.bullet_list("bulletUpperA") - elif hasattr(child_widget, "changeBulletEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.BulletUR): - print("Change Bullet Event Called") - child_widget.bullet_list("bulletUpperR") - - elif hasattr(child_widget, "changeAlignmentEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.AlignLeft): - print("Change Alignment Event Called") - child_widget.changeAlignmentEvent("alignLeft") - elif hasattr(child_widget, "changeAlignmentEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.AlignCenter): - print("Change Alignment Event Called") - child_widget.changeAlignmentEvent("alignCenter") - elif hasattr(child_widget, "changeAlignmentEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.AlignRight): - print("Change Alignment Event Called") - child_widget.changeAlignmentEvent("alignRight") - - elif hasattr(child_widget, "changeBackgroundColorEvent") and (changedWidgetAttribute == ChangedWidgetAttribute.BackgroundColor): - print("Chang Background Color Event Called") - child_widget.changeBackgroundColorEvent(value) - elif hasattr(child_widget, "paperColor") and (changedWidgetAttribute == ChangedWidgetAttribute.PaperColor): - print("Change Page Color Event Called") - child_widget.paperColor(value) def connectTableSignals(self, tableWidget): tableWidget.rowAdded.connect(self.resizeTable) diff --git a/Modules/Multiselect.py b/Modules/Multiselect.py index 77d905f..d07b7c5 100644 --- a/Modules/Multiselect.py +++ b/Modules/Multiselect.py @@ -156,7 +156,7 @@ def finishDrawingArea(self, event): # highlight all text for textwidgets for o in self.selectedObjects: # Checks if child is textwidget - if (isinstance(o.childWidget, QTextBrowser)): + if (isinstance(o.childWidget, QTextEdit)): print("TEXT WIDGET FOUND. HIGHLIGHTING") # Call function in textwidget to highlight all text in their textbox o.childWidget.selectAllText() diff --git a/Styles/styles.qss b/Styles/styles.qss index 023d70e..765b4f5 100644 --- a/Styles/styles.qss +++ b/Styles/styles.qss @@ -125,3 +125,8 @@ QPushButton#addPage { QPushButton#addPage::hover { background-color: red; } + +QTextEdit { + selection-background-color: #F0F0F0; + selection-color: #000000 +} \ No newline at end of file diff --git a/Widgets/Textbox.py b/Widgets/Textbox.py index 36db394..43dd13c 100644 --- a/Widgets/Textbox.py +++ b/Widgets/Textbox.py @@ -8,7 +8,7 @@ FONT_SIZES = [7, 8, 9, 10, 11, 12, 13, 14, 18, 24, 36, 48, 64, 72, 96, 144, 288] -class TextboxWidget(QTextBrowser): +class TextboxWidget(QTextEdit): def __init__(self, x, y, w=15, h=30, t=""): super().__init__() @@ -22,18 +22,21 @@ def check_appearance(): self.setGeometry(x, y, w, h) # This sets geometry of DraggableObject self.setText(t) + self.setStyleSheet("selection-background-color: #FFFFFF;") + self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.textChanged.connect(self.textChangedEvent) editorSignalsInstance.widgetAttributeChanged.connect(self.widgetAttributeChanged) + if check_appearance() == True: self.setStyleSheet("background-color: rgba(31,31,30,255);") #self.changeBackgroundColorEvent(31, 31, 30) self.setTextColor("white") self.changeAllTextColors("white") - + self.set else: self.setStyleSheet("background-color: rgba(0, 0, 0, 0);") #self.changeBackgroundColorEvent(0,0,0) @@ -92,6 +95,45 @@ def checkEmpty(self): if len(self.toPlainText()) < 1: return True return False + + # Handles events from any toolbar button + def widgetAttributeChanged(self, changedWidgetAttribute, value): + # dictionary of toolbar functions + attribute_functions = { + # note: for functions with no value passed, lambda _ will allow it to pass with no value + + # font functions + ChangedWidgetAttribute.FontSize: lambda val: self.changeFontSizeEvent(val), + ChangedWidgetAttribute.FontBold: lambda _: self.changeFontBoldEvent(), + ChangedWidgetAttribute.FontItalic: lambda _: self.changeFontItalicEvent(), + ChangedWidgetAttribute.FontUnderline: lambda _: self.changeFontUnderlineEvent(), + ChangedWidgetAttribute.Strikethrough: lambda _: self.setStrikeOut(), + ChangedWidgetAttribute.Font: lambda val: self.changeFontEvent(val), + ChangedWidgetAttribute.FontColor: lambda val: self.changeFontColorEvent(val), + ChangedWidgetAttribute.TextHighlightColor: lambda val: self.changeTextHighlightColorEvent(val), + + # background color functions + ChangedWidgetAttribute.BackgroundColor: lambda val: self.changeBackgroundColorEvent(val), + ChangedWidgetAttribute.PaperColor: lambda val: self.paperColor(val), # not implemented yet + + # Bullet list functions + ChangedWidgetAttribute.Bullet: lambda _: self.bullet_list("bulletReg"), + ChangedWidgetAttribute.Bullet_Num: lambda _: self.bullet_list("bulletNum"), + ChangedWidgetAttribute.Bullet_Num: lambda _: self.bullet_list("bulletUpperA"), + ChangedWidgetAttribute.Bullet_Num: lambda _: self.bullet_list("bulletUpperR"), + + # Alignment functions + ChangedWidgetAttribute.Bullet_Num: lambda _: self.changeAlignmentEvent("alignLeft"), + ChangedWidgetAttribute.Bullet_Num: lambda _: self.changeAlignmentEvent("alignCenter"), + ChangedWidgetAttribute.Bullet_Num: lambda _: self.changeAlignmentEvent("alignRight") + } + + if self.hasFocus and changedWidgetAttribute in attribute_functions: + # Calls the function in the dictionary + attribute_functions[changedWidgetAttribute](value) + else: + # Handle invalid attribute or other cases + pass def customMenuItems(self): def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): @@ -126,30 +168,31 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): ) align_left = build_action(toolbarBottom, "./Assets/icons/svg_align_left", "Align Left", "Align Left", False) - align_left.triggered.connect(lambda x: self.setAlignment(Qt.AlignLeft)) + # align_left.triggered.connect(lambda x: self.setAlignment(Qt.AlignLeft)) + align_left.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.AlignLeft, None)) + align_center = build_action(toolbarBottom, "./Assets/icons/svg_align_center", "Align Center", "Align Center", False) - align_center.triggered.connect(lambda x: self.setAlignment(Qt.AlignCenter)) + # align_center.triggered.connect(lambda x: self.setAlignment(Qt.AlignCenter)) + align_center.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.AlignCenter, None)) + align_right = build_action(toolbarBottom, "./Assets/icons/svg_align_right", "Align Right", "Align Right", False) align_right.triggered.connect(lambda x: self.setAlignment(Qt.AlignRight)) + align_right.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.AlignRight, None)) + bold = build_action( toolbarBottom, "./Assets/icons/svg_font_bold", "Bold", "Bold", True ) - bold.toggled.connect(lambda x: self.setFontWeightCustom(700 if x else 500)) + bold.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontBold, None)) italic = build_action( toolbarBottom, "./Assets/icons/svg_font_italic", "Italic", "Italic", True ) - italic.toggled.connect(lambda x: self.setFontItalicCustom(True if x else False)) + italic.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontItalic, None)) - underline = build_action( - toolbarBottom, - "./Assets/icons/svg_font_underline", - "Underline", - "Underline", - True, + underline = build_action(toolbarBottom,"./Assets/icons/svg_font_underline","Underline","Underline",True, ) underline.toggled.connect( lambda x: self.setFontUnderlineCustom(True if x else False) @@ -615,39 +658,8 @@ def setStrikeOut(self): self.setTextCursor(cursor) #self.setFocus() - # Handles events from any toolbar button - def widgetAttributeChanged(self, changedWidgetAttribute, value): - #if (self.hasFocus and changedWidgetAttribute == ChangedWidgetAttribute.LoseFocus): - #self.emptyWidget() - # test function for refactoring code - if (self.hasFocus and changedWidgetAttribute == ChangedWidgetAttribute.Refactor): - print("REFACTOR TEST WORKED") - editorSignalsInstance.checkMade.emit(CheckSignal.BoldCheck, None) - # self.refactorTest() - # Font Size function - elif (self.hasFocus and changedWidgetAttribute == ChangedWidgetAttribute.FontSize): - self.changeFontSizeEvent(value) - # Bold function - elif (self.hasFocus and changedWidgetAttribute == ChangedWidgetAttribute.FontBold): - self.changeFontBoldEvent() - # Italics function - elif (self.hasFocus and changedWidgetAttribute == ChangedWidgetAttribute.FontItalic): - self.changeFontItalicEvent() - # Underline function - elif (self.hasFocus and changedWidgetAttribute == ChangedWidgetAttribute.FontUnderline): - self.changeFontUnderlineEvent() - # - elif (self.hasFocus and changedWidgetAttribute == ChangedWidgetAttribute.FontUnderline): - self.changeFontUnderlineEvent() - elif (self.hasFocus and changedWidgetAttribute == ChangedWidgetAttribute.Strikethrough): - self.setStrikeOut() - elif (self.hasFocus and changedWidgetAttribute == ChangedWidgetAttribute.Font): - self.changeFontEvent(value) - elif (self.hasFocus and changedWidgetAttribute == ChangedWidgetAttribute.FontColor): - self.changeFontColorEvent(value) - elif (self.hasFocus and changedWidgetAttribute == ChangedWidgetAttribute.TextHighlightColor): - self.changeTextHighlightColorEvent(value) - # elif (self.hasFocus and changedWidgetAttribute == ChangedWidgetAttribute.FontUnderline): + + def refactorTest(self): cursor = self.textCursor() current_format = cursor.charFormat() From 284e9aa4c819ac1723fd0b37c7be7c4454e85a25 Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Mon, 1 Apr 2024 18:30:45 -0500 Subject: [PATCH 111/127] text widgets now expand if max height is reached - When a textbox widget goes beyond it's current size, it will expand by one row. - textbox widget default size now is closer to the size oneNote uses --- Models/DraggableContainer.py | 14 ++++++++--- Widgets/Textbox.py | 47 +++++++++++++++++++----------------- 2 files changed, 36 insertions(+), 25 deletions(-) diff --git a/Models/DraggableContainer.py b/Models/DraggableContainer.py index 651753b..d0a32a7 100644 --- a/Models/DraggableContainer.py +++ b/Models/DraggableContainer.py @@ -122,6 +122,7 @@ def mousePressEvent(self, e: QMouseEvent): pass''' # need to add code for setting cursor to the end of the textbox + # On double click, focus on child and make mouse events pass through this container to child def mouseDoubleClickEvent(self, e: QMouseEvent): print("MOUSEDOUBLECLICKEVENT FROM DRAGGABLE CONTAINER") @@ -137,13 +138,20 @@ def mouseReleaseEvent(self, e: QMouseEvent): return True # Dont let the release go to the editor frame def leaveEvent(self, e: QMouseEvent): - self.childWidget.setAttribute(Qt.WA_TransparentForMouseEvents, True) - self.setStyleSheet("border: none;") - + if(self.childWidget.hasFocus() == False): + self.childWidget.setAttribute(Qt.WA_TransparentForMouseEvents, True) + self.setStyleSheet("border: none;") # If mouse leaves draggable container, set focus to the editor #if self.childWidget.hasFocus(): # self.setFocus()''' + # this is to lose the border of the draggable container if the container is no longer in focus + def focusOutEvent(self, event): + self.setStyleSheet("border: none;") + self.childWidget.setAttribute(Qt.WA_TransparentForMouseEvents, True) + super().focusOutEvent(event) + + def buildDragContainerMenu(self): # Get custom menu actions from child widget diff --git a/Widgets/Textbox.py b/Widgets/Textbox.py index 43dd13c..e1758bc 100644 --- a/Widgets/Textbox.py +++ b/Widgets/Textbox.py @@ -18,11 +18,11 @@ def check_appearance(): p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) return bool(p.communicate()[0]) - + self.setGeometry(x, y, w, h) # This sets geometry of DraggableObject self.setText(t) - self.setStyleSheet("selection-background-color: #FFFFFF;") + # self.setStyleSheet("background-color: rgba(0, 0, 0, 0); selection-background-color: #FFFFFF;") self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) @@ -65,9 +65,25 @@ def setCursorPosition(self, event): cursor = self.cursorForPosition(event.pos()) self.setTextCursor(cursor) + # Initial size is w=15, h=30. once changes to textbox has been detected, change the size def textChangedEvent(self): + width = 150 + height = 50 if len(self.toPlainText()) < 2: - self.resize(100, 100) + self.resize(width, height) + else: + # handle cases where text reaches past the textbox + document = self.document() + documentSize = document.size().toSize() + documentHeight = documentSize.height() + # the document height is the text height. This is to expand the widget size to match document height + if(newHeight < documentHeight): + newHeight = documentHeight + self.resize(width, height) + + + + @staticmethod def new(clickPos: QPoint): @@ -187,30 +203,17 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): ) bold.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontBold, None)) - italic = build_action( - toolbarBottom, "./Assets/icons/svg_font_italic", "Italic", "Italic", True - ) + italic = build_action(toolbarBottom, "./Assets/icons/svg_font_italic", "Italic", "Italic", True) italic.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontItalic, None)) - underline = build_action(toolbarBottom,"./Assets/icons/svg_font_underline","Underline","Underline",True, - ) - underline.toggled.connect( - lambda x: self.setFontUnderlineCustom(True if x else False) - ) + underline = build_action(toolbarBottom,"./Assets/icons/svg_font_underline","Underline","Underline",True,) + underline.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontUnderline, None)) - strikethrough = build_action( - toolbarBottom,"./Assets/icons/svg_strikethrough", "Strikethrough", "Strikethrough", True - ) - strikethrough.toggled.connect(lambda: self.setStrikeOut()) + strikethrough = build_action(toolbarBottom,"./Assets/icons/svg_strikethrough", "Strikethrough", "Strikethrough", True) + strikethrough.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Strikethrough, None)) - fontColor = build_action( - toolbarBottom, - "./Assets/icons/svg_font_color", - "Font Color", - "Font Color", - False, - ) + fontColor = build_action(toolbarBottom,"./Assets/icons/svg_font_color","Font Color","Font Color",False) fontColor.triggered.connect( lambda: self.setTextColorCustom(QColorDialog.getColor()) ) From 629136bcb6b6e9cb1943bd9761852ce115575fd3 Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Mon, 1 Apr 2024 20:44:25 -0500 Subject: [PATCH 112/127] minor changes - fixed typo - removed experimental changes with focusOutEvent - fixing changes from refactoring --- Models/DraggableContainer.py | 24 +++++++++++++----------- Widgets/Textbox.py | 32 ++++++++++++-------------------- 2 files changed, 25 insertions(+), 31 deletions(-) diff --git a/Models/DraggableContainer.py b/Models/DraggableContainer.py index d0a32a7..1f40573 100644 --- a/Models/DraggableContainer.py +++ b/Models/DraggableContainer.py @@ -53,9 +53,10 @@ def __init__(self, childWidget, editorFrame): self.menu = self.buildDragContainerMenu() if hasattr(self.childWidget, "newGeometryEvent"): self.newGeometry.connect(childWidget.newGeometryEvent) - editorSignalsInstance.widgetAttributeChanged.connect(self.deselect) - + + editorSignalsInstance.widgetAttributeChanged.connect(self.deselect_and_delete) + def setChildWidget(self, childWidget): if childWidget: @@ -120,7 +121,7 @@ def mousePressEvent(self, e: QMouseEvent): else: # Handle the case where self.childWidget is not a TextBox pass''' - # need to add code for setting cursor to the end of the textbox + # On double click, focus on child and make mouse events pass through this container to child @@ -138,18 +139,19 @@ def mouseReleaseEvent(self, e: QMouseEvent): return True # Dont let the release go to the editor frame def leaveEvent(self, e: QMouseEvent): - if(self.childWidget.hasFocus() == False): - self.childWidget.setAttribute(Qt.WA_TransparentForMouseEvents, True) - self.setStyleSheet("border: none;") + #if(self.childWidget.hasFocus() == False): + self.childWidget.setAttribute(Qt.WA_TransparentForMouseEvents, True) + self.setStyleSheet("border: none;") # If mouse leaves draggable container, set focus to the editor #if self.childWidget.hasFocus(): # self.setFocus()''' # this is to lose the border of the draggable container if the container is no longer in focus - def focusOutEvent(self, event): - self.setStyleSheet("border: none;") + '''def focusOutEvent(self, event: QMouseEvent): + print("FOCUS OUT EVENT CALLED FROM DRAGGABLE CONTAINER") self.childWidget.setAttribute(Qt.WA_TransparentForMouseEvents, True) - super().focusOutEvent(event) + self.setStyleSheet("border: none;") + super().focusOutEvent(event)''' def buildDragContainerMenu(self): @@ -175,7 +177,7 @@ def buildDragContainerMenu(self): copy.triggered.connect(lambda: editorSignalsInstance.widgetCopied.emit(self)) paste = QAction("&Paste", self) - paste.triggered.connect(lambda: self.pasteWidget(event.pos())) + paste.triggered.connect(lambda: self.pasteWidget(self.pos())) delete = QAction("&Delete", self) delete.triggered.connect(lambda: editorSignalsInstance.widgetRemoved.emit(self)) @@ -405,7 +407,7 @@ def mouseMoveEvent(self, e: QMouseEvent): self.newGeometry.emit(self.geometry()) # Used for deselecting text and removing container if empty - def deselect(self, changedWidgetAttribute): + def deselect_and_delete(self, changedWidgetAttribute): #print(f"changedWidgetAttribute is {changedWidgetAttribute} and value is {value}") child_widget = self.childWidget diff --git a/Widgets/Textbox.py b/Widgets/Textbox.py index e1758bc..ead97f0 100644 --- a/Widgets/Textbox.py +++ b/Widgets/Textbox.py @@ -29,6 +29,7 @@ def check_appearance(): self.textChanged.connect(self.textChangedEvent) editorSignalsInstance.widgetAttributeChanged.connect(self.widgetAttributeChanged) + if check_appearance() == True: @@ -77,10 +78,12 @@ def textChangedEvent(self): documentSize = document.size().toSize() documentHeight = documentSize.height() # the document height is the text height. This is to expand the widget size to match document height - if(newHeight < documentHeight): - newHeight = documentHeight + if(height < documentHeight): + height = documentHeight self.resize(width, height) - + def focusOutEvent(self, event): + super().focusOutEvent(event) + @@ -115,6 +118,7 @@ def checkEmpty(self): # Handles events from any toolbar button def widgetAttributeChanged(self, changedWidgetAttribute, value): # dictionary of toolbar functions + print(f"{changedWidgetAttribute} {value}") attribute_functions = { # note: for functions with no value passed, lambda _ will allow it to pass with no value @@ -226,23 +230,11 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): False, ) # bgColor.triggered.connect(lambda: self.setBackgroundColor(QColorDialog.getColor())) - bgColor.triggered.connect( - lambda: self.changeBackgroundColorEvent(QColorDialog.getColor()) - ) - textHighlightColor = build_action( - toolbarBottom, - "./Assets/icons/svg_textHighlightColor", - "Text Highlight Color", - "Text Highlight Color", - False, - ) - textHighlightColor.triggered.connect( - lambda: self.changeTextHighlightColorEvent(QColorDialog.getColor()) - ) + bgColor.triggered.connect(lambda: self.changeBackgroundColorEvent(QColorDialog.getColor())) + textHighlightColor = build_action(toolbarBottom,"./Assets/icons/svg_textHighlightColor","Text Highlight Color","Text Highlight Color",False,) + textHighlightColor.triggered.connect(lambda: self.changeTextHighlightColorEvent(QColorDialog.getColor())) - bullets = build_action( - toolbarBottom, "./Assets/icons/svg_bullets", "Bullets", "Bullets", True - ) + bullets = build_action(toolbarBottom, "./Assets/icons/svg_bullets", "Bullets", "Bullets", True) bullets.toggled.connect(lambda: self.bullet_list("bulletReg")) toolbarTop.addWidget(font) @@ -598,7 +590,7 @@ def changeBackgroundColorEvent(self, color: QColor): if color.isValid(): rgb = color.getRgb() - self.setStyleSheet(f"QTextBrowser {{background-color: rgb({rgb[0]}, {rgb[1]}, {rgb[2]}); }}") + self.setStyleSheet(f"QTextEdit {{background-color: rgb({rgb[0]}, {rgb[1]}, {rgb[2]}); }}") else: rgb = (color, g, b) From 35b20062b5aa56dc887f194e48941f628b9cfdb6 Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Mon, 1 Apr 2024 21:07:58 -0500 Subject: [PATCH 113/127] fixing widgetattributechanged function --- Widgets/Textbox.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/Widgets/Textbox.py b/Widgets/Textbox.py index ead97f0..0a6bb22 100644 --- a/Widgets/Textbox.py +++ b/Widgets/Textbox.py @@ -29,7 +29,6 @@ def check_appearance(): self.textChanged.connect(self.textChangedEvent) editorSignalsInstance.widgetAttributeChanged.connect(self.widgetAttributeChanged) - if check_appearance() == True: @@ -37,7 +36,6 @@ def check_appearance(): #self.changeBackgroundColorEvent(31, 31, 30) self.setTextColor("white") self.changeAllTextColors("white") - self.set else: self.setStyleSheet("background-color: rgba(0, 0, 0, 0);") #self.changeBackgroundColorEvent(0,0,0) @@ -118,7 +116,6 @@ def checkEmpty(self): # Handles events from any toolbar button def widgetAttributeChanged(self, changedWidgetAttribute, value): # dictionary of toolbar functions - print(f"{changedWidgetAttribute} {value}") attribute_functions = { # note: for functions with no value passed, lambda _ will allow it to pass with no value @@ -139,16 +136,17 @@ def widgetAttributeChanged(self, changedWidgetAttribute, value): # Bullet list functions ChangedWidgetAttribute.Bullet: lambda _: self.bullet_list("bulletReg"), ChangedWidgetAttribute.Bullet_Num: lambda _: self.bullet_list("bulletNum"), - ChangedWidgetAttribute.Bullet_Num: lambda _: self.bullet_list("bulletUpperA"), - ChangedWidgetAttribute.Bullet_Num: lambda _: self.bullet_list("bulletUpperR"), + ChangedWidgetAttribute.BulletUA: lambda _: self.bullet_list("bulletUpperA"), + ChangedWidgetAttribute.BulletUR: lambda _: self.bullet_list("bulletUpperR"), # Alignment functions - ChangedWidgetAttribute.Bullet_Num: lambda _: self.changeAlignmentEvent("alignLeft"), - ChangedWidgetAttribute.Bullet_Num: lambda _: self.changeAlignmentEvent("alignCenter"), - ChangedWidgetAttribute.Bullet_Num: lambda _: self.changeAlignmentEvent("alignRight") + ChangedWidgetAttribute.AlignLeft: lambda _: self.changeAlignmentEvent("alignLeft"), + ChangedWidgetAttribute.AlignCenter: lambda _: self.changeAlignmentEvent("alignCenter"), + ChangedWidgetAttribute.AlignRight: lambda _: self.changeAlignmentEvent("alignRight") } if self.hasFocus and changedWidgetAttribute in attribute_functions: + print(f"{changedWidgetAttribute} {value}") # Calls the function in the dictionary attribute_functions[changedWidgetAttribute](value) else: From d27f24f3b59efec9614955295be32fc530f6c742 Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Mon, 1 Apr 2024 21:26:17 -0500 Subject: [PATCH 114/127] fixed bullets, align, and background color --- Widgets/Textbox.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Widgets/Textbox.py b/Widgets/Textbox.py index 0a6bb22..765302c 100644 --- a/Widgets/Textbox.py +++ b/Widgets/Textbox.py @@ -145,7 +145,7 @@ def widgetAttributeChanged(self, changedWidgetAttribute, value): ChangedWidgetAttribute.AlignRight: lambda _: self.changeAlignmentEvent("alignRight") } - if self.hasFocus and changedWidgetAttribute in attribute_functions: + if (self.hasFocus() or self.parentWidget().hasFocus()) and changedWidgetAttribute in attribute_functions: print(f"{changedWidgetAttribute} {value}") # Calls the function in the dictionary attribute_functions[changedWidgetAttribute](value) From 43866d4ddf8c84c10a22d3e341213e488ae83414 Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Wed, 3 Apr 2024 22:41:34 -0500 Subject: [PATCH 115/127] minor changes --- Modules/BuildUI.py | 6 +++--- Widgets/Textbox.py | 11 +++-------- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index 71ba521..8adef42 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -232,8 +232,8 @@ def handleCheck(action): delete.triggered.connect(lambda: editorSignalsInstance.widgetRemoved.emit(DraggableContainer)) # Bullets with placeholder for more bullet options - bullet = build_action(editor.homeToolbar, './Assets/icons/svg_bullets', "Bullets", "Bullets", False) - bullet.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Bullet, None)) + bullets = build_action(editor.homeToolbar, './Assets/icons/svg_bullets', "Bullets", "Bullets", False) + bullets.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Bullet, None)) editor.homeToolbar.addWidget(spacer1) editor.homeToolbar.addActions([paste, cut, copy]) @@ -245,7 +245,7 @@ def handleCheck(action): editor.homeToolbar.addSeparator() - editor.homeToolbar.addActions([bold, italic, underline, strikethrough, refactor, fontColor, textHighlightColor, bgColor, delete, bullet]) + editor.homeToolbar.addActions([bold, italic, underline, strikethrough, refactor, fontColor, textHighlightColor, bgColor, delete, bullets]) # numbering menu start numbering_menu = QMenu(editor) diff --git a/Widgets/Textbox.py b/Widgets/Textbox.py index 765302c..e11af46 100644 --- a/Widgets/Textbox.py +++ b/Widgets/Textbox.py @@ -144,8 +144,9 @@ def widgetAttributeChanged(self, changedWidgetAttribute, value): ChangedWidgetAttribute.AlignCenter: lambda _: self.changeAlignmentEvent("alignCenter"), ChangedWidgetAttribute.AlignRight: lambda _: self.changeAlignmentEvent("alignRight") } - + # if current widget is in focus if (self.hasFocus() or self.parentWidget().hasFocus()) and changedWidgetAttribute in attribute_functions: + #if self.hasFocus() and changedWidgetAttribute in attribute_functions: print(f"{changedWidgetAttribute} {value}") # Calls the function in the dictionary attribute_functions[changedWidgetAttribute](value) @@ -220,13 +221,7 @@ def build_action(parent, icon_path, action_name, set_status_tip, set_checkable): lambda: self.setTextColorCustom(QColorDialog.getColor()) ) - bgColor = build_action( - toolbarBottom, - "./Assets/icons/svg_font_bucket", - "Background Color", - "Background Color", - False, - ) + bgColor = build_action(toolbarBottom,"./Assets/icons/svg_font_bucket","Background Color","Background Color",False) # bgColor.triggered.connect(lambda: self.setBackgroundColor(QColorDialog.getColor())) bgColor.triggered.connect(lambda: self.changeBackgroundColorEvent(QColorDialog.getColor())) textHighlightColor = build_action(toolbarBottom,"./Assets/icons/svg_textHighlightColor","Text Highlight Color","Text Highlight Color",False,) From 131a6fa6af3e45fb1522e56063b081f15de30533 Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Wed, 3 Apr 2024 23:08:48 -0500 Subject: [PATCH 116/127] Fix minor typo which caused multiselect issue --- Widgets/Textbox.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Widgets/Textbox.py b/Widgets/Textbox.py index e11af46..4a6b3ad 100644 --- a/Widgets/Textbox.py +++ b/Widgets/Textbox.py @@ -145,7 +145,7 @@ def widgetAttributeChanged(self, changedWidgetAttribute, value): ChangedWidgetAttribute.AlignRight: lambda _: self.changeAlignmentEvent("alignRight") } # if current widget is in focus - if (self.hasFocus() or self.parentWidget().hasFocus()) and changedWidgetAttribute in attribute_functions: + if (self.hasFocus or self.parentWidget.hasFocus) and changedWidgetAttribute in attribute_functions: #if self.hasFocus() and changedWidgetAttribute in attribute_functions: print(f"{changedWidgetAttribute} {value}") # Calls the function in the dictionary From e59c027c4329a080fc4adf45f5f6bae54b21acc0 Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Thu, 4 Apr 2024 00:03:59 -0500 Subject: [PATCH 117/127] Removing changes made for testing --- Models/Editor.py | 4 ++-- Modules/BuildUI.py | 3 --- Widgets/Textbox.py | 3 --- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/Models/Editor.py b/Models/Editor.py index 599c331..ef29eb0 100644 --- a/Models/Editor.py +++ b/Models/Editor.py @@ -19,8 +19,8 @@ class Editor(QMainWindow): def __init__(self): super().__init__() - # self.setWindowFlags(Qt.WindowType.FramelessWindowHint) - # self.setWindowFlags(Qt.WindowType.Window | Qt.WindowType.CustomizeWindowHint) + self.setWindowFlags(Qt.WindowType.FramelessWindowHint) + # self.setWindowFlags(Qt.WindowType.Window | Qt.WindowType.CustomizeWindowHint) # This changes the window back to a state that allows resizing self.notebook = NotebookModel('Untitled Notebook') # Current notebook object # self.selected = None # Selected object (for font attributes of TextBox) diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index 8adef42..6dbd080 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -212,12 +212,9 @@ def handleCheck(action): bold = build_action(editor.homeToolbar, './Assets/icons/bold', "Bold", "Bold", True) bold.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontBold, None)) - #if(checkMade == CheckSignal.BoldCheck): - # handleCheck(bold) italic = build_action(editor.homeToolbar, './Assets/icons/italic.svg', "Italic", "Italic", True) italic.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontItalic, None)) - italic.setChecked(True) underline = build_action(editor.homeToolbar, './Assets/icons/underline.svg', "Underline", "Underline", True) underline.toggled.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.FontUnderline, None)) diff --git a/Widgets/Textbox.py b/Widgets/Textbox.py index 4a6b3ad..aac56d6 100644 --- a/Widgets/Textbox.py +++ b/Widgets/Textbox.py @@ -584,10 +584,7 @@ def changeBackgroundColorEvent(self, color: QColor): if color.isValid(): rgb = color.getRgb() self.setStyleSheet(f"QTextEdit {{background-color: rgb({rgb[0]}, {rgb[1]}, {rgb[2]}); }}") - else: - rgb = (color, g, b) - self.setStyleSheet(f"background-color: rgb({rgb[0]}, {rgb[1]}, {rgb[2]});") self.deselectText() # Changes textbox background color From a9da77a89e9a9405dfa4b8a08a1961df4d16b9ce Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Thu, 4 Apr 2024 01:02:39 -0500 Subject: [PATCH 118/127] small fix --- Widgets/Textbox.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Widgets/Textbox.py b/Widgets/Textbox.py index aac56d6..4312a7a 100644 --- a/Widgets/Textbox.py +++ b/Widgets/Textbox.py @@ -145,7 +145,7 @@ def widgetAttributeChanged(self, changedWidgetAttribute, value): ChangedWidgetAttribute.AlignRight: lambda _: self.changeAlignmentEvent("alignRight") } # if current widget is in focus - if (self.hasFocus or self.parentWidget.hasFocus) and changedWidgetAttribute in attribute_functions: + if (self.hasFocus or self.parentWidget().hasFocus) and changedWidgetAttribute in attribute_functions: #if self.hasFocus() and changedWidgetAttribute in attribute_functions: print(f"{changedWidgetAttribute} {value}") # Calls the function in the dictionary From 6b1b7658314c4236590199c5991b0bb06c885418 Mon Sep 17 00:00:00 2001 From: Jettorix <109848112+Jettorix@users.noreply.github.com> Date: Wed, 10 Apr 2024 17:01:01 -0500 Subject: [PATCH 119/127] Added Undo/Redo buttons to toolabr --- Modules/BuildUI.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index 6dbd080..b662717 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -232,6 +232,11 @@ def handleCheck(action): bullets = build_action(editor.homeToolbar, './Assets/icons/svg_bullets', "Bullets", "Bullets", False) bullets.triggered.connect(lambda: editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.Bullet, None)) + + # Adds the undo and redo buttons to the toolbar + undo = build_action(editor.homeToolbar, './Assets/icons/svg_undo', "Undo", "Undo", False) + redo = build_action(editor.homeToolbar, './Assets/icons/svg_redo', "Redo", "Redo", False) + editor.homeToolbar.addWidget(spacer1) editor.homeToolbar.addActions([paste, cut, copy]) @@ -430,4 +435,4 @@ def build_menubutton(parent, icon_path, text, tooltip, style, menu): button.setObjectName(tooltip) button.setStyleSheet(style) button.setMenu(menu) - return button \ No newline at end of file + return button From 9ebe8200751bf35b7c58f5d5865b4b5eec14f554 Mon Sep 17 00:00:00 2001 From: Jettorix <109848112+Jettorix@users.noreply.github.com> Date: Wed, 10 Apr 2024 17:02:31 -0500 Subject: [PATCH 120/127] Small toolbar change --- Modules/BuildUI.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index b662717..e94b4b9 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -247,7 +247,7 @@ def handleCheck(action): editor.homeToolbar.addSeparator() - editor.homeToolbar.addActions([bold, italic, underline, strikethrough, refactor, fontColor, textHighlightColor, bgColor, delete, bullets]) + editor.homeToolbar.addActions([undo, redo, bold, italic, underline, strikethrough, fontColor, textHighlightColor, bgColor, delete, bullet]) # numbering menu start numbering_menu = QMenu(editor) From bb822c1d91fab6bd61e395ed4dc8acbd237a7c87 Mon Sep 17 00:00:00 2001 From: sillypenguin77 <67487654+sillypenguin77@users.noreply.github.com> Date: Wed, 10 Apr 2024 22:03:03 -0500 Subject: [PATCH 121/127] Updated documentation Added comments to various pages to better understand the code. --- Models/DraggableContainer.py | 14 ++++++++++---- Models/Editor.py | 21 +++++++++++++-------- Models/NotebookModel.py | 9 ++++++--- Models/PageModel.py | 6 ++++-- Models/SectionModel.py | 2 +- Modules/BuildUI.py | 15 +++++++++++++-- Modules/Clipboard.py | 8 ++++++-- Modules/Load.py | 4 ++++ Modules/Screensnip.py | 15 ++++++++++++++- Views/EditorFrameView.py | 21 ++++++++++++++++----- Views/NotebookTitleView.py | 1 + 11 files changed, 88 insertions(+), 28 deletions(-) diff --git a/Models/DraggableContainer.py b/Models/DraggableContainer.py index 653ad86..33bfd6b 100644 --- a/Models/DraggableContainer.py +++ b/Models/DraggableContainer.py @@ -25,9 +25,10 @@ class DraggableContainer(QWidget): menu = None mode = Mode.NONE position = None - outFocus = Signal(bool) - newGeometry = Signal(QRect) + outFocus = Signal(bool) # Signal emitted when the container loses focus + newGeometry = Signal(QRect) # Signal emitted when the container's geometry changes + # Initializes a DraggableContainer object def __init__(self, childWidget, editorFrame): super().__init__(parent=editorFrame) @@ -74,6 +75,7 @@ def eventFilter(self, obj, e): self.resize(self.childWidget.size()) return False + # Displays the container menu at a given position def popupShow(self, pt: QPoint): global_ = self.mapToGlobal(pt) self.m_showMenu = True @@ -136,6 +138,7 @@ def leaveEvent(self, e: QMouseEvent): #if self.childWidget.hasFocus(): # self.setFocus()''' + # Builds and returns the context menu for the container def buildDragContainerMenu(self): # Get custom menu actions from child widget @@ -258,7 +261,7 @@ def buildDragContainerMenu(self): if type(item) != QWidgetAction: menu.addAction(item) - return menu + return menu # returns the QMenu: The constructed context menu # Determine which cursor to show and which mode to be in when user is interacting with the box def setCursorShape(self, e_pos: QPoint): @@ -493,13 +496,16 @@ def keyReleaseEvent(self, event: QKeyEvent) -> None: else: super().keyReleaseEvent(event) + # Pastes a widget at the specified position def pasteWidget(self, clickPos): widgetOnClipboard = self.clipboard.getWidgetToPaste() - dc = DraggableContainer(widgetOnClipboard, self) + dc = DraggableContainer(widgetOnClipboard, self) # Create a new DraggableContainer with the widget to paste self.undoHandler.pushCreate(dc) editorSignalsInstance.widgetAdded.emit(dc) # Notify section that widget was added editorSignalsInstance.changeMade.emit() + + # Move the container to the specified position and show it dc.move(clickPos.x(), clickPos.y()) dc.show() diff --git a/Models/Editor.py b/Models/Editor.py index cc06222..61c3532 100644 --- a/Models/Editor.py +++ b/Models/Editor.py @@ -19,7 +19,7 @@ class Editor(QMainWindow): def __init__(self): super().__init__() - self.setWindowFlag(Qt.WindowType.FramelessWindowHint) + self.setWindowFlag(Qt.WindowType.FramelessWindowHint) self.notebook = NotebookModel('Untitled Notebook') # Current notebook object # self.selected = None # Selected object (for font attributes of TextBox) @@ -33,14 +33,15 @@ def __init__(self): self.autosaver = Autosaver(self) # Waits for change signals and saves the notebook self.setFocus() - self.settings = QSettings("UNT - Team Olive", "OpenNote") + self.settings = QSettings("UNT - Team Olive", "OpenNote") #pre-saved settings needed for window state restoration build_ui(self) action_names = self.save_toolbar_actions([self.homeToolbar, self.insertToolbar, self.drawToolbar]) self.titlebar.set_action_names(action_names) + + # Handles the window close event, it saves the window's geometry and state before exiting def closeEvent(self, event): - # Save window size and position before exiting print("Window closing event triggered") @@ -48,8 +49,8 @@ def closeEvent(self, event): self.settings.setValue("windowState", self.saveState()) super().closeEvent(event) + # Handles the window showing event, it restores the window's geometry and state def showEvent(self, event): - # Restores window size and position print("Window showing event triggered") @@ -59,12 +60,14 @@ def showEvent(self, event): # def focusInEvent(self, event): # self.repaint() + # Handles changes in window state, particularly the window state change event def changeEvent(self, event): if event.type() == QEvent.Type.WindowStateChange: self.titlebar.window_state_changed(self.windowState()) super().changeEvent(event) event.accept() + # mousePress, mouseMove, and mouseRelease handle mouse move events inside the window def mousePressEvent(self, event): if event.button() == Qt.LeftButton: self.moveFlag = True @@ -80,15 +83,17 @@ def mouseMoveEvent(self, event): def mouseReleaseEvent(self, QMouseEvent): self.moveFlag = False + # Collects action names from the toolbars def save_toolbar_actions(self, toolbars): action_names = [] - for toolbar in toolbars: + for toolbar in toolbars: #loops through all toolbars for action in toolbar.actions(): if action.objectName(): - action_names.append(action.objectName()) + action_names.append(action.objectName()) # Add the object name of the action to the list + # Loop through child widgets of the toolbar (buttons, tool buttons, combo boxes) for widget in toolbar.findChildren(QPushButton) + toolbar.findChildren(QToolButton) + toolbar.findChildren(QComboBox): if widget.objectName() and widget.objectName() != "qt_toolbar_ext_button": - action_names.append(widget.objectName()) + action_names.append(widget.objectName()) # Add the object name of the widget to the list - return action_names \ No newline at end of file + return action_names # Return the list of action names collected from the toolbars \ No newline at end of file diff --git a/Models/NotebookModel.py b/Models/NotebookModel.py index 6ecf21e..c92a71e 100644 --- a/Models/NotebookModel.py +++ b/Models/NotebookModel.py @@ -1,5 +1,8 @@ + +# Represents a notebook in the application. class NotebookModel: def __init__(self, title): - self.path = None - self.title = title - self.pages = [] # PageModel[] + self.path = None # The file path of the notebook if saved + self.title = title # The title of the notebook + + self.pages = [] # PageModel[] - List to store PageModel instances representing pages in the notebook diff --git a/Models/PageModel.py b/Models/PageModel.py index 06b426d..77ca4e3 100644 --- a/Models/PageModel.py +++ b/Models/PageModel.py @@ -1,9 +1,11 @@ import uuid +# Represents a page within a notebook + class PageModel: def __init__(self, title: str, parentUuid: int = 0): self.title = title - self.sections = [] # SectionModel[] + self.sections = [] # SectionModel[] - List to store SectionModel instances representing sections in the page # These are used to represent the tree structure, the model is not actually concerned with parent and children # The tree structure lets us build a view that we can interact with as if there were really nested pages @@ -14,7 +16,7 @@ def __init__(self, title: str, parentUuid: int = 0): def newRootPage(): rootPage = PageModel("Notebook") rootPage.__uuid = 0 - return rootPage + return rootPage # A new root page def isRoot(self): return self.__uuid == 0 diff --git a/Models/SectionModel.py b/Models/SectionModel.py index 522d404..f9c9df9 100644 --- a/Models/SectionModel.py +++ b/Models/SectionModel.py @@ -6,7 +6,7 @@ class SectionModel: def __init__(self, title: str): self.title = title - self.widgets: List[DraggableContainer] = [] + self.widgets: List[DraggableContainer] = [] # List of draggable containers in the section, each container holds an instance of a widget (ex. TextboxWidget) # When saving, convert the list of DraggableContainers to a list of their child widget's models def __getstate__(self): diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index 422c84e..ba869cf 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -26,6 +26,8 @@ def build_ui(editor): editor.resize(800, 450) editor.setAcceptDrops(True) + + # Checks wether mac is in dark mode, then sets proper window css if check_appearance() == False: with open('./Styles/styles.qss',"r") as fh: editor.setStyleSheet(fh.read()) @@ -100,6 +102,8 @@ def build_ui(editor): #editor.restoreGeometry(editor.settings.value("geometry", editor.saveGeometry())) #editor.restoreState(editor.settings.value("windowState", editor.saveState())) +# Constructs the menu bar with different menus like File, Home, Insert, Draw, and Plugins +# It adds actions to these menus and connects them to their functions def build_menubar(editor): editor.menubar = editor.menuBar() @@ -142,6 +146,8 @@ def build_menubar(editor): draw.addAction(toggle_draw_toolbar) plugins.addAction(add_widget) +# Constructs toolbars for different functionalities like home, insert, and draw +# It adds actions and buttons to these toolbars and connects them to their functions def build_toolbar(editor): # homeToolbar code editor.homeToolbar = QToolBar() @@ -374,6 +380,7 @@ def check_appearance(): stderr=subprocess.PIPE, shell=True) return bool(p.communicate()[0]) +# toggles the visibility of the specified toolbar based on user interaction def set_toolbar_visibility(editor, triggered_toolbar): # Find all toolbars in the editor toolbars = editor.findChildren(QToolBar) @@ -388,6 +395,7 @@ def set_toolbar_visibility(editor, triggered_toolbar): # Hide all other toolbars toolbar.setVisible(False) +# opens a color dialog for selecting font color or background color def openGetColorDialog(purpose): color = QColorDialog.getColor() if color.isValid(): @@ -396,13 +404,15 @@ def openGetColorDialog(purpose): elif purpose == "background": editorSignalsInstance.widgetAttributeChanged.emit(ChangedWidgetAttribute.BackgroundColor, color) +# creates a QAction object with the specified parameters def build_action(parent, icon_path, action_name, tooltip, checkable): action = QAction(QIcon(icon_path), action_name, parent) action.setObjectName(action_name) action.setStatusTip(tooltip) action.setCheckable(checkable) return action - + +# creates a QPushButton widget with the specified parameters def build_button(parent, icon_path, text, tooltip, checkable): button = QPushButton(parent) button.setIcon(QIcon(icon_path)) @@ -411,7 +421,8 @@ def build_button(parent, icon_path, text, tooltip, checkable): button.setToolTip(tooltip) button.setCheckable(checkable) return button - + +# creates a QToolButton widget with an associated menu def build_menubutton(parent, icon_path, text, tooltip, style, menu): button = QToolButton(parent) button.setIconSize(QSize(18,18)) diff --git a/Modules/Clipboard.py b/Modules/Clipboard.py index 91e2f07..aad99b6 100644 --- a/Modules/Clipboard.py +++ b/Modules/Clipboard.py @@ -2,17 +2,21 @@ class Clipboard: def __init__(self): + + # Initialize variables to store copied widget state and class self.copiedWidgetState = None self.copiedWidgetClass = None editorSignalsInstance.widgetCopied.connect(self.copyWidgetEvent) + # triggered when a widget is copied def copyWidgetEvent(self, draggableContainer): - widget = draggableContainer.childWidget + widget = draggableContainer.childWidget # Get the child widget from the draggable container print("copy widget") self.copiedWidgetClass = type(widget) self.copiedWidgetState = widget.__getstate__() + # def getWidgetToPaste(self): widgetState = self.copiedWidgetState widgetClass = self.copiedWidgetClass @@ -20,4 +24,4 @@ def getWidgetToPaste(self): newWidget = widgetClass.__new__(widgetClass) # Get uninitialized instance of widget class newWidget.__setstate__(widgetState) # Initialize the widget instance with its setstate method - return newWidget + return newWidget # Return the initialized widget instance diff --git a/Modules/Load.py b/Modules/Load.py index bce98b7..5add389 100644 --- a/Modules/Load.py +++ b/Modules/Load.py @@ -23,6 +23,8 @@ def new(editor): # Loads models.notebook.Notebook class from file def load(editor): print("LOADING") + + # Open file dialog for selecting notebook file path, accept = QFileDialog.getOpenFileName( editor, 'Open Notebook', @@ -47,6 +49,7 @@ def load(editor): def load_most_recent_notebook(editor): print("LOAD RECENT RAN") + # Search for most recent notebook file files = [] saves_directory = os.path.join(os.getcwd(), 'Saves') for file in os.listdir(saves_directory): @@ -60,6 +63,7 @@ def load_most_recent_notebook(editor): if (f.endswith(".on") or f.endswith(".ontemp")): print("FOUND: " + str(f)) try: + # Open and load the notebook # prob need load from file function, dup functionality file = open(os.path.join(os.getcwd() + "\\Saves", f), 'rb') destroy(editor) diff --git a/Modules/Screensnip.py b/Modules/Screensnip.py index 5ef9e48..9dd22f9 100644 --- a/Modules/Screensnip.py +++ b/Modules/Screensnip.py @@ -14,6 +14,7 @@ class SnippingWidget(QWidget): def __init__(self): super(SnippingWidget, self).__init__() + # Set window attributes based on the platform if platform == "linux": self.setWindowFlags(Qt.FramelessWindowHint) self.setAttribute(Qt.WA_TranslucentBackground) @@ -30,6 +31,7 @@ def start(self, event_pos): print("SnippingWidget.start") SnippingWidget.is_snipping = True + # Set window opacity and cursor based on the platform if platform != "linux": self.setWindowOpacity(0.3) @@ -38,6 +40,7 @@ def start(self, event_pos): self.show() print("SnippingWidget.start done") + # handle painting the snipping rectangle def paintEvent(self, event): if SnippingWidget.is_snipping: #brush_color = (128, 128, 255, 100) @@ -49,11 +52,13 @@ def paintEvent(self, event): self.setWindowOpacity(opacity) qp = QPainter(self) + # Set pen and brush for drawing the rectangle qp.setPen(QPen(QColor('black'), lw)) qp.setBrush(QColor(*brush_color)) rect = QRectF(self.begin, self.end) qp.drawRect(rect) else: + # Reset coordinates and brush color when snipping is not in progress self.begin = QPoint() self.end = QPoint() brush_color = (0, 0, 0, 0) @@ -70,18 +75,24 @@ def mouseMoveEvent(self, event): self.update() def mouseReleaseEvent(self, event): + + # Set the flag to indicate that snipping is complete SnippingWidget.is_snipping = False QApplication.restoreOverrideCursor() + + # Calculate the coordinates of the snipped area rect = self.geometry() x1 = min(self.begin.x(), self.end.x()) + rect.left() y1 = min(self.begin.y(), self.end.y()) + rect.top() x2 = max(self.begin.x(), self.end.x()) + rect.left() y2 = max(self.begin.y(), self.end.y()) + rect.top() + # Repaint the widget and process any pending events self.repaint() QApplication.processEvents() try: + # Capture the screenshot of the snipped area if platform == "darwin": #img = ImageGrab.grab(bbox=( (x1 ) * 2, (y1 + 55 ) * 2, (x2 ) * 2, (y2 + 55) * 2)) [may be needed for different mac version - testing in progress] img = ImageGrab.grab(bbox=(x1, y1 + 55, x2, y2 + 55)) # For mac version 14.1.2 @@ -94,10 +105,12 @@ def mouseReleaseEvent(self, event): try: + # Convert the captured image to OpenCV format for further processing img = cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR) except: img = None - + + # Trigger the snipping completed callback with the captured image if self.onSnippingCompleted is not None: self.onSnippingCompleted(img) diff --git a/Views/EditorFrameView.py b/Views/EditorFrameView.py index 6a6e520..9e08527 100644 --- a/Views/EditorFrameView.py +++ b/Views/EditorFrameView.py @@ -23,7 +23,7 @@ # Handles all widget display (could be called widget view, but so could draggablecontainer) class EditorFrameView(QWidget): - SETTINGS_KEY = "BackgroundColor" + SETTINGS_KEY = "BackgroundColor" # Key for saving the background color setting def __init__(self, editor): super(EditorFrameView, self).__init__() @@ -36,6 +36,7 @@ def check_appearance(): stderr=subprocess.PIPE, shell=True) return bool(p.communicate()[0]) + # Reference to the main editor window self.editor = editor # Store reference to the editor (QMainWindow) self.editorFrame = QFrame(editor) @@ -89,6 +90,7 @@ def triggerUndo(self): def pasteWidget(self, clickPos): widgetOnClipboard = self.clipboard.getWidgetToPaste() + # Create draggable container for pasted widget dc = DraggableContainer(widgetOnClipboard, self) self.undoHandler.pushCreate(dc) editorSignalsInstance.widgetAdded.emit(dc) # Notify section that widget was added @@ -104,6 +106,7 @@ def onSnippingCompleted(imageMatrix): # Called after screensnipper ge if imageMatrix is None: return + #Create image widget from the captured image widgetModel = ImageWidget.newFromMatrix(clickPos, imageMatrix) dc = DraggableContainer(widgetModel, self) self.undoHandler.pushCreate(dc) @@ -249,13 +252,17 @@ def mousePressEvent(self, event): def insertLink(self, clickPos): link_dialog = LinkDialog() - result = link_dialog.exec_() + result = link_dialog.exec_() #Execute the dialog and wait for user input if result == QDialog.Accepted: - link_address, display_text = link_dialog.get_link_data() - textboxWidget = TextboxWidget.new(clickPos) - textboxWidget.insertTextLink(link_address, display_text) + + link_address, display_text = link_dialog.get_link_data() # Get the link address and display text from the dialog + textboxWidget = TextboxWidget.new(clickPos) # Create a new TextboxWidget at the specified position + textboxWidget.insertTextLink(link_address, display_text) # Insert the hyperlink into the TextboxWidget + + # Create a DraggableContainer for the TextboxWidget and show it dc = DraggableContainer(textboxWidget, self) dc.show() + self.undoHandler.pushCreate(dc) editorSignalsInstance.widgetAdded.emit(dc) editorSignalsInstance.changeMade.emit() @@ -373,6 +380,7 @@ def mouseMoveEvent(self, e): # This event is only called after clicking down on def slot_action1(self, item): print("Action 1 triggered") + # Handles changes to the background color of the editor frame. def pageColor(self, color: QColor): print("CHANGE BACKGROUND COLOR EVENT") if color.isValid(): @@ -380,15 +388,18 @@ def pageColor(self, color: QColor): self.editorFrame.setStyleSheet(f"background-color: {color.name()};") self.saveBackgroundColor() + #Loads the previously saved background color from settings def loadBackgroundColor(self): settings = QSettings() color = settings.value(self.SETTINGS_KEY, type=QColor) return color + # Saves the current background color to settings def saveBackgroundColor(self): settings = QSettings() settings.setValue(self.SETTINGS_KEY, self.currentBackgroundColor) + # Retrieves the current background color of the editor frame def getCurrentBackgroundColor(self): return self.currentBackgroundColor diff --git a/Views/NotebookTitleView.py b/Views/NotebookTitleView.py index ca8dbb1..5faadfc 100644 --- a/Views/NotebookTitleView.py +++ b/Views/NotebookTitleView.py @@ -9,6 +9,7 @@ def __init__(self, notebookTitle: str): self.notebookTitle = notebookTitle # Reference to the title on the notebook model + # Creating the QTextEdit widget for displaying and editing the title self.titleWidget = QTextEdit() self.titleWidget.setText(self.notebookTitle) self.titleWidget.setFixedHeight(30) From 7f2048fbccae5f5c6d67e007952bc9bdba729eb1 Mon Sep 17 00:00:00 2001 From: benjamintran1 <145232360+benjamintran1@users.noreply.github.com> Date: Thu, 11 Apr 2024 11:32:06 -0500 Subject: [PATCH 122/127] Update BuildUI.py --- Modules/BuildUI.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index 1985a38..ee085fc 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -253,7 +253,7 @@ def handleCheck(action): editor.homeToolbar.addSeparator() - editor.homeToolbar.addActions([undo, redo, bold, italic, underline, strikethrough, fontColor, textHighlightColor, bgColor, delete, bullet]) + editor.homeToolbar.addActions([undo, redo, bold, italic, underline, strikethrough, fontColor, textHighlightColor, bgColor, delete, bullets]) # numbering menu start numbering_menu = QMenu(editor) From aa32c1157143c51ac116e5586754fd4f41478fe5 Mon Sep 17 00:00:00 2001 From: ldeltastreaml <70774713+ldeltastreaml@users.noreply.github.com> Date: Sat, 20 Apr 2024 16:45:15 -0500 Subject: [PATCH 123/127] Changed from Menubar to Tabbar - File and Plugin have are now toolbars instead of menus - all toolbars have moved to being inside a tabbar as per request of sponsor --- Models/Editor.py | 3 +- Modules/BuildUI.py | 151 +++++++++++++++++++++++++++------------------ Styles/styles.qss | 2 +- 3 files changed, 95 insertions(+), 61 deletions(-) diff --git a/Models/Editor.py b/Models/Editor.py index b578ac8..4314a2f 100644 --- a/Models/Editor.py +++ b/Models/Editor.py @@ -37,7 +37,8 @@ def __init__(self): self.settings = QSettings("UNT - Team Olive", "OpenNote") #pre-saved settings needed for window state restoration build_ui(self) - action_names = self.save_toolbar_actions([self.homeToolbar, self.insertToolbar, self.drawToolbar]) + + action_names = self.save_toolbar_actions([self.fileToolbar, self.homeToolbar, self.insertToolbar, self.drawToolbar, self.pluginToolbar]) self.titlebar.set_action_names(action_names) def closeEvent(self, event): diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index ee085fc..f41e021 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -35,8 +35,9 @@ def build_ui(editor): with open('./Styles/stylesDark.qss',"r") as fh: editor.setStyleSheet(fh.read()) - build_menubar(editor) - build_toolbar(editor) + build_tabbar(editor) + # build_menubar(editor) + # build_toolbar(editor) # Main layout of the app gridLayout = QGridLayout() @@ -61,10 +62,11 @@ def build_ui(editor): barsLayout.setSpacing(0) # Add the bars to the layout with individual margins - barsLayout.addWidget(editor.menubar) - barsLayout.addWidget(editor.homeToolbar) - barsLayout.addWidget(editor.insertToolbar) - barsLayout.addWidget(editor.drawToolbar) + barsLayout.addWidget(editor.tabbar) + # barsLayout.addWidget(editor.menubar) + # barsLayout.addWidget(editor.homeToolbar) + # barsLayout.addWidget(editor.insertToolbar) + # barsLayout.addWidget(editor.drawToolbar) topSideLayout.addWidget(editor.titlebar, 0) topSideLayout.addWidget(barsLayoutContainerWidget, 1) @@ -102,65 +104,28 @@ def build_ui(editor): #editor.restoreGeometry(editor.settings.value("geometry", editor.saveGeometry())) #editor.restoreState(editor.settings.value("windowState", editor.saveState())) -# Constructs the menu bar with different menus like File, Home, Insert, Draw, and Plugins -# It adds actions to these menus and connects them to their functions -def build_menubar(editor): - editor.menubar = editor.menuBar() - - file = editor.menubar.addMenu('&File') - home = editor.menubar.addMenu('&Home') - insert = editor.menubar.addMenu('&Insert') - draw = editor.menubar.addMenu('&Draw') - plugins = editor.menubar.addMenu('&Plugins') - - new_file = build_action(editor, './Assets/icons/svg_file_open', 'New Notebook', 'New Notebook', False) - new_file.setShortcut(QKeySequence.StandardKey.New) - new_file.triggered.connect(lambda: new(editor)) - - open_file = build_action(editor, './Assets/icons/svg_file_open', 'Open Notebook', 'Open Notebook', False) - open_file.setShortcut(QKeySequence.StandardKey.Open) - open_file.triggered.connect(lambda: load(editor)) - - save_file = build_action(editor, './Assets/icons/svg_file_save', 'Save Notebook', 'Save Notebook', False) - save_file.setShortcut(QKeySequence.StandardKey.Save) - save_file.triggered.connect(lambda: save(editor)) +# Constructs the tab bar with different tabs like File, Home, Insert, Draw, and Plugins +# It adds toolbars to these tabs and connects them to their functions +def build_tabbar(editor): + editor.tabbar = QTabWidget() + editor.tabbar.setTabsClosable(False) - save_fileAs = build_action(editor, './Assets/icons/svg_file_save', 'Save Notebook As...', 'Save Notebook As', False) - save_fileAs.setShortcut(QKeySequence.fromString('Ctrl+Shift+S')) - save_fileAs.triggered.connect(lambda: saveAs(editor)) - - toggle_home_toolbar = build_action(editor, '', 'Toggle Home Toolbar', 'Toggle Home Toolbar', False) - toggle_home_toolbar.triggered.connect(lambda: set_toolbar_visibility(editor, 'homeToolbar')) - - toggle_insert_toolbar = build_action(editor, '', 'Toggle Insert Toolbar', 'Toggle Insert Toolbar', False) - toggle_insert_toolbar.triggered.connect(lambda: set_toolbar_visibility(editor, 'insertToolbar')) - - toggle_draw_toolbar = build_action(editor, '', 'Toggle Draw Toolbar', 'Toggle Draw Toolbar', False) - toggle_draw_toolbar.triggered.connect(lambda: set_toolbar_visibility(editor, 'drawToolbar')) + editor.fileToolbar = QToolBar() + editor.homeToolbar = QToolBar() + editor.insertToolbar = QToolBar() + editor.drawToolbar = QToolBar() + editor.pluginToolbar = QToolBar() - add_widget = build_action(editor, './Assets/icons/svg_question', 'Add Custom Widget', 'Add Custom Widget', False) - file.addActions([new_file, open_file, save_file, save_fileAs]) - home.addAction(toggle_home_toolbar) - insert.addAction(toggle_insert_toolbar) - draw.addAction(toggle_draw_toolbar) - plugins.addAction(add_widget) + # Toolbars + # Constructs toolbars for different functionalities like home, insert, and draw + # It adds actions and buttons to these toolbars and connects them to their functions + # --------------------------------------------------------------------------------- -# Constructs toolbars for different functionalities like home, insert, and draw -# It adds actions and buttons to these toolbars and connects them to their functions -def build_toolbar(editor): def handleCheck(action): action.setChecked(True) #editorSignalsInstance.checkMade.connect(editor.checkMade) - # homeToolbar code - editor.homeToolbar = QToolBar() - editor.homeToolbar.setObjectName('homeToolbar') - editor.homeToolbar.setIconSize(QSize(18, 18)) - editor.homeToolbar.setMovable(False) - editor.homeToolbar.setFixedHeight(40) - editor.addToolBar(Qt.ToolBarArea.TopToolBarArea, editor.homeToolbar) - # For adding space to the left the first button added to a toolbar spacer1 = QWidget() spacer1.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) @@ -174,6 +139,46 @@ def handleCheck(action): spacer3.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) spacer3.setFixedWidth(3) + # --------------------------------------------------------------------------------- + # fileToolbar code + + editor.fileToolbar.setObjectName('fileToolbar') + editor.fileToolbar.setIconSize(QSize(18,18)) + editor.fileToolbar.setMovable(False) + editor.fileToolbar.setVisible(False) + editor.fileToolbar.setFixedHeight(40) + editor.addToolBar(Qt.ToolBarArea.TopToolBarArea, editor.fileToolbar) + + new_file = build_button(editor.fileToolbar, './Assets/icons/svg_file_open', 'New Notebook', 'New Notebook', False) + new_file.setShortcut(QKeySequence.StandardKey.New) + new_file.clicked.connect(lambda: new(editor)) + + open_file = build_button(editor.fileToolbar, './Assets/icons/svg_file_open', 'Open Notebook', 'Open Notebook', False) + open_file.setShortcut(QKeySequence.StandardKey.Open) + open_file.clicked.connect(lambda: load(editor)) + + save_file = build_button(editor.fileToolbar, './Assets/icons/svg_file_save', 'Save Notebook', 'Save Notebook', False) + save_file.setShortcut(QKeySequence.StandardKey.Save) + save_file.clicked.connect(lambda: save(editor)) + + save_fileAs = build_button(editor.fileToolbar, './Assets/icons/svg_file_save', 'Save Notebook As...', 'Save Notebook As', False) + save_fileAs.setShortcut(QKeySequence.fromString('Ctrl+Shift+S')) + save_fileAs.clicked.connect(lambda: saveAs(editor)) + + editor.fileToolbar.addWidget(new_file) + editor.fileToolbar.addWidget(open_file) + editor.fileToolbar.addWidget(save_file) + editor.fileToolbar.addWidget(save_fileAs) + + # --------------------------------------------------------------------------------- + # homeToolbar code + + editor.homeToolbar.setObjectName('homeToolbar') + editor.homeToolbar.setIconSize(QSize(18, 18)) + editor.homeToolbar.setMovable(False) + editor.homeToolbar.setFixedHeight(40) + editor.addToolBar(Qt.ToolBarArea.TopToolBarArea, editor.homeToolbar) + paste = build_action(editor.homeToolbar, './Assets/icons/svg_paste', "Paste", "Paste", False) paste.triggered.connect(editor.frameView.toolbar_paste) @@ -292,7 +297,9 @@ def handleCheck(action): editor.homeToolbar.addSeparator() + # --------------------------------------------------------------------------------- # Classic Home Toolbar + editor.classicToolbar = QToolBar() editor.classicToolbar.setObjectName('classicHomeToolbar') editor.classicToolbar.setIconSize(QSize(18,18)) @@ -303,8 +310,9 @@ def handleCheck(action): + # --------------------------------------------------------------------------------- # insertToolbar code - editor.insertToolbar = QToolBar() + editor.insertToolbar.setObjectName('insertToolbar') editor.insertToolbar.setIconSize(QSize(18,18)) editor.insertToolbar.setFixedHeight(40) @@ -360,8 +368,9 @@ def handleCheck(action): editor.insertToolbar.addWidget(dateTime) + # --------------------------------------------------------------------------------- # drawToolbar code - editor.drawToolbar = QToolBar() + editor.drawToolbar.setObjectName('drawToolbar') editor.drawToolbar.setIconSize(QSize(18, 18)) editor.drawToolbar.setFixedHeight(40) @@ -385,6 +394,30 @@ def handleCheck(action): editor.drawToolbar.addAction(paperColor) + # --------------------------------------------------------------------------------- + # pluginToolbar code + + editor.pluginToolbar.setObjectName('pluginToolbar') + editor.pluginToolbar.setIconSize(QSize(18,18)) + editor.pluginToolbar.setFixedHeight(40) + editor.pluginToolbar.setMovable(False) + editor.pluginToolbar.setVisible(False) + editor.addToolBar(Qt.ToolBarArea.TopToolBarArea, editor.pluginToolbar) + + add_widget = build_button(editor, './Assets/icons/svg_question', 'Add Custom Widget', 'Add Custom Widget', False) + + editor.pluginToolbar.addWidget(add_widget) + # --------------------------------------------------------------------------------- + + editor.tabbar.addTab(editor.fileToolbar, '&File') + editor.tabbar.addTab(editor.homeToolbar, '&Home') + editor.tabbar.addTab(editor.insertToolbar, '&Insert') + editor.tabbar.addTab(editor.drawToolbar, '&Draw') + editor.tabbar.addTab(editor.pluginToolbar, '&Plugins') + + # Sets the first shown tab as the home tab + editor.tabbar.setCurrentIndex(1) + def check_appearance(): """Checks DARK/LIGHT mode of macos.""" cmd = 'defaults read -g AppleInterfaceStyle' diff --git a/Styles/styles.qss b/Styles/styles.qss index 765b4f5..cc089fb 100644 --- a/Styles/styles.qss +++ b/Styles/styles.qss @@ -73,7 +73,7 @@ QPushButton#font_color { } QToolBar QToolButton::hover, -QToolBar QPushButton#font_color::hover { +QToolBar QPushButton::hover { background-color: #cecece; } From 8c61fdc54f27137c5e316d5521d6eeb061762739 Mon Sep 17 00:00:00 2001 From: Jettorix <109848112+Jettorix@users.noreply.github.com> Date: Tue, 23 Apr 2024 10:22:13 -0500 Subject: [PATCH 124/127] Updated Undo widget selection --- Models/Editor.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/Models/Editor.py b/Models/Editor.py index 4314a2f..3b15a43 100644 --- a/Models/Editor.py +++ b/Models/Editor.py @@ -66,8 +66,26 @@ def changeEvent(self, event): self.titlebar.window_state_changed(self.windowState()) super().changeEvent(event) event.accept() + + def triggerUndo(self): + print("Item added to Stack") + # Get the currently focused widget + focused_widget = self.focusWidget() + print(f"Focused widget: {focused_widget}") + + if focused_widget and isinstance(focused_widget, (QTextEdit, QLineEdit)): + print("Undo Action Completed") + + backspace_event = QKeyEvent(QEvent.KeyPress, Qt.Key_Backspace, Qt.NoModifier) + backspace_release_event = QKeyEvent(QEvent.KeyRelease, Qt.Key_Backspace, Qt.NoModifier) + + # Post the key press event to the focused widget + QApplication.postEvent(focused_widget, backspace_event) + QApplication.postEvent(focused_widget, backspace_release_event) + # mousePress, mouseMove, and mouseRelease handle mouse move events inside the window + def mousePressEvent(self, event): if event.button() == Qt.LeftButton: self.moveFlag = True @@ -96,4 +114,4 @@ def save_toolbar_actions(self, toolbars): if widget.objectName() and widget.objectName() != "qt_toolbar_ext_button": action_names.append(widget.objectName()) # Add the object name of the widget to the list - return action_names # Return the list of action names collected from the toolbars \ No newline at end of file + return action_names # Return the list of action names collected from the toolbars From d6f0f0d3de767053afe81530a40a96261af124cd Mon Sep 17 00:00:00 2001 From: Jettorix <109848112+Jettorix@users.noreply.github.com> Date: Wed, 24 Apr 2024 20:39:48 -0500 Subject: [PATCH 125/127] Implemented Redo Functionality --- Models/Editor.py | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/Models/Editor.py b/Models/Editor.py index 3b15a43..721b7c9 100644 --- a/Models/Editor.py +++ b/Models/Editor.py @@ -33,6 +33,7 @@ def __init__(self): self.autosaver = Autosaver(self) # Waits for change signals and saves the notebook self.setFocus() + self.undoStack = [] self.settings = QSettings("UNT - Team Olive", "OpenNote") #pre-saved settings needed for window state restoration @@ -68,21 +69,40 @@ def changeEvent(self, event): event.accept() def triggerUndo(self): - print("Item added to Stack") - # Get the currently focused widget + print("Item added to Undo Stack") focused_widget = self.focusWidget() - print(f"Focused widget: {focused_widget}") + if focused_widget and isinstance(focused_widget, (QTextEdit, QLineEdit)): - print("Undo Action Completed") + cursor = focused_widget.textCursor() # Get the cursor of the widget + if cursor.position() > 0: # Check if there's a character to delete + cursor.movePosition(QTextCursor.Left, QTextCursor.KeepAnchor) # Select character to the left + char_to_delete = cursor.selectedText() # Get the selected text + self.undoStack.append(char_to_delete) # Append it to the stack + print(f"Stored '{char_to_delete}' in redo stack") - + backspace_event = QKeyEvent(QEvent.KeyPress, Qt.Key_Backspace, Qt.NoModifier) backspace_release_event = QKeyEvent(QEvent.KeyRelease, Qt.Key_Backspace, Qt.NoModifier) - # Post the key press event to the focused widget QApplication.postEvent(focused_widget, backspace_event) QApplication.postEvent(focused_widget, backspace_release_event) + + def triggerRedo(self): + if not self.undoStack: + print("No characters to redo") + return + + char_to_redo = self.undoStack.pop() # Get the last character from the stack + focused_widget = self.focusWidget() + + if focused_widget and isinstance(focused_widget, (QTextEdit, QLineEdit)): + redo_event = QKeyEvent(QEvent.KeyPress, 0, Qt.NoModifier, text=char_to_redo) + QApplication.postEvent(focused_widget, redo_event) + print(f"Redo action: Typed '{char_to_redo}'") + print(f"Item Removed from stack") + else: + print("Focused widget is not a QTextEdit or QLineEdit") # mousePress, mouseMove, and mouseRelease handle mouse move events inside the window From 0ccbc770bc0b0e8531e793efd28cf8f3ca4468c7 Mon Sep 17 00:00:00 2001 From: Jettorix <109848112+Jettorix@users.noreply.github.com> Date: Wed, 24 Apr 2024 20:50:27 -0500 Subject: [PATCH 126/127] Corrected function calling for Undo/Redo --- Modules/BuildUI.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index f41e021..bb403a2 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -379,9 +379,12 @@ def handleCheck(action): editor.addToolBar(Qt.ToolBarArea.TopToolBarArea, editor.drawToolbar) undo = build_action(editor.drawToolbar, './Assets/icons/svg_undo', "Undo", "Undo", False) - undo.triggered.connect(editor.frameView.triggerUndo) - + undo_action = QAction(QIcon('./Assets/icons/undo.png'), '&Undo', editor) + undo.triggered.connect(editor.triggerUndo) + redo = build_action(editor.drawToolbar, './Assets/icons/svg_redo', "Redo", "Redo", False) + redo_action = QAction(QIcon('./Assets/icons/redo.png'), '&Redo', editor) + redo.triggered.connect(editor.triggerRedo) # redo.triggered.connect(editor.frameView.triggerRedo) paperColor= build_action(editor.drawToolbar, './Assets/icons/svg_paper', "Paper Color", "Paper Color", False) From 05c1c9bc9e1cb19089e6bed14c0cf9f4fabd7be8 Mon Sep 17 00:00:00 2001 From: Jettorix <109848112+Jettorix@users.noreply.github.com> Date: Wed, 24 Apr 2024 21:01:05 -0500 Subject: [PATCH 127/127] Deleted code that was causing bugs --- Modules/BuildUI.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/Modules/BuildUI.py b/Modules/BuildUI.py index bb403a2..11c4ff2 100644 --- a/Modules/BuildUI.py +++ b/Modules/BuildUI.py @@ -378,11 +378,9 @@ def handleCheck(action): editor.drawToolbar.setVisible(False) editor.addToolBar(Qt.ToolBarArea.TopToolBarArea, editor.drawToolbar) - undo = build_action(editor.drawToolbar, './Assets/icons/svg_undo', "Undo", "Undo", False) undo_action = QAction(QIcon('./Assets/icons/undo.png'), '&Undo', editor) undo.triggered.connect(editor.triggerUndo) - redo = build_action(editor.drawToolbar, './Assets/icons/svg_redo', "Redo", "Redo", False) redo_action = QAction(QIcon('./Assets/icons/redo.png'), '&Redo', editor) redo.triggered.connect(editor.triggerRedo) # redo.triggered.connect(editor.frameView.triggerRedo)