Updating samples to include focus pages

This commit is contained in:
Matthias Koefferlein 2025-09-04 19:24:49 +02:00
parent b9115fc0a2
commit b3123d385a
2 changed files with 474 additions and 85 deletions

View File

@ -8,29 +8,39 @@
<shortcut></shortcut> <shortcut></shortcut>
<interpreter>ruby</interpreter> <interpreter>ruby</interpreter>
<text># Sample plugin <text># Sample plugin
#
# This plugin implements a box that can be drawn by # This plugin implements a box that can be drawn by
# clicking at the first and then at the second point. # clicking at the first and then at the second point.
# There is one box which is replacing the previous one. # There is one box which is replacing the previous one.
# Line color and line width of the box can be configured # Line color and line width of the box can be configured
# by editor options (line width) or configuration pages # by editor options (line width) or configuration pages
# (color). # (color). These settings are managed through configuration
# options and their current state is persisted.
#
# The dimension of the box can be entered numerically
# while dragging the box. This feature is implemented
# through a modal "focus page", which opens when you
# press the Tab key during editing and when the keyboard
# focus is on the canvas.
#
# Register this macro as "autorun" to enable the plugin
# on startup.
module DragBox module DragBox
# Register this macro as "autorun" to enable the plugin
CFG_COLOR = "drag-box-color" CFG_COLOR = "drag-box-color"
CFG_WIDTH = "drag-box-width" CFG_WIDTH = "drag-box-width"
# The widget placed into the editor options dock # An option page providing a single entry box for configuring the line width
# This page communicates via configuration options. One advantage of this
# approach is that the values are persisted
class DragBoxEditorOptionsPage &lt; RBA::EditorOptionsPage class DragBoxEditorOptionsPage &lt; RBA::EditorOptionsPage
# Creates a new page with title "Options" and at position 1 (second from left)
def initialize def initialize
# Creates a new page with title "Options" and at
# position 1 (second from left)
super("Options", 1) super("Options", 1)
layout2 = RBA::QVBoxLayout::new(self) layout2 = RBA::QVBoxLayout::new(self)
@ -44,10 +54,15 @@ class DragBoxEditorOptionsPage &lt; RBA::EditorOptionsPage
layout.addWidget(@spin_box) layout.addWidget(@spin_box)
layout.addStretch(1) layout.addStretch(1)
layout2.addStretch(1) layout2.addStretch(1)
# connect the spin box value change with the "edited" slot
# which will result in a call of "apply".
@spin_box.valueChanged = lambda { |x| self.edited } @spin_box.valueChanged = lambda { |x| self.edited }
end end
# "setup" is called when the page needs to be populated with information -
# i.e. on first show.
def setup(dispatcher) def setup(dispatcher)
begin begin
@spin_box.setValue(dispatcher.get_config(CFG_WIDTH).to_i) @spin_box.setValue(dispatcher.get_config(CFG_WIDTH).to_i)
@ -56,23 +71,123 @@ class DragBoxEditorOptionsPage &lt; RBA::EditorOptionsPage
end end
end end
# "apply" is called when the page is requested to submit the entered
# values to the plugin. Usually this should be done via configuration
# events.
def apply(dispatcher) def apply(dispatcher)
dispatcher.set_config(CFG_WIDTH, @spin_box.value.to_s) dispatcher.set_config(CFG_WIDTH, @spin_box.value.to_s)
end end
end end
# The widget placed into the configuration page # A (modal) option page, also called a "focus page". This page is
# registered like an editor options page. It is brought to front
class DragBoxConfigPage &lt; RBA::ConfigPage # when the user hits the "Tab" key during editing.
# In this case, this page uses "setup" and "apply" callbacks to
# set and fetch information. It also employs a handler named
# "update_box" to communicate changes between the client (the
# plugin) and the page.
#
# Attributes that the client needs to take care of are
# "self.box" (the current box), "self.pfix" (the start point)
# and "self.update_box".
class DragBoxFocusPage &lt; RBA::EditorOptionsPage
# Creates a new page with title "Options" and at
# position 1 (second from left)
attr_accessor :box
attr_accessor :pfix
attr_accessor :update_box
def initialize def initialize
super("Geometry", 2)
self.focus_page = true
self.modal_page = true
@box = RBA::DBox::new
@pfix = RBA::DPoint::new
layout = RBA::QGridLayout::new(self)
layout.setColumnStretch(1, 1)
label = RBA::QLabel::new("Width", self)
layout.addWidget(label, 0, 0, 1, 1)
@le_width = RBA::QLineEdit::new(self)
layout.addWidget(@le_width, 0, 1, 1, 1)
label = RBA::QLabel::new("Height", self)
layout.addWidget(label, 1, 0, 1, 1)
@le_height = RBA::QLineEdit::new(self)
layout.addWidget(@le_height, 1, 1, 1, 1)
layout.setRowStretch(2, 1)
end
# Is called when the page needs to be set up.
# We assume that the client has properly set up self.box
def setup(dispatcher)
@le_width.text = "%.12g" % @box.width
@le_height.text = "%.12g" % @box.height
end
# Apply is called when the dialog is accepted or the "Apply" button is pressed
# Usually this method is intended to submit configuration parameter changes,
# but we can use it for any other purpose as well.
# places the widget on a new section ("Drag Box") def apply(dispatcher)
# and "Configure" page
# fetches the coordinates from the entry boxes
# throws an exception in case of an error
x = @le_width.text.to_f
y = @le_height.text.to_f
# prepares a new box with the given dimensions
# using the initial point ("pfix") and considering
# the drag direction
t = b = @pfix.y
l = r = @pfix.x
if @box.bottom &lt; t - 1e-10
b = t - y
else
t = b + y
end
if @box.left &lt; l - 1e-10
l = r - x
else
r = l + x
end
# issue the event (call the handler) to inform the plugin of this change
if @update_box
@update_box.call(RBA::DBox::new(l, b, r, t))
end
end
end
# The widget placed into the configuration page
# A configuration page with a single entry box to change
# the box color in RGB hex style.
# Configuration pages appear in the Setup dialog and can
# communicate only through configuration parameter updates.
class DragBoxConfigPage &lt; RBA::ConfigPage
# Initializes the page. Places it on a new section ("Drag Box") and "Configure" page
# and creates a single entry field.
def initialize
super("Drag Box|Configure") super("Drag Box|Configure")
# Qt user interface setup
layout = RBA::QHBoxLayout::new(self) layout = RBA::QHBoxLayout::new(self)
label = RBA::QLabel::new("Color (hex, rrggbb)", self) label = RBA::QLabel::new("Color (hex, rrggbb)", self)
layout.addWidget(label) layout.addWidget(label)
@ -82,22 +197,26 @@ class DragBoxConfigPage &lt; RBA::ConfigPage
end end
# This method is called to request an update of the entry fields
def setup(dispatcher) def setup(dispatcher)
@line_edit.setText(dispatcher.get_config(CFG_COLOR)) @line_edit.setText(dispatcher.get_config(CFG_COLOR))
end end
# This method is called to request a transfer of the edited values
# to the configuration space.
def apply(dispatcher) def apply(dispatcher)
dispatcher.set_config(CFG_COLOR, @line_edit.text) dispatcher.set_config(CFG_COLOR, @line_edit.text)
end end
end end
# The custom plugin implementation.
class DragBoxPlugin &lt; RBA::Plugin class DragBoxPlugin &lt; RBA::Plugin
def initialize(view) def initialize(view)
super() super()
@marker = nil @marker = nil
@last_box = nil @last_marker = nil
@box = nil @box = nil
@start_point = nil @start_point = nil
@view = view @view = view
@ -105,14 +224,14 @@ class DragBoxPlugin &lt; RBA::Plugin
@width = 1 @width = 1
end end
# This method receives configuration callbacks
def configure(name, value) def configure(name, value)
# receives configuration callbacks
if name == CFG_COLOR if name == CFG_COLOR
# configure marker color # configure marker color
begin begin
@color = value != "" ? value.to_i(16) : nil @color = value != "" ? value.to_i(16) : nil
rescue rescue
self.color = nil @color = nil
end end
self._configure_marker self._configure_marker
elsif name == CFG_WIDTH elsif name == CFG_WIDTH
@ -126,57 +245,97 @@ class DragBoxPlugin &lt; RBA::Plugin
end end
end end
# clears all markers
def _clear_marker def _clear_marker
# clears all markers [ @marker, @last_marker ].each { |marker| marker &amp;&amp; marker._destroy }
[ @marker, @last_box ].each { |m| m &amp;&amp; m._destroy }
@marker = nil @marker = nil
@last_box = nil @last_marker = nil
end end
# stops dragging the marker and copy to a static one
def _finish
if @last_marker
@last_marker._destroy
end
@last_marker = @marker
@marker = nil
# reset to idle
self.ungrab_mouse
RBA::MainWindow.instance.message("Box finished: " + @box.to_s, 10000)
end
# updates the marker with the current box
def _update_marker def _update_marker
# updates the marker with the current box if ! @marker
if !@marker @marker = RBA::Marker::new(@view)
@marker = RBA::Marker::new(self.view)
self._configure_marker self._configure_marker
end end
@marker.set(@box) @marker.set(@box)
end end
def freeze_marker # changes the marker's appearance
# stop dragging the marker and copy to a static one
if @last_box
@last_box._destroy()
end
@last_box = @marker
@marker = nil
end
def _configure_marker def _configure_marker
# change the marker's appearance
if @marker if @marker
@marker.line_style = 2 # short-dashed @marker.line_style = 2 # short-dashed
@marker.vertex_size = 0 # no vertexes @marker.vertex_size = 0 # no vertexes
@marker.line_width = @width @marker.line_width = @width
@marker.color = @color ? (@color | 0xff000000) : 0 @marker.color = @color ? (@color | 0xff000000) : 0 # auto
end end
end end
# Updates the box with the given value and updates the marker.
# This method is bound to the focus page handler when needed.
def _update_box(box)
@box = box
self._update_marker
end
# overloaded callback: the focus page is requested
def focus_page_open(fp)
# stop unless dragging
if !@marker
return
end
# configure the focus page and show it:
# the page will call the handler of "update_box" to commit
# changes to the box
fp.box = @box
fp.pfix = @start_point
fp.update_box = lambda { |box| self._update_box(box) }
ret = fp.show
fp.update_box = nil
if ret == 1
# accepted: stop dragging now, we are done.
self._finish
end
return ret
end
# overloaded callback:
# plugin is activated - i.e. the mode is selected
def activated def activated
# plugin is activated - i.e. the mode is selected
RBA::MainWindow.instance.message("Click on point to start dragging a box", 10000) RBA::MainWindow.instance.message("Click on point to start dragging a box", 10000)
end end
# overloaded callback:
# plugin is deactivated - i.e. the mode is unselected
def deactivated def deactivated
# plugin is deactivated - i.e. the mode is unselected
self._clear_marker self._clear_marker
RBA::MainWindow.instance.message("", 0) RBA::MainWindow.instance.message("", 0)
end end
# overloaded callback:
# a mouse button was clicked
def mouse_click_event(p, buttons, prio) def mouse_click_event(p, buttons, prio)
if prio if prio
# first-level event: start a new box or # first-level event: start a new box or
# stop dragging it and freeze the box # stop dragging it and freeze the box
if !@marker if ! @marker
p = self.snap2(p) p = self.snap2(p)
@box = RBA::DBox::new(p, p) @box = RBA::DBox::new(p, p)
@start_point = p @start_point = p
@ -186,49 +345,55 @@ class DragBoxPlugin &lt; RBA::Plugin
RBA::MainWindow.instance.message("Drag the box and click again", 10000) RBA::MainWindow.instance.message("Drag the box and click again", 10000)
else else
p = self.snap2(p, @start_point, true, self.ac_from_buttons(buttons)) p = self.snap2(p, @start_point, true, self.ac_from_buttons(buttons))
self.freeze_marker self._update_box(RBA::DBox::new(@start_point, p))
self.ungrab_mouse self._finish
RBA::MainWindow.instance.message("Box finished: " + @box.to_s, 10000)
end end
# consume event
return true return true
else
return false
end end
return false
end end
# overloaded callback:
# the mouse was moved
def mouse_moved_event(p, buttons, prio) def mouse_moved_event(p, buttons, prio)
if prio if prio
# first-level event: if not dragging, provide a # first-level event: if not dragging, provide a
# mouse cursor for tracking. If dragging, update # mouse cursor for tracking. If dragging, update
# the box and provide a mouse cursor. # the box and provide a mouse cursor.
if !@marker if !@marker
self.clear_mouse_cursors self.clear_mouse_cursors
p = self.snap2(p, true) p = self.snap2(p, :visualize =&gt; true)
self.add_mouse_cursor(p) self.add_mouse_cursor(p)
else else
self.clear_mouse_cursors self.clear_mouse_cursors
p = self.snap2(p, @start_point, true, self.ac_from_buttons(buttons), true) p = self.snap2(p, @start_point, true, self.ac_from_buttons(buttons), :visualize =&gt; true)
self.add_mouse_cursor(p) self.add_mouse_cursor(p)
@box = RBA::DBox::new(@start_point, p) @box = RBA::DBox::new(@start_point, p)
self._update_marker self._update_marker
end end
end end
# NOTE: we must not digest this event (i.e. return true) # NOTE: we must not digest this event (i.e. return true)
# to allow the mouse tracker to receive the events as well # to allow the mouse tracker to receive the events as well
return false return false
end end
end end
# Implements a "plugin factory". # Implements a "plugin factory".
# Purpose of this object is to create a plugin object # The purpose of this object is to create a plugin object
# and corresponding UI objects. # and corresponding UI objects.
class DragBoxPluginFactory &lt; RBA::PluginFactory class DragBoxPluginFactory &lt; RBA::PluginFactory
def initialize def initialize
super() super
self.has_tool_entry = true self.has_tool_entry = true
# NOTE: it's a good practice to register configuration options # NOTE: it's a good practice to register configuration options
self.add_option(CFG_WIDTH, "1") self.add_option(CFG_WIDTH, "1")
@ -236,23 +401,28 @@ class DragBoxPluginFactory &lt; RBA::PluginFactory
self.register(-1000, "drag_box", "Drag Box") self.register(-1000, "drag_box", "Drag Box")
end end
# Called to create the configuration pages
def create_config_pages def create_config_pages
self.add_config_page(DragBoxConfigPage::new) self.add_config_page(DragBoxConfigPage::new)
end end
# Called to create the editor options pages
def create_editor_options_pages def create_editor_options_pages
self.add_editor_options_page(DragBoxEditorOptionsPage::new) self.add_editor_options_page(DragBoxEditorOptionsPage::new)
self.add_editor_options_page(DragBoxFocusPage::new)
end end
# Creates the plugin
def create_plugin(manager, root, view) def create_plugin(manager, root, view)
return DragBoxPlugin::new(view) return DragBoxPlugin::new(view)
end end
end
# Create the singleton instance - as we register it, end
# Creates the singleton instance - as we register it,
# it is not garbage collected # it is not garbage collected
DragBoxPluginFactory::new DragBoxPluginFactory::new
end</text> end
</text>
</klayout-macro> </klayout-macro>

View File

@ -8,15 +8,23 @@
<shortcut></shortcut> <shortcut></shortcut>
<interpreter>python</interpreter> <interpreter>python</interpreter>
<text># Sample plugin <text># Sample plugin
#
# This plugin implements a box that can be drawn by # This plugin implements a box that can be drawn by
# clicking at the first and then at the second point. # clicking at the first and then at the second point.
# There is one box which is replacing the previous one. # There is one box which is replacing the previous one.
# Line color and line width of the box can be configured # Line color and line width of the box can be configured
# by editor options (line width) or configuration pages # by editor options (line width) or configuration pages
# (color). # (color). These settings are managed through configuration
# options and their current state is persisted.
#
# The dimension of the box can be entered numerically
# while dragging the box. This feature is implemented
# through a modal "focus page", which opens when you
# press the Tab key during editing and when the keyboard
# focus is on the canvas.
#
# Register this macro as "autorun" to enable the plugin # Register this macro as "autorun" to enable the plugin
# on startup.
cfg_color = "drag-box-color" cfg_color = "drag-box-color"
cfg_width = "drag-box-width" cfg_width = "drag-box-width"
@ -24,11 +32,19 @@ cfg_width = "drag-box-width"
# The widget placed into the editor options dock # The widget placed into the editor options dock
class DragBoxEditorOptionsPage(pya.EditorOptionsPage): class DragBoxEditorOptionsPage(pya.EditorOptionsPage):
"""
An option page providing a single entry box for configuring the line width
This page communicates via configuration options. One advantage of this
approach is that the values are persisted
"""
def __init__(self): def __init__(self):
# Creates a new page with title "Options" and at """
# position 1 (second from left) Creates a new page with title "Options" and at position 1 (second from left)
"""
super(DragBoxEditorOptionsPage, self).__init__("Options", 1) super(DragBoxEditorOptionsPage, self).__init__("Options", 1)
layout2 = pya.QVBoxLayout(self) layout2 = pya.QVBoxLayout(self)
@ -43,25 +59,142 @@ class DragBoxEditorOptionsPage(pya.EditorOptionsPage):
layout.addStretch(1) layout.addStretch(1)
layout2.addStretch(1) layout2.addStretch(1)
# connect the spin box value change with the "edited" slot
# which will result in a call of "apply".
self.spin_box.valueChanged = lambda x: self.edited() self.spin_box.valueChanged = lambda x: self.edited()
def setup(self, dispatcher): def setup(self, dispatcher):
"""
"setup" is called when the page needs to be populated with information -
i.e. on first show.
"""
try: try:
self.spin_box.setValue(int(dispatcher.get_config(cfg_width))) self.spin_box.setValue(int(dispatcher.get_config(cfg_width)))
except: except:
self.spin_box.setValue(1) self.spin_box.setValue(1)
def apply(self, dispatcher): def apply(self, dispatcher):
"""
"apply" is called when the page is requested to submit the entered
values to the plugin. Usually this should be done via configuration
events.
"""
dispatcher.set_config(cfg_width, str(self.spin_box.value)) dispatcher.set_config(cfg_width, str(self.spin_box.value))
# The modal dialog page that appears when "Tab" is pressed
class DragBoxFocusPage(pya.EditorOptionsPage):
"""
A (modal) option page, also called a "focus page". This page is
registered like an editor options page. It is brought to front
when the user hits the "Tab" key during editing.
In this case, this page uses "setup" and "apply" callbacks to
set and fetch information. It also employs a handler named
"update_box" to communicate changes between the client (the
plugin) and the page.
Attributes that the client needs to take care of are
"self.box" (the current box), "self.pfix" (the start point)
and "self.update_box".
"""
def __init__(self):
"""
Creates a new page with title "Options" and at
position 1 (second from left)
"""
super(DragBoxFocusPage, self).__init__("Geometry", 2)
self.focus_page = True
self.modal_page = True
self.box = pya.DBox()
self.pfix = pya.DPoint()
self.update_box = None
layout = pya.QGridLayout(self)
layout.setColumnStretch(1, 1)
label = pya.QLabel("Width", self)
layout.addWidget(label, 0, 0, 1, 1)
self.le_width = pya.QLineEdit(self)
layout.addWidget(self.le_width, 0, 1, 1, 1)
label = pya.QLabel("Height", self)
layout.addWidget(label, 1, 0, 1, 1)
self.le_height = pya.QLineEdit(self)
layout.addWidget(self.le_height, 1, 1, 1, 1)
layout.setRowStretch(2, 1)
def setup(self, dispatcher):
"""
Is called when the page needs to be set up.
We assume that the client has properly set up self.box
"""
self.le_width.text = "%.12g" % self.box.width()
self.le_height.text = "%.12g" % self.box.height()
def apply(self, dispatcher):
"""
Apply is called when the dialog is accepted or the "Apply" button is pressed
Usually this method is intended to submit configuration parameter changes,
but we can use it for any other purpose as well.
"""
# fetches the coordinates from the entry boxes
# throws an exception in case of an error
x = float(self.le_width.text)
y = float(self.le_height.text)
# prepares a new box with the given dimensions
# using the initial point ("pfix") and considering
# the drag direction
t = b = self.pfix.y
l = r = self.pfix.x
if self.box.bottom &lt; t - 1e-10:
b = t - y
else:
t = b + y
if self.box.left &lt; l - 1e-10:
l = r - x
else:
r = l + x
# issue the event (call the handler) to inform the plugin of this change
if self.update_box is not None:
self.update_box(pya.DBox(l, b, r, t))
# The widget placed into the configuration page # The widget placed into the configuration page
class DragBoxConfigPage(pya.ConfigPage): class DragBoxConfigPage(pya.ConfigPage):
"""
A configuration page with a single entry box to change
the box color in RGB hex style.
Configuration pages appear in the Setup dialog and can
communicate only through configuration parameter updates.
"""
def __init__(self): def __init__(self):
# places the widget on a new section ("Drag Box") """
# and "Configure" page Initializes the page. Places it on a new section ("Drag Box") and "Configure" page
and creates a single entry field.
"""
super(DragBoxConfigPage, self).__init__("Drag Box|Configure") super(DragBoxConfigPage, self).__init__("Drag Box|Configure")
layout = pya.QHBoxLayout(self) layout = pya.QHBoxLayout(self)
@ -72,17 +205,28 @@ class DragBoxConfigPage(pya.ConfigPage):
layout.addStretch(1) layout.addStretch(1)
def setup(self, dispatcher): def setup(self, dispatcher):
"""
This method is called to request an update of the entry fields
"""
self.line_edit.setText(dispatcher.get_config(cfg_color)) self.line_edit.setText(dispatcher.get_config(cfg_color))
def apply(self, dispatcher): def apply(self, dispatcher):
"""
This method is called to request a transfer of the edited values
to the configuration space.
"""
dispatcher.set_config(cfg_color, self.line_edit.text) dispatcher.set_config(cfg_color, self.line_edit.text)
class DragBoxPlugin(pya.Plugin): class DragBoxPlugin(pya.Plugin):
"""
The custom plugin implementation.
"""
def __init__(self, view): def __init__(self, view):
super(DragBoxPlugin, self).__init__() super(DragBoxPlugin, self).__init__()
self.marker = None self.marker = None
self.last_box = None self.last_marker = None
self.box = None self.box = None
self.start_point = None self.start_point = None
self.view = view self.view = view
@ -90,8 +234,9 @@ class DragBoxPlugin(pya.Plugin):
self.width = 1 self.width = 1
def configure(self, name, value): def configure(self, name, value):
# receives configuration callbacks """
needs_update = False This method receives configuration callbacks
"""
if name == cfg_color: if name == cfg_color:
# configure marker color # configure marker color
try: try:
@ -111,29 +256,40 @@ class DragBoxPlugin(pya.Plugin):
self._configure_marker() self._configure_marker()
def _clear_marker(self): def _clear_marker(self):
# clears all markers """
for marker in [ self.marker, self.last_box ]: clears all markers
"""
for marker in [ self.marker, self.last_marker ]:
if marker is not None: if marker is not None:
marker._destroy() marker._destroy()
self.marker = None self.marker = None
self.last_box = None self.last_marker = None
def _finish(self):
"""
stops dragging the marker and copy to a static one
"""
if self.last_marker is not None:
self.last_marker._destroy()
self.last_marker = self.marker
self.marker = None
# reset to idle
self.ungrab_mouse()
pya.MainWindow.instance().message("Box finished: " + str(self.box), 10000)
def _update_marker(self): def _update_marker(self):
# updates the marker with the current box """
updates the marker with the current box
"""
if self.marker is None: if self.marker is None:
self.marker = pya.Marker(self.view) self.marker = pya.Marker(self.view)
self._configure_marker() self._configure_marker()
self.marker.set(self.box) self.marker.set(self.box)
def freeze_marker(self):
# stop dragging the marker and copy to a static one
if self.last_box is not None:
self.last_box._destroy()
self.last_box = self.marker
self.marker = None
def _configure_marker(self): def _configure_marker(self):
# change the marker's appearance """
changes the marker's appearance
"""
if self.marker is not None: if self.marker is not None:
self.marker.line_style = 2 # short-dashed self.marker.line_style = 2 # short-dashed
self.marker.vertex_size = 0 # no vertexes self.marker.vertex_size = 0 # no vertexes
@ -142,17 +298,64 @@ class DragBoxPlugin(pya.Plugin):
self.marker.color = self.color | 0xff000000 self.marker.color = self.color | 0xff000000
else: else:
self.marker.color = 0 # auto self.marker.color = 0 # auto
def _update_box(self, box):
"""
Updates the box with the given value and updates the marker.
This method is bound to the focus page handler when needed.
"""
self.box = box
self._update_marker()
def focus_page_open(self, fp):
"""
overloaded callback: the focus page is requested
"""
# stop unless dragging
if self.marker is None:
return
# configure the focus page and show it:
# the page will call the handler of "update_box" to commit
# changes to the box
fp.box = self.box
fp.pfix = self.start_point
fp.update_box = self._update_box
ret = fp.show()
fp.update_box = None
if ret == 1:
# accepted: stop dragging now, we are done.
self._finish()
return ret
def activated(self): def activated(self):
# plugin is activated - i.e. the mode is selected
"""
overloaded callback:
plugin is activated - i.e. the mode is selected
"""
pya.MainWindow.instance().message("Click on point to start dragging a box", 10000) pya.MainWindow.instance().message("Click on point to start dragging a box", 10000)
def deactivated(self): def deactivated(self):
# plugin is deactivated - i.e. the mode is unselected
"""
overloaded callback:
plugin is deactivated - i.e. the mode is unselected
"""
self._clear_marker() self._clear_marker()
pya.MainWindow.instance().message("", 0) pya.MainWindow.instance().message("", 0)
def mouse_click_event(self, p, buttons, prio): def mouse_click_event(self, p, buttons, prio):
"""
overloaded callback:
a mouse button was clicked
"""
if prio: if prio:
# first-level event: start a new box or # first-level event: start a new box or
# stop dragging it and freeze the box # stop dragging it and freeze the box
@ -166,13 +369,18 @@ class DragBoxPlugin(pya.Plugin):
pya.MainWindow.instance().message("Drag the box and click again", 10000) pya.MainWindow.instance().message("Drag the box and click again", 10000)
else: else:
p = self.snap2(p, self.start_point, True, self.ac_from_buttons(buttons)) p = self.snap2(p, self.start_point, True, self.ac_from_buttons(buttons))
self.freeze_marker() self._update_box(pya.DBox(self.start_point, p))
self.ungrab_mouse() self._finish()
pya.MainWindow.instance().message("Box finished: " + str(self.box), 10000)
return True return True
return False return False
def mouse_moved_event(self, p, buttons, prio): def mouse_moved_event(self, p, buttons, prio):
"""
overloaded callback:
the mouse was moved
"""
if prio: if prio:
# first-level event: if not dragging, provide a # first-level event: if not dragging, provide a
# mouse cursor for tracking. If dragging, update # mouse cursor for tracking. If dragging, update
@ -191,13 +399,14 @@ class DragBoxPlugin(pya.Plugin):
# to allow the mouse tracker to receive the events as well # to allow the mouse tracker to receive the events as well
return False return False
# Implements a "plugin factory".
# Purpose of this object is to create a plugin object
# and corresponding UI objects.
class DragBoxPluginFactory(pya.PluginFactory): class DragBoxPluginFactory(pya.PluginFactory):
"""
Implements a "plugin factory".
The purpose of this object is to create a plugin object
and corresponding UI objects.
"""
def __init__(self): def __init__(self):
super(DragBoxPluginFactory, self).__init__() super(DragBoxPluginFactory, self).__init__()
self.has_tool_entry = True self.has_tool_entry = True
@ -207,15 +416,25 @@ class DragBoxPluginFactory(pya.PluginFactory):
self.register(-1000, "drag_box", "Drag Box") self.register(-1000, "drag_box", "Drag Box")
def create_config_pages(self): def create_config_pages(self):
"""
Called to create the configuration pages
"""
self.add_config_page(DragBoxConfigPage()) self.add_config_page(DragBoxConfigPage())
def create_editor_options_pages(self): def create_editor_options_pages(self):
"""
Called to create the editor options pages
"""
self.add_editor_options_page(DragBoxEditorOptionsPage()) self.add_editor_options_page(DragBoxEditorOptionsPage())
self.add_editor_options_page(DragBoxFocusPage())
def create_plugin(self, manager, root, view): def create_plugin(self, manager, root, view):
"""
Creates the plugin
"""
return DragBoxPlugin(view) return DragBoxPlugin(view)
# Create the singleton instance - as we register it, # Creates the singleton instance - as we register it,
# it is not garbage collected # it is not garbage collected
DragBoxPluginFactory() DragBoxPluginFactory()
</text> </text>