Class: RubyRich::Layout
- Inherits:
-
Object
- Object
- RubyRich::Layout
- Defined in:
- lib/ruby_rich/layout.rb
Instance Attribute Summary collapse
-
#children ⇒ Object
Returns the value of attribute children.
-
#content ⇒ Object
Returns the value of attribute content.
-
#height ⇒ Object
Returns the value of attribute height.
-
#name ⇒ Object
Returns the value of attribute name.
-
#parent ⇒ Object
Returns the value of attribute parent.
-
#ratio ⇒ Object
Returns the value of attribute ratio.
-
#size ⇒ Object
Returns the value of attribute size.
-
#split_direction ⇒ Object
readonly
Returns the value of attribute split_direction.
-
#width ⇒ Object
Returns the value of attribute width.
-
#x_offset ⇒ Object
Returns the value of attribute x_offset.
-
#y_offset ⇒ Object
Returns the value of attribute y_offset.
Instance Method Summary collapse
- #[](name) ⇒ Object
- #calculate_dimensions(terminal_width, terminal_height) ⇒ Object
- #calculate_node_dimensions(available_width, available_height) ⇒ Object
- #draw ⇒ Object
- #find_by_name(name) ⇒ Object
-
#initialize(name: nil, ratio: 1, size: nil) ⇒ Layout
constructor
A new instance of Layout.
- #render ⇒ Object
- #render_into(buffer) ⇒ Object
- #render_to_buffer ⇒ Object
- #root ⇒ Object
- #split_column(*layouts) ⇒ Object
- #split_row(*layouts) ⇒ Object
- #update_content(content) ⇒ Object
Constructor Details
#initialize(name: nil, ratio: 1, size: nil) ⇒ Layout
Returns a new instance of Layout.
6 7 8 9 10 11 12 13 14 15 16 17 18 |
# File 'lib/ruby_rich/layout.rb', line 6 def initialize(name: nil, ratio: 1, size: nil) @name = name @ratio = ratio @size = size @children = [] @content = nil @parent = nil @x_offset = 0 @y_offset = 0 @width = nil @height = nil @split_direction = nil end |
Instance Attribute Details
#children ⇒ Object
Returns the value of attribute children.
3 4 5 |
# File 'lib/ruby_rich/layout.rb', line 3 def children @children end |
#content ⇒ Object
Returns the value of attribute content.
3 4 5 |
# File 'lib/ruby_rich/layout.rb', line 3 def content @content end |
#height ⇒ Object
Returns the value of attribute height.
3 4 5 |
# File 'lib/ruby_rich/layout.rb', line 3 def height @height end |
#name ⇒ Object
Returns the value of attribute name.
3 4 5 |
# File 'lib/ruby_rich/layout.rb', line 3 def name @name end |
#parent ⇒ Object
Returns the value of attribute parent.
3 4 5 |
# File 'lib/ruby_rich/layout.rb', line 3 def parent @parent end |
#ratio ⇒ Object
Returns the value of attribute ratio.
3 4 5 |
# File 'lib/ruby_rich/layout.rb', line 3 def ratio @ratio end |
#size ⇒ Object
Returns the value of attribute size.
3 4 5 |
# File 'lib/ruby_rich/layout.rb', line 3 def size @size end |
#split_direction ⇒ Object (readonly)
Returns the value of attribute split_direction.
4 5 6 |
# File 'lib/ruby_rich/layout.rb', line 4 def split_direction @split_direction end |
#width ⇒ Object
Returns the value of attribute width.
3 4 5 |
# File 'lib/ruby_rich/layout.rb', line 3 def width @width end |
#x_offset ⇒ Object
Returns the value of attribute x_offset.
3 4 5 |
# File 'lib/ruby_rich/layout.rb', line 3 def x_offset @x_offset end |
#y_offset ⇒ Object
Returns the value of attribute y_offset.
3 4 5 |
# File 'lib/ruby_rich/layout.rb', line 3 def y_offset @y_offset end |
Instance Method Details
#[](name) ⇒ Object
46 47 48 |
# File 'lib/ruby_rich/layout.rb', line 46 def [](name) find_by_name(name) end |
#calculate_dimensions(terminal_width, terminal_height) ⇒ Object
40 41 42 43 44 |
# File 'lib/ruby_rich/layout.rb', line 40 def calculate_dimensions(terminal_width, terminal_height) @x_offset = 0 @y_offset = 0 calculate_node_dimensions(terminal_width, terminal_height) end |
#calculate_node_dimensions(available_width, available_height) ⇒ Object
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 |
# File 'lib/ruby_rich/layout.rb', line 136 def calculate_node_dimensions(available_width, available_height) # 只在未设置宽度时计算宽度 @width ||= if @size [@size, available_width].min else available_width end # 只在未设置高度时计算高度 @height ||= if @size [@size, available_height].min else available_height end if @content.class == RubyRich::Panel @content.width = @width @content.height = @height end return if @children.empty? case @split_direction when :row remaining_width = @width fixed_children, flexible_children = @children.partition { |c| c.size } fixed_children.each do |child| child_width = [child.size, remaining_width].min child.width = child_width remaining_width -= child_width end total_ratio = flexible_children.sum(&:ratio) if total_ratio > 0 ratio_width = remaining_width.to_f / total_ratio flexible_children.each do |child| child_width = (child.ratio * ratio_width).floor child.width = child_width remaining_width -= child_width end flexible_children.last.width += remaining_width if remaining_width > 0 end @children.each { |child| child.height = @height } current_x = @x_offset @children.each do |child| child.x_offset = current_x child.y_offset = @y_offset current_x += child.width child.calculate_node_dimensions(child.width, child.height) end when :column remaining_height = @height fixed_children, flexible_children = @children.partition { |c| c.size } fixed_children.each do |child| child_height = [child.size, remaining_height].min child.height = child_height remaining_height -= child_height end total_ratio = flexible_children.sum(&:ratio) if total_ratio > 0 ratio_height = remaining_height.to_f / total_ratio flexible_children.each do |child| child_height = (child.ratio * ratio_height).floor child.height = child_height remaining_height -= child_height end flexible_children.last.height += remaining_height if remaining_height > 0 end @children.each { |child| child.width = @width } current_y = @y_offset @children.each do |child| child.x_offset = @x_offset child.y_offset = current_y current_y += child.height child.calculate_node_dimensions(child.width, child.height) end end end |
#draw ⇒ Object
74 75 76 |
# File 'lib/ruby_rich/layout.rb', line 74 def draw puts render end |
#find_by_name(name) ⇒ Object
50 51 52 53 54 55 56 57 |
# File 'lib/ruby_rich/layout.rb', line 50 def find_by_name(name) return self if @name == name @children.each do |child| result = child.find_by_name(name) return result if result end nil end |
#render ⇒ Object
59 60 61 62 |
# File 'lib/ruby_rich/layout.rb', line 59 def render # 将缓冲区转换为字符串(每行用换行符连接) render_to_buffer.map { |line| line.compact.join("") }.join("\n") end |
#render_into(buffer) ⇒ Object
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/ruby_rich/layout.rb', line 78 def render_into(buffer) children.each { |child| child.render_into(buffer) } if children return unless content content_lines = if content.is_a?(String) content.split("\n")[0...height] else content.render[0...height] end content_lines.each_with_index do |line, line_index| y_pos = y_offset + line_index next if y_pos >= buffer.size in_escape = false escape_char = "" char_width = 0 # 初始宽度调整为0,方便位置计算 line.each_char do |char| # 处理ANSI转义码 if in_escape escape_char += char in_escape = false if char == 'm' if escape_char=="\e[0m" escape_char = "" end next elsif char.ord == 27 # 检测到转义开始符\e in_escape = true escape_char += char next end # 计算字符宽度 char_w = case char.ord when 0x0000..0x007F then 1 # 英文字符 when 0x4E00..0x9FFF then 2 # 中文字符 else Unicode::DisplayWidth.of(char) end # 计算字符的起始位置 x_start = x_offset + char_width # 超出右边界则跳过 next if x_start >= buffer[y_pos].size # 处理字符渲染(中文字符可能占用多个位置) char_w.times do |i| x_pos = x_start + i break if x_pos >= buffer[y_pos].size # 超出右边界停止 unless escape_char.empty? char = escape_char + char + "\e[0m" # 每次都记录字符的实际颜色 end buffer[y_pos][x_pos] = char unless i > 0 # 中文字符仅在第一个位置写入,避免覆盖 buffer[y_pos][x_pos+1] = nil if char_w == 2 end char_width += char_w # 更新累计宽度 end end end |
#render_to_buffer ⇒ Object
64 65 66 67 68 69 70 71 72 |
# File 'lib/ruby_rich/layout.rb', line 64 def render_to_buffer # 初始化缓冲区(二维数组,每个元素代表一个字符) buffer = Array.new(@height) { Array.new(@width, " ") } # 递归填充内容到缓冲区 render_into(buffer) return buffer end |
#root ⇒ Object
20 21 22 |
# File 'lib/ruby_rich/layout.rb', line 20 def root @parent ? @parent.root : self end |
#split_column(*layouts) ⇒ Object
30 31 32 33 34 |
# File 'lib/ruby_rich/layout.rb', line 30 def split_column(*layouts) @split_direction = :column layouts.each { |l| l.parent = self } @children.concat(layouts) end |
#split_row(*layouts) ⇒ Object
24 25 26 27 28 |
# File 'lib/ruby_rich/layout.rb', line 24 def split_row(*layouts) @split_direction = :row layouts.each { |l| l.parent = self } @children.concat(layouts) end |
#update_content(content) ⇒ Object
36 37 38 |
# File 'lib/ruby_rich/layout.rb', line 36 def update_content(content) @content = content end |