Does a context-menu-based application menu exist?

@ngraham, I obviously wasn’t clear enough, because that’s exactly what I want. I don’t need a favourites list, etc, if I can have it inherit the non-Plasma styles.

I really like Breeze - I don’t like that plasmashell’s reimplementation of it.

I’ve seen search bars inside what appear to be QMenus, maybe inside KDevelop somewhere. Are those reimplementations that are designed to appear similar, or do you consider a subclass to be a separate control, for the purposes of this discussion?

Regardless, the Application Menu provided by the Mouse Actions is enough for me. I just need a way to invoke it from a panel.

I don’t think such a thing exists; you’ll probably have to create it yourself. After you do, feel free to put it on store.kde.org!

1 Like

I’ll get right to it. Thanks!

I did as @skyfishgoo suggested … but I got a question.

I have several apps (seven) on Lost Found (hmm whatever happened to the ‘&’ there?). Which file is responsible for this desktop Application Launcher so I can edit it and correctly place them in their correct sections?

@Archie, I rather hid that - apologies:

It’s been remediated in a later version of Plasma, per invent.kde.org/plasma/plasma-workspace/-/merge_requests/5158.

Like ngraham and I said, it doesn’t exist. The desktop menu is about as…simple as it comes. And it has a mind of its own btw by placing subs to the top.

Thank you, @rokejulianlockhart for the heads up. I just noticed it and since it’s already fix on 6.3, I guess all I have to do is wait for my distro to get up to the version. Thank you.

1 Like

Seems that it’s perfectly possible with a QWidgetAction:

  1. import sys
    from PyQt5.QtCore import pyqtSlot
    from PyQt5.QtWidgets import QAction, QApplication, QLineEdit, QMainWindow, QMenu, QWidgetAction
    
    
    class Example(QMainWindow):
        def __init__(self):
            super().__init__()
            self.menubar = self.menuBar()
            self.menubar.installEventFilter(self)
            self.fileMenu = self.menubar.addMenu("&Circuit Set-Up")
            self.populate()
    
            self.setGeometry(300, 300, 300, 200)
            self.show()
    
        @pyqtSlot(str)
        def onTextChanged(self, text):
            print(text)
    
        def populate(self):
    
            factors = [
                "Enter Transducer Calibration Constant [default 1] = 1",
                "Enter Gauge Factor [default 2] = 2",
                "Passion Ratio [default 0.3] = 0.3",
            ]
    
            for m in range(3):
                menu = QMenu("Channel{}".format(m), self)
                self.fileMenu.addMenu(menu)
                for n in range(3):
                    ql = QLineEdit(factors[n])
                    ql.setMinimumWidth(350)
                    ql.textChanged.connect(self.onTextChanged)
                    wAction = QWidgetAction(self)
                    wAction.setDefaultWidget(ql)
                    menu.addAction(wAction)
    
    
    if __name__ == "__main__":
    
        app = QApplication(sys.argv)
        ex = Example()
        sys.exit(app.exec_())
    

Never would have thought that they were that versatile. In fact, I managed to get Claude to basically re-engineer the GUI: [1]

  1. from typing import Optional, List
    from PyQt6.QtWidgets import (
        QMenu, QLineEdit, QWidgetAction, QWidget,
        QPushButton
    )
    from PyQt6.QtCore import Qt, pyqtSignal
    from PyQt6.QtGui import QAction
    
    class FilteredContextMenu(QMenu):
        """A context menu with a search filter for its entries."""
        
        item_selected = pyqtSignal(str)  # Signal emitted when menu item is selected
        
        def __init__(self, parent: Optional[QWidget] = None) -> None:
            super().__init__(parent)
            
            # Create the search widget
            self.search_edit = QLineEdit()
            self.search_edit.setPlaceholderText("Search...")
            self.search_edit.textChanged.connect(self._filter_entries)
            
            # Create a widget action for the search box
            search_action = QWidgetAction(self)
            search_action.setDefaultWidget(self.search_edit)
            
            # Add the search box to the menu
            self.addAction(search_action)
            self.addSeparator()
            
            # Sample menu items (you would typically populate these dynamically)
            self.menu_items: List[QAction] = [
                self.addAction("Open File"),
                self.addAction("Save Document"),
                self.addAction("Export as PDF"),
                self.addAction("Print Document"),
                self.addAction("Share via Email"),
                self.addAction("Document Properties"),
                self.addAction("Version History"),
                self.addAction("Access Controls"),
                self.addAction("Delete Document")
            ]
            
            # Connect the actions
            for action in self.menu_items:
                action.triggered.connect(
                    lambda checked, text=action.text(): self.item_selected.emit(text)
                )
        
        def _filter_entries(self, text: str) -> None:
            """Filter menu entries based on search text.
            
            Args:
                text: The search filter text
            """
            search_text = text.lower()
            for action in self.menu_items:
                action.setVisible(search_text in action.text().lower())
    
    # Example usage
    if __name__ == "__main__":
        import sys
        from PyQt6.QtWidgets import QApplication, QMainWindow
        
        app = QApplication(sys.argv)
        window = QMainWindow()
        
        # Create a button to show the context menu
        button = QPushButton("Show Context Menu", window)
        window.setCentralWidget(button)
        
        # Create and configure the filtered menu
        menu = FilteredContextMenu(window)
        
        def show_menu() -> None:
            """Show the context menu at the button's position."""
            menu.popup(button.mapToGlobal(button.rect().bottomLeft()))
        
        def on_item_selected(text: str) -> None:
            """Handle menu item selection.
            
            Args:
                text: The text of the selected menu item
            """
            print(f"Selected: {text}")
        
        # Connect signals
        button.clicked.connect(show_menu)
        menu.item_selected.connect(on_item_selected)
        
        window.resize(300, 100)
        window.show()
        
        sys.exit(app.exec())
    
  2. Full List

  3. Filtered (via the QLineEdit)

…now I’ve just gotta rewrite all of that (it’s rather poorly formatted, and devoid of type hints, etcetera), then ascertain how to replace the QMainWindow with whatever Plasma Shell consumes as a plasmoid’s base.


  1. claude.site/artifacts/74d93fee-850a-412f-9a5f-7d0ec868e478 ↩︎