mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* ext/tk/lib/tk/canvas.rb: improve coords support for canvas items.
Now, supports all of the followings. TkcLine.new(c, 0, 0, 100, 100, :fill=>'red') TkcLine.new(c, [0, 0, 100, 100], :fill=>'red') TkcLine.new(c, [0, 0], [100, 100], :fill=>'red') TkcLine.new(c, [[0, 0], [100, 100]], :fill=>'red') TkcLine.new(c, :coords=>[0, 0, 100, 100], :fill=>'red') TkcLine.new(c, :coords=>[[0, 0], [100, 100]], :fill=>'red') git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8@6309 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
dc5fbe7c3c
commit
7268344d38
4 changed files with 99 additions and 116 deletions
11
ChangeLog
11
ChangeLog
|
@ -1,3 +1,14 @@
|
||||||
|
Fri May 14 18:39:25 2004 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
|
||||||
|
|
||||||
|
* ext/tk/lib/tk/canvas.rb: improve coords support for canvas items.
|
||||||
|
Now, supports all of the followings.
|
||||||
|
TkcLine.new(c, 0, 0, 100, 100, :fill=>'red')
|
||||||
|
TkcLine.new(c, [0, 0, 100, 100], :fill=>'red')
|
||||||
|
TkcLine.new(c, [0, 0], [100, 100], :fill=>'red')
|
||||||
|
TkcLine.new(c, [[0, 0], [100, 100]], :fill=>'red')
|
||||||
|
TkcLine.new(c, :coords=>[0, 0, 100, 100], :fill=>'red')
|
||||||
|
TkcLine.new(c, :coords=>[[0, 0], [100, 100]], :fill=>'red')
|
||||||
|
|
||||||
Fri May 14 12:11:43 Hirokazu Yamamoto <ocean@m2.ccsnet.ne.jp>
|
Fri May 14 12:11:43 Hirokazu Yamamoto <ocean@m2.ccsnet.ne.jp>
|
||||||
|
|
||||||
* util.c (ruby_strtod): strtod("0", &end); => end should point '\0'.
|
* util.c (ruby_strtod): strtod("0", &end); => end should point '\0'.
|
||||||
|
|
|
@ -60,12 +60,9 @@ class TkCanvas<TkWindow
|
||||||
private :tagid
|
private :tagid
|
||||||
|
|
||||||
|
|
||||||
def create(type, *args)
|
|
||||||
# create a canvas item without creating a TkcItem object
|
# create a canvas item without creating a TkcItem object
|
||||||
if type.kind_of?(TkcItem)
|
def create(type, *args)
|
||||||
fail ArgumentError, 'TkcItem class expected for 1st argument'
|
type.create(self, *args)
|
||||||
end
|
|
||||||
type.create(@path, *args)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -252,6 +249,9 @@ class TkCanvas<TkWindow
|
||||||
def itemconfigure(tagOrId, key, value=None)
|
def itemconfigure(tagOrId, key, value=None)
|
||||||
if key.kind_of? Hash
|
if key.kind_of? Hash
|
||||||
key = _symbolkey2str(key)
|
key = _symbolkey2str(key)
|
||||||
|
coords = key.delete('coords')
|
||||||
|
self.coords(tagOrId, coords) if coords
|
||||||
|
|
||||||
if ( key['font'] || key['kanjifont'] \
|
if ( key['font'] || key['kanjifont'] \
|
||||||
|| key['latinfont'] || key['asciifont'] )
|
|| key['latinfont'] || key['asciifont'] )
|
||||||
tagfont_configure(tagid(tagOrId), key.dup)
|
tagfont_configure(tagid(tagOrId), key.dup)
|
||||||
|
@ -261,7 +261,9 @@ class TkCanvas<TkWindow
|
||||||
end
|
end
|
||||||
|
|
||||||
else
|
else
|
||||||
if ( key == 'font' || key == :font ||
|
if ( key == 'coords' || key == :coords )
|
||||||
|
self.coords(tagOrId, value)
|
||||||
|
elsif ( key == 'font' || key == :font ||
|
||||||
key == 'kanjifont' || key == :kanjifont ||
|
key == 'kanjifont' || key == :kanjifont ||
|
||||||
key == 'latinfont' || key == :latinfont ||
|
key == 'latinfont' || key == :latinfont ||
|
||||||
key == 'asciifont' || key == :asciifont )
|
key == 'asciifont' || key == :asciifont )
|
||||||
|
@ -292,6 +294,8 @@ class TkCanvas<TkWindow
|
||||||
if TkComm::GET_CONFIGINFO_AS_ARRAY
|
if TkComm::GET_CONFIGINFO_AS_ARRAY
|
||||||
if key
|
if key
|
||||||
case key.to_s
|
case key.to_s
|
||||||
|
when 'coords'
|
||||||
|
return ['coords', '', '', '', self.coords(tagOrId)]
|
||||||
when 'dash', 'activedash', 'disableddash'
|
when 'dash', 'activedash', 'disableddash'
|
||||||
conf = tk_split_simplelist(tk_send_without_enc('itemconfigure', tagid(tagOrId), "-#{key}"))
|
conf = tk_split_simplelist(tk_send_without_enc('itemconfigure', tagid(tagOrId), "-#{key}"))
|
||||||
if conf[3] && conf[3] =~ /^[0-9]/
|
if conf[3] && conf[3] =~ /^[0-9]/
|
||||||
|
@ -342,18 +346,21 @@ class TkCanvas<TkWindow
|
||||||
conf[1] = conf[1][1..-1] if conf.size == 2 # alias info
|
conf[1] = conf[1][1..-1] if conf.size == 2 # alias info
|
||||||
conf
|
conf
|
||||||
}
|
}
|
||||||
|
|
||||||
fontconf = ret.assoc('font')
|
fontconf = ret.assoc('font')
|
||||||
if fontconf
|
if fontconf
|
||||||
ret.delete_if{|item| item[0] == 'font' || item[0] == 'kanjifont'}
|
ret.delete_if{|item| item[0] == 'font' || item[0] == 'kanjifont'}
|
||||||
fontconf[4] = tagfont_configinfo(tagid(tagOrId), fontconf[4])
|
fontconf[4] = tagfont_configinfo(tagid(tagOrId), fontconf[4])
|
||||||
ret.push(fontconf)
|
ret.push(fontconf)
|
||||||
else
|
|
||||||
ret
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ret << ['coords', '', '', '', self.coords(tagOrId)]
|
||||||
end
|
end
|
||||||
else # ! TkComm::GET_CONFIGINFO_AS_ARRAY
|
else # ! TkComm::GET_CONFIGINFO_AS_ARRAY
|
||||||
if key
|
if key
|
||||||
case key.to_s
|
case key.to_s
|
||||||
|
when 'coords'
|
||||||
|
{'coords' => ['', '', '', self.coords(tagOrId)]}
|
||||||
when 'dash', 'activedash', 'disableddash'
|
when 'dash', 'activedash', 'disableddash'
|
||||||
conf = tk_split_simplelist(tk_send_without_enc('itemconfigure',
|
conf = tk_split_simplelist(tk_send_without_enc('itemconfigure',
|
||||||
tagid(tagOrId),
|
tagid(tagOrId),
|
||||||
|
@ -410,6 +417,7 @@ class TkCanvas<TkWindow
|
||||||
ret[key] = conf
|
ret[key] = conf
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
|
|
||||||
fontconf = ret['font']
|
fontconf = ret['font']
|
||||||
if fontconf
|
if fontconf
|
||||||
ret.delete('font')
|
ret.delete('font')
|
||||||
|
@ -417,6 +425,9 @@ class TkCanvas<TkWindow
|
||||||
fontconf[3] = tagfont_configinfo(tagid(tagOrId), fontconf[3])
|
fontconf[3] = tagfont_configinfo(tagid(tagOrId), fontconf[3])
|
||||||
ret['font'] = fontconf
|
ret['font'] = fontconf
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ret['coords'] = ['', '', '', self.coords(tagOrId)]
|
||||||
|
|
||||||
ret
|
ret
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -513,6 +524,7 @@ class TkcItem<TkObject
|
||||||
extend Tk
|
extend Tk
|
||||||
include TkcTagAccess
|
include TkcTagAccess
|
||||||
|
|
||||||
|
CItemTypeName = nil
|
||||||
CItemTypeToClass = {}
|
CItemTypeToClass = {}
|
||||||
CItemID_TBL = TkCore::INTERP.create_table
|
CItemID_TBL = TkCore::INTERP.create_table
|
||||||
|
|
||||||
|
@ -529,8 +541,39 @@ class TkcItem<TkObject
|
||||||
end
|
end
|
||||||
|
|
||||||
########################################
|
########################################
|
||||||
|
def self._parse_create_args(args)
|
||||||
|
fontkeys = {}
|
||||||
|
if args[-1].kind_of? Hash
|
||||||
|
keys = _symbolkey2str(args.pop)
|
||||||
|
if args.size == 0
|
||||||
|
args = keys.delete('coords')
|
||||||
|
unless args.kind_of?(Array)
|
||||||
|
fail "coords parameter must be given by an Array"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
['font', 'kanjifont', 'latinfont', 'asciifont'].each{|key|
|
||||||
|
fontkeys[key] = keys.delete(key) if keys.key?(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
args = args.flatten.concat(hash_kv(keys))
|
||||||
|
else
|
||||||
|
args = args.flatten
|
||||||
|
end
|
||||||
|
|
||||||
|
[args, fontkeys]
|
||||||
|
end
|
||||||
|
private_class_method :_parse_create_args
|
||||||
|
|
||||||
def self.create(canvas, *args)
|
def self.create(canvas, *args)
|
||||||
fail RuntimeError, "TkcItem is an abstract class"
|
unless self::CItemTypeName
|
||||||
|
fail RuntimeError, "#{self} is an abstract class"
|
||||||
|
end
|
||||||
|
args, fontkeys = _parse_create_args(args)
|
||||||
|
idnum = tk_call_without_enc(canvas.path, 'create',
|
||||||
|
self::CItemTypeName, *args)
|
||||||
|
canvas.itemconfigure(idnum, fontkeys) unless fontkeys.empty?
|
||||||
|
idnum.to_i # 'canvas item id' is an integer number
|
||||||
end
|
end
|
||||||
########################################
|
########################################
|
||||||
|
|
||||||
|
@ -540,42 +583,13 @@ class TkcItem<TkObject
|
||||||
end
|
end
|
||||||
@parent = @c = parent
|
@parent = @c = parent
|
||||||
@path = parent.path
|
@path = parent.path
|
||||||
fontkeys = {}
|
|
||||||
if args.size == 1 && args[0].kind_of?(Hash)
|
@id = create_self(*args) # an integer number as 'canvas item id'
|
||||||
args[0] = _symbolkey2str(args[0])
|
|
||||||
coords = args[0].delete('coords')
|
|
||||||
unless coords.kind_of?(Array)
|
|
||||||
fail "coords parameter must be given by an Array"
|
|
||||||
end
|
|
||||||
args[0,0] = coords.flatten
|
|
||||||
end
|
|
||||||
if args[-1].kind_of? Hash
|
|
||||||
keys = _symbolkey2str(args.pop)
|
|
||||||
['font', 'kanjifont', 'latinfont', 'asciifont'].each{|key|
|
|
||||||
fontkeys[key] = keys.delete(key) if keys.key?(key)
|
|
||||||
}
|
|
||||||
args.concat(hash_kv(keys))
|
|
||||||
end
|
|
||||||
@id = create_self(*args).to_i ;# 'canvas item id' is integer number
|
|
||||||
CItemID_TBL[@path] = {} unless CItemID_TBL[@path]
|
CItemID_TBL[@path] = {} unless CItemID_TBL[@path]
|
||||||
CItemID_TBL[@path][@id] = self
|
CItemID_TBL[@path][@id] = self
|
||||||
configure(fontkeys) unless fontkeys.empty?
|
|
||||||
|
|
||||||
######## old version
|
|
||||||
# if args[-1].kind_of? Hash
|
|
||||||
# keys = args.pop
|
|
||||||
# end
|
|
||||||
# @id = create_self(*args).to_i ;# 'canvas item id' is integer number
|
|
||||||
# CItemID_TBL[@path] = {} unless CItemID_TBL[@path]
|
|
||||||
# CItemID_TBL[@path][@id] = self
|
|
||||||
# if keys
|
|
||||||
# # tk_call @path, 'itemconfigure', @id, *hash_kv(keys)
|
|
||||||
# configure(keys) if keys
|
|
||||||
# end
|
|
||||||
########
|
|
||||||
end
|
end
|
||||||
def create_self(*args)
|
def create_self(*args)
|
||||||
self.class.create(@path, *args)
|
self.class.create(@c, *args) # return an integer number as 'canvas item id'
|
||||||
end
|
end
|
||||||
private :create_self
|
private :create_self
|
||||||
|
|
||||||
|
@ -593,105 +607,65 @@ class TkcItem<TkObject
|
||||||
end
|
end
|
||||||
|
|
||||||
class TkcArc<TkcItem
|
class TkcArc<TkcItem
|
||||||
CItemTypeToClass['arc'] = self
|
CItemTypeName = 'arc'.freeze
|
||||||
def self.create(path, *args)
|
CItemTypeToClass[CItemTypeName] = self
|
||||||
if args[-1].kind_of?(Hash)
|
|
||||||
keys = args.pop
|
|
||||||
args.concat(hash_kv(keys))
|
|
||||||
end
|
|
||||||
tk_call_without_enc(path, 'create', 'arc', *args)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
class TkcBitmap<TkcItem
|
class TkcBitmap<TkcItem
|
||||||
CItemTypeToClass['bitmap'] = self
|
CItemTypeName = 'bitmap'.freeze
|
||||||
def self.create(path, *args)
|
CItemTypeToClass[CItemTypeName] = self
|
||||||
if args[-1].kind_of?(Hash)
|
|
||||||
keys = args.pop
|
|
||||||
args.concat(hash_kv(keys))
|
|
||||||
end
|
|
||||||
tk_call_without_enc(path, 'create', 'bitmap', *args)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
class TkcImage<TkcItem
|
class TkcImage<TkcItem
|
||||||
CItemTypeToClass['image'] = self
|
CItemTypeName = 'image'.freeze
|
||||||
def self.create(path, *args)
|
CItemTypeToClass[CItemTypeName] = self
|
||||||
if args[-1].kind_of?(Hash)
|
|
||||||
keys = args.pop
|
|
||||||
args.concat(hash_kv(keys))
|
|
||||||
end
|
|
||||||
tk_call_without_enc(path, 'create', 'image', *args)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
class TkcLine<TkcItem
|
class TkcLine<TkcItem
|
||||||
CItemTypeToClass['line'] = self
|
CItemTypeName = 'line'.freeze
|
||||||
def self.create(path, *args)
|
CItemTypeToClass[CItemTypeName] = self
|
||||||
if args[-1].kind_of?(Hash)
|
|
||||||
keys = args.pop
|
|
||||||
args.concat(hash_kv(keys))
|
|
||||||
end
|
|
||||||
tk_call_without_enc(path, 'create', 'line', *args)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
class TkcOval<TkcItem
|
class TkcOval<TkcItem
|
||||||
CItemTypeToClass['oval'] = self
|
CItemTypeName = 'oval'.freeze
|
||||||
def self.create(path, *args)
|
CItemTypeToClass[CItemTypeName] = self
|
||||||
if args[-1].kind_of?(Hash)
|
|
||||||
keys = args.pop
|
|
||||||
args.concat(hash_kv(keys))
|
|
||||||
end
|
|
||||||
tk_call_without_enc(path, 'create', 'oval', *args)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
class TkcPolygon<TkcItem
|
class TkcPolygon<TkcItem
|
||||||
CItemTypeToClass['polygon'] = self
|
CItemTypeName = 'polygon'.freeze
|
||||||
def self.create(path, *args)
|
CItemTypeToClass[CItemTypeName] = self
|
||||||
if args[-1].kind_of?(Hash)
|
|
||||||
keys = args.pop
|
|
||||||
args.concat(hash_kv(keys))
|
|
||||||
end
|
|
||||||
tk_call_without_enc(path, 'create', 'polygon', *args)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
class TkcRectangle<TkcItem
|
class TkcRectangle<TkcItem
|
||||||
CItemTypeToClass['rectangle'] = self
|
CItemTypeName = 'rectangle'.freeze
|
||||||
def self.create(path, *args)
|
CItemTypeToClass[CItemTypeName] = self
|
||||||
if args[-1].kind_of?(Hash)
|
|
||||||
keys = args.pop
|
|
||||||
args.concat(hash_kv(keys))
|
|
||||||
end
|
|
||||||
tk_call_without_enc(path, 'create', 'rectangle', *args)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
class TkcText<TkcItem
|
class TkcText<TkcItem
|
||||||
CItemTypeToClass['text'] = self
|
CItemTypeName = 'text'.freeze
|
||||||
def self.create(path, *args)
|
CItemTypeToClass[CItemTypeName] = self
|
||||||
|
def self.create(canvas, *args)
|
||||||
if args[-1].kind_of?(Hash)
|
if args[-1].kind_of?(Hash)
|
||||||
keys = args.pop
|
keys = _symbolkey2str(args.pop)
|
||||||
args.concat(hash_kv(keys))
|
txt = keys['text']
|
||||||
|
keys['text'] = _get_eval_enc_str(txt) if txt
|
||||||
|
args.push(keys)
|
||||||
end
|
end
|
||||||
#tk_call_without_enc(path, 'create', 'text',
|
super(canvas, *args)
|
||||||
# *(args.each{|arg| _get_eval_enc_str(arg)}))
|
|
||||||
tk_call(path, 'create', 'text', *args)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class TkcWindow<TkcItem
|
class TkcWindow<TkcItem
|
||||||
CItemTypeToClass['window'] = self
|
CItemTypeName = 'window'.freeze
|
||||||
def self.create(path, *args)
|
CItemTypeToClass[CItemTypeName] = self
|
||||||
|
def self.create(canvas, *args)
|
||||||
if args[-1].kind_of?(Hash)
|
if args[-1].kind_of?(Hash)
|
||||||
keys = _symbolkey2str(args.pop)
|
keys = _symbolkey2str(args.pop)
|
||||||
win = keys['window']
|
win = keys['window']
|
||||||
# keys['window'] = win.epath if win.kind_of?(TkWindow)
|
# keys['window'] = win.epath if win.kind_of?(TkWindow)
|
||||||
keys['window'] = _epath(win) if win
|
keys['window'] = _epath(win) if win
|
||||||
args.concat(hash_kv(keys))
|
args.push(keys)
|
||||||
end
|
end
|
||||||
tk_call_without_enc(path, 'create', 'window', *args)
|
super(canvas, *args)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -184,7 +184,7 @@ TkcText.new(cvs, '22.5c', '9c', 'anchor'=>'n', 'font'=>font1, 'width'=>'4c',
|
||||||
'text'=>'A short string of text, word-wrapped, justified left, and anchored north (at the top). The rectangles show the anchor points for each piece of text.', 'tags'=>$tag_item )
|
'text'=>'A short string of text, word-wrapped, justified left, and anchored north (at the top). The rectangles show the anchor points for each piece of text.', 'tags'=>$tag_item )
|
||||||
TkcRectangle.new(cvs, '25.4c','10.9c','25.6c','11.1c')
|
TkcRectangle.new(cvs, '25.4c','10.9c','25.6c','11.1c')
|
||||||
TkcText.new(cvs, '25.5c', '11c', 'anchor'=>'w', 'font'=>font1, 'fill'=>blue,
|
TkcText.new(cvs, '25.5c', '11c', 'anchor'=>'w', 'font'=>font1, 'fill'=>blue,
|
||||||
'text'=>'Several lines,\n each centered\nindividually,\nand all anchored\nat the left edge.', 'justify'=>'center', 'tags'=>$tag_item )
|
'text'=>"Several lines,\n each centered\nindividually,\nand all anchored\nat the left edge.", 'justify'=>'center', 'tags'=>$tag_item )
|
||||||
TkcRectangle.new(cvs, '24.9c','13.9c','25.1c','14.1c')
|
TkcRectangle.new(cvs, '24.9c','13.9c','25.1c','14.1c')
|
||||||
if $tk_version =~ /^4\.[01]/
|
if $tk_version =~ /^4\.[01]/
|
||||||
TkcText.new(cvs, '25c', '14c', 'anchor'=>'c', 'font'=>font2, 'fill'=>red,
|
TkcText.new(cvs, '25c', '14c', 'anchor'=>'c', 'font'=>font2, 'fill'=>red,
|
||||||
|
|
|
@ -178,12 +178,10 @@ TkcOval.new(cvs, '16c','10c','19c','15c', 'outline'=>'',
|
||||||
TkcText.new(cvs, '25c', '8.2c', 'text'=>'¥Æ¥¥¹¥È', 'anchor'=>'n')
|
TkcText.new(cvs, '25c', '8.2c', 'text'=>'¥Æ¥¥¹¥È', 'anchor'=>'n')
|
||||||
TkcRectangle.new(cvs, '22.4c','8.9c','22.6c','9.1c')
|
TkcRectangle.new(cvs, '22.4c','8.9c','22.6c','9.1c')
|
||||||
TkcText.new(cvs, '22.5c', '9c', 'anchor'=>'n', 'font'=>font1, 'width'=>'4c',
|
TkcText.new(cvs, '22.5c', '9c', 'anchor'=>'n', 'font'=>font1, 'width'=>'4c',
|
||||||
'text'=>'短いテキスト。ワードラップ、左揃え、アンカーは北 (上)。\
|
'text'=>'短いテキスト。ワードラップ、左揃え、アンカーは北(上)。□は各テキストのアンカーポイントを示す。', 'tags'=>$tag_item )
|
||||||
□は各テキストのアンカーポイントを示す。', 'tags'=>$tag_item )
|
|
||||||
TkcRectangle.new(cvs, '25.4c','10.9c','25.6c','11.1c')
|
TkcRectangle.new(cvs, '25.4c','10.9c','25.6c','11.1c')
|
||||||
TkcText.new(cvs, '25.5c', '11c', 'anchor'=>'w', 'font'=>font1, 'fill'=>blue,
|
TkcText.new(cvs, '25.5c', '11c', 'anchor'=>'w', 'font'=>font1, 'fill'=>blue,
|
||||||
'text'=>'いくつかの行。\nそれぞれ独立に\n行揃え。\n\
|
'text'=>"いくつかの行。\nそれぞれ独立に\n行揃え。\n全て左端がアンカーされている。", 'justify'=>'center', 'tags'=>$tag_item )
|
||||||
全て左端がアンカーされている。', 'justify'=>'center', 'tags'=>$tag_item )
|
|
||||||
TkcRectangle.new(cvs, '24.9c','13.9c','25.1c','14.1c')
|
TkcRectangle.new(cvs, '24.9c','13.9c','25.1c','14.1c')
|
||||||
if $tk_version =~ /^4\.[01]/
|
if $tk_version =~ /^4\.[01]/
|
||||||
TkcText.new(cvs, '25c', '14c', 'anchor'=>'c', 'font'=>font2, 'fill'=>red,
|
TkcText.new(cvs, '25c', '14c', 'anchor'=>'c', 'font'=>font2, 'fill'=>red,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue