{"id":15971126,"url":"https://github.com/glurp/dsl-gtk","last_synced_at":"2025-03-29T01:31:22.641Z","repository":{"id":1986671,"uuid":"2918787","full_name":"glurp/dsl-gtk","owner":"glurp","description":"DSL for make a simple ruby GUI application","archived":false,"fork":false,"pushed_at":"2018-11-06T14:26:46.000Z","size":22732,"stargazers_count":16,"open_issues_count":2,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-28T03:23:38.663Z","etag":null,"topics":["dsl","gtk3","gui","ruby"],"latest_commit_sha":null,"homepage":"","language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/glurp.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.txt","contributing":null,"funding":null,"license":"LICENSE.html","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2011-12-05T18:19:49.000Z","updated_at":"2023-05-17T17:28:27.000Z","dependencies_parsed_at":"2022-08-19T17:40:53.126Z","dependency_job_id":null,"html_url":"https://github.com/glurp/dsl-gtk","commit_stats":null,"previous_names":["glurp/ruiby"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/glurp%2Fdsl-gtk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/glurp%2Fdsl-gtk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/glurp%2Fdsl-gtk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/glurp%2Fdsl-gtk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/glurp","download_url":"https://codeload.github.com/glurp/dsl-gtk/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246125613,"owners_count":20727450,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dsl","gtk3","gui","ruby"],"created_at":"2024-10-07T20:07:43.943Z","updated_at":"2025-03-29T01:31:19.370Z","avatar_url":"https://github.com/glurp.png","language":"HTML","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Ruiby\n\n[![Build Status](https://travis-ci.org/glurp/dsl-gtk.svg?branch=master)](https://travis-ci.org/glurp/dsl-gtk)\n[![Gem Version](https://badge.fury.io/rb/Ruiby.png)](http://badge.fury.io/rb/Ruiby)\n[![AppVeyor](https://ci.appveyor.com/api/projects/status/y6pqyq79ybcmj9ye?svg=true)](https://ci.appveyor.com/project/Glurp/dsl-gtk/branch/master)\n\nA DSL for building simple GUI ruby application.\nBased on gtk.\n\n\nResources\n==========\n\n\nCode: http://github.com/glurp/Ruiby\n\nDoc: [Reference+Exemples.](https://rawgithub.com/glurp/Ruiby/master/doc.html)\n\nGem : https://rubygems.org/gems/Ruiby\n\nBased on Ruby-Gmome2 :\n* [Sources, Issues](https://github.com/ruby-gnome2/ruby-gnome2)\n* [API](http://ruby-gnome2.osdn.jp/hiki.cgi?Ruby%2FGTK)\n\n\nStatus\n======\n\nNEW : 3.24.0 !!   28-11-2017 : Linear Gradient on canvas draw surfaces primitives\n\nNow, plotters and dashboard can have beautiful background :)\n\n\n\nTO DO  :\n\n* [x] improve graphics quality on canvas : linear gradient\n* [x] improve graphics quality on canvas : radial  gradient\n* [x] improve graphics quality on canvas : transparency\n* [ ] refactoring samples demos with last improve: dynvar/autoslot...\n* [ ] resolve 100% gtk3 deprecated warning\n* [ ] complete rspec =\u003e 99% coverage ?\n\nAbandoned :\n\n* [x] gadget API\n\n\n\n\n\nInstallation\n============\n1) system\n\nInstall Ruby 2.x  #  x\u003e1\n\n\n2) install Ruiby\n(```gem install Ruiby``` will install ruby-gtk3 which install gtk3 libs)\n```\n\u003e gem install Ruiby\n```\n\nTest it:\n\n```\n\u003e ruiby_demo             # check good installation with gtk3 (default)\n\u003e ruiby_sketchi          # write and test ruiby code\n```\n\n\nHere a working gem config on windows (25-Sept-2016, Ruby  2.3.3p222) :\n```\n  did_you_mean-1.0.0\n  pkg-config-1.2.3\n  native-package-installer-1.0.4\n  cairo-1.15.9\n  glib2-3.1.8\n  gobject-introspection-3.1.8\n  gio2-3.1.8\n  atk-3.1.8\n  cairo-gobject-3.1.8\n  pango-3.1.8\n  gdk_pixbuf2-3.1.8\n  gdk3-3.1.8\n  rsvg2-3.1.8\n  gtk3-3.1.8\n  Ruiby-3.23.0\n  gtksourceview3-3.1.8\n```\n\n\nUsage\n======\nDSL is usable via inherit, include, Ruiby.app bloc, or one-liner command.\n\nBy inherit:\n\n```ruby\nclass Application \u003c Ruiby_gtk\n    def initialize(t,w,h)\n        super(t,w,h)\n    end\n\tdef component()\n\t  stack do\n\t\t...\n\t  end\n\tend\n\t.....your code....\nend\nRuiby.start { Win.new(\"application title\",350,10) }\n\n```\n\nBy include, calling ruiby-component() :\n\n```ruby\nclass Win \u003c Gtk::Window\n\tinclude Ruiby\n    def initialize(t,w,h)\n        super()\n\t\tadd(@vb=VBox.new(false, 2))\n\t\t....\n    end\n\tdef add_a_ruiby_button()\n\t\truiby_component do\n\t\t\tappend_to(@vb) do\n\t\t\t\tbutton(\"Hello Word #{@vb.children.size}\") {\n\t\t\t\t\tadd_a_ruiby_button()\n\t\t\t\t}\n\t\t\tend\n\t\tend\n\tend\nend\nRuiby.start { Win.new(\"application title\",350,10) }\n```\n\nAutonomous DSL, for  little application (most of demo in samples/ are\ndone with this pattern) :\n\n```ruby\nrequire  'Ruiby'\nRuiby.app do\n\tstack do\n\t\t. . .\n\tend\nend\n```\nAnd, for very little application ('~' are replaced by guillemet):\n\n```ruby\n\n\u003e ruiby   button(~Continue ? ~) \"{  exit!(0) }\"\n\u003e ruiby   fields([%w{a b},%w{b c},%w{c d}]) { \"|a,b,c|\" p [a,b,c] if a; exit!(a ?0:1) }\n\u003e ruiby -width 100  -height 300 -title \"Please, select a file\" \\\n             l=list(~Files :~);l.set_data Dir.glob(~*~) ;  \\\n             buttoni(~Selected~) { puts l.selection ; exit!(0) } ;\\\n\t\t\t buttoni(~Annul~) { exit!(1) }\n\n```\n\nRequire\n=======\nSimple usage with gtk3 :\n\n```ruby\nrequire 'Ruiby'\n```\n\n\nUsage with Event Machine: load event-machine before Ruiby :\n\n```ruby\nrequire 'em-proxy'\nrequire 'Ruiby'\n```\n\nWarning : EM.run is done when starting mainloop, after creation of window(s).\nSo, if you need initialization of event-machine callback, do it in component(), in a after(0):\n\n```ruby\nRuiby.app do\n  ....\n  after(0) { EventMachine::start_server().. { ... } }\nend\n```\n\nSee samples/spygui.rb, for example of GUI with EM.\n\n\nThreading\n=========\nRuiby does not have confidence in gtk multi threading, so all Ruiby commands must be done in\nmain thread context. A Ruiby delegate is provided in Kernel module for support multi-threading\n\nA Queue is polled by main-window thread :\n* main window poll Queue , messages are proc to be instance_eval() in the main window context\n* everywhere, a thread can invoke ```invoke_gui {ruiby code}```. this send to the main queue the proc,\n   which will be evaluated asynchronously\n\ninstance_eval is avoided in ruiby. He is used only for thread invoker : gui_invoke().\n\n```ruby\nrequire_relative '../lib/Ruiby'\nclass App \u003c Ruiby_gtk\n    def initialize\n        super(\"Testing Ruiby for Threading\",150,0)\n\t\tthreader(10)\n\t\tThread.new { A.new.run }\n    end\n\tdef component()\n\t  stack do\n\t\tsloti(label(\"Hello, this is Thread test !\"))\n\t\tstack { @lab=stacki { } }\n\t  end\n\tend # endcomponent\n\nend\nclass A\n\tdef run\n \t\tloop do\n\t\t \tsleep(1) # thread...\n\t\t\tthere=self\n\t\t\tgui_invoke { append_to(@lab) { sloti(\n\t\t\t\t\tlabel( there.aaa )  # ! instance_eval on main window\n\t\t\t)  } }\n\t\tend\n\tend\n\tdef aaa() Time.now.to_s  end\nend\n\nRuiby.start { App.new }\n\n```\n\n\nObserved Object/Variable\n========================\n\nDynamic variable\n----------------\nOften, a widget (an entry, a label, a slider...) show the value of a ruby variable.\neach time a code modify this variable, it must modify the widget, and vice-versa...\nThis is very tiring :)\n\nWith data binding, this notifications are done by the framework\n\nSo ```DynVar``` can be  used for representing a value variable which is dynamics, ie.\nwhich must notify widgets which show the variable state.\n\nSo we can do :\n```ruby\n  foo=DynVar.new(0)\n  entry(foo)\n  islider(foo)\n  ....\n  foo.value=43  \n  ....\n```\n\nThat works ! the entry and the slider will be updated.\n\nA move on slider will update foo.value and the entry.\nIdem for a key in the entry : slider and foo.value will be updated.\n\nif you want to be notified for your own treatment, you can observe a DynVar :\n\n```ruby\n  foo.observ { |v| @socket.puts(v.to_s) rescue nil }\n```\n\nHere, a modification of foo variable will be send on the network...\n\nWarning !! the block will always be executed in the main thread context (mainloop gtk context).\nSo DynVar is a resource internal to Ruiby framework.\n\nWidget which accept DynVar are : entry, ientry, islider, label, check_button,\n\n```\nmust be extend to button, togglebutton, combo, radio_button ... list, grid,...\n```\n\n\nDynamic Object\n--------------\n\nOften, this kind of Dyn variables are members of a 'record', which should be organized by an\nRuby Object (a Struct...)\n\nSo ```DynObject``` create a class, which is organized by a hash  :\n* packet of variable name\n* put initial value for each\n* each variable will be a DynVar\n\n```ruby\n  FooClass=make_DynClass(\"v1\" =\u003e 1 , \"v2\" =\u003e 2, \"s1\" =\u003e 'Hello...')\n  foo=FooClass.new( \"s1\" =\u003e Time.now.to_s ) # default value of s1 variable is replaced\n  ...\n  label(\" foo: \") ; entry(foo.s1)\n  islider(foo.v1)\n  islider(foo.v2)\n  ....\n  button(\"4x33\") { Thread.new { foo.s1.value=\"s4e33\" ; foo.v2.value=33 ; foo.v1.value=4} }\n  ....\n```\n\nDynamic Stock Object\n--------------------\nDynObject can be persisted to file system : use ```make_StockDynObject```, and\ninstantiate with an object persistent ID\n\n```ruby\n  FooClass=make_StockDynClass(\"v1\"=\u003e 1 , \"v2\" =\u003e 2, \"s1\" =\u003e 'Hello...')\n  foo1=FooClass.new( \"foo1\" , \"s1\" =\u003e Time.now.to_s )\n  foo2=FooClass.new( \"foo2\" , \"s1\" =\u003e (Time.now+10).to_s )\n  ....\n  button(\"Exit\") { ruiby_exit} # on exit, foo1 and foo2 will been saved to {tmpdir}/\u003c$0\u003e.storage  \n  ....\n```\n`make_StockDynObject` do both : Class creation **and** class instantiation.\n\n```ruby\n  foo=make_StockDynObject(\"v1\"=\u003e 1 , \"v2\" =\u003e 2, \"s1\" =\u003e 'Hello...')\n  ....\n  button(foo.s1) { foo.s1.value= prompt(\"new S1 value ?\")}\n  button(\"Exit\") { ruiby_exit} # on exit, foo1 and foo2 will been saved to {tmpdir}/\u003c$0\u003e.storage  \n  ....\n```\n\nComponent\n=========\nRuiby is not really object-orented : most of DSL words are simple method in Ruby_dsl module.\n\nSometime, this is not good enough :\n* when a component must have many specific methods\n* when component have (model) state : variable member must be used\n\nSo Component concept has been added (Fev 2016).It authorize to define a\nclass, child of AbstractComponent, which can be used by a DSL Word.\n\nComponents code seem very close to a Ruiby window : free constructor,\ndefine ```component()``` method for draw the widgets\n\nCreate a component:\n```ruby\nclass AAA \u003c AbstractComposant\n   def initialize(name)\n      @name= name\n      @state=1\n   end\n   def component()\n    framei(\"Component Comp:#{@name}\") do\n      label_clickable(\"B#{@name}...\") { @state=2 }\n      entry(@name,4)\n    end\n   end\n   def get_state() @state end\nend\n```\n\nDefine a word which instantiate a component of class AAA:\n```ruby\nmodule Ruiby_dsl\n  def aaa(*args)\n    c=install_composant(self,AAA.new(*args))\n  end\nend\n```\n\nUse the component:\n```ruby\n        c=nil\n        stack {\n           c=aaa \"foo\"\n           flowi { aaa 1; aaa 2 }\n        }\n        button(\"?\") { alert( c.get_state() ) }\n```\n\nA demo is at ```samples/composant.rb```.\n\nTO-DO:\n* Canvas and Plot must be converted to Component, soon :)\n* Define ```destroy()```\n* Hook for auto-generate DSL word\n* Test Stock, Dynvar, threading,\n* Tests, tests, test...\n\n\nLicense\n=======\nRuiby                   : LGPL, CC BY-SA\n\nfafamfam rasters images : CC Attribution 4.0 http://www.famfamfam.com/\n\nCrystal Clear icon set  : LGPL\n\nFarm Fresh icon set     :  CC Attribution 3.0 License http://www.fatcow.com/free-icons\n\nExemples\n========\nSee samples in \"./samples\" directory (run all.rb)\nSee at end of Doc reference : [Ex.](https://rawgithub.com/glurp/Ruiby/master/doc.html#code)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fglurp%2Fdsl-gtk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fglurp%2Fdsl-gtk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fglurp%2Fdsl-gtk/lists"}