diff --git a/Tests/button/button.rb b/Tests/button/button.rb index 1f6c8fa6..d72583d8 100644 --- a/Tests/button/button.rb +++ b/Tests/button/button.rb @@ -35,7 +35,7 @@ icon_pos: "right" do para "right image" end - button "top", width: 80, height: 45, icon: "#{DIR}/static/icon-info.png", + @b = button "top", width: 80, height: 45, icon: "#{DIR}/static/icon-info.png", icon_pos: "top" do para "top image" end diff --git a/Tests/layout/l1.rb b/Tests/layout/l1.rb index d0b9a5f7..5289c8e0 100644 --- a/Tests/layout/l1.rb +++ b/Tests/layout/l1.rb @@ -1,7 +1,7 @@ class MyLayout attr_accessor :pos_x, :pos_y, :w, :h - attr_accessor :contents + attr_accessor :contents, :canvas def initialize() @pos_x = 25 @@ -9,25 +9,41 @@ def initialize() @contents = [] end - def setup(attr) + def setup(canvas, attr) + @canvas = canvas @w = attr[:width] @h = attr[:height] puts "setup #{@w} X #{@h}" end - def add(widget) + def add(canvas, widget, attrs) @contents << widget widget.move @pos_x, @pos_y @pos_x += 25 @pos_y += 25 end + + def remove(canvas, widget, pos) + return true + end + + def size(canvas, pass) + $stderr.puts "callback: size pass=#{pass}" + end + + def clear() + end + + def finish() + @canvas.show + end end Shoes.app width: 350, height: 400, resizeable: true do stack do para "Before layout" @ml = MyLayout.new - layout manager: @ml, width: 300, height: 300 do + @lay = layout use: @ml, width: 300, height: 300 do background yellow p1 = para "First Para" a = button "one" @@ -35,6 +51,7 @@ def add(widget) p2 = para "I am #{self.class}" end end + @lay.start {@lay.finish} para "After layout" para "@ml is #{@ml.class}" end diff --git a/Tests/layout/l2.rb b/Tests/layout/l2.rb index c76279c8..b88b40c4 100644 --- a/Tests/layout/l2.rb +++ b/Tests/layout/l2.rb @@ -4,23 +4,35 @@ class MyLayout attr_accessor :incr_x, :incr_y, :canvas def initialize() - puts "initialized" - clear + $stderr.puts "initialized" + self.clear end def setup(canvas, attr) @canvas = canvas @w = attr[:width] @h = attr[:height] - puts "callback: setup #{@w} X #{@h}" + $stderr.puts "callback: setup #{@w} X #{@h}" end - def add(canvas, widget) - puts "callback add: #{widget.class} #{canvas.contents.size}" - puts "w: #{widget.width} h: #{widget.height}" + def add(canvas, widget, attrs) + $stderr.puts "callback add: #{widget.class} #{canvas.contents.size}" widget.move @pos_x, @pos_y @pos_x += @incr_x @pos_y += @incr_y + name = attrs && attrs[:name] + if name + $stderr.puts "Winner, Winner, Chicken Dinner for #{name}" + end + end + + def remove(canvas, widget, pos) + $stderr.puts"callback: remove" + return true + end + + def size(canvas, pass) + $stderr.puts "callback: size pass=#{pass} w: #{canvas.width} h:#{canvas.height}" end def clear @@ -28,18 +40,11 @@ def clear @pos_y = 5 @incr_x = 25 @incr_y = 25 - puts "callback: clear" + $stderr.puts "callback: clear" end - - def refresh - @pos_x = 5 - @pos_y = 5 - @canvas.contents.each do |widget| - widget.move @pos_x, @pos_y - @pos_x += @incr_x - @pos_y += @incr_y - puts "w: #{widget.width} h: #{widget.height}" - end + + def finish() + @canvas.show end end @@ -48,10 +53,10 @@ def refresh stack do @p = para "Before layout" @ml = MyLayout.new - @lay = layout manager: @ml, width: 340, height: 380 do + @lay = layout use: @ml, width: 340, height: 380 do background yellow - p1 = para "First Para" - a = button "one" + p1 = para "First Para", name: 'p1' + a = button "one", name: 'b1' b = button "two" p2 = para "I am #{self.class}" end diff --git a/Tests/layout/l3.rb b/Tests/layout/l3.rb new file mode 100644 index 00000000..c7e1b981 --- /dev/null +++ b/Tests/layout/l3.rb @@ -0,0 +1,210 @@ +Shoes.setup do + gem 'cassowary-ruby' +end +require 'cassowary' +include Cassowary +class CassowaryLayout + attr_accessor :canvas, :widgets, :solver, :attrs, :left_limit, + :right_limit, :top_limit, :height_limit, :right_limit_stay, + :canvas_set, :canvas_w, :canvas_h + + def initialize() + #$stderr.puts "initialized" + @widgets = {} + @solver = SimplexSolver.new + @attrs = {} + @canvas_set = false + @canvas_x = 0 + @canvas_y = 0 + end + + + # canvas does not have a width or height. be careful + def setup(canvas, attr) + @canvas = canvas + hgt = 0 + wid = 0 + if (attr && attr[:width]) + wid = attr[:width] + else + wid = 500 + canvas.style width: wid + end + if (attr && attr[:height]) + hgt = attr[:height] + else + hgt = 400 + canvas.style height: hgt + end + @left_limit = Variable.new(name: 'left', value: 0.0) + @right_limit = Variable.new(name: 'width', value: wid) + @top_limit = Variable.new(name: "top", value: 0.0) + @height_limit = Variable.new(name: "height", value: hgt) + @solver.add_stay(@left_limit) + @solver.add_stay(@right_limit, Strength::WeakStrength) + $stderr.puts "callback: setup #{wid} X #{hgt}" + end + + def add(canvas, widget, attrs) + # widget is not on-screen and allocated at this time. Pity + # DO NOT enumerate attrs hash - crash if you try. + name = attrs && attrs[:name] + $stderr.puts "callback add: #{name} #{widget.class} #{canvas.contents.size}" + self.track widget, name if name + end + + def remove(canvas, widget, pos) + $stderr.puts"callback: remove" + return true + end + + + def track(obj, str) + @widgets[str] = obj + vars = {} + vars['left'] = Variable.new(name: 'left'+str, value: 0) + vars['width'] = Variable.new(name: 'width'+str, value: 0) + vars['top'] = Variable.new(name: 'top'+str, value: 0) + vars['height'] = Variable.new(name: 'height'+str, value: 0) + @attrs[str] = vars + end + + # parse string like 'b1-width' and return Cassowary Variable + def var(str) + str[/(\w+)\-(\w+)/] + @attrs[$1][$2] + end + + def size(canvas, pass) + if pass == 0 + return + else + $stderr.puts "callback: size Change! w: #{canvas.width} h:#{canvas.height}" + end + end + + def widget_defaults + @canvas.show + @widgets.each_pair do |id, ele| + vh = @attrs[id]['height'] + vh.value = ele.height + vw = @attrs[id]['width'] + vw.value = ele.width + $stderr.puts "widget #{id} w:#{vw.value} h:#{vh.value}" + end + end + + def resize(w, h) + @right_limit.value = w + @height_limit.value = h + #@solver.add_stay(@right_limit, Strength::RequiredStrength) + + #right_limit_stay = solver.add_constraint(right_limit, strength=REQUIRED) + #solver.add_constraint(right_limit_stay) + end + + def clear() + $stderr.puts "callback: clear" + end + + def rules(arg) + $stderr.puts "callback rules #{arg}" + end + + def finish() + @widgets.each_pair do |k, widget| + left = widget.left + top = widget.top + height = widget.height + width = widget.width + $stderr.puts "From #{left},#{top}" + left = @attrs[k]['left'].value.to_i + top = @attrs[k]['top'].value.to_i + width = @attrs[k]['width'].value.to_i + height = @attrs[k]['height'].value.to_i + $stderr.puts "move to #{left}, #{top} for w:#{width} h:#{height}" + widget.style width: width + widget.move(left, top) + end + end + + # send other methods to @solver + def method_missing(meth, *args, &block) + if @solver.respond_to? meth + @solver.send(meth, *args, &block) + else + super + end + end + +end + +Shoes.app width: 480, height: 280, resizeable: true do + stack do + flow do + para "Before layout " + @p = para "unknown" + end + @ml = CassowaryLayout.new + @lay = layout use: @ml, width: 450, height: 200 do + #@lay = layout manager: @ml do + background teal + a = button "one", name: 'b1' + b = button "two", name: 'b2' + para "Strings Too!", name: 'b3' + end + @lay.start do + # Every thing has a default h and w now. We can compute things + @ml.rules "foobar" # for a test + @ml.widget_defaults + # The two buttons are the same width + @ml.add_constraint(@ml.var('b1-width').cn_equal @ml.var('b2-width')) + + # Button1 starts 50 from the left margin. + @ml.add_constraint(@ml.var('b1-left').cn_equal @ml.left_limit + 50) + + # Button2 ends 50 from the right margin + @ml.add_constraint((@ml.left_limit + @ml.right_limit).cn_equal @ml.var('b2-left') + @ml.var('b2-width') + 50) + + # Button2 starts at least 50 from the end of Button1. This is the + # "elastic" constraint in the system that will absorb extra space + # in the layout. + @ml.add_constraint(@ml.var('b2-left').cn_equal @ml.var('b1-left') + @ml.var('b1-width') + 50) + + # Button1 has a minimum width of 87 + @ml.add_constraint(@ml.var('b1-width').cn_geq 87) + + # Button1's preferred width is 87 + @ml.add_constraint(@ml.var('b1-width').cn_equal 87, Strength::StrongStrength) + + # Button2's minimum width is 113 + @ml.add_constraint(@ml.var('b2-width').cn_geq 113) + + # Button2's preferred width is 113 + @ml.add_constraint(@ml.var('b2-width').cn_equal 113, Strength::StrongStrength) + + # string b3 is at the bottom ? + @ml.add_constraint(@ml.height_limit.cn_equal @ml.var('b3-top')) + + @lay.finish + @p.text = @lay.inspect + end + end + button "refresh" do + @lay.finish + end + button "shrink" do + wid = (@lay.width * 0.9).to_i + hgt = (@lay.height * 0.9).to_i + @ml.resize(wid,hgt) + @lay.style width: wid, height: hgt + @lay.finish + end + button "expand" do + wid = (@lay.width * 1.1).to_i + hgt = (@lay.height * 1.1).to_i + @ml.resize(wid, hgt) + @lay.style width: wid, height: hgt + @lay.finish + end +end diff --git a/Tests/layout/vfl1.rb b/Tests/layout/vfl1.rb new file mode 100644 index 00000000..05f8b1be --- /dev/null +++ b/Tests/layout/vfl1.rb @@ -0,0 +1,16 @@ + +Shoes.app width: 350, height: 400, resizeable: true do + stack do + para "Before layout" + @lay = layout use: :foobar, width: 300, height: 300 do + para "First Para", name: 'Label_1' + button "one", name: 'Button_1' + button "two", name: 'Button_2' + end + @lay.start { + @lay.rules 'foo.vfl' + @lay.finish + } + end + para "After layout" +end diff --git a/app.yaml b/app.yaml index f3834fef..1362f5f8 100644 --- a/app.yaml +++ b/app.yaml @@ -1,7 +1,7 @@ name: Shoes major: 3 minor: 3 -tiny: 7 +tiny: 8 release: walkabout revision: git icons: diff --git a/shoes/canvas.c b/shoes/canvas.c index 736f544d..3ccb4fd9 100644 --- a/shoes/canvas.c +++ b/shoes/canvas.c @@ -122,7 +122,8 @@ VALUE shoes_canvas_style(int argc, VALUE *argv, VALUE self) { break; case 2: - if (NIL_P(canvas->attr)) canvas->attr = rb_hash_new(); + if (NIL_P(canvas->attr)) + canvas->attr = rb_hash_new(); rb_funcall(canvas->attr, s_update, 1, args.a[0]); shoes_canvas_repaint_all(canvas->parent); break; @@ -611,6 +612,9 @@ VALUE shoes_canvas_draw(VALUE self, VALUE c, VALUE actual) { if (RTEST(actual)) { shoes_canvas_place(c1); } + if (c1->layout_mgr != Qnil) { + shoes_layout_size(c1, 1); // TODO: is this the best place? + } } } @@ -864,7 +868,7 @@ VALUE shoes_canvas_layout(int argc, VALUE *argv, VALUE self) { VALUE layout_canvas; VALUE layout_obj; SETUP_CANVAS(); - fprintf(stderr, "canvas_layout: called\n"); + //fprintf(stderr, "canvas_layout: called\n"); rb_parse_args(argc, argv, "|h&", &args); layout_obj = shoes_layout_new(args.a[0], self); @@ -876,13 +880,15 @@ VALUE shoes_canvas_layout(int argc, VALUE *argv, VALUE self) { DRAW(layout, canvas->app, rb_funcall(args.a[1], s_call, 0)); */ rb_ary_push(canvas->app->nesting, layout_canvas); - rb_funcall(args.a[1], s_call, 0); // this is the block arg + /* + * This calls the block (which adds the buttons, para, widgets etc + */ + rb_funcall(args.a[1], s_call, 0); rb_ary_pop(canvas->app->nesting); } - shoes_add_ele(canvas, layout_canvas); // Shoes tracks the canvas - - // yes, we return the canvas, not the Layout Object - //return layout_canvas; + shoes_add_ele(canvas, layout_canvas); // Shoes tracks the layout's canvas + Data_Get_Struct(layout_canvas, shoes_canvas, canvas); + shoes_layout_size(canvas, 0); // callback to user layout method return layout_obj; } diff --git a/shoes/types/layout.c b/shoes/types/layout.c index ad61fd2a..0f1660fe 100644 --- a/shoes/types/layout.c +++ b/shoes/types/layout.c @@ -11,12 +11,15 @@ #include "shoes/types/types.h" #include "shoes/types/settings.h" #include "shoes/types/layout.h" -#include // -// Shoes::Layout needs to be a slot-like class - same api? +// Shoes::Layout needs to be a slot-like class - mostly same api // extern VALUE cButton, cBackground; +// user written managers must implment these methods: +static ID s_manager, s_setup, s_addw, s_clear; +extern ID s_remove, s_finish, s_size; + /* FUNC_M generate two functions here * shoes_canvas_c_layout(int argc, VALUE *argv, VALUE self) { ..} * + means call shoes_canvas_repaint_all() at end @@ -29,9 +32,14 @@ void shoes_layout_init() { rb_define_method(cLayout, "clear", CASTHOOK(shoes_layout_clear), -1); rb_define_method(cLayout, "insert", CASTHOOK(shoes_layout_insert), -1); rb_define_method(cLayout, "delete_at", CASTHOOK(shoes_layout_delete_at), -1); - rb_define_method(cLayout, "rule", CASTHOOK(shoes_layout_add_rule), -1); + rb_define_method(cLayout, "rules", CASTHOOK(shoes_layout_add_rules), -1); rb_define_method(cLayout, "finish", CASTHOOK(shoes_layout_finish), -1); + rb_define_method(cLayout, "height", CASTHOOK(shoes_layout_get_height), 0); + rb_define_method(cLayout, "width", CASTHOOK(shoes_layout_get_width), 0); + rb_define_method(cLayout, "start", CASTHOOK(shoes_layout_start), -1); + rb_define_method(cLayout, "style", CASTHOOK(shoes_layout_style), -1); + /* RUBY_M generates defines (allow Ruby to call the FUNC_M funtions rb_define_method(cCanvas, "layout", CASTHOOK(shoes_canvas_c_layout), -1); rb_define_method(cApp, "layout", CASTHOOK(shoes_app_c_layout), -1) @@ -54,35 +62,70 @@ VALUE shoes_layout_alloc(VALUE klass) { SHOE_MEMZERO(ly, shoes_layout, 1); obj = Data_Wrap_Struct(klass, shoes_layout_mark, shoes_layout_free, ly); // set fields ? - ly->x = 10; - ly->y = 10; ly->delegate = Qnil; ly->canvas = Qnil; return obj; } VALUE shoes_layout_new(VALUE attr, VALUE parent) { - fprintf(stderr, "shoes_layout_new called\n"); + //fprintf(stderr, "shoes_layout_new called\n"); VALUE obj = shoes_layout_alloc(cLayout); - shoes_layout *ly; - Data_Get_Struct(obj, shoes_layout, ly); - // Most of shoes thinks its a Flow (cFlow or cLayout ?) + shoes_layout *lay; + Data_Get_Struct(obj, shoes_layout, lay); + // Most of shoes thinks its a Flow (cFlow) + VALUE hgt = ATTR(attr, height); + if (NIL_P(hgt)) { + ATTRSET(attr, height, INT2NUM(100)); + } + // user layout starts out as hidden. - Don't - won't have h/w set + //ATTRSET(attr, hidden, Qtrue); VALUE canvas = shoes_slot_new(cFlow, attr, parent); - ly->canvas = canvas; + lay->canvas = canvas; shoes_canvas *cvs; Data_Get_Struct(canvas, shoes_canvas, cvs); - // get manager from attr, put in delegate. VALUE mgr; - ID s_manager = rb_intern ("manager"); + s_manager = rb_intern ("use"); + s_setup = rb_intern("setup"); + s_addw = rb_intern("add"); + s_clear = rb_intern("clear"); + // get manager from attr, put in delegate. mgr = ATTR(attr, manager); - if (! NIL_P(mgr)) { - ly->delegate = mgr; - ID s_setup = rb_intern("setup"); - if (rb_respond_to(mgr, s_setup)) - rb_funcall(mgr, s_setup, 2, canvas, attr); + if (SYMBOL_P(mgr) || NIL_P(mgr)) { + lay->mgr = 0; // internal + if (NIL_P(mgr)) + lay->mgr = Layout_None; + else { + ID mgrid = SYM2ID(mgr); + if (mgrid == rb_intern("Vfl")) + lay->mgr = Layout_VFL; + else if (mgrid == rb_intern("constraints")) + lay->mgr = Layout_Constraints; + else if (mgrid == rb_intern("grid")) + lay->mgr = Layout_Grid; + else { + lay->mgr = Layout_None; + } + } + shoes_layout_internal_setup(lay, cvs, attr); + } else { + // verify class implements required methods + if (!rb_respond_to(mgr, s_setup)) + rb_raise(rb_eArgError, "'setup' not implment in Layout"); + if (!rb_respond_to(mgr, s_addw)) + rb_raise(rb_eArgError, "'add' not implment in Layout"); + if (!rb_respond_to(mgr, s_remove)) + rb_raise(rb_eArgError, "'remove' not implment in Layout"); + if (!rb_respond_to(mgr, s_finish)) + rb_raise(rb_eArgError, "'finish' not implment in Layout"); + if (!rb_respond_to(mgr, s_clear)) + rb_raise(rb_eArgError, "'clear' not implment in Layout"); + if (!rb_respond_to(mgr, s_size)) + rb_raise(rb_eArgError, "'size' not implment in Layout"); + + lay->delegate = mgr; + rb_funcall(mgr, s_setup, 2, canvas, attr); } cvs->layout_mgr = obj; // me - //return cvs; return obj; } @@ -107,9 +150,16 @@ VALUE shoes_layout_delete_at(int argc, VALUE *argv, VALUE self) { rb_parse_args(argc, argv, "i", &args); long pos = NUM2LONG(args.a[0]); VALUE ele = rb_ary_entry(canvas->contents, pos); - ID s_rm = rb_intern("remove"); - if (rb_respond_to(ele, s_rm)) - rb_funcall(ele, s_rm, 0, Qnil); + VALUE ok; + if (lay->delegate) + ok = rb_funcall(lay->delegate, s_remove, 3, canvas_obj, ele, args.a[0]); + else + ok = shoes_layout_internal_delete_at(lay, canvas, ele, pos); + if (! NIL_P(ok)) { + // normal elements respond to 'remove' themselves + if (rb_respond_to(ele, s_remove)) + rb_funcall(ele, s_remove, 0, Qnil); + } return self; } @@ -117,92 +167,195 @@ VALUE shoes_layout_clear(int argc, VALUE *argv, VALUE self) { shoes_layout *lay; Data_Get_Struct(self, shoes_layout, lay); VALUE canvas = lay->canvas; - rb_arg_list args; shoes_canvas_clear_contents(argc, argv, canvas); + return Qnil; +} + +VALUE shoes_layout_style(int argc, VALUE *argv, VALUE self) { + shoes_layout *lay; + Data_Get_Struct(self, shoes_layout, lay); + VALUE canvas = lay->canvas; + shoes_canvas_style(argc, argv, canvas); + return Qtrue; +} + + +VALUE shoes_layout_finish(int argc, VALUE *argv, VALUE self) { + //fprintf(stderr, "shoes_layout_finish called\n"); + shoes_layout *lay; + Data_Get_Struct(self, shoes_layout, lay); + shoes_canvas *canvas; + Data_Get_Struct(lay->canvas, shoes_canvas, canvas); + if (canvas->layout_mgr != Qnil) { + shoes_layout *ly; + Data_Get_Struct(canvas->layout_mgr, shoes_layout, ly); + if (! NIL_P(ly->delegate)) { + VALUE del = ly->delegate; + rb_funcall(del, s_finish, 0); + return Qtrue; + } + } + // here if no delgate or no manager object + shoes_layout_internal_finish(canvas); + return Qtrue; +} + +VALUE shoes_layout_get_height(VALUE self) { + //fprintf(stderr,"shoes_layout_get_height called\n"); + shoes_layout *lay; + Data_Get_Struct(self, shoes_layout, lay); + shoes_canvas *canvas; + Data_Get_Struct(lay->canvas, shoes_canvas, canvas); + return INT2NUM(canvas->height); + } + +VALUE shoes_layout_get_width(VALUE self) { + //fprintf(stderr,"shoes_layout_get_width called\n"); + shoes_layout *lay; + Data_Get_Struct(self, shoes_layout, lay); + shoes_canvas *canvas; + Data_Get_Struct(lay->canvas, shoes_canvas, canvas); + return INT2NUM(canvas->width); +} + + +VALUE shoes_layout_start(int argc, VALUE *argv, VALUE self) { + shoes_layout *lay; + Data_Get_Struct(self, shoes_layout, lay); + shoes_canvas_start(argc, argv, lay->canvas); + return Qtrue; +} + +VALUE shoes_layout_add_rules(int argc, VALUE *argv, VALUE self) { + // TODO: call parse_args once we figure out what it is. + VALUE arg; + if (argc < 1) + arg = Qnil; + else + arg = argv[1]; + shoes_layout *lay; + Data_Get_Struct(self, shoes_layout, lay); + shoes_canvas *canvas; + Data_Get_Struct(lay->canvas, shoes_canvas, canvas); + if (! NIL_P(lay->delegate)) { + ID s_rules = rb_intern("rules"); + if (rb_respond_to(lay->delegate, s_rules)) + rb_funcall(lay->delegate, s_rules, 1, arg); + else + rb_raise(rb_eArgError, "'rules' not implmented in Layout"); + } else { + shoes_layout_internal_rules(lay, canvas, arg); + } + return Qtrue; +} + +// --------------- called from canvas internals ------------ + +void shoes_layout_size(shoes_canvas *canvas, int pass) { + //fprintf(stderr,"shoes_layout_size called\n"); + shoes_layout *lay; + Data_Get_Struct(canvas->layout_mgr, shoes_layout, lay); + if ((canvas->height != lay->cache_h) || (lay->cache_w != canvas->width)) { + lay->cache_h = canvas->height; + lay->cache_w = canvas->width; + } else { + return; + } + // Find a delegate or use the internal internal? + if (lay->delegate != Qnil) { + shoes_canvas *cvs; + Data_Get_Struct(lay->canvas, shoes_canvas, cvs); + VALUE del = lay->delegate; + rb_funcall(lay->delegate, s_size, 2, lay->canvas, INT2NUM(pass)); + } else { + // here if no manager object + shoes_layout_internal_size(lay, canvas, pass); + } + return; +} + + // called from shoes_add_ele (def in canvas.c) by widget creators // The ele has already been added to canvas->contents void shoes_layout_add_ele(shoes_canvas *canvas, VALUE ele) { if (rb_obj_is_kind_of(ele, cBackground)) { - fprintf(stderr, "skipping background widget\n"); + //fprintf(stderr, "skipping background widget\n"); return; } - // Find a delegate or use the internal default? + // Find a delegate or use the internal? if (canvas->layout_mgr != Qnil) { shoes_layout *ly; Data_Get_Struct(canvas->layout_mgr, shoes_layout, ly); - // for debug shoes_canvas *cvs; Data_Get_Struct(ly->canvas, shoes_canvas, cvs); if (! NIL_P(ly->delegate)) { - //printf(stderr,"Delegating\n"); VALUE del = ly->delegate; - ID s_addw = rb_intern("add"); - if (rb_respond_to(del, s_addw)) - rb_funcall(del, s_addw, 2, ly->canvas, ele); - else { - rb_raise( rb_eArgError, "'add' not implment in Layout"); - } + shoes_abstract *widget; + Data_Get_Struct(ele, shoes_abstract, widget); + rb_funcall(del, s_addw, 3, ly->canvas, ele, widget->attr); return; } } // here if no delgate or no manager object - shoes_layout_default_add(canvas, ele); + shoes_layout_internal_add(canvas, ele); return; } // called from inside shoes (shoes_canvas_clear) void shoes_layout_cleared(shoes_canvas *canvas) { - fprintf(stderr,"shoes_layout_clear called\n"); + //fprintf(stderr,"shoes_layout_clear called\n"); if (canvas->layout_mgr != Qnil) { shoes_layout *ly; Data_Get_Struct(canvas->layout_mgr, shoes_layout, ly); if (! NIL_P(ly->delegate)) { - //printf(stderr,"Delegating\n"); VALUE del = ly->delegate; - ID s_clear = rb_intern("clear"); - if (rb_respond_to(del, s_clear)) - rb_funcall(del, s_clear, 0); - else { - rb_raise( rb_eArgError, "'clear' not implment in Layout"); - } + rb_funcall(del, s_clear, 0); return; } } // here if no delgate or no manager object - shoes_layout_default_clear(canvas); + shoes_layout_internal_clear(canvas); return; } + /* - * Methods to call the default layout manager - + * Methods to call the internal layout manager - * Might be a cassawory variant? grid_bag? Something Gtk or Cocoa? */ -void shoes_layout_default_add(shoes_canvas *canvas, VALUE ele) { - fprintf(stderr, "default layout add\n"); + +void shoes_layout_internal_setup(shoes_layout *lay, shoes_canvas *canvas, + VALUE attr) { + if (lay->mgr == Layout_VFL) + fprintf(stderr, "Vfl internal layout setup called\n"); + else + fprintf(stderr, "shoes_layout_internal_setup called\n"); } -void shoes_layout_default_clear(shoes_canvas *canvas) { - fprintf(stderr, "default layout clear\n"); +void shoes_layout_internal_add(shoes_canvas *canvas, VALUE ele) { + fprintf(stderr, "shoes_layout_internal_add called\n"); } -VALUE shoes_layout_add_rule(int argc, VALUE *argv, VALUE self) { - shoes_layout *lay; - Data_Get_Struct(self, shoes_layout, lay); - VALUE cobj = lay->canvas; - shoes_canvas *canvas; - Data_Get_Struct(cobj, shoes_canvas, canvas); +void shoes_layout_internal_clear(shoes_canvas *canvas) { + fprintf(stderr, "shoes_layout_internal_clear called\n"); +} - fprintf(stderr,"shoes_layout_add_rule called\n"); +void shoes_layout_internal_rules(shoes_layout *lay, shoes_canvas *canvas, VALUE arg) { + fprintf(stderr, "shoes_layout_internal_rules called\n"); } -VALUE shoes_layout_finish(int argc, VALUE *argv, VALUE self) { - shoes_layout *lay; - Data_Get_Struct(self, shoes_layout, lay); - VALUE cobj = lay->canvas; - shoes_canvas *canvas; - Data_Get_Struct(cobj, shoes_canvas, canvas); +void shoes_layout_internal_finish(shoes_canvas *canvas) { + fprintf(stderr,"shoes_layout_internal_finish called\n"); +} + +void shoes_layout_internal_size(shoes_layout *lay, shoes_canvas *canvas, int pass) { + fprintf(stderr,"shoes_layout_internal_size called pass: %d\n", pass); +} - fprintf(stderr, "shoes_layout_compute called\n"); +VALUE shoes_layout_internal_delete_at(shoes_layout *lay, shoes_canvas *canvas, + VALUE ele, int pos) { + fprintf(stderr, "shoes_layout_internal_delete_at called\n"); + return Qtrue; } diff --git a/shoes/types/layout.h b/shoes/types/layout.h index 9e6cfa1f..86d47674 100644 --- a/shoes/types/layout.h +++ b/shoes/types/layout.h @@ -1,15 +1,33 @@ #ifndef SHOES_LAYOUT_TYPE_H #define SHOES_LAYOUT_TYPE_H +// C level layouts. Not all are implemented. +typedef enum { + Layout_None, + Layout_Constraints, + Layout_VFL, + Layout_Grid, +} Layout_Types; + typedef struct { - VALUE delegate; + VALUE delegate; // user Written Ruby layout class VALUE canvas; - // fields below belong to the C crafted default layout manager, what ever that + int cache_w; // used to synthesize 'size' event + int cache_h; + // fields below belong to the C crafted layout manager(s), what ever that // turns out to be. - int x; - int y; + Layout_Types mgr; + VALUE fields; // whatever the manager needs it to be. } shoes_layout; +// all drawables do/should implement this at the top - slightly safer +// than deconstructing shoes_canvas for everything. Treat as read-only +typedef struct { + VALUE parent; + VALUE attr; + shoes_place place; +} shoes_abstract; + extern VALUE cLayout; void shoes_layout_init(); VALUE shoes_layout_new(VALUE attr, VALUE parent); @@ -17,16 +35,27 @@ VALUE shoes_layout_new(VALUE attr, VALUE parent); VALUE shoes_layout_insert(int argc, VALUE *argv, VALUE self); VALUE shoes_layout_delete_at(int argc, VALUE *argv, VALUE self); VALUE shoes_layout_clear(int argc, VALUE *argv, VALUE self); -VALUE shoes_layout_refresh(int argc, VALUE *argv, VALUE self); -VALUE shoes_layout_add_rule(int argc, VALUE *argv, VALUE self); +VALUE shoes_layout_add_rules(int argc, VALUE *argv, VALUE self); VALUE shoes_layout_finish(int argc, VALUE *argv, VALUE self); +VALUE shoes_layout_get_height(VALUE self); +VALUE shoes_layout_get_width(VALUE self); +VALUE shoes_layout_start(int argc, VALUE *argv, VALUE self); +VALUE shoes_layout_style(int argc, VALUE *argv, VALUE self); // canvas calls these, delegate to usr or the secret layout +void shoes_layout_size(shoes_canvas *canvas, int pass); void shoes_layout_cleared(shoes_canvas *canvas); void shoes_layout_add_ele(shoes_canvas *canvas, VALUE ele); VALUE shoes_layout_delete_ele(shoes_canvas *canvas, VALUE ele); -// TODO: delagate methods for the secret default manager. -void shoes_layout_default_add(shoes_canvas *canvas, VALUE ele); -void shoes_layout_default_clear(shoes_canvas *canvas); +// TODO: delegate methods for the future internal manager(s). +void shoes_layout_internal_setup(shoes_layout *lay, shoes_canvas *canvas, + VALUE attr); +void shoes_layout_internal_add(shoes_canvas *canvas, VALUE ele); +VALUE shoes_layout_internal_delete_at(shoes_layout *lay, shoes_canvas *canvas, + VALUE ele, int pos); +void shoes_layout_internal_clear(shoes_canvas *canvas); +void shoes_layout_internal_size(shoes_layout *lay, shoes_canvas *canvas, int pass); +void shoes_layout_internal_finish(shoes_canvas *canvas); +void shoes_layout_internal_rules(shoes_layout *lay, shoes_canvas *canvas, VALUE arg); #endif diff --git a/shoes/types/native.c b/shoes/types/native.c index c1453e89..d18e1977 100644 --- a/shoes/types/native.c +++ b/shoes/types/native.c @@ -9,9 +9,12 @@ CLASS_COMMON(control); EVENT_COMMON(control, control, click); EVENT_COMMON(control, control, change); -// TODO: May need to refactor all types depending on native to use either types/native_{.c,.h} or types/native/{.c,.h}. That would be proper etiquette. For now, just using shoes_0_native_type_init(). +/* TODO: May need to refactor all types depending on native to use either +* types/native_{.c,.h} or types/native/{.c,.h}. That would be +* proper etiquette. For now, just using shoes_0_native_type_init(). +*/ -// Many types depend on native, so initialization needs to be triggered first. +// Many widgets depend on cNative, so initialization needs to be triggered first. void shoes_0_native_type_init() { cNative = rb_define_class_under(cTypes, "Native", rb_cObject);