Skip to content

Commit

Permalink
feat: roles/3d_printing
Browse files Browse the repository at this point in the history
  • Loading branch information
timgreen committed Oct 10, 2024
1 parent dff85a2 commit ab65597
Show file tree
Hide file tree
Showing 3 changed files with 199 additions and 1 deletion.
3 changes: 2 additions & 1 deletion local.yml
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,11 @@
- dev
- never
roles:
# - vscode
- vscode
- nvm
- rustup
- conda
- 3d_printing

- name: Chrome os
hosts: localhost
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
# TODO: show disabled actions at the bottom of search
# TODO: better fuzzy search?
# TODO: better visuals:
# see: https://stackoverflow.com/questions/41107202/pyqt-coloring-part-of-text-in-qlistwidget
# - better path: right-aligned + grey
# - show the keyboard shortcut for the item?
# - highlight matched parts of search
# - larger text
# TODO: toggle visibility on keyboard shortcut if already displayed


# Useful methods on QAction menu items
# text(): The text of the menu item with '&' before the shortcut key.
# toolTip(): on hover tooltip as html.
# shortcut(): shortcut keys for that action as a QKeySequence.
# trigger(): invoke that action.

from PySide import QtGui, QtCore

def enumerateActions(menu, path=[]):
actionList = []
for action in menu.actions():
if action.isSeparator():
pass
elif action.menu():
actionList.extend(enumerateActions(action.menu(), path + [action.text()]))
else:
actionList.append((action, path))
return actionList

def getMenuItems():
def convertAction(action, path):
# For an unknown reason, there are a bunch of blank menu items -- filter them out.
if not action.text():
return None

# For now, don't include disabled actions.
if not action.isEnabled():
return None

pathText = "->".join(path)
fullText = f"{action.text()} ({pathText})"
# fixedText = action.text().replace('&', '')
fixedText = fullText.replace('&', '')

item = PaletteListWidgetItem()
item.setText(fixedText)
item.setSearchText(fixedText.casefold())
item.setToolTip(action.toolTip())
item.setIcon(action.icon())
item.setTrigger(action.trigger)
return item

mw = Gui.getMainWindow()
menuBar = mw.menuBar()
return [convertAction(action, path) for action, path in enumerateActions(menuBar) if action is not None]


class PaletteDialog(QtGui.QDialog):
def __init__(self, parent):
super().__init__(parent)
self.installEventFilter(self)

def eventFilter(self, obj, event):
# Hide the palette if it ever loses focus.
if event.type() == QtCore.QEvent.WindowDeactivate:
self.hide()
return True
return False


class PaletteLineEdit(QtGui.QLineEdit):
keyMappings = {}

def keyPressEvent(self, event):
keyFn = self.keyMappings.get(event.key())
if keyFn is not None:
keyFn()
return

super().keyPressEvent(event)

def setMappings(self, keyMappings):
self.keyMappings = keyMappings

class PaletteListWidgetItem(QtGui.QListWidgetItem):
_searchText = None
_trigger = None

def searchText(self):
return self._searchText

def setSearchText(self, text):
self._searchText = text

def matches(self, text):
return False

def runTrigger(self):
self._trigger()

def setTrigger(self, trigger):
self._trigger = trigger

class CommandPalette:
MIN_DIALOG_WIDTH = 600
MIN_DIALOG_HEIGHT = 400
def activate(self):
items = getMenuItems()
dialog = PaletteDialog(Gui.getMainWindow())
dialog.setObjectName("CommandPalette")
dialog.setMinimumWidth(self.MIN_DIALOG_WIDTH)
dialog.setMinimumHeight(self.MIN_DIALOG_HEIGHT)
dialog.setWindowFlags(dialog.windowFlags() | QtCore.Qt.FramelessWindowHint)


vbox = QtGui.QVBoxLayout(dialog)

searchBar = PaletteLineEdit()
searchBar.textChanged.connect(self.textChanged)
searchBar.returnPressed.connect(self.returnPressed)
searchBar.setMappings({
QtCore.Qt.Key.Key_Down: self.downPressed,
QtCore.Qt.Key.Key_Up: self.upPressed,
})
vbox.addWidget(searchBar)

commandList = QtGui.QListWidget()
vbox.addWidget(commandList)

for item in items:
commandList.addItem(item)

commandList.itemClicked.connect(self.itemClicked)

commandList.show()
dialog.show()


self.commandList = commandList
self.dialog = dialog # prevent dialog from being garbage collected


def textChanged(self, newText):
foldedText = newText.casefold()
foldedTerms = foldedText.split()
currentItemSet = False
for i in range(0, self.commandList.count()):
item = self.commandList.item(i)

if all(term in item.searchText() for term in foldedTerms):
item.setHidden(False)
if not currentItemSet:
self.commandList.setCurrentItem(item)
currentItemSet = True
else:
item.setHidden(True)

def returnPressed(self):
# Run the selected action.
currentItem = self.commandList.currentItem()
if currentItem is not None:
self.dialog.hide()
currentItem.runTrigger()

def downPressed(self):
# Select the next unhidden action, if any.
currentRow = self.commandList.currentRow()
for i in range(currentRow + 1, self.commandList.count()):
if not self.commandList.item(i).isHidden():
self.commandList.setCurrentRow(i)
return

def upPressed(self):
# Select the previous unhidden action, if any.
currentRow = self.commandList.currentRow()
for i in range(currentRow - 1, -1, -1):
if not self.commandList.item(i).isHidden():
self.commandList.setCurrentRow(i)
return

def itemClicked(self, item):
self.dialog.hide()
item.runTrigger()


palette = CommandPalette()
palette.activate()
9 changes: 9 additions & 0 deletions roles/3d_printing/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
- block:
- name: Stow 3d printing
command: stow -v -t ~ -d {{ role_path }}/files -S . --no-folding
register: output
changed_when: '"LINK" in output.stderr'

tags:
- 3d_printing

0 comments on commit ab65597

Please sign in to comment.