Skip to content
DSL for make a simple ruby GUI application
HTML Ruby Batchfile
Find file
Latest commit 6f92a29 @glurp update
Failed to load latest commit information.
bin creation
lib dialog validation
media creation
samples creation
spec do not test editor() if travis running
tmp creation
.travis.yml supress gstreamer dependency
CHANGELOG.txt update
Gemfile remove rspec simplevov dependency
LICENSE.html update txt
README.md update
Rakefile.rb project name diff of directory name
Ruiby.gemspec dempend on gtk3 3.0.5
VERSION update
doc.html update
gitc.bat ceation

README.md

Ruiby

Build Status Gem Version

A DSL for building simple GUI ruby application. Based on gtk.

Resources

Code: http://github.com/glurp/Ruiby

Doc: Reference+Exemples.

Gem : https://rubygems.org/gems/Ruiby

Status

NEW : 3.9.0!! 04-02-2016 : bugs corrections in combo, dialog

TODO :

  • Gadget api: actual gadgets are cairo drawing => to be encapsuled
  • refactor samples demos with last improve: dynvar/autoslot...
  • resolve 100% gtk3 deprecated warning
  • corrections in ruiby_require(?)
  • complete treeview and tree_grid,
  • complete rspec => 99% coverage ?

Installation

1) system

Install Ruby 2.x

2) install Ruiby (Ruiby install ruby-gtk3 which install gtk3 libs)

> gem install Ruiby

> ruiby_demo             # check good installation with gtk3 (default)
> ruiby_sketchi          # write and test ruiby code

3) if you need video/gstreamer, install gst/clutter :

  > gem install gstreamer
  > gem install clutter-gtk
  > gem install clutter-gstreamer

Here a working gem config on windows (15-September-2014, ruby 2.0.0p0) :

 pkg-config  1.1.4
       cairo 1.12.8
      glib2  2.2.0
 gobject-introspection  2.2.0
       gio2  2.2.0
        atk  2.2.0
      pango  2.2.0
 gdk_pixbuf2  2.2.0
       gdk3  2.2.0
       gtk3  2.2.0
  gstreamer  2.2.0
 cairo-gobject  2.2.0
    clutter  2.2.0
clutter-gtk  2.2.0
 clutter-gstreamer  2.2.0

Usage

DSL is usable via inherit, include, Ruiby.app bloc, or one-liner command.

By inherit:

class Application < Ruiby_gtk
    def initialize(t,w,h)
        super(t,w,h)
    end
    def component()
      stack do
        ...
      end
    end
    .....your code....
end
Ruiby.start { Win.new("application title",350,10) }

By include, calling ruiby_component() :

class Win < Gtk::Window
    include Ruiby
    def initialize(t,w,h)
        super()
        add(@vb=VBox.new(false, 2))
        ....
    end
    def add_a_ruiby_button()
        ruiby_component do
            append_to(@vb) do
                button("Hello Word #{@vb.children.size}") {
                    add_a_ruiby_button()
                }
            end
        end
    end
end
Ruiby.start { Win.new("application title",350,10) }

Autonomous DSL, for little application :

require  'Ruiby'
Ruiby.app do
    stack do
        . . .
    end
end

And, for very little application ('~' are replaced by guillemet):

> ruiby   button(~Continue ? ~) "{  exit!(0) }"
> ruiby   fields([%w{a b},%w{b c},%w{c d}]) { "|a,b,c|" p [a,b,c] if a; exit!(a ?0:1) }
> ruiby -width 100  -height 300 -title "Please, select a file" \
             l=list(~Files :~);l.set_data Dir.glob(~*~) ;  \
             buttoni(~Selected~) { puts l.selection ; exit!(0) } ;\
             buttoni(~Annul~) { exit!(1) }

Require

Simple usage with gtk3 :

require 'Ruiby'

Usage with Event Machine: preload event-machine before Ruiby :

require 'em-proxy'
require 'Ruiby'

Warning : EM.run is done when starting mainloop, after creation of window(s). So, if you need initialization of event-machine callback, do it in component(), in a after(0):

Ruiby.app do
  ....
  after(0) { EventMachine::start_server().. { ... } }
end

