lib/ctioga2/graphics/elements/primitive.rb in ctioga2-0.3 vs lib/ctioga2/graphics/elements/primitive.rb in ctioga2-0.4

- old
+ new

@@ -14,22 +14,28 @@ require 'ctioga2/utils' require 'ctioga2/log' require 'ctioga2/graphics/types' +require 'ctioga2/graphics/styles' require 'shellwords' # This module contains all the classes used by ctioga module CTioga2 - Version::register_svn_info('$Revision$', '$Date$') + Version::register_svn_info('$Revision: 370 $', '$Date: 2012-12-28 17:40:18 +0100 (Fri, 28 Dec 2012) $') module Graphics module Elements # A TiogaElement that represents a graphics primitive. + # + # @todo Most of the objects here should rely on getting a + # BasicStyle object from the options hash and use it to + # draw. There is no need to make cumbersome and hard to extend + # hashes. class TiogaPrimitiveCall < TiogaElement # Some kind of reimplementation of Command for graphics # primitives class TiogaPrimitive @@ -85,22 +91,27 @@ "Graphics primitives", "Tioga graphics primitives", 3) # Creates a new primitive with the given parameters, and makes # it immediately available as a command. - def self.primitive(name, long_name, comp, opts = {}, &code) + def self.primitive(name, long_name, comp, opts = {}, + desc = nil, &code) primitive = TiogaPrimitive.new(name, comp, opts, &code) @known_primitives[name] = primitive # Now, create the command cmd_args = comp.map do |x| CmdArg.new(x) end cmd_opts = {} for k,v in opts - cmd_opts[k] = CmdArg.new(v) + cmd_opts[k] = if v.respond_to?(:type) + v + else + CmdArg.new(v) + end end cmd = Cmd.new("draw-#{name}",nil,"--draw-#{name}", cmd_args, cmd_opts) do |plotmaker, *rest| options = rest.pop @@ -109,78 +120,102 @@ rest, options) call.last_curve_style = plotmaker.curve_style_stack.last plotmaker.root_object.current_plot. add_element(call) end + if ! desc + desc = "Directly draws #{long_name} on the current plot" + end cmd.describe("Draws #{long_name}", - "Directly draws #{long_name} on the current plot", PrimitiveGroup) + desc, + PrimitiveGroup) PrimitiveCommands[name] = cmd end + # This creates a primitive base on a style object, given a + # _style_class_, the base _style_name_ for the underlying + # styling system, options to remove and options to add. + # + # The underlying code receives: + # * the FigureMaker object + # * the compulsory arguments + # * the style + # * the raw options + def self.styled_primitive(name, long_name, comp, style_class, + style_name, without = [], + additional_options = {}, + set_style_command = nil, # This + # could be + # removed + &code) + options = style_class.options_hash.without(without) + options.merge!(additional_options) + options['base-style'] = 'text' # the base style name + set_style_command ||= style_name + desc = <<"EOD" +Draws #{long_name} on the current plot, using the given style. +For more information on the available options, see the +{command: define-#{set_style_command}-style} command. +EOD + + self.primitive(name, long_name, comp, options, desc) do |*all| + opts = all.pop + st_name = opts['base-style'] || "base" + style = Styles::StyleSheet.style_for(style_class,st_name) + style.set_from_hash(opts) + all << style << opts + code.call(*all) + end + end + + # Returns a pair primitive/primitive command for the named # primitive, or [ _nil_, _nil_ ] def self.get_primitive(name) return [@known_primitives[name], PrimitiveCommands[name]] end # Now, a list of primitives, along with their code. - primitive("text", "text", [ 'point', 'text' ], - { - 'color' => 'color', - 'scale' => 'float', - 'angle' => 'float', - 'justification' => 'justification', - 'alignment' => 'alignment', - 'font' => 'latex-font', - } - ) do |t, point, string, options| + styled_primitive("text", "text", + [ 'point', 'text' ], + Styles::FullTextStyle, + 'text', + ['text'], + {'font' => 'latex-font'} + ) do |t, point, string, style, options| # @todo add a way to specify fonts ??? options ||= {} if options['font'] string = options['font'].fontify(string) - options.delete('font') end - options['text'] = string - options['at'] = point.to_figure_xy(t) - t.show_text(options) + style.draw_text(t, string, *(point.to_figure_xy(t))) end - # @todo add rendering mode !! - MarkerOptions = { - 'color' => 'color', - 'stroke_color' => 'color', - 'fill_color' => 'color', - 'scale' => 'float', - 'horizontal_scale' => 'float', - 'vertical_scale' => 'float', - 'angle' => 'float', - 'justification' => 'justification', - 'alignment' => 'alignment', - } - - primitive("marker", "marker", [ 'point', 'marker' ], - MarkerOptions) do |t, point, marker, options| - ## \todo add a way to specify fonts ??? - options ||= {} - options['marker'] = marker - options['at'] = point.to_figure_xy(t) - t.show_marker(options) + styled_primitive("marker", "marker", + [ 'point', 'marker' ], + Styles::MarkerStringStyle, + 'marker', + ['font'] # font doesn't make any sense with a + # marker spec + ) do |t, point, marker, style, options| + style.draw_marker(t, marker, *point.to_figure_xy(t)) end - primitive("string-marker", "marker", [ 'point', 'text' ], - {'font' => 'pdf-font' }.update(MarkerOptions) - ) do |t, point, string, options| - ## \todo add a way to specify fonts ??? - options ||= {} - options['text'] = string - options['at'] = point.to_figure_xy(t) - t.show_marker(options) + styled_primitive("string-marker", "marker", + [ 'point', 'text' ], + Styles::MarkerStringStyle, + 'marker-string', [], + {}, + 'marker' + ) do |t, point, string, style, options| + style.draw_string_marker(t, string, *point.to_figure_xy(t)) end + # options for arrows (and therefore tangents) ArrowOptions = { 'color' => 'color', 'head_scale' => 'float', 'head_marker' => 'marker', @@ -190,35 +225,46 @@ 'tail_color' => 'color', 'line_width' => 'float', 'line_style' => 'line-style', } - primitive("arrow", "arrow", [ 'point', 'point' ], - ArrowOptions) do |t, tail,head, options| - ## \todo a scale or marker_scale option that sets the scale - ## of both head and tail - options ||= {} - options['head'] = head.to_figure_xy(t) - options['tail'] = tail.to_figure_xy(t) - t.show_arrow(options) + styled_primitive("arrow", "arrow", + [ 'point', 'point' ], + Styles::ArrowStyle, + 'arrow') do |t, tail, head, style, options| + style.draw_arrow(t, *tail.to_figure_xy(t), + *head.to_figure_xy(t)) end - - primitive("line", "line", [ 'point', 'point' ], - { - 'color' => 'color', - 'line_width' => 'float', - 'line_style' => 'line-style', - } - ) do |t, tail,head, options| - options ||= {} - for a in ['head', 'tail'] - options["#{a}_marker"] = "None" - end - options['head'] = head.to_figure_xy(t) - options['tail'] = tail.to_figure_xy(t) - t.show_arrow(options) + + styled_primitive("line", "line", + [ 'point', 'point' ], + Styles::StrokeStyle, + 'line' + ) do |t, tail, head, style, options| + style.draw_line(t, *(tail.to_figure_xy(t)), + *(head.to_figure_xy(t))) end + # Here, we need to add deprecated options for backward + # compatibility + + for cmd in ['draw-line', 'draw-arrow'] + Commands::make_alias_for_option cmd, 'width', 'line_width', true + Commands::make_alias_for_option cmd, 'style', 'line_style', true + end + + styled_primitive("box", "box", + [ 'point', 'point' ], + Styles::BoxStyle, + 'box') do |t, tl, br, style, options| + x1,y1 = tl.to_figure_xy(t) + x2,y2 = br.to_figure_xy(t) + style.draw_box(t, x1, y1, x2, y2) + end + + + Commands::make_alias_for_option 'draw-box', 'fill_color', 'fill-color' + Commands::make_alias_for_option 'draw-box', 'fill_transparency', 'fill-transparency' protected # Draws the primitive def real_do(t)