grmenu 4.0.2 → 4.1.0

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 +3 -3
  3. data/data/help.txt +1 -1
  4. data/grmenu.rb +261 -125
  5. metadata +1 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c028e16af097dddc8e61b7cc766cc6a7f1870616e3c5169c832fe6edcf79fb55
4
- data.tar.gz: 1c0070cb22cebd71fa4b235c0cea7bd51c1af58c7b662fbe5bd2d9976709e774
3
+ metadata.gz: 4cfab6080b581db0dddff8e9285cb831f70f259bb9da2965761702829c07292f
4
+ data.tar.gz: 172214b97293124225a3f6eef3f9b71842d3e49a7159e3cc27bacc407ec6db66
5
5
  SHA512:
6
- metadata.gz: ba425e3a5e0a2d4692f9bc79e249a8303a245e0aeca137bd343fee489020d6b3f1b4c37147751ca4d5c05ab119b97848f6f7470803984550c69b93c0ae77a8cc
7
- data.tar.gz: 90959c3c3c4ae76ec8bca759faea2ecdb801ee8fbc977bfae15618ad3af603202c95b2192e0296193cee5a933a0aa93e2ac559db84e0a967380c3e4737839c50
6
+ metadata.gz: 2437295ff5176fc4ace40768e03e7cd25ecbfa0e1562ef625e348eac1f69c7e91c60b2cedf3d48c0f4a9285272978e8b0ae3ec8c1a81e3dbf2c47296b4ef7d0d
7
+ data.tar.gz: 021bf58afb13dce516963e7bb16b0fe5830498c2e88ab961a6dca0c4f7d5dc13e54fde83cf89b2b5a89a632f9a63a107539a462b82b65ec60f64e78f92eefee8
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # GRmenu (Ruby) v4.0.2
1
+ # GRmenu (Ruby) v4.1.0
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
 
@@ -73,7 +73,7 @@ gem install grmenu
73
73
  ### Vía Gemfile
74
74
 
75
75
  ```ruby
76
- gem 'grmenu', '~> 4.0'
76
+ gem 'grmenu', '~> 4.1'
77
77
  ```
78
78
 
79
79
  ### Requerimiento en scripts de Ruby
