Module: Clogs::Editable
Overview
Shared single/multi-line text editing.
This is a deliberately small editor: caret, selection, the usual navigation keys, and clipboard via Clipboard. libui offers no way to embed its own entry widget in an area, so there is nothing to delegate to.
Instance Attribute Summary collapse
-
#anchor ⇒ Object
readonly
Returns the value of attribute anchor.
-
#caret ⇒ Object
readonly
Returns the value of attribute caret.
Instance Method Summary collapse
- #caret_line_offset(direction) ⇒ Object
- #delete_selection ⇒ Object
- #editable_init ⇒ Object
- #focus_gained ⇒ Object
- #focus_lost ⇒ Object
- #focusable? ⇒ Boolean
- #handle_char(event) ⇒ Object
- #handle_ctrl(event) ⇒ Object
- #insert(str) ⇒ Object
- #line_end(pos) ⇒ Object
- #line_start(pos) ⇒ Object
- #move_caret(pos, extend_selection) ⇒ Object
- #multiline? ⇒ Boolean
- #on_key(event) ⇒ Object
- #selection_range ⇒ Object
- #text_value ⇒ Object
- #text_value=(new_text) ⇒ Object
Instance Attribute Details
#anchor ⇒ Object (readonly)
Returns the value of attribute anchor.
183 184 185 |
# File 'lib/clogs/drawables/controls.rb', line 183 def anchor @anchor end |
#caret ⇒ Object (readonly)
Returns the value of attribute caret.
183 184 185 |
# File 'lib/clogs/drawables/controls.rb', line 183 def caret @caret end |
Instance Method Details
#caret_line_offset(direction) ⇒ Object
333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 |
# File 'lib/clogs/drawables/controls.rb', line 333 def caret_line_offset(direction) return @caret unless multiline? column = @caret - line_start(@caret) if direction.negative? prev_end = line_start(@caret) - 1 return @caret if prev_end.negative? prev_start = line_start(prev_end) [prev_start + column, prev_end].min else next_start = line_end(@caret) + 1 return @caret if next_start > text_value.length [next_start + column, line_end(next_start)].min end end |
#delete_selection ⇒ Object
220 221 222 223 224 225 226 227 228 229 |
# File 'lib/clogs/drawables/controls.rb', line 220 def delete_selection range = selection_range return false unless range from, to = range self.text_value = text_value.dup.tap { |t| t[from...to] = "" } @caret = from @anchor = nil true end |
#editable_init ⇒ Object
185 186 187 188 189 190 |
# File 'lib/clogs/drawables/controls.rb', line 185 def editable_init @caret = text_value.length @anchor = nil @scroll_x = 0 @scroll_y = 0 end |
#focus_gained ⇒ Object
205 206 207 |
# File 'lib/clogs/drawables/controls.rb', line 205 def focus_gained redraw! end |
#focus_lost ⇒ Object
209 210 211 212 |
# File 'lib/clogs/drawables/controls.rb', line 209 def focus_lost @anchor = nil redraw! end |
#focusable? ⇒ Boolean
201 202 203 |
# File 'lib/clogs/drawables/controls.rb', line 201 def focusable? true end |
#handle_char(event) ⇒ Object
266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 |
# File 'lib/clogs/drawables/controls.rb', line 266 def handle_char(event) char = event.char return false unless char case char when "\b", "\x7F" unless delete_selection if @caret.positive? t = text_value.dup t[@caret - 1] = "" self.text_value = t @caret -= 1 end end when "\r", "\n" return false unless multiline? insert("\n") when "\t" return false else return false if char.ord < 32 insert(char) end redraw! true end |
#handle_ctrl(event) ⇒ Object
295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 |
# File 'lib/clogs/drawables/controls.rb', line 295 def handle_ctrl(event) case event.char when "a", "\x01" @anchor = 0 @caret = text_value.length when "c", "\x03" range = selection_range Clipboard.write(text_value[range[0]...range[1]]) if range when "x", "\x18" range = selection_range if range Clipboard.write(text_value[range[0]...range[1]]) delete_selection end when "v", "\x16" text = Clipboard.read insert(text) if text && !text.empty? else return false end redraw! true end |
#insert(str) ⇒ Object
231 232 233 234 235 236 237 |
# File 'lib/clogs/drawables/controls.rb', line 231 def insert(str) delete_selection t = text_value.dup t.insert(@caret, str) self.text_value = t @caret += str.length end |
#line_end(pos) ⇒ Object
329 330 331 |
# File 'lib/clogs/drawables/controls.rb', line 329 def line_end(pos) text_value.index("\n", pos) || text_value.length end |
#line_start(pos) ⇒ Object
325 326 327 |
# File 'lib/clogs/drawables/controls.rb', line 325 def line_start(pos) (text_value.rindex("\n", [pos - 1, 0].max) || -1) + 1 end |
#move_caret(pos, extend_selection) ⇒ Object
319 320 321 322 323 |
# File 'lib/clogs/drawables/controls.rb', line 319 def move_caret(pos, extend_selection) @anchor = @caret if extend_selection && @anchor.nil? @anchor = nil unless extend_selection @caret = pos.clamp(0, text_value.length) end |
#multiline? ⇒ Boolean
351 352 353 |
# File 'lib/clogs/drawables/controls.rb', line 351 def multiline? false end |
#on_key(event) ⇒ Object
239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 |
# File 'lib/clogs/drawables/controls.rb', line 239 def on_key(event) return false if event.up if event.ctrl? return handle_ctrl(event) end case event.ext when :left then move_caret(@caret - 1, event.shift?) when :right then move_caret(@caret + 1, event.shift?) when :home then move_caret(line_start(@caret), event.shift?) when :end then move_caret(line_end(@caret), event.shift?) when :up then move_caret(caret_line_offset(-1), event.shift?) when :down then move_caret(caret_line_offset(1), event.shift?) when :delete unless delete_selection t = text_value.dup t[@caret] = "" if @caret < t.length self.text_value = t end else return handle_char(event) end redraw! true end |
#selection_range ⇒ Object
214 215 216 217 218 |
# File 'lib/clogs/drawables/controls.rb', line 214 def selection_range return nil if @anchor.nil? || @anchor == @caret [[@anchor, @caret].min, [@anchor, @caret].max] end |
#text_value ⇒ Object
192 193 194 |
# File 'lib/clogs/drawables/controls.rb', line 192 def text_value style(:text).to_s end |
#text_value=(new_text) ⇒ Object
196 197 198 199 |
# File 'lib/clogs/drawables/controls.rb', line 196 def text_value=(new_text) @styles["text"] = new_text notify("change", new_text) end |