aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xlogout-manager-ncurses.py163
1 files changed, 163 insertions, 0 deletions
diff --git a/logout-manager-ncurses.py b/logout-manager-ncurses.py
new file mode 100755
index 0000000..7356569
--- /dev/null
+++ b/logout-manager-ncurses.py
@@ -0,0 +1,163 @@
+#!/usr/bin/env python3
+# File: logout-manager-tui.py
+# License: MIT
+# Author: adamlamers, bgstack15
+# Startdate: 2020-03-09 17:06
+# Title: ncurses based logout manager
+# Usage:
+#
+# Reference:
+# https://docs.python.org/3/howto/curses.html
+# ripped straight from http://adamlamers.com/post/FTPD9KNRA8CT
+# https://stackoverflow.com/questions/3061/calling-a-function-of-a-module-by-using-its-name-a-string/12025554#12025554
+# Improve:
+# add "disabled" option in menu, with default=enabled
+# Documentation:
+
+import curses, sys, os
+sys.path.append("/home/bgirton/dev/logout-manager")
+import lmlib
+
+class CursesMenu(object):
+
+ INIT = {'type' : 'init'}
+
+ def __init__(self, menu_options):
+ self.screen = curses.initscr()
+ self.menu_options = menu_options
+ self.selected_option = 0
+ self._previously_selected_option = None
+ self.running = True
+
+ #init curses and curses input
+ curses.noecho()
+ curses.cbreak()
+ curses.start_color()
+ curses.curs_set(0) #Hide cursor
+ self.screen.keypad(1)
+
+ #set up color pair for highlighted option
+ curses.init_pair(1, curses.COLOR_BLACK, curses.COLOR_WHITE)
+ self.hilite_color = curses.color_pair(1)
+ self.normal_color = curses.A_NORMAL
+
+ def prompt_selection(self, parent=None):
+ if parent is None:
+ lastoption = "Cancel"
+ else:
+ lastoption = "Return to previous menu ({})".format(parent['title'])
+
+ option_count = len(self.menu_options['options'])
+
+ input_key = None
+
+ ENTER_KEY = ord('\n')
+ #NUM_KEYS = [ord('1')]
+ #NUM_KEYS = [ord(1),ord(2)...]
+ NUM_KEYS = [ord(str(i)) for i in range(1,option_count+2)]
+ done = False
+ while not done:
+ if self.selected_option != self._previously_selected_option:
+ self._previously_selected_option = self.selected_option
+
+ self.screen.border(0)
+ self._draw_title()
+ for option in range(option_count):
+ if self.selected_option == option:
+ self._draw_option(option, self.hilite_color)
+ else:
+ self._draw_option(option, self.normal_color)
+
+ if self.selected_option == option_count:
+ self.screen.addstr(5 + option_count, 4, "{:2} - {}".format(option_count+1,
+ lastoption), self.hilite_color)
+ else:
+ self.screen.addstr(5 + option_count, 4, "{:2} - {}".format(option_count+1,
+ lastoption), self.normal_color)
+
+ max_y, max_x = self.screen.getmaxyx()
+ if input_key is not None:
+ self.screen.addstr(max_y-3, max_x - 5, "{:3}".format(self.selected_option))
+ self.screen.refresh()
+
+
+ input_key = self.screen.getch()
+ down_keys = [curses.KEY_DOWN, ord('j')]
+ up_keys = [curses.KEY_UP, ord('k')]
+ exit_keys = [ord('q')]
+
+ if input_key in down_keys:
+ if self.selected_option < option_count:
+ self.selected_option += 1
+ else:
+ self.selected_option = 0
+
+ if input_key in up_keys:
+ if self.selected_option > 0:
+ self.selected_option -= 1
+ else:
+ self.selected_option = option_count
+
+ if input_key in exit_keys:
+ self.selected_option = option_count #auto select exit and return
+ break
+
+ if input_key == ENTER_KEY or input_key in NUM_KEYS:
+ if input_key in NUM_KEYS:
+ self.selected_option=int(chr(input_key))-1
+ done = True
+ return self.selected_option
+
+ def _draw_option(self, option_number, style):
+ self.screen.addstr(5 + option_number,
+ 4,
+ "{:2} - {}".format(option_number+1, self.menu_options['options'][option_number]['title']),
+ style)
+
+ def _draw_title(self):
+ self.screen.addstr(2, 2, self.menu_options['title'], curses.A_STANDOUT)
+ self.screen.addstr(4, 2, self.menu_options['subtitle'], curses.A_BOLD)
+
+ def display(self):
+ selected_option = self.prompt_selection()
+ i, _ = self.screen.getmaxyx()
+ curses.endwin()
+ #os.system('clear')
+ if selected_option < len(self.menu_options['options']):
+ selected_opt = self.menu_options['options'][selected_option]
+ return selected_opt
+ else:
+ self.running = False
+ return {'title' : 'Cancel', 'type' : 'exitmenu'}
+
+menu = {'title' : 'Logout Manager',
+ 'type' : 'menu',
+ 'subtitle' : 'Use arrows or number keys'}
+
+option_1 = {'title' : 'Hello World',
+ 'type' : 'command',
+ 'command' : 'echo Hello World!'}
+
+# build menu object from config.
+config = lmlib.Initialize_config()
+actions = lmlib.Actions
+
+menu['options'] = [
+ {'title': 'Lock', 'type': 'action', 'action': 'lock'},
+ {'title': 'Logout', 'type': 'action', 'action': 'logout'},
+ {'title': 'Hibernate', 'type': 'action', 'action': 'hibernate'},
+ {'title': 'Shutdown', 'type': 'action', 'action': 'shutdown'},
+ {'title': 'Reboot', 'type': 'action', 'action': 'reboot'}
+ ]
+
+m = CursesMenu(menu)
+selected_action = m.display()
+
+if selected_action['type'] == 'exitmenu':
+ print("Cancelled")
+elif selected_action['type'] == 'command':
+ os.system(selected_action['command'])
+elif selected_action['type'] == 'action':
+ #a = selected_action['action']:
+ func = getattr(globals()['actions'],selected_action['action'])
+ func(config)
bgstack15