@@ -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.2!")
98
+ GRmenu.alert(:success, "Bienvenido a GRmenu v4.1.0!")
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.2) {bright_cyan}║{reset}
11
+ {bright_cyan}║{bright_yellow} DOCUMENTACION Y GUIA COMPLETA DE PARAMETROS (v4.1.0) {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,7 +6,7 @@ require 'zlib'
6
6
  require 'open3'
7
7
 
8
8
  class GRmenu
9
- VERSION = "4.0.2"
9
+ VERSION = "4.1.0"
10
10
  CLEAR_SCREEN_SEQUENCE = "\e[H\e[2J\e[3J"
11
11
  HIDE_CURSOR = "\e[?25l"
12
12
  SHOW_CURSOR = "\e[?25h"
@@ -1531,10 +1531,24 @@ class GRmenu
1531
1531
  @divider = divider.dup
1532
1532
  @font = font.to_i
1533
1533
  @desc_prefix = desc_prefix.to_s
1534
+ @explicitly_set = {}
1534
1535
  end
1535
1536
 
1536
- def desc_prefix(prefix_str = nil)
1537
+ def explicitly_set?(key)
1538
+ @explicitly_set ||= {}
1539
+ @explicitly_set[key.to_sym] == true || self.class.explicitly_set?(key)
1540
+ end
1541
+
1542
+ def mark_explicit(key)
1543
+ @explicitly_set ||= {}
1544
+ @explicitly_set[key.to_sym] = true
1545
+ end
1546
+
1547
+ def desc_prefix(prefix_str = nil, from_css: false)
1537
1548
  return @desc_prefix if prefix_str.nil?
1549
+ return self if from_css && explicitly_set?(:desc_prefix)
1550
+ @explicitly_set ||= {}
1551
+ @explicitly_set[:desc_prefix] = true unless from_css
1538
1552
  @desc_prefix = prefix_str.to_s
1539
1553
  self
1540
1554
  end
@@ -1542,8 +1556,11 @@ class GRmenu
1542
1556
  alias_method :desc_prefix=, :desc_prefix
1543
1557
  alias_method :description_prefix=, :desc_prefix
1544
1558
 
1545
- def border(color_name = nil, brightness_level = 1)
1559
+ def border(color_name = nil, brightness_level = 1, from_css: false)
1546
1560
  return @border if color_name.nil?
1561
+ return self if from_css && explicitly_set?(:border)
1562
+ @explicitly_set ||= {}
1563
+ @explicitly_set[:border] = true unless from_css
1547
1564
  @border = parse_color(color_name, brightness_level)
1548
1565
  self
1549
1566
  end
@@ -1551,8 +1568,11 @@ class GRmenu
1551
1568
  alias_method :set_border, :border
1552
1569
  alias_method :border=, :border
1553
1570
 
1554
- def options(color_name = nil, brightness_level = 1)
1571
+ def options(color_name = nil, brightness_level = 1, from_css: false)
1555
1572
  return @options if color_name.nil?
1573
+ return self if from_css && explicitly_set?(:options)
1574
+ @explicitly_set ||= {}
1575
+ @explicitly_set[:options] = true unless from_css
1556
1576
  @options = parse_color(color_name, brightness_level)
1557
1577
  self
1558
1578
  end
@@ -1560,8 +1580,11 @@ class GRmenu
1560
1580
  alias_method :set_options, :options
1561
1581
  alias_method :options=, :options
1562
1582
 
1563
- def focus(color_name = nil, brightness_level = 2)
1583
+ def focus(color_name = nil, brightness_level = 2, from_css: false)
1564
1584
  return @focus if color_name.nil?
1585
+ return self if from_css && explicitly_set?(:focus)
1586
+ @explicitly_set ||= {}
1587
+ @explicitly_set[:focus] = true unless from_css
1565
1588
  @focus = parse_color(color_name, brightness_level)
1566
1589
  self
1567
1590
  end
@@ -1569,8 +1592,11 @@ class GRmenu
1569
1592
  alias_method :set_focus, :focus
1570
1593
  alias_method :focus=, :focus
1571
1594
 
1572
- def title(color_name = nil, brightness_level = 2)
1595
+ def title(color_name = nil, brightness_level = 2, from_css: false)
1573
1596
  return @title if color_name.nil?
1597
+ return self if from_css && explicitly_set?(:title)
1598
+ @explicitly_set ||= {}
1599
+ @explicitly_set[:title] = true unless from_css
1574
1600
  @title = parse_color(color_name, brightness_level)
1575
1601
  self
1576
1602
  end
@@ -1578,8 +1604,11 @@ class GRmenu
1578
1604
  alias_method :set_title, :title
1579
1605
  alias_method :title=, :title
1580
1606
 
1581
- def banner(color_name = nil, brightness_level = 2)
1607
+ def banner(color_name = nil, brightness_level = 2, from_css: false)
1582
1608
  return @banner if color_name.nil?
1609
+ return self if from_css && explicitly_set?(:banner)
1610
+ @explicitly_set ||= {}
1611
+ @explicitly_set[:banner] = true unless from_css
1583
1612
  @banner = parse_color(color_name, brightness_level)
1584
1613
  self
1585
1614
  end
@@ -1587,8 +1616,11 @@ class GRmenu
1587
1616
  alias_method :set_banner, :banner
1588
1617
  alias_method :banner=, :banner
1589
1618
 
1590
- def subtitle(color_name = nil, brightness_level = 2)
1619
+ def subtitle(color_name = nil, brightness_level = 2, from_css: false)
1591
1620
  return @subtitle if color_name.nil?
1621
+ return self if from_css && explicitly_set?(:subtitle)
1622
+ @explicitly_set ||= {}
1623
+ @explicitly_set[:subtitle] = true unless from_css
1592
1624
  @subtitle = parse_color(color_name, brightness_level)
1593
1625
  self
1594
1626
  end
@@ -1596,8 +1628,11 @@ class GRmenu
1596
1628
  alias_method :set_subtitle, :subtitle
1597
1629
  alias_method :subtitle=, :subtitle
1598
1630
 
1599
- def divider(color_name = nil, brightness_level = 1)
1631
+ def divider(color_name = nil, brightness_level = 1, from_css: false)
1600
1632
  return @divider if color_name.nil?
1633
+ return self if from_css && explicitly_set?(:divider)
1634
+ @explicitly_set ||= {}
1635
+ @explicitly_set[:divider] = true unless from_css
1601
1636
  @divider = parse_color(color_name, brightness_level)
1602
1637
  self
1603
1638
  end
@@ -1605,8 +1640,11 @@ class GRmenu
1605
1640
  alias_method :set_divider, :divider
1606
1641
  alias_method :divider=, :divider
1607
1642
 
1608
- def font(font_id = nil)
1643
+ def font(font_id = nil, from_css: false)
1609
1644
  return @font if font_id.nil?
1645
+ return self if from_css && explicitly_set?(:font)
1646
+ @explicitly_set ||= {}
1647
+ @explicitly_set[:font] = true unless from_css
1610
1648
  @font = font_id.to_i
1611
1649
  self
1612
1650
  end
@@ -1625,74 +1663,111 @@ class GRmenu
1625
1663
  end
1626
1664
 
1627
1665
  class << self
1628
- def border(color_name = nil, brightness_level = 1)
1666
+ def explicitly_set?(key)
1667
+ @explicitly_set ||= {}
1668
+ @explicitly_set[key.to_sym] == true
1669
+ end
1670
+
1671
+ def mark_explicit(key)
1672
+ @explicitly_set ||= {}
1673
+ @explicitly_set[key.to_sym] = true
1674
+ end
1675
+
1676
+ def border(color_name = nil, brightness_level = 1, from_css: false)
1629
1677
  @default_border ||= { color: "cyan", level: 1 }
1630
1678
  return @default_border if color_name.nil?
1679
+ return @default_border if from_css && explicitly_set?(:border)
1680
+ @explicitly_set ||= {}
1681
+ @explicitly_set[:border] = true unless from_css
1631
1682
  @default_border = { color: color_name.to_s, level: brightness_level.to_i }
1632
1683
  end
1633
1684
  alias_method :Border, :border
1634
1685
  alias_method :border=, :border
1635
1686
 
1636
- def options(color_name = nil, brightness_level = 1)
1687
+ def options(color_name = nil, brightness_level = 1, from_css: false)
1637
1688
  @default_options ||= { color: "white", level: 1 }
1638
1689
  return @default_options if color_name.nil?
1690
+ return @default_options if from_css && explicitly_set?(:options)
1691
+ @explicitly_set ||= {}
1692
+ @explicitly_set[:options] = true unless from_css
1639
1693
  @default_options = { color: color_name.to_s, level: brightness_level.to_i }
1640
1694
  end
1641
1695
  alias_method :Options, :options
1642
1696
  alias_method :options=, :options
1643
1697
 
1644
- def focus(color_name = nil, brightness_level = 2)
1698
+ def focus(color_name = nil, brightness_level = 2, from_css: false)
1645
1699
  @default_focus ||= { color: "green", level: 2 }
1646
1700
  return @default_focus if color_name.nil?
1701
+ return @default_focus if from_css && explicitly_set?(:focus)
1702
+ @explicitly_set ||= {}
1703
+ @explicitly_set[:focus] = true unless from_css
1647
1704
  @default_focus = { color: color_name.to_s, level: brightness_level.to_i }
1648
1705
  end
1649
1706
  alias_method :Focus, :focus
1650
1707
  alias_method :focus=, :focus
1651
1708
 
1652
- def title(color_name = nil, brightness_level = 2)
1709
+ def title(color_name = nil, brightness_level = 2, from_css: false)
1653
1710
  @default_title ||= { color: "yellow", level: 2 }
1654
1711
  return @default_title if color_name.nil?
1712
+ return @default_title if from_css && explicitly_set?(:title)
1713
+ @explicitly_set ||= {}
1714
+ @explicitly_set[:title] = true unless from_css
1655
1715
  @default_title = { color: color_name.to_s, level: brightness_level.to_i }
1656
1716
  end
1657
1717
  alias_method :Title, :title
1658
1718
  alias_method :title=, :title
1659
1719
 
1660
- def banner(color_name = nil, brightness_level = 2)
1720
+ def banner(color_name = nil, brightness_level = 2, from_css: false)
1661
1721
  @default_banner ||= { color: "magenta", level: 2 }
1662
1722
  return @default_banner if color_name.nil?
1723
+ return @default_banner if from_css && explicitly_set?(:banner)
1724
+ @explicitly_set ||= {}
1725
+ @explicitly_set[:banner] = true unless from_css
1663
1726
  @default_banner = { color: color_name.to_s, level: brightness_level.to_i }
1664
1727
  end
1665
1728
  alias_method :Banner, :banner
1666
1729
  alias_method :banner=, :banner
1667
1730
 
1668
- def subtitle(color_name = nil, brightness_level = 2)
1731
+ def subtitle(color_name = nil, brightness_level = 2, from_css: false)
1669
1732
  @default_subtitle ||= { color: "cyan", level: 2 }
1670
1733
  return @default_subtitle if color_name.nil?
1734
+ return @default_subtitle if from_css && explicitly_set?(:subtitle)
1735
+ @explicitly_set ||= {}
1736
+ @explicitly_set[:subtitle] = true unless from_css
1671
1737
  @default_subtitle = { color: color_name.to_s, level: brightness_level.to_i }
1672
1738
  end
1673
1739
  alias_method :Subtitle, :subtitle
1674
1740
  alias_method :subtitle=, :subtitle
1675
1741
 
1676
- def divider(color_name = nil, brightness_level = 1)
1742
+ def divider(color_name = nil, brightness_level = 1, from_css: false)
1677
1743
  @default_divider ||= { color: "blue", level: 1 }
1678
1744
  return @default_divider if color_name.nil?
1745
+ return @default_divider if from_css && explicitly_set?(:divider)
1746
+ @explicitly_set ||= {}
1747
+ @explicitly_set[:divider] = true unless from_css
1679
1748
  @default_divider = { color: color_name.to_s, level: brightness_level.to_i }
1680
1749
  end
1681
1750
  alias_method :Divider, :divider
1682
1751
  alias_method :divider=, :divider
1683
1752
 
1684
- def font(font_id = nil)
1753
+ def font(font_id = nil, from_css: false)
1685
1754
  @default_font ||= 1
1686
1755
  return @default_font if font_id.nil?
1756
+ return @default_font if from_css && explicitly_set?(:font)
1757
+ @explicitly_set ||= {}
1758
+ @explicitly_set[:font] = true unless from_css
1687
1759
  @default_font = font_id.to_i
1688
1760
  end
1689
1761
  alias_method :Font, :font
1690
1762
  alias_method :set_font, :font
1691
1763
  alias_method :font=, :font
1692
1764
 
1693
- def desc_prefix(prefix_str = nil)
1765
+ def desc_prefix(prefix_str = nil, from_css: false)
1694
1766
  @default_desc_prefix ||= "[i]"
1695
1767
  return @default_desc_prefix if prefix_str.nil?
1768
+ return @default_desc_prefix if from_css && explicitly_set?(:desc_prefix)
1769
+ @explicitly_set ||= {}
1770
+ @explicitly_set[:desc_prefix] = true unless from_css
1696
1771
  @default_desc_prefix = prefix_str.to_s
1697
1772
  end
1698
1773
  alias_method :description_prefix, :desc_prefix
@@ -1709,7 +1784,7 @@ class GRmenu
1709
1784
  end
1710
1785
  end
1711
1786
 
1712
- attr_accessor :functions, :title, :subtitle, :banner, :banner_style, :divider, :style, :index, :style_config, :center, :page_size, :search, :columns, :query, :image, :image_width
1787
+ attr_accessor :functions, :title, :subtitle, :banner, :banner_style, :divider, :index, :style_config, :center, :page_size, :search, :columns, :query, :image, :image_width
1713
1788
 
1714
1789
  alias_method :options, :functions
1715
1790
  alias_method :options=, :functions=
@@ -1720,6 +1795,19 @@ class GRmenu
1720
1795
  alias_method :description, :subtitle
1721
1796
  alias_method :description=, :subtitle=
1722
1797
 
1798
+ def desc_prefix
1799
+ @desc_prefix || @style_config&.desc_prefix || SetStyle.desc_prefix
1800
+ end
1801
+
1802
+ def desc_prefix=(val)
1803
+ @desc_prefix = val.to_s
1804
+ @style_config&.desc_prefix(val)
1805
+ end
1806
+ alias_method :prefix, :desc_prefix
1807
+ alias_method :prefix=, :desc_prefix=
1808
+ alias_method :description_prefix, :desc_prefix
1809
+ alias_method :description_prefix=, :desc_prefix=
1810
+
1723
1811
  def self.STYLES; STYLES; end
1724
1812
  def self.COLORS; COLORS; end
1725
1813
  def self.BORDERS; BORDERS; end
@@ -1831,38 +1919,40 @@ class GRmenu
1831
1919
  m = (sec["menu"] || {}).merge(glob)
1832
1920
 
1833
1921
  if m && !m.empty?
1834
- if m["border"] || m["border_color"]
1922
+ if (m["border"] || m["border_color"]) && !SetStyle.explicitly_set?(:border)
1835
1923
  c, l = extract_color_and_level(m["border"] || m["border_color"], 1)
1836
- SetStyle.border(c, l)
1924
+ SetStyle.border(c, l, from_css: true)
1837
1925
  end
1838
- if m["title"] || m["title_color"]
1926
+ if (m["title"] || m["title_color"]) && !SetStyle.explicitly_set?(:title)
1839
1927
  c, l = extract_color_and_level(m["title"] || m["title_color"], 2)
1840
- SetStyle.title(c, l)
1928
+ SetStyle.title(c, l, from_css: true)
1841
1929
  end
1842
- if m["focus"] || m["focus_color"]
1930
+ if (m["focus"] || m["focus_color"]) && !SetStyle.explicitly_set?(:focus)
1843
1931
  c, l = extract_color_and_level(m["focus"] || m["focus_color"], 2)
1844
- SetStyle.focus(c, l)
1932
+ SetStyle.focus(c, l, from_css: true)
1845
1933
  end
1846
- if m["options"] || m["options_color"]
1934
+ if (m["options"] || m["options_color"]) && !SetStyle.explicitly_set?(:options)
1847
1935
  c, l = extract_color_and_level(m["options"] || m["options_color"], 1)
1848
- SetStyle.options(c, l)
1936
+ SetStyle.options(c, l, from_css: true)
1849
1937
  end
1850
- if m["banner"] || m["banner_color"]
1938
+ if (m["banner"] || m["banner_color"]) && !SetStyle.explicitly_set?(:banner)
1851
1939
  c, l = extract_color_and_level(m["banner"] || m["banner_color"], 2)
1852
- SetStyle.banner(c, l)
1940
+ SetStyle.banner(c, l, from_css: true)
1853
1941
  end
1854
- if m["subtitle"] || m["subtitle_color"]
1942
+ if (m["subtitle"] || m["subtitle_color"]) && !SetStyle.explicitly_set?(:subtitle)
1855
1943
  c, l = extract_color_and_level(m["subtitle"] || m["subtitle_color"], 1)
1856
- SetStyle.subtitle(c, l)
1944
+ SetStyle.subtitle(c, l, from_css: true)
1857
1945
  end
1858
- if m["divider"] || m["divider_color"]
1946
+ if (m["divider"] || m["divider_color"]) && !SetStyle.explicitly_set?(:divider)
1859
1947
  c, l = extract_color_and_level(m["divider"] || m["divider_color"], 1)
1860
- SetStyle.divider(c, l)
1948
+ SetStyle.divider(c, l, from_css: true)
1861
1949
  end
1862
- if m["desc_prefix"] || m["description_prefix"] || m["prefix"]
1863
- SetStyle.desc_prefix(m["desc_prefix"] || m["description_prefix"] || m["prefix"])
1950
+ if (m["desc_prefix"] || m["description_prefix"] || m["prefix"]) && !SetStyle.explicitly_set?(:desc_prefix)
1951
+ SetStyle.desc_prefix(m["desc_prefix"] || m["description_prefix"] || m["prefix"], from_css: true)
1952
+ end
1953
+ if m["font"] && !SetStyle.explicitly_set?(:font)
1954
+ SetStyle.font(m["font"].to_i, from_css: true)
1864
1955
  end
1865
- SetStyle.font(m["font"].to_i) if m["font"]
1866
1956
  end
1867
1957
 
1868
1958
  sec.each do |k, v|
@@ -1871,22 +1961,22 @@ class GRmenu
1871
1961
  c, l = extract_color_and_level(c_val, (v["level"] || 1).to_i)
1872
1962
  case k
1873
1963
  when "border"
1874
- SetStyle.border(c, l)
1964
+ SetStyle.border(c, l, from_css: true) unless SetStyle.explicitly_set?(:border)
1875
1965
  when "options"
1876
- SetStyle.options(c, l)
1966
+ SetStyle.options(c, l, from_css: true) unless SetStyle.explicitly_set?(:options)
1877
1967
  when "focus"
1878
- SetStyle.focus(c, l)
1968
+ SetStyle.focus(c, l, from_css: true) unless SetStyle.explicitly_set?(:focus)
1879
1969
  when "title"
1880
- SetStyle.title(c, l)
1970
+ SetStyle.title(c, l, from_css: true) unless SetStyle.explicitly_set?(:title)
1881
1971
  when "banner"
1882
- SetStyle.banner(c, l)
1972
+ SetStyle.banner(c, l, from_css: true) unless SetStyle.explicitly_set?(:banner)
1883
1973
  when "subtitle"
1884
- SetStyle.subtitle(c, l)
1974
+ SetStyle.subtitle(c, l, from_css: true) unless SetStyle.explicitly_set?(:subtitle)
1885
1975
  when "divider"
1886
- SetStyle.divider(c, l)
1976
+ SetStyle.divider(c, l, from_css: true) unless SetStyle.explicitly_set?(:divider)
1887
1977
  end
1888
1978
  end
1889
- SetStyle.font(glob["font"].to_i) if glob["font"]
1979
+ SetStyle.font(glob["font"].to_i, from_css: true) if glob["font"] && !SetStyle.explicitly_set?(:font)
1890
1980
  end
1891
1981
 
1892
1982
  def self.style(css_content)
@@ -2586,7 +2676,7 @@ class GRmenu
2586
2676
  end
2587
2677
  end
2588
2678
 
2589
- def initialize(functions = [], *positional_arguments, title: nil, banner: nil, subtitle: nil, description: nil, divider: nil, style: nil, banner_style: nil, center: true, font: nil, page_size: nil, search: false, columns: 1, image: nil, image_width: nil, mouse: nil, tabs: nil, active_tab_color: nil, tab_color: nil, **keyword_arguments)
2679
+ def initialize(functions = [], *positional_arguments, title: nil, banner: nil, subtitle: nil, description: nil, divider: nil, style: nil, banner_style: nil, center: true, font: nil, page_size: nil, search: false, columns: 1, image: nil, image_width: nil, mouse: nil, tabs: nil, active_tab_color: nil, tab_color: nil, desc_prefix: nil, prefix: nil, border: nil, border_color: nil, options_color: nil, focus_color: nil, title_color: nil, banner_color: nil, subtitle_color: nil, divider_color: nil, **keyword_arguments)
2590
2680
  tabs_data = tabs || keyword_arguments[:tabs] || (functions.is_a?(Hash) ? functions : nil)
2591
2681
  if tabs_data.is_a?(Hash) && !tabs_data.empty?
2592
2682
  @tabs = tabs_data.keys.map(&:to_s)
@@ -2659,7 +2749,9 @@ class GRmenu
2659
2749
  @cached_image_lines = nil
2660
2750
  @cached_image_cols = nil
2661
2751
 
2662
- init_font = font || keyword_arguments[:font_style] || SetStyle.font || 1
2752
+ init_font = font || keyword_arguments[:font] || keyword_arguments[:font_style] || SetStyle.font || 1
2753
+ raw_pfx = desc_prefix || prefix || keyword_arguments[:desc_prefix] || keyword_arguments[:prefix] || keyword_arguments[:description_prefix]
2754
+ @desc_prefix = raw_pfx.to_s unless raw_pfx.nil?
2663
2755
  init_pfx = @desc_prefix || (@@global_theme.is_a?(Hash) && (@@global_theme.dig(:sections, 'menu', 'desc_prefix') || @@global_theme.dig(:sections, 'menu', 'prefix'))) || SetStyle.desc_prefix || "[i]"
2664
2756
 
2665
2757
  @style_config = SetStyle.new(
@@ -2673,6 +2765,37 @@ class GRmenu
2673
2765
  font: init_font,
2674
2766
  desc_prefix: init_pfx
2675
2767
  )
2768
+ @style_config.mark_explicit(:font) if font || keyword_arguments[:font] || keyword_arguments[:font_style]
2769
+ @style_config.mark_explicit(:desc_prefix) unless raw_pfx.nil?
2770
+
2771
+ if border || border_color || keyword_arguments[:border] || keyword_arguments[:border_color]
2772
+ b_c, b_l = self.class.extract_color_and_level(border || border_color || keyword_arguments[:border] || keyword_arguments[:border_color], 1)
2773
+ @style_config.border(b_c, b_l)
2774
+ end
2775
+ if options_color || keyword_arguments[:options_color] || keyword_arguments[:options]
2776
+ o_c, o_l = self.class.extract_color_and_level(options_color || keyword_arguments[:options_color] || keyword_arguments[:options], 1)
2777
+ @style_config.options(o_c, o_l)
2778
+ end
2779
+ if focus_color || keyword_arguments[:focus_color] || keyword_arguments[:focus]
2780
+ f_c, f_l = self.class.extract_color_and_level(focus_color || keyword_arguments[:focus_color] || keyword_arguments[:focus], 2)
2781
+ @style_config.focus(f_c, f_l)
2782
+ end
2783
+ if title_color || keyword_arguments[:title_color]
2784
+ t_c, t_l = self.class.extract_color_and_level(title_color || keyword_arguments[:title_color], 2)
2785
+ @style_config.title(t_c, t_l)
2786
+ end
2787
+ if banner_color || keyword_arguments[:banner_color]
2788
+ bn_c, bn_l = self.class.extract_color_and_level(banner_color || keyword_arguments[:banner_color], 2)
2789
+ @style_config.banner(bn_c, bn_l)
2790
+ end
2791
+ if subtitle_color || keyword_arguments[:subtitle_color]
2792
+ s_c, s_l = self.class.extract_color_and_level(subtitle_color || keyword_arguments[:subtitle_color], 1)
2793
+ @style_config.subtitle(s_c, s_l)
2794
+ end
2795
+ if divider_color || keyword_arguments[:divider_color]
2796
+ d_c, d_l = self.class.extract_color_and_level(divider_color || keyword_arguments[:divider_color], 1)
2797
+ @style_config.divider(d_c, d_l)
2798
+ end
2676
2799
  end
2677
2800
 
2678
2801
  def current_matching_indices
@@ -2772,8 +2895,8 @@ class GRmenu
2772
2895
  end
2773
2896
 
2774
2897
  is_neon_color = color_name.start_with?("neon")
2775
- is_anim_active = is_neon_color || (@animate && ["diagonal", "linear", "fade", "rgb", "rainbow", "chroma", "neon"].include?(@animate.to_s.downcase))
2776
- is_chroma = color_name == "rgb" || color_name == "rainbow" || color_name == "chroma" || @animate.to_s.downcase == "rgb"
2898
+ is_anim_active = is_neon_color || (@animate && ["neon", "fade"].include?(@animate.to_s.downcase))
2899
+ is_chroma = color_name == "rgb" || color_name == "rainbow" || color_name == "chroma" || (@animate && ["rgb", "rainbow", "chroma"].include?(@animate.to_s.downcase))
2777
2900
 
2778
2901
  if is_chroma
2779
2902
  tick = @rgb_tick || 0.0
@@ -2822,53 +2945,13 @@ class GRmenu
2822
2945
  BASE_RGB[color_name] || [255, 255, 255]
2823
2946
  end
2824
2947
 
2825
- if @animate.to_s.downcase == "fade"
2826
- factor = (Math.sin(tick + phase_offset) + 1.0) / 2.0
2827
- f = 0.35 + 0.65 * factor
2828
- r = (base[0] * f).clamp(0, 255).to_i
2829
- g = (base[1] * f).clamp(0, 255).to_i
2830
- b = (base[2] * f).clamp(0, 255).to_i
2831
- glow = (factor > 0.85) ? ";1" : ""
2832
- return "\e[38;2;#{r};#{g};#{b}#{glow}m#{text}#{self.class.ansi_reset}"
2833
- else
2834
- out = String.new("")
2835
- char_count = 0
2836
- in_escape = false
2837
- escape_buf = String.new("")
2838
-
2839
- text.to_s.each_char do |ch|
2840
- if ch == "\e"
2841
- in_escape = true
2842
- escape_buf << ch
2843
- next
2844
- end
2845
- if in_escape
2846
- escape_buf << ch
2847
- if ch =~ /[a-zA-Z]/
2848
- in_escape = false
2849
- out << escape_buf
2850
- escape_buf.clear
2851
- end
2852
- next
2853
- end
2854
-
2855
- if ch == " " || ch == "\t" || ch == "\r" || ch == "\n"
2856
- out << ch
2857
- else
2858
- phase = char_count * 0.22 + phase_offset
2859
- factor = (Math.sin(tick + phase) + 1.0) / 2.0
2860
- f = 0.35 + 0.65 * factor
2861
- r = (base[0] * f).clamp(0, 255).to_i
2862
- g = (base[1] * f).clamp(0, 255).to_i
2863
- b = (base[2] * f).clamp(0, 255).to_i
2864
- glow = (factor > 0.85) ? ";1" : ""
2865
- out << "\e[38;2;#{r};#{g};#{b}#{glow}m#{ch}"
2866
- char_count += 1
2867
- end
2868
- end
2869
- out << self.class.ansi_reset
2870
- return out
2871
- end
2948
+ factor = (Math.sin(tick + phase_offset) + 1.0) / 2.0
2949
+ f = 0.35 + 0.65 * factor
2950
+ r = (base[0] * f).clamp(0, 255).to_i
2951
+ g = (base[1] * f).clamp(0, 255).to_i
2952
+ b = (base[2] * f).clamp(0, 255).to_i
2953
+ glow = (factor > 0.85) ? ";1" : ""
2954
+ return "\e[38;2;#{r};#{g};#{b}#{glow}m#{text}#{self.class.ansi_reset}"
2872
2955
  end
2873
2956
 
2874
2957
  color_code = self.class.ansi_color(color_name, brightness_level)
@@ -3091,7 +3174,8 @@ class GRmenu
3091
3174
  if @banner && !@banner.empty?
3092
3175
  banner_lines, banner_box_w = render_banner_lines(term_cols)
3093
3176
  unless banner_lines.empty?
3094
- rendered_lines.concat(banner_lines)
3177
+ b_pad = (@center && term_cols > banner_box_w) ? " " * ((term_cols - banner_box_w) / 2) : ""
3178
+ rendered_lines.concat(banner_lines.map { |l| "#{b_pad}#{l}" })
3095
3179
  rendered_lines << ""
3096
3180
  header_lines_count += banner_lines.length + 1
3097
3181
  header_box_width = [header_box_width, banner_box_w].max
@@ -3111,30 +3195,69 @@ class GRmenu
3111
3195
  calculated_width = [size_max, GRmenu.display_width(@title) + 4, grid_suggested_w].max
3112
3196
  calculated_width = ([calculated_width, GRmenu.display_width(active_desc) + 8].max) unless active_desc.empty?
3113
3197
  calculated_width = ([calculated_width, GRmenu.display_width(@query) + 16].max) if @search
3198
+ if @tabs && !@tabs.empty?
3199
+ tabs_min_w = @tabs.map { |t| GRmenu.display_width(t) + 4 }.sum + (@tabs.length - 1) * 3
3200
+ calculated_width = [calculated_width, tabs_min_w + 4].max
3201
+ end
3114
3202
  total_width = [calculated_width, term_cols - 2].min
3115
3203
 
3116
- reference_width = header_box_width > 0 ? header_box_width : total_width
3117
- margin_left = (@center && reference_width > total_width) ? " " * ((reference_width - total_width) / 2) : ""
3204
+ sub_1_preview_w = 0
3205
+ sub_2_preview_w = 0
3206
+ if @open_level >= 1 && is_submenu_item?(@functions[@index])
3207
+ s1_acts = get_submenu_actions(@functions[@index])
3208
+ if s1_acts && !s1_acts.empty?
3209
+ s1_names = s1_acts.map { |a| extract_name_from_action(a) }
3210
+ s1_max = s1_names.empty? ? 10 : s1_names.map { |n| GRmenu.display_width(n) }.max
3211
+ s1_title = all_names[@index] || ""
3212
+ sub_1_preview_w = [s1_max + 8, GRmenu.display_width(s1_title) + 6, 20].max
3213
+ sub_1_preview_w = [sub_1_preview_w, 36].min
3214
+
3215
+ if @open_level >= 2 && is_submenu_item?(s1_acts[@sub_index_1])
3216
+ s2_acts = get_submenu_actions(s1_acts[@sub_index_1])
3217
+ if s2_acts && !s2_acts.empty?
3218
+ s2_names = s2_acts.map { |a| extract_name_from_action(a) }
3219
+ s2_max = s2_names.empty? ? 10 : s2_names.map { |n| GRmenu.display_width(n) }.max
3220
+ s2_title = extract_name_from_action(s1_acts[@sub_index_1]) || ""
3221
+ sub_2_preview_w = [s2_max + 8, GRmenu.display_width(s2_title) + 6, 20].max
3222
+ sub_2_preview_w = [sub_2_preview_w, 36].min
3223
+ end
3224
+ end
3225
+ end
3226
+ end
3227
+
3228
+ total_chain_w = total_width
3229
+ total_chain_w += 2 + sub_1_preview_w if sub_1_preview_w > 0
3230
+ total_chain_w += 2 + sub_2_preview_w if sub_2_preview_w > 0
3231
+
3232
+ margin_left = if @center && term_cols > total_chain_w
3233
+ " " * ((term_cols - total_chain_w) / 2)
3234
+ elsif @center && term_cols > total_width
3235
+ " " * ((term_cols - total_width) / 2)
3236
+ else
3237
+ ""
3238
+ end
3118
3239
 
3119
3240
  subtitle_lines_count = 0
3120
3241
  if @subtitle && !@subtitle.empty?
3121
3242
  subtitle_lines = @subtitle.lines.map(&:chomp)
3122
- div_w = @divider.is_a?(Numeric) ? @divider.to_i : [reference_width, term_cols - 2].min
3243
+ ref_sub_w = header_box_width > 0 ? header_box_width : total_chain_w
3244
+ div_w = @divider.is_a?(Numeric) ? @divider.to_i : [ref_sub_w, term_cols - 2].min
3245
+ sub_pad = (@center && term_cols > div_w) ? " " * ((term_cols - div_w) / 2) : ""
3123
3246
 
3124
3247
  if @divider
3125
- rendered_lines << colorize("─" * div_w, @style_config.divider, 0.0)
3248
+ rendered_lines << "#{sub_pad}#{colorize("─" * div_w, @style_config.divider, 0.0)}"
3126
3249
  subtitle_lines_count += 1
3127
3250
  end
3128
3251
 
3129
3252
  subtitle_lines.each_with_index do |sub_line, s_i|
3130
3253
  pad_sub = [div_w - GRmenu.display_width(sub_line), 0].max
3131
3254
  formatted_sub = @center ? (" " * (pad_sub / 2) + sub_line + " " * (pad_sub - (pad_sub / 2))) : sub_line
3132
- rendered_lines << colorize(formatted_sub, @style_config.subtitle, s_i * 0.3)
3255
+ rendered_lines << "#{sub_pad}#{colorize(formatted_sub, @style_config.subtitle, s_i * 0.3)}"
3133
3256
  subtitle_lines_count += 1
3134
3257
  end
3135
3258
 
3136
3259
  if @divider
3137
- rendered_lines << colorize("─" * div_w, @style_config.divider, 0.6)
3260
+ rendered_lines << "#{sub_pad}#{colorize("─" * div_w, @style_config.divider, 0.6)}"
3138
3261
  subtitle_lines_count += 1
3139
3262
  end
3140
3263
  rendered_lines << ""
@@ -3227,6 +3350,7 @@ class GRmenu
3227
3350
  v_left = colorize(v_l_raw, border_color_cfg, 0.2)
3228
3351
  v_right = colorize(v_r_raw, border_color_cfg, 0.8)
3229
3352
 
3353
+ main_box_start = rendered_lines.length
3230
3354
  top_border_line = box_border[:tl] + top_fill + box_border[:tr]
3231
3355
  rendered_lines << "#{margin_left}#{colorize(top_border_line, border_color_cfg, 0.0)}"
3232
3356
 
@@ -3449,9 +3573,9 @@ class GRmenu
3449
3573
  if sub_2_lines
3450
3574
  total_3_w = margin_left.length + total_width + 2 + sub_1_w + 2 + sub_2_w
3451
3575
  if total_3_w <= term_cols
3452
- sub_1_start = [[parent_row_idx - 1, 0].max, [rendered_lines.length - sub_1_lines.length, 0].max].min
3576
+ sub_1_start = main_box_start
3453
3577
  p1_abs_row = sub_1_start + (p_row_1 || 1)
3454
- sub_2_start = [[p1_abs_row - 1, 0].max, [rendered_lines.length - sub_2_lines.length, 0].max].min
3578
+ sub_2_start = main_box_start
3455
3579
  max_3_lines = [rendered_lines.length, sub_1_start + sub_1_lines.length, sub_2_start + sub_2_lines.length].max
3456
3580
 
3457
3581
  x1_start = margin_left.length + total_width + 2
@@ -3498,7 +3622,7 @@ class GRmenu
3498
3622
  rendered_lines = stitched_lines
3499
3623
  elsif (sub_1_w + 2 + sub_2_w) <= term_cols
3500
3624
  p1_abs_row = (p_row_1 || 1)
3501
- sub_2_start = [[p1_abs_row - 1, 0].max, [sub_1_lines.length - sub_2_lines.length, 0].max].min
3625
+ sub_2_start = main_box_start
3502
3626
  max_2_lines = [sub_1_lines.length, sub_2_start + sub_2_lines.length].max
3503
3627
 
3504
3628
  x1_start = margin_left.length
@@ -3538,7 +3662,7 @@ class GRmenu
3538
3662
  else
3539
3663
  total_2_w = margin_left.length + total_width + 2 + sub_1_w
3540
3664
  if total_2_w <= term_cols
3541
- sub_start_line = [[parent_row_idx - 1, 0].max, [rendered_lines.length - sub_1_lines.length, 0].max].min
3665
+ sub_start_line = main_box_start
3542
3666
  max_total_lines = [rendered_lines.length, sub_start_line + sub_1_lines.length].max
3543
3667
 
3544
3668
  x1_start = margin_left.length + total_width + 2
@@ -3620,7 +3744,8 @@ class GRmenu
3620
3744
  end
3621
3745
  end
3622
3746
 
3623
- def style(css_content)
3747
+ def style(css_content = nil)
3748
+ return @style if css_content.nil?
3624
3749
  parsed = self.class.parse_config_text(css_content)
3625
3750
  m = ((parsed[:sections] && parsed[:sections]["menu"]) || {}).merge(parsed[:global] || {})
3626
3751
  if m["style"]
@@ -3630,38 +3755,40 @@ class GRmenu
3630
3755
  @banner_style = m["banner_style"].to_i if m["banner_style"]
3631
3756
  @animate = m["animate"].to_s if m["animate"]
3632
3757
  @center = (m["center"].to_s != "false") if m.key?("center")
3633
- if m["border"] || m["border_color"]
3758
+ if (m["border"] || m["border_color"]) && !@style_config.explicitly_set?(:border)
3634
3759
  c, l = self.class.extract_color_and_level(m["border"] || m["border_color"], 1)
3635
- @style_config.border(c, l)
3760
+ @style_config.border(c, l, from_css: true)
3636
3761
  end
3637
- if m["options"] || m["options_color"]
3762
+ if (m["options"] || m["options_color"]) && !@style_config.explicitly_set?(:options)
3638
3763
  c, l = self.class.extract_color_and_level(m["options"] || m["options_color"], 1)
3639
- @style_config.options(c, l)
3764
+ @style_config.options(c, l, from_css: true)
3640
3765
  end
3641
- if m["focus"] || m["focus_color"]
3766
+ if (m["focus"] || m["focus_color"]) && !@style_config.explicitly_set?(:focus)
3642
3767
  c, l = self.class.extract_color_and_level(m["focus"] || m["focus_color"], 2)
3643
- @style_config.focus(c, l)
3768
+ @style_config.focus(c, l, from_css: true)
3644
3769
  end
3645
- if m["title"] || m["title_color"]
3770
+ if (m["title"] || m["title_color"]) && !@style_config.explicitly_set?(:title)
3646
3771
  c, l = self.class.extract_color_and_level(m["title"] || m["title_color"], 2)
3647
- @style_config.title(c, l)
3772
+ @style_config.title(c, l, from_css: true)
3648
3773
  end
3649
- if m["banner"] || m["banner_color"]
3774
+ if (m["banner"] || m["banner_color"]) && !@style_config.explicitly_set?(:banner)
3650
3775
  c, l = self.class.extract_color_and_level(m["banner"] || m["banner_color"], 2)
3651
- @style_config.banner(c, l)
3776
+ @style_config.banner(c, l, from_css: true)
3652
3777
  end
3653
- if m["subtitle"] || m["subtitle_color"]
3778
+ if (m["subtitle"] || m["subtitle_color"]) && !@style_config.explicitly_set?(:subtitle)
3654
3779
  c, l = self.class.extract_color_and_level(m["subtitle"] || m["subtitle_color"], 1)
3655
- @style_config.subtitle(c, l)
3780
+ @style_config.subtitle(c, l, from_css: true)
3656
3781
  end
3657
- if m["divider"] || m["divider_color"]
3782
+ if (m["divider"] || m["divider_color"]) && !@style_config.explicitly_set?(:divider)
3658
3783
  c, l = self.class.extract_color_and_level(m["divider"] || m["divider_color"], 1)
3659
- @style_config.divider(c, l)
3784
+ @style_config.divider(c, l, from_css: true)
3660
3785
  end
3661
- if m["desc_prefix"] || m["description_prefix"] || m["prefix"]
3662
- @style_config.desc_prefix(m["desc_prefix"] || m["description_prefix"] || m["prefix"])
3786
+ if (m["desc_prefix"] || m["description_prefix"] || m["prefix"]) && !@style_config.explicitly_set?(:desc_prefix)
3787
+ @style_config.desc_prefix(m["desc_prefix"] || m["description_prefix"] || m["prefix"], from_css: true)
3788
+ end
3789
+ if m["font"] && !@style_config.explicitly_set?(:font)
3790
+ @style_config.font(m["font"].to_i, from_css: true)
3663
3791
  end
3664
- @style_config.font(m["font"].to_i) if m["font"]
3665
3792
  @mouse = (m["mouse"].to_s == "true") if m.key?("mouse")
3666
3793
  if parsed[:sections] && parsed[:sections]["tabs"]
3667
3794
  t_sec = parsed[:sections]["tabs"]
@@ -3671,6 +3798,15 @@ class GRmenu
3671
3798
  self
3672
3799
  end
3673
3800
 
3801
+ def style=(val)
3802
+ if val.is_a?(String) && (val.include?("::") || val.include?("<<") || val.include?("@theme"))
3803
+ style(val)
3804
+ else
3805
+ @style = val.to_i
3806
+ @border_config = BORDERS[@style] || BORDERS[3]
3807
+ end
3808
+ end
3809
+
3674
3810
  def export_config(path = nil)
3675
3811
  if path.nil?
3676
3812
  caller_loc = caller_locations.find { |c| !c.path.include?(__FILE__) }
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.2
4
+ version: 4.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - grcode