grmenu 4.0.1 → 4.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (5) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/data/help.txt +1 -1
  4. data/grmenu.rb +160 -144
  5. metadata +1 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 15a2bac2ca8d2fcd19044ec0e07c589799400b840a302751a0b787f58095e548
4
- data.tar.gz: b73e42131614a574a3f85313dd611f294814e97da90ceb681714e33ffab51cae
3
+ metadata.gz: 2204001c5ee3dc5f6a037e839683035a655d73d98d74c667906f268ba84d0d07
4
+ data.tar.gz: cc4d101354a88160890e4ebdb36073b5dd73cfb2ca5447aee609d6386aecb3d8
5
5
  SHA512:
6
- metadata.gz: 3598fafb53860c943e0752730c8720424436f01035122f094c4d17938786a5dee451d41b388ef4032083f132752ea6cdef15bae2f56d01eea6871d323bbb1164
7
- data.tar.gz: 0f4dd3d3da4f1f65f6c4e926815ebe294e82dca8195c2362bd3fd614da399b7f8be3ca620e05b7a158bef49bb57347469b451675490930161192fa689f8caa9f
6
+ metadata.gz: 9c91666f2d8e9c9bb6094e50eca470029223425e0bf58e10adc83bfdc5d28062bb664f2a2569b78cf33a3cfb569c9873800cce7b1ec54c64c8ee383a310c6eb5
7
+ data.tar.gz: 9da6c6d0543fc48c2f01cfdd4f64f6916698c433381504006cef981ab0b7974f785bff0c777b5e2ccc8092315658de5eaf45f42d340aed20c99abd9f9ab04f5c
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # GRmenu (Ruby) v4.0.1
1
+ # GRmenu (Ruby) v4.0.3
2
2
 
3
3
  **Suite TUI Profesional y Ligera para la Creación de Interfaces de Línea de Comandos en Terminales TTY.**
4
4
 
@@ -95,7 +95,7 @@ require 'grmenu'
95
95
  GRmenu.theme(:neon_red)
96
96
 
97
97
  def saludar
98
- GRmenu.alert(:success, "Bienvenido a GRmenu v4.0.1!")
98
+ GRmenu.alert(:success, "Bienvenido a GRmenu v4.0.3!")
99
99
  end
100
100
 
101
101
  def ver_tabla
data/data/help.txt CHANGED
@@ -8,7 +8,7 @@
8
8
  {bright_cyan}╚═══════════════════════════════════════════════════════════════════════════════════╝{reset}
9
9
 
10
10
  {bright_cyan}╔═══════════════════════════════════════════════════════════════════════════════════╗{reset}
11
- {bright_cyan}║{bright_yellow} DOCUMENTACION Y GUIA COMPLETA DE PARAMETROS (v4.0.1) {bright_cyan}║{reset}
11
+ {bright_cyan}║{bright_yellow} DOCUMENTACION Y GUIA COMPLETA DE PARAMETROS (v4.0.3) {bright_cyan}║{reset}
12
12
  {bright_cyan}║{gray} Soporte Raton SGR 1006, Submenus en Cascada 3 Niveles, Pestanas y CSS .gr {bright_cyan}║{reset}
13
13
  {bright_cyan}╚═══════════════════════════════════════════════════════════════════════════════════╝{reset}
14
14
 
data/grmenu.rb CHANGED
@@ -6,15 +6,15 @@ require 'zlib'
6
6
  require 'open3'
7
7
 
8
8
  class GRmenu
9
- VERSION = "4.0.1"
9
+ VERSION = "4.0.3"
10
10
  CLEAR_SCREEN_SEQUENCE = "\e[H\e[2J\e[3J"
11
11
  HIDE_CURSOR = "\e[?25l"
12
12
  SHOW_CURSOR = "\e[?25h"
13
13
  CURSOR_HOME = "\e[H"
14
14
  CLEAR_TO_EOL = "\e[K"
15
15
  CLEAR_TO_EOS = "\e[J"
