From 943ba9d35d93eef5578ed1eb1b7dfdc375f22b29 Mon Sep 17 00:00:00 2001 From: Cecil Date: Fri, 23 Nov 2018 20:48:19 -0700 Subject: [PATCH] big batch of changes for #410 * cassowary-ruby gem may be working correctly - it's hard to KNOW can use vfl_parser * native cassowary (emeus) is not working - but now I have something to compare with. --- Tests/layout/{l3.rb => cas1.rb} | 6 +- Tests/layout/cas2.rb | 33 ++ Tests/layout/cas3.rb | 31 ++ Tests/layout/cas4.rb | 25 + Tests/layout/grid.rb | 89 ++++ Tests/layout/vfl2.rb | 66 --- Tests/layout/vfl3.rb | 32 +- Tests/layout/vfl4.rb | 34 ++ lib/layout/cassowary.rb | 231 +++++++++ make/linux/minlin/env.rb | 1 + .../layout/emeus-constraint-layout-private.h | 14 +- shoes/layout/emeus-constraint-layout.c | 462 ++++-------------- shoes/layout/emeus-constraint-layout.h | 33 +- shoes/layout/shoes-vfl-parser.c | 3 +- shoes/layout/shoes-vfl.c | 278 ++++++++++- shoes/layout/shoes-vfl.h | 13 +- shoes/types/layout.c | 5 +- 17 files changed, 853 insertions(+), 503 deletions(-) rename Tests/layout/{l3.rb => cas1.rb} (98%) create mode 100644 Tests/layout/cas2.rb create mode 100644 Tests/layout/cas3.rb create mode 100644 Tests/layout/cas4.rb create mode 100644 Tests/layout/grid.rb delete mode 100644 Tests/layout/vfl2.rb create mode 100644 Tests/layout/vfl4.rb create mode 100644 lib/layout/cassowary.rb diff --git a/Tests/layout/l3.rb b/Tests/layout/cas1.rb similarity index 98% rename from Tests/layout/l3.rb rename to Tests/layout/cas1.rb index f3279c28..60a72d74 100644 --- a/Tests/layout/l3.rb +++ b/Tests/layout/cas1.rb @@ -89,7 +89,7 @@ def size(canvas, pass) #@rl_stay = @solver.add_constraint(@right_limit, Strength::RequiredStrength) #@solver.add_constraint(@rl_stay) @solver.solve - self.finish + self.finish(nil) end end @@ -114,7 +114,7 @@ def rules(arg) $stderr.puts "callback rules #{arg}" end - def finish() + def finish(arg) @widgets.each_pair do |k, widget| left = widget.left top = widget.top @@ -189,7 +189,7 @@ def method_missing(meth, *args, &block) # string b3 is at the bottom ? @ml.add_constraint(@ml.var('b3-top').cn_equal 100) - @lay.finish + @lay.finish(nil) @p.text = @lay.inspect end end diff --git a/Tests/layout/cas2.rb b/Tests/layout/cas2.rb new file mode 100644 index 00000000..6c38af21 --- /dev/null +++ b/Tests/layout/cas2.rb @@ -0,0 +1,33 @@ +require 'layout/cassowary' + +Shoes.app width: 500, height: 400, resizeable: true do + stack do + para "Test vfl parser" + @cls = CassowaryLayout.new() + @lay = layout use: @cls, width: 450, height: 300 do + background cornsilk + para "OverConstrained", name: 'para1' + edit_line "one", name: 'el1' + button "two", name: 'but1' + button "three", name: "but2" + button "four", name: "but3" + end + @lay.start { + metrics = { + padding: 80.7 + } + lines = [ + "H:|-[para1(but1)]-[but1]-|", + "H:|-[el1(but2)]-[but2]-|", + "H:[but3(but2)]-|", + "V:|-[para1(el1)]-[el1]-|", + "V:|-[but1(but2,but3)]-[but2]-[but3]-|" + ] + if @lay.vfl_parse lines: lines, views: @cls.contents, metrics: metrics + constraints = @lay.vfl_constraints + @lay.finish constraints + end + } + end + para "After layout" +end diff --git a/Tests/layout/cas3.rb b/Tests/layout/cas3.rb new file mode 100644 index 00000000..38254855 --- /dev/null +++ b/Tests/layout/cas3.rb @@ -0,0 +1,31 @@ +require 'layout/cassowary' + +Shoes.app width: 350, height: 400, resizeable: true do + stack do + para "Test vfl parser" + @cls = CassowaryLayout.new() + @lay = layout use: @cls, width: 300, height: 300 do + background cornsilk + edit_line "one", name: 'el1' + button "two", name: 'but1' + end + @lay.start { + metrics = { + padding: 8 + } + lines = [ + '[but1]-[el1]' + ] + if false + cs = @cls.var('el1','start').cn_equal (@cls.var('but1','end')) + puts cs.inspect + @lay.finish([cs]) + else + @lay.vfl_parse lines: lines, views: @cls.contents, metrics: metrics + constraints = @lay.vfl_constraints + @lay.finish constraints + end + } + end + para "After layout" +end diff --git a/Tests/layout/cas4.rb b/Tests/layout/cas4.rb new file mode 100644 index 00000000..f585b274 --- /dev/null +++ b/Tests/layout/cas4.rb @@ -0,0 +1,25 @@ +require 'layout/cassowary' + +Shoes.app width: 350, height: 400, resizeable: true do + stack do + para "Test vfl parser" + @cls = CassowaryLayout.new() + @lay = layout use: @cls, width: 300, height: 300 do + background cornsilk + edit_line "one", name: 'el1' + button "two", name: 'but1' + end + @lay.start { + metrics = { + padding: 25 + } + lines = [ + 'V:|-[but1]-[el1]|' + ] + @lay.vfl_parse lines: lines, views: @cls.contents, metrics: metrics + constraints = @lay.vfl_constraints + @lay.finish constraints + } + end + para "After layout" +end diff --git a/Tests/layout/grid.rb b/Tests/layout/grid.rb new file mode 100644 index 00000000..93585464 --- /dev/null +++ b/Tests/layout/grid.rb @@ -0,0 +1,89 @@ +# Tests/layout/l4.rb - grid layout + +class GridLayout + + attr_accessor :ncol, :nrow, :colsz, :rowsz, :widgets, :hpad, :vpad + + def initialize(attr = {}) + @ncol = 0 + @nrow = 0 + @colsz = 0 + @rowsz = 0 + @widgets = [] + @hpad = attr[:hpad] ? attr[:hpad] : 1 + @vpad = attr[:vpad] ? attr[:vpad] : 1 + end + + def setup(canvas, attr) + end + + def add(canvas, ele, attr) + col = attr[:col] ? attr[:col]-1 : 0 + row = attr[:row] ? attr[:row]-1 : 0 + rspan = attr[:rspan] + cspan = attr[:cspan] + @ncol = [@ncol, col + (cspan ? cspan : 1)].max + @nrow = [@nrow, row + (rspan ? rspan : 1)].max + widgets << {ele: ele, col: col, row: row, cspan: cspan, rspan: rspan} + end + + def remove + end + + def clear + end + + def size (canvas, pass) + return if pass == 0 + @rowsz = (canvas.height / @nrow).to_i + @colsz = (canvas.width / @ncol).to_i + @widgets.each do |entry| + x = entry[:col] * @colsz + @hpad + y = entry[:row] * @rowsz + @vpad + widget = entry[:ele] + widget.move(x, y) + if entry[:cspan] + w = entry[:cspan] * @colsz - @hpad + if widget.width != w + widget.style width: w + end + end + if entry[:rspan] + h = entry[:rspan] * @rowsz - @vpad + if widget.height != h + widget.style height: h + end + end + end + end + + def finish + end + +end + +Shoes.app width: 400, height: 400 do + stack do + para "Before Grid" + grid = GridLayout.new vpad: 5, hpad: 3 + @lay = layout use: grid, width: 300, height: 305 do + background aliceblue + button "one", col: 1, row: 1, cspan: 2, rspan: 1 + button "two", col: 3, row: 1, cspan: 2, rspan: 2 + para "Long String of characters", col: 2, row: 5, cspan: 2 + button "three", col: 2, row: 3, cspan: 1 + svg "#{DIR}/samples/good/paris.svg", width: 10, height: 10, col: 3, row: 3, rspan: 2, + cspan: 3 + image "http://shoesrb.com/img/shoes-icon.png", row: 5, col: 4, cspan: 2, rspan: 2 + edit_line "foobar", row: 7, col: 1, cspan: 2 + end + flow do + button "+" do + @lay.style width: (@lay.width * 1.1).to_i + end + button "-" do + @lay.style width: (@lay.width * 0.9).to_i + end + end + end +end diff --git a/Tests/layout/vfl2.rb b/Tests/layout/vfl2.rb deleted file mode 100644 index 48224ca4..00000000 --- a/Tests/layout/vfl2.rb +++ /dev/null @@ -1,66 +0,0 @@ -class Sample - attr_accessor :widgets, :canvas - - def initialize() - @widgets = {} - end - - def setup(canvas, attr) - @canvas = canvas - end - - def add(canvas, widget, attrs) - name = attrs && attrs[:name] - @widgets[name] = widget - end - - def contents - return @widgets - end - - def remove(canvas, widget, pos) - return true - end - - def size(canvas, pass) - end - - def clear() - end - - def finish() - end -end - -Shoes.app width: 350, height: 400, resizeable: true do - stack do - para "Test vfl parser" - @cls = Sample.new() - @lay = layout use: @cls, width: 300, height: 300 do - para "OverConstrained", name: 'para1' - edit_line "one", name: 'el1' - button "two", name: 'but1' - button "three", name: "but2" - button "four", name: "but3" - end - @lay.start { - metrics = { - el1: 80.7, # what does this mean? - } - lines = [ - "H:|-[para1(but1)]-[but1]-|", - "H:|-[el1(but2)]-[but2]-|", - "H:[but3(but2)]-|", - "V:|-[para1(el1)]-[el1]-|", - "V:|-[but1(but2,but3)]-[but2]-[but3]-|" - ] - if @lay.vfl_parse lines: lines, views: @cls.contents, metrics: metrics - constraints = @lay.vfl_constraints - # display only! - constraints.each { |c| $stderr.puts c.inspect } - @lay.finish constraints - end - } - end - para "After layout" -end diff --git a/Tests/layout/vfl3.rb b/Tests/layout/vfl3.rb index fd55acdb..d3115721 100644 --- a/Tests/layout/vfl3.rb +++ b/Tests/layout/vfl3.rb @@ -1,34 +1,30 @@ + Shoes.app width: 350, height: 400, resizeable: true do stack do - para "Vfl layout" + para "Test vfl parser" + @lay = layout use: :Vfl, width: 300, height: 300 do - para "OverConstrained", name: 'para1' edit_line "one", name: 'el1' button "two", name: 'but1' - button "three", name: "but2" - button "four", name: "but3" end @lay.start { metrics = { - 'padding' => 10 + padding: 8 } lines = [ - "H:|-[para1(but1)]-[but1]-|", - "H:|-[el1(but2)]-[but2]-|", - "H:[but3(but2)]-|", - "V:|-[para1(el1)]-[el1]-|", - "V:|-[but1(but2,but3)]-[but2]-[but3]-|" + '|[but1]-[el1]|' ] - if @lay.vfl_parse lines: lines, metrics: metrics - constraints = @lay.vfl_constraints #true # true produces hash - # display purposes only? - #constraints.each { |c| $stderr.puts c.inspect } - #@lay.vfl_append constraints[10] + if false + cs = @cls.var('el1','start').cn_equal (@cls.var('but1','width')) + puts cs.inspect + @lay.finish([cs]) + else + @lay.vfl_parse lines: lines, views: @cls.contents, metrics: metrics + constraints = @lay.vfl_constraints @lay.finish constraints end } - end - #cs = Shoes::Constraint.new 'but1','width', 'eq', 'but3', 'width', 1, 8.0, 1001001000 - #para "#{cs.inspect}" + end + para "After layout" end diff --git a/Tests/layout/vfl4.rb b/Tests/layout/vfl4.rb new file mode 100644 index 00000000..fd55acdb --- /dev/null +++ b/Tests/layout/vfl4.rb @@ -0,0 +1,34 @@ + +Shoes.app width: 350, height: 400, resizeable: true do + stack do + para "Vfl layout" + @lay = layout use: :Vfl, width: 300, height: 300 do + para "OverConstrained", name: 'para1' + edit_line "one", name: 'el1' + button "two", name: 'but1' + button "three", name: "but2" + button "four", name: "but3" + end + @lay.start { + metrics = { + 'padding' => 10 + } + lines = [ + "H:|-[para1(but1)]-[but1]-|", + "H:|-[el1(but2)]-[but2]-|", + "H:[but3(but2)]-|", + "V:|-[para1(el1)]-[el1]-|", + "V:|-[but1(but2,but3)]-[but2]-[but3]-|" + ] + if @lay.vfl_parse lines: lines, metrics: metrics + constraints = @lay.vfl_constraints #true # true produces hash + # display purposes only? + #constraints.each { |c| $stderr.puts c.inspect } + #@lay.vfl_append constraints[10] + @lay.finish constraints + end + } + end + #cs = Shoes::Constraint.new 'but1','width', 'eq', 'but3', 'width', 1, 8.0, 1001001000 + #para "#{cs.inspect}" +end diff --git a/lib/layout/cassowary.rb b/lib/layout/cassowary.rb new file mode 100644 index 00000000..a68a1cb3 --- /dev/null +++ b/lib/layout/cassowary.rb @@ -0,0 +1,231 @@ +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, :rl_stay, :hl_stay, + :ready, :canvas_w, :canvas_h + + def initialize() + #$stderr.puts "initialized" + @widgets = {} + @solver = SimplexSolver.new + # @attrs[name][attr] = Variable for name.attr + @attrs = {} + @ready = false + end + + + # canvas may 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] + end + if (attr && attr[:height]) + hgt = attr[:height] + end + vars = {} + vars['start'] = Variable.new(name: 'super.start', value: 0.0) + vars['width'] = Variable.new(name: 'super.width', value: wid) + vars['top'] = Variable.new(name: "super.top", value: 0.0) + vars['height'] = Variable.new(name: "super.height", value: hgt) + vars['end'] = Variable.new(name: "super.end", value: wid) + vars['bottom'] = Variable.new(name: "super.bottom", value: hgt) + @attrs['super'] = vars + @left_limit = vars['start'] + @right_limit = vars['end'] + @top_limit = vars['top'] + @height_limit = vars['bottom'] + @rl_stay = @solver.add_stay(@right_limit) + @hl_stay = @solver.add_stay(@height_limit) + $stderr.puts "callback: setup #{wid} X #{hgt}" + end + + def contents + @widgets + end + + def var(n,a) + @attrs[n][a] + end + + def solver + @solver + end + + # callback from Shoes to notify addition of widget to layout. + # widget is not on-screen and allocated at this time. Pity + # DO NOT enumerate attrs hash - a crash if you try. + def add(canvas, widget, attrs) + name = attrs && attrs[:name] + $stderr.puts "callback add: #{name} #{widget.class} #{canvas.contents.size}" + if name + @widgets[name] = widget + # create Cassowary Variables for Shoes element + vars = {} + vars['start'] = Variable.new(name: "#{name}.start", value: 0) + vars['end'] = Variable.new(name: "#{name}.end", value: 0) + vars['width'] = Variable.new(name: "#{name}.width", value: 0) + vars['top'] = Variable.new(name: "#{name}.top", value: 0) + vars['bottom'] = Variable.new(name: "#{name}.bottom", value: 0) + vars['height'] = Variable.new(name: "#{name}.height", value: 0) + @attrs[name] = vars + end + end + + def remove(canvas, widget, pos) + $stderr.puts"callback: remove" + return true + end + + # add a constraint (of the hash variety from an emeus vlf_parse) + # TODO: multiplier is this correct? Seems OK, but... + # TODO: is constant correct? Seems OK, but... + # TODO: convert start to left, end to right? affects add() method + def add_cs(h) + $stderr.puts h.inspect + ## convert hash to Cassowary::Constraint and add to solver + tgt = h[:view1] + tgta = h[:attr1] + rel = h[:relation] + src = h[:view2] + srca = h[:attr2] + cons = h[:constant] + mult = h[:multiplier] + strength = h[:strength] + $stderr.puts "#{tgt}.#{tgta} #{rel} #{src}.#{srca} #{cons} #{mult} #{strength}" + t = @attrs[tgt][tgta] + if src + s = @attrs[src][srca] + else + s = 0 + end + stg = nil + case strength + when "required" + stg = Strength::RequiredStrength + when "strong" + stg = Strength::StrongStrength + when "medium" + stg = Strength::MediumStrength + when "weak" + stg = Strength::WeakStrength + end + cn = nil + case rel + when "EQ" + cn = (t * mult).cn_equal (s + cons), stg + when "GE" + cn = (t * mult).cn_geq (s + cons), stg + when "LE" + cn = (t * mult).cn_leq (s + cons), stg + end + $stderr.puts "#{cn.inspect}" + @solver.add_constraint(cn) + end + + + def size(canvas, pass) + if pass == 0 + return + else + $stderr.puts "callback: size Change! w: #{canvas.width} h:#{canvas.height}" + # reset stays for new window size + @solver.remove_constraint(@rl_stay) if @ready + @right_limit.value = canvas.width + @rl_stay = @solver.add_stay(@right_limit, Strength::RequiredStrength) + @solver.remove_constraint(@hl_stay) if ready + @height_limit.value = canvas.height + @solver.add_stay(@height_limit, Strength::RequiredStrength) + self.move_widgets if @ready + end + end + + + def move_widgets + @widgets.each_pair do |k, widget| + l = widget.left + t = widget.top + h = widget.height + w = widget.width + $stderr.puts "#{k} #{widget.inspect} from #{l},#{t},#{w},#{h}" + puts @attrs.inspect + + left = @attrs[k]['start'].value.to_i + top = @attrs[k]['top'].value.to_i + e = @attrs[k]['end'].value.to_i + width = @attrs[k]['width'].value.to_i + height = @attrs[k]['height'].value.to_i + b = @attrs[k]['bottom'].value.to_i + $stderr.puts "move to #{left}, #{top} for w:#{width}|#{e-left} h:#{height}|#{b-top}" + widget.style width: width, height: height + widget.move(left, top) + + end + end + + def resize(w, h) + end + + def clear() + $stderr.puts "callback: clear" + end + + def rules(arg) + $stderr.puts "callback rules #{arg}" + end + + # does the heavy work. Constraint arguments can be + # the hash type from vfl_parse or painfully handcrafted + def finish(constraints) + $stderr.puts "callback finish" + # move initial widget settings to Solver Variables. + @widgets.each_pair do |nm, ele| + left = ele.left + top = ele.top + height = ele.height + width = ele.width + $stderr.puts "\n#{nm} #{ele.inspect} from #{left},#{top},#{width},#{height}" + # update Solver Vars with real settings + vars = @attrs[nm] + vars['start'].value = ele.left + vars['top'].value = ele.top + vars['width'].value = ele.width + vars['height'].value = ele.height + vars['bottom'].value = ele.top + ele.height + vars['end'].value = ele.left + ele.width + + $stderr.puts "Setting #{nm}: #{vars.inspect}" + # need all 3 to get horizontal mostly correct + @solver.add_constraint(vars['start'].cn_geq @attrs['super']['start'], Strength::RequiredStrength) + @solver.add_constraint(vars['width'].cn_geq width) + @solver.add_constraint(vars['width'].cn_equal vars['end'] - vars['start'] , Strength::RequiredStrength) + # need all 3 to get vertical mostly correct + @solver.add_constraint(vars['top'].cn_geq @attrs['super']['top'], Strength::RequiredStrength) + @solver.add_constraint(vars['height'].cn_geq height) + @solver.add_constraint(vars['height'].cn_equal vars['bottom'] - vars['top'] , Strength::RequiredStrength) + end + puts "\nAdd constraints #{@attrs.inspect}" + # add the constraints + if constraints + constraints.each do |c| + if c.class == Cassowary::LinearEquation + # handcrafted cassowary-ruby style + @solver.add_constraint(c) + else + self.add_cs(c) + end + end + end + @ready = true + $stderr.puts "\nSolving..." + @solver.solve + self.move_widgets + end + +end diff --git a/make/linux/minlin/env.rb b/make/linux/minlin/env.rb index a918526b..4439c977 100644 --- a/make/linux/minlin/env.rb +++ b/make/linux/minlin/env.rb @@ -17,6 +17,7 @@ LINUX_CFLAGS << " -DRUBY_HTTP" LINUX_CFLAGS << " -DRUBY_1_9" #LINUX_CFLAGS << " -DSZBUG" +LINUX_CFLAGS << " -DEMEUS_ENABLE_DEBUG" LINUX_CFLAGS << " -DDEBUG" if ENV['DEBUG'] LINUX_CFLAGS << " -DSHOES_GTK -fPIC -shared -Wno-unused-but-set-variable" # Following line may need handcrafting diff --git a/shoes/layout/emeus-constraint-layout-private.h b/shoes/layout/emeus-constraint-layout-private.h index b2b11e83..b9d3aad0 100644 --- a/shoes/layout/emeus-constraint-layout-private.h +++ b/shoes/layout/emeus-constraint-layout-private.h @@ -27,7 +27,9 @@ G_BEGIN_DECLS struct _EmeusConstraintLayoutChild { //GtkBin parent_instance; - GshoesEle *parent_instance; + GObject parent_instance; + + GshoesEle *widget; /* An optional name for the child, to be used when building * constraints from string descriptions @@ -69,9 +71,13 @@ struct _EmeusConstraintLayoutChild struct _EmeusConstraintLayout { //GtkContainer parent_instance; - void * parent_instance; // points to shoes_layout struct - - GSequence *children; + GObject parent_instance; + shoes_layout *sh_layout; // points to shoes_layout struct + gboolean setup; + + GList *parsed_constraints; // from load. Shoes can get them. + + GSequence *children; // of EmeusConstraintLayoutChild NOT Gtk-Bin SimplexSolver solver; diff --git a/shoes/layout/emeus-constraint-layout.c b/shoes/layout/emeus-constraint-layout.c index b516df28..05976ba6 100644 --- a/shoes/layout/emeus-constraint-layout.c +++ b/shoes/layout/emeus-constraint-layout.c @@ -177,7 +177,7 @@ */ #include "config.h" - +#include "shoes/layout/shoes-vfl.h" #include "emeus-constraint-layout-private.h" #include "emeus-constraint-private.h" @@ -192,7 +192,7 @@ enum { CHILD_PROP_NAME = 1, - + CHILD_PROP_ELEMENT, CHILD_N_PROPS }; @@ -253,7 +253,7 @@ emeus_constraint_layout_destroy (GshoesEle *widget) //GTK_WIDGET_CLASS (emeus_constraint_layout_parent_class)->destroy (widget); } -static Variable * +Variable * get_layout_attribute (EmeusConstraintLayout *layout, EmeusConstraintAttribute attr) { @@ -378,7 +378,7 @@ get_layout_attribute (EmeusConstraintLayout *layout, return res; } -static Variable * +extern Variable * get_child_attribute (EmeusConstraintLayoutChild *child, EmeusConstraintAttribute attr) { @@ -545,6 +545,12 @@ add_layout_stays (EmeusConstraintLayout *self) simplex_solver_add_stay_variable (&self->solver, var, STRENGTH_WEAK); } +/* + * TODO CJC: This may not need to be called by Shoes. But, if it was, + * setup() phase would be the time to do it. + * Gtk discussion: By adding the temp stay(s) the solver (re)computes + * layout(s) which is returned. Then the stays are removed. (which recomputes) +*/ #if 0 static void emeus_constraint_layout_get_preferred_size (EmeusConstraintLayout *self, @@ -619,7 +625,8 @@ emeus_constraint_layout_get_preferred_size (EmeusConstraintLayout *self, if (natural_p != NULL) *natural_p = value; } - +#endif +#if 0 static void emeus_constraint_layout_get_preferred_width (GtkWidget *widget, int *minimum_p, @@ -665,16 +672,23 @@ emeus_constraint_layout_get_preferred_height_for_width (GtkWidget *widget, width, minimum_p, natural_p); } - -static void -emeus_constraint_layout_size_allocate (GtkWidget *widget, - GtkAllocation *allocation) +#endif +/* + * Shoes calls this at size() time with real values for height and width + */ +//static void +//emeus_constraint_layout_size_allocate (GtkWidget *widget, +// GtkAllocation *allocation) +void +emeus_constraint_layout_size_allocate (EmeusConstraintLayout *self, + int canvas_width, + int canvas_height) { - EmeusConstraintLayout *self = EMEUS_CONSTRAINT_LAYOUT (widget); + //EmeusConstraintLayout *self = EMEUS_CONSTRAINT_LAYOUT (widget); Constraint *stay_x, *stay_y; Constraint *stay_w, *stay_h; - gtk_widget_set_allocation (widget, allocation); + //gtk_widget_set_allocation (widget, allocation); if (g_sequence_is_empty (self->children)) return; @@ -684,16 +698,20 @@ emeus_constraint_layout_size_allocate (GtkWidget *widget, Variable *layout_width = get_layout_attribute (self, EMEUS_CONSTRAINT_ATTRIBUTE_WIDTH); Variable *layout_height = get_layout_attribute (self, EMEUS_CONSTRAINT_ATTRIBUTE_HEIGHT); - variable_set_value (layout_left, allocation->x); + //variable_set_value (layout_left, allocation->x); + variable_set_value (layout_left, 0); stay_x = simplex_solver_add_stay_variable (&self->solver, layout_left, STRENGTH_REQUIRED); - variable_set_value (layout_top, allocation->y); + //variable_set_value (layout_top, allocation->y); + variable_set_value (layout_top, 0); stay_y = simplex_solver_add_stay_variable (&self->solver, layout_top, STRENGTH_REQUIRED); - variable_set_value (layout_width, allocation->width); + //variable_set_value (layout_width, allocation->width); + variable_set_value (layout_width, canvas_width); stay_w = simplex_solver_add_stay_variable (&self->solver, layout_width, STRENGTH_REQUIRED); - variable_set_value (layout_height, allocation->height); + //variable_set_value (layout_height, allocation->height); + variable_set_value (layout_height, canvas_height); stay_h = simplex_solver_add_stay_variable (&self->solver, layout_height, STRENGTH_REQUIRED); #ifdef EMEUS_ENABLE_DEBUG @@ -713,8 +731,8 @@ emeus_constraint_layout_size_allocate (GtkWidget *widget, Variable *top, *left, *width, *height; Variable *center_x, *center_y; Variable *baseline; - GtkAllocation child_alloc; - GtkRequisition minimum; + //GtkAllocation child_alloc; + //GtkRequisition minimum; child = g_sequence_get (iter); iter = g_sequence_iter_next (iter); @@ -741,7 +759,7 @@ emeus_constraint_layout_size_allocate (GtkWidget *widget, variable_get_value (center_x), variable_get_value (center_y), variable_get_value (baseline))); #endif - +#if 0 gtk_widget_get_preferred_size (GTK_WIDGET (child), &minimum, NULL); child_alloc.x = floor (variable_get_value (left)); @@ -754,6 +772,27 @@ emeus_constraint_layout_size_allocate (GtkWidget *widget, : minimum.height; gtk_widget_size_allocate (GTK_WIDGET (child), &child_alloc); +#else + // shoes: + int x,y,wid,hgt; + shoes_abstract *ab; + VALUE abv = (VALUE)gshoes_ele_get_element(child->widget); + Data_Get_Struct(abv, shoes_abstract, ab); + //variable_set_value(top, ab->place.y); + //variable_set_value(left, ab->place.x); + //variable_set_value(width, ab->place.w); + //variable_set_value(height, ab->place.h); + x = floor (variable_get_value (left)); + y = floor (variable_get_value (top)); + wid = variable_get_value (width) > ab->place.w + ? ceil (variable_get_value (width)) + : ab->place.w; + hgt = variable_get_value (height) > ab->place.h + ? ceil (variable_get_value (height)) + : ab->place.h; + // call into shoes-vfl.c to do the Shoes work + shoes_vfl_change_pos(child->widget, x, y, wid, hgt); +#endif } simplex_solver_remove_constraint (&self->solver, stay_x); @@ -762,6 +801,7 @@ emeus_constraint_layout_size_allocate (GtkWidget *widget, simplex_solver_remove_constraint (&self->solver, stay_h); } +#if 0 static gboolean emeus_constraint_layout_draw (GtkWidget *widget, cairo_t *cr) @@ -935,355 +975,7 @@ typedef struct { double constant; double multiplier; } ConstraintData; -#if 0 - -typedef struct { - GObject *object; - GtkBuilder *builder; - GSList *items; -} SubParserData; - -static void -constraint_data_free (gpointer _data) -{ - ConstraintData *data = _data; - - if (data == NULL) - return; - - g_free (data->source_name); - g_free (data->source_attr); - g_free (data->target_name); - g_free (data->target_attr); - g_free (data->relation); - g_free (data->strength); - - g_slice_free (ConstraintData, data); -} - -/* Taken from gtk+/gtk/gtkbuilder.c */ -static gboolean -_gtk_builder_enum_from_string (GType type, - const gchar *string, - gint *enum_value, - GError **error) -{ - GEnumClass *eclass; - GEnumValue *ev; - gchar *endptr; - gint value; - gboolean ret; - - g_return_val_if_fail (G_TYPE_IS_ENUM (type), FALSE); - g_return_val_if_fail (string != NULL, FALSE); - - ret = TRUE; - - endptr = NULL; - errno = 0; - value = g_ascii_strtoull (string, &endptr, 0); - if (errno == 0 && endptr != string) /* parsed a number */ - *enum_value = value; - else - { - eclass = g_type_class_ref (type); - ev = g_enum_get_value_by_name (eclass, string); - if (!ev) - ev = g_enum_get_value_by_nick (eclass, string); - - if (ev) - *enum_value = ev->value; - else - { - g_set_error (error, - GTK_BUILDER_ERROR, - GTK_BUILDER_ERROR_INVALID_VALUE, - "Could not parse enum: '%s'", - string); - ret = FALSE; - } - g_type_class_unref (eclass); - } - - return ret; -} - -static bool -parse_double (const char *string, - double *value_p, - double default_value) -{ - double value; - char *endptr; - - if (string == NULL) - { - *value_p = default_value; - return false; - } - - errno = 0; - value = g_ascii_strtod (string, &endptr); - if (errno == 0 && endptr != string) - { - *value_p = value; - return true; - } - - *value_p = default_value; - - return false; -} - -static EmeusConstraint * -constraint_data_to_constraint (const ConstraintData *data, - GtkBuilder *builder, - GError **error) -{ - gpointer source, target; - int source_attr, target_attr; - int relation, strength; - gboolean res; - - if (g_strcmp0 (data->source_name, "super") == 0) - source = NULL; - else if (data->source_name == NULL) - { - if (data->source_attr != NULL) - { - g_set_error (error, GTK_BUILDER_ERROR, - GTK_BUILDER_ERROR_INVALID_VALUE, - "Constraints without 'source-object' must also not " - "have a 'source-attr' attribute"); - return NULL; - } - - source = NULL; - } - else - source = gtk_builder_get_object (builder, data->source_name); - - if (g_strcmp0 (data->target_name, "super") == 0) - target = NULL; - else - { - target = gtk_builder_get_object (builder, data->target_name); - - if (target == NULL) - { - g_set_error (error, GTK_BUILDER_ERROR, - GTK_BUILDER_ERROR_INVALID_VALUE, - "Unable to find target '%s' for constraint", - data->target_name); - return NULL; - } - } - - if (data->source_attr != NULL) - { - res = _gtk_builder_enum_from_string (EMEUS_TYPE_CONSTRAINT_ATTRIBUTE, - data->source_attr, - &source_attr, - error); - if (!res) - return NULL; - } - else - source_attr = EMEUS_CONSTRAINT_ATTRIBUTE_INVALID; - - res = _gtk_builder_enum_from_string (EMEUS_TYPE_CONSTRAINT_ATTRIBUTE, - data->target_attr, - &target_attr, - error); - if (!res) - return NULL; - - if (data->relation != NULL) - { - res = _gtk_builder_enum_from_string (EMEUS_TYPE_CONSTRAINT_RELATION, - data->relation, - &relation, - error); - if (!res) - return NULL; - } - else - relation = EMEUS_CONSTRAINT_RELATION_EQ; - - if (data->strength != NULL) - { - res = _gtk_builder_enum_from_string (EMEUS_TYPE_CONSTRAINT_STRENGTH, - data->strength, - &strength, - error); - } - else - strength = EMEUS_CONSTRAINT_STRENGTH_REQUIRED; - - return emeus_constraint_new (target, target_attr, - relation, - source, source_attr, - data->multiplier, - data->constant, - strength); -} - -static void -constraints_free (gpointer data) -{ - g_slist_free_full (data, constraint_data_free); -} - -static void -constraint_layout_start_element (GMarkupParseContext *context, - const gchar *element_name, - const gchar **names, - const gchar **values, - gpointer user_data, - GError **error) -{ - SubParserData *data = user_data; - - if (strcmp (element_name, TAG_CONSTRAINT) == 0) - { - const char *source_name, *source_attr; - const char *target_name, *target_attr; - const char *relation, *strength; - const char *multiplier, *constant; - ConstraintData *cdata; - - if (!g_markup_collect_attributes (element_name, names, values, error, - G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, ATTR_SOURCE_OBJECT, &source_name, - G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, ATTR_SOURCE_ATTR, &source_attr, - G_MARKUP_COLLECT_STRING, ATTR_TARGET_OBJECT, &target_name, - G_MARKUP_COLLECT_STRING, ATTR_TARGET_ATTR, &target_attr, - G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, ATTR_RELATION, &relation, - G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, ATTR_STRENGTH, &strength, - G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, ATTR_MULTIPLIER, &multiplier, - G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, ATTR_CONSTANT, &constant, - G_MARKUP_COLLECT_INVALID)) - { - return; - } - - cdata = g_slice_new (ConstraintData); - cdata->source_name = g_strdup (source_name); - cdata->source_attr = g_strdup (source_attr); - cdata->target_name = g_strdup (target_name); - cdata->target_attr = g_strdup (target_attr); - cdata->relation = g_strdup (relation); - cdata->strength = g_strdup (strength); - parse_double (multiplier, &cdata->multiplier, 1.0); - parse_double (constant, &cdata->constant, 0.0); - - data->items = g_slist_prepend (data->items, cdata); - } -} - -static const GMarkupParser constraint_layout_parser = { - constraint_layout_start_element -}; - -static gboolean -emeus_constraint_layout_buildable_custom_tag_start (GtkBuildable *buildable, - GtkBuilder *builder, - GObject *child, - const gchar *tagname, - GMarkupParser *parser, - gpointer *parser_data) -{ - if (parent_buildable_iface->custom_tag_start (buildable, builder, child, tagname, parser, parser_data)) - return TRUE; - - if (strcmp (tagname, TAG_CONSTRAINTS) == 0) - { - SubParserData *data; - - data = g_slice_new0 (SubParserData); - data->items = NULL; - data->object = G_OBJECT (buildable); - data->builder = builder; - - *parser = constraint_layout_parser; - *parser_data = data; - - return TRUE; - } - - return FALSE; -} - -static void -emeus_constraint_layout_buildable_custom_finished (GtkBuildable *buildable, - GtkBuilder *builder, - GObject *child, - const gchar *tagname, - gpointer user_data) -{ - parent_buildable_iface->custom_finished (buildable, builder, child, tagname, user_data); - - if (strcmp (tagname, TAG_CONSTRAINTS) == 0) - { - SubParserData *data = user_data; - - g_object_set_qdata_full (G_OBJECT (buildable), quark_buildable_constraints, - data->items, - constraints_free); - - g_slice_free (SubParserData, data); - } -} - -static void -emeus_constraint_layout_buildable_parser_finished (GtkBuildable *buildable, - GtkBuilder *builder) -{ - EmeusConstraintLayout *self = EMEUS_CONSTRAINT_LAYOUT (buildable); - GSList *constraints, *l; - GError *error = NULL; - - /* Maintain the order in which the constraints were defined */ - constraints = g_object_get_qdata (G_OBJECT (buildable), quark_buildable_constraints); - constraints = g_slist_reverse (constraints); - - for (l = constraints; l != NULL; l = l->next) - { - const ConstraintData *cdata = l->data; - EmeusConstraint *c = constraint_data_to_constraint (cdata, builder, &error); - - if (error != NULL) - { - g_critical ("Unable to parse constraint '%s.%s [%s] %s.%s * %g + %g': %s", - cdata->target_name, cdata->target_attr, - cdata->relation, - cdata->source_name, cdata->source_attr, - cdata->multiplier, - cdata->constant, - error->message); - g_clear_error (&error); - continue; - } - - DEBUG (g_debug ("Adding constraint [%p] from GtkBuilder definition", c)); - emeus_constraint_layout_add_constraint (self, c); - } - - g_object_set_qdata (G_OBJECT (buildable), quark_buildable_constraints, NULL); - - parent_buildable_iface->parser_finished (buildable, builder); -} - -static void -emeus_constraint_layout_buildable_iface_init (GtkBuildableIface *iface) -{ - parent_buildable_iface = g_type_interface_peek_parent (iface); - - iface->parser_finished = emeus_constraint_layout_buildable_parser_finished; - iface->custom_tag_start = emeus_constraint_layout_buildable_custom_tag_start; - iface->custom_finished = emeus_constraint_layout_buildable_custom_finished; -} -#endif // CJC Gtk 3.22 dependency: //extern void gtk_widget_class_set_css_name(GtkWidgetClass *widget_class, // const char *name); @@ -1321,6 +1013,8 @@ emeus_constraint_layout_init (EmeusConstraintLayout *self) //gtk_widget_set_has_window (GTK_WIDGET (self), FALSE); simplex_solver_init (&self->solver); + + self->setup = false; self->children = g_sequence_new (NULL); @@ -1344,11 +1038,16 @@ emeus_constraint_layout_init (EmeusConstraintLayout *self) * * Since: 1.0 */ -//GtkWidget * +// TODO cjc was GtkWidget * +// Should use fancy Gobject parameters for init EmeusConstraintLayout * -emeus_constraint_layout_new (void) +emeus_constraint_layout_new (shoes_layout *lay) { - return g_object_new (EMEUS_TYPE_CONSTRAINT_LAYOUT, NULL); + EmeusConstraintLayout *layout; + layout = g_object_new (EMEUS_TYPE_CONSTRAINT_LAYOUT, NULL); + layout->sh_layout = lay; + return layout; + //return g_object_new (EMEUS_TYPE_CONSTRAINT_LAYOUT, NULL); } static void @@ -1755,7 +1454,6 @@ emeus_constraint_layout_add_constraints (EmeusConstraintLayout *layout, * * Since: 1.0 */ -// TODO cjc: may not be used in Shoes with this name void emeus_constraint_layout_pack (EmeusConstraintLayout *layout, GshoesEle *child, @@ -1772,10 +1470,10 @@ emeus_constraint_layout_pack (EmeusConstraintLayout *layout, g_return_if_fail (EMEUS_IS_CONSTRAINT (first_constraint) || first_constraint == NULL); //g_return_if_fail (gtk_widget_get_parent (child) == NULL); - + +#if 0 if (EMEUS_IS_CONSTRAINT_LAYOUT_CHILD (child)) layout_child = EMEUS_CONSTRAINT_LAYOUT_CHILD (child); -#if 0 else { layout_child = (EmeusConstraintLayoutChild *) emeus_constraint_layout_child_new (name); @@ -1783,6 +1481,11 @@ emeus_constraint_layout_pack (EmeusConstraintLayout *layout, gtk_widget_show (GTK_WIDGET (layout_child)); gtk_container_add (GTK_CONTAINER (layout_child), child); } +#else + // TODO cjc: arg should be GshoeEle (get name from there) + layout_child = (EmeusConstraintLayoutChild *) emeus_constraint_layout_child_new (name, child); + + #endif layout_child->iter = g_sequence_append (layout->children, layout_child); layout_child->solver = &layout->solver; @@ -1946,7 +1649,9 @@ emeus_constraint_layout_child_set_property (GObject *gobject, case CHILD_PROP_NAME: self->name = g_value_dup_string (value); break; - + case CHILD_PROP_ELEMENT: + self->widget = g_value_get_pointer(value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); } @@ -1965,6 +1670,9 @@ emeus_constraint_layout_child_get_property (GObject *gobject, case CHILD_PROP_NAME: g_value_set_string (value, self->name); break; + case CHILD_PROP_ELEMENT: + g_value_set_pointer(value, (gpointer)self->widget); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); @@ -2159,6 +1867,11 @@ emeus_constraint_layout_child_class_init (EmeusConstraintLayoutChildClass *klass G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + + emeus_constraint_layout_child_properties[CHILD_PROP_ELEMENT] = + g_param_spec_pointer ("element", "Element", "The shoes element", + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY); g_object_class_install_properties (gobject_class, CHILD_N_PROPS, emeus_constraint_layout_child_properties); @@ -2191,10 +1904,11 @@ emeus_constraint_layout_child_init (EmeusConstraintLayoutChild *self) * Since: 1.0 */ EmeusConstraintLayoutChild * -emeus_constraint_layout_child_new (const char *name) +emeus_constraint_layout_child_new (const char *name, GshoesEle *ele) { return g_object_new (EMEUS_TYPE_CONSTRAINT_LAYOUT_CHILD, "name", name, + "element", ele, NULL); } diff --git a/shoes/layout/emeus-constraint-layout.h b/shoes/layout/emeus-constraint-layout.h index f948998c..70b78e75 100644 --- a/shoes/layout/emeus-constraint-layout.h +++ b/shoes/layout/emeus-constraint-layout.h @@ -22,6 +22,7 @@ #include "shoes/layout/emeus-types.h" #include "shoes/layout/emeus-constraint.h" #include "shoes/layout/gshoes-ele.h" +#include "shoes/layout/shoes-vfl.h" G_BEGIN_DECLS #define EMEUS_TYPE_CONSTRAINT_LAYOUT (emeus_constraint_layout_get_type()) @@ -40,13 +41,22 @@ EMEUS_AVAILABLE_IN_1_0 G_DECLARE_FINAL_TYPE (EmeusConstraintLayout, emeus_constraint_layout, EMEUS, CONSTRAINT_LAYOUT, GObject) EMEUS_AVAILABLE_IN_1_0 -EmeusConstraintLayout * emeus_constraint_layout_new (void); -EMEUS_AVAILABLE_IN_1_0 -void emeus_constraint_layout_pack (EmeusConstraintLayout *layout, - GshoesEle *child, - const char *name, - EmeusConstraint *first_constraint, - ...); +EmeusConstraintLayout * emeus_constraint_layout_new (shoes_layout *lay); +EMEUS_AVAILABLE_IN_1_0 +void emeus_constraint_layout_pack (EmeusConstraintLayout *layout, + GshoesEle *child, + const char *name, + EmeusConstraint *first_constraint, + ...); +extern void +emeus_constraint_layout_size_allocate (EmeusConstraintLayout *self, + int width, + int height); +extern Variable * +get_layout_attribute (EmeusConstraintLayout *layout, + EmeusConstraintAttribute attr); + + EMEUS_AVAILABLE_IN_1_0 void emeus_constraint_layout_add_constraint (EmeusConstraintLayout *layout, EmeusConstraint *constraint); @@ -77,8 +87,13 @@ EMEUS_AVAILABLE_IN_1_0 G_DECLARE_FINAL_TYPE (EmeusConstraintLayoutChild, emeus_constraint_layout_child, EMEUS, CONSTRAINT_LAYOUT_CHILD, GObject) EMEUS_AVAILABLE_IN_1_0 -EmeusConstraintLayoutChild * emeus_constraint_layout_child_new (const char *name); - +EmeusConstraintLayoutChild * emeus_constraint_layout_child_new (const char *name, + GshoesEle *ele); + +extern Variable * +get_child_attribute (EmeusConstraintLayoutChild *child, + EmeusConstraintAttribute attr); + EMEUS_AVAILABLE_IN_1_0 const char * emeus_constraint_layout_child_get_name (EmeusConstraintLayoutChild *child); EMEUS_AVAILABLE_IN_1_0 diff --git a/shoes/layout/shoes-vfl-parser.c b/shoes/layout/shoes-vfl-parser.c index cdb969b0..df6eb65c 100644 --- a/shoes/layout/shoes-vfl-parser.c +++ b/shoes/layout/shoes-vfl-parser.c @@ -129,7 +129,8 @@ VALUE shoes_vfl_wrap_constraint(VflConstraint *c) { rb_hash_aset(hsh, key, val); key = ID2SYM(rb_intern("strength")); - val = DBL2NUM(c->strength); + //val = DBL2NUM(c->strength); + val = rb_str_new2(strength_to_string (c->strength)); rb_hash_aset(hsh, key, val); return hsh; diff --git a/shoes/layout/shoes-vfl.c b/shoes/layout/shoes-vfl.c index f0c02815..35a23f16 100644 --- a/shoes/layout/shoes-vfl.c +++ b/shoes/layout/shoes-vfl.c @@ -39,7 +39,7 @@ VALUE shoes_vfl_hash_emeus(EmeusConstraint *c); EmeusConstraintAttribute shoes_vfl_attr_from_str(char *attr); EmeusConstraintRelation shoes_vfl_rel_from_str(char *rel); // Temporary - just enough to link on non gtk platforms. WARNING. - +#if 0 SimplexSolver * emeus_constraint_layout_get_solver(EmeusConstraintLayout *layout) { return layout->solver; @@ -56,7 +56,7 @@ void emeus_constraint_layout_deactivate_constraint(EmeusConstraintLayout *layout { printf("emeus_constraint_layout_deactivate_constraint called\n"); } - +#endif // --------- implement shoes usr layout protocol for vfl/emeus ----------- @@ -65,26 +65,20 @@ void shoes_vfl_setup(shoes_layout *lay, shoes_canvas *canvas, VALUE attr) { fprintf(stderr, "shoes_vfl_setup called\n"); // create OUR layout struct - different from the shoes_layout, sort of. EmeusConstraintLayout *layout; - layout = malloc(sizeof(EmeusConstraintLayout)); - // make a pointer to the solver (aka context, tableau) - SimplexSolver *solver = malloc(sizeof (SimplexSolver)); - solver->initialized = 0; - simplex_solver_init (solver); - layout->solver = solver; - layout->children = NULL; - layout->shoes_contents = lay; // cross link + layout = emeus_constraint_layout_new(lay); lay->root = (void *)layout; // get height and width from attr VALUE hgtobj, widobj; - int wid, hgt = 0; + int wid, hgt = 100; widobj = ATTR(attr, width); if (! NIL_P(widobj)) wid = NUM2INT(widobj); hgtobj = ATTR(attr, height); if (! NIL_P(hgtobj)) hgt = NUM2INT(hgtobj); - + +#if 0 // init hash tables for elements (views) and metrics layout->views = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free); layout->metrics = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free); @@ -98,6 +92,7 @@ void shoes_vfl_setup(shoes_layout *lay, shoes_canvas *canvas, VALUE attr) { NULL); shoes_vfl_add_layout_stays (layout); +#endif } void shoes_vfl_add_ele(shoes_canvas *canvas, VALUE ele) { @@ -110,10 +105,16 @@ void shoes_vfl_add_ele(shoes_canvas *canvas, VALUE ele) { rb_raise(rb_eArgError, "please supply a name: "); char *str = RSTRING_PTR(name); rb_hash_aset(lay->views, name, ele); +#if 0 /* * create Variables/constraints for 'ele'. At this point in time - * we don't have w or h for the elements + * we don't have w or h for the element */ + GString *gstr = g_string_new(str); + GshoesEle *gele = gshoes_ele_new(gstr, (gpointer)ele); + EmeusConstraintLayout *layout = (EmeusConstraintLayout *)lay->root; + emeus_constraint_layout_pack (layout, gele, str, NULL, NULL); +#endif } void shoes_vfl_delete_at(shoes_layout *lay, shoes_canvas *canvas, VALUE ele, @@ -129,27 +130,73 @@ void shoes_vfl_clear(shoes_layout *lay, shoes_canvas *canvas) void shoes_vfl_size(shoes_layout *lay, shoes_canvas *canvas, int pass) { fprintf(stderr, "shoes_vfl_size pass: %d called\n", pass); + if (pass == 0) + return; + EmeusConstraintLayout *layout = (EmeusConstraintLayout *)lay->root; + if (layout->setup) { + fprintf(stderr, "shoes_vfl_size: recomputing\n"); + shoes_vfl_outer_size(layout, canvas->width, canvas->height); + } + return; } + void shoes_vfl_finish(shoes_layout *lay, shoes_canvas *canvas) { fprintf(stderr,"shoes_vfl_finish called\n"); + /* + * create Variables/constraints for elements + */ EmeusConstraintLayout *layout = (EmeusConstraintLayout *)lay->root; - // Now What ? + VALUE keys; + keys = rb_funcall(lay->views, rb_intern("keys"), 0); + for (int i = 0; i < RARRAY_LEN(keys); i++) { + VALUE ent = rb_ary_entry(keys, i); + GString *str = g_string_new(RSTRING_PTR(ent)); + // we want the Shoes ele to match the name (key) + VALUE ele = rb_hash_aref(lay->views, ent); + GshoesEle *gele = gshoes_ele_new(str, (gpointer)ele); + emeus_constraint_layout_pack (layout, gele, RSTRING_PTR(ent), NULL, NULL); + } + // Update the outer w/h constraints and stays, and the inners. + shoes_vfl_outer_size(layout, canvas->width, canvas->height); + // compute (may not be needed ? + simplex_solver_resolve (&layout->solver); + // debug printout + layout->setup = true; + #if 0 // height,top,width,left - the stays. GHashTableIter iter; gpointer key, value; - g_hash_table_iter_init (&iter, layout->bound_attributes); + g_hash_table_iter_init (&iter, layout->constraints); while (g_hash_table_iter_next (&iter, &key, &value)) { /* do something with key and value */ char *str = (char *)key; - EmeusConstraintAttribute *attr = (EmeusConstraintAttribute *)value; - fprintf(stderr, "attr: %s\n", str); + EmeusConstraint *cs = (EmeusConstraint *)value; + char *as = emeus_constraint_to_string(cs); + fprintf(stderr, "stay cs: %s: %s \n", str, as); } + #endif } +GshoesEle * +shoes_vfl_find_child(EmeusConstraintLayout *layout, char *name) { + GSequenceIter *iter; + GshoesEle *target = NULL; + iter = g_sequence_get_begin_iter (layout->children); + while (!g_sequence_iter_is_end (iter)) { + EmeusConstraintLayoutChild *child; + child = (EmeusConstraintLayoutChild *)g_sequence_get (iter); + if (strcmp(child->name, name) == 0) { + target = child->widget; + break; + } + } + return target; +} + void shoes_vfl_add_contraints(shoes_layout *lay, shoes_canvas *canvas, VALUE arg) { fprintf(stderr, "shoes_vfl_add_contraints called\n"); @@ -174,8 +221,9 @@ void shoes_vfl_add_contraints(shoes_layout *lay, shoes_canvas *canvas, VALUE arg if (NIL_P(rbv)) rb_raise(rb_eArgError,"no Shoes element named: %s", name); - // get the gshoes_ele from layout->views - - target = g_hash_table_lookup(layout->views, name); + // get the gshoes_ele from layout->children + //target = g_hash_table_lookup(layout->views, name); + target = shoes_vfl_find_child(layout, name); if (target == NULL) { // make a gshoes_ele GString *gstr = g_string_new(name); @@ -200,7 +248,8 @@ void shoes_vfl_add_contraints(shoes_layout *lay, shoes_canvas *canvas, VALUE arg rb_raise(rb_eArgError,"no Shoes element named: %s", name); // get the gshoes_ele from layout->views - - source = g_hash_table_lookup(layout->views, name); + //source = g_hash_table_lookup(layout->views, name); + source = shoes_vfl_find_child(layout, name); if (source == NULL) { // make a gshoes_ele GString *gstr = g_string_new(name); @@ -235,9 +284,12 @@ VALUE shoes_vfl_parse(shoes_layout *lay, shoes_canvas *canvas, VALUE args) { fprintf(stderr, "shoes_vfl_parse called\n"); GError *error = NULL; + GHashTable *views, *metrics; //int hspacing = 10; //int vspacing = 10; EmeusConstraintLayout *layout = (EmeusConstraintLayout *)lay->root; + views = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free); + metrics = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free); // get view names (shoes ele's) VALUE keys; @@ -260,7 +312,7 @@ VALUE shoes_vfl_parse(shoes_layout *lay, shoes_canvas *canvas, VALUE args) // we want the Shoes ele to match the name (key) VALUE ele = rb_hash_aref(lay->views, ent); GshoesEle *gele = gshoes_ele_new(str, (gpointer)ele); - g_hash_table_insert(layout->views, RSTRING_PTR(ent), gele); + g_hash_table_insert(views, RSTRING_PTR(ent), gele); // create an EmuesChildLayout (equiv) here? Create solver variables? } @@ -299,7 +351,7 @@ VALUE shoes_vfl_parse(shoes_layout *lay, shoes_canvas *canvas, VALUE args) *v = NUM2DBL(metv); //fprintf(stderr,"metrics key: %s => %g\n", str, *v); } - g_hash_table_insert(layout->metrics, (char *)str, v); + g_hash_table_insert(metrics, (char *)str, v); } // convert lines. @@ -317,7 +369,7 @@ VALUE shoes_vfl_parse(shoes_layout *lay, shoes_canvas *canvas, VALUE args) // store the glist in EmeusConstrainLayout->parsed_constraints layout->parsed_constraints = emeus_create_constraints_from_description( - lines, n_lines, -1, -1, layout->views, layout->metrics); + lines, n_lines, -1, -1, views, metrics); // finish() will move them into the Solver somehow. // In Theory. May not be need - the constraints are in the solver? // Don't forget to free the lines array strings @@ -369,6 +421,7 @@ gboolean shoes_vfl_is_element(GshoesEle *p) { return true; } +#if 0 void shoes_vfl_add_layout_stays(EmeusConstraintLayout *self) { Variable *var; @@ -405,7 +458,7 @@ void shoes_vfl_add_layout_stays(EmeusConstraintLayout *self) { self->stays.height = simplex_solver_add_stay_variable (self->solver, var, STRENGTH_WEAK); } - +#endif VALUE shoes_vfl_hash_emeus(EmeusConstraint *c) { gpointer source, target; @@ -598,3 +651,180 @@ EmeusConstraintRelation shoes_vfl_rel_from_str(char *rel) { } return EMEUS_CONSTRAINT_RELATION_EQ; } + +void shoes_vfl_change_pos(GshoesEle *gs, int x, int y, int width, int height) +{ + shoes_abstract *ab; + gpointer gp = gshoes_ele_get_element(gs); + Data_Get_Struct((VALUE)gp, shoes_abstract, ab); + //if (x != ab->place.x || y != ab->place.y) { + fprintf(stderr, "move from %d,%d to %d,%d\n", ab->place.x, ab->place.y, x, y); + fprintf(stderr, "size from %d, %d to %d %d\n", ab->place.w, ab->place.h, width, height); + //} +} + +// Move the shoes element's width,height to constraints +// TODO: finish the +void shoes_vfl_child_size(EmeusConstraintLayoutChild *self) { + Variable *attr = NULL; + Variable *top, *left, *width, *height; + if (self->solver == NULL) + return; + shoes_abstract *ab; + VALUE abv = (VALUE)gshoes_ele_get_element(self->widget); + Data_Get_Struct(abv, shoes_abstract, ab); + top = get_child_attribute (self, EMEUS_CONSTRAINT_ATTRIBUTE_TOP); + left = get_child_attribute (self, EMEUS_CONSTRAINT_ATTRIBUTE_LEFT); + width = get_child_attribute (self, EMEUS_CONSTRAINT_ATTRIBUTE_WIDTH); + height = get_child_attribute (self, EMEUS_CONSTRAINT_ATTRIBUTE_HEIGHT); + + Data_Get_Struct(abv, shoes_abstract, ab); + //variable_set_value(top, ab->place.y); + //variable_set_value(left, ab->place.x); + variable_set_value(width, ab->place.w); + variable_set_value(height, ab->place.h); + // width_constraint + attr = get_child_attribute (self, EMEUS_CONSTRAINT_ATTRIBUTE_WIDTH); + // if (element is not hidden in Shoes: + { + /* replace the constraint because the min width can change */ + if (self->width_constraint != NULL) + simplex_solver_remove_constraint (self->solver, self->width_constraint); + + Expression *e = expression_new_from_constant (ab->place.w); + + self->width_constraint = + simplex_solver_add_constraint (self->solver, + attr, OPERATOR_TYPE_GE, e, + STRENGTH_MEDIUM); + expression_unref (e); + } + /* else hidden + if (self->width_constraint != NULL) + { + simplex_solver_remove_constraint (self->solver, self->width_constraint); + self->width_constraint = NULL; + } + */ + // height_constraint + attr = get_child_attribute (self, EMEUS_CONSTRAINT_ATTRIBUTE_HEIGHT); + // if (element is not hidden): + { + /* reeplace the constraint because the min height can change */ + if (self->height_constraint != NULL) + simplex_solver_remove_constraint (self->solver, self->height_constraint); + + Expression *e = expression_new_from_constant (ab->place.h); + + self->height_constraint = + simplex_solver_add_constraint (self->solver, + attr, OPERATOR_TYPE_GE, e, + STRENGTH_MEDIUM); + expression_unref (e); + } + /* else hidden + if (self->height_constraint != NULL) + { + simplex_solver_remove_constraint (self->solver, self->height_constraint); + self->height_constraint = NULL; + } + */ +} + +void shoes_vfl_outer_size(EmeusConstraintLayout *self, int canvas_width, int canvas_height) +{ + //EmeusConstraintLayout *self = EMEUS_CONSTRAINT_LAYOUT (widget); + Constraint *stay_x, *stay_y; + Constraint *stay_w, *stay_h; + + //gtk_widget_set_allocation (widget, allocation); + + if (g_sequence_is_empty (self->children)) + return; + + Variable *layout_top = get_layout_attribute (self, EMEUS_CONSTRAINT_ATTRIBUTE_TOP); + Variable *layout_left = get_layout_attribute (self, EMEUS_CONSTRAINT_ATTRIBUTE_LEFT); + Variable *layout_width = get_layout_attribute (self, EMEUS_CONSTRAINT_ATTRIBUTE_WIDTH); + Variable *layout_height = get_layout_attribute (self, EMEUS_CONSTRAINT_ATTRIBUTE_HEIGHT); + + //variable_set_value (layout_left, allocation->x); + variable_set_value (layout_left, 0); + stay_x = simplex_solver_add_stay_variable (&self->solver, layout_left, STRENGTH_REQUIRED); + + //variable_set_value (layout_top, allocation->y); + variable_set_value (layout_top, 0); + stay_y = simplex_solver_add_stay_variable (&self->solver, layout_top, STRENGTH_REQUIRED); + + //variable_set_value (layout_width, allocation->width); + variable_set_value (layout_width, canvas_width); + stay_w = simplex_solver_add_stay_variable (&self->solver, layout_width, STRENGTH_REQUIRED); + + //variable_set_value (layout_height, allocation->height); + variable_set_value (layout_height, canvas_height); + stay_h = simplex_solver_add_stay_variable (&self->solver, layout_height, STRENGTH_REQUIRED); + +#ifdef EMEUS_ENABLE_DEBUG + printf("layout [%p] = { .top:%g, .left:%g, .width:%g, .height:%g }\n", + self, + variable_get_value (layout_top), + variable_get_value (layout_left), + variable_get_value (layout_width), + variable_get_value (layout_height)); +#endif + // iterate thru the children + // Set the /h/w and constraints for the elements + EmeusConstraintLayoutChild *child = NULL; + GSequenceIter *iter = g_sequence_get_begin_iter (self->children); + while (!g_sequence_iter_is_end (iter)) { + child = g_sequence_get (iter); + shoes_vfl_child_size(child); + iter = g_sequence_iter_next (iter); + } + // loop again to copy computed positions to Shoes + iter = g_sequence_get_begin_iter (self->children); + while (!g_sequence_iter_is_end (iter)) { + Variable *top, *left, *width, *height; + Variable *center_x, *center_y; + Variable *baseline; + int x,y,wid,hgt; + + child = g_sequence_get (iter); + iter = g_sequence_iter_next (iter); + + top = get_child_attribute (child, EMEUS_CONSTRAINT_ATTRIBUTE_TOP); + left = get_child_attribute (child, EMEUS_CONSTRAINT_ATTRIBUTE_LEFT); + width = get_child_attribute (child, EMEUS_CONSTRAINT_ATTRIBUTE_WIDTH); + height = get_child_attribute (child, EMEUS_CONSTRAINT_ATTRIBUTE_HEIGHT); + center_x = get_child_attribute (child, EMEUS_CONSTRAINT_ATTRIBUTE_CENTER_X); + center_y = get_child_attribute (child, EMEUS_CONSTRAINT_ATTRIBUTE_CENTER_Y); + baseline = get_child_attribute (child, EMEUS_CONSTRAINT_ATTRIBUTE_BASELINE); +#ifdef EMEUS_ENABLE_DEBUG + printf ("child '%s' [%p] = { " + ".top:%g, .left:%g, .width:%g, .height:%g, " + ".center:(%g, %g), .baseline:%g " + "}\n", + child->name != NULL ? child->name : "", + child, + variable_get_value (top), + variable_get_value (left), + variable_get_value (width), + variable_get_value (height), + variable_get_value (center_x), + variable_get_value (center_y), + variable_get_value (baseline)); +#endif + + x = floor (variable_get_value (left)); + y = floor (variable_get_value (top)); + wid = ceil (variable_get_value (width)); + hgt = ceil (variable_get_value (height)); + shoes_vfl_change_pos(child->widget, x, y, wid, hgt); + } + // remove the Required Stays (leaving the weak stays from setup) + // -- until we resize again + simplex_solver_remove_constraint (&self->solver, stay_x); + simplex_solver_remove_constraint (&self->solver, stay_y); + simplex_solver_remove_constraint (&self->solver, stay_w); + simplex_solver_remove_constraint (&self->solver, stay_h); +} + diff --git a/shoes/layout/shoes-vfl.h b/shoes/layout/shoes-vfl.h index d3f6f8e8..2bca757a 100644 --- a/shoes/layout/shoes-vfl.h +++ b/shoes/layout/shoes-vfl.h @@ -31,6 +31,9 @@ #include "shoes/layout/emeus-simplex-solver-private.h" #include "shoes/layout/emeus-utils-private.h" #include "shoes/layout/emeus.h" +#include "shoes/layout/emeus-constraint-layout-private.h" +#include "shoes/layout/emeus-constraint-layout.h" +#if 0 // These structs are mostly glib - not ruby typedef struct { SimplexSolver *solver; @@ -50,7 +53,7 @@ typedef struct { Constraint *top, *left, *width, *height; } stays; } EmeusConstraintLayout; - +#endif // in shoes-vfl-parser.c: VALUE shoes_vfl_rules(shoes_layout *lay, shoes_canvas *canvas, VALUE args); // in shoes-vfl.c: @@ -66,12 +69,16 @@ VALUE shoes_vfl_parse(shoes_layout *lay, shoes_canvas *canvas, VALUE arg); VALUE shoes_vfl_get_constraints(shoes_layout *lay, shoes_canvas *canvas); VALUE shoes_vfl_get_constraints_hash(shoes_layout *lay, shoes_canvas *canvas); gboolean shoes_vfl_is_element(GshoesEle *ele); + // some emeus-contraint-layout functions we sort of emulate. -SimplexSolver * emeus_constraint_layout_get_solver(EmeusConstraintLayout *layout); +SimplexSolver *emeus_constraint_layout_get_solver(EmeusConstraintLayout *layout); void emeus_constraint_layout_activate_constraint (EmeusConstraintLayout *layout, EmeusConstraint *constraint); void emeus_constraint_layout_deactivate_constraint(EmeusConstraintLayout *layout, EmeusConstraint *constraint); - + +void shoes_vfl_change_pos(GshoesEle *ele, int x, int y, int width, int height); +void shoes_vfl_child_size(EmeusConstraintLayoutChild *child); +void shoes_vfl_outer_size(EmeusConstraintLayout *layout, int width, int height); #endif diff --git a/shoes/types/layout.c b/shoes/types/layout.c index 43c5cacd..74054bd5 100644 --- a/shoes/types/layout.c +++ b/shoes/types/layout.c @@ -194,6 +194,9 @@ VALUE shoes_layout_style(int argc, VALUE *argv, VALUE self) { VALUE shoes_layout_finish(int argc, VALUE *argv, VALUE self) { //fprintf(stderr, "shoes_layout_finish called\n"); + VALUE arg = Qnil; + if (argc > 0) + arg = argv[0]; shoes_layout *lay; Data_Get_Struct(self, shoes_layout, lay); shoes_canvas *canvas; @@ -203,7 +206,7 @@ VALUE shoes_layout_finish(int argc, VALUE *argv, VALUE self) { Data_Get_Struct(canvas->layout_mgr, shoes_layout, ly); if (! NIL_P(ly->delegate)) { VALUE del = ly->delegate; - rb_funcall(del, s_finish, 0); + rb_funcall(del, s_finish, 1, arg); return Qtrue; } }