How to position editbox's cursor in shoes? - ruby

Shoes is very handy GUI tool. I would like to do a search form so that a user is helped to navigate through larger texts for editing. For this I need to move the cursor within an editbox element.
Here you'll see my question in code:
Shoes.app do
stack do
p=para "After pressing 'search' a question will arise"
box=edit_box
box.text="One\nof\nthe\nmost\nstriking\ndifferences\nbetween\na\ncat\nand\na\nlie\nis\nthat\na\ncat\nhas\nonly\nnine lives."
flow :margin_top=>0.1 do
search=edit_line
button("search") do
pos=box.text.index search.text
y = box.text[0..pos].split.size-1 if pos
if not y.nil?
#For example if you searched "only" then
#cursor should jump/scroll to line 17.
#
#Anything there for cursor positioning,
#like: box.cursor=[0,y]
#
p.text="How can I move editbox's cursor in line #{y+1}?"
else
alert "'#{search.text}' not found"
end
end
end
end
end
Is there is any way to change cursor's position of an editbox? If not, do you know an alternative way of implementation?

Unfortunately, Shoes doesn't seem to provide any way to do that. These are the only methods defined on EditBox (it inherits from Native, which has several methods, but again, none to reposition the cursor).
rb_define_method(cEditBox, "text", CASTHOOK(shoes_edit_box_get_text), 0);
rb_define_method(cEditBox, "text=", CASTHOOK(shoes_edit_box_set_text), 1);
rb_define_method(cEditBox, "draw", CASTHOOK(shoes_edit_box_draw), 2);
rb_define_method(cEditBox, "change", CASTHOOK(shoes_control_change), -1);
http://github.com/why/shoes/blob/cea39a8bf9a5b7057b1824a9fab868d1f8609d69/shoes/ruby.c

Related

How do you update and change an object in ruby 2D?

I have a text object in ruby 2D showing score. How do I update the text?
I have this so far
update do
text = Text.new("Score: #{#score}")
end
Instead of replacing it, it is creating a new text object on top of it. How could you replace it instead of adding it on?
Based on docs it seems like you need to instantiate the Text object outside of the update loop. This will draw it to the screen "forever" until you call the remove method.
In your current code you are just instantiating a new object every time, and Ruby 2D is secretly keeping it around even though you don't have it assigned to a variable.
Unlike some other 2D libraries like Gosu, Ruby 2D does not stop drawing something until you explicitly tell it to.
Try
#text = Text.new("Score: #{#score}")
update do
...
#text.remove # At a time you want to stop displaying that text.
...
end
Adding and removing objects in Ruby 2D
here a simple example how to use the Text class in ruby2d
require 'ruby2d'
sector = 3
txt = Text.new(
sector.to_s,
x: 10, y: 10,
size: 20,
color: 'white',
z: 10
)
on :key_down do |event|
case event.key
when 'a'
sector += 1
txt.text = sector.to_s
when 's'
sector -= 1
txt.text = sector.to_s
end
end
show

scrollable window ncurses ruby

