Class: Teek::UI::CanvasItem
- Inherits:
-
Object
- Object
- Teek::UI::CanvasItem
- Defined in:
- lib/teek/ui/canvas_item.rb
Overview
A handle onto one or more canvas items, addressed by Tk's own
tagOrId - either the numeric id a create call returns (a single
item) or an arbitrary tag string (every item currently carrying it,
zero or more). Every method here is exactly that uniform - Tk's own
canvas command already treats a tag and an id identically for
move/coords/itemconfigure/delete/stacking/scale, so a shared tag is
addressable as a group with no separate "group handle" type: get one
via a shape-creation method (see Handle#line and friends, a
single-item handle) or Handle#tagged (an existing tag, whatever it
currently matches).
Instance Attribute Summary collapse
-
#tag_or_id ⇒ String
readonly
The tagOrId this handle addresses.
Instance Method Summary collapse
-
#[](opt) ⇒ String
Read back a single item option -
item[:fill]. -
#[]=(opt, value) ⇒ Object
Set a single item option -
item[:fill] = 'red'. -
#bounds ⇒ Array<Float>?
(also: #bbox)
[x1, y1, x2, y2]bounding box, ornilif nothing currently matches #tag_or_id. -
#bring_to_front(above = nil) ⇒ self
(also: #tk_raise)
Bring to the front of the stacking order (drawn last, on top of everything), or - given
above- just in front of that one item/tag instead of all the way to the front. -
#configure(**opts) ⇒ self
Mutate several item options at once.
-
#delete ⇒ nil
Remove the item(s) from the canvas.
-
#draggable {|x, y| ... } ⇒ self
Makes this item movable by mouse drag, with zero coordinate math of your own - press and drag it around the canvas, it follows the pointer.
-
#exists? ⇒ Boolean
Whether any item currently matches #tag_or_id - always true for a single-item handle from a creation method (the item exists until #deleted), meaningful for a Handle#tagged group that may currently match zero items.
-
#initialize(app, canvas_path, tag_or_id) ⇒ CanvasItem
constructor
private
A new instance of CanvasItem.
-
#move(dx, dy) ⇒ self
Move relative to the current position.
-
#on_click { ... } ⇒ self
Fires on a left click, only when the click lands on this specific item/tag - other items on the same canvas are untouched.
-
#on_drag {|x, y| ... } ⇒ self
Fires while dragging this item (left button held down and moving).
-
#on_right_click(menu = nil) { ... } ⇒ self
Fires on a right click, however the platform spells it - see MouseEvents::RIGHT_CLICK_EVENTS.
-
#points ⇒ Array<Float>
(also: #coords)
The current coordinate list.
-
#points=(new_coords) ⇒ void
(also: #coords=)
Replace the coordinate list outright (as opposed to #move's relative shift).
-
#scale(ox, oy, sx, sy) ⇒ self
Scale coordinates relative to a fixed point.
-
#send_to_back(below = nil) ⇒ self
(also: #lower)
Send to the back of the stacking order (drawn first, under everything), or - given
below- just behind that one item/tag instead of all the way to the back. -
#virtual_path ⇒ String
The canvas's own path, marked past the point a real Tk path stops applying - an item/tag has no independent Tk path of its own, only the canvas does.
Constructor Details
#initialize(app, canvas_path, tag_or_id) ⇒ CanvasItem
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns a new instance of CanvasItem.
22 23 24 25 26 |
# File 'lib/teek/ui/canvas_item.rb', line 22 def initialize(app, canvas_path, tag_or_id) @app = app @canvas_path = canvas_path @tag_or_id = tag_or_id.to_s end |
Instance Attribute Details
#tag_or_id ⇒ String (readonly)
Returns the tagOrId this handle addresses.
19 20 21 |
# File 'lib/teek/ui/canvas_item.rb', line 19 def tag_or_id @tag_or_id end |
Instance Method Details
#[](opt) ⇒ String
Read back a single item option - item[:fill].
77 78 79 |
# File 'lib/teek/ui/canvas_item.rb', line 77 def [](opt) @app.command(@canvas_path, :itemcget, @tag_or_id, "-#{opt}") end |
#[]=(opt, value) ⇒ Object
Set a single item option - item[:fill] = 'red'. Shorthand for
configure(opt => value) when there's only one to change.
86 87 88 89 |
# File 'lib/teek/ui/canvas_item.rb', line 86 def []=(opt, value) configure(opt => value) value end |
#bounds ⇒ Array<Float>? Also known as: bbox
Returns [x1, y1, x2, y2] bounding box, or
nil if nothing currently matches #tag_or_id.
140 141 142 143 |
# File 'lib/teek/ui/canvas_item.rb', line 140 def bounds result = @app.command(@canvas_path, :bbox, @tag_or_id) result.empty? ? nil : @app.split_list(result).map(&:to_f) end |
#bring_to_front(above = nil) ⇒ self Also known as: tk_raise
Bring to the front of the stacking order (drawn last, on top of
everything), or - given above - just in front of that one
item/tag instead of all the way to the front.
103 104 105 106 107 |
# File 'lib/teek/ui/canvas_item.rb', line 103 def bring_to_front(above = nil) args = above ? [resolve(above)] : [] @app.command(@canvas_path, :raise, @tag_or_id, *args) self end |
#configure(**opts) ⇒ self
Mutate several item options at once.
69 70 71 72 |
# File 'lib/teek/ui/canvas_item.rb', line 69 def configure(**opts) @app.command(@canvas_path, :itemconfigure, @tag_or_id, **opts) self end |
#delete ⇒ nil
Remove the item(s) from the canvas.
93 94 95 96 |
# File 'lib/teek/ui/canvas_item.rb', line 93 def delete @app.command(@canvas_path, :delete, @tag_or_id) nil end |
#draggable {|x, y| ... } ⇒ self
Makes this item movable by mouse drag, with zero coordinate math
of your own - press and drag it around the canvas, it follows the
pointer. Binds <Button-1> (to capture the starting position) and
<B1-Motion> (to shift #move by the delta each tick) on this
item/tag, replacing any #on_click/#on_drag binding already set
on it, the same way any two binds on the same item/event replace
each other in Tk.
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 |
# File 'lib/teek/ui/canvas_item.rb', line 221 def draggable(&block) last = nil press = lambda do |raw_x, raw_y| last = canvas_xy(raw_x, raw_y) end bind_item_event('<Button-1>', press, subs: %i[x y]) drag = lambda do |raw_x, raw_y| x, y = canvas_xy(raw_x, raw_y) move(x - last[0], y - last[1]) last = [x, y] block.call(x, y) if block end bind_item_event('<B1-Motion>', drag, subs: %i[x y]) self end |
#exists? ⇒ Boolean
Returns whether any item currently matches #tag_or_id - always true for a single-item handle from a creation method (the item exists until #deleted), meaningful for a Handle#tagged group that may currently match zero items.
150 151 152 |
# File 'lib/teek/ui/canvas_item.rb', line 150 def exists? !@app.command(@canvas_path, :find, :withtag, @tag_or_id).empty? end |
#move(dx, dy) ⇒ self
Move relative to the current position.
44 45 46 47 |
# File 'lib/teek/ui/canvas_item.rb', line 44 def move(dx, dy) @app.command(@canvas_path, :move, @tag_or_id, dx, dy) self end |
#on_click { ... } ⇒ self
Fires on a left click, only when the click lands on this specific
item/tag - other items on the same canvas are untouched. Wired
immediately, via the canvas's own bind subcommand (Tk has no
per-item widget path to bind a plain bind against) - unlike
Handle, a CanvasItem only ever exists post-realize, so there's no
queue-before-realize phase to worry about here.
162 163 164 165 |
# File 'lib/teek/ui/canvas_item.rb', line 162 def on_click(&block) bind_item_event('<Button-1>', block) self end |
#on_drag {|x, y| ... } ⇒ self
Fires while dragging this item (left button held down and moving). Delivers Integer x/y already converted through the canvas's own canvasx/canvasy, same as Handle#on_drag does when bound to a canvas - callers never have to remember to do that themselves.
201 202 203 204 205 206 207 208 |
# File 'lib/teek/ui/canvas_item.rb', line 201 def on_drag(&block) wrapped = lambda do |raw_x, raw_y| x, y = canvas_xy(raw_x, raw_y) block.call(x, y) end bind_item_event('<B1-Motion>', wrapped, subs: %i[x y]) self end |
#on_right_click(menu = nil) { ... } ⇒ self
Fires on a right click, however the platform spells it - see
MouseEvents::RIGHT_CLICK_EVENTS. Either handle it yourself with a
block, or hand it a :menu/:context_menu handle to pop up at the
click's screen position - not both.
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 |
# File 'lib/teek/ui/canvas_item.rb', line 175 def on_right_click( = nil, &block) if && block raise ArgumentError, "on_right_click takes either a menu handle or a block, not both" elsif unless MouseEvents::MENU_HANDLE_TYPES.include?(.type) raise ArgumentError, "on_right_click(menu) needs a :menu or :context_menu handle (got a :#{.type})" end popup = lambda do |root_x, root_y| @app.(.path, x: root_x, y: root_y) end MouseEvents::RIGHT_CLICK_EVENTS.each { |event| bind_item_event(event, popup, subs: %i[root_x root_y]) } elsif block MouseEvents::RIGHT_CLICK_EVENTS.each { |event| bind_item_event(event, block) } else raise ArgumentError, "on_right_click needs either a menu handle or a block" end self end |
#points ⇒ Array<Float> Also known as: coords
Returns the current coordinate list.
50 51 52 53 |
# File 'lib/teek/ui/canvas_item.rb', line 50 def points result = @app.command(@canvas_path, :coords, @tag_or_id) @app.split_list(result).map(&:to_f) end |
#points=(new_coords) ⇒ void Also known as: coords=
This method returns an undefined value.
Replace the coordinate list outright (as opposed to #move's relative shift).
61 62 63 |
# File 'lib/teek/ui/canvas_item.rb', line 61 def points=(new_coords) @app.command(@canvas_path, :coords, @tag_or_id, *new_coords.flatten) end |
#scale(ox, oy, sx, sy) ⇒ self
Scale coordinates relative to a fixed point.
133 134 135 136 |
# File 'lib/teek/ui/canvas_item.rb', line 133 def scale(ox, oy, sx, sy) @app.command(@canvas_path, :scale, @tag_or_id, ox, oy, sx, sy) self end |
#send_to_back(below = nil) ⇒ self Also known as: lower
Send to the back of the stacking order (drawn first, under
everything), or - given below - just behind that one item/tag
instead of all the way to the back.
120 121 122 123 124 |
# File 'lib/teek/ui/canvas_item.rb', line 120 def send_to_back(below = nil) args = below ? [resolve(below)] : [] @app.command(@canvas_path, :lower, @tag_or_id, *args) self end |
#virtual_path ⇒ String
Returns the canvas's own path, marked past the point a
real Tk path stops applying - an item/tag has no independent Tk
path of its own, only the canvas does. ! is illegal in a Tk
path segment, so handing this to a raw Tk command fails loudly
(an "invalid command name" Tcl error) instead of silently
misbehaving - the same marked-address shape
MenuEntryAddressing#virtual_path uses for a menu entry, the
other kind of thing with no Tk path of its own.
36 37 38 |
# File 'lib/teek/ui/canvas_item.rb', line 36 def virtual_path "#{@canvas_path}!#{@tag_or_id}" end |