16
- ENABLE_MOUSE = "\e[?1000h\e[?1006h"
17
- DISABLE_MOUSE = "\e[?1000l\e[?1006l"
16
+ ENABLE_MOUSE = "\e[?1000h\e[?1002h\e[?1006h"
17
+ DISABLE_MOUSE = "\e[?1006l\e[?1002l\e[?1000l"
18
18
 
19
19
  def self.find_data_file(filename)
20
20
  local_path = File.expand_path("data/#{filename}", __dir__)
@@ -24,6 +24,30 @@ class GRmenu
24
24
  nil
25
25
  end
26
26
 
27
+ def self.enable_windows_vt
28
+ return unless Gem.win_platform? || RUBY_PLATFORM =~ /mswin|mingw|cygwin/
29
+ require 'fiddle'
30
+ kernel32 = Fiddle.dlopen('kernel32')
31
+ get_std_handle = Fiddle::Function.new(kernel32['GetStdHandle'], [Fiddle::TYPE_INT], Fiddle::TYPE_VOIDP)
32
+ get_console_mode = Fiddle::Function.new(kernel32['GetConsoleMode'], [Fiddle::TYPE_VOIDP, Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT)
33
+ set_console_mode = Fiddle::Function.new(kernel32['SetConsoleMode'], [Fiddle::TYPE_VOIDP, Fiddle::TYPE_INT], Fiddle::TYPE_INT)
34
+
35
+ h_out = get_std_handle.call(-11)
36
+ out_mode = ' ' * 4
37
+ if get_console_mode.call(h_out, out_mode) != 0
38
+ m = out_mode.unpack1('L')
39
+ set_console_mode.call(h_out, m | 0x0004)
40
+ end
41
+
42
+ h_in = get_std_handle.call(-10)
43
+ in_mode = ' ' * 4
44
+ if get_console_mode.call(h_in, in_mode) != 0
45
+ m = in_mode.unpack1('L')
46
+ set_console_mode.call(h_in, m | 0x0200)
47
+ end
48
+ rescue StandardError
49
+ end
50
+
27
51
  def self.load_json_data(filename)
28
52
  path = find_data_file(filename)
29
53
  return {} unless path && File.exist?(path)
@@ -1448,27 +1472,37 @@ class GRmenu
1448
1472
  return nil if first_char.nil?
1449
1473
 
1450
1474
  if first_char == "\e"
1451
- begin
1452
- second = is_tty ? input_stream.read_nonblock(1) : input_stream.read(1)
1453
- if second
1454
- first_char << second
1455
- if second == "[" || second == "O"
1456
- while true
1457
- ch = is_tty ? input_stream.read_nonblock(1) : input_stream.read(1)
1458
- break if ch.nil?
1459
- first_char << ch
1460
- break if ch =~ /[a-zA-Z~]/
1461
- end
1462
- end
1475
+ seq = first_char.dup
1476
+ if is_tty
1477
+ while (ch = (input_stream.getch(min: 0, time: 0.1) rescue nil))
1478
+ seq << ch
1479
+ break if seq =~ /[a-zA-Z~]\z/
1480
+ end
1481
+ else
1482
+ while (IO.select([input_stream], nil, nil, 0.05) rescue nil)
1483
+ ch = (input_stream.read(1) rescue nil)
1484
+ break if ch.nil?
1485
+ seq << ch
1486
+ break if seq =~ /[a-zA-Z~]\z/
1463
1487
  end
1464
- rescue IO::WaitReadable, IO::EAGAINWaitReadable, EOFError
1465
1488
  end
1466
- elsif first_char == "\x00" || first_char == "\xe0"
1467
- begin
1468
- second_char = is_tty ? input_stream.read_nonblock(1) : input_stream.read(1)
1469
- first_char << second_char if second_char
1470
- rescue IO::WaitReadable, IO::EAGAINWaitReadable, EOFError
1489
+
1490
+ if seq == "\e[M"
1491
+ cb = is_tty ? (input_stream.getch(min: 0, time: 0.1) rescue nil) : (input_stream.read(1) rescue nil)
1492
+ cx = is_tty ? (input_stream.getch(min: 0, time: 0.1) rescue nil) : (input_stream.read(1) rescue nil)
1493
+ cy = is_tty ? (input_stream.getch(min: 0, time: 0.1) rescue nil) : (input_stream.read(1) rescue nil)
1494
+ if cb && cx && cy
1495
+ btn_c = cb.ord - 32
1496
+ col_c = cx.ord - 32
1497
+ row_c = cy.ord - 32
1498
+ return "\e[<#{btn_c};#{col_c};#{row_c}M"
1499
+ end
1471
1500
  end
1501
+
1502
+ return seq
1503
+ elsif first_char == "\x00" || first_char == "\xe0"
1504
+ second_char = is_tty ? (input_stream.getch(min: 0, time: 0.1) rescue nil) : (input_stream.read(1) rescue nil)
1505
+ return first_char + second_char if second_char
1472
1506
  end
1473
1507
 
1474
1508
  first_char
@@ -2587,8 +2621,12 @@ class GRmenu
2587
2621
  @image = image || keyword_arguments[:image]
2588
2622
  @image_width = (image_width || keyword_arguments[:image_width])&.to_i
2589
2623
  @animate = (keyword_arguments[:animate] || (@@global_theme.is_a?(Hash) && @@global_theme.dig(:sections, 'menu', 'animate')) || false).to_s
2590
- @desc_prefix = keyword_arguments[:desc_prefix] || keyword_arguments[:description_prefix]
2591
- @mouse = (mouse == true || keyword_arguments[:mouse] == true || mouse.to_s == 'true' || keyword_arguments[:mouse].to_s == 'true' || (theme_menu_sec['mouse'].to_s == 'true'))
2624
+ m_val = mouse.nil? ? keyword_arguments[:mouse] : mouse
2625
+ if m_val.nil?
2626
+ @mouse = theme_menu_sec.key?('mouse') ? (theme_menu_sec['mouse'].to_s != 'false') : true
2627
+ else
2628
+ @mouse = (m_val == true || m_val.to_s == 'true')
2629
+ end
2592
2630
 
2593
2631
  t_sec = (@@global_theme.is_a?(Hash) && @@global_theme.dig(:sections, "tabs")) || {}
2594
2632
  @active_tab_color = (active_tab_color || keyword_arguments[:active_tab_color] || t_sec["active_tab"] || t_sec["active_tab_color"] || "yellow").to_s
@@ -2733,8 +2771,7 @@ class GRmenu
2733
2771
  brightness_level = parts[1].to_i if parts[1] && !parts[1].empty?
2734
2772
  end
2735
2773
 
2736
- is_neon_color = color_name.start_with?("neon")
2737
- is_anim_active = is_neon_color || (@animate && ["diagonal", "linear", "fade", "rgb", "rainbow", "chroma", "neon"].include?(@animate.to_s.downcase))
2774
+ is_anim_active = @animate && ["neon", "fade"].include?(@animate.to_s.downcase)
2738
2775
  is_chroma = color_name == "rgb" || color_name == "rainbow" || color_name == "chroma" || @animate.to_s.downcase == "rgb"
2739
2776
 
2740
2777
  if is_chroma
@@ -2784,53 +2821,13 @@ class GRmenu
2784
2821
  BASE_RGB[color_name] || [255, 255, 255]
2785
2822
  end
2786
2823
 
2787
- if @animate.to_s.downcase == "fade"
2788
- factor = (Math.sin(tick + phase_offset) + 1.0) / 2.0
2789
- f = 0.35 + 0.65 * factor
2790
- r = (base[0] * f).clamp(0, 255).to_i
2791
- g = (base[1] * f).clamp(0, 255).to_i
2792
- b = (base[2] * f).clamp(0, 255).to_i
2793
- glow = (factor > 0.85) ? ";1" : ""
2794
- return "\e[38;2;#{r};#{g};#{b}#{glow}m#{text}#{self.class.ansi_reset}"
2795
- else
2796
- out = String.new("")
2797
- char_count = 0
2798
- in_escape = false
2799
- escape_buf = String.new("")
2800
-
2801
- text.to_s.each_char do |ch|
2802
- if ch == "\e"
2803
- in_escape = true
2804
- escape_buf << ch
2805
- next
2806
- end
2807
- if in_escape
2808
- escape_buf << ch
2809
- if ch =~ /[a-zA-Z]/
2810
- in_escape = false
2811
- out << escape_buf
2812
- escape_buf.clear
2813
- end
2814
- next
2815
- end
2816
-
2817
- if ch == " " || ch == "\t" || ch == "\r" || ch == "\n"
2818
- out << ch
2819
- else
2820
- phase = char_count * 0.22 + phase_offset
2821
- factor = (Math.sin(tick + phase) + 1.0) / 2.0
2822
- f = 0.35 + 0.65 * factor
2823
- r = (base[0] * f).clamp(0, 255).to_i
2824
- g = (base[1] * f).clamp(0, 255).to_i
2825
- b = (base[2] * f).clamp(0, 255).to_i
2826
- glow = (factor > 0.85) ? ";1" : ""
2827
- out << "\e[38;2;#{r};#{g};#{b}#{glow}m#{ch}"
2828
- char_count += 1
2829
- end
2830
- end
2831
- out << self.class.ansi_reset
2832
- return out
2833
- end
2824
+ factor = (Math.sin(tick + phase_offset) + 1.0) / 2.0
2825
+ f = 0.35 + 0.65 * factor
2826
+ r = (base[0] * f).clamp(0, 255).to_i
2827
+ g = (base[1] * f).clamp(0, 255).to_i
2828
+ b = (base[2] * f).clamp(0, 255).to_i
2829
+ glow = (factor > 0.85) ? ";1" : ""
2830
+ return "\e[38;2;#{r};#{g};#{b}#{glow}m#{text}#{self.class.ansi_reset}"
2834
2831
  end
2835
2832
 
2836
2833
  color_code = self.class.ansi_color(color_name, brightness_level)
@@ -3053,7 +3050,8 @@ class GRmenu
3053
3050
  if @banner && !@banner.empty?
3054
3051
  banner_lines, banner_box_w = render_banner_lines(term_cols)
3055
3052
  unless banner_lines.empty?
3056
- rendered_lines.concat(banner_lines)
3053
+ b_pad = (@center && term_cols > banner_box_w) ? " " * ((term_cols - banner_box_w) / 2) : ""
3054
+ rendered_lines.concat(banner_lines.map { |l| "#{b_pad}#{l}" })
3057
3055
  rendered_lines << ""
3058
3056
  header_lines_count += banner_lines.length + 1
3059
3057
  header_box_width = [header_box_width, banner_box_w].max
@@ -3075,28 +3073,63 @@ class GRmenu
3075
3073
  calculated_width = ([calculated_width, GRmenu.display_width(@query) + 16].max) if @search
3076
3074
  total_width = [calculated_width, term_cols - 2].min
3077
3075
 
3078
- reference_width = header_box_width > 0 ? header_box_width : total_width
3079
- margin_left = (@center && reference_width > total_width) ? " " * ((reference_width - total_width) / 2) : ""
3076
+ sub_1_preview_w = 0
3077
+ sub_2_preview_w = 0
3078
+ if @open_level >= 1 && is_submenu_item?(@functions[@index])
3079
+ s1_acts = get_submenu_actions(@functions[@index])
3080
+ if s1_acts && !s1_acts.empty?
3081
+ s1_names = s1_acts.map { |a| extract_name_from_action(a) }
3082
+ s1_max = s1_names.empty? ? 10 : s1_names.map { |n| GRmenu.display_width(n) }.max
3083
+ s1_title = all_names[@index] || ""
3084
+ sub_1_preview_w = [s1_max + 8, GRmenu.display_width(s1_title) + 6, 20].max
3085
+ sub_1_preview_w = [sub_1_preview_w, 36].min
3086
+
3087
+ if @open_level >= 2 && is_submenu_item?(s1_acts[@sub_index_1])
3088
+ s2_acts = get_submenu_actions(s1_acts[@sub_index_1])
3089
+ if s2_acts && !s2_acts.empty?
3090
+ s2_names = s2_acts.map { |a| extract_name_from_action(a) }
3091
+ s2_max = s2_names.empty? ? 10 : s2_names.map { |n| GRmenu.display_width(n) }.max
3092
+ s2_title = extract_name_from_action(s1_acts[@sub_index_1]) || ""
3093
+ sub_2_preview_w = [s2_max + 8, GRmenu.display_width(s2_title) + 6, 20].max
3094
+ sub_2_preview_w = [sub_2_preview_w, 36].min
3095
+ end
3096
+ end
3097
+ end
3098
+ end
3099
+
3100
+ total_chain_w = total_width
3101
+ total_chain_w += 2 + sub_1_preview_w if sub_1_preview_w > 0
3102
+ total_chain_w += 2 + sub_2_preview_w if sub_2_preview_w > 0
3103
+
3104
+ margin_left = if @center && term_cols > total_chain_w
3105
+ " " * ((term_cols - total_chain_w) / 2)
3106
+ elsif @center && term_cols > total_width
3107
+ " " * ((term_cols - total_width) / 2)
3108
+ else
3109
+ ""
3110
+ end
3080
3111
 
3081
3112
  subtitle_lines_count = 0
3082
3113
  if @subtitle && !@subtitle.empty?
3083
3114
  subtitle_lines = @subtitle.lines.map(&:chomp)
3084
- div_w = @divider.is_a?(Numeric) ? @divider.to_i : [reference_width, term_cols - 2].min
3115
+ ref_sub_w = header_box_width > 0 ? header_box_width : total_chain_w
3116
+ div_w = @divider.is_a?(Numeric) ? @divider.to_i : [ref_sub_w, term_cols - 2].min
3117
+ sub_pad = (@center && term_cols > div_w) ? " " * ((term_cols - div_w) / 2) : ""
3085
3118
 
3086
3119
  if @divider
3087
- rendered_lines << colorize("─" * div_w, @style_config.divider, 0.0)
3120
+ rendered_lines << "#{sub_pad}#{colorize("─" * div_w, @style_config.divider, 0.0)}"
3088
3121
  subtitle_lines_count += 1
3089
3122
  end
3090
3123
 
3091
3124
  subtitle_lines.each_with_index do |sub_line, s_i|
3092
3125
  pad_sub = [div_w - GRmenu.display_width(sub_line), 0].max
3093
3126
  formatted_sub = @center ? (" " * (pad_sub / 2) + sub_line + " " * (pad_sub - (pad_sub / 2))) : sub_line
3094
- rendered_lines << colorize(formatted_sub, @style_config.subtitle, s_i * 0.3)
3127
+ rendered_lines << "#{sub_pad}#{colorize(formatted_sub, @style_config.subtitle, s_i * 0.3)}"
3095
3128
  subtitle_lines_count += 1
3096
3129
  end
3097
3130
 
3098
3131
  if @divider
3099
- rendered_lines << colorize("─" * div_w, @style_config.divider, 0.6)
3132
+ rendered_lines << "#{sub_pad}#{colorize("─" * div_w, @style_config.divider, 0.6)}"
3100
3133
  subtitle_lines_count += 1
3101
3134
  end
3102
3135
  rendered_lines << ""
@@ -3189,6 +3222,7 @@ class GRmenu
3189
3222
  v_left = colorize(v_l_raw, border_color_cfg, 0.2)
3190
3223
  v_right = colorize(v_r_raw, border_color_cfg, 0.8)
3191
3224
 
3225
+ main_box_start = rendered_lines.length
3192
3226
  top_border_line = box_border[:tl] + top_fill + box_border[:tr]
3193
3227
  rendered_lines << "#{margin_left}#{colorize(top_border_line, border_color_cfg, 0.0)}"
3194
3228
 
@@ -3411,9 +3445,9 @@ class GRmenu
3411
3445
  if sub_2_lines
3412
3446
  total_3_w = margin_left.length + total_width + 2 + sub_1_w + 2 + sub_2_w
3413
3447
  if total_3_w <= term_cols
3414
- sub_1_start = [[parent_row_idx - 1, 0].max, [rendered_lines.length - sub_1_lines.length, 0].max].min
3448
+ sub_1_start = main_box_start
3415
3449
  p1_abs_row = sub_1_start + (p_row_1 || 1)
3416
- sub_2_start = [[p1_abs_row - 1, 0].max, [rendered_lines.length - sub_2_lines.length, 0].max].min
3450
+ sub_2_start = main_box_start
3417
3451
  max_3_lines = [rendered_lines.length, sub_1_start + sub_1_lines.length, sub_2_start + sub_2_lines.length].max
3418
3452
 
3419
3453
  x1_start = margin_left.length + total_width + 2
@@ -3460,7 +3494,7 @@ class GRmenu
3460
3494
  rendered_lines = stitched_lines
3461
3495
  elsif (sub_1_w + 2 + sub_2_w) <= term_cols
3462
3496
  p1_abs_row = (p_row_1 || 1)
3463
- sub_2_start = [[p1_abs_row - 1, 0].max, [sub_1_lines.length - sub_2_lines.length, 0].max].min
3497
+ sub_2_start = main_box_start
3464
3498
  max_2_lines = [sub_1_lines.length, sub_2_start + sub_2_lines.length].max
3465
3499
 
3466
3500
  x1_start = margin_left.length
@@ -3500,7 +3534,7 @@ class GRmenu
3500
3534
  else
3501
3535
  total_2_w = margin_left.length + total_width + 2 + sub_1_w
3502
3536
  if total_2_w <= term_cols
3503
- sub_start_line = [[parent_row_idx - 1, 0].max, [rendered_lines.length - sub_1_lines.length, 0].max].min
3537
+ sub_start_line = main_box_start
3504
3538
  max_total_lines = [rendered_lines.length, sub_start_line + sub_1_lines.length].max
3505
3539
 
3506
3540
  x1_start = margin_left.length + total_width + 2
@@ -3736,11 +3770,15 @@ class GRmenu
3736
3770
  target_width = min_width || size_max || 20
3737
3771
  action_to_execute = nil
3738
3772
 
3773
+ self.class.enable_windows_vt
3774
+ $stdout.sync = true
3775
+
3739
3776
  is_tty = $stdin.respond_to?(:tty?) && $stdin.tty?
3740
3777
 
3741
3778
  begin
3742
3779
  Kernel.print("#{HIDE_CURSOR}#{CLEAR_SCREEN_SEQUENCE}")
3743
3780
  Kernel.print(ENABLE_MOUSE) if @mouse
3781
+ $stdout.flush
3744
3782
 
3745
3783
  if @animate && !["false", "rgb", "", "nil"].include?(@animate.downcase)
3746
3784
  intro_lines = render_lines(target_width)
@@ -3757,17 +3795,21 @@ class GRmenu
3757
3795
  ensure
3758
3796
  Kernel.print(DISABLE_MOUSE) if @mouse
3759
3797
  Kernel.print(SHOW_CURSOR)
3798
+ $stdout.flush
3760
3799
  end
3761
3800
 
3762
3801
  if action_to_execute
3763
3802
  Kernel.print(CLEAR_SCREEN_SEQUENCE)
3803
+ $stdout.flush
3764
3804
  execute_action(action_to_execute)
3765
3805
  else
3766
3806
  Kernel.print(CLEAR_SCREEN_SEQUENCE)
3807
+ $stdout.flush
3767
3808
  end
3768
3809
  rescue Interrupt
3769
3810
  Kernel.print(DISABLE_MOUSE) if @mouse
3770
3811
  Kernel.print("#{SHOW_CURSOR}#{CLEAR_SCREEN_SEQUENCE}")
3812
+ $stdout.flush
3771
3813
  nil
3772
3814
  end
3773
3815
 
@@ -3782,6 +3824,7 @@ class GRmenu
3782
3824
  end
3783
3825
  buffer << CLEAR_TO_EOS
3784
3826
  Kernel.print(buffer)
3827
+ $stdout.flush
3785
3828
  end
3786
3829
 
3787
3830
  def run_interactive_loop(input_stream, target_width)
@@ -3823,34 +3866,40 @@ class GRmenu
3823
3866
  act = $4
3824
3867
 
3825
3868
  if btn == 64
3826
- if @level == 2 && @open_level >= 2 && is_submenu_item?(@functions[@index])
3869
+ if @open_level >= 2 && @sub_2_col_rng && @sub_2_col_rng.cover?(col) && is_submenu_item?(@functions[@index])
3827
3870
  s1_acts = get_submenu_actions(@functions[@index])
3828
3871
  s2_acts = get_submenu_actions(s1_acts[@sub_index_1]) if s1_acts
3829
3872
  @sub_index_2 = (@sub_index_2 - 1) % s2_acts.length if s2_acts && !s2_acts.empty?
3830
- elsif @level == 1 && @open_level >= 1 && is_submenu_item?(@functions[@index])
3873
+ @level = 2
3874
+ elsif @open_level >= 1 && @sub_1_col_rng && @sub_1_col_rng.cover?(col) && is_submenu_item?(@functions[@index])
3831
3875
  s1_acts = get_submenu_actions(@functions[@index])
3832
3876
  @sub_index_1 = (@sub_index_1 - 1) % s1_acts.length if s1_acts && !s1_acts.empty?
3833
3877
  @sub_index_2 = 0
3878
+ @level = 1
3834
3879
  else
3835
3880
  move_up
3836
3881
  @sub_index_1 = 0
3837
3882
  @sub_index_2 = 0
3883
+ @level = 0
3838
3884
  end
3839
3885
  draw_frame(target_width)
3840
3886
  next
3841
3887
  elsif btn == 65
3842
- if @level == 2 && @open_level >= 2 && is_submenu_item?(@functions[@index])
3888
+ if @open_level >= 2 && @sub_2_col_rng && @sub_2_col_rng.cover?(col) && is_submenu_item?(@functions[@index])
3843
3889
  s1_acts = get_submenu_actions(@functions[@index])
3844
3890
  s2_acts = get_submenu_actions(s1_acts[@sub_index_1]) if s1_acts
3845
3891
  @sub_index_2 = (@sub_index_2 + 1) % s2_acts.length if s2_acts && !s2_acts.empty?
3846
- elsif @level == 1 && @open_level >= 1 && is_submenu_item?(@functions[@index])
3892
+ @level = 2
3893
+ elsif @open_level >= 1 && @sub_1_col_rng && @sub_1_col_rng.cover?(col) && is_submenu_item?(@functions[@index])
3847
3894
  s1_acts = get_submenu_actions(@functions[@index])
3848
3895
  @sub_index_1 = (@sub_index_1 + 1) % s1_acts.length if s1_acts && !s1_acts.empty?
3849
3896
  @sub_index_2 = 0
3897
+ @level = 1
3850
3898
  else
3851
3899
  move_down
3852
3900
  @sub_index_1 = 0
3853
3901
  @sub_index_2 = 0
3902
+ @level = 0
3854
3903
  end
3855
3904
  draw_frame(target_width)
3856
3905
  next
@@ -3889,14 +3938,9 @@ class GRmenu
3889
3938
  s1_acts = get_submenu_actions(@functions[@index])
3890
3939
  s2_acts = get_submenu_actions(s1_acts[@sub_index_1]) if s1_acts
3891
3940
  if s2_acts && s2_clicked < s2_acts.length
3892
- if @level == 2 && @sub_index_2 == s2_clicked
3893
- return s2_acts[s2_clicked]
3894
- else
3895
- @level = 2
3896
- @sub_index_2 = s2_clicked
3897
- draw_frame(target_width)
3898
- next
3899
- end
3941
+ @level = 2
3942
+ @sub_index_2 = s2_clicked
3943
+ return s2_acts[s2_clicked]
3900
3944
  end
3901
3945
  end
3902
3946
 
@@ -3905,67 +3949,39 @@ class GRmenu
3905
3949
  s1_acts = get_submenu_actions(@functions[@index])
3906
3950
  if s1_acts && s1_clicked < s1_acts.length
3907
3951
  t_act = s1_acts[s1_clicked]
3908
- if @level == 1 && @sub_index_1 == s1_clicked
3909
- if is_submenu_item?(t_act)
3910
- @open_level = 2
3911
- @level = 2
3912
- @sub_index_2 = 0
3913
- draw_frame(target_width)
3914
- next
3915
- else
3916
- return t_act
3917
- end
3918
- else
3919
- @level = 1
3920
- @sub_index_1 = s1_clicked
3921
- if is_submenu_item?(t_act)
3922
- @open_level = 2
3923
- @sub_index_2 = 0
3924
- else
3925
- @open_level = 1
3926
- end
3952
+ @level = 1
3953
+ @sub_index_1 = s1_clicked
3954
+ if is_submenu_item?(t_act)
3955
+ @open_level = 2
3956
+ @level = 2
3957
+ @sub_index_2 = 0
3927
3958
  draw_frame(target_width)
3928
3959
  next
3960
+ else
3961
+ return t_act
3929
3962
  end
3930
3963
  end
3931
3964
  end
3932
3965
 
3933
3966
  if @row_hit_map && @row_hit_map[row]
3934
3967
  hit = @row_hit_map[row]
3935
- inner_x = col - hit[:margin_left] - 3
3936
- if inner_x >= 0
3937
- c_idx = (inner_x / (hit[:col_w] + 2)).to_i
3938
- c_idx = [[c_idx, 0].max, hit[:cols] - 1].min
3968
+ x_in_box = col - hit[:margin_left]
3969
+ if x_in_box > 0 && (hit[:total_w].nil? || x_in_box <= hit[:total_w])
3970
+ c_idx = [[((x_in_box - 2) / ([hit[:col_w], 1].max + 2)).to_i, 0].max, hit[:cols] - 1].min
3939
3971
  clicked_item = hit[:row_indices][c_idx]
3940
3972
  if clicked_item
3941
- if @index == clicked_item
3942
- if is_submenu_item?(@functions[clicked_item])
3943
- @open_level = 1
3944
- @level = 1
3945
- @sub_index_1 = 0
3946
- @sub_index_2 = 0
3947
- @active_panel = :sub
3948
- @submenu_open = true
3949
- draw_frame(target_width)
3950
- next
3951
- else
3952
- return @functions[clicked_item]
3953
- end
3954
- else
3955
- @index = clicked_item
3956
- @level = 0
3957
- @active_panel = :main
3958
- if is_submenu_item?(@functions[clicked_item])
3959
- @open_level = 1
3960
- @sub_index_1 = 0
3961
- @sub_index_2 = 0
3962
- @submenu_open = true
3963
- else
3964
- @open_level = 0
3965
- @submenu_open = false
3966
- end
3973
+ @index = clicked_item
3974
+ if is_submenu_item?(@functions[clicked_item])
3975
+ @open_level = 1
3976
+ @level = 1
3977
+ @sub_index_1 = 0
3978
+ @sub_index_2 = 0
3979
+ @active_panel = :sub
3980
+ @submenu_open = true
3967
3981
  draw_frame(target_width)
3968
3982
  next
3983
+ else
3984
+ return @functions[clicked_item]
3969
3985
  end
3970
3986
  end
3971
3987
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: grmenu
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.1
4
+ version: 4.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - grcode