lib/ctioga2/graphics/styles/factory.rb in ctioga2-0.0 vs lib/ctioga2/graphics/styles/factory.rb in ctioga2-0.1
- old
+ new
@@ -15,11 +15,11 @@
require 'ctioga2/log'
# This module contains all the classes used by ctioga
module CTioga2
- Version::register_svn_info('$Revision: 59 $', '$Date: 2009-05-28 23:15:50 +0200 (Thu, 28 May 2009) $')
+ Version::register_svn_info('$Revision: 217 $', '$Date: 2010-12-31 16:18:20 +0100 (Fri, 31 Dec 2010) $')
module Graphics
module Styles
@@ -50,22 +50,27 @@
attr_accessor :short_option
# The MetaBuilder::Type object that can convert a String to
# an Array suitable for use with CircularArray.
attr_accessor :sets_type
+
+ # If this attribute is on, then CurveStyleFactory will not
+ # generate commands for this parameter, only the option.
+ attr_accessor :disable_commands
# Creates a new CurveStyleFactoryParameter object.
def initialize(name, type, sets, description,
- short_option = nil)
+ short_option = nil, disable_cmds = false)
@name = name
@type = Commands::CommandType.get_type(type)
@sets = sets
@description = description
@short_option = short_option
-
- # TODO: it is not very satisfying to mix CommandTypes and
+ @disable_commands = disable_cmds
+
+ ## \todo it is not very satisfying to mix CommandTypes and
# MetaBuilder::Type on the same level.
if @sets
@sets_type =
MetaBuilder::Type.get_type({
:type => :set,
@@ -93,15 +98,20 @@
AutoRE = /auto/i
# Sets some parameter to _false_.
DisableRE = /no(ne)?|off/i
+ # If that matches, we use the value as a link to other values.
+ LinkRE = /(?:=|->)(\S+)/
# Creates a new parameter for the style factory.
+ #
+ # \todo add a way to add some more text to the description;
+ # possibly a self.describe_parameter function ?
def self.define_parameter(target, name, type, sets, description,
- short_option = nil)
+ short_option = nil, disable_cmds = false)
# We define two new types:
# - first, the color-or-auto type:
base_type = Commands::CommandType.get_type(type)
if ! Commands::Interpreter.type("#{base_type.name}-or-auto")
@@ -110,28 +120,32 @@
mb_type.re_shortcuts.dup : {})
mb_type.re_shortcuts[AutoRE] = 'auto'
mb_type.re_shortcuts[DisableRE] = false
+ # Add passthrough for expressions such as =color...
+ mb_type.passthrough = LinkRE
+
# Now, register a type for the type or automatic.
CmdType.new("#{base_type.name}-or-auto", mb_type,
- "Same thing as type #{base_type.name}, or 'auto'")
+ "Same thing as {type:#{base_type.name}}, or @auto@ to let the style factory handle automatically.")
end
if sets and ! Commands::Interpreter.type("#{base_type.name}-set")
# Now, register a type for the type or automatic.
CmdType.new("#{base_type.name}-set",{
:type => :set,
:subtype => base_type.type,
:shortcuts => sets
} ,
- "Sets of #{base_type.name}")
+ "Sets of {type: #{base_type.name}}")
end
param =
CurveStyleFactoryParameter.new(name, type, sets,
- description, short_option)
+ description, short_option,
+ disable_cmds)
@parameters ||= {}
@parameters[target] = param
@name_to_target ||= {}
@name_to_target[name] = target
@@ -149,45 +163,49 @@
end
# The CmdGroup for stylistic information about
# curves.
CurveStyleGroup =
- CmdGroup.new('curve-style', "Curve styles",
- "Set stylistic details about curves", 1)
+ CmdGroup.new('curve-style', "Curves styles",
+ "Set stylistic details of curves or other object drawn from data", 1)
# Creates two commands for each parameter of the object:
# * a command to set the override
# * a command to choose the sets.
def self.create_commands
parameters.each do |target, param|
+ next if param.disable_commands
override_cmd =
Cmd.new("#{param.name}",
param.short_option,
"--#{param.name}",
[
CmdArg.new("#{param.type.name}-or-auto")
], {},
"Sets the #{param.description} for subsequent curves",
- "Sets the #{param.description} for subsequent curves, until cancelled with 'auto' as argument.", CurveStyleGroup) do |plotmaker, value|
+ "Sets the #{param.description} for subsequent curves, until cancelled with @auto@ as argument.", CurveStyleGroup) do |plotmaker, value|
plotmaker.curve_generator.style_factory.
set_parameter_override(target, value)
end
if param.sets
+ next if param.disable_commands
set_cmd =
Cmd.new("#{param.name}-set",
nil,
"--#{param.name}-set",
[
CmdArg.new("#{param.type.name}-set")
], {},
"Chooses a set for the #{param.description} of subsequent curves",
- "Chooses a set for the #{param.description} of subsequent curves",
+ "Chooses a set for the #{param.description} of subsequent curves. Also sets {command: #{param.name}} to @auto@, so that the set takes effect immediately",
CurveStyleGroup) do |plotmaker, value|
plotmaker.curve_generator.style_factory.
set_parameter_set(target, value)
+ plotmaker.curve_generator.style_factory.
+ set_parameter_override(target, 'auto')
end
end
end
end
@@ -242,12 +260,11 @@
for target, array in @parameters_carrays
base[target] = array.next
end
base.merge!(@override_parameters)
base.merge!(hash_name_to_target(one_time))
- # TODO: here, resolve 'links', such as :->color ?
- return CurveStyle.from_hash(base)
+ return CurveStyle.from_hash(resolve_links(base))
end
# Sets the override for the given parameter. This corresponds
@@ -263,12 +280,22 @@
# Perform automatic type conversion only on strings.
if value.is_a? String
if value =~ AutoRE
@override_parameters.delete(target)
return
- end
- if value =~ DisableRE
+ elsif value =~ LinkRE
+ t = $1
+ convert = self.class.name_to_target
+ if convert.key?(t)
+ value = "=#{convert[t]}".to_sym
+ else
+ warn { "No known key: #{t}, treating as auto" }
+ @override_parameters.delete(target)
+ return
+ end
+
+ elsif value =~ DisableRE
value = false
else
value = param.type.string_to_type(value)
end
end
@@ -285,29 +312,79 @@
end
@parameters_carrays[target].set = value
end
# Now, the parameters:
+
+ # Lines:
define_parameter 'line_color', 'color', 'color',
Sets::ColorSets, "color", "-c"
define_parameter 'line_width', 'line-width', 'float',
Sets::LineWidthSets, "line width", nil
define_parameter 'line_style', 'line-style', 'line-style',
Sets::LineStyleSets, "line style", nil
+ # Markers
define_parameter 'marker_marker', 'marker', 'marker',
Sets::MarkerSets, "marker", '-m'
define_parameter 'marker_color', 'marker-color', 'color',
Sets::ColorSets, "marker color", nil
define_parameter 'marker_scale', 'marker-scale', 'float',
Sets::LineWidthSets, "marker scale", nil
+ # Error bars:
+ define_parameter 'error_bar_color', 'error-bar-color', 'color',
+ Sets::ColorSets, "error bar color", nil
+ # Location:
+ define_parameter 'location_xaxis', 'xaxis', 'axis',
+ nil, "X axis", nil, true
+
+ define_parameter 'location_yaxis', 'yaxis', 'axis',
+ nil, "Y axis", nil, true
+
+ # Now, fill style
+ define_parameter 'fill_y0', 'fill', 'fill-until',
+ {}, "Fill until", nil
+
+ define_parameter 'fill_color', 'fill-color', 'color',
+ Sets::ColorSets, "fill color", nil
+
+ define_parameter 'fill_transparency', 'fill-transparency', 'float',
+ {}, "Fill transparency", nil
+
+ # Region handling
+ define_parameter 'region_position', 'region-side', 'region-side',
+ {"default" => [:above, :below]}, "region side", nil
+
+
+ define_parameter 'style', 'style', 'text',
+ {}, "Path style", nil
+
+ # Only for xyz-maps or xy-parametric
+ define_parameter 'color_map', 'color-map', 'colormap',
+ nil, "Color map", nil
+
+
+ define_parameter 'zaxis', 'zaxis', 'text',
+ nil, "Name for the Z axis", nil
+
+ ## @todo For xy-parametric, there should be a way to specify
+ ## to which z value the maps apply (ie lines = y2, marker =
+ ## y3...). Although for readability, it is probably better
+ ## to avoid that...
+ define_parameter 'marker_color_map', 'marker-color-map', 'colormap',
+ nil, "Marker color map", nil
+
+ define_parameter 'split_on_nan', 'split-on-nan', 'boolean',
+ nil, "Split on NaN", nil
+
+
# And finally, we register all necessary commands...
create_commands
# A constant suitable for use as the optional arguments of the
# plot command.
@@ -337,13 +414,52 @@
convert = self.class.name_to_target
for k,v in h
if convert.key? k
retval[convert[k]] = v
else
- warn "Unkown key for hash_name_to_target: #{k}"
+ warn { "Unkown key for hash_name_to_target: #{k}" }
end
end
return retval
+ end
+
+ # Resolve potential links in the form of :=stuff within the
+ # given hash, and returns a new version of the hash.
+ #
+ # \warning the _h_ parameter is completely destroyed in the
+ # process
+ def resolve_links(h)
+ tv = {}
+
+ # First, copy plain values
+ for k,v in h
+ if v.is_a?(Symbol) && v.to_s =~ /^(=|->)/
+ # We keep for later
+ else
+ tv[k] = v
+ h.delete(k)
+ end
+ end
+
+ # Now, we will iterate over the remaining things; we will
+ # stop with an error if the number of remaining keys does
+ # not decrease after one step
+ while h.size > 0
+ pre_size = h.size
+ for k,v in h
+ v.to_s =~ /^(?:=|->)(\S+)/
+ target = $1
+ if tv.key? target
+ tv[k] = tv[target]
+ h.delete(k)
+ end
+ end
+ if h.size >= pre_size
+ raise "Error: infinite recursion loop while gathering styles"
+ end
+ end
+
+ return tv
end
end
end
end
end