Permalink
Browse files

calculator example operational

  • Loading branch information...
1 parent 71b7112 commit aa822e91138e572e1581732fe3c3e4b58409f517 @EugeneBrazwick committed May 14, 2010
View
1,014 LICENSE

Large diffs are not rendered by default.

Oops, something went wrong.
View

Large diffs are not rendered by default.

Oops, something went wrong.
View

Large diffs are not rendered by default.

Oops, something went wrong.
View
@@ -63,6 +63,11 @@ task :play_rminiarp do
sh "#{RUBY} bin/rminiarp --bpm=120 --wrap=UM-2 fixtures/miniarp.dat"
end
+desc 'as an example to run gui examples: calculator'
+task :run_calculator_example do
+ `#{RUBY} -I lib lib/reform/examples/widgets/calculator.rb`
+end
+
desc 'panic'
task :panic do
sh "#{RUBY} bin/panic 20:1"
View
@@ -137,6 +137,7 @@ class ReformError < StandardError
module Instantiator
def createInstantiator_i name, qt_implementor_class, reform_class
# tag "define_method #{self}::#{name}."
+ remove_method name if private_method_defined?(name)
define_method name do |quickylabel = nil, &block|
# tag "arrived in #{self}::#{name}()"
# It's important to use parent_qtc_to_use, since it must be a true widget.
@@ -155,7 +156,7 @@ def createInstantiator_i name, qt_implementor_class, reform_class
# NOT GOING TO WORK.
# BAD respond_to is USELESS!! if qparent.respond_to?(:layout) && qparent.layout && reform_class <= Layout # smart!!
if qparent
- if reform_class <= Layout && (qparent.inherits('QWidget') && qparent.layout || qparent.inherits('QGraphicsScene'))
+ if reform_class <= Layout && (qparent.widgetType? && qparent.layout || qparent.inherits('QGraphicsScene'))
# insert an additional generic frame (say Qt::GroupBox)
# you cannot store a layout in a layout, nor can you store a layout in a graphicsscene.
if qparent.inherits('QGraphicsScene') # even if a GraphicsItem, you cannot pass the scene as a qparent! && !(reform_class <= GraphicsItem)
@@ -176,10 +177,15 @@ def createInstantiator_i name, qt_implementor_class, reform_class
# tag "reform_class=#{reform_class}, calling new_qt_implementor"
newqtc = qt_implementor_class &&
ctrl.instantiate_child(reform_class, qt_implementor_class, qparent)
- c = reform_class.new ctrl, newqtc
- c.text = quickylabel if quickylabel
- # addControl will execute block, and then also call postSetup
- ctrl.addControl(c, &block)
+# tag "#{reform_class}.new"
+ if reform_class <= Model
+ ctrl.setModel(reform_class.new, &block)
+ else
+ c = reform_class.new ctrl, newqtc
+ c.text(quickylabel) if quickylabel
+ # addControl will execute block, and then also call postSetup
+ ctrl.addControl(c, &block)
+ end
end # define_method name
# make the method private:
private name
@@ -211,7 +217,7 @@ def registerControlClassProxy_i name, thePath
define_method name do |quickylabel = nil, &block|
# tag "arrived in #{self}::#{name}() PROXY"
# when called the method is removed to prevent loops
- klass.send :undef_method, name
+ klass.send :remove_method, name
# tag "require_relative '#{thePath}'"
require_relative thePath
# the loaded module should call registerControlClass which recreates the method
@@ -234,6 +240,10 @@ module SceneContext
extend Instantiator
end # module SceneContext
+ module FormContext
+ extend Instantiator
+ end # module SceneContext
+
# this class just stores a name with the arguments to a widget constructor
class Macro
private
@@ -267,7 +277,7 @@ def self.registerControlClassProxy_i name, thePath
return if private_method_defined?(name)
klass = self
define_method name do |quickylabel = nil, &block|
- klass.send :undef_method, name
+ klass.send :remove_method, name
require_relative thePath
send(name, quickylabel, &block)
end
@@ -290,15 +300,40 @@ def self.registerGraphicsControlClassProxy id, path
# SceneFrameMacroContext::registerControlClassProxy_i id, path
end
- require_relative 'widget'
+ def self.registerModelClassProxy id, path
+ FormContext::registerControlClassProxy_i id, path
+ end
+
+# require_relative 'widget'
+
+ # some forwards, for the ultimate lazy programming:
+ class Control < Qt::Object
+ end
+
+ class Widget < Control
+ end
+
+ class Frame < Widget
+ end
+
+ class Layout < Frame
+ end
+
+ module Model
+ end
# delegator. See App::createInstantiator
- def self.createInstantiator name, qt_implementor_class, reform_class = Widget
+ def self.createInstantiator name, qt_implementor_class, reform_class = Widget, options = {}
# tag "createInstantiator '#{name}'"
if reform_class <= Widget
- FrameContext::createInstantiator_i name, qt_implementor_class, reform_class
- App::createInstantiator_i name
+ unless options[:form]
+ FrameContext::createInstantiator_i name, qt_implementor_class, reform_class
+ end
+ App::createInstantiator_i name, qt_implementor_class, reform_class, options
# SceneFrameMacroContext::createInstantiator_i name
+ elsif reform_class <= Model
+# tag "creating instantiator #{name} in FormContext"
+ FormContext::createInstantiator_i name, qt_implementor_class, reform_class
else
# note: since a Scene is a Frame it also receives the Widget instantiators.
SceneContext::createInstantiator_i name, qt_implementor_class, reform_class
@@ -347,7 +382,7 @@ def self.registerControlClassProxy_i name , thePath
# tag "define_method #{self}::#{name}"
define_method name do |quickylabel = nil, &block|
# Remove ourselves, so if we accidentally come back here we cause no stack overflow
- App.send :undef_method, name
+ App.send :remove_method, name
require_relative thePath
send(name, quickylabel, &block)
end
@@ -385,16 +420,27 @@ def exec
which the class can be instantiated. In the app space all implementors
generate a macro that is added to the implicit QMainWindow
=end
- def self.createInstantiator_i name
- define_method name do |quickylabel = nil, &block|
- raise ReformError, 'put controls in forms' unless @all_forms.length <= 1
-# puts "creating implementor_class #{implementor_class}, rf_class=#{rf_class}"
- require_relative 'controls/form'
- require_relative 'mainwindow'
- @firstform ||= ReForm.new(QMainWindow.new) # this is just form { }, the first time called
- # we delay creating the elements until form.run is called.
- Macro.new(@firstform, name, quickylabel, block)
+ def self.createInstantiator_i name, qt_implementor_class, reform_class, options
+ remove_method name if private_method_defined?(name)
+ if options[:form]
+ define_method name do |quicky = nil, &block|
+ qform = qt_implementor_class.new
+ form = reform_class.new qform
+ @firstform ||= form # it looks the same, but is completely different
+ form.windowTitle = quicky if quicky
+ form.setup = block
+ # and now we wait for 'run'
+ end
+ else
+ define_method name do |quickylabel = nil, &block|
+ raise ReformError, 'put controls in forms' unless @all_forms.length <= 1
+ # puts "creating implementor_class #{implementor_class}, rf_class=#{rf_class}"
+ @firstform ||= form
+ # we delay creating the elements until form.run is called.
+ Macro.new(@firstform, name, quickylabel, block)
+ end
end
+ # make it private:
private name
end # App::createInstantiator_i
@@ -446,6 +492,10 @@ def self.app &block
basename = File.basename(file, '.rb')
registerGraphicsControlClassProxy basename, 'graphics/' + basename
end
+ for file in Dir[File.dirname(__FILE__) + '/models/*.rb']
+ basename = File.basename(file, '.rb')
+ registerModelClassProxy basename, 'models/' + basename
+ end
$qApp.instance_eval(&block) if block
$qApp.exec
end # app
@@ -1,4 +1,6 @@
+# Copyright (c) 2010 Eugene Brazwick
+
# qtruby version of the AnalogClock example widget
module Reform
@@ -0,0 +1,29 @@
+
+# Copyright (c) 2010 Eugene Brazwick
+
+module Reform
+
+ require_relative '../controls/button'
+
+ class QSpacyToolButton < Qt::ToolButton
+
+ private
+ def initialize parent = nil
+ super
+# tag "setSizePolicy"
+ setSizePolicy Qt::SizePolicy::Expanding, Qt::SizePolicy::Preferred
+ end
+
+ public
+ def sizeHint
+ size = super
+ size.height += 20
+ size.width = [size.width, size.height].max
+# tag "sizeHint -> #{size.inspect}"
+ size
+ end
+ end
+
+ createInstantiator File.basename(__FILE__, '.rb'), QSpacyToolButton, Button
+
+end # Reform
View
@@ -50,10 +50,12 @@ def self.define_simple_setter *list
# default.
def executeMacros
- @macros and @macros.each { |macro| macro.exec }
+ instance_variable_defined?(:@macros) and @macros.each { |macro| macro.exec }
end
- def name aName
+ def name aName = nil
+ return name unless aName
+ @name = aName
@containing_frame.registerName aName, self
end
@@ -68,6 +70,11 @@ def whenTimeout &block
@whenTimeout = block
end
+ def connect_id
+ instance_variable_defined?(:@connect_id) ? @connect_id :
+ instance_variable_defined?(:@name) ? @name : nil
+ end
+
protected
#override
def timerEvent event
@@ -76,6 +83,23 @@ def timerEvent event
@whenTimeout.call
end
+ # use this to wrap a rescue clause around any user-callback. Also
+ # it calls the callback not in the object's context, but in that of the
+ # form (MVC controller)
+ def rfCallBlockBack *args, &block
+ begin
+ return containing_form.instance_exec(*args, &block)
+ rescue LocalJumpError
+ # ignore
+ rescue IOError, RuntimeError => exception
+ msg = "#{exception.message}\n"
+ rescue StandardError => exception
+ msg = "#{exception.class}: #{exception}\n" + exception.backtrace.join("\n")
+ end
+ # this must be fixed using an alert, but it may depend on the kind of exception...
+ $stderr << msg
+ end
+
public
# the parent widget (a Reform::Frame)
attr :containing_frame
@@ -89,6 +113,10 @@ def timerEvent event
# tuple w,h as set in last call of setSize/setGeometry
attr :requested_size
+ def addWidget control, q
+ @qtc.addWidget q
+ end
+
# return macros array, creating it if it was undefined
# Macros are executed right after the setup block (if present)
def macros!
@@ -106,7 +134,6 @@ def whenResized &block
@whenResized = block
end
-
# normally the Qt implementor, but for layouts we add subcontrols to the
# layouts owner. In other words, the result must be a Qt::Widget in all cases
# which does not hold for all Controls.@qtc values.
@@ -158,6 +185,41 @@ def timer?
def graphic?
end
+
+ def model?
+ end
+
+=begin rdoc
+ connect a model (may be nil) to the control
+ The rules are as follows:
+ - if the control has a connect_id (defaults to name) and that name is also
+ a public method of model,
+ with no arguments (a getter therefore) and if model is not nil, then we
+ apply the method and use the result to set the value of the control.
+ - otherwise if the control has no name, nor a connect_id set, it is left untouched,
+ but the connect may propagate
+ - otherwise the value of the control is cleared. The result must be 'clean'
+ but validation may trigger if the user tries to 'commit' the formdata (clicks 'Update').
+ - the specific value of nil stands for a nonset value. This could be automatically
+ converted to 0 or an empty string, but the control must not treat the value as
+ valid by default and validation must be triggered if the user attempts to 'commit'
+ the formdata.
+ - controls that can be changed should be protected if the accompanying setter is
+ not available.
+ - controls can set a @connect_id, that overrides @name.
+ - if :initializing is set in 'options' the control must keep or set its 'clean'
+ state, and must
+ treat the field as being untouched by the user. In particular no triggers should be
+ applied, and no validation should take place.
+ - controls that have components must propagate the connection, even if they have no
+ name.
+ - if the value of a control does not change by the connect operation, no triggers must
+ be called (at least not now).
+ See Frame#connect
+=end
+ def connectModel model, options = nil
+ end
+
end # class Control
# forward
@@ -0,0 +1,26 @@
+
+# Copyright (c) 2010 Eugene Brazwick
+
+module Reform
+
+ class Button < Widget
+ private
+ define_simple_setter :text
+
+ # with a block associate the block with the 'clicked' signal.
+ # Without a block we emit 'clicked'
+ def whenClicked &block
+ if block
+ connect(@qtc, SIGNAL('clicked()'), self) do
+ rfCallBlockBack(&block)
+ end
+ else
+ @qtc.clicked
+ end
+ end #whenClicked
+
+ end
+
+ createInstantiator File.basename(__FILE__, '.rb'), Qt::PushButton, Button
+
+end # Reform
@@ -0,0 +1,16 @@
+
+# Copyright (c) 2010 Eugene Brazwick
+
+module Reform
+
+ require_relative 'form'
+
+=begin rdoc
+a QDialog wrapper
+=end
+ class Dialog < ReForm
+ end # class Dialog
+
+ createInstantiator File.basename(__FILE__, '.rb'), Qt::Dialog, Dialog, form: true
+
+end # module Reform
Oops, something went wrong.

0 comments on commit aa822e9

Please sign in to comment.