See samples/spygui.rb, for exemple of gui with EM.

Threading

Ruiby does not have confidence in gtk multi threading, so all Ruiby commands must be done in main thread context. A Ruiby delegate is provided in Kernel module for support multi-threading

A Queue is polled by main-window thread :

  • main window poll Queue , messagers are proc to be instance_eval() in the main window context
  • everywere, a thread can invoke invoke_gui {ruiby code}. this send to the main queue the proc, which will be evaluated asynchroniously

instance_eval is avoided in ruiby. He is used only for thread invoker : gui_invoke().

require_relative '../lib/Ruiby'
class App < Ruiby_gtk
    def initialize
        super("Testing Ruiby for Threading",150,0)
        threader(10)
        Thread.new { A.new.run }
    end
    def component()
      stack do
        sloti(label("Hello, this is Thread test !"))
        stack { @lab=stacki { } }
      end
    end # endcomponent

end
class A
    def run
        loop do
            sleep(1) # thread...
            there=self
            gui_invoke { append_to(@lab) { sloti(
                    label( there.aaa )  # ! instance_eval on main window
            )  } }
        end
    end
    def aaa() Time.now.to_s  end
end

Ruiby.start { App.new }

Observed Object/Variable

Dynamic variable

Often, a widget (an entry, a label, a slider...) show the value of a ruby variable. each time a code mofify this variable, it must modify the widget, and vice-versa... This is very tyring :)

With data binding, this notifications are done by the framework

So DynVar can be used for representing a value variable which is dynamics, ie. which must notify widgets which show the variable state.

So we can do :

  foo=DynVar.new(0)
  entry(foo)
  islider(foo)
  ....
  foo.value=43  
  ....

That works ! the entry and the slider will be updated.

A move on slider will update foo.value and the entry. Idem for a key in the entry : slider and foo.value will be updated.

if you want to be notified for your own traitment, you can observ a DynVar :

  foo.observ { |v| @socket.puts(v.to_s) rescue nil }

Here, a modification of foo variable will be send on the network...

Warning !! the block will always be executed in the main thread context (mainloop gtk context). So DynVar is a ressource internal to Ruiby framework.

Widget which accept DynVar are : entry, ientry, islider, label, check_button,

must be extend to button, togglebutton, combo, radio_button ... list, grid,...

Dynamic Object

Often, this kind of Dyn variables are members of a 'record', which should be organised by an Ruby Object (a Struct...)

So DynObject create a class, which is organised by a hash :

  • packet of variable name
  • put initial value for each
  • each variable will be a DynVar
  FooClass=make_DynClass("v1" => 1 , "v2" => 2, "s1" => 'Hello...')
  foo=FooClass.new( "s1" => Time.now.to_s ) # default value of s1 variable is replaced
  ...
  label(" foo: ") ; entry(foo.s1)
  islider(foo.v1)
  islider(foo.v2)
  ....
  button("4x33") { Thread.new { foo.s1.value="s4e33" ; foo.v2.value=33 ; foo.v1.value=4} }
  ....

Dynamic Stock Object

DynObject can be persisted to filesystem : use make_StockDynObject, and instantiate with an object persistant ID

  FooClass=make_StockDynClass("v1"=> 1 , "v2" => 2, "s1" => 'Hello...')
  foo1=FooClass.new( "foo1" , "s1" => Time.now.to_s )
  foo2=FooClass.new( "foo2" , "s1" => (Time.now+10).to_s )
  ....
  button("Exit") { ruiby_exit} # on exit, foo1 and foo2 will been saved to {tmpdir}/<$0>.storage  
  ....

make_StockDynObject do both : Class creation and class instanciation.

  foo=make_StockDynObject("v1"=> 1 , "v2" => 2, "s1" => 'Hello...')
  ....
  button(foo.s1) { foo.s1.value= prompt("new S1 value ?")}
  button("Exit") { ruiby_exit} # on exit, foo1 and foo2 will been saved to {tmpdir}/<$0>.storage  
  ....

License

LGPL, CC BY-SA

Exemples

see samples in "./samples" directory (run all.rb) cd sampSee at end of Doc reference : Ex.

Something went wrong with that request. Please try again.