README.org in fxruby-enhancement-0.0.4 vs README.org in fxruby-enhancement-0.1.0

- old
+ new

@@ -11,30 +11,36 @@ - [[#fox-toolkit-instantiation][FOX Toolkit instantiation]] - [[#events-from-other-threads][Events from other Threads]] - [[#the-queue_ding-queues][The Queue_Ding Queues]] - [[#enhancementingress][Enhancement.ingress]] - [[#enhancementegress][Enhancement.egress]] + - [[#reusable-components-and-dynamic-creation-and-the-reuse-flag][Reusable components and dynamic creation, and the 'reuse' flag]] - [[#api--dsl][API & DSL]] - [[#ref-refc-and-tagging-your-objects][ref(), refc() and tagging your objects]] - [[#fox_component-and-fox_instance][fox_component and fox_instance]] - [[#fx_app][fx_app]] + - [[#fx_data_target][fx_data_target]] - [[#instance][instance]] - [[#ingress_handler][ingress_handler]] + - [[#starten-and-stoppen-with-resuable-components][#starten and #stoppen with resuable components]] - [[#deferred_setup][deferred_setup]] - [[#mapping-between-fx_-declarations-and-the-fx-fxruby-objects][Mapping between fx_* declarations and the FX* FXRuby objects]] - [[#bindingfx][binding.fx]] - [[#examples][Examples]] - [[#hello-world-example-full-the-enhancement-way][Hello World example (full) the Enhancement Way]] - [[#hello-world-the-old-fxruby-way][Hello World the old fxruby way:]] - [[#bouncing-ball-example-full][Bouncing Ball example (full):]] - [[#bouncing-ball-the-old-fxruby-way][Bouncing Ball the old fxruby way:]] + - [[#datatarget-example][DataTarget Example]] - [[#release-notes][Release Notes]] - [[#known-issues][Known Issues]] - [[#contributing-to-fxruby-enhancement][Contributing to fxruby-enhancement]] - [[#copyright-and-licensing][Copyright and Licensing]] - [[#the-junkyard--scratchpad][The Junkyard / Scratchpad]] - - [[#genesis-of-the-meta-meta-programming-whereby-brain-goes-boom][Genesis of the meta-meta programming, whereby brain goes boom]] + - [[#junkyard-genesis-of-the-meta-meta-programming-whereby-brain-goes-boom][JUNKYARD Genesis of the meta-meta programming, whereby brain goes boom]] + - [[#junkyard-resuable-components-and-data-targets][JUNKYARD Resuable components and data targets]] + - [[#junkyard-data-targets][JUNKYARD Data Targets]] * fxruby-enhancement ** Introduction The fxruby library is an excellent wrapper for the FOX Toolkit. However, it reflects the C++-ness of FOX, rather than being more @@ -47,19 +53,28 @@ So, if you need to redo a layout, it becomes a messy exercise. fxruby-enhancement makes this a snap to do. You simply declare your GUI arrangement in a nested fashion. fxruby-enhancement will take care of passing parents to the nested children, and other issues - as well. You can now focus on creating a good GUI layout that you + as well. You can now focus on creating your great GUI layout that you can change on the fly without much fuss and bother. - fxruby-enhancement is basically a DSL of sorts, and every effort has - been taken to make it intuitive to use. Once you get the hang of it, - you should be able to look at the FXRuby API documentation and infer - the DSL construct for fxruby-enhancement. Please also see the many - [[file:examples][examples]]. + fxruby-enhancement (also referred to as "Enhancement") is basically a + DSL of sorts, and every effort has been taken to make it intuitive to + use. Once you get the hang of it, you should be able to look at the + FXRuby API documentation and infer the DSL construct for fxruby-enhancement. + Please also see the many [[file:examples][examples]]. + Enhancement basically leverages Ruby's singleton feature, and eliminates + the need to "subclass" the FXRuby objects and the like. In fact, you might + even consider this Enhancement's own "paradigm" for doing GUI programming. + + Your input and criticisms are more than welcome. Feel free to raise + issues on GitHub. I have not anticipated all the ways someone might try + to use Enhancement. I am making heavy use of Enhancement in my RubyNEAT + project -- which is why I created it. + ** Installation To install the gem from commandline: #+begin_src bash gem install fxruby-enhancement @@ -194,33 +209,88 @@ #+end_src And so your handler will most likely act as a dispatcher for the payloads received. For example: #+begin_src ruby - ingress_handler :status do |tag, logline| + ingress_handler :log_info, :log_error do |tag, logline| puts "received #{tag} => #{payload}" case tag when :log_info ref(:logging_info).appendItem logline when :log_error ref(:logging_error).appendItem logline end end #+end_src + Note that this ingress handler is responding to two tags. You can have + as many tags as you like for your ingress handler, and as many + ingress handlers as you like. + + Currently, all the tags should be unique. Later we may support having + multiple blocks associated with the same tag. Please feel free to generate + an issue if you want this!!! + ***** Enhancement.egress Wnen your Fox application needs to send a message to other listening threads, You simply push your payload onto the egress queue thusly: #+begin_src ruby Enhancement.egress << [:button_clicked, "I was clicked!"] #+end_src and your Ruby thread external to Fox would simply do: - #+begin_src + #+begin_src ruby + ... + message = Enhancement.egress.next + ... #+end_src + + where you'll block pending the arrival of the next message. If you + do not wish to block, you may do: + #+begin_src ruby + ... + unless Enhancement.egress.empty? + message = Enhancement.egress.next + else + # some action to take + end + ... + #+end_src +*** Reusable components and dynamic creation, and the 'reuse' flag + There are times you may want to be able to create, and popup, say, a dialog + box, or perhaps you want to create on the fly child components on an + existing window. + + This is made possible with the "reuse: true" flag. For example: + #+begin_src ruby + fx_dialog_box(:dialog, reuse: true) { + title "I am a Dialog!" + opts DECOR_ALL + + fx_button { + text "&It Works!" + instance { |dia| + dia.sel_command { + refc(:dialog).stoppen + } + } + } + instance { |dia| dia.show PLACEMENT_OWNER } + } + #+end_src + + This code snippet can be run in the context of the app or a window. + If you do it in a window context, that window will become the "owner", + and will initially be placed hovering over it. + + With reusable components, you will use the #starten and #stoppen methods + to create and destroy the component. Please see + the [[file:examples/dialog_box.rb][Dialog Box]] for a full example, and also + the docs for #starten and #stoppen. + *** API & DSL **** ref(), refc() and tagging your objects In an effort to eliminate the fuss and bother with scoping issues and object reference, ref(:some_tag) will retrive the FXRuby instance object so tagged with :some_tag. @@ -235,16 +305,29 @@ #+begin_src ruby ref(:some_tag) refc(:some_tag).inst #+end_src - There may be some edge cases where you might want to - reference the underlying component ahead of FXRuby object - instaniation, but in the vast majority of the cases, it should - be unnecessary. My goal is to enable to do what you need, not - to restrict you. You may need it for debugging, etc. - + Where might you want to use refc() instead of ref()? In cases + where the underlying FXRuby object have not been instantiated yet, + you'd use refc() instead of ref(), almost always during the component + configuration. For example: + #+begin_src ruby + fx_app :app do + ... + fx_button { + text "&See Ya!" + selector FXApp::ID_QUIT + target refc(:app) + } + ... + #+end_src + + Here, we set the button to exit the application by sending the FXApp object the ID_QUIT + message. But at the time we set the configuration, the FXApp object has not been instantiated + yet. So we use refc() instead of ref(). + Underlying, the component object is really a subclass of OpenScript. While you may like to stuff some additional data there, this is frowned upon because it might conflict with Enhancement. If you have a need for this, please do a issue in GitHub. @@ -291,10 +374,41 @@ #+end_src Typeically you'd do this inside of a module, but you could do it also in a class body. Please see the examples. +**** fx_data_target + FOX (and therefor FXRuby) supports data synchronization among components. + fx_data_target encapsulates the FXDataTarget class, just like all the + other fx_* directives do. However, in this case, some special treatment + is necessary since it is referenced at a time the underlying FXRuby + object has not been created yet. + + Enter refc(). You use refc(), instead of ref(), to use it when you are + configuring the component (really, specifying the initial parameters + to the underlying FXRuby class!) We illustrate here: + #+begin_src ruby + ... + fx_data_target (:mydata) { value "initial value" } + ... + fx_text (:text_3) { + target refc(:mydata) + selector FXDataTarget::ID_VALUE + } + fx_text (:text_4) { + target refc(:mydata) + selector FXDataTarget::ID_VALUE + } + #+end_src + + And so the two text components -- or widgets -- are initially + set to the value of "initial value", and when one changes, the + other is instantly updated. + + Otherwise, you can deal with fx_data_target as expected. See + the [[#datatarget-example][DataTarget Example]]. + **** instance Inside of your component declaration, you will undoubtly want to specify what you want to do once the FXRuby object is actually instantiated. This is what the instance clause will allow you to do. Your code block there will be passed @@ -377,10 +491,34 @@ end #+end_src The same block is assigned to all the given tags of :warn, :info, and :error. +**** #starten and #stoppen with resuable components + To designate a component as reusable, declare it with "reuse: true" + as in the example: + #+begin_src ruby + fx_dialog_box(:dialog, reuse: true) { ... } + #+end_src + + Then in the instance clause or to the response to an event, + you would do: + #+begin_src ruby + refc(:dialog).starten + #+end_src + + to activate it, and + #+begin_src ruby + refc(:dialog).stoppen + #+end_src + + to deactive it (and remove the 'server'-side FOX components!) + + Note that you call refc(), not ref() in this case, because the + functionality lies in the component object holder for the actual + FOX component, not within the FXRuby object itself. + **** TODO deferred_setup **** TODO Mapping between fx_* declarations and the FX* FXRuby objects **** binding.fx This is a way to split up your layouts into different .fx "modules", purely for organizational reasons. For example, @@ -416,11 +554,11 @@ is still in the works. However, you are free to look at the code that is there to get good ideas. https://github.com/flajann2/rubyneat-panel/tree/master/lib/rubyneat-panel - Class-based enhancement (this has not been tested yet!!!): + Class-based Enhancement (this is currently not supported!!!): #+begin_src ruby class Main < FXMainWindow compose :my_window do title "RubyNEAT Panel" show PLACEMENT_SCREEN @@ -449,11 +587,11 @@ ... end end #+end_src - Class-free enhancement: + Class-free Enhancement (strongly recommended): #+begin_src ruby mw = fx_main_window :my_window do title "RubyNEAT Panel" width 700 height 400 @@ -884,23 +1022,92 @@ The Ball class is the same, but the actual Fox-related code should clearly illustrate the power of Enhancement. More examples can be found [[file:examples][HERE]]. +**** DataTarget Example + fx_data_target (:some_name) must be referenced as refc(:some_name) and + not ref(...). See the example below. + + #+begin_src ruby +#!/usr/bin/env ruby +require 'fxruby-enhancement' + +include Fox +include Fox::Enhancement::Mapper + +fx_app :app do + app_name "DataTarget" + vendor_name "Example" + + fx_data_target (:textx) { value "x marks the spot!" } + fx_data_target (:texty) { value "y do it?" } + + fx_main_window(:main) { + title "fx_data_target example" + opts DECOR_ALL + width 300 + x 100 + y 200 + + fx_text_field (:text_1) { + ncols 40 + target refc(:textx) + selector FXDataTarget::ID_VALUE + } + fx_text_field (:text_2) { + ncols 40 + target refc(:textx) + selector FXDataTarget::ID_VALUE + } + fx_text (:text_3) { + opts LAYOUT_FILL_X + target refc(:texty) + selector FXDataTarget::ID_VALUE + } + fx_text (:text_4) { + opts LAYOUT_FILL_X + target refc(:texty) + selector FXDataTarget::ID_VALUE + } + fx_button { + text "&See ya!" + selector FXApp::ID_QUIT + opts BUTTON_NORMAL|LAYOUT_CENTER_X + + instance { |b| + b.target = ref(:app) + } + } + + instance { |w| + w.show PLACEMENT_SCREEN + } + } +end + +# alias for fox_component is fxc +fox_component :app do |app| + app.launch +end + #+end_src + ** Release Notes - | Version | Date | Notes | - |---------+------------+---------------------------------------------------------| - | 0.0.2 | 2017-01-11 | Initial release | - | 0.0.3 | 2017-01-15 | Needed to require fox16/colors for FXColor to be loaded | - | 0.0.4 | 2017-01-16 | ingress_handler now handles multiple tags. | + | Version | Date | Notes | + |---------+------------+-------------------------------------------------------------| + | 0.0.2 | 2017-01-11 | Initial release | + | 0.0.3 | 2017-01-15 | Needed to require fox16/colors for FXColor to be loaded | + | 0.0.4 | 2017-01-16 | ingress_handler now handles multiple tags. | + | 0.1.0 | 2017-01-18 | special handling for fx_data_target and resuable components | ** Known Issues - | Version | Date | Issues | - |---------+------------+-------------------------------------------------------| - | 0.0.2 | 2017-01-11 | Not enough example code!!! Need more documentation!!! | + | Version | Date | Issues | + |---------+------------------------+--------------------------------------------------------------------| + | 0.0.2 | 2017-01-11 | Not enough example code!!! Need more documentation!!! | + | 0.1.0 | Trump Inaguration Day, | deferred_setup not fully implemented, and may go away. | + | | 2017-01-20 | compose is not really needed, and is not fully implemented anyway. | - ** Contributing to fxruby-enhancement - Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet. - Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it. - Fork the project. @@ -915,11 +1122,11 @@ ** The Junkyard / Scratchpad These are my personal notes, not meant for anyone else. You may see some interesting tidbits here, but I am not gauranteeing anything to be useful or reliable in this section. YOU HAVE BEEN WARNED. -*** Genesis of the meta-meta programming, whereby brain goes boom +*** JUNKYARD Genesis of the meta-meta programming, whereby brain goes boom #+begin_src ruby class FXToolBar # monkey patch include Enhancement attr_accessor :_o end @@ -951,5 +1158,21 @@ <% end %> <% end %> #+end_src +*** JUNKYARD Resuable components and data targets + We have an issue with needing to have reusable components + (dialog boxes, say), and ṕroperly handling data targets designations. +**** JUNKYARD Data Targets + Data targets cannot be done the same way we are doing the other + fxruby components, because they have a different workflow. Basically, + they need to be instantiated before the other comonents that uses + them, and they are not really "child" objects, either. Referring to them + using the ref() or refc() approach simply fails, because they won't + be instantiated in time. + + We have ameroliated this problem by checking in the parameter list + for an OpenStruct object, and calling #inst on it to pass in the instance, + rather than the object itself. So now you simply use refc() + in those cases. +