# frozen_string_literal: true module Cryptum # Cryptum::UI Module used for Presenting the # Cryptum Curses Interface module UI require 'cryptum/ui/command' require 'cryptum/ui/exit' require 'cryptum/ui/key_press_event' require 'cryptum/ui/market_trend' require 'cryptum/ui/matrix' require 'cryptum/ui/order' require 'cryptum/ui/portfolio' require 'cryptum/ui/signal_engine' require 'cryptum/ui/terminal_window' require 'cryptum/ui/ticker' # Initialize the UI public_class_method def self.init # Initialize curses Screen Curses.init_screen # Ensure the cursor is invisible Curses.curs_set(0) # Do not echo keystrokes back to the UI Curses.noecho # Used to immediately evaluate characters submitted # without pressing ENTER (e.g. b, r, & w key events) Curses.crmode # Curses.nocrmode # Curses.raw # NO # Curses.noraw # Disable Line Buffering Curses.ESCDELAY = 0 # Start Color! Curses.start_color # This is important to ensure -1 maintains # the original background color in the terminal # when defining color pairs Curses.use_default_colors # This object is used to pass all of the UI sections # around to various Cryptum modules Cryptum::UI::TerminalWindow.new rescue Interrupt # Exit Gracefully if CTRL+C is Pressed During Session Cryptum::UI::Exit.gracefully(which_self: self) rescue StandardError => e # Produce a Stacktrace for anything else Curses.close_screen raise e end # Create New Curses Window public_class_method def self.window(opts = {}) height = opts[:height].to_i width = opts[:width].to_i top = opts[:top].to_i left = opts[:left].to_i window = Curses::Window.new( height, width, top, left ) window.nodelay = true window rescue Interrupt # Exit Gracefully if CTRL+C is Pressed During Session Cryptum::UI::Exit.gracefully(which_self: self) rescue StandardError => e # Produce a Stacktrace for anything else Curses.close_screen raise e end # Draw a Box Around a Window public_class_method def self.line(opts = {}) ui_win = opts[:ui_win] out_line_no = opts[:out_line_no].to_i color = opts[:color] color ||= :white style = :normal style = :bold unless color == :white ui_win.setpos(out_line_no, 0) colorize( ui_win: ui_win, color: color, style: style, string: "\u2500" * Curses.cols ) rescue Interrupt # Exit Gracefully if CTRL+C is Pressed During Session Cryptum::UI::Exit.gracefully(which_self: self) rescue StandardError => e # Produce a Stacktrace for anything else Curses.close_screen raise e end # Jump to First Column public_class_method def self.colorize(opts = {}) ui_win = opts[:ui_win] color = opts[:color].to_s.to_sym red = opts[:red].to_i green = opts[:green].to_i blue = opts[:blue].to_i style = opts[:style].to_s.to_sym style = :normal if opts[:style].nil? bg = opts[:bg].to_i bg = -1 if opts[:bg].nil? string = opts[:string] case color when :black # It's more Gray than Black # color_id = 0 # color_fg = Curses::COLOR_BLACK color_id = 256 Curses.init_color(color_id, 0, 0, 500) color_fg = color_id color_bg = bg when :red color_id = 1 color_fg = Curses::COLOR_RED color_bg = bg when :green color_id = 2 color_fg = Curses::COLOR_GREEN color_bg = bg when :yellow color_id = 3 color_fg = Curses::COLOR_YELLOW color_bg = bg when :blue color_id = 4 color_fg = Curses::COLOR_BLUE color_bg = bg when :magenta color_id = 5 color_fg = Curses::COLOR_MAGENTA color_bg = bg when :cyan color_id = 6 color_fg = Curses::COLOR_CYAN color_bg = bg when :white color_id = 7 color_fg = Curses::COLOR_WHITE color_bg = bg when :rainbow color_id = 254 red = Random.rand(0..1000) green = Random.rand(0..1000) blue = Random.rand(0..1000) Curses.init_color(color_id, red, green, blue) color_fg = color_id color_bg = bg when :custom color_id = 255 Curses.init_color(color_id, red, green, blue) color_fg = color_id color_bg = bg else raise "Color Not Implemented for this Method: #{color}" end case style when :blink font = Curses::A_BLINK when :bold font = Curses::A_BOLD when :highlight font = Curses::A_STANDOUT when :normal font = Curses::A_NORMAL when :reverse font = Curses::A_REVERSE else raise "Font Style Not Implemented for this Method: #{style}" end Curses.init_pair(color_id, color_fg, color_bg) ui_win.attron(Curses.color_pair(color_id) | font) do ui_win.addstr(string) end rescue Interrupt # Exit Gracefully if CTRL+C is Pressed During Session Cryptum::UI::Exit.gracefully(which_self: self) rescue StandardError => e # Produce a Stacktrace for anything else Curses.close_screen raise e end # Jump to First Column public_class_method def self.col_center(opts = {}) str = opts[:str] str_divided_by_two = str.length / 2 (Curses.cols / 2) - str_divided_by_two rescue Interrupt # Exit Gracefully if CTRL+C is Pressed During Session Cryptum::UI::Exit.gracefully(which_self: self) rescue StandardError => e # Produce a Stacktrace for anything else Curses.close_screen raise e end public_class_method def self.col_first 0 rescue Interrupt # Exit Gracefully if CTRL+C is Pressed During Session Cryptum::UI::Exit.gracefully(which_self: self) rescue StandardError => e # Produce a Stacktrace for anything else Curses.close_screen raise e end # Jump to Second Column public_class_method def self.col_second (Curses.cols / 8) + 5 rescue Interrupt # Exit Gracefully if CTRL+C is Pressed During Session Cryptum::UI::Exit.gracefully(which_self: self) rescue StandardError => e # Produce a Stacktrace for anything else Curses.close_screen raise e end # Jump to Third Column public_class_method def self.col_third ((Curses.cols / 8) * 3) + 2 rescue Interrupt # Exit Gracefully if CTRL+C is Pressed During Session Cryptum::UI::Exit.gracefully(which_self: self) rescue StandardError => e # Produce a Stacktrace for anything else Curses.close_screen raise e end # Jump to Fourth Column public_class_method def self.col_fourth ((Curses.cols / 4) * 3) - 3 rescue Interrupt # Exit Gracefully if CTRL+C is Pressed During Session Cryptum::UI::Exit.gracefully(which_self: self) rescue StandardError => e # Produce a Stacktrace for anything else Curses.close_screen raise e end public_class_method def self.detect_key_press_in_ui(opts = {}) key_press_event = opts[:key_press_event] ui_win = opts[:ui_win] key_press = ui_win.get_char # Useful for detecting and logging actual key presses to file # unless key_press.nil? # File.open('/tmp/detect_key_press_in_ui-cryptum.txt', 'a') do |f| # f.puts key_press.class # f.print key_press.inspect # f.puts "\n\n\n" # end # end case key_press when 'C' key_press_event.key_c = true when 'G' key_press_event.key_g = true when 'r' key_press_event.key_r = true when 'u' key_press_event.key_u = true when 'w' key_press_event.key_w = true when 'x' key_press_event.key_x = true when "\e" key_press_event.key_esc = true when "\n" key_press_event.key_enter = true when "\t" key_press_event.key_tab = true end # What a hack to detect special keys (-.-) if key_press_event.key_esc key_press_event.key_ansi = true if key_press == '[' if key_press_event.key_ansi key_press_event.key_up_arrow = true if key_press == 'A' key_press_event.key_down_arrow = true if key_press == 'B' # NOTE: the ~ at the end of these keys are ignored # which may result in other keys working in place of them # e.g. home is \e[1~ but we know it's home as soon as # \e[1 is detected. key_press_event.key_page_up = true if key_press == '5' key_press_event.key_page_down = true if key_press == '6' key_press_event.key_home = true if key_press == '1' key_press_event.key_end = true if key_press == '4' end end key_press_event rescue Interrupt # Exit Gracefully if CTRL+C is Pressed During Session Cryptum::UI::Exit.gracefully(which_self: self) rescue StandardError => e # Produce a Stacktrace for anything else Curses.close_screen raise e end # Display a List of Every UI Module public_class_method def self.help constants.sort end end end