Rubymotion: how can I define a mouseDown event for an NSView? - events

Edit: this first part has been solved
Sorry for the probably noob question, but I've searched for two days without finding an answer.
I've read the Objective-C documentation on event handling but I'm really not able to translate that to Rubymotion.
I am simply trying to define a mouseDown event on an NSView that contains a subview with an image.
Any hint?
Thanks.
New issue
EXAMPLE CODE: updated with new issue (look at the comments)
class ViewController < NSView
def loadWindow
#window = NSWindow.alloc.initWithContentRect([[400, 500], [480, 200]],
styleMask: NSTitledWindowMask|NSClosableWindowMask,
backing: NSBackingStoreBuffered,
defer: false)
#window.setTitle("Test")
#cView = ViewController.alloc.initWithFrame([[400,500], [480, 200]])
#window.setContentView(#cView)
#iView = NSImageView.alloc.initWithFrame([[100,100], [30, 30]])
#iView.setImage(NSImage.imageNamed "Icon")
#cView.addSubview(#iView)
#window.orderFrontRegardless
#window.makeKeyWindow
#var = "variable"
puts #var # This works and puts "variable"
end
def mouseDown(event)
puts "mouse click" # This puts "mouse click"
puts #var # This puts a blank line
end
end

Your answer was in the docs, but you just missed it :)
Handling a mouse down event is handled by NSView's parent class NSResponder:
https://developer.apple.com/library/mac/documentation/cocoa/reference/applicationkit/classes/NSResponder_Class/Reference/Reference.html#//apple_ref/occ/instm/NSResponder/mouseDown:
You just need to define mouseDown on your view.
class MyView < NSView
def mouseDown(event)
# what you want to do
end
end

if use the sugarcube gem, you can achieve it like this:
button = UIButton.alloc.initWithFrame([0, 0, 10, 10])
button.on(:touch) { my_code }
button.on(:touch_up_outside, :touch_cancel) { |event|
puts event.inspect
# my_code...
}
# remove handlers
button.off(:touch, :touch_up_outside, :touch_cancel)
button.off(:all)
detail: https://github.com/rubymotion/sugarcube

Related

Cannot print a text with Gosu in Ruby

Im sitting here with what I think is a very simple bug I just can not figure out.. Im trying to learn how to make games with Gosu gem with Ruby, but have hit a speed bump. Here is my code.
require "gosu"
class Hello < Gosu::Window
def initialize width = 800, height = 600, fullscreen = false
super
self.caption = "Ruby Practise"
#image = Gosu::Image.from_text self. "My text to print".
Gosu.default_font_name.
100
end
def button_down id
close if id == Gosu::KbEscape
end
def update
end
def draw
#image.draw 0, 0, 0
end
end
Hello.new.show
There is something wrong but I do not know what. I have spent at least 1 hour on it.. It complains on the String, here is the output from terminal.
hello.rb:8: syntax error, unexpected tSTRING_BEG
#image = Gosu::Image.from_text self. "My text to print".
^
hello.rb:10: syntax error, unexpected tINTEGER
I do not what I am doing wrong, do some one know? It is probably something really simple..
Use commas to separate function arguments, not dots:
#image = Gosu::Image.from_text self, "My text to print",
Gosu.default_font_name,
100

Ruby GTK Pixbuf timed image change