I created a class that I am trying to make to simulate richtextbox, sort of, on windows forms. this means when you add new data to the form/richtextbox it is added to the bottom of the box/window and the rest is scrolled up one line.
ive tried to enable scrollok(), but it does not seem to want to scroll. i am not sure if it's bugged or my way of implementing it is wrong.
class Textpad
attr_accessor :data, :name, :window
def initialize(name, height, width, startx, starty)
#data = []
#name = name
#height = height
#width = width
#startx = startx
#starty = starty
Ncurses.refresh
#window = Ncurses.newwin(height, width, starty, startx)
#window.scrollok true
#window.wrefresh
end
def add(packetid, username, message)
#data.push [Time.new.strftime('[%T]'), packetid, username, message]
#data.shift if #data.length > 500
end
def draw
Ncurses.init_pair(1, Ncurses::COLOR_YELLOW, Ncurses::COLOR_BLACK)
Ncurses.init_pair(2, Ncurses::COLOR_CYAN, Ncurses::COLOR_BLACK)
Ncurses.init_pair(3, Ncurses::COLOR_RED, Ncurses::COLOR_BLACK)
Ncurses.init_pair(4, Ncurses::COLOR_WHITE, Ncurses::COLOR_BLACK)
#window.wclear
position = 0
#data.each do |timestamp, packetid, username, message|
case packetid
when '1005'
#window.mvwprintw(1*position, 1, "#{timestamp} «#{username}» #{message}")
#window.mvchgat(1*position, timestamp.length+2, 1, Ncurses::A_NORMAL, 3, NIL)
#window.mvchgat(1*position, timestamp.length+3+username.length, 1, Ncurses::A_NORMAL, 3, NIL) #colorize the symboles around the username
end
position += 1
end
#window.wrefresh
end
end
the problem would be inside my draw method of the Textpad class. i can fill the data array for the Textpad class with hundreds of entries but only the very top of the array gets written (until it reaches the bottom of the window) with no scrolling. Do i manually have to scroll the screen or something? from the documentation it says it should automatically scroll when the cursor reaches the bottom and another line is added.
To quote the man page:
The scrollok option controls what happens when the cursor of a window is moved off the edge of the window or scrolling region, either as a result of a newline action on the bottom line, or typing the last character of the last line. If disabled, (bf is FALSE), the cursor is left on the bottom line. If enabled, (bf is TRUE), the window is scrolled up one line...
What is happening in your code is that you are attempting to print outside the window which is an error, but an error that curses handles by not printing anything.
You can either print an new line when you get to the bottom of the window or once your reach the bottom of the window you can call #window.scroll.
Either way you will need to keep printing on the last line if you are explicitly setting the position.

How do I get the line of text under the cursor in a TextView in gtk#?

I have a GTK# TextView and I want to read the line of text under the cursor. I don't see a single method that will do that, so I think I need to combine several method calls, like Buffer.GetText, Buffer.GetIterAtOffset, Buffer.CursorPosition, but it's not obvious to me what the right combination is.
TextIter are a bit odd to use. Buffer.CursorPosition gives you the current position.
It's easy to find the end of the line:
var end = Buffer.CursorPosition;
end.ForwardToLineEnd();
To get the first character, there's not symetrical method, so you might try:
var start = Buffer.CursorPosition;
start.BackwardChars(start.LineOffset); // LineOffset gives you the iter offset on the current line.

How to create a walking animation in LOVE 2D

So I was wondering how to change an image of character I've created depending on the key I've pressed/am pressing?
My ultimate going to to have a walking animation occuring when "d" (or any of the wasd keys) is pressed but then he stands still when the "d" key has just been pressed etc. All images have been created already.
I've tried this but it didn't work out:
function love.load()
if love.keyboard.isDown("a") then
hero = love.graphics.newImage("/hero/11.png")
elseif love.keyboard.isDown("d") then
hero = love.graphics.newImage("/hero/5.png")
elseif love.keyboard.isDown("s") then
hero = love.graphics.newImage("/hero/fstand.png")
elseif love.keyboard.isDown("w") then
hero = love.graphics.newImage("/hero/1.png")
end
function love.draw()
love.graphics.draw(background)
love.graphics.draw(hero, x, y)
end
You must understand how LÖVE works. It (very basically) does this:
love.load() -- invoke love.load just once, at the beginning
while true do -- loop that repeats the following "forever" (until game ends)
love.update(dt) -- call love.update()
love.draw() -- call love.draw()
end
This schema is so frequent that the loop itself has a name - it's called The Game Loop.
Your code does't work because you are using love.load() as if it was part of the game loop, but it isn't. It's called at the beginning, during the first millisecond or so of your program, and never again.
You want to use love.load do load the images, and love.update to change them:
function love.load()
heroLeft = love.graphics.newImage("/hero/11.png")
heroRight = love.graphics.newImage("/hero/5.png")
heroDown = love.graphics.newImage("/hero/fstand.png")
heroUp = love.graphics.newImage("/hero/1.png")
hero = heroLeft -- the player starts looking to the left
end
function love.update(dt)
if love.keyboard.isDown("a") then
hero = heroLeft
elseif love.keyboard.isDown("d") then
hero = heroRight
elseif love.keyboard.isDown("s") then
hero = heroDown
elseif love.keyboard.isDown("w") then
hero = heroUp
end
end
function love.draw()
love.graphics.draw(background)
love.graphics.draw(hero, x, y)
end
The code above has certain repetitiveness that can be factored out using tables, but I've left it simple on purpose.
You will also notice that I have included the dt parameter in the love.update function. This is important, since you will need it to make sure that animations work the same in all computers (the speed at which love.update is called depends on each computer, and dt allows you to cope with that)
Nevertheless, if you want to do animations, you will probably want to use this Animation Lib or my own.

MATLAB: Modify getline() to remove 'end input on double-click' functionality

The matlab function getline (image processing toolbox) returns the position of a polyline (which has previously been defined with the cursor) either on a double-click or on pressing the return key or spacebar.
Due to my butter-fingers and accidentally double-clicking I want to remove the ability to end on a double-click.
What part do I need to change, or what functions should I be looking out for, I can't find out how a double click is even defined in matlab.
Cheers!
MATLAB associates "callback" functions with graphics objects, which define what to do when the mouse is clicked, keys are pressed, etc.. In getline(), the section to look at is the NextButtonDown() subfunction. This is the callback that is associated with subsequent mouse presses after the first mouse press to initiate the line. The key is that is checks the SelectionType figure property, which will be open for a double click. When that is the case, it closes the figure. So, to disable that functionality, just remove the extra case and checking logic. Here is the diff for my r2009b version:
306,310d305
< selectionType = get(GETLINE_FIG, 'SelectionType');
< if (~strcmp(selectionType, 'open'))
< % We don't want to add a point on the second click
< % of a double-click
<
322,328d316
<
< end
<
< if (~strcmp(get(GETLINE_FIG, 'SelectionType'), 'normal'))
< % We're done!
< set(GETLINE_H1, 'UserData', 'Completed');
< end
The answer provided by #JohnColby solves your problem by editing the GETLINE.m function file. Basically you comment out every line that check if a double-click was performed. This information is obtained by querying the 'SelectionType' figure property.
Alternatively, if you are like me and you hate making changes to built-in functions, then consider the following solution that doesn't involve changing any existing functions. Here is an example of how we use it:
h = addlistener(handle(gcf), 'WindowButtonDownFcn', 'PostSet', #changedWBDFcn);
[x,y] = getline();
delete(h)
plot(x,y, 'Color','r')
The idea is to create an event listener that gets triggered when the 'WindowButtonDownFcn' figure property changes. We use it to insert a function that gets called just before the previously set callback function (actually we replace the callback with our own function that calls the old one at the end).
This allows us to insert a section that checks if the call was triggered by a double-click, and simply skip such event.
This had to be done twice, because GETLINE first calls FirstButtonDown on first click, which sets NextButtonDown to be called on subsequent clicks, thus the use of the flag variable to differentiate between the two cases.
The code for the above event listener function:
function changedWBDFcn(src,ev,flag)
hFig = ev.AffectedObject; %# figure handle
currFcn = ev.NewValue; %# current callback function
delete(src); %# delete event listener
if nargin < 3, flag = false; end %# determine flag
%# hijack WindowButtonDownFcn function
set(hFig, 'WindowButtonDownFcn',{#wbdFcn,currFcn,flag})
%# callback function
function wbdFcn(o,e,currFcn,flag)
%# skip anything but single-clicks
if ~strcmpi(get(hFig,'SelectionType'),'normal')
return
end
%# evaluate previous callback function
hgfeval(currFcn) %# getline('FirstButtonDown'),getline('NextButtonDown')
%# repeat process after first click
if flag
addlistener(handle(hFig), 'WindowButtonDownFcn', ...
'PostSet', {#changedWBDFcn,true});
end
end
end

Resources