A simple input control for DragonRuby.
The Multiline input is fast enough to edit Alice's Adventures in Wonderland (~170k character), but War and Peace (~3.3M characters) is over the limits. This limit doesn't appear to be related to the code, as even loading the War and Peace text file takes multiple seconds (M1 Pro Max). I have not explored where the limit is beyond a simple experiment with these two files from Project Gutenberg, but if you need to edit a reasonable sized novel, perhaps a chapter-based approach is better anyway.
Grab the latest single file release input.rb from the Releases page and save it in your DragonRuby game folder (I'm assuming in a lib directory in the sample below). As of version 0.1.0, you can call Input.download_update! on the DragonRuby console to update to the most recent version.
require 'lib/input.rb'
def tick(args)
# Create an input
args.state.input ||= Input::Text.new(x: 100, y: 600, w: 300, focussed: true)
# Allow the input to process inputs and render text (render_target)
args.state.input.tick
# Get the value
args.state.input_value = args.state.input.value
# Output the input
args.outputs.primitives << args.state.input
# Output the value
args.outputs.debug << { x: 100, y: 100, text: args.state.input_value }.label!
endSee app/main.rb for a more complex example.
Color arguments can be passed as Hashes or Arrays suffixed with _color, or individual Integer values suffixed with _r, _g, _b, _a. In all cases, if a color element is missing, the corresponding default value will be used.
For example, for the prompt you can pass:
- A
prompt_coloras aHash, like{ r: 100, g: 100, b: 100, a: 255 } - A
prompt_coloras anArray, like[100, 100, 100, 255] - A
prompt_coloras anInteger, like0xFF33BBor0xFF33BBFF - Individual
prompt_r,prompt_g,prompt_bandprompt_aIntegervalues
NOTE: For Integer (hex) rgba to work, there has to be a red component > 0. If you need red to be zero, use the Hash or Array format
The argument list below will list prompt_color but not the individual prompt_* values.
x- x location, default 0y- y location, default 0w- width, default 256h- height, default is the height of the font (as measured bycalcstringbox) + 2 * thepaddingvalue- initial input value (string), default ''padding- padding, default 2font- font path (eg.'fonts/myfont.ttf'), default ''size_enum- size enumeration (integer), or named size such as:small,:normal,:large, default::normal(0)size_px- font size in pixels, takes precedence oversize_enumif giventext_color- text color, default{ r: 0, g: 0, b: 0, a: 255 }r- text color, red component, default 0, used iftext_colorisnilg- text color, green component, default 0, used iftext_colorisnilb- text color, blue component, default 0, used iftext_colorisnila- text color, alpha component, default 255, used iftext_colorisnilprompt- prompt text - ghosted text when the control is empty, default ''prompt_r- prompt color, default{ r: 128, g: 128, b: 128, a: 255 }cursor_color- cursor color, default{ r: 0, g: 0, b: 0, a: 255 }cursor_width- cursor width, default 2background_color- background color, default nil (non-nil default components,{ r: 0, g: 0, b: 0, a: 255 })blurred_background_color- background color, defaultbackground_color(non-nil default components,{ r: 0, g: 0, b: 0, a: 255 })word_chars- characters considered to be parts of a word, default('a'..'z').to_a + ('A'..'Z').to_a + ('0'..'9').to_a + ['_', '-']punctuation_chars- charcters considered to be punctuation, default%w[! % , . ; : ' " \) ] } * &]`selection_start- start of the selection (if any) in characters (Integer), default the length of the initial valueselection_end- end of the selection (if any) and the location of the cursor in characters (Integer), defaultselection_startselection_color- selection color, default{ r: 102, g: 178, b: 255, a: 128 }blurred_selection_color- blurred selection color, default{ r: 112, g: 128, b: 144, a: 128 }key_repeat_delay- delay before function key combinations (cursor, cut/copy/paste and so on) begin to repeat in ticks (Integer), default 20key_repeat_debounce- number of ticks (Integer) between function key repeat, default 4word_wrap- if the control should wrap (Boolean), default falsereadonly- initial input read only state (Boolean), default falsefocussed- initial input focus (Boolean), default falsefocused- Alias forfocussedon_clicked- Deprecated - useon_clickon_click- on click callback, receives 2 parameters, the click and theInputcontrol instance, defaultNOOPon_unhandled_key- on unhandle key pressed callback, receives 2 parameters, the key and theInputcontrol instance, default NOOP. This callback receives keys like[tab]and[enter]as symbols, so:taband:entermax_length- maximum allowed length (Integer), defaultfalsewhich disables length checksfill_from_bottom- fill the text from the bottom, like for a log or game terminal, defaultfalsedraw_autocomplete_menu- if the input draws the autocomplete menu automatically, defaulttrue
value- The current valuevalue_changed- Returns true if the value changed in the last#tickselection_start- The start of the current selectionselection_end- The end of the current selection. This is the cursor location.lines- The value broken into individual lines (readonly,Multilineonly)content_w- The width of the full content (value) as rendered (readonly,Textonly)content_h- The height of the full content (value) as rendered (readonly,Multilineonly)rect- Returns the control's containing rect as a hash (readonly)readonly- Returns or sets the control's read only statescroll_x- The x position of the full scrollable area as renderedscroll_y- The y position of the full scrollable area as rendered. NOTE:scroll_y = 0is the bottomscroll_w- The width of the full scrollable area as rendered (readonly)scroll_h- The height of the full scrollable area as rendered (readonly)shift_lock- If Shift Lock is engaged
#insert(text)- Inserts text at the cursor location, or replaces if there's a selection#insert_at(text, start, end = start)- Inserts text at the start location, or replaces if end != start, without changing the selection#replace(text)- Alias for#insert(text)#replace_at(text, start, end = start)- Alias for#insert_at(text, start, end = start)#append(text)- Appends text the end of the value, without changing the selection#delete_forward- Deletes selection or the character to the right of the cursor location if the selection is empty (typically in response to theDeletekey)#delete_back- Deletes selection or the character to the left of the cursor location if the selection is empty (typically in response to theBackspacekey)#current_selection- Returns the currently selected text#current_selection- Returns the currently selected text#current_line- Returns the currently selected line object#current_word- Returns the word currently under the cursor#find(text)- Selects the searched for text if found#find_next- Selects the next instance of the currently selected text#find_prev- Selects the previous instance of the currently selected text#cut- Cut selection to system clipboard#copy- Copy selection to system clipboard#paste- Paste value in system clipboard#move_to_start- Move to the start of the current line#move_word_left- Move the cursor a word to the left#move_char_left- Move the cursor a character to the left#move_word_right- Move the cursor a word to the right#move_char_right- Move the cursor a character to the right#move_line_up- Move the cursor one line up (Multilineonly)#move_line_down- Move the cursor one line up (Multilineonly)#move_page_up- Move the cursor one page up (Multilineonly)#move_page_down- Move the cursor one page up (Multilineonly)#select_all- Select all#select_to_start- Select to the start of the text value#select_to_line_start- Select to the start of the current line (Multilineonly)#select_word_left- Select a word to the left#select_char_left- Select a character to the left#select_to_end- Select to the end of the text value#select_to_line_end- Select to the end of the current line (Multilineonly)#select_word_right- Select a word to the right#select_char_right- Select a character to the right#select_line_up- Select one line up (Multilineonly)#select_line_down- Select one line down (Multilineonly)#select_page_up- Select one page up (Multilineonly)#select_page_down- Select one page down (Multilineonly)#focus- Focusses the instance. Note the instance will only receive the focus after it's rendered. This prevents multiple instances from handling the keyboard and mouse events in the same tick.#blur- Removes the focus from the instance. This happens immediately and the instance will not process keyboard and some mouse events after being blurred.#focussed?- Returns true if the input is focussed, false otherwise#focused?- Alias for#focussed?#value_changed?- Returns true if the input value changed in the last tick, false otherwise
There may be cases where you want to do some custom keyboard handling, like filtering out certain characters. In order to do this, create a subclass of Input::Text or Input::Multiline and override the handle_keyboard method, calling super when your special handling is done. The following instance variables are available:
@meta- true if the Meta key is down (the Command key on a Mac, or Windows key on Windows)@alt- true if the Alt key is down@shift- true if the Shift key is down orshift_lockis set@ctrl- true if the Control key is down@down_keys- anArrayofSymbols of keys that are down excluding the special keys above@text_keys- anArrayof printable characters that has been typed this tick
class FilenameInput < Input::Text
ALLOWED_CHARS = ('a'..'z').to_a + ('A'..'Z').to_a + ('0'..'9').to_a + ['_', '-', '.']
def handle_keyboard
@text_keys.select! { |key| ALLOWED_CHARS.include?(key) }
super
end
endThis library includes the ability to replace the default DragonRuby Console (~). Simply call Input.replace_console! once to enable this.
- Adding a
background_colorsignificantly improves the rendering of the text.
The autocomplete menu is drawn by the input by default, but this might cause layering issues where the menu draw behind other elements on the screen. Setting draw_autocomplete_menu to false allows you to add the #autocomplete_menu into the outputs whereever you like.
- @danhealy for Zif. The Zif Input was the starting point for this. Though you wouldn't be able to tell now, it was a really solid place to start.
- @leviondiscord (on Discord, aka @leviongithub) for suggesting
#delete_prefixwhen I would have done something much dumber. And also providing other interesting methods I'm likely to use at some point. - @DarkGriffin (on Discord) for requesting this control in the first place, and not being shy about the crazy desired feature list (of which, I feel like, I've only touched the surface).
- @aquillo (on Discord) for asking me (and others) to review his code, where I learnt that the value returned by
keyboard.keyis thetick_countthe key was pressed which made implementing key repeat much simpler than the silly thing I would've done. - @cookie (on Discord) for reigniting my interest in building this control by asking about how to use it, finding a new, novel use for it, and pushing me to improve the sample(s).
- @kfischer_okarin (on Discord, aka @kfischer-okarin) for contributing
size_px, and fixing (or forcing me to fix) the tests. This input is used in his product Palantir which you should check out. - @pvande (on Discord and GitHub) for requesting resizing and font size changes for his own nefarious needs in a CSS-like layout system, which I have interest in (and also pointing out a left over
putsdebug)