I am creating an image slideshow in ruby, using gtk pixbuf to load images. I am very new to ruby & GTK, this may be an stupid question.
Currently image changes are linked to the GUI button_press_event, I would like them to change /refresh automatically based on a set time, like a slideshow or animation. I saw the gtk animation using a gif method, but I would like to use individual jpeg files inline sequence, so that I can set the time to show a slide. Once the loop has gone through all the images, the GUI should display buttons for replay or quit. ( I haven't used #time yet, it is just there for possibilities ) Thanks for any suggestions;
require 'gtk2'
class Pics
attr_accessor :pile, :picindex, :imgLoaded, :image, :box, :window, :time
def initialize
#window = Gtk::Window.new()
#window.signal_connect("destroy"){Gtk.main_quit}
pic1 = "1.jpg"
pic2 = "2.jpg"
pic3 = "3.jpg"
pic4 = "4.jpg"
#pile = [pic1, pic2, pic3, pic4]
#picindex = 0
self.getImage
#box = Gtk::EventBox.new.add(#image)
#time = true
end
def nuImage
#box.remove(#image)
#picindex = #picindex + 1
#picindex = 0 if #picindex == #pile.length
self.getImage
#box.add(#image)
#box.show
end
def getImage
#imgLoaded = #pile[#picindex]
img = Gdk::Pixbuf.new(#imgLoaded, 556, 900)
#image = Gtk::Image.new(img)
#image.show
end
end # class Pics
pics = Pics.new
pics.box.signal_connect("button_press_event"){pics.nuImage}
pics.window.set_default_size(556, 900)
pics.window.add(pics.box)
pics.window.show_all
Gtk.main
use GLib.timeout_add () or GLib.timeout_add_seconds (). Return False if you don't want to use it anymore.read GLib documentation, Section: Main Event Loop
This is a solution:
def start_button__clicked(but)
#thread = Thread.new {
loop do
next_button__clicked
sleep(2)
end
end
def stop_button__clicked(but)
#thread.kill
end
This is how I would do it in visual ruby. Its basically the same.
You'd just have a form with a button named "start_button" and "stop_button" etc.
the following code is an implementation:
GLib::Timeout.add(1000) do
pics.nuImage if pics.time
true
end
pics.window.signal_connect("key_press_event") do |_window, event|
case event.keyval
when Gdk::Keyval::GDK_KEY_space
pics.time = !pics.time
end
end
more details:
http://ruby-gnome2.sourceforge.jp/hiki.cgi?GLib%3A%3ATimeout

RubyMotion - Styling NSTableCellView with Teacup

I'm beginning with Rubymotion development, and I'm creating my first NSTableView with custom cells.
The following code is working, but I cannot manage to see how I should declare the NSTableCellView with Teacup layout (in order to move frame size in my stylesheet)
def tableView(table_view, viewForTableColumn: column, row: row_index)
cell_identifier = 'cell_id'
cell = table_view.makeViewWithIdentifier(cell_identifier, owner: self)
unless cell
cell = NSTableCellView.alloc.initWithFrame(CGRectMake(0, 0, table_view.bounds.size.width, rowHeight))
cell.identifier = cell_identifier
layout(cell) do
subview(NSTextField, :cell_text)
end
end
cell.subviews[0].stringValue = "value for #{row_index}"
cell
end
I already tried this code but it's not working:
def tableView(table_view, viewForTableColumn: column, row: row_index)
cell_identifier = 'cell_id'
#cell = table_view.makeViewWithIdentifier(cell_identifier, owner: self)
unless #cell
layout(nil, :root) do
#cell = subview(NSTableCellView, :cell_view) do |cell|
cell.identifier = cell_identifier
subview(NSTextField, :cell_text)
end
end
end
#cell.subviews[0].stringValue = "value for #{row_index}"
#cell
end
Thanks for your help
It should work if you assign the stylesheet and call reapply!
cell.stylesheet = :stylesheet
cell.reapply!

Refreshing a view in Gtk3-Ruby

I'm having a problem changing a view in my feed reader. When a button in the feed list is clicked, the feed window is supposed to update. Instead, the feed window stays empty. How do you remove and replace a widget in gtk3-ruby?
The problem method:
def feed=(feed)
#feed.destroy()
#title, #count = feed.channel.title, feed.items.size
#label.set_markup "<b>#{#title} (#{#count} articles)</b>"
#feed = FeedItems.new(feed.items, #parent)
self.pack_end(#feed)
#feed.show()
end
The full source is on pastebin:
http://pastebin.com/KPKAfCmx
I should have used show_all and the widget updates.
def feed=(feed)
self.remove(#feed)
#title, #count = feed.channel.title, feed.items.size
#label.set_markup "<b>#{#title} (#{#count} articles)</b>"
#feed = FeedItems.new(feed.items, #parent)
self.pack_end(#feed)
self.show_all
end

Ruby setter idiom

I'm working on a Chart class and it has a margin parameter, that holds :top, :bottom, :right and :left values. My first option was to make margin a setter and set values like this:
# Sets :left and :right margins and doesn't alter :top and :bottom
chart.margins = {:left => 10, :right => 15}
It's nice, because it is clearly a setter, but, after some thought, I think it could be confusing too: the user might think that margins contains only :left and :right values, what is not right. Another option is eliminate = and make it an ordinary method:
chart.margins(:left => 10, :right => 15)
With this syntax, it's easy to figure out what is happening, but it is not a standard setter and conflicts with margins getter. And there's still another option:
chart.margins(:left, 10)
chart.margins(:right, 15)
I don't know what to think about this. For me, it is obvious the method is a setter, but this time I cannot set multiple values with just one call and there's the problem with getter again. I'm relatively new to Ruby and I haven't got used to all the idioms yet. So, what do you think guys? Which is the best option?
You could also make a Margin class to enjoy the following clear syntax:
class Margin
attr_accessor :left, :right, :top, :bottom
...
end
class Chart
attr_accessor :margins
...
end
chart.margins.left = 10
puts chart.margins.right
Not so sure if this is the kind of syntax that you would like to make available (sorry if not : )
#!/usr/bin/ruby
class Margins < Struct.new(:top, :bottom, :left, :right)
end
class Chart
attr_reader :margins
def initialize()
#margins = Margins.new(0,0,0,0)
end
def margins=(hash)
[:top, :bottom, :left, :right].each do |dir|
if (hash[dir])
#margins[dir] = hash[dir]
end
end
end
end
c = Chart.new
c.margins.left = 10
c.margins={:top=>12,:bottom=>13}
puts c.margins.left
# 10
puts c.inspect;
# #<Chart:0xb7caaf8c #margins=#<struct Margins top=12, bottom=13, left=10, right=0>>
# However c.margins.foo = 12 would give you an error
In addition to paradigmatic's answer, you could add a method to the Margins class to support:
chart.margins.set :left => 10, :right => 15
You could extend the margins= method to treat a numeric argument:
chart.margins = 20
as sugar for:
chart.margins = Margins.new(20, 20, 20, 20)
I don't think creating a class for Margin is an overkill. You can always expose its values as a hash using to_hash or something similar.
Also, if you like, you can make it work in DSL-style:
chart.margins do |m|
m.left 10
m.right 20
m.vertical 5 # sets both top and bottom margin
end
But I guess I would choose paradigmatic's approach anyway...
You could also stick with what you had first and use the normal hash syntax.
margins["left"] = 10 #to set just one without changing the others

Resources