systeminfo/lib/display_handler.rb
2023-09-24 17:31:26 -06:00

248 lines
7.6 KiB
Ruby
Executable File

# frozen_string_literal: true
require 'curses'
require 'readline'
class DisplayHandler
def self.display(system_info)
setup_readline
Curses.init_screen
Curses.start_color
Curses.init_pair(1, Curses::COLOR_BLUE, Curses::COLOR_BLACK)
Curses.init_pair(2, Curses::COLOR_GREEN, Curses::COLOR_BLACK)
Curses.init_pair(3, Curses::COLOR_YELLOW, Curses::COLOR_BLACK)
@main_win = Curses::Window.new(0, 0, 0, 0)
@menu_win = @main_win.subwin(Curses.lines - 4, 20, 1, 1)
@info_win = @main_win.subwin(Curses.lines - 4, Curses.cols - 22, 1, 22)
@menu_win.keypad(true)
exit_menu = false # Flag to indicate if the menu should exit
loop do
draw_main_box
draw_menu_box
draw_info_box
choices = ['OS Info', 'Hardware Info', 'Network Info', 'Exit']
selected_index = 0
loop do
row = 2 # Starting row
col = 3 # Starting column
choices.each_with_index do |choice, index|
@menu_win.setpos(row + index, col) # Explicitly set position for each choice
if index == selected_index
@menu_win.attron(Curses.color_pair(3)) { @menu_win.addstr(choice) }
else
@menu_win.addstr(choice)
end
@menu_win.setpos(row + index + 1, col) # Move to the next line
end
@menu_win.refresh
input = @menu_win.getch
case input
when Curses::KEY_UP
selected_index = [selected_index - 1, 0].max
when Curses::KEY_DOWN
selected_index = [selected_index + 1, choices.length - 1].min
when 10, 13 # Enter key
case choices[selected_index]
when 'Exit'
exit_menu = true # Set flag to true
break # Break inner loop
when 'OS Info'
display_os_info(system_info.slice(:kernel, :os, :uptime))
when 'Hardware Info'
display_hardware_info(system_info.slice(:cpu, :ram, :disks, :gpu))
when 'Network Info'
display_network_info(system_info.slice(:network, :nic))
end
end
break if exit_menu # Break outer loop if flag is true
end
break if exit_menu # Break outer loop if flag is true
end
Curses.close_screen
end
def self.draw_main_box
@main_win.box('|', '-')
@main_win.setpos(0, (Curses.cols - 11) / 2)
@main_win.addstr('System Info')
@main_win.setpos(Curses.lines - 1, Curses.cols - 4)
@main_win.addstr('V1.0')
@main_win.refresh
end
def self.draw_menu_box
@menu_win.box('|', '-')
@menu_win.setpos(0, 5)
@menu_win.addstr('Menu')
@menu_win.refresh
end
def self.draw_info_box
@info_win.box('|', '-')
@info_win.setpos(0, @info_win.maxx - 13)
@info_win.addstr('Information')
@info_win.refresh
end
def self.prepare_info_window(title)
@info_win.clear
draw_info_box
@info_win.setpos(2, 2)
@info_win.attron(Curses.color_pair(1)) { @info_win.addstr(title) }
@info_win.setpos(3, 2)
@info_win.addstr('-' * (title.length + 2))
end
def self.display_os_info(os_info)
@info_win.clear
draw_info_box
@info_win.setpos(2, 2)
@info_win.attron(Curses.color_pair(1)) { @info_win.addstr('OS Information') }
@info_win.setpos(3, 2)
@info_win.addstr('--------------')
display_info(os_info, @info_win)
@info_win.refresh
end
def self.display_hardware_info(hardware_info)
@info_win.clear
draw_info_box
# CPU and RAM on the left side
left_row = 4
left_row = display_cpu_info(hardware_info[:cpu], left_row)
display_ram_info(hardware_info[:ram], left_row)
# Disks and GPU on the right side
right_row = 4
right_col = 40 # Adjust this value to place it at the desired column
right_row = display_disk_info(hardware_info[:disks], right_row, right_col)
display_gpu_info(hardware_info[:gpu], right_row, right_col)
@info_win.refresh
end
def self.display_cpu_info(cpu_info, start_row)
@info_win.setpos(start_row, 2)
@info_win.attron(Curses.color_pair(1)) { @info_win.addstr('CPU Information') }
start_row += 1
@info_win.setpos(start_row, 2)
@info_win.addstr('--------------')
start_row += 1
@info_win.setpos(start_row, 2)
display_info(cpu_info, @info_win, start_row, 4)
start_row += cpu_info.keys.length + 1
start_row
end
def self.display_ram_info(ram_info, start_row, col = 2)
@info_win.setpos(start_row, col)
@info_win.attron(Curses.color_pair(1)) { @info_win.addstr('RAM Information') }
start_row += 1
@info_win.setpos(start_row, col)
@info_win.addstr('--------------')
start_row += 1
display_info(ram_info, @info_win, start_row, 4, col)
start_row += ram_info.keys.length + 1
start_row
end
def self.display_disk_info(disk_info, start_row, col = 2)
@info_win.setpos(start_row, col)
@info_win.attron(Curses.color_pair(1)) { @info_win.addstr('Disk Information')}
start_row += 1
@info_win.setpos(start_row, col)
@info_win.addstr('---------------')
start_row += 1
display_info({ disks: disk_info }, @info_win, start_row, 0, col)
start_row += (disk_info.length * 3) + 1
start_row
end
def self.display_gpu_info(gpu_info, start_row, col = 2)
@info_win.setpos(start_row, col)
@info_win.attron(Curses.color_pair(1)) { @info_win.addstr('GPU Information')}
start_row += 1
@info_win.setpos(start_row, col)
@info_win.addstr('--------------')
start_row += 1
display_info(gpu_info, @info_win, start_row, 4, col)
start_row += gpu_info.keys.length + 1
start_row
end
def self.display_network_info(network_info)
@info_win.clear
draw_info_box
@info_win.setpos(2, 2)
@info_win.attron(Curses.color_pair(1)) { @info_win.addstr('Network Information') }
@info_win.setpos(3, 2)
@info_win.addstr('-------------------')
display_info(network_info, @info_win)
@info_win.refresh
end
def self.display_info(info_hash, win, row = 4, indent = 0, col = 2)
info_hash.each do |key, value|
row = handle_value_type(value, win, row, indent, col, key)
end
row
end
def self.handle_value_type(value, win, row, indent, col, key)
formatted_key = key.to_s.gsub('_', ' ').split.map(&:capitalize).join(' ')
if value.is_a?(Hash)
display_hash_value(value, win, row, indent, col, formatted_key)
elsif value.is_a?(Array)
display_array_value(value, win, row, indent, col)
else
display_scalar_value(value, win, row, indent, col, formatted_key)
end
end
def self.display_hash_value(value, win, row, indent, col, key)
win.setpos(row, col + indent)
win.addstr("#{key}: ")
display_info(value, win, row, indent + 4, col)
end
def self.display_array_value(value, win, row, indent, col)
value.each do |item|
if item.is_a?(Hash)
row = display_info(item, win, row, indent + 4, col)
else
win.setpos(row, col + indent + 4)
win.addstr(item.to_s)
row += 1
end
end
row
end
def self.display_scalar_value(value, win, row, indent, col, key)
win.setpos(row, col + indent)
win.addstr("#{key}: #{value}")
row + 1
end
def self.setup_readline
# Set up Readline for proper terminal settings
Readline.emacs_editing_mode
# the above line sets Readline to emacs_editing_mode so that terminals behave like they're supposed to
Readline.completion_append_character = ' '
# we remove Readlines thing where it adds a space to the end of tab completes because it breaks the Curses cursor
Readline.completion_proc = proc { |_s| [] }
# here we basically are disabling tab completion all together. That's because for some reason it breaks the cursor
end
private_class_method :display_info, :setup_readline
end