Class: MittensUi::TableView

Inherits:
Core
  • Object
show all
Defined in:
lib/mittens_ui/table_view.rb

Overview

A simple, custom table widget built on Gtk::Grid.

Features:

  • Sorting with ▲ ▼ indicators

  • Row selection (mouse + keyboard)

  • Single & double click callbacks

  • Pagination for large datasets (auto-enabled > 500 rows)

  • Built-in pagination UI (Prev / Next buttons + page indicator)

  • Dark mode friendly styling

Examples:

Basic usage

table = MittensUi::TableView.new(
  ['Name', 'Email'],
  [['John', 'john@example.com']]
)

Add row

table.add(['Jane', 'jane@example.com'])

Pagination (automatic)

# Pagination UI appears automatically when data > 500 rows, unless you change it by using options hash.

Constant Summary collapse

PAGE_THRESHOLD =
500
PAGE_SIZE =
100

Instance Attribute Summary collapse

Attributes inherited from Core

#core_widget

Instance Method Summary collapse

Methods inherited from Core

#hidden?, #hide, #keyboard_shortcut, #remove, #remove_keyboard_shortcut, #render, #shortcuts, #show

Methods included from Helpers

#icon_map, #list_system_icons, #set_margin_from_opts_for

Constructor Details

#initialize(headers = [], data = [], options = {}) ⇒ TableView

Returns a new instance of TableView.



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/mittens_ui/table_view.rb', line 34

def initialize(headers = [], data = [], options = {})
  @headers = headers
  @data = data

  @row_widgets = []
  @header_labels = []
  @selected_row_idx = nil
  @sort_directions = {}
  @current_page = 0

  @page_threshold = options.fetch(:page_threshold, PAGE_THRESHOLD)
  @page_size = options.fetch(:page_size, PAGE_SIZE)

  # ---------------------------
  # GTK Structure
  # ---------------------------

  @grid = Gtk::Grid.new
  @grid.set_column_spacing(0)
  @grid.set_row_spacing(0)

  @scroller = Gtk::ScrolledWindow.new
  @scroller.set_policy(:automatic, :automatic)
  @scroller.set_child(@grid)
  @scroller.set_vexpand(true)
  @scroller.set_min_content_height(300)
  @scroller.set_max_content_height(300)

  # Pagination UI
  @pagination_box = Gtk::Box.new(:horizontal, 10)
  @pagination_box.set_margin_top(10)
  @pagination_box.set_halign(:center)

  @prev_btn = Gtk::Button.new(label: '← Prev')
  @next_btn = Gtk::Button.new(label: 'Next →')
  @page_label = Gtk::Label.new('')

  @prev_btn.signal_connect('clicked') { prev_page }
  @next_btn.signal_connect('clicked') { next_page }

  @pagination_box.append(@prev_btn)
  @pagination_box.append(@page_label)
  @pagination_box.append(@next_btn)

  # Root container (important for Core)
  @container = Gtk::Box.new(:vertical, 0)
  @container.append(@scroller)
  @container.append(@pagination_box)

  super(@container, options)

  # Events
  @on_row_clicked = nil
  @on_row_double_clicked = nil
  @last_click_time = nil
  @last_clicked_row = nil

  setup_css
  setup_keyboard

  render_headers
  render_rows
  update_pagination_ui
end

Instance Attribute Details

#dataObject (readonly)

Returns the value of attribute data.



29
30
31
# File 'lib/mittens_ui/table_view.rb', line 29

def data
  @data
end

#headersObject (readonly)

Returns the value of attribute headers.



29
30
31
# File 'lib/mittens_ui/table_view.rb', line 29

def headers
  @headers
end

#selected_row_idxObject (readonly)

Returns the value of attribute selected_row_idx.



29
30
31
# File 'lib/mittens_ui/table_view.rb', line 29

def selected_row_idx
  @selected_row_idx
end

Instance Method Details

#add(row, direction = :append) ⇒ Object


Public API




103
104
105
106
107
108
109
110
111
# File 'lib/mittens_ui/table_view.rb', line 103

def add(row, direction = :append)
  return if row.nil? || row.empty?

  direction == :prepend ? @data.unshift(row) : @data << row

  adjust_page_after_insert
  render_rows
  update_pagination_ui
end

#adjust_page_after_insertObject



178
179
180
181
182
# File 'lib/mittens_ui/table_view.rb', line 178

def adjust_page_after_insert
  return if @data.size <= @page_threshold

  @current_page = (@data.size / @page_size.to_f).floor
end

#next_pageObject



161
162
163
164
165
166
167
168
# File 'lib/mittens_ui/table_view.rb', line 161

def next_page
  return if @data.size <= @page_threshold

  max_page = (@data.size / @page_size.to_f).ceil - 1
  @current_page = [@current_page + 1, max_page].min
  render_rows
  update_pagination_ui
end

#paginated_dataObject


Pagination




154
155
156
157
158
159
# File 'lib/mittens_ui/table_view.rb', line 154

def paginated_data
  return @data if @data.size <= @page_threshold

  start = @current_page * @page_size
  @data.slice(start, @page_size) || []
end

#prev_pageObject



170
171
172
173
174
175
176
# File 'lib/mittens_ui/table_view.rb', line 170

def prev_page
  return if @data.size <= @page_threshold

  @current_page = [@current_page - 1, 0].max
  render_rows
  update_pagination_ui
end

#remove_selectedObject



132
133
134
135
136
137
138
139
140
# File 'lib/mittens_ui/table_view.rb', line 132

def remove_selected
  return nil unless @selected_row_idx

  removed = @data.delete_at(@selected_row_idx)
  @selected_row_idx = nil
  render_rows
  update_pagination_ui
  removed
end

#row_clicked(&block) ⇒ Object



142
143
144
# File 'lib/mittens_ui/table_view.rb', line 142

def row_clicked(&block)
  @on_row_clicked = block
end

#row_double_clicked(&block) ⇒ Object



146
147
148
# File 'lib/mittens_ui/table_view.rb', line 146

def row_double_clicked(&block)
  @on_row_double_clicked = block
end

#row_selected?(idx = nil) ⇒ Boolean

Returns:

  • (Boolean)


120
121
122
123
124
# File 'lib/mittens_ui/table_view.rb', line 120

def row_selected?(idx = nil)
  return !@selected_row_idx.nil? if idx.nil?

  @selected_row_idx == idx
end

#selected_rowObject



126
127
128
129
130
# File 'lib/mittens_ui/table_view.rb', line 126

def selected_row
  return nil unless @selected_row_idx

  @data[@selected_row_idx]
end

#update_data(new_data) ⇒ Object



113
114
115
116
117
118
# File 'lib/mittens_ui/table_view.rb', line 113

def update_data(new_data)
  @data = new_data
  @current_page = 0
  render_rows
  update_pagination_ui
end

#update_pagination_uiObject



184
185
186
187
188
189
190
191
192
193
194
195
196
197
# File 'lib/mittens_ui/table_view.rb', line 184

def update_pagination_ui
  if @data.size <= @page_threshold
    @pagination_box.hide
    return
  end

  total_pages = (@data.size / @page_size.to_f).ceil
  @page_label.set_label("#{@current_page + 1} / #{total_pages}")

  @prev_btn.set_sensitive(@current_page > 0)
  @next_btn.set_sensitive(@current_page < total_pages - 1)

  @pagination_box.show
end