Merge pull request #2264 from KLayout/wip

Wip
This commit is contained in:
Matthias Köfferlein 2026-02-07 09:46:38 +01:00 committed by GitHub
commit 887914944b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
143 changed files with 4935 additions and 1467 deletions

View File

@ -20,11 +20,11 @@ jobs:
max-parallel: 12
matrix:
include:
- os: "macos-13" # intel runner
- os: "macos-15-intel" # intel runner
cibuild: "*macosx*"
cibw_arch: "macos_x86_64"
macos-arch: "x86_64"
- os: "macos-14" # M1 runner
- os: "macos-latest" # M1 runner
cibuild: "*macosx*"
cibw_arch: "macos_arm64"
macos-arch: "arm64"

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>665</width>
<height>103</height>
<height>108</height>
</rect>
</property>
<property name="windowTitle">
@ -56,6 +56,13 @@
<property name="spacing">
<number>0</number>
</property>
<item row="1" column="1">
<widget class="QRadioButton" name="ruler_diag_rb">
<property name="text">
<string>Diagonal</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QRadioButton" name="ruler_hor_rb">
<property name="text">
@ -77,17 +84,17 @@
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QRadioButton" name="ruler_diag_rb">
<item row="0" column="3">
<widget class="QRadioButton" name="ruler_vert_rb">
<property name="text">
<string>Diagonal</string>
<string>Vertical only</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QRadioButton" name="ruler_vert_rb">
<widget class="QRadioButton" name="ruler_diag_only_rb">
<property name="text">
<string>Vertical only</string>
<string>Diagonal only</string>
</property>
</widget>
</item>
@ -102,7 +109,6 @@
<tabstop>ruler_ortho_rb</tabstop>
<tabstop>ruler_diag_rb</tabstop>
<tabstop>ruler_hor_rb</tabstop>
<tabstop>ruler_vert_rb</tabstop>
</tabstops>
<resources/>
<connections/>

View File

@ -644,6 +644,11 @@
<string>Orthogonal</string>
</property>
</item>
<item>
<property name="text">
<string>Diagonal only</string>
</property>
</item>
<item>
<property name="text">
<string>Horizontal only</string>

View File

@ -31,6 +31,7 @@ SOURCES = \
HEADERS += \
antConfig.h \
antEditorOptionsPages.h \
antObject.h \
antPlugin.h \
antService.h \
@ -40,6 +41,7 @@ HEADERS += \
SOURCES += \
antConfig.cc \
antEditorOptionsPages.cc \
antObject.cc \
antPlugin.cc \
antService.cc \

View File

@ -29,47 +29,6 @@ namespace ant
// ------------------------------------------------------------
// Helper functions to get and set the configuration
std::string
ACConverter::to_string (const lay::angle_constraint_type &m)
{
if (m == lay::AC_Any) {
return "any";
} else if (m == lay::AC_Diagonal) {
return "diagonal";
} else if (m == lay::AC_Ortho) {
return "ortho";
} else if (m == lay::AC_Horizontal) {
return "horizontal";
} else if (m == lay::AC_Vertical) {
return "vertical";
} else if (m == lay::AC_Global) {
return "global";
} else {
return "";
}
}
void
ACConverter::from_string (const std::string &tt, lay::angle_constraint_type &m)
{
std::string t (tl::trim (tt));
if (t == "any") {
m = lay::AC_Any;
} else if (t == "diagonal") {
m = lay::AC_Diagonal;
} else if (t == "ortho") {
m = lay::AC_Ortho;
} else if (t == "horizontal") {
m = lay::AC_Horizontal;
} else if (t == "vertical") {
m = lay::AC_Vertical;
} else if (t == "global") {
m = lay::AC_Global;
} else {
m = lay::AC_Any;
}
}
std::string
StyleConverter::to_string (ant::Object::style_type s)
{

View File

@ -51,12 +51,6 @@ extern ANT_PUBLIC const std::string cfg_current_ruler_template;
// ------------------------------------------------------------
// Helper functions to get and set the configuration
struct ACConverter
{
std::string to_string (const lay::angle_constraint_type &m);
void from_string (const std::string &s, lay::angle_constraint_type &m);
};
struct StyleConverter
{
std::string to_string (ant::Object::style_type s);

View File

@ -159,10 +159,11 @@ ConfigPage3::setup (lay::Dispatcher *root)
{
// snap mode
lay::angle_constraint_type rm = lay::AC_Any;
root->config_get (cfg_ruler_snap_mode, rm, ACConverter ());
root->config_get (cfg_ruler_snap_mode, rm, lay::ACConverter ());
mp_ui->ruler_any_angle_rb->setChecked (rm == lay::AC_Any);
mp_ui->ruler_ortho_rb->setChecked (rm == lay::AC_Ortho);
mp_ui->ruler_diag_rb->setChecked (rm == lay::AC_Diagonal);
mp_ui->ruler_diag_only_rb->setChecked (rm == lay::AC_DiagonalOnly);
mp_ui->ruler_hor_rb->setChecked (rm == lay::AC_Horizontal);
mp_ui->ruler_vert_rb->setChecked (rm == lay::AC_Vertical);
}
@ -180,13 +181,16 @@ ConfigPage3::commit (lay::Dispatcher *root)
if (mp_ui->ruler_diag_rb->isChecked ()) {
rm = lay::AC_Diagonal;
}
if (mp_ui->ruler_diag_only_rb->isChecked ()) {
rm = lay::AC_DiagonalOnly;
}
if (mp_ui->ruler_hor_rb->isChecked ()) {
rm = lay::AC_Horizontal;
}
if (mp_ui->ruler_vert_rb->isChecked ()) {
rm = lay::AC_Vertical;
}
root->config_set (cfg_ruler_snap_mode, rm, ACConverter ());
root->config_set (cfg_ruler_snap_mode, rm, lay::ACConverter ());
}
// ------------------------------------------------------------

View File

@ -0,0 +1,155 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2025 Matthias Koefferlein
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if defined(HAVE_QT)
#include "antService.h"
#include "antEditorOptionsPages.h"
#include "layWidgets.h"
#include "layDispatcher.h"
#include "tlInternational.h"
#include <QHBoxLayout>
namespace ant
{
// ------------------------------------------------------------------
// Annotations Toolbox widget
ToolkitWidget::ToolkitWidget (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
: lay::EditorOptionsPageWidget (view, dispatcher)
{
mp_layout = new QHBoxLayout (this);
mp_x_le = new lay::DecoratedLineEdit (this);
mp_x_le->set_label ("dx:");
mp_layout->addWidget (mp_x_le);
mp_y_le = new lay::DecoratedLineEdit (this);
mp_y_le->set_label ("dy:");
mp_layout->addWidget (mp_y_le);
mp_d_le = new lay::DecoratedLineEdit (this);
mp_d_le->set_label ("d:");
mp_layout->addWidget (mp_d_le);
mp_layout->addStretch (1);
hide ();
set_toolbox_widget (true);
set_transparent (true);
}
ToolkitWidget::~ToolkitWidget ()
{
// .. nothing yet ..
}
std::string
ToolkitWidget::title () const
{
return "Box Options";
}
const char *
ToolkitWidget::name () const
{
return ant::Service::editor_options_name ();
}
void
ToolkitWidget::deactivated ()
{
hide ();
}
void
ToolkitWidget::commit (lay::Dispatcher *dispatcher)
{
try {
if (mp_d_le->hasFocus ()) {
double d = 0.0;
tl::from_string (tl::to_string (mp_d_le->text ()), d);
dispatcher->call_function (ant::Service::d_function_name (), tl::to_string (d));
} else {
double dx = 0.0, dy = 0.0;
tl::from_string (tl::to_string (mp_x_le->text ()), dx);
tl::from_string (tl::to_string (mp_y_le->text ()), dy);
dispatcher->call_function (ant::Service::xy_function_name (), db::DVector (dx, dy).to_string ());
}
} catch (...) {
}
}
void
ToolkitWidget::configure (const std::string &name, const std::string &value)
{
if (name == ant::Service::xy_configure_name () && ! mp_x_le->hasFocus () && ! mp_y_le->hasFocus ()) {
try {
db::DVector mv;
tl::from_string (value, mv);
mp_x_le->setText (tl::to_qstring (tl::micron_to_string (mv.x ())));
mp_y_le->setText (tl::to_qstring (tl::micron_to_string (mv.y ())));
} catch (...) {
}
} else if (name == ant::Service::d_configure_name () && ! mp_x_le->hasFocus () && ! mp_y_le->hasFocus ()) {
try {
double d;
tl::from_string (value, d);
mp_d_le->setText (tl::to_qstring (tl::micron_to_string (d)));
} catch (...) {
}
}
}
// ------------------------------------------------------------------
// Registrations
// toolkit widgets
static tl::RegisteredClass<lay::EditorOptionsPageFactoryBase> s_tookit_widget_factory (new lay::EditorOptionsPageFactory<ToolkitWidget> ("ant::Plugin"), 0);
}
#endif

View File

@ -0,0 +1,68 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2025 Matthias Koefferlein
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if defined(HAVE_QT)
#ifndef HDR_antEditorOptionsPages
#define HDR_antEditorOptionsPages
#include "layEditorOptionsPageWidget.h"
class QHBoxLayout;
namespace lay
{
class DecoratedLineEdit;
}
namespace ant
{
/**
* @brief The toolbox widget for annotations
*/
class ToolkitWidget
: public lay::EditorOptionsPageWidget
{
Q_OBJECT
public:
ToolkitWidget (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher);
~ToolkitWidget ();
virtual std::string title () const;
virtual const char *name () const;
virtual int order () const { return 0; }
virtual void configure (const std::string &name, const std::string &value);
virtual void commit (lay::Dispatcher *root);
virtual void deactivated ();
private:
QHBoxLayout *mp_layout;
lay::DecoratedLineEdit *mp_x_le, *mp_y_le, *mp_d_le;
};
}
#endif
#endif

View File

@ -24,6 +24,7 @@
#include "antObject.h"
#include "antTemplate.h"
#include "antConfig.h"
#include "layConverters.h"
#include "tlString.h"
#include "tlExpression.h"
@ -425,7 +426,24 @@ class AnnotationEvalFunction
: public tl::EvalFunction
{
public:
AnnotationEvalFunction (char function, const AnnotationEval *eval, size_t index)
enum FunctionType {
ManhattanLength, // L
ManhattanLengthIncremental, // LL
EuclidianDistance, // D
EuclidianDistanceIncremental, // DD
XDelta, // X
XDeltaIncremental, // XX
YDelta, // Y
YDeltaIncremental, // YY
P1X, // U
P1Y, // V
P2X, // P
P2Y, // Q
Area, // A
Angle // G
};
AnnotationEvalFunction (FunctionType function, const AnnotationEval *eval, size_t index)
: m_function (function), mp_eval (eval), m_index (index)
{
// .. nothing yet ..
@ -440,25 +458,53 @@ public:
const Object &obj = mp_eval->obj ();
const db::DFTrans &trans = mp_eval->trans ();
if (m_function == 'L') {
out = fabs (delta_x (obj, trans)) + fabs (delta_y (obj, trans));
} else if (m_function == 'D') {
out = sqrt (delta_x (obj, trans) * delta_x (obj, trans) + delta_y (obj, trans) * delta_y (obj, trans));
} else if (m_function == 'A') {
out = delta_x (obj, trans) * delta_y (obj, trans) * 1e-6;
} else if (m_function == 'X') {
out = delta_x (obj, trans);
} else if (m_function == 'Y') {
out = delta_y (obj, trans);
} else if (m_function == 'U') {
out = (trans * p1 (obj)).x ();
} else if (m_function == 'V') {
out = (trans * p1 (obj)).y ();
} else if (m_function == 'P') {
out = (trans * p2 (obj)).x ();
} else if (m_function == 'Q') {
out = (trans * p2 (obj)).y ();
} else if (m_function == 'G') {
if (m_function == ManhattanLength) {
out = fabs (delta_x (obj, trans, m_index)) + fabs (delta_y (obj, trans, m_index));
} else if (m_function == ManhattanLengthIncremental) {
double res = 0.0;
for (size_t index = 0; index <= m_index; ++index) {
res += fabs (delta_x (obj, trans, index)) + fabs (delta_y (obj, trans, index));
}
out = res;
} else if (m_function == EuclidianDistance) {
auto dx = delta_x (obj, trans, m_index);
auto dy = delta_y (obj, trans, m_index);
out = sqrt (dx * dx + dy * dy);
} else if (m_function == EuclidianDistanceIncremental) {
double res = 0.0;
for (size_t index = 0; index <= m_index; ++index) {
auto dx = delta_x (obj, trans, index);
auto dy = delta_y (obj, trans, index);
res += sqrt (dx * dx + dy * dy);
}
out = res;
} else if (m_function == Area) {
out = delta_x (obj, trans, m_index) * delta_y (obj, trans, m_index) * 1e-6;
} else if (m_function == XDelta) {
out = delta_x (obj, trans, m_index);
} else if (m_function == XDeltaIncremental) {
double res = 0.0;
for (size_t index = 0; index <= m_index; ++index) {
res += delta_x (obj, trans, index);
}
out = res;
} else if (m_function == YDelta) {
out = delta_y (obj, trans, m_index);
} else if (m_function == YDeltaIncremental) {
double res = 0.0;
for (size_t index = 0; index <= m_index; ++index) {
res += delta_y (obj, trans, index);
}
out = res;
} else if (m_function == P1X) {
out = (trans * p1 (obj, m_index)).x ();
} else if (m_function == P1Y) {
out = (trans * p1 (obj, m_index)).y ();
} else if (m_function == P2X) {
out = (trans * p2 (obj, m_index)).x ();
} else if (m_function == P2Y) {
out = (trans * p2 (obj, m_index)).y ();
} else if (m_function == Angle) {
double r, a1, a2;
db::DPoint c;
if (obj.compute_angle_parameters (r, c, a1, a2)) {
@ -471,20 +517,20 @@ public:
}
}
db::DPoint p1 (const Object &obj) const
db::DPoint p1 (const Object &obj, size_t index) const
{
return obj.seg_p1 (m_index);
return obj.seg_p1 (index);
}
db::DPoint p2 (const Object &obj) const
db::DPoint p2 (const Object &obj, size_t index) const
{
return obj.seg_p2 (m_index);
return obj.seg_p2 (index);
}
double
delta_x (const Object &obj, const db::DFTrans &t) const
delta_x (const Object &obj, const db::DFTrans &t, size_t index) const
{
double dx = ((t * p2 (obj)).x () - (t * p1 (obj)).x ());
double dx = ((t * p2 (obj, index)).x () - (t * p1 (obj, index)).x ());
// avoid "almost 0" outputs
if (fabs (dx) < 1e-5 /*micron*/) {
@ -495,9 +541,9 @@ public:
}
double
delta_y (const Object &obj, const db::DFTrans &t) const
delta_y (const Object &obj, const db::DFTrans &t, size_t index) const
{
double dy = ((t * p2 (obj)).y () - (t * p1 (obj)).y ());
double dy = ((t * p2 (obj, index)).y () - (t * p1 (obj, index)).y ());
// avoid "almost 0" outputs
if (fabs (dy) < 1e-5 /*micron*/) {
@ -508,7 +554,7 @@ public:
}
private:
char m_function;
FunctionType m_function;
const AnnotationEval *mp_eval;
size_t m_index;
};
@ -517,16 +563,20 @@ std::string
Object::formatted (const std::string &fmt, const db::DFTrans &t, size_t index) const
{
AnnotationEval eval (*this, t);
eval.define_function ("L", new AnnotationEvalFunction('L', &eval, index)); // manhattan length
eval.define_function ("D", new AnnotationEvalFunction('D', &eval, index)); // euclidian distance
eval.define_function ("X", new AnnotationEvalFunction('X', &eval, index)); // x delta
eval.define_function ("Y", new AnnotationEvalFunction('Y', &eval, index)); // y delta
eval.define_function ("U", new AnnotationEvalFunction('U', &eval, index)); // p1.x
eval.define_function ("V", new AnnotationEvalFunction('V', &eval, index)); // p1.y
eval.define_function ("P", new AnnotationEvalFunction('P', &eval, index)); // p2.x
eval.define_function ("Q", new AnnotationEvalFunction('Q', &eval, index)); // p2.y
eval.define_function ("A", new AnnotationEvalFunction('A', &eval, index)); // area mm2
eval.define_function ("G", new AnnotationEvalFunction('G', &eval, index)); // angle (if applicable)
eval.define_function ("L", new AnnotationEvalFunction (AnnotationEvalFunction::ManhattanLength, &eval, index)); // manhattan length
eval.define_function ("LL", new AnnotationEvalFunction (AnnotationEvalFunction::ManhattanLengthIncremental, &eval, index)); // manhattan length
eval.define_function ("D", new AnnotationEvalFunction (AnnotationEvalFunction::EuclidianDistance, &eval, index)); // euclidian distance
eval.define_function ("DD", new AnnotationEvalFunction (AnnotationEvalFunction::EuclidianDistanceIncremental, &eval, index)); // euclidian distance (incremental, for multi-rulers)
eval.define_function ("X", new AnnotationEvalFunction (AnnotationEvalFunction::XDelta, &eval, index)); // x delta
eval.define_function ("XX", new AnnotationEvalFunction (AnnotationEvalFunction::XDeltaIncremental, &eval, index)); // x delta (incremental, for multi-rulers)
eval.define_function ("Y", new AnnotationEvalFunction (AnnotationEvalFunction::YDelta, &eval, index)); // y delta
eval.define_function ("YY", new AnnotationEvalFunction (AnnotationEvalFunction::YDeltaIncremental, &eval, index)); // y delta (incremental, for multi-rulers)
eval.define_function ("U", new AnnotationEvalFunction (AnnotationEvalFunction::P1X, &eval, index)); // p1.x
eval.define_function ("V", new AnnotationEvalFunction (AnnotationEvalFunction::P1Y, &eval, index)); // p1.y
eval.define_function ("P", new AnnotationEvalFunction (AnnotationEvalFunction::P2X, &eval, index)); // p2.x
eval.define_function ("Q", new AnnotationEvalFunction (AnnotationEvalFunction::P2Y, &eval, index)); // p2.y
eval.define_function ("A", new AnnotationEvalFunction (AnnotationEvalFunction::Area, &eval, index)); // area mm2
eval.define_function ("G", new AnnotationEvalFunction (AnnotationEvalFunction::Angle, &eval, index)); // angle (if applicable)
return eval.interpolate (fmt);
}
@ -713,7 +763,7 @@ Object::from_string (const char *s, const char * /*base_dir*/)
std::string s;
ex.read_word (s);
ant::ACConverter sc;
lay::ACConverter sc;
lay::angle_constraint_type sm;
sc.from_string (s, sm);
angle_constraint (sm);
@ -817,7 +867,7 @@ Object::to_string () const
r += ",";
r += "angle_constraint=";
ant::ACConverter acc;
lay::ACConverter acc;
r += acc.to_string (angle_constraint ());
return r;

View File

@ -102,7 +102,7 @@ PluginDeclaration::get_options (std::vector < std::pair<std::string, std::string
options.push_back (std::pair<std::string, std::string> (cfg_ruler_snap_range, "8"));
options.push_back (std::pair<std::string, std::string> (cfg_ruler_color, lay::ColorConverter ().to_string (tl::Color ())));
options.push_back (std::pair<std::string, std::string> (cfg_ruler_halo, "true"));
options.push_back (std::pair<std::string, std::string> (cfg_ruler_snap_mode, ACConverter ().to_string (lay::AC_Any)));
options.push_back (std::pair<std::string, std::string> (cfg_ruler_snap_mode, lay::ACConverter ().to_string (lay::AC_Any)));
options.push_back (std::pair<std::string, std::string> (cfg_ruler_obj_snap, tl::to_string (true)));
options.push_back (std::pair<std::string, std::string> (cfg_ruler_grid_snap, tl::to_string (false)));
options.push_back (std::pair<std::string, std::string> (cfg_ruler_templates, std::string ()));
@ -138,6 +138,15 @@ PluginDeclaration::create_plugin (db::Manager *manager, lay::Dispatcher *, lay::
return new ant::Service (manager, view);
}
std::vector<std::string>
PluginDeclaration::additional_editor_options_pages () const
{
std::vector<std::string> names;
// TODO: provide in a central place instead of borrowing from the edt module
names.push_back ("GenericEditorOptions");
return names;
}
bool
PluginDeclaration::menu_activated (const std::string &symbol) const
{

View File

@ -54,6 +54,8 @@ public:
virtual void uninitialize (lay::Dispatcher *);
virtual bool menu_activated (const std::string &symbol) const;
virtual std::vector<std::string> additional_editor_options_pages () const;
void register_annotation_template (const ant::Template &t, lay::Plugin *plugin = 0);
void unregister_annotation_template (const std::string &category, lay::Plugin *plugin = 0);

View File

@ -33,6 +33,7 @@
#include "layConverters.h"
#include "layLayoutCanvas.h"
#include "layFixedFont.h"
#include "layEditorOptionsPage.h"
#if defined(HAVE_QT)
# include "layProperties.h"
#endif
@ -1041,6 +1042,12 @@ View::render (const lay::Viewport &vp, lay::ViewObjectCanvas &canvas)
// -------------------------------------------------------------
// ant::Service implementation
const char *Service::editor_options_name () { return "ant-toolkit-widget-name"; }
const char *Service::xy_configure_name () { return "ant-toolkit-widget-xy-value"; }
const char *Service::d_configure_name () { return "ant-toolkit-widget-d-value"; }
const char *Service::xy_function_name () { return "ant-toolkit-widget-xy-commit"; }
const char *Service::d_function_name () { return "ant-toolkit-widget-d-commit"; }
Service::Service (db::Manager *manager, lay::LayoutViewBase *view)
: lay::EditorServiceBase (view),
lay::Drawing (1/*number of planes*/, view->drawings ()),
@ -1056,6 +1063,9 @@ Service::Service (db::Manager *manager, lay::LayoutViewBase *view)
m_drawing (false), m_current (),
m_move_mode (MoveNone),
m_seg_index (0),
m_length_confined (false),
m_length (0.0),
m_centered (false),
m_current_template (0),
m_hover (false),
m_hover_wait (false),
@ -1134,7 +1144,7 @@ Service::configure (const std::string &name, const std::string &value)
} else if (name == cfg_ruler_snap_mode) {
lay::angle_constraint_type sm = lay::AC_Any;
ACConverter ().from_string (value, sm);
lay::ACConverter ().from_string (value, sm);
m_snap_mode = sm;
} else if (name == cfg_ruler_templates) {
@ -1169,6 +1179,21 @@ Service::config_finalize ()
{
}
void
Service::show_toolbox (bool visible)
{
lay::EditorOptionsPage *tb = toolbox_widget ();
if (tb) {
tb->set_visible (visible);
}
}
lay::EditorOptionsPage *
Service::toolbox_widget ()
{
return mp_view->editor_options_pages () ? mp_view->editor_options_pages ()->page_with_name (editor_options_name ()) : 0;
}
void
Service::annotations_changed ()
{
@ -1244,6 +1269,7 @@ void
Service::drag_cancel ()
{
if (m_drawing) {
show_toolbox (false);
ui ()->ungrab_mouse (this);
m_drawing = false;
}
@ -1598,72 +1624,84 @@ Service::move (const db::DPoint &p, lay::angle_constraint_type ac)
auto ac_eff = ac == lay::AC_Global ? m_snap_mode : ac;
clear_mouse_cursors ();
if (m_move_mode == MoveP1) {
m_current.seg_p1 (m_seg_index, snap2_visual (m_p1, p, &m_current, ac));
m_rulers [0]->redraw ();
} else if (m_move_mode == MoveP2) {
m_current.seg_p2 (m_seg_index, snap2_visual (m_p1, p, &m_current, ac));
m_rulers [0]->redraw ();
} else if (m_move_mode == MoveP12) {
db::DPoint p12 = snap2_visual (m_p1, p, &m_current, ac);
m_current.seg_p1 (m_seg_index, db::DPoint (m_current.seg_p1 (m_seg_index).x(), p12.y ()));
m_current.seg_p2 (m_seg_index, db::DPoint (p12.x (), m_current.seg_p2 (m_seg_index).y ()));
m_rulers [0]->redraw ();
} else if (m_move_mode == MoveP21) {
db::DPoint p21 = snap2_visual (m_p1, p, &m_current, ac);
m_current.seg_p1 (m_seg_index, db::DPoint (p21.x (), m_current.seg_p1 (m_seg_index).y ()));
m_current.seg_p2 (m_seg_index, db::DPoint (m_current.seg_p2 (m_seg_index).x(), p21.y ()));
m_rulers [0]->redraw ();
} else if (m_move_mode == MoveP1X) {
db::DPoint pc = snap2_visual (m_p1, p, &m_current, ac);
m_current.seg_p1 (m_seg_index, db::DPoint (pc.x (), m_current.seg_p1 (m_seg_index).y ()));
m_rulers [0]->redraw ();
} else if (m_move_mode == MoveP2X) {
db::DPoint pc = snap2_visual (m_p1, p, &m_current, ac);
m_current.seg_p2 (m_seg_index, db::DPoint (pc.x (), m_current.seg_p2 (m_seg_index).y ()));
m_rulers [0]->redraw ();
} else if (m_move_mode == MoveP1Y) {
db::DPoint pc = snap2_visual (m_p1, p, &m_current, ac);
m_current.seg_p1 (m_seg_index, db::DPoint (m_current.seg_p1 (m_seg_index).x (), pc.y ()));
m_rulers [0]->redraw ();
} else if (m_move_mode == MoveP2Y) {
db::DPoint pc = snap2_visual (m_p1, p, &m_current, ac);
m_current.seg_p2 (m_seg_index, db::DPoint (m_current.seg_p2 (m_seg_index).x (), pc.y ()));
m_rulers [0]->redraw ();
} else if (m_move_mode == MoveSelected) {
if (m_move_mode == MoveSelected) {
db::DVector dp = p - m_p1;
dp = lay::snap_angle (dp, ac_eff);
m_trans = db::DTrans (dp + (m_p1 - db::DPoint ()) - m_trans.disp ()) * m_trans * db::DTrans (db::DPoint () - m_p1);
propose_move_transformation (m_trans, 1);
snap_rulers (ac_eff);
for (std::vector<ant::View *>::iterator r = m_rulers.begin (); r != m_rulers.end (); ++r) {
(*r)->transform_by (db::DCplxTrans (m_trans));
}
show_message ();
} else if (m_move_mode != MoveNone) {
db::DPoint ps = snap2_visual (m_p1, p, &m_current, ac);
m_trans = db::DTrans (ps - m_p1);
apply_partial_move (ps);
propose_move_transformation (db::DTrans (ps - m_p1), 1);
// display current move distance
std::string pos = std::string ("dx: ") + tl::micron_to_string (ps.x () - m_p1.x ()) + " "
+ "dy: " + tl::micron_to_string (ps.y () - m_p1.y ());
view ()->message (pos);
}
}
void
Service::apply_partial_move (db::DPoint &ps)
{
if (m_move_mode == MoveP1) {
m_current.seg_p1 (m_seg_index, ps);
} else if (m_move_mode == MoveP2) {
m_current.seg_p2 (m_seg_index, ps);
} else if (m_move_mode == MoveP12) {
m_current.seg_p1 (m_seg_index, db::DPoint (m_current.seg_p1 (m_seg_index).x(), ps.y ()));
m_current.seg_p2 (m_seg_index, db::DPoint (ps.x (), m_current.seg_p2 (m_seg_index).y ()));
} else if (m_move_mode == MoveP21) {
m_current.seg_p1 (m_seg_index, db::DPoint (ps.x (), m_current.seg_p1 (m_seg_index).y ()));
m_current.seg_p2 (m_seg_index, db::DPoint (m_current.seg_p2 (m_seg_index).x(), ps.y ()));
} else if (m_move_mode == MoveP1X) {
ps.set_y (m_p1.y ());
m_current.seg_p1 (m_seg_index, db::DPoint (ps.x (), m_current.seg_p1 (m_seg_index).y ()));
} else if (m_move_mode == MoveP2X) {
ps.set_y (m_p1.y ());
m_current.seg_p2 (m_seg_index, db::DPoint (ps.x (), m_current.seg_p2 (m_seg_index).y ()));
} else if (m_move_mode == MoveP1Y) {
ps.set_x (m_p1.x ());
m_current.seg_p1 (m_seg_index, db::DPoint (m_current.seg_p1 (m_seg_index).x (), ps.y ()));
} else if (m_move_mode == MoveP2Y) {
ps.set_x (m_p1.x ());
m_current.seg_p2 (m_seg_index, db::DPoint (m_current.seg_p2 (m_seg_index).x (), ps.y ()));
}
if (m_move_mode != MoveSelected) {
show_message ();
}
m_rulers [0]->redraw ();
}
void
@ -1676,6 +1714,13 @@ Service::show_message ()
view ()->message (pos);
}
void
Service::end_move (const db::DVector &v)
{
m_trans = db::DTrans (v) * db::DTrans (m_trans.fp_trans ());
end_move (db::DPoint (), lay::AC_Any);
}
void
Service::end_move (const db::DPoint &, lay::angle_constraint_type)
{
@ -1705,6 +1750,9 @@ Service::end_move (const db::DPoint &, lay::angle_constraint_type)
} else if (m_move_mode != MoveNone) {
db::DPoint ps = m_trans * m_p1;
apply_partial_move (ps);
// replace the ruler that was moved
m_current.clean_points ();
mp_view->annotation_shapes ().replace (*m_selected.begin (), db::DUserObject (new ant::Object (m_current)));
@ -1830,9 +1878,23 @@ Service::mouse_double_click_event (const db::DPoint & /*p*/, unsigned int button
finish_drawing ();
return true;
} else {
return false;
}
}
return false;
bool
Service::key_event (unsigned int key, unsigned int buttons)
{
if (m_drawing && buttons == 0 && (key == lay::KeyEnter || key == lay::KeyReturn)) {
// ends the current ruler (specifically in multi-segment mode)
finish_drawing ();
return true;
} else {
return false;
}
}
lay::TwoPointSnapToObjectResult
@ -1873,6 +1935,7 @@ Service::mouse_click_event (const db::DPoint &p, unsigned int buttons, bool prio
// cancel any edit operations so far
m_move_mode = MoveNone;
m_length_confined = false;
// reset selection
clear_selection ();
@ -1969,6 +2032,7 @@ Service::mouse_click_event (const db::DPoint &p, unsigned int buttons, bool prio
mp_active_ruler->thaw ();
m_drawing = true;
show_toolbox (true);
ui ()->grab_mouse (this, false);
}
@ -1989,6 +2053,7 @@ Service::mouse_click_event (const db::DPoint &p, unsigned int buttons, bool prio
pts.push_back (m_p1);
m_current.set_points_exact (pts);
m_length_confined = false;
}
@ -2021,6 +2086,116 @@ Service::create_measure_ruler (const db::DPoint &pt, lay::angle_constraint_type
}
}
void
Service::function (const std::string &name, const std::string &value)
{
if (name == xy_function_name ()) {
try {
db::DVector s;
tl::from_string (value, s);
if (m_drawing) {
ant::Object::point_list pts = m_current.points ();
if (pts.size () >= 2) {
db::DVector d = pts.back () - pts [pts.size () - 2];
// Adjust the direction so positive coordinates are in the current drag direction
s = db::DVector (s.x () * (d.x () < 0 ? -1.0 : 1.0), s.y () * (d.y () < 0 ? -1.0 : 1.0));
pts.back () = pts [pts.size () - 2] + s;
m_current.set_points_exact (pts);
}
const ant::Template &tpl = current_template ();
if (tpl.mode () == ant::Template::RulerMultiSegment || tpl.mode () == ant::Template::RulerThreeClicks) {
if (tpl.mode () == ant::Template::RulerThreeClicks && pts.size () == 3) {
finish_drawing ();
} else {
// add a new point
m_p1 = pts.back ();
pts.push_back (m_p1);
m_current.set_points_exact (pts);
}
} else {
finish_drawing ();
}
}
} catch (...) {
}
} else if (name == d_function_name ()) {
try {
double s = 0.0;
tl::from_string (value, s);
if (m_drawing) {
m_length_confined = true;
m_length = s;
ant::Object::point_list pts = m_current.points ();
confine_length (pts);
m_current.set_points_exact (pts);
}
} catch (...) {
}
}
}
void
Service::confine_length (ant::Object::point_list &pts)
{
if (m_length_confined && pts.size () >= 2) {
const ant::Template &tpl = current_template ();
bool is_box_style = tpl.mode () == ant::Template::RulerNormal && (tpl.outline () == ant::Object::OL_box || tpl.outline () == ant::Object::OL_ellipse);
db::DPoint p1 = m_centered ? m_p1 : pts [pts.size () - 2];
db::DVector s = pts.back () - p1;
if (is_box_style) {
db::DVector snew = s;
double l = m_centered ? m_length * 0.5 : m_length;
if (fabs (s.x ()) < fabs (s.y ()) + db::epsilon) {
snew.set_y (l * (s.y () < 0 ? -1.0 : 1.0));
}
if (fabs (s.y ()) < fabs (s.x ()) + db::epsilon) {
snew.set_x (l * (s.x () < 0 ? -1.0 : 1.0));
}
s = snew;
} else {
double l = s.double_length ();
if (l > db::epsilon) {
s *= m_length / l;
}
}
pts.back () = p1 + s;
}
}
bool
Service::mouse_move_event (const db::DPoint &p, unsigned int buttons, bool prio)
{
@ -2040,11 +2215,26 @@ Service::mouse_move_event (const db::DPoint &p, unsigned int buttons, bool prio)
}
const ant::Template &tpl = current_template ();
// for normal rulers with box or ellipse rendering we use a different button scheme:
// Shift will keep the center, Ctrl will confine the box to a square/ellipse to a circle
bool is_box_style = tpl.mode () == ant::Template::RulerNormal && (tpl.outline () == ant::Object::OL_box || tpl.outline () == ant::Object::OL_ellipse);
bool snap_square = is_box_style && (buttons & lay::ControlButton) != 0;
m_centered = is_box_style && (buttons & lay::ShiftButton) != 0;
lay::PointSnapToObjectResult snap_details;
if (m_drawing) {
snap_details = snap2_details (m_p1, p, mp_active_ruler->ruler (), ac_from_buttons (buttons));
lay::angle_constraint_type ac;
if (snap_square) {
ac = lay::AC_DiagonalOnly;
} else if (is_box_style) {
ac = lay::AC_Any;
} else {
ac = ac_from_buttons (buttons);
}
snap_details = snap2_details (m_p1, p, mp_active_ruler->ruler (), ac);
} else {
const ant::Template &tpl = current_template ();
snap_details = snap1_details (p, m_obj_snap && tpl.snap () && (tpl.mode () != ant::Template::RulerAutoMetricEdge || ! view ()->transient_selection_mode ()));
}
@ -2058,10 +2248,36 @@ Service::mouse_move_event (const db::DPoint &p, unsigned int buttons, bool prio)
// otherwise we risk manipulating p1 too.
ant::Object::point_list pts = m_current.points ();
if (! pts.empty ()) {
pts.back () = snap_details.snapped_point;
confine_length (pts);
if (is_box_style) {
if (m_centered) {
pts.front () = m_p1 - (pts.back () - m_p1);
} else {
pts.front () = m_p1;
}
}
}
m_current.set_points_exact (pts);
db::DVector delta;
if (pts.size () >= 2) {
delta = pts.back () - pts[pts.size () - 2];
delta = db::DVector (fabs (delta.x ()), fabs (delta.y ()));
}
lay::EditorOptionsPage *tb = toolbox_widget ();
if (tb) {
double d = is_box_style ? std::min (fabs (delta.x ()), fabs (delta.y ())) : delta.length ();
tb->configure (xy_configure_name (), delta.to_string ());
tb->configure (d_configure_name (), tl::to_string (d));
}
mp_active_ruler->redraw ();
show_message ();

View File

@ -197,6 +197,13 @@ Q_OBJECT
public:
typedef lay::AnnotationShapes::iterator obj_iterator;
// for communicating with the toolbox widget
static const char *editor_options_name ();
static const char *xy_configure_name ();
static const char *d_configure_name ();
static const char *xy_function_name ();
static const char *d_function_name ();
/**
* The current move mode:
* MoveNone - not moving
@ -347,6 +354,11 @@ public:
*/
virtual void end_move (const db::DPoint &p, lay::angle_constraint_type ac);
/**
* @brief Terminate a "move" operation with compulsory move vector
*/
virtual void end_move (const db::DVector &v);
/**
* @brief Return the bbox of the selection (reimplementation of lay::Editable interface)
*/
@ -498,10 +510,15 @@ public:
}
/**
* @brief Implement the menu response function
* @brief Implements the menu response function
*/
void menu_activated (const std::string &symbol);
/**
* @brief Implements the toolbox widget response function
*/
void function (const std::string &name, const std::string &value);
/**
* @brief Return the annotation iterator that delivers the annotations (and only these)
*/
@ -583,6 +600,11 @@ private:
MoveMode m_move_mode;
// The currently moving segment
size_t m_seg_index;
// When set to true, the length is confined to the value given by m_length
bool m_length_confined;
double m_length;
// When set to true, the last point was established in centered fashion
bool m_centered;
// The ruler template
std::vector<ant::Template> m_ruler_templates;
unsigned int m_current_template;
@ -603,10 +625,15 @@ private:
db::DPoint snap2_visual (const db::DPoint &p1, const db::DPoint &p2, const ant::Object *obj, lay::angle_constraint_type ac);
lay::PointSnapToObjectResult snap2_details (const db::DPoint &p1, const db::DPoint &p2, const ant::Object *obj, lay::angle_constraint_type ac);
lay::TwoPointSnapToObjectResult auto_measure (const db::DPoint &p, lay::angle_constraint_type ac, const ant::Template &tpl);
void confine_length (ant::Object::point_list &pts);
const ant::Template &current_template () const;
void show_toolbox (bool visible);
lay::EditorOptionsPage *toolbox_widget ();
void show_message ();
void apply_partial_move (db::DPoint &ps);
/**
* @brief A handler for the shape container's changed event
@ -617,6 +644,7 @@ private:
virtual bool mouse_press_event (const db::DPoint &p, unsigned int buttons, bool prio);
virtual bool mouse_click_event (const db::DPoint &p, unsigned int buttons, bool prio);
virtual bool mouse_double_click_event (const db::DPoint &p, unsigned int buttons, bool prio);
virtual bool key_event (unsigned int key, unsigned int buttons);
virtual void deactivated ();
void snap_rulers (lay::angle_constraint_type ac);

View File

@ -23,6 +23,7 @@
#include "antTemplate.h"
#include "antConfig.h"
#include "layConverters.h"
#include "tlInternational.h"
#include "tlException.h"
#include "tlLog.h"
@ -263,7 +264,7 @@ Template::from_string (const std::string &s)
} else if (key == "angle_constraint") {
ant::ACConverter sc;
lay::ACConverter sc;
lay::angle_constraint_type sm;
sc.from_string (s, sm);
r.back ().angle_constraint (sm);
@ -373,7 +374,7 @@ Template::to_string (const std::vector<Template> &v)
r += ",";
r += "angle_constraint=";
ant::ACConverter acc;
lay::ACConverter acc;
r += acc.to_string (t->angle_constraint ());
}

View File

@ -53,6 +53,7 @@ static int outline_radius () { return int (ant::Object::OL_radius); }
static int angle_any () { return int (lay::AC_Any); }
static int angle_diagonal () { return int (lay::AC_Diagonal); }
static int angle_diagonal_only () { return int (lay::AC_DiagonalOnly); }
static int angle_ortho () { return int (lay::AC_Ortho); }
static int angle_horizontal () { return int (lay::AC_Horizontal); }
static int angle_vertical () { return int (lay::AC_Vertical); }
@ -653,6 +654,11 @@ gsi::Class<AnnotationRef> decl_Annotation (decl_BasicAnnotation, "lay", "Annotat
"@brief Gets the diagonal angle code for use with the \\angle_constraint method\n"
"If this value is specified for the angle constraint, only multiples of 45 degree are allowed."
) +
gsi::method ("AngleDiagonalOnly", &gsi::angle_diagonal_only,
"@brief Gets the diagonal angle code for use with the \\angle_constraint method\n"
"If this value is specified for the angle constraint, only 45 degree or 135 degree are allowed.\n"
"This constant has been introduced in version 0.30.6."
) +
gsi::method ("AngleOrtho", &gsi::angle_ortho,
"@brief Gets the ortho angle code for use with the \\angle_constraint method\n"
"If this value is specified for the angle constraint, only multiples of 90 degree are allowed."

View File

@ -475,7 +475,7 @@ GenericReaderOptions::add_options (tl::CommandLineOptions &cmd)
"For example, a datatype specification of \"6,1:61,2:62\" will use datatype 6 for via geometry without a mask assignment, "
"datatype 61 for via geometry assigned to MASK 1 and datatype 62 for via geometry assigned to MASK 2.\n"
"\n"
"An alternative way to provide a layer mapping is through a map file (see '--" + m_long_prefix + "lefdef-map-file')."
"An alternative way to provide a layer mapping is through a map file (see '--" + m_long_prefix + "lefdef-map')."
)
<< tl::arg (group +
"#--" + m_long_prefix + "lefdef-via-geometry-datatype", &m_lefdef_via_geometry_datatype, "Specifies the via geometry layer datatype in pattern-based mode",

View File

@ -31,6 +31,7 @@
#include "dbEdgesUtils.h"
#include "dbEdgePairFilters.h"
#include "dbPropertiesFilter.h"
#include "dbRegionProcessors.h"
#include "gsiDeclDbContainerHelpers.h"
#include "gsiDeclDbMeasureHelpers.h"
@ -531,6 +532,71 @@ static db::Region extents0 (const db::EdgePairs *r)
return extents2 (r, 0, 0);
}
namespace {
// a combined processor that implements db::RelativeExtents on the edge bounding boxes
class EdgePairsRelativeExtents
: virtual public db::EdgePairToPolygonProcessorBase,
virtual public db::RelativeExtents
{
public:
EdgePairsRelativeExtents (double fx1, double fy1, double fx2, double fy2, db::Coord dx, db::Coord dy)
: db::RelativeExtents (fx1, fy1, fx2, fy2, dx, dy)
{
// .. nothing yet ..
}
// not needed, but mutes
void process (const db::PolygonWithProperties &poly, std::vector<db::PolygonWithProperties> &result) const
{
db::RelativeExtents::process (poly, result);
}
void process (const db::EdgePairWithProperties &ep, std::vector<db::PolygonWithProperties> &result) const
{
db::RelativeExtents::process (db::Polygon (ep.bbox ()), result);
}
};
class EdgePairsRelativeExtentsAsEdges
: virtual public db::EdgePairToEdgeProcessorBase,
virtual public db::RelativeExtentsAsEdges
{
public:
EdgePairsRelativeExtentsAsEdges (double fx1, double fy1, double fx2, double fy2)
: db::RelativeExtentsAsEdges (fx1, fy1, fx2, fy2)
{
// .. nothing yet ..
}
void process (const db::PolygonWithProperties &poly, std::vector<db::EdgeWithProperties> &result) const
{
db::RelativeExtentsAsEdges::process (poly, result);
}
void process (const db::EdgePairWithProperties &ep, std::vector<db::EdgeWithProperties> &result) const
{
db::RelativeExtentsAsEdges::process (db::Polygon (ep.bbox ()), result);
}
};
}
static db::Region extent_refs (const db::EdgePairs *r, double fx1, double fy1, double fx2, double fy2, db::Coord dx, db::Coord dy)
{
db::Region result;
r->processed (result, EdgePairsRelativeExtents (fx1, fy1, fx2, fy2, dx, dy));
return result;
}
static db::Edges extent_refs_edges (const db::EdgePairs *r, double fx1, double fy1, double fx2, double fy2)
{
db::Edges result;
r->processed (result, EdgePairsRelativeExtentsAsEdges (fx1, fy1, fx2, fy2));
return result;
}
static db::Edges edges (const db::EdgePairs *ep)
{
db::Edges e;
@ -1247,7 +1313,15 @@ Class<db::EdgePairs> decl_EdgePairs (decl_dbShapeCollection, "db", "EdgePairs",
"The boxes will not be merged, so it is possible to determine overlaps "
"of these boxes for example.\n"
) +
method_ext ("filter", &filter, gsi::arg ("filter"),
method_ext ("extent_refs", &extent_refs,
"@hide\n"
"This method is provided for DRC implementation.\n"
) +
method_ext ("extent_refs_edges", &extent_refs_edges,
"@hide\n"
"This method is provided for DRC implementation.\n"
) +
method_ext ("filter", &filter, gsi::arg ("filter"),
"@brief Applies a generic filter in place (replacing the edge pairs from the EdgePair collection)\n"
"See \\EdgePairFilter for a description of this feature.\n"
"\n"

View File

@ -32,6 +32,7 @@
#include "dbOriginalLayerRegion.h"
#include "dbLayoutUtils.h"
#include "dbPropertiesFilter.h"
#include "dbRegionProcessors.h"
#include "gsiDeclDbContainerHelpers.h"
#include "gsiDeclDbMeasureHelpers.h"
@ -941,6 +942,69 @@ static std::vector<db::Edges> split_interacting_with_region (const db::Edges *r,
return as_2edges_vector (r->selected_interacting_differential (other, min_count, max_count));
}
namespace {
// a combined processor that implements db::RelativeExtents on the edge bounding boxes
class EdgesRelativeExtents
: virtual public db::EdgeToPolygonProcessorBase,
virtual public db::RelativeExtents
{
public:
EdgesRelativeExtents (double fx1, double fy1, double fx2, double fy2, db::Coord dx, db::Coord dy)
: db::RelativeExtents (fx1, fy1, fx2, fy2, dx, dy)
{
// .. nothing yet ..
}
// not needed, but mutes
void process (const db::PolygonWithProperties &poly, std::vector<db::PolygonWithProperties> &result) const
{
db::RelativeExtents::process (poly, result);
}
void process (const db::EdgeWithProperties &edge, std::vector<db::PolygonWithProperties> &result) const
{
db::RelativeExtents::process (db::Polygon (edge.bbox ()), result);
}
};
class EdgesRelativeExtentsAsEdges
: virtual public db::EdgeProcessorBase,
virtual public db::RelativeExtentsAsEdges
{
public:
EdgesRelativeExtentsAsEdges (double fx1, double fy1, double fx2, double fy2)
: db::RelativeExtentsAsEdges (fx1, fy1, fx2, fy2)
{
// .. nothing yet ..
}
void process (const db::PolygonWithProperties &poly, std::vector<db::EdgeWithProperties> &result) const
{
db::RelativeExtentsAsEdges::process (poly, result);
}
void process (const db::EdgeWithProperties &edge, std::vector<db::EdgeWithProperties> &result) const
{
db::RelativeExtentsAsEdges::process (db::Polygon (edge.bbox ()), result);
}
};
}
static db::Region extent_refs (const db::Edges *r, double fx1, double fy1, double fx2, double fy2, db::Coord dx, db::Coord dy)
{
db::Region result;
r->processed (result, EdgesRelativeExtents (fx1, fy1, fx2, fy2, dx, dy));
return result;
}
static db::Edges extent_refs_edges (const db::Edges *r, double fx1, double fy1, double fx2, double fy2)
{
return r->processed (EdgesRelativeExtentsAsEdges (fx1, fy1, fx2, fy2));
}
static tl::Variant nth (const db::Edges *edges, size_t n)
{
const db::Edge *e = edges->nth (n);
@ -2372,6 +2436,14 @@ Class<db::Edges> decl_Edges (decl_dbShapeCollection, "db", "Edges",
"The boxes will not be merged, so it is possible to determine overlaps "
"of these boxes for example.\n"
) +
method_ext ("extent_refs", &extent_refs,
"@hide\n"
"This method is provided for DRC implementation.\n"
) +
method_ext ("extent_refs_edges", &extent_refs_edges,
"@hide\n"
"This method is provided for DRC implementation.\n"
) +
method_ext ("extended_in", &extended_in, gsi::arg ("e"),
"@brief Returns a region with shapes representing the edges with the given width\n"
"@param e The extension width\n"

View File

@ -4,8 +4,8 @@
<doc>
<title>About Libraries</title>
<keyword>Library</keyword>
<keyword>Libraries</keyword>
<keyword name="Library"/>
<keyword name="Libraries"/>
<p>
Starting with version 0.22, KLayout offers a library concept.

View File

@ -4,6 +4,7 @@
<doc>
<title>About PCells</title>
<keyword name="PCells"/>
<p>
Starting with version 0.22, KLayout offers parametrized cells (PCells).

View File

@ -4,6 +4,7 @@
<doc>
<title>About The Basic Library</title>
<keyword name="Basic Library"/>
<h2-index/>

View File

@ -4,6 +4,7 @@
<doc>
<title>Connectivity</title>
<keyword name="Connectivity"/>
<p>
Use the connectivity page to specify the conductor layers and their connections.

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE language SYSTEM "klayout_doc.dtd">
<!-- generated by /home/matthias/klayout/master/scripts/drc_lvs_doc/extract_doc.rb -->
<!-- generated by /home/matthias/klayout/master2/scripts/drc_lvs_doc/extract_doc.rb -->
<!-- DO NOT EDIT! -->
<doc>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE language SYSTEM "klayout_doc.dtd">
<!-- generated by /home/matthias/klayout/master/scripts/drc_lvs_doc/extract_doc.rb -->
<!-- generated by /home/matthias/klayout/master2/scripts/drc_lvs_doc/extract_doc.rb -->
<!-- DO NOT EDIT! -->
<doc>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE language SYSTEM "klayout_doc.dtd">
<!-- generated by /home/matthias/klayout/master/scripts/drc_lvs_doc/extract_doc.rb -->
<!-- generated by /home/matthias/klayout/master2/scripts/drc_lvs_doc/extract_doc.rb -->
<!-- DO NOT EDIT! -->
<doc>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE language SYSTEM "klayout_doc.dtd">
<!-- generated by /home/matthias/klayout/master/scripts/drc_lvs_doc/extract_doc.rb -->
<!-- generated by /home/matthias/klayout/master2/scripts/drc_lvs_doc/extract_doc.rb -->
<!-- DO NOT EDIT! -->
<doc>
@ -1182,20 +1182,19 @@ The formal specifiers for lines are:
<li><b>:right </b>or <b>:r </b>: the right line </li>
</ul>
</p><p>
Dots are represented by small (2x2 DBU) boxes or point-like
The following additional option controls the output format:
</p><p>
<ul>
<li><b>as_boxes </b>: with this option, boxes (rectangular polygons) will be produced on output </li>
<li><b>as_dots </b>or <b>as_edges </b>: with this option, edges will be produced on output </li>
</ul>
</p><p>
Dots on are represented by small (2x2 DBU) boxes or point-like
edges with edge output. Lines are represented by narrow or
flat (2 DBU) boxes or edges for edge output. Edges will follow
the orientation convention for the corresponding edges - i.e.
"inside" of the bounding box is on the right side of the edge.
</p><p>
The following additional option controls the output format:
</p><p>
<ul>
<li><b>as_boxes </b>: with this option, small boxes will be produced as markers </li>
<li><b>as_dots </b>or <b>as_edges </b>: with this option, point-like edges will be produced for dots
and edges will be produced for line-like selections </li>
</ul>
</p><p>
The following table shows a few applications:
</p><p>
<table>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE language SYSTEM "klayout_doc.dtd">
<!-- generated by /home/matthias/klayout/master/scripts/drc_lvs_doc/extract_doc.rb -->
<!-- generated by /home/matthias/klayout/master2/scripts/drc_lvs_doc/extract_doc.rb -->
<!-- DO NOT EDIT! -->
<doc>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE language SYSTEM "klayout_doc.dtd">
<!-- generated by /home/matthias/klayout/master/scripts/drc_lvs_doc/extract_doc.rb -->
<!-- generated by /home/matthias/klayout/master2/scripts/drc_lvs_doc/extract_doc.rb -->
<!-- DO NOT EDIT! -->
<doc>

View File

@ -4,8 +4,8 @@
<doc>
<title>About Expressions</title>
<keyword>Expressions</keyword>
<keyword>Expression Syntax</keyword>
<keyword name="Expressions"/>
<keyword name="Expression Syntax"/>
<p>
Beside a ruby and Python programming API, KLayout provides support for simple expressions in some places.

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE language SYSTEM "klayout_doc.dtd">
<!-- generated by /home/matthias/klayout/master/scripts/drc_lvs_doc/extract_doc.rb -->
<!-- generated by /home/matthias/klayout/master2/scripts/drc_lvs_doc/extract_doc.rb -->
<!-- DO NOT EDIT! -->
<doc>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE language SYSTEM "klayout_doc.dtd">
<!-- generated by /home/matthias/klayout/master/scripts/drc_lvs_doc/extract_doc.rb -->
<!-- generated by /home/matthias/klayout/master2/scripts/drc_lvs_doc/extract_doc.rb -->
<!-- DO NOT EDIT! -->
<doc>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE language SYSTEM "klayout_doc.dtd">
<!-- generated by /home/matthias/klayout/master/scripts/drc_lvs_doc/extract_doc.rb -->
<!-- generated by /home/matthias/klayout/master2/scripts/drc_lvs_doc/extract_doc.rb -->
<!-- DO NOT EDIT! -->
<doc>

View File

@ -14,7 +14,15 @@
the second point. Press the ESC key to cancel the operation.
</p>
<p><b>Hint:</b> A box, once created, will remain a box. For example, it is not possible to delete one vertex
<p>
While you drag the box, two edit boxes are shown at the top of the layout view.
Press the Tab key to enter these edit boxes.
Use the Tab and Shift+Tab keys to navigate between the boxes.
You can specify numerical values for the box width and height here. Pressing the Enter key will apply these
dimensions. Pressing the Escape key will leave the edit fields.
</p>
<p><b>Note:</b> A box, once created, will remain a box. For example, it is not possible to delete one vertex
of it, thus forming a triangle. This is only possible for polygons.
</p>

View File

@ -18,8 +18,24 @@
To actually draw a path,
choose a layer from the layer panel in which to create a new path.
Left click at the first vertex, move the mouse to the second vertex, click to place this one and continue
to the last vertex. Double-click at the last vertex to finish the path. Press the ESC key to cancel the operation.
Use the backspace key to remove the current segment and go back to the previous segment.
to the last vertex. Double-click at the last vertex or press the Enter key to finish the path.
Press the Escape key to cancel the operation.
Use the Backspace key to remove the current segment and go back to the previous segment.
</p>
<p>
To temporarily constrain the segment direction, press the Shift or Ctrl key or both while dragging
the segment. Shift will apply Manhattan
constraints (vertical and horizontal only), Ctrl will allow diagonal directions in addition and
pressing Shift+Ctrl will allow all directions.
</p>
<p>
While you drag a path segment, two edit boxes are shown at the top of the layout view.
Press the Tab key to enter these edit boxes.
Use the Tab and Shift+Tab keys to navigate between the boxes.
You can specify a numerical values for the segment vector here. Pressing the Enter key will apply these
relative coordinates and enter a new segment. Pressing the Escape key will leave the edit fields.
</p>
<p>

View File

@ -14,11 +14,28 @@
with a left mouse button click. Move to the next vertex. Depending on the connection mode, the edges
created are confined to certain directions. See <link href="/manual/editor_options.xml"/>
for a detailed description of the modes. Use the "editor options" dialog (F3 shortcut) to change the mode,
even during editing.
even during editing.
</p>
<p>
Double-click at the final point to finish the polygon. Press the ESC key to cancel the operation.
To temporarily constrain the segment direction, press the Shift or Ctrl key or both while dragging
the segment. Shift will apply Manhattan
constraints (vertical and horizontal only), Ctrl will allow diagonal directions in addition and
pressing Shift+Ctrl will allow all directions.
</p>
<p>
Double-click at the final point or press the Enter key to finish the polygon.
Press the Escape key to cancel the operation. Use the Backspace key to delete the
last segment.
</p>
<p>
While you drag a polygon segment, two edit boxes are shown at the top of the layout view.
Press the Tab key to enter these edit boxes.
Use the Tab and Shift+Tab keys to navigate between the boxes.
You can specify a numerical values for the segment vector here. Pressing the Enter key will apply these
relative coordinates and enter a new segment. Pressing the Escape key will leave the edit fields.
</p>
<p>

View File

@ -10,13 +10,37 @@
<p>
A measurement can be performed by clicking on the ruler icon in the
toolbar and selecting "Ruler" from the drop-down options.
Left-click on a point in the layout and then left-click again to
specify the second point. A ruler will be shown that indicates
the distance measured.
Left-click on a point in the layout and then left-click again
or press the Enter key to set the second point.
A ruler will be shown that indicates the distance measured.
</p>
<p>
A more convenient way is provided with the single-click measurement
While you move the endpoint, you can hold the Shift or Ctrl key
or both. With only the Shift key pressed, the ruler's direction
will be limited to horizontal or vertical only. With only the Ctrl
key pressed, the direction is limited to horizontal, vertical or
diagonal. With Ctrl and Shift pressed together, no limitation
of direction applies.
</p>
<p>
While the ruler is dragged, the current drag distance is indicated
in three edit fields at the top of the layout view. By pressing the
Tab key, the input focus changes to these edit fields. You can
specify a numerical value for the distances here. Use Tab and
Shift+Tab to jump between the fields. Press the Escape key to
leave the edit fields. Pressing the Enter key while
the cursor is on the "dx" or "dy" field will
accept the values and apply them to the ruler.
If you specify a value in the last field labelled "d" and press
Enter, the ruler will enter "fixed length" mode - in that mode you
can still define the ruler's direction with the mouse, but the
length is fixed to the given value.
</p>
<p>
A convenient way to measure a distance is the single-click measurement
ruler. Select "Measure" from the drop-down options of the ruler symbol.
In this mode, a single click will set a ruler to the specified
position. This feature will look for edges in the vicinity of the
@ -24,6 +48,11 @@
is attached perpendicular to the edge next to the initial point.
</p>
<p>
The "Measure Edge" ruler type is also a single-click measurement
ruler, but measures the length of an edge at the click position.
</p>
<p>
You can mark a position with a single click by selecting the "Cross"
ruler type. Clicking at a location will place such a ruler. The ruler
@ -35,7 +64,12 @@
object. Click and the first point to start such a ruler. Then click
on more points to add new segments to the ruler. Each segment is shown
as an individual ruler with tick marks and a length. Finish the sequence
with a double-click.
with a double-click or by pressing the Enter key.
Note that the lengths indicated by the ruler labels are the lengths
of the individual segments. To get an incremental length (the sum
of all segment length), change the ruler's label format from "$D" to "$DD" ("DD"
is variable giving the incremental length).
See the description of ruler templates below, about how to make this change permanent.
</p>
<p>

View File

@ -12,10 +12,16 @@
All selected shapes are moved to the layer that is the current one (marked with a rectangle) in the layer list.
The shapes will not be moved across the hierarchy but just inside their cell.
</p>
<p>
All layers (source and target) must be located in the same layout. To move shapes to a
different layout, use copy &amp; paste.
</p>
<p>
You can also change the layer in the shape properties. This will effectively
move shapes to other layers too.
</p>
</doc>

View File

@ -17,19 +17,27 @@
<p>
While moving, the whole selection can be rotated by 90 degree counterclockwise with a right mouse
button click.
The ESC key will cancel the operation.
The Escape key will cancel the operation.
</p>
<p>
For movements, the movement direction constraint apply.
See <link href="/manual/editor_options.xml"/> for details about the modes
available. For example, in manhattan mode, only horizontal and vertical movements are allowed.
available. For example, in Manhattan mode, only horizontal and vertical movements are allowed.
The global movement constraint can be overridden by pressing Shift (orthogonal), Ctrl (diagonal) or
both Shift and Ctrl (any angle) while moving the mouse.
</p>
<p>
If a move distance and direction is known numerically, "Move By" from the "Edit/Selection" menu can be used.
While you move the selection, two edit boxes are shown at the top of the layout view.
Press the Tab key to enter these edit boxes.
Use the Tab and Shift+Tab keys to navigate between the boxes.
You can specify a numerical shift value here. Pressing the Enter key will apply these
shifts. Pressing the Escape key will leave the edit fields.
</p>
<p>
To apply a specific shift, you can also use "Move By" from the "Edit/Selection" menu.
A dialog will open that allows specification of the horizontal and vertical move distance in micrometers.
Positive values move to the top or right and negative ones to the bottom or left.
This dialog also applies to partial mode, so that edges or parts of a layout can be

View File

@ -35,7 +35,9 @@
Simply clicking at an item immediately enters "move" mode. In this mode, you can position the element at the desired
target location and place it there by left-clicking at the position. Press "ESC" to cancel the operation.
When a complex selection is made, move mode is entered by clicking at one of the selected items (the edges
or vertices, not the shape to which they belong).
or vertices, not the shape to which they belong). While you move, two edit boxes are shown at the top of
the layout view. Press the Tab key to enter these edit fields. You can specify explicit move distances there.
Press the Enter key to apply them or the Escape key to leave these edit fields.
</p>
<p>

View File

@ -53,9 +53,14 @@
<ul>
<li><b>$X</b>: The value of the X variable (the horizontal distance, see below for a complete list of variables).</li>
<li><b>$(sprintf('%.2f',X))</b>: The value of the 'X' variable formatted as two digit fixed precision value.</li>
<li><b>$(abs(X)+abs(Y))</b>: The manhattan distance of the ruler.</li>
<li><b>$(sprintf('%.2f',X))</b>: The value of the 'X' variable formatted as two digit fixed precision value.
The "sprintf" function follows the conventions of the same standard C function.</li>
<li><b>$(abs(X)+abs(Y))</b>: The Manhattan distance of the ruler.</li>
<li><b>$min(X,Y)</b>: The minimum of X and Y.</li>
<li><b>$(X) ($Y)</b>: the value of the X variable, followed by the value of the Y variables in brackets.
This will give a string like "2.5 (-0.5)". Note
that you cannot simply write "$X ($Y)" because the expression evaluation reads that as an attempt to call a
function named "X".</li>
</ul>
<p>
@ -68,7 +73,7 @@
<ul>
<li><b>D:</b> The length of the ruler in micron units.</li>
<li><b>L:</b> The manhattan length of the ruler in micron units.</li>
<li><b>L:</b> The Manhattan length of the ruler in micron units.</li>
<li><b>U:</b> The x-position of the ruler's first point in micron units.</li>
<li><b>V:</b> The y-position of the ruler's first point in micron units.</li>
<li><b>P:</b> The x-position of the ruler's second point in micron units.</li>
@ -79,5 +84,17 @@
<li><b>G:</b> The angle enclosed by the first and last segment of the ruler (used for angle measurement rulers).</li>
</ul>
<p>
For multi-rulers additional variables are provided for "incremental" values.
These are the sums of the respective values up to the given part:
</p>
<ul>
<li><b>DD:</b> The sum of all lengths up to the labelled segment.</li>
<li><b>LL:</b> The sum of all Manhattan up to the labelled segment.</li>
<li><b>XX:</b> The horizontal distance between first and current point.</li>
<li><b>YY:</b> The vertical distance between first and current point.</li>
</ul>
</doc>

View File

@ -1463,20 +1463,19 @@ CODE
# @li @b :right @/b or @b :r @/b: the right line @/li
# @/ul
#
# Dots are represented by small (2x2 DBU) boxes or point-like
# The following additional option controls the output format:
#
# @ul
# @li @b as_boxes @/b: with this option, boxes (rectangular polygons) will be produced on output @/li
# @li @b as_dots @/b or @b as_edges @/b: with this option, edges will be produced on output @/li
# @/ul
#
# Dots on are represented by small (2x2 DBU) boxes or point-like
# edges with edge output. Lines are represented by narrow or
# flat (2 DBU) boxes or edges for edge output. Edges will follow
# the orientation convention for the corresponding edges - i.e.
# "inside" of the bounding box is on the right side of the edge.
#
# The following additional option controls the output format:
#
# @ul
# @li @b as_boxes @/b: with this option, small boxes will be produced as markers @/li
# @li @b as_dots @/b or @b as_edges @/b: with this option, point-like edges will be produced for dots
# and edges will be produced for line-like selections @/li
# @/ul
#
# The following table shows a few applications:
#
# @table
@ -1511,7 +1510,7 @@ CODE
@engine._context("#{f}") do
requires_region
requires_edges_edge_pairs_or_region
f = []
as_edges = false
@ -1714,7 +1713,7 @@ CODE
dbu_trans = RBA::VCplxTrans::new(1.0 / @engine.dbu)
@engine.run_timed("\\"#{f}\\" in: " + @engine.src_line, self.data) do
self.data.send(new_data.is_a?(RBA::EdgePairs) ? :each : :each_merged) do |object|
self.data.send(self.data.is_a?(RBA::EdgePairs) ? :each : :each_merged) do |object|
insert_object_into(new_data, block.call(object.transformed(t)), dbu_trans)
end
new_data
@ -6105,6 +6104,10 @@ END
self.data.is_a?(RBA::Edges) || self.data.is_a?(RBA::Region) || raise(name ? "#{name} requires an edge or polygon layer" : "Requires an edge or polygon layer")
end
def requires_edges_edge_pairs_or_region(name = nil)
self.data.is_a?(RBA::Edges) || self.data.is_a?(RBA::Region) || self.data.is_a?(RBA::EdgePairs) || raise(name ? "#{name} requires an edge, edge pair or polygon layer" : "Requires an edge, edge pair or polygon layer")
end
def requires_edges_texts_or_region(name = nil)
self.data.is_a?(RBA::Edges) || self.data.is_a?(RBA::Region) || self.data.is_a?(RBA::Texts) || raise(name ? "#{name} requires an edge, text or polygon layer" : "Requires an edge, text or polygon layer")
end

View File

@ -24,6 +24,7 @@
#include "edtBoxService.h"
#include "layLayoutViewBase.h"
#include "layEditorOptionsPage.h"
#if defined(HAVE_QT)
# include "edtPropertiesPages.h"
@ -35,8 +36,11 @@ namespace edt
// -----------------------------------------------------------------------------
// BoxService implementation
const char *BoxService::configure_name () { return "box-toolkit-widget-value"; }
const char *BoxService::function_name () { return "box-toolkit-widget-commit"; }
BoxService::BoxService (db::Manager *manager, lay::LayoutViewBase *view)
: ShapeEditService (manager, view, db::ShapeIterator::Boxes)
: ShapeEditService (manager, view, db::ShapeIterator::Boxes), m_centered (false)
{
// .. nothing yet ..
}
@ -65,10 +69,42 @@ BoxService::do_begin_edit (const db::DPoint &p)
update_marker ();
}
void
BoxService::function (const std::string &name, const std::string &value)
{
if (name == function_name ()) {
try {
db::DVector dim;
tl::from_string (value, dim);
if (! m_centered) {
// Adjust the direction so positive coordinates are in the current drag direction
db::DVector d = m_p2 - m_p1;
dim = db::DVector (dim.x () * (d.x () < 0 ? -1.0 : 1.0), dim.y () * (d.y () < 0 ? -1.0 : 1.0));
} else {
dim = db::DVector (fabs (dim.x ()) * 0.5, fabs (dim.y ()) * 0.5);
}
m_p2 = m_p1 + dim;
finish_editing (true);
} catch (...) {
}
}
}
db::Box
BoxService::get_box () const
{
return db::Box (trans () * m_p1, trans () * m_p2);
if (m_centered) {
db::DVector d = m_p2 - m_p1;
return db::Box (trans () * (m_p1 - d), trans () * (m_p1 + d));
} else {
return db::Box (trans () * m_p1, trans () * m_p2);
}
}
void
@ -79,10 +115,18 @@ BoxService::update_marker ()
marker->set (get_box (), db::VCplxTrans (1.0 / layout ().dbu ()) * trans ().inverted ());
db::DVector d = m_p2 - m_p1;
db::DVector dim = db::DVector (fabs (d.x ()), fabs (d.y ())) * (m_centered ? 2.0 : 1.0);
view ()->message (std::string ("lx: ") +
tl::micron_to_string (m_p2.x () - m_p1.x ()) +
tl::micron_to_string (dim.x ()) +
std::string (" ly: ") +
tl::micron_to_string (m_p2.y () - m_p1.y ()));
tl::micron_to_string (dim.y ()));
auto p = toolbox_widget ();
if (p) {
p->configure (configure_name (), dim.to_string ());
}
}
@ -108,10 +152,14 @@ BoxService::do_mouse_move_inactive (const db::DPoint &p)
void
BoxService::do_mouse_move (const db::DPoint &p)
{
lay::PointSnapToObjectResult snap_details = snap2_details (p);
// snap to square if Ctrl button is pressed
bool snap_square = (mouse_buttons () & lay::ControlButton) != 0;
bool centered = (mouse_buttons () & lay::ShiftButton) != 0;
lay::PointSnapToObjectResult snap_details = snap2_details (p, m_p1, snap_square ? lay::AC_DiagonalOnly : lay::AC_Any);
db::DPoint ps = snap_details.snapped_point;
if (snap_details.object_snap == lay::PointSnapToObjectResult::NoObject) {
if (snap_details.object_snap == lay::PointSnapToObjectResult::NoObject && ! m_centered) {
clear_mouse_cursors ();
@ -122,12 +170,22 @@ BoxService::do_mouse_move (const db::DPoint &p)
lay::PointSnapToObjectResult snap_details_y = snap2_details (py);
if (snap_details_x.object_snap != lay::PointSnapToObjectResult::NoObject) {
ps = db::DPoint (snap_details_x.snapped_point.x (), ps.y ());
if (snap_square) {
double dx = fabs (snap_details_x.snapped_point.x () - m_p1.x ());
ps = db::DPoint (snap_details_x.snapped_point.x (), m_p1.y () + (ps.y () < m_p1.y () ? -dx : dx));
} else {
ps = db::DPoint (snap_details_x.snapped_point.x (), ps.y ());
}
mouse_cursor_from_snap_details (snap_details_x, true /*add*/);
}
if (snap_details_y.object_snap != lay::PointSnapToObjectResult::NoObject) {
ps = db::DPoint (ps.x (), snap_details_y.snapped_point.y ());
if (snap_square) {
double dy = fabs (snap_details_y.snapped_point.x () - m_p1.y ());
ps = db::DPoint (m_p1.x () + (ps.x () < m_p1.x () ? -dy : dy), snap_details_y.snapped_point.y ());
} else {
ps = db::DPoint (ps.x (), snap_details_y.snapped_point.y ());
}
mouse_cursor_from_snap_details (snap_details_y, true /*add*/);
}
@ -139,6 +197,7 @@ BoxService::do_mouse_move (const db::DPoint &p)
set_cursor (lay::Cursor::cross);
m_p2 = ps;
m_centered = centered;
update_marker ();
}
@ -150,7 +209,7 @@ BoxService::do_mouse_click (const db::DPoint &p)
}
void
BoxService::do_finish_edit ()
BoxService::do_finish_edit (bool /*accept*/)
{
deliver_shape (get_box ());
commit_recent ();

View File

@ -36,6 +36,9 @@ class BoxService
: public ShapeEditService
{
public:
static const char *configure_name ();
static const char *function_name ();
BoxService (db::Manager *manager, lay::LayoutViewBase *view);
#if defined(HAVE_QT)
@ -45,12 +48,14 @@ public:
virtual void do_mouse_move (const db::DPoint &p);
virtual void do_mouse_move_inactive (const db::DPoint &p);
virtual bool do_mouse_click (const db::DPoint &p);
virtual void do_finish_edit ();
virtual void do_finish_edit (bool accept);
virtual void do_cancel_edit ();
virtual bool selection_applies (const lay::ObjectInstPath &sel) const;
virtual void function (const std::string &name, const std::string &value);
private:
db::DPoint m_p1, m_p2;
bool m_centered;
void update_marker ();
db::Box get_box () const;

View File

@ -29,6 +29,7 @@
#include "edtPCellParametersPage.h"
#include "edtConfig.h"
#include "edtService.h"
#include "edtBoxService.h"
#include "edtEditorOptionsPages.h"
#include "edtPropertiesPageUtils.h"
#include "tlExceptions.h"
@ -72,7 +73,7 @@ static void configure_from_line_edit (lay::Dispatcher *dispatcher, QLineEdit *le
// EditorOptionsGeneric implementation
EditorOptionsGeneric::EditorOptionsGeneric (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
: EditorOptionsPage (view, dispatcher)
: lay::EditorOptionsPageWidget (view, dispatcher)
{
mp_ui = new Ui::EditorOptionsGeneric ();
mp_ui->setupUi (this);
@ -215,7 +216,7 @@ EditorOptionsGeneric::setup (lay::Dispatcher *root)
// EditorOptionsText implementation
EditorOptionsText::EditorOptionsText (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
: lay::EditorOptionsPage (view, dispatcher)
: lay::EditorOptionsPageWidget (view, dispatcher)
{
mp_ui = new Ui::EditorOptionsText ();
mp_ui->setupUi (this);
@ -293,7 +294,7 @@ EditorOptionsText::setup (lay::Dispatcher *root)
// EditorOptionsPath implementation
EditorOptionsPath::EditorOptionsPath (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
: lay::EditorOptionsPage (view, dispatcher)
: lay::EditorOptionsPageWidget (view, dispatcher)
{
mp_ui = new Ui::EditorOptionsPath ();
mp_ui->setupUi (this);
@ -394,7 +395,7 @@ EditorOptionsPath::setup (lay::Dispatcher *root)
// EditorOptionsInst implementation
EditorOptionsInst::EditorOptionsInst (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
: lay::EditorOptionsPage (view, dispatcher)
: lay::EditorOptionsPageWidget (view, dispatcher)
{
mp_ui = new Ui::EditorOptionsInst ();
mp_ui->setupUi (this);
@ -687,7 +688,7 @@ EditorOptionsInst::setup (lay::Dispatcher *root)
// EditorOptionsInstPCellParam implementation
EditorOptionsInstPCellParam::EditorOptionsInstPCellParam (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
: lay::EditorOptionsPage (view, dispatcher), mp_pcell_parameters (0), mp_placeholder_label (0)
: lay::EditorOptionsPageWidget (view, dispatcher), mp_pcell_parameters (0), mp_placeholder_label (0)
{
mp_ui = new Ui::EditorOptionsInstPCellParam ();
mp_ui->setupUi (this);
@ -898,6 +899,348 @@ EditorOptionsInstPCellParam::update_pcell_parameters (const std::vector <tl::Var
}
}
// ------------------------------------------------------------------
// Box toolbox widget
BoxToolboxWidget::BoxToolboxWidget (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
: lay::EditorOptionsPageWidget (view, dispatcher)
{
mp_layout = new QHBoxLayout (this);
mp_x_le = new lay::DecoratedLineEdit (this);
mp_x_le->set_label ("w:");
mp_layout->addWidget (mp_x_le);
mp_y_le = new lay::DecoratedLineEdit (this);
mp_y_le->set_label ("h:");
mp_layout->addWidget (mp_y_le);
mp_layout->addStretch (1);
hide ();
set_toolbox_widget (true);
set_transparent (true);
}
BoxToolboxWidget::~BoxToolboxWidget ()
{
// .. nothing yet ..
}
std::string
BoxToolboxWidget::title () const
{
return "Box Options";
}
void
BoxToolboxWidget::deactivated ()
{
hide ();
}
void
BoxToolboxWidget::commit (lay::Dispatcher *dispatcher)
{
try {
double dx = 0.0, dy = 0.0;
tl::from_string (tl::to_string (mp_x_le->text ()), dx);
tl::from_string (tl::to_string (mp_y_le->text ()), dy);
dispatcher->call_function (BoxService::function_name (), db::DVector (dx, dy).to_string ());
} catch (...) {
}
}
void
BoxToolboxWidget::configure (const std::string &name, const std::string &value)
{
if (name == BoxService::configure_name () && ! mp_x_le->hasFocus () && ! mp_y_le->hasFocus ()) {
try {
db::DVector mv;
tl::from_string (value, mv);
mp_x_le->setText (tl::to_qstring (tl::micron_to_string (mv.x ())));
mp_y_le->setText (tl::to_qstring (tl::micron_to_string (mv.y ())));
} catch (...) {
}
}
}
// ------------------------------------------------------------------
// Connections toolbox widget (for polygons)
ConnectionToolboxWidget::ConnectionToolboxWidget (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
: lay::EditorOptionsPageWidget (view, dispatcher), m_in_commit (false)
{
mp_layout = new QHBoxLayout (this);
mp_x_le = new lay::DecoratedLineEdit (this);
mp_x_le->set_label ("dx:");
mp_layout->addWidget (mp_x_le);
mp_y_le = new lay::DecoratedLineEdit (this);
mp_y_le->set_label ("dy:");
mp_layout->addWidget (mp_y_le);
mp_layout->addStretch (1);
hide ();
set_toolbox_widget (true);
set_transparent (true);
}
ConnectionToolboxWidget::~ConnectionToolboxWidget ()
{
// .. nothing yet ..
}
std::string
ConnectionToolboxWidget::title () const
{
return "Connection Options";
}
void
ConnectionToolboxWidget::deactivated ()
{
hide ();
}
void
ConnectionToolboxWidget::commit (lay::Dispatcher *dispatcher)
{
m_in_commit = true;
try {
double dx = 0.0, dy = 0.0;
tl::from_string (tl::to_string (mp_x_le->text ()), dx);
tl::from_string (tl::to_string (mp_y_le->text ()), dy);
dispatcher->call_function (ShapeEditService::connection_function_name (), db::DVector (dx, dy).to_string ());
} catch (...) {
}
m_in_commit = false;
}
void
ConnectionToolboxWidget::configure (const std::string &name, const std::string &value)
{
if (name == ShapeEditService::connection_configure_name () &&
((! mp_x_le->hasFocus () && ! mp_y_le->hasFocus ()) || m_in_commit)) {
try {
db::DVector mv;
tl::from_string (value, mv);
mp_x_le->setText (tl::to_qstring (tl::micron_to_string (mv.x ())));
mp_y_le->setText (tl::to_qstring (tl::micron_to_string (mv.y ())));
} catch (...) {
}
}
}
// ------------------------------------------------------------------
// Connections toolbox widget (for paths)
PathConnectionToolboxWidget::PathConnectionToolboxWidget (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
: lay::EditorOptionsPageWidget (view, dispatcher), m_in_commit (false)
{
mp_layout = new QHBoxLayout (this);
mp_x_le = new lay::DecoratedLineEdit (this);
mp_x_le->set_label ("dx:");
mp_layout->addWidget (mp_x_le);
mp_y_le = new lay::DecoratedLineEdit (this);
mp_y_le->set_label ("dy:");
mp_layout->addWidget (mp_y_le);
mp_width = new lay::DecoratedLineEdit (this);
mp_width->set_label ("w:");
mp_layout->addWidget (mp_width);
mp_layout->addStretch (1);
hide ();
set_toolbox_widget (true);
set_transparent (true);
}
PathConnectionToolboxWidget::~PathConnectionToolboxWidget ()
{
// .. nothing yet ..
}
std::string
PathConnectionToolboxWidget::title () const
{
return "Path Connection Options";
}
void
PathConnectionToolboxWidget::deactivated ()
{
hide ();
}
void
PathConnectionToolboxWidget::commit (lay::Dispatcher *dispatcher)
{
m_in_commit = true;
try {
if (mp_x_le->hasFocus () || mp_y_le->hasFocus ()) {
double dx = 0.0, dy = 0.0;
tl::from_string (tl::to_string (mp_x_le->text ()), dx);
tl::from_string (tl::to_string (mp_y_le->text ()), dy);
dispatcher->call_function (ShapeEditService::connection_function_name (), db::DVector (dx, dy).to_string ());
} else if (mp_width->hasFocus ()) {
double w = 0.0;
tl::from_string (tl::to_string (mp_width->text ()), w);
// NOTE: going the way through "configure" makes the width part of the recent path configuration
dispatcher->config_set (cfg_edit_path_width, tl::to_string (w));
}
} catch (...) {
}
m_in_commit = false;
}
void
PathConnectionToolboxWidget::configure (const std::string &name, const std::string &value)
{
if (name == ShapeEditService::connection_configure_name () &&
((! mp_x_le->hasFocus () && ! mp_y_le->hasFocus ()) || m_in_commit)) {
try {
db::DVector mv;
tl::from_string (value, mv);
mp_x_le->setText (tl::to_qstring (tl::micron_to_string (mv.x ())));
mp_y_le->setText (tl::to_qstring (tl::micron_to_string (mv.y ())));
} catch (...) {
}
} else if (name == cfg_edit_path_width &&
(! mp_width->hasFocus () || m_in_commit)) {
try {
double w = 0.0;
tl::from_string (value, w);
mp_width->setText (tl::to_qstring (tl::micron_to_string (w)));
} catch (...) {
}
}
}
// ------------------------------------------------------------------
// Connections toolbox widget (for texts)
TextToolboxWidget::TextToolboxWidget (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
: lay::EditorOptionsPageWidget (view, dispatcher), m_in_commit (false)
{
mp_layout = new QHBoxLayout (this);
mp_text = new lay::DecoratedLineEdit (this);
mp_text->set_label ("l:");
mp_layout->addWidget (mp_text);
mp_layout->addStretch (1);
hide ();
set_toolbox_widget (true);
set_transparent (true);
}
TextToolboxWidget::~TextToolboxWidget ()
{
// .. nothing yet ..
}
std::string
TextToolboxWidget::title () const
{
return "Text Options";
}
void
TextToolboxWidget::deactivated ()
{
hide ();
}
void
TextToolboxWidget::commit (lay::Dispatcher *dispatcher)
{
m_in_commit = true;
try {
dispatcher->config_set (cfg_edit_text_string, tl::to_string (mp_text->text ()));
} catch (...) {
}
m_in_commit = false;
}
void
TextToolboxWidget::configure (const std::string &name, const std::string &value)
{
if (name == cfg_edit_text_string && (! mp_text->hasFocus () || m_in_commit)) {
mp_text->setText (tl::to_qstring (value));
}
}
// ------------------------------------------------------------------
// Registrations
// unspecific editor options - used for all plugins that want it
static tl::RegisteredClass<lay::EditorOptionsPageFactoryBase> s_factory_generic (new lay::EditorOptionsPageFactory<EditorOptionsGeneric> ("GenericEditorOptions"), 0);
static tl::RegisteredClass<lay::EditorOptionsPageFactoryBase> s_factory_texts (new lay::EditorOptionsPageFactory<edt::EditorOptionsText> ("edt::Service(Texts)"), 0);
static tl::RegisteredClass<lay::EditorOptionsPageFactoryBase> s_factory_paths (new lay::EditorOptionsPageFactory<edt::EditorOptionsPath> ("edt::Service(Paths)"), 0);
static tl::RegisteredClass<lay::EditorOptionsPageFactoryBase> s_factory_insts (new lay::EditorOptionsPageFactory<edt::EditorOptionsInstPCellParam> ("edt::Service(CellInstances)"), 0);
static tl::RegisteredClass<lay::EditorOptionsPageFactoryBase> s_factory_insts_pcell (new lay::EditorOptionsPageFactory<edt::EditorOptionsInst> ("edt::Service(CellInstances)"), 0);
// toolkit widgets
static tl::RegisteredClass<lay::EditorOptionsPageFactoryBase> s_box_tookit_widget_factory (new lay::EditorOptionsPageFactory<BoxToolboxWidget> ("edt::Service(Boxes)"), 0);
static tl::RegisteredClass<lay::EditorOptionsPageFactoryBase> s_path_connection_tookit_widget_factory (new lay::EditorOptionsPageFactory<PathConnectionToolboxWidget> ("edt::Service(Paths)"), 0);
static tl::RegisteredClass<lay::EditorOptionsPageFactoryBase> s_connection_tookit_widget_factory_polygons (new lay::EditorOptionsPageFactory<ConnectionToolboxWidget> ("edt::Service(Polygons)"), 0);
static tl::RegisteredClass<lay::EditorOptionsPageFactoryBase> s_text_tookit_widget_factory (new lay::EditorOptionsPageFactory<TextToolboxWidget> ("edt::Service(Texts)"), 0);
}
#endif

View File

@ -26,6 +26,7 @@
#define HDR_edtEditorOptionsPages
#include "layEditorOptionsPage.h"
#include "layEditorOptionsPageWidget.h"
#include <tlVariant.h>
@ -35,6 +36,7 @@
class QTabWidget;
class QLabel;
class QHBoxLayout;
namespace Ui
{
@ -50,10 +52,10 @@ namespace Ui
namespace lay
{
class PluginDeclaration;
class Dispatcher;
class LayoutViewBase;
class Plugin;
class DecoratedLineEdit;
}
namespace edt
@ -65,7 +67,7 @@ class PCellParametersPage;
* @brief The generic properties page
*/
class EditorOptionsGeneric
: public lay::EditorOptionsPage
: public lay::EditorOptionsPageWidget
{
Q_OBJECT
@ -74,7 +76,7 @@ public:
~EditorOptionsGeneric ();
virtual std::string title () const;
virtual int order () const { return 0; }
virtual int order () const { return -10; }
void apply (lay::Dispatcher *root);
void setup (lay::Dispatcher *root);
@ -90,14 +92,14 @@ private:
* @brief The text properties page
*/
class EditorOptionsText
: public lay::EditorOptionsPage
: public lay::EditorOptionsPageWidget
{
public:
EditorOptionsText (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher);
~EditorOptionsText ();
virtual std::string title () const;
virtual int order () const { return 10; }
virtual int order () const { return 0; }
void apply (lay::Dispatcher *root);
void setup (lay::Dispatcher *root);
@ -109,7 +111,7 @@ private:
* @brief The path properties page
*/
class EditorOptionsPath
: public lay::EditorOptionsPage
: public lay::EditorOptionsPageWidget
{
Q_OBJECT
@ -118,7 +120,7 @@ public:
~EditorOptionsPath ();
virtual std::string title () const;
virtual int order () const { return 30; }
virtual int order () const { return 0; }
void apply (lay::Dispatcher *root);
void setup (lay::Dispatcher *root);
@ -133,7 +135,7 @@ private:
* @brief The instance properties page
*/
class EditorOptionsInst
: public lay::EditorOptionsPage
: public lay::EditorOptionsPageWidget
{
Q_OBJECT
@ -142,7 +144,7 @@ public:
~EditorOptionsInst ();
virtual std::string title () const;
virtual int order () const { return 20; }
virtual int order () const { return 0; }
void apply (lay::Dispatcher *root);
void setup (lay::Dispatcher *root);
@ -165,7 +167,7 @@ private:
* @brief The instance properties page (PCell parameters)
*/
class EditorOptionsInstPCellParam
: public lay::EditorOptionsPage
: public lay::EditorOptionsPageWidget
{
Q_OBJECT
@ -174,7 +176,7 @@ public:
~EditorOptionsInstPCellParam ();
virtual std::string title () const;
virtual int order () const { return 21; }
virtual int order () const { return 1; }
void apply (lay::Dispatcher *root);
void setup (lay::Dispatcher *root);
@ -192,6 +194,101 @@ private:
virtual void technology_changed (const std::string &);
};
/**
* @brief The toolbox widget for boxes
*/
class BoxToolboxWidget
: public lay::EditorOptionsPageWidget
{
Q_OBJECT
public:
BoxToolboxWidget (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher);
~BoxToolboxWidget ();
virtual std::string title () const;
virtual int order () const { return 200; }
virtual void configure (const std::string &name, const std::string &value);
virtual void commit (lay::Dispatcher *root);
virtual void deactivated ();
private:
QHBoxLayout *mp_layout;
lay::DecoratedLineEdit *mp_x_le, *mp_y_le;
};
/**
* @brief The toolbox widget for connections (polygon edges)
*/
class ConnectionToolboxWidget
: public lay::EditorOptionsPageWidget
{
Q_OBJECT
public:
ConnectionToolboxWidget (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher);
~ConnectionToolboxWidget ();
virtual std::string title () const;
virtual int order () const { return 200; }
virtual void configure (const std::string &name, const std::string &value);
virtual void commit (lay::Dispatcher *root);
virtual void deactivated ();
private:
QHBoxLayout *mp_layout;
lay::DecoratedLineEdit *mp_x_le, *mp_y_le;
bool m_in_commit;
};
/**
* @brief The toolbox widget for connections (path segments)
*/
class PathConnectionToolboxWidget
: public lay::EditorOptionsPageWidget
{
Q_OBJECT
public:
PathConnectionToolboxWidget (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher);
~PathConnectionToolboxWidget ();
virtual std::string title () const;
virtual int order () const { return 200; }
virtual void configure (const std::string &name, const std::string &value);
virtual void commit (lay::Dispatcher *root);
virtual void deactivated ();
private:
QHBoxLayout *mp_layout;
lay::DecoratedLineEdit *mp_x_le, *mp_y_le, *mp_width;
bool m_in_commit;
};
/**
* @brief The toolbox widget for texts
*/
class TextToolboxWidget
: public lay::EditorOptionsPageWidget
{
Q_OBJECT
public:
TextToolboxWidget (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher);
~TextToolboxWidget ();
virtual std::string title () const;
virtual int order () const { return 200; }
virtual void configure (const std::string &name, const std::string &value);
virtual void commit (lay::Dispatcher *root);
virtual void deactivated ();
private:
QHBoxLayout *mp_layout;
lay::DecoratedLineEdit *mp_text;
bool m_in_commit;
};
}
#endif

View File

@ -226,7 +226,7 @@ BEGIN_PROTECTED
layout = &cv->layout ();
}
lay::LibraryCellSelectionForm form (this, layout, "browse_lib_cell", false, lib != 0 /*for libs show top cells only*/);
lay::LibraryCellSelectionForm form (this, layout, "browse_lib_cell", false, lib != 0 /*for libs show top cells only*/, lib != 0 /*for libs hide private cells*/);
if (lib) {
form.setWindowTitle (tl::to_qstring (tl::to_string (QObject::tr ("Select Cell - Library: ")) + lib->get_description ()));
}

View File

@ -417,7 +417,7 @@ InstService::do_mouse_click (const db::DPoint &p)
}
void
InstService::do_finish_edit ()
InstService::do_finish_edit (bool /*accept*/)
{
try {

View File

@ -53,7 +53,7 @@ public:
virtual void do_mouse_move (const db::DPoint &p);
virtual bool do_mouse_click (const db::DPoint &p);
virtual void do_mouse_transform (const db::DPoint &p, db::DFTrans trans);
virtual void do_finish_edit ();
virtual void do_finish_edit (bool accept);
virtual void do_cancel_edit ();
virtual bool do_activated ();
#if defined(HAVE_QT)

View File

@ -133,6 +133,13 @@ MoveTrackerService::end_move (const db::DPoint & /*p*/, lay::angle_constraint_ty
move_cancel (); // formally this functionality fits here
}
void
MoveTrackerService::end_move (const db::DVector & /*v*/)
{
call_editor_hooks (m_editor_hooks, &edt::EditorHooks::commit_edit);
move_cancel (); // formally this functionality fits here
}
void
MoveTrackerService::edit_cancel ()
{

View File

@ -68,6 +68,11 @@ public:
*/
virtual void end_move (const db::DPoint &p, lay::angle_constraint_type ac);
/**
* @brief Terminate a "move" operation with compulsory move vector
*/
virtual void end_move (const db::DVector &v);
/**
* @brief Access to the view object
*/

View File

@ -26,6 +26,7 @@
#include "laySnap.h"
#include "layFinder.h"
#include "layConverters.h"
#include "layMove.h"
#include "tlProgress.h"
#include "edtPartialService.h"
#include "edtService.h"
@ -1096,7 +1097,7 @@ PartialService::PartialService (db::Manager *manager, lay::LayoutViewBase *view,
db::Object (manager),
mp_view (view),
mp_root (root),
m_dragging (false),
m_moving (false),
m_keep_selection (true),
mp_box (0),
m_color (0),
@ -1406,15 +1407,6 @@ PartialService::snap (const db::DVector &v_org) const
}
}
const int sr_pixels = 8; // TODO: make variable
lay::PointSnapToObjectResult
PartialService::snap2 (const db::DPoint &p) const
{
double snap_range = ui ()->mouse_event_trans ().inverted ().ctrans (sr_pixels);
return lay::obj_snap (m_snap_to_objects ? view () : 0, m_start, p, m_edit_grid == db::DVector () ? m_global_grid : m_edit_grid, move_ac (), snap_range);
}
void
PartialService::transform (const db::DCplxTrans &tr)
{
@ -1769,7 +1761,7 @@ void
PartialService::edit_cancel ()
{
// stop dragging, clear selection
m_dragging = false;
m_moving = false;
if (mp_box) {
delete mp_box;
@ -1790,74 +1782,85 @@ PartialService::wheel_event (int /*delta*/, bool /*horizontal*/, const db::DPoin
return false;
}
bool
PartialService::mouse_move_event (const db::DPoint &p, unsigned int buttons, bool prio)
const int sr_pixels = 8; // TODO: make variable
void
PartialService::move_impl (const db::DPoint &p)
{
clear_mouse_cursors ();
// drag the vertex or edge/segment
if (is_single_point_selection () || is_single_edge_selection ()) {
if (m_dragging) {
lay::PointSnapToObjectResult snap_details;
set_cursor (lay::Cursor::size_all);
// for a single selected point or edge, m_start is the original position and we snap the target -
// thus, we can bring the point on grid or to an object's edge or vertex
double snap_range = ui ()->mouse_event_trans ().inverted ().ctrans (sr_pixels);
snap_details = lay::obj_snap (m_snap_to_objects ? view () : 0, m_start, p, m_edit_grid == db::DVector () ? m_global_grid : m_edit_grid, lay::AC_Any, snap_range);;
m_alt_ac = lay::ac_from_buttons (buttons);
if (snap_details.object_snap == lay::PointSnapToObjectResult::NoObject) {
// drag the vertex or edge/segment
if (is_single_point_selection () || is_single_edge_selection ()) {
lay::PointSnapToObjectResult snap_details;
// for a single selected point or edge, m_start is the original position and we snap the target -
// thus, we can bring the point on grid or to an object's edge or vertex
snap_details = snap2 (p);
if (snap_details.object_snap == lay::PointSnapToObjectResult::NoObject) {
m_current = m_start + snap_move (p - m_start);
} else {
auto snapped_to_object = snap_details.snapped_point;
m_current = snapped_to_object;
if (snap_details.object_snap != lay::PointSnapToObjectResult::ObjectVertex) {
// snap to grid on longer side of reference edge and to object on shorter
auto snapped_to_object_and_grid = m_start + snap_move (snapped_to_object - m_start);
if (std::abs (snap_details.object_ref.dx ()) > std::abs (snap_details.object_ref.dy ())) {
m_current.set_x (snapped_to_object_and_grid.x ());
// project to edge, so we always hit it
auto cp = snap_details.object_ref.cut_point (db::DEdge (m_current, m_current + db::DVector (0, 1.0)));
if (cp.first) {
m_current.set_y (cp.second.y ());
}
} else if (std::abs (snap_details.object_ref.dy ()) > std::abs (snap_details.object_ref.dx ())) {
m_current.set_y (snapped_to_object_and_grid.y ());
// project to edge, so we always hit it
auto cp = snap_details.object_ref.cut_point (db::DEdge (m_current, m_current + db::DVector (1.0, 0)));
if (cp.first) {
m_current.set_x (cp.second.x ());
}
}
}
mouse_cursor_from_snap_details (snap_details);
}
m_current = m_start + snap_move (p - m_start);
} else {
// snap movement to angle and grid without object
m_current = m_start + snap_move (p - m_start);
clear_mouse_cursors ();
auto snapped_to_object = snap_details.snapped_point;
m_current = snapped_to_object;
if (snap_details.object_snap != lay::PointSnapToObjectResult::ObjectVertex) {
// snap to grid on longer side of reference edge and to object on shorter
auto snapped_to_object_and_grid = m_start + snap_move (snapped_to_object - m_start);
if (std::abs (snap_details.object_ref.dx ()) > std::abs (snap_details.object_ref.dy ())) {
m_current.set_x (snapped_to_object_and_grid.x ());
// project to edge, so we always hit it
auto cp = snap_details.object_ref.cut_point (db::DEdge (m_current, m_current + db::DVector (0, 1.0)));
if (cp.first) {
m_current.set_y (cp.second.y ());
}
} else if (std::abs (snap_details.object_ref.dy ()) > std::abs (snap_details.object_ref.dx ())) {
m_current.set_y (snapped_to_object_and_grid.y ());
// project to edge, so we always hit it
auto cp = snap_details.object_ref.cut_point (db::DEdge (m_current, m_current + db::DVector (1.0, 0)));
if (cp.first) {
m_current.set_x (cp.second.x ());
}
}
}
mouse_cursor_from_snap_details (snap_details);
}
selection_to_view ();
if (is_single_edge_selection ()) {
call_editor_hooks (m_editor_hooks, &edt::EditorHooks::begin_edits);
issue_editor_hook_calls (m_editor_hooks);
call_editor_hooks (m_editor_hooks, &edt::EditorHooks::end_edits);
// in case of edge movement, project the move vector to the edge normal -
// that is cosmetic, so we don't imply a lateral shift
auto e = single_selected_edge ().d ();
if (e.double_length () > db::epsilon) {
db::DVector n = db::DVector (e.y (), -e.x ()) * (1.0 / e.double_length ());
m_current = m_start + n * db::sprod (m_current - m_start, n);
}
m_alt_ac = lay::AC_Global;
}
} else {
// snap movement to angle and grid without object
m_current = m_start + snap_move (p - m_start);
}
selection_to_view ();
}
bool
PartialService::mouse_move_event (const db::DPoint &p, unsigned int buttons, bool prio)
{
if (m_moving) {
// event is handled by the move service
return false;
} else if (prio) {
@ -1916,9 +1919,9 @@ PartialService::mouse_press_event (const db::DPoint &p, unsigned int buttons, bo
return false;
}
if (m_dragging) {
if (m_moving) {
// eat events if already dragging
// eat events if moving -> handled by move service
return true;
} else if (! mp_box) {
@ -1964,25 +1967,8 @@ PartialService::mouse_press_event (const db::DPoint &p, unsigned int buttons, bo
} else {
// something was selected: start dragging this ..
m_dragging = true;
m_keep_selection = true;
if (is_single_point_selection ()) {
// for a single selected point we use the original point as the start location which
// allows bringing it to grid
m_current = m_start = single_selected_point ();
} else if (is_single_edge_selection ()) {
// for an edge selection use the point projected to edge as the start location which
// allows bringing it to grid
m_current = m_start = projected_to_edge (single_selected_edge (), p);
} else {
m_current = m_start = p;
}
ui ()->grab_mouse (this, true);
open_editor_hooks ();
// delegate further actions to move service, which will start a move operation
mp_view->move_service ()->start_move ();
}
@ -2014,43 +2000,9 @@ PartialService::mouse_click_event (const db::DPoint &p, unsigned int buttons, bo
return false;
}
if (m_dragging) {
if (m_moving) {
m_alt_ac = lay::ac_from_buttons (buttons);
if (m_current != m_start) {
// stop dragging
ui ()->ungrab_mouse (this);
if (manager ()) {
manager ()->transaction (tl::to_string (tr ("Partial move")));
}
// heuristically, if there is just one edge selected: do not confine to the movement
// angle constraint - the edge usually is confined enough
db::DTrans move_trans = db::DTrans (m_current - m_start);
transform_selection (move_trans);
if (manager ()) {
manager ()->commit ();
}
}
if (! m_keep_selection) {
m_selection.clear ();
}
m_dragging = false;
selection_to_view ();
close_editor_hooks (true);
m_alt_ac = lay::AC_Global;
return true;
return false;
} else if (ui ()->mouse_event_viewport ().contains (p)) {
@ -2143,26 +2095,16 @@ PartialService::mouse_click_event (const db::DPoint &p, unsigned int buttons, bo
}
// start dragging with that single selection
// start dragging with the selection
if (mode == lay::Editable::Replace && ! m_selection.empty ()) {
m_dragging = true;
// delegate further actions to move service, which will start a move operation
mp_view->move_service ()->start_move ();
// modify the decision to keep the selection (needs to come after the
// move service called begin_move)
m_keep_selection = ! new_selection;
if (is_single_point_selection ()) {
// for a single selected point we use the original point as the start location which
// allows bringing it to grid
m_current = m_start = single_selected_point ();
} else if (is_single_edge_selection ()) {
// for an edge selection use the point projected to edge as the start location which
// allows bringing it to grid
m_current = m_start = projected_to_edge (single_selected_edge (), p);
} else {
m_current = m_start = p;
}
open_editor_hooks ();
}
selection_to_view ();
@ -2197,10 +2139,6 @@ PartialService::mouse_double_click_event (const db::DPoint &p, unsigned int butt
close_editor_hooks (false);
// stop dragging
ui ()->ungrab_mouse (this);
m_dragging = false;
partial_select (db::DBox (p, p), lay::Editable::Replace);
if (! m_selection.empty ()) {
@ -2345,6 +2283,17 @@ PartialService::mouse_release_event (const db::DPoint &p, unsigned int buttons,
return false;
}
bool
PartialService::key_event (unsigned int key, unsigned int buttons)
{
if (m_moving && buttons == 0 && (key == lay::KeyEnter || key == lay::KeyReturn)) {
mp_view->move_service ()->end_move ();
return true;
} else {
return false;
}
}
bool
PartialService::begin_move (MoveMode mode, const db::DPoint &p, lay::angle_constraint_type ac)
{
@ -2352,7 +2301,7 @@ PartialService::begin_move (MoveMode mode, const db::DPoint &p, lay::angle_const
m_alt_ac = ac;
m_dragging = true;
m_moving = true;
m_keep_selection = true;
if (is_single_point_selection ()) {
@ -2432,7 +2381,7 @@ PartialService::snap_marker_to_grid (const db::DVector &v, bool &snapped) const
if (snapped) {
vr += vv;
return db::DVector (vr.x () * snapped_to.x (), vr.y () * snapped_to.y ());
return db::DVector (vr.x () * fabs (snapped_to.x ()), vr.y () * fabs (snapped_to.y ()));
} else {
return db::DVector ();
}
@ -2452,62 +2401,42 @@ PartialService::snap_move (const db::DVector &v) const
void
PartialService::move (const db::DPoint &p, lay::angle_constraint_type ac)
{
if (! m_dragging) {
if (! m_moving) {
return;
}
m_alt_ac = ac;
set_cursor (lay::Cursor::size_all);
clear_mouse_cursors ();
// drag the vertex or edge/segment
if (is_single_point_selection () || is_single_edge_selection ()) {
move_impl (p);
lay::PointSnapToObjectResult snap_details;
// for a single selected point or edge, m_start is the original position and we snap the target -
// thus, we can bring the point on grid or to an object's edge or vertex
snap_details = snap2 (p);
if (snap_details.object_snap == lay::PointSnapToObjectResult::NoObject) {
m_current = m_start + snap_move (p - m_start);
} else {
m_current = snap_details.snapped_point;
mouse_cursor_from_snap_details (snap_details);
}
} else {
// snap movement to angle and grid without object
m_current = m_start + snap_move (p - m_start);
clear_mouse_cursors ();
}
selection_to_view ();
propose_move_transformation (db::DTrans (m_current - m_start), 0);
m_alt_ac = lay::AC_Global;
}
void
PartialService::end_move (const db::DPoint & /*p*/, lay::angle_constraint_type ac)
PartialService::end_move (const db::DVector &v)
{
if (! m_dragging) {
m_current = m_start + v;
end_move (db::DPoint (), lay::AC_Any);
}
void
PartialService::end_move (const db::DPoint & /*p*/, lay::angle_constraint_type /*ac*/)
{
if (! m_moving) {
return;
}
m_alt_ac = ac;
if (m_current != m_start) {
// stop dragging
ui ()->ungrab_mouse (this);
if (manager ()) {
manager ()->transaction (tl::to_string (tr ("Partial move")));
}
// heuristically, if there is just one edge selected: do not confine to the movement
// angle constraint - the edge usually is confined enough
db::DTrans move_trans = db::DTrans (m_current - m_start);
transform_selection (move_trans);
@ -2522,7 +2451,7 @@ PartialService::end_move (const db::DPoint & /*p*/, lay::angle_constraint_type a
m_selection.clear ();
}
m_dragging = false;
m_moving = false;
selection_to_view ();
clear_mouse_cursors ();
@ -2608,9 +2537,6 @@ PartialService::del ()
{
std::set<db::Layout *> needs_cleanup;
// stop dragging
ui ()->ungrab_mouse (this);
std::map <std::pair <db::cell_index_type, std::pair <unsigned int, unsigned int> >, std::vector <partial_objects::const_iterator> > shapes_to_delete_by_cell;
for (partial_objects::iterator r = m_selection.begin (); r != m_selection.end (); ++r) {
@ -2703,7 +2629,6 @@ PartialService::del ()
handle_guiding_shape_changes ();
m_selection.clear ();
m_dragging = false;
selection_to_view ();
close_editor_hooks (false);
@ -3008,22 +2933,8 @@ PartialService::do_selection_to_view ()
{
// if dragging, establish the current displacement
db::DTrans move_trans;
if (m_dragging) {
// heuristically, if there is just one edge selected: do not confine to the movement
// angle constraint - the edge usually is confined enough
if (m_selection.size () == 1 && ! m_selection.begin ()->first.is_cell_inst () && m_selection.begin ()->second.size () == 3 /*p1,p2,edge*/) {
move_trans = db::DTrans (m_current - m_start);
} else {
// TODO: DTrans should have a ctor that takes a vector
move_trans = db::DTrans (lay::snap_angle (m_current - m_start, move_ac ()));
}
// display vector
view ()->message (std::string ("dx: ") + tl::micron_to_string (move_trans.disp ().x ()) +
std::string (" dy: ") + tl::micron_to_string (move_trans.disp ().y ()) +
std::string (" d: ") + tl::micron_to_string (move_trans.disp ().length ()));
if (m_moving) {
move_trans = db::DTrans (m_current - m_start);
}
size_t n_marker = 0;
@ -3065,7 +2976,7 @@ PartialService::do_selection_to_view ()
std::map <EdgeWithIndex, db::Edge> new_edges;
std::map <PointWithIndex, db::Point> new_points;
if (m_dragging) {
if (m_moving) {
create_shift_sets (r->first.shape (), r->second, new_points, new_edges, move_vector);
}

View File

@ -234,6 +234,11 @@ public:
*/
virtual bool mouse_release_event (const db::DPoint &p, unsigned int buttons, bool prio);
/**
* @brief Key handling event
*/
virtual bool key_event (unsigned int key, unsigned int buttons);
/**
* @brief Transforms the selection
*
@ -287,6 +292,11 @@ public:
*/
virtual void end_move (const db::DPoint &p, lay::angle_constraint_type ac);
/**
* @brief Terminate a "move" operation with compulsory move vector
*/
virtual void end_move (const db::DVector &v);
/**
* @brief Implement the "select" method at least to clear the selection
*/
@ -335,7 +345,7 @@ private:
// The layout view that this service is attached to
lay::LayoutViewBase *mp_view;
lay::Dispatcher *mp_root;
bool m_dragging;
bool m_moving;
bool m_keep_selection;
db::DPoint m_start, m_current;
db::DPoint m_p1, m_p2;
@ -381,10 +391,10 @@ private:
db::DPoint snap (const db::DPoint &p) const;
db::DVector snap (const db::DVector &p) const;
lay::PointSnapToObjectResult snap2 (const db::DPoint &p) const;
void update_vector_snapped_point (const db::DPoint &pt, db::DVector &vr, bool &result_set) const;
db::DVector snap_marker_to_grid (const db::DVector &v, bool &snapped) const;
db::DVector snap_move(const db::DVector &p) const;
void move_impl (const db::DPoint &p);
void enter_edge (const EdgeWithIndex &e, size_t &nmarker, partial_objects::const_iterator sel, const std::map <PointWithIndex, db::Point> &new_points, const std::map <EdgeWithIndex, db::Edge> &new_edges, const db::ICplxTrans &gt, const std::vector<db::DCplxTrans> &tv, bool transient);
void enter_vertices (size_t &nmarker, partial_objects::const_iterator sel, const std::map <PointWithIndex, db::Point> &new_points, const std::map <EdgeWithIndex, db::Edge> &new_edges, const db::ICplxTrans &gt, const std::vector<db::DCplxTrans> &tv, bool transient);

View File

@ -26,6 +26,7 @@
#include "edtPropertiesPages.h"
#include "layLayoutViewBase.h"
#include "layEditorOptionsPage.h"
#include "layFinder.h"
namespace edt
@ -160,13 +161,15 @@ PathService::do_delete ()
}
void
PathService::do_finish_edit ()
PathService::do_finish_edit (bool accept)
{
// one point is reserved for the "current one"
if (m_points.size () < 3) {
// one point is reserved for the "current one" if accept is false
if (! accept && ! m_points.empty ()) {
m_points.pop_back ();
}
if (m_points.size () < 2) {
throw tl::Exception (tl::to_string (tr ("A path must have at least 2 points")));
}
m_points.pop_back ();
deliver_shape (get_path ());
@ -175,6 +178,32 @@ PathService::do_finish_edit ()
close_editor_hooks (true);
}
void
PathService::function (const std::string &name, const std::string &value)
{
if (name == ShapeEditService::connection_function_name ()) {
try {
db::DVector dim;
tl::from_string (value, dim);
if (m_points.size () >= 2) {
m_last = m_points.back () = m_points.end () [-2] + dim;
m_points.push_back (m_last);
update_marker ();
update_via ();
}
} catch (...) {
}
}
}
void
PathService::update_marker ()
{
@ -185,12 +214,17 @@ PathService::update_marker ()
marker->set (path, db::VCplxTrans (1.0 / layout ().dbu ()) * trans ().inverted ());
if (m_points.size () >= 2) {
db::DVector dim = m_points.back () - m_points.end () [-2];
view ()->message (std::string ("lx: ") +
tl::micron_to_string (m_points.back ().x () - m_points.end () [-2].x ()) +
tl::micron_to_string (dim.x ()) +
std::string (" ly: ") +
tl::micron_to_string (m_points.back ().y () - m_points.end () [-2].y ()) +
tl::micron_to_string (dim.y ()) +
std::string (" l: ") +
tl::micron_to_string (m_points.back ().distance (m_points.end () [-2])));
tl::micron_to_string (dim.length ()));
auto tb = toolbox_widget ();
if (tb) {
tb->configure (ShapeEditService::connection_configure_name (), dim.to_string ());
}
}
}
@ -695,6 +729,11 @@ PathService::pop_segment ()
bool
PathService::configure (const std::string &name, const std::string &value)
{
auto tb = toolbox_widget ();
if (tb) {
tb->configure (name, value);
}
if (name == cfg_edit_path_width) {
tl::from_string (value, m_width);
m_needs_update = true;

View File

@ -47,11 +47,12 @@ public:
virtual bool do_mouse_click (const db::DPoint &p);
virtual void do_mouse_move_inactive (const db::DPoint &p);
virtual void do_delete ();
virtual void do_finish_edit ();
virtual void do_finish_edit (bool accept);
virtual void do_cancel_edit ();
virtual bool do_activated ();
virtual void via (int dir);
virtual bool selection_applies (const lay::ObjectInstPath &sel) const;
virtual void function (const std::string &name, const std::string &value);
protected:
bool configure (const std::string &name, const std::string &value);

View File

@ -21,13 +21,9 @@
*/
#if defined(HAVE_QT)
# include "layTipDialog.h"
# include "layEditorOptionsPages.h"
#endif
#include "layDispatcher.h"
#include "layLayoutViewBase.h"
#include "layEditorOptionsPage.h"
#include "edtPlugin.h"
#include "edtConfig.h"
#include "edtService.h"
@ -40,38 +36,19 @@
#include "edtMainService.h"
#include "edtPartialService.h"
#include "edtMoveTrackerService.h"
#if defined(HAVE_QT)
# include "edtEditorOptionsPages.h"
# include "edtRecentConfigurationPage.h"
#endif
#include "edtEditorOptionsPages.h"
#include "edtRecentConfigurationPage.h"
#if defined(HAVE_QT)
# include <QApplication>
# include <QLayout>
# include <QMessageBox>
# include "layTipDialog.h"
#endif
namespace edt
{
#if defined(HAVE_QT)
edt::RecentConfigurationPage::ConfigurationDescriptor shape_cfg_descriptors[] =
{
edt::RecentConfigurationPage::ConfigurationDescriptor ("", tl::to_string (tr ("Layer")), edt::RecentConfigurationPage::Layer),
};
#endif
#if defined(HAVE_QT)
static
void get_shape_editor_options_pages (std::vector<lay::EditorOptionsPage *> &ret, lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
{
ret.push_back (new RecentConfigurationPage (view, dispatcher, "edit-recent-shape-param",
&shape_cfg_descriptors[0], &shape_cfg_descriptors[sizeof (shape_cfg_descriptors) / sizeof (shape_cfg_descriptors[0])]));
}
#else
static void get_shape_editor_options_pages () { }
#endif
static
void get_text_options (std::vector < std::pair<std::string, std::string> > &options)
{
@ -81,27 +58,6 @@ void get_text_options (std::vector < std::pair<std::string, std::string> > &opti
options.push_back (std::pair<std::string, std::string> (cfg_edit_text_valign, "bottom"));
}
#if defined(HAVE_QT)
static
void get_text_editor_options_pages (std::vector<lay::EditorOptionsPage *> &ret, lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
{
static edt::RecentConfigurationPage::ConfigurationDescriptor text_cfg_descriptors[] =
{
edt::RecentConfigurationPage::ConfigurationDescriptor ("", tl::to_string (tr ("Layer")), edt::RecentConfigurationPage::Layer),
edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_text_string, tl::to_string (tr ("Text")), edt::RecentConfigurationPage::Text),
edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_text_size, tl::to_string (tr ("Size")), edt::RecentConfigurationPage::Double),
edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_text_halign, tl::to_string (tr ("Hor. align")), edt::RecentConfigurationPage::Text),
edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_text_valign, tl::to_string (tr ("Vert. align")), edt::RecentConfigurationPage::Text)
};
ret.push_back (new RecentConfigurationPage (view, dispatcher, "edit-recent-text-param",
&text_cfg_descriptors[0], &text_cfg_descriptors[sizeof (text_cfg_descriptors) / sizeof (text_cfg_descriptors[0])]));
ret.push_back (new edt::EditorOptionsText (view, dispatcher));
}
#else
static void get_text_editor_options_pages () { }
#endif
static
void get_path_options (std::vector < std::pair<std::string, std::string> > &options)
{
@ -111,27 +67,6 @@ void get_path_options (std::vector < std::pair<std::string, std::string> > &opti
options.push_back (std::pair<std::string, std::string> (cfg_edit_path_ext_var_end, "0.0"));
}
#if defined(HAVE_QT)
static
void get_path_editor_options_pages (std::vector<lay::EditorOptionsPage *> &ret, lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
{
static edt::RecentConfigurationPage::ConfigurationDescriptor path_cfg_descriptors[] =
{
edt::RecentConfigurationPage::ConfigurationDescriptor ("", tl::to_string (tr ("Layer")), edt::RecentConfigurationPage::Layer),
edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_path_width, tl::to_string (tr ("Width")), edt::RecentConfigurationPage::Double),
edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_path_ext_type, tl::to_string (tr ("Ends")), edt::RecentConfigurationPage::Int),
edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_path_ext_var_begin, tl::to_string (tr ("Begin ext.")), edt::RecentConfigurationPage::Double),
edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_path_ext_var_end, tl::to_string (tr ("End ext.")), edt::RecentConfigurationPage::Double)
};
ret.push_back (new RecentConfigurationPage (view, dispatcher, "edit-recent-path-param",
&path_cfg_descriptors[0], &path_cfg_descriptors[sizeof (path_cfg_descriptors) / sizeof (path_cfg_descriptors[0])]));
ret.push_back (new EditorOptionsPath (view, dispatcher));
}
#else
static void get_path_editor_options_pages () { }
#endif
static
void get_inst_options (std::vector < std::pair<std::string, std::string> > &options)
{
@ -153,58 +88,17 @@ void get_inst_options (std::vector < std::pair<std::string, std::string> > &opti
options.push_back (std::pair<std::string, std::string> (cfg_edit_show_shapes_of_instances, "true"));
}
#if defined(HAVE_QT)
static
void get_inst_editor_options_pages (std::vector<lay::EditorOptionsPage *> &ret, lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
{
static edt::RecentConfigurationPage::ConfigurationDescriptor inst_cfg_descriptors[] =
{
edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_inst_lib_name, tl::to_string (tr ("Library")), edt::RecentConfigurationPage::CellLibraryName),
edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_inst_cell_name, tl::to_string (tr ("Cell")), edt::RecentConfigurationPage::CellDisplayName),
edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_inst_angle, tl::to_string (tr ("Angle")), edt::RecentConfigurationPage::Double),
edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_inst_mirror, tl::to_string (tr ("Mirror")), edt::RecentConfigurationPage::Bool),
edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_inst_scale, tl::to_string (tr ("Scale")), edt::RecentConfigurationPage::Double),
edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_inst_array, tl::to_string (tr ("Array")), edt::RecentConfigurationPage::ArrayFlag),
edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_inst_rows, tl::to_string (tr ("Rows")), edt::RecentConfigurationPage::IntIfArray),
edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_inst_row_x, tl::to_string (tr ("Row step (x)")), edt::RecentConfigurationPage::DoubleIfArray),
edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_inst_row_y, tl::to_string (tr ("Row step (y)")), edt::RecentConfigurationPage::DoubleIfArray),
edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_inst_columns, tl::to_string (tr ("Columns")), edt::RecentConfigurationPage::IntIfArray),
edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_inst_column_x, tl::to_string (tr ("Column step (x)")), edt::RecentConfigurationPage::DoubleIfArray),
edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_inst_column_y, tl::to_string (tr ("Column step (y)")), edt::RecentConfigurationPage::DoubleIfArray),
edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_inst_pcell_parameters, tl::to_string (tr ("PCell parameters")), edt::RecentConfigurationPage::PCellParameters)
};
ret.push_back (new RecentConfigurationPage (view, dispatcher, "edit-recent-inst-param",
&inst_cfg_descriptors[0], &inst_cfg_descriptors[sizeof (inst_cfg_descriptors) / sizeof (inst_cfg_descriptors[0])]));
ret.push_back (new EditorOptionsInstPCellParam (view, dispatcher));
ret.push_back (new EditorOptionsInst (view, dispatcher));
}
#else
static void get_inst_editor_options_pages () { }
#endif
template <class Svc>
class PluginDeclaration
: public PluginDeclarationBase
{
public:
#if defined(HAVE_QT)
PluginDeclaration (const std::string &title, const std::string &mouse_mode,
void (*option_get_f) (std::vector < std::pair<std::string, std::string> > &) = 0,
void (*pages_f) (std::vector <lay::EditorOptionsPage *> &, lay::LayoutViewBase *, lay::Dispatcher *) = 0)
: m_title (title), m_mouse_mode (mouse_mode), mp_option_get_f (option_get_f), mp_pages_f (pages_f)
void (*option_get_f) (std::vector < std::pair<std::string, std::string> > &) = 0)
: m_title (title), m_mouse_mode (mouse_mode), mp_option_get_f (option_get_f)
{
// .. nothing yet ..
}
#else
PluginDeclaration (const std::string &title, const std::string &mouse_mode,
void (*option_get_f) (std::vector < std::pair<std::string, std::string> > &) = 0,
void (*pages_f) () = 0)
: m_title (title), m_mouse_mode (mouse_mode), mp_option_get_f (option_get_f), mp_pages_f (pages_f)
{
// .. nothing yet ..
}
#endif
virtual void get_options (std::vector < std::pair<std::string, std::string> > &options) const
{
@ -225,19 +119,6 @@ public:
// .. nothing yet ..
}
#if defined(HAVE_QT)
virtual void get_editor_options_pages (std::vector<lay::EditorOptionsPage *> &pages, lay::LayoutViewBase *view, lay::Dispatcher *root) const
{
if (mp_pages_f != 0) {
size_t nstart = pages.size ();
(*mp_pages_f) (pages, view, root);
while (nstart < pages.size ()) {
pages [nstart++]->set_plugin_declaration (this);
}
}
}
#endif
virtual lay::Plugin *create_plugin (db::Manager *manager, lay::Dispatcher *, lay::LayoutViewBase *view) const
{
Svc *service = new Svc (manager, view);
@ -261,45 +142,47 @@ public:
}
}
virtual std::vector<std::string> additional_editor_options_pages () const
{
std::vector<std::string> names;
names.push_back ("GenericEditorOptions");
return names;
}
private:
std::string m_title;
std::string m_mouse_mode;
void (*mp_option_get_f) (std::vector < std::pair<std::string, std::string> > &options);
#if defined(HAVE_QT)
void (*mp_pages_f) (std::vector <lay::EditorOptionsPage *> &, lay::LayoutViewBase *, lay::Dispatcher *);
#else
void (*mp_pages_f) ();
#endif
};
static tl::RegisteredClass<lay::PluginDeclaration> config_decl1 (
new edt::PluginDeclaration<edt::PolygonService> (tl::to_string (tr ("Polygons")), "polygon:edit_mode\t" + tl::to_string (tr ("Polygon")) + "<:polygon_24px.png>" + tl::to_string (tr ("{Create a polygon}")), 0, &get_shape_editor_options_pages),
new edt::PluginDeclaration<edt::PolygonService> (tl::to_string (tr ("Polygons")), "polygon:edit_mode\t" + tl::to_string (tr ("Polygon")) + "<:polygon_24px.png>" + tl::to_string (tr ("{Create a polygon}")), 0),
4010,
"edt::Service(Polygons)"
);
static tl::RegisteredClass<lay::PluginDeclaration> config_decl2 (
new edt::PluginDeclaration<edt::BoxService> (tl::to_string (tr ("Boxes")), "box:edit_mode\t" + tl::to_string (tr ("Box")) + "\t<:box_24px.png>" + tl::to_string (tr ("{Create a box}")), 0, &get_shape_editor_options_pages),
new edt::PluginDeclaration<edt::BoxService> (tl::to_string (tr ("Boxes")), "box:edit_mode\t" + tl::to_string (tr ("Box")) + "\t<:box_24px.png>" + tl::to_string (tr ("{Create a box}")), 0),
4011,
"edt::Service(Boxes)"
);
static tl::RegisteredClass<lay::PluginDeclaration> config_decl3 (
new edt::PluginDeclaration<edt::TextService> (tl::to_string (tr ("Texts")), "text:edit_mode\t" + tl::to_string (tr ("Text")) + "\t<:text_24px.png>" + tl::to_string (tr ("{Create a text object}")), &get_text_options, &get_text_editor_options_pages),
new edt::PluginDeclaration<edt::TextService> (tl::to_string (tr ("Texts")), "text:edit_mode\t" + tl::to_string (tr ("Text")) + "\t<:text_24px.png>" + tl::to_string (tr ("{Create a text object}")), &get_text_options),
4012,
"edt::Service(Texts)"
);
static tl::RegisteredClass<lay::PluginDeclaration> config_decl4 (
new edt::PluginDeclaration<edt::PathService> (tl::to_string (tr ("Paths")), "path:edit_mode\t" + tl::to_string (tr ("Path")) + "\t<:path_24px.png>" + tl::to_string (tr ("{Create a path}")), &get_path_options, &get_path_editor_options_pages),
new edt::PluginDeclaration<edt::PathService> (tl::to_string (tr ("Paths")), "path:edit_mode\t" + tl::to_string (tr ("Path")) + "\t<:path_24px.png>" + tl::to_string (tr ("{Create a path}")), &get_path_options),
4013,
"edt::Service(Paths)"
);
static tl::RegisteredClass<lay::PluginDeclaration> config_decl5 (
new edt::PluginDeclaration<edt::PointService> (tl::to_string (tr ("Points")), std::string (), 0, &get_shape_editor_options_pages),
new edt::PluginDeclaration<edt::PointService> (tl::to_string (tr ("Points")), std::string (), 0),
4014,
"edt::Service(Points)"
);
static tl::RegisteredClass<lay::PluginDeclaration> config_decl6 (
new edt::PluginDeclaration<edt::InstService> (tl::to_string (tr ("Instances")), "instance:edit_mode\t" + tl::to_string (tr ("Instance")) + "\t<:instance_24px.png>" + tl::to_string (tr ("{Create a cell instance}")), &get_inst_options, &get_inst_editor_options_pages),
new edt::PluginDeclaration<edt::InstService> (tl::to_string (tr ("Instances")), "instance:edit_mode\t" + tl::to_string (tr ("Instance")) + "\t<:instance_24px.png>" + tl::to_string (tr ("{Create a cell instance}")), &get_inst_options),
4020,
"edt::Service(CellInstances)"
);
@ -418,15 +301,6 @@ public:
return false;
}
#if defined(HAVE_QT)
virtual void get_editor_options_pages (std::vector<lay::EditorOptionsPage *> &pages, lay::LayoutViewBase *view, lay::Dispatcher *dispatcher) const
{
// NOTE: we do not set plugin_declaration which makes the page unspecific
EditorOptionsGeneric *generic_opt = new EditorOptionsGeneric (view, dispatcher);
pages.push_back (generic_opt);
}
#endif
virtual void initialize (lay::Dispatcher *root)
{
lay::Dispatcher *mp = lay::Dispatcher::instance ();
@ -524,16 +398,6 @@ public:
// .. nothing yet ..
}
virtual void get_options (std::vector < std::pair<std::string, std::string> > & /*options*/) const
{
// .. nothing yet ..
}
virtual void get_editor_options_pages (std::vector<lay::EditorOptionsPage *> & /*pages*/, lay::LayoutViewBase * /*view*/, lay::Dispatcher * /*root*/) const
{
// .. no specific ones ..
}
virtual lay::Plugin *create_plugin (db::Manager *manager, lay::Dispatcher *root, lay::LayoutViewBase *view) const
{
return new edt::PartialService (manager, view, root);
@ -551,6 +415,13 @@ public:
return true;
}
virtual std::vector<std::string> additional_editor_options_pages () const
{
std::vector<std::string> names;
names.push_back ("GenericEditorOptions");
return names;
}
private:
std::string m_title;
std::string m_mouse_mode;

View File

@ -124,7 +124,7 @@ PointService::do_mouse_click (const db::DPoint &p)
}
void
PointService::do_finish_edit ()
PointService::do_finish_edit (bool /*accept*/)
{
deliver_shape (get_point ());
commit_recent ();

View File

@ -45,7 +45,7 @@ public:
virtual void do_mouse_move (const db::DPoint &p);
virtual void do_mouse_move_inactive (const db::DPoint &p);
virtual bool do_mouse_click (const db::DPoint &p);
virtual void do_finish_edit ();
virtual void do_finish_edit (bool);
virtual void do_cancel_edit ();
virtual bool selection_applies (const lay::ObjectInstPath &sel) const;

View File

@ -24,6 +24,7 @@
#include "edtPolygonService.h"
#include "layLayoutViewBase.h"
#include "layEditorOptionsPage.h"
#if defined(HAVE_QT)
# include "edtPropertiesPages.h"
@ -135,13 +136,44 @@ PolygonService::do_mouse_click (const db::DPoint &p)
}
void
PolygonService::do_finish_edit ()
PolygonService::do_finish_edit (bool accept)
{
if (accept) {
// add a dummy point in this case for the current one
m_last = m_points.back ();
m_points.push_back (db::DPoint ());
}
deliver_shape (get_polygon (false));
commit_recent ();
close_editor_hooks (true);
}
void
PolygonService::function (const std::string &name, const std::string &value)
{
if (name == ShapeEditService::connection_function_name ()) {
try {
db::DVector dim;
tl::from_string (value, dim);
if (m_points.size () >= 2) {
m_last = m_points.back () = m_points.end () [-2] + dim;
m_points.push_back (m_last);
update_marker ();
}
} catch (...) {
}
}
}
db::Polygon
PolygonService::get_polygon (bool editing) const
{
@ -363,12 +395,17 @@ PolygonService::update_marker ()
}
if (m_points.size () >= 2) {
db::DVector dim = m_points.back () - m_points [m_points.size () - 2];
view ()->message (std::string ("lx: ") +
tl::micron_to_string (m_points.back ().x () - m_points.end () [-2].x ()) +
tl::micron_to_string (dim.x ()) +
std::string (" ly: ") +
tl::micron_to_string (m_points.back ().y () - m_points.end () [-2].y ()) +
tl::micron_to_string (dim.y ()) +
std::string (" l: ") +
tl::micron_to_string (m_points.back ().distance (m_points.end () [-2])));
tl::micron_to_string (dim.length ()));
auto tb = toolbox_widget ();
if (tb) {
tb->configure (ShapeEditService::connection_configure_name (), dim.to_string ());
}
}
// call hooks with new shape

View File

@ -46,9 +46,10 @@ public:
virtual void do_mouse_move (const db::DPoint &p);
virtual void do_mouse_move_inactive (const db::DPoint &p);
virtual bool do_mouse_click (const db::DPoint &p);
virtual void do_finish_edit ();
virtual void do_finish_edit (bool);
virtual void do_cancel_edit ();
virtual bool selection_applies (const lay::ObjectInstPath &sel) const;
virtual void function (const std::string &name, const std::string &value);
private:
std::vector <db::DPoint> m_points;

View File

@ -23,6 +23,7 @@
#if defined(HAVE_QT)
#include "edtRecentConfigurationPage.h"
#include "edtConfig.h"
#include "layDispatcher.h"
#include "layLayoutViewBase.h"
#include "layLayerTreeModel.h"
@ -497,6 +498,92 @@ RecentConfigurationPage::config_recent_for_layer (lay::Dispatcher *root, const d
}
}
// ------------------------------------------------------------------
// Configurations and registrations
namespace {
class RecentShapeConfigurationPage
: public edt::RecentConfigurationPage
{
public:
RecentShapeConfigurationPage (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
: edt::RecentConfigurationPage (view, dispatcher, "edit-recent-shape-param")
{
add (edt::RecentConfigurationPage::ConfigurationDescriptor ("", tl::to_string (tr ("Layer")), edt::RecentConfigurationPage::Layer));
init ();
}
};
class RecentTextConfigurationPage
: public edt::RecentConfigurationPage
{
public:
RecentTextConfigurationPage (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
: edt::RecentConfigurationPage (view, dispatcher, "edit-recent-text-param")
{
add (edt::RecentConfigurationPage::ConfigurationDescriptor ("", tl::to_string (tr ("Layer")), edt::RecentConfigurationPage::Layer));
add (edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_text_string, tl::to_string (tr ("Text")), edt::RecentConfigurationPage::Text));
add (edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_text_size, tl::to_string (tr ("Size")), edt::RecentConfigurationPage::Double));
add (edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_text_halign, tl::to_string (tr ("Hor. align")), edt::RecentConfigurationPage::Text));
add (edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_text_valign, tl::to_string (tr ("Vert. align")), edt::RecentConfigurationPage::Text));
init ();
}
};
class RecentPathConfigurationPage
: public edt::RecentConfigurationPage
{
public:
RecentPathConfigurationPage (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
: edt::RecentConfigurationPage (view, dispatcher, "edit-recent-path-param")
{
add (edt::RecentConfigurationPage::ConfigurationDescriptor ("", tl::to_string (tr ("Layer")), edt::RecentConfigurationPage::Layer));
add (edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_path_width, tl::to_string (tr ("Width")), edt::RecentConfigurationPage::Double));
add (edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_path_ext_type, tl::to_string (tr ("Ends")), edt::RecentConfigurationPage::Int));
add (edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_path_ext_var_begin, tl::to_string (tr ("Begin ext.")), edt::RecentConfigurationPage::Double));
add (edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_path_ext_var_end, tl::to_string (tr ("End ext.")), edt::RecentConfigurationPage::Double));
init ();
}
};
class RecentInstConfigurationPage
: public edt::RecentConfigurationPage
{
public:
RecentInstConfigurationPage (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
: edt::RecentConfigurationPage (view, dispatcher, "edit-recent-inst-param")
{
add (edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_inst_lib_name, tl::to_string (tr ("Library")), edt::RecentConfigurationPage::CellLibraryName));
add (edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_inst_cell_name, tl::to_string (tr ("Cell")), edt::RecentConfigurationPage::CellDisplayName));
add (edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_inst_angle, tl::to_string (tr ("Angle")), edt::RecentConfigurationPage::Double));
add (edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_inst_mirror, tl::to_string (tr ("Mirror")), edt::RecentConfigurationPage::Bool));
add (edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_inst_scale, tl::to_string (tr ("Scale")), edt::RecentConfigurationPage::Double));
add (edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_inst_array, tl::to_string (tr ("Array")), edt::RecentConfigurationPage::ArrayFlag));
add (edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_inst_rows, tl::to_string (tr ("Rows")), edt::RecentConfigurationPage::IntIfArray));
add (edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_inst_row_x, tl::to_string (tr ("Row step (x)")), edt::RecentConfigurationPage::DoubleIfArray));
add (edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_inst_row_y, tl::to_string (tr ("Row step (y)")), edt::RecentConfigurationPage::DoubleIfArray));
add (edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_inst_columns, tl::to_string (tr ("Columns")), edt::RecentConfigurationPage::IntIfArray));
add (edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_inst_column_x, tl::to_string (tr ("Column step (x)")), edt::RecentConfigurationPage::DoubleIfArray));
add (edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_inst_column_y, tl::to_string (tr ("Column step (y)")), edt::RecentConfigurationPage::DoubleIfArray));
add (edt::RecentConfigurationPage::ConfigurationDescriptor (cfg_edit_inst_pcell_parameters, tl::to_string (tr ("PCell parameters")), edt::RecentConfigurationPage::PCellParameters));
init ();
}
};
}
static tl::RegisteredClass<lay::EditorOptionsPageFactoryBase> s_factory_polygons (new lay::EditorOptionsPageFactory<RecentShapeConfigurationPage> ("edt::Service(Polygons)"), 0);
static tl::RegisteredClass<lay::EditorOptionsPageFactoryBase> s_factory_boxes (new lay::EditorOptionsPageFactory<RecentShapeConfigurationPage> ("edt::Service(Boxes)"), 0);
static tl::RegisteredClass<lay::EditorOptionsPageFactoryBase> s_factory_points (new lay::EditorOptionsPageFactory<RecentShapeConfigurationPage> ("edt::Service(Points)"), 0);
static tl::RegisteredClass<lay::EditorOptionsPageFactoryBase> s_factory_texts (new lay::EditorOptionsPageFactory<RecentTextConfigurationPage> ("edt::Service(Texts)"), 0);
static tl::RegisteredClass<lay::EditorOptionsPageFactoryBase> s_factory_paths (new lay::EditorOptionsPageFactory<RecentPathConfigurationPage> ("edt::Service(Paths)"), 0);
static tl::RegisteredClass<lay::EditorOptionsPageFactoryBase> s_factory_insts (new lay::EditorOptionsPageFactory<RecentInstConfigurationPage> ("edt::Service(CellInstances)"), 0);
}
#endif

View File

@ -26,7 +26,7 @@
#define HDR_edtRecentConfigurationPage
#include "edtCommon.h"
#include "layEditorOptionsPage.h"
#include "layEditorOptionsPageWidget.h"
#include "tlObject.h"
#include "tlDeferredExecution.h"
@ -48,13 +48,11 @@ namespace edt
class PCellParametersPage;
class EditorOptionsPages;
/**
* @brief The base class for a object properties page
*/
class EDT_PUBLIC RecentConfigurationPage
: public lay::EditorOptionsPage
: public lay::EditorOptionsPageWidget
{
Q_OBJECT
@ -84,11 +82,10 @@ public:
ConfigurationRendering rendering;
};
template <class Iter>
RecentConfigurationPage (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher, const std::string &recent_cfg_name, Iter begin_cfg, Iter end_cfg)
: EditorOptionsPage (view, dispatcher), m_recent_cfg_name (recent_cfg_name), m_cfg (begin_cfg, end_cfg), dm_update_list (this, &RecentConfigurationPage::update_list)
RecentConfigurationPage (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher, const std::string &recent_cfg_name)
: EditorOptionsPageWidget (view, dispatcher), m_recent_cfg_name (recent_cfg_name), dm_update_list (this, &RecentConfigurationPage::update_list)
{
init ();
// .. nothing yet ..
}
virtual ~RecentConfigurationPage ();
@ -100,6 +97,21 @@ public:
virtual void commit_recent (lay::Dispatcher *root);
virtual void config_recent_for_layer (lay::Dispatcher *root, const db::LayerProperties &lp, int cv_index);
protected:
/**
* @brief Adds a configuration descriptors
* Use this method in the constructor to add descriptors.
*/
void add (const ConfigurationDescriptor &cfg)
{
m_cfg.push_back (cfg);
}
/**
* @brief Initializes the widget after the configuration items have been added
*/
void init ();
private slots:
void item_clicked (QTreeWidgetItem *item);
@ -109,7 +121,6 @@ private:
QTreeWidget *mp_tree_widget;
tl::DeferredMethod<RecentConfigurationPage> dm_update_list;
void init ();
void update_list (const std::list<std::vector<std::string> > &stored_values);
void update_list ();
std::list<std::vector<std::string> > get_stored_values () const;

View File

@ -32,7 +32,7 @@
#include "layLayoutView.h"
#include "laySnap.h"
#include "layConverters.h"
#include "layEditorOptionsPages.h"
#include "layEditorOptionsPage.h"
#include "tlProgress.h"
#include "tlTimer.h"
@ -46,7 +46,7 @@ Service::Service (db::Manager *manager, lay::LayoutViewBase *view, db::ShapeIter
db::Object (manager),
mp_view (view),
mp_transient_marker (0),
m_mouse_in_view (false), m_editing (false), m_immediate (false),
m_mouse_buttons (0), m_mouse_in_view (false), m_editing (false), m_immediate (false),
m_selection_maybe_invalid (false),
m_cell_inst_service (false),
m_flags (flags),
@ -70,7 +70,7 @@ Service::Service (db::Manager *manager, lay::LayoutViewBase *view)
db::Object (manager),
mp_view (view),
mp_transient_marker (0),
m_mouse_in_view (false), m_editing (false), m_immediate (false),
m_mouse_buttons (0), m_mouse_in_view (false), m_editing (false), m_immediate (false),
m_selection_maybe_invalid (false),
m_cell_inst_service (true),
m_flags (db::ShapeIterator::Nothing),
@ -103,14 +103,21 @@ Service::~Service ()
clear_transient_selection ();
}
lay::angle_constraint_type
lay::angle_constraint_type
Service::alt_ac () const
{
// fetch m_alt_ac (which is set from mouse buttons)
return m_alt_ac;
}
lay::angle_constraint_type
Service::connect_ac () const
{
// m_alt_ac (which is set from mouse buttons) can override the specified connect angle constraint
return m_alt_ac != lay::AC_Global ? m_alt_ac : m_connect_ac;
}
lay::angle_constraint_type
lay::angle_constraint_type
Service::move_ac () const
{
// m_alt_ac (which is set from mouse buttons) can override the specified move angle constraint
@ -290,11 +297,23 @@ Service::snap2 (const db::DPoint &p) const
return snap2_details (p).snapped_point;
}
lay::PointSnapToObjectResult
Service::snap2_details (const db::DPoint &p, const db::DPoint &plast, lay::angle_constraint_type ac) const
{
double snap_range = ui ()->mouse_event_trans ().inverted ().ctrans (lay::snap_range_pixels ());
return lay::obj_snap (m_snap_to_objects ? view () : 0, plast, p, m_edit_grid == db::DVector () ? m_global_grid : m_edit_grid, ac, snap_range);
}
lay::PointSnapToObjectResult
Service::snap2_details (const db::DPoint &p, const db::DPoint &plast, bool connect) const
{
return snap2_details (p, plast, connect ? connect_ac () : move_ac ());
}
db::DPoint
Service::snap2 (const db::DPoint &p, const db::DPoint &plast, bool connect) const
{
double snap_range = ui ()->mouse_event_trans ().inverted ().ctrans (lay::snap_range_pixels ());
return lay::obj_snap (m_snap_to_objects ? view () : 0, plast, p, m_edit_grid == db::DVector () ? m_global_grid : m_edit_grid, connect ? connect_ac () : move_ac (), snap_range).snapped_point;
return snap2_details (p, plast, connect ? connect_ac () : move_ac ()).snapped_point;
}
void
@ -544,15 +563,20 @@ void
Service::move (const db::DPoint &pu, lay::angle_constraint_type ac)
{
m_alt_ac = ac;
if (view ()->is_editable () && m_moving) {
db::DPoint ref = snap (m_move_start);
bool snapped = false;
db::DPoint p = ref + snap_marker_to_grid (pu - m_move_start, snapped);
if (! snapped) {
p = ref + snap (pu - m_move_start, false /*move*/);
}
move_markers (db::DTrans (p - db::DPoint ()) * db::DTrans (m_move_trans.fp_trans ()) * db::DTrans (db::DPoint () - ref));
}
m_alt_ac = lay::AC_Global;
}
@ -560,28 +584,46 @@ void
Service::move_transform (const db::DPoint &pu, db::DFTrans tr, lay::angle_constraint_type ac)
{
m_alt_ac = ac;
if (view ()->is_editable () && m_moving) {
db::DPoint ref = snap (m_move_start);
bool snapped = false;
db::DPoint p = ref + snap_marker_to_grid (pu - m_move_start, snapped);
if (! snapped) {
p = ref + snap (pu - m_move_start, false /*move*/);
}
move_markers (db::DTrans (p - db::DPoint ()) * db::DTrans (tr * m_move_trans.fp_trans ()) * db::DTrans (db::DPoint () - ref));
}
m_alt_ac = lay::AC_Global;
}
void
Service::end_move (const db::DPoint & /*p*/, lay::angle_constraint_type ac)
void
Service::end_move (const db::DVector &v)
{
if (view ()->is_editable () && m_moving) {
transform (db::DCplxTrans (db::DTrans (v) * db::DTrans (m_move_trans.fp_trans ())));
move_cancel (); // formally this functionality fits here
// accept changes to guiding shapes
handle_guiding_shape_changes (true);
}
m_alt_ac = lay::AC_Global;
}
void
Service::end_move (const db::DPoint & /*p*/, lay::angle_constraint_type /*ac*/)
{
m_alt_ac = ac;
if (view ()->is_editable () && m_moving) {
transform (db::DCplxTrans (m_move_trans));
move_cancel (); // formally this functionality fits here
// accept changes to guiding shapes
handle_guiding_shape_changes (true);
}
m_alt_ac = lay::AC_Global;
}
@ -860,6 +902,7 @@ bool
Service::mouse_move_event (const db::DPoint &p, unsigned int buttons, bool prio)
{
m_mouse_pos = p;
m_mouse_buttons = buttons;
if (view ()->is_editable () && prio) {
@ -896,6 +939,9 @@ Service::mouse_move_event (const db::DPoint &p, unsigned int buttons, bool prio)
bool
Service::mouse_press_event (const db::DPoint &p, unsigned int buttons, bool prio)
{
m_mouse_pos = p;
m_mouse_buttons = buttons;
if (view ()->is_editable () && prio) {
if ((buttons & lay::LeftButton) != 0) {
@ -910,9 +956,7 @@ Service::mouse_press_event (const db::DPoint &p, unsigned int buttons, bool prio
} else {
if (do_mouse_click (p)) {
m_editing = false;
set_edit_marker (0);
do_finish_edit ();
finish_editing (false);
}
}
@ -942,14 +986,14 @@ Service::enter_event (bool /*prio*/)
}
bool
Service::mouse_double_click_event (const db::DPoint & /*p*/, unsigned int buttons, bool prio)
Service::mouse_double_click_event (const db::DPoint &p, unsigned int buttons, bool prio)
{
m_mouse_pos = p;
m_mouse_buttons = buttons;
if (m_editing && prio && (buttons & lay::LeftButton) != 0) {
m_alt_ac = lay::ac_from_buttons (buttons);
do_finish_edit ();
m_editing = false;
set_edit_marker (0);
m_alt_ac = lay::AC_Global;
finish_editing (false);
return true;
} else {
return false;
@ -959,6 +1003,9 @@ Service::mouse_double_click_event (const db::DPoint & /*p*/, unsigned int button
bool
Service::mouse_click_event (const db::DPoint &p, unsigned int buttons, bool prio)
{
m_mouse_pos = p;
m_mouse_buttons = buttons;
if (view ()->is_editable () && prio && (buttons & lay::RightButton) != 0 && m_editing) {
m_alt_ac = lay::ac_from_buttons (buttons);
do_mouse_transform (p, db::DFTrans (db::DFTrans::r90));
@ -975,11 +1022,26 @@ Service::key_event (unsigned int key, unsigned int buttons)
if (view ()->is_editable () && m_editing && buttons == 0 && key == lay::KeyBackspace) {
do_delete ();
return true;
} else if (view ()->is_editable () && m_editing && buttons == 0 && (key == lay::KeyEnter || key == lay::KeyReturn)) {
m_alt_ac = lay::AC_Global;
finish_editing (true);
return true;
} else {
return false;
}
}
void
Service::finish_editing (bool accept)
{
do_finish_edit (accept);
m_editing = false;
show_toolbox (false);
set_edit_marker (0);
m_alt_ac = lay::AC_Global;
}
void
Service::activated ()
{
@ -1682,16 +1744,11 @@ Service::select (const lay::ObjectInstPath &obj, lay::Editable::SelectionMode mo
void
Service::move_markers (const db::DTrans &t)
{
if (m_move_trans != t) {
if (has_selection ()) {
propose_move_transformation (t, 0);
}
// display current move vector
if (has_selection ()) {
std::string pos = std::string ("dx: ") + tl::micron_to_string (t.disp ().x ()) + " dy: " + tl::micron_to_string (t.disp ().y ());
if (t.rot () != 0) {
pos += std::string (" ") + ((const db::DFTrans &) t).to_string ();
}
view ()->message (pos);
}
if (m_move_trans != t) {
for (auto r = m_markers.begin (); r != m_markers.end (); ++r) {
@ -1712,6 +1769,7 @@ void
Service::begin_edit (const db::DPoint &p)
{
do_begin_edit (p);
show_toolbox (true);
m_editing = true;
}
@ -2005,18 +2063,44 @@ Service::handle_guiding_shape_changes (bool commit)
void
Service::commit_recent ()
{
#if defined(HAVE_QT)
lay::EditorOptionsPages *eo_pages = view ()->editor_options_pages ();
if (!eo_pages) {
lay::EditorOptionsPageCollection *eo_pages = view ()->editor_options_pages ();
if (! eo_pages) {
return;
}
for (std::vector<lay::EditorOptionsPage *>::const_iterator op = eo_pages->pages ().begin (); op != eo_pages->pages ().end (); ++op) {
if ((*op)->plugin_declaration () == plugin_declaration ()) {
auto pages = eo_pages->editor_options_pages ();
for (auto op = pages.begin (); op != pages.end (); ++op) {
if ((*op)->for_plugin_declaration (plugin_declaration ())) {
(*op)->commit_recent (view ());
}
}
#endif
}
void
Service::show_toolbox (bool visible)
{
auto p = toolbox_widget ();
if (p) {
p->set_visible (visible);
}
}
lay::EditorOptionsPage *
Service::toolbox_widget ()
{
lay::EditorOptionsPageCollection *eo_pages = view ()->editor_options_pages ();
if (! eo_pages) {
return 0;
}
auto pages = eo_pages->editor_options_pages (plugin_declaration ());
for (auto op = pages.begin (); op != pages.end (); ++op) {
if ((*op)->is_toolbox_widget ()) {
return *op;
}
}
return 0;
}
// -------------------------------------------------------------

View File

@ -190,6 +190,11 @@ public:
*/
virtual void end_move (const db::DPoint &p, lay::angle_constraint_type ac);
/**
* @brief Terminate a "move" operation with compulsory move vector
*/
virtual void end_move (const db::DVector &v);
/**
* @brief Indicates whether objects are selected
*/
@ -513,9 +518,12 @@ protected:
/**
* @brief Reimplemented by the specific implementation of the shape editors
*
* This method is called when the object is finished
* This method is called when the object is finished.
*
* 'accept' is set to true if triggered by the Enter/Return key, false if triggered by a mouse click.
* In the latter case, first the mouse click is delivered and then "do_finish_edit" is called.
*/
virtual void do_finish_edit () { }
virtual void do_finish_edit (bool /*accept*/) { }
/**
* @brief Reimplemented by the specific implementation of the shape editors
@ -611,6 +619,7 @@ protected:
db::DPoint snap2 (const db::DPoint &p, const db::DPoint &plast, bool connect = true) const;
protected:
lay::angle_constraint_type alt_ac () const;
lay::angle_constraint_type connect_ac () const;
lay::angle_constraint_type move_ac () const;
@ -644,16 +653,49 @@ protected:
return m_mouse_pos;
}
int mouse_buttons () const
{
return m_mouse_buttons;
}
/**
* @brief Commits the current configuration to the recent attributes list
*/
void commit_recent ();
/**
* @brief Shows the toolbox widget in case one is registered for this plugin
*/
void show_toolbox (bool visible);
/**
* @brief Finishes the edit operation
*
* Calls do_finish_edit() and terminates the editing operation.
* See "do_finish_edit" for an explanation of the "accept" parameter.
*/
void finish_editing (bool accept);
/**
* @brief Gets the toolbox widget or 0 if none is registered
*/
lay::EditorOptionsPage *toolbox_widget ();
/**
* @brief Point snapping with detailed return value
*/
lay::PointSnapToObjectResult snap2_details (const db::DPoint &p) const;
/**
* @brief Point snapping with detailed return value
*/
lay::PointSnapToObjectResult snap2_details (const db::DPoint &p, const db::DPoint &plast, bool connect) const;
/**
* @brief Point snapping with detailed return value and specific angle constraint
*/
lay::PointSnapToObjectResult snap2_details (const db::DPoint &p, const db::DPoint &plast, lay::angle_constraint_type ac) const;
private:
friend class EditableSelectionIterator;
@ -669,9 +711,12 @@ private:
// The marker representing the object to be edited
std::vector<lay::ViewObject *> m_edit_markers;
// The last mouse position
// The last mouse position of the current mouse move/press/click event
db::DPoint m_mouse_pos;
// The buttons flag of the current mouse move/press/click event
int m_mouse_buttons;
// A flag indicating whether the mouse is inside the view
bool m_mouse_in_view;

View File

@ -25,21 +25,23 @@
#include "edtPathService.h"
#include "edtPropertiesPages.h"
#include "layLayoutView.h"
#include "layEditorOptionsPage.h"
#include "dbEdgeProcessor.h"
#include "dbPolygonTools.h"
#if defined(HAVE_QT)
# include "layTipDialog.h"
# include "layTipDialog.h"
#endif
#include "layEditorOptionsPages.h"
namespace edt
{
// -----------------------------------------------------------------------------
// ShapeEditService implementation
const char *ShapeEditService::connection_configure_name () { return "connection-toolkit-widget-value"; }
const char *ShapeEditService::connection_function_name () { return "connection-toolkit-widget-commit"; }
ShapeEditService::ShapeEditService (db::Manager *manager, lay::LayoutViewBase *view, db::ShapeIterator::flags_type shape_types)
: edt::Service (manager, view, shape_types),
m_layer (0), m_cv_index (0), mp_cell (0), mp_layout (0), m_combine_mode (CM_Add), m_update_edit_layer_enabled (true)
@ -76,21 +78,19 @@ ShapeEditService::config_recent_for_layer (const db::LayerProperties &lp, int cv
return;
}
#if defined(HAVE_QT)
lay::EditorOptionsPages *eo_pages = view ()->editor_options_pages ();
if (!eo_pages) {
lay::EditorOptionsPageCollection *eo_pages = view ()->editor_options_pages ();
if (! eo_pages) {
return;
}
for (std::vector<lay::EditorOptionsPage *>::const_iterator op = eo_pages->pages ().begin (); op != eo_pages->pages ().end (); ++op) {
if ((*op)->plugin_declaration () == plugin_declaration ()) {
auto pages = eo_pages->editor_options_pages ();
for (auto op = pages.begin (); op != pages.end (); ++op) {
if ((*op)->for_plugin_declaration (plugin_declaration ())) {
(*op)->config_recent_for_layer (dispatcher (), lp, cv_index);
}
}
#endif
}
void
ShapeEditService::get_edit_layer ()
{

View File

@ -37,6 +37,9 @@ class ShapeEditService
: public edt::Service
{
public:
static const char *connection_configure_name ();
static const char *connection_function_name ();
ShapeEditService (db::Manager *manager, lay::LayoutViewBase *view, db::ShapeIterator::flags_type shape_types);
protected:

View File

@ -25,6 +25,7 @@
#include "layLayoutViewBase.h"
#include "layConverters.h"
#include "layEditorOptionsPage.h"
#if defined(HAVE_QT)
# include "edtPropertiesPages.h"
@ -155,7 +156,7 @@ TextService::get_text () const
}
void
TextService::do_finish_edit ()
TextService::do_finish_edit (bool /*accept*/)
{
{
db::Transaction transaction (manager (), tl::to_string (tr ("Create text")));
@ -199,6 +200,11 @@ TextService::selection_applies (const lay::ObjectInstPath &sel) const
bool
TextService::configure (const std::string &name, const std::string &value)
{
auto tb = toolbox_widget ();
if (tb) {
tb->configure (name, value);
}
if (name == cfg_edit_text_size) {
double size (0);
tl::from_string (value, size);

View File

@ -47,7 +47,7 @@ public:
virtual void do_mouse_move (const db::DPoint &p);
virtual void do_mouse_move_inactive (const db::DPoint &p);
virtual bool do_mouse_click (const db::DPoint &p);
virtual void do_finish_edit ();
virtual void do_finish_edit (bool);
virtual void do_cancel_edit ();
virtual bool do_activated ();
virtual bool selection_applies (const lay::ObjectInstPath &sel) const;

View File

@ -203,13 +203,29 @@ public:
}
/**
* @brief Iterates all subclasses (end)
* @brief Iterates all child classes (end)
*/
tl::weak_collection<ClassBase>::const_iterator end_child_classes () const
{
return m_child_classes.end ();
}
/**
* @brief Iterates all subclasses (begin)
*/
tl::weak_collection<ClassBase>::const_iterator begin_subclasses () const
{
return m_subclasses.begin ();
}
/**
* @brief Iterates all subclasses (end)
*/
tl::weak_collection<ClassBase>::const_iterator end_subclasses () const
{
return m_subclasses.end ();
}
/**
* @brief Iterates all classes present (begin)
*/

View File

@ -553,8 +553,12 @@ VariantUserClassImpl::execute (const tl::ExpressionParserContext &context, tl::V
bool ret = false;
if (args [0].is_user ()) {
const tl::VariantUserClassBase *ub = args [0].user_cls ();
if (ub && ub->gsi_cls () == mp_cls) {
ret = true;
if (ub) {
const gsi::ClassBase *ub_gsi = ub->gsi_cls ();
const gsi::ClassBase *cls = mp_cls;
while (cls && ! (ret = (ub_gsi == cls))) {
cls = cls->base ();
}
}
}

View File

@ -898,3 +898,19 @@ TEST(17)
"it.add_value(17.5)").execute ();
}
// is_a
TEST(18)
{
tl::Eval e;
tl::Variant v;
v = e.parse ("var b=B.new(); b.is_a(C)").execute ();
EXPECT_EQ (v.to_string (), std::string ("false"));
v = e.parse ("var x=X.new(); x.is_a(X)").execute ();
EXPECT_EQ (v.to_string (), std::string ("true"));
// Y is not a base class of X
v = e.parse ("var x=X.new(); x.is_a(Y)").execute ();
EXPECT_EQ (v.to_string (), std::string ("false"));
// X is a base class of Y
v = e.parse ("var y=Y.new(); y.is_a(X)").execute ();
EXPECT_EQ (v.to_string (), std::string ("true"));
}

View File

@ -62,6 +62,15 @@ PluginDeclaration::get_options (std::vector < std::pair<std::string, std::string
options.push_back (std::pair<std::string, std::string> (cfg_images_visible, "true"));
}
std::vector<std::string>
PluginDeclaration::additional_editor_options_pages () const
{
std::vector<std::string> names;
// TODO: provide in a central place instead of borrowing from the edt module
names.push_back ("GenericEditorOptions");
return names;
}
static tl::RegisteredClass<lay::PluginDeclaration> config_decl (new img::PluginDeclaration (), 4000, "img::Plugin");
}

View File

@ -39,6 +39,7 @@ public:
virtual lay::Plugin *create_plugin (db::Manager *manager, lay::Dispatcher *, lay::LayoutViewBase *view) const;
virtual bool implements_editable (std::string &title) const;
virtual void get_options (std::vector < std::pair<std::string, std::string> > &options) const;
virtual std::vector<std::string> additional_editor_options_pages () const;
};
}

View File

@ -419,6 +419,7 @@ Service::Service (db::Manager *manager, lay::LayoutViewBase *view)
mp_transient_view (0),
m_move_mode (Service::move_none),
m_moved_landmark (0),
m_ac (lay::AC_Global),
m_keep_selection_for_move (false),
m_images_visible (true),
m_visibility_cache_valid (false)
@ -608,12 +609,14 @@ Service::begin_move (lay::Editable::MoveMode mode, const db::DPoint &p, lay::ang
double l = catch_distance ();
db::DBox search_dbox = db::DBox (p, p).enlarged (db::DVector (l, l));
m_plast = m_p1 = p;
m_trans = db::DTrans ();
m_ac = lay::AC_Global;
// choose move mode
if (mode == lay::Editable::Selected) {
m_move_mode = move_selected;
m_p1 = p;
m_trans = db::DTrans ();
selection_to_view ();
for (std::vector <img::View *>::iterator r = m_selected_image_views.begin (); r != m_selected_image_views.end (); ++r) {
@ -657,7 +660,6 @@ Service::begin_move (lay::Editable::MoveMode mode, const db::DPoint &p, lay::ang
} else if (mode == lay::Editable::Any) {
m_move_mode = move_none;
m_p1 = p;
double dmin = std::numeric_limits <double>::max ();
const db::DUserObject *robj = find_image (p, search_dbox, l, dmin);
@ -705,11 +707,14 @@ Service::move_transform (const db::DPoint &p, db::DFTrans tr, lay::angle_constra
return;
}
db::DTrans tr_new = db::DTrans (p - db::DPoint ()) * db::DTrans (tr) * db::DTrans (m_trans.fp_trans ()) * db::DTrans (db::DPoint () - m_p1);
if (m_move_mode == move_all) {
db::DVector dp = p - db::DPoint ();
db::DTrans dt = tr_new * m_trans.inverted ();
m_current.transform (db::DTrans (dp) * db::DTrans (tr) * db::DTrans (-dp));
m_current.transform (dt);
m_trans = dt * m_trans;
// display current images' parameters
show_message ();
@ -718,7 +723,7 @@ Service::move_transform (const db::DPoint &p, db::DFTrans tr, lay::angle_constra
} else if (m_move_mode == move_selected) {
m_trans *= db::DTrans (m_p1 - db::DPoint ()) * db::DTrans (tr) * db::DTrans (db::DPoint () - m_p1);
m_trans = tr_new;
for (std::vector<img::View *>::iterator r = m_selected_image_views.begin (); r != m_selected_image_views.end (); ++r) {
(*r)->transform_by (db::DCplxTrans (m_trans));
@ -734,10 +739,25 @@ Service::move (const db::DPoint &p, lay::angle_constraint_type ac)
return;
}
m_ac = ac;
do_move (p, ac);
if (m_move_mode != move_selected) {
m_selected_image_views [0]->redraw ();
show_message ();
}
propose_move_transformation (m_trans, 2);
}
void
Service::do_move (const db::DPoint &p, lay::angle_constraint_type ac)
{
if (m_move_mode == move_selected) {
db::DVector dp = p - m_p1;
m_p1 = p;
db::DVector dp = p - m_plast;
m_plast = p;
m_trans = db::DTrans (dp) * m_trans;
@ -747,6 +767,8 @@ Service::move (const db::DPoint &p, lay::angle_constraint_type ac)
} else if (m_move_mode == move_landmark) {
m_trans = db::DTrans (p - m_p1);
std::vector <db::DPoint> li = m_initial.landmarks ();
for (std::vector <db::DPoint>::iterator l = li.begin (); l != li.end (); ++l) {
*l = m_initial.matrix ().trans (*l);
@ -770,20 +792,20 @@ Service::move (const db::DPoint &p, lay::angle_constraint_type ac)
db::adjust_matrix (m, li, lm, adjust, int (m_moved_landmark));
m_current.set_matrix (m * m_initial.matrix ());
m_selected_image_views [0]->redraw ();
} else {
if (m_move_mode == move_all) {
db::DVector dp = p - m_p1;
m_p1 = p;
db::DVector dp = p - m_plast;
m_plast = p;
m_trans = db::DTrans (dp) * m_trans;
m_current.transform (db::DTrans (dp));
} else {
m_current = m_initial;
m_trans = db::DTrans (p - m_p1);
db::DVector dx (0.5 * m_current.width (), 0.5 * m_current.height ());
db::Matrix3d it = (m_current.matrix () * db::Matrix3d::disp (-dx)).inverted ();
@ -847,15 +869,6 @@ Service::move (const db::DPoint &p, lay::angle_constraint_type ac)
}
// display current images' parameters
show_message ();
m_selected_image_views [0]->redraw ();
}
if (m_move_mode != move_selected) {
show_message ();
}
}
@ -871,7 +884,14 @@ Service::show_message ()
*/
}
void
void
Service::end_move (const db::DVector &v)
{
do_move (m_p1 + v, m_ac);
end_move (db::DPoint (), lay::AC_Any);
}
void
Service::end_move (const db::DPoint &, lay::angle_constraint_type)
{
if (! m_selected_image_views.empty () && ! m_selected.empty ()) {

View File

@ -359,6 +359,11 @@ public:
*/
virtual void end_move (const db::DPoint &p, lay::angle_constraint_type ac);
/**
* @brief Terminate a "move" operation with compulsory move vector
*/
virtual void end_move (const db::DVector &v);
/**
* @brief Return the bbox of the selection (reimplementation of lay::Editable interface)
*/
@ -500,8 +505,10 @@ private:
std::set<obj_iterator> m_selected;
// The previous selection
std::set<obj_iterator> m_previous_selection;
// The reference point in move mode
// The starting point in move mode
db::DPoint m_p1;
// The last reference point in move mode
db::DPoint m_plast;
// The image object representing the image being moved as it was before it was moved
img::Object m_initial;
// The image object representing the image being moved
@ -514,6 +521,8 @@ private:
MoveMode m_move_mode;
// The index of the landmark being moved
size_t m_moved_landmark;
// The last "angle constraint" (button combination) used in move
lay::angle_constraint_type m_ac;
// Flag indicating that we want to keep the selection after the landmark was moved
bool m_keep_selection_for_move;
// Flag indicating whether images are visible
@ -523,6 +532,8 @@ private:
std::map<const img::Object *, bool> m_visibility_cache;
void show_message ();
void do_move (const db::DPoint &p, lay::angle_constraint_type ac);
/**
* @brief Select a certain image

View File

@ -993,7 +993,11 @@ GSIHelpProvider::produce_class_doc (const std::string &cls) const
<< "<!DOCTYPE language SYSTEM \"klayout_doc.dtd\">" << std::endl
<< std::endl;
os << "<doc><title>" << tl::to_string (QObject::tr ("API reference - Class")) << " " << escape_xml (cls) << "</title>" << std::endl;
os << "<doc><title>" << tl::to_string (QObject::tr ("API reference - Class")) << " " << escape_xml (cls);
if (class_doc.hidden) {
os << " " << tl::to_string (QObject::tr ("[internal]"));
}
os << "</title>" << std::endl;
os << "<property name=\"module\" value=\"" << escape_xml (cls_obj->module ()) << "\"/>" << std::endl;
os << "<keyword name=\"" << escape_xml (cls) << "\"/>" << std::endl;
@ -1006,13 +1010,15 @@ GSIHelpProvider::produce_class_doc (const std::string &cls) const
os << "<p><b>" << tl::to_string (QObject::tr ("Description")) << "</b>: " << escape_xml (class_doc.brief_doc) << "</p>" << std::endl;
std::vector<const gsi::ClassBase *> classes;
classes.push_back (real_class (cls_obj));
const gsi::ClassBase *act_cls_obj = real_class (cls_obj);
const gsi::ClassBase *base = real_class (cls_obj)->base ();
std::vector<const gsi::ClassBase *> classes;
classes.push_back (act_cls_obj);
const gsi::ClassBase *base = act_cls_obj->base ();
if (base) {
const gsi::ClassBase *last_cls = real_class (cls_obj);
const gsi::ClassBase *last_cls = act_cls_obj;
bool all_collected = false;
os << "<p><b>" << tl::to_string (QObject::tr ("Class hierarchy")) << "</b>: " << make_qualified_name (cls_obj);
@ -1032,6 +1038,7 @@ GSIHelpProvider::produce_class_doc (const std::string &cls) const
all_collected = true;
} else if (! all_collected) {
// class needs to be mixed into the parent
os << " &#187; <a href=\"" << escape_xml (class_doc_url (base->name ())) << "\">" << escape_xml (base->name ()) << " " << tl::to_string (QObject::tr ("[internal]")) << "</a>";
classes.push_back (base);
}
@ -1051,34 +1058,90 @@ GSIHelpProvider::produce_class_doc (const std::string &cls) const
os << "</p>" << std::endl;
}
// Produce child classes
bool any = false;
for (std::vector<const gsi::ClassBase *>::const_iterator c = classes.begin (); c != classes.end (); ++c) {
for (tl::weak_collection<gsi::ClassBase>::const_iterator cc = (*c)->begin_child_classes (); cc != (*c)->end_child_classes (); ++cc) {
DocumentationParser &cdoc = cls_documentation (cc.operator-> ());
if (! cdoc.hidden || ! cdoc.alias.empty ()) {
if (any) {
os << ", ";
} else {
os << "<p><b>" << tl::to_string (QObject::tr ("Sub-classes")) << "</b>: ";
any = true;
}
os << "<a href=\"" << escape_xml (class_doc_url (make_qualified_name (cc.operator-> ()))) << "\">" << escape_xml (cc->name ()) << "</a>";
if (any) {
os << ", ";
} else {
os << "<p><b>" << tl::to_string (QObject::tr ("Child classes")) << "</b>: ";
any = true;
}
os << "<a href=\""
<< escape_xml (class_doc_url (make_qualified_name (cc.operator-> ())))
<< "\">"
<< escape_xml (cc->name ());
if (cdoc.hidden && cdoc.alias.empty ()) {
os << " " << tl::to_string (QObject::tr ("[internal]"));
}
os << "</a>";
}
}
if (any) {
os << "</p>" << std::endl;
}
// Produce subclasses (parent classes)
any = false;
for (tl::weak_collection<gsi::ClassBase>::const_iterator cc = act_cls_obj->begin_subclasses (); cc != act_cls_obj->end_subclasses (); ++cc) {
DocumentationParser &cdoc = cls_documentation (cc.operator-> ());
if (any) {
os << ", ";
} else {
os << "<p><b>" << tl::to_string (QObject::tr ("Subclasses")) << "</b>: ";
any = true;
}
os << "<a href=\""
<< escape_xml (class_doc_url (make_qualified_name (cc.operator-> ())))
<< "\">"
<< escape_xml (cc->name ());
if (cdoc.hidden && cdoc.alias.empty ()) {
os << " " << tl::to_string (QObject::tr ("[internal]"));
}
os << "</a>";
}
if (any) {
os << "</p>" << std::endl;
}
// Inserts an index
os << "<h2-index/>" << std::endl;
// Produce class doc body
if (class_doc.hidden && class_doc.alias.empty ()) {
os << "<p><b>"
<< tl::to_string (QObject::tr ("Note"))
<< "</b>: "
<< tl::to_string (QObject::tr (
"This class is an internal class provided for technical reasons - i.e. "
"as a placeholder class for argument binding or as an abstract interface. "
"You should not instantiate objects of this class directly. "
"Instead, use the subclasses listed above. "
"Also see there for more documentation and actual incarnations of this class."
))
<< "</p>" << std::endl;
}
os << replace_references (class_doc.doc_html (), cls_obj) << std::endl;
// collect the methods of the class and their hidden base classes
@ -1116,6 +1179,8 @@ GSIHelpProvider::produce_class_doc (const std::string &cls) const
os << "</doc>" << std::endl;
return os.str ();
}
// Produce methods brief descriptions
int n = 0;
int row = 0;
@ -1190,6 +1255,8 @@ GSIHelpProvider::produce_class_doc (const std::string &cls) const
os << "</table>" << std::endl;
}
// Produce static methods brief descriptions
any = false;
n = 0;
@ -1230,6 +1297,8 @@ GSIHelpProvider::produce_class_doc (const std::string &cls) const
os << "</table>" << std::endl;
}
// Produce protected methods brief descriptions
any = false;
n = 0;
@ -1272,6 +1341,8 @@ GSIHelpProvider::produce_class_doc (const std::string &cls) const
os << "</table>" << std::endl;
}
// Produce deprecated methods brief descriptions
any = false;
n = 0;
@ -1323,6 +1394,8 @@ GSIHelpProvider::produce_class_doc (const std::string &cls) const
os << "</table>" << std::endl;
}
// Produce method details
n = 0;
os << "<a name=\"detailed\"/><h2>" << tl::to_string (QObject::tr ("Detailed description")) << "</h2>" << std::endl;

View File

@ -1722,7 +1722,7 @@ MainWindow::update_editor_options_dock ()
eo_visible = pd_sel->editable_enabled ();
}
if (current_view () && eo_visible) {
lay::EditorOptionsPages *eo_pages = current_view ()->editor_options_pages ();
lay::EditorOptionsPageCollection *eo_pages = current_view ()->editor_options_pages ();
if (! eo_pages || ! eo_pages->has_content ()) {
eo_visible = false;
}

View File

@ -41,13 +41,13 @@ static lay::Dispatcher *dispatcher_instance ()
return lay::Dispatcher::instance ();
}
static tl::Variant get_config (lay::Dispatcher *dispatcher, const std::string &name)
static tl::Variant get_config (lay::Dispatcher *dispatcher, const std::string &name, const tl::Variant &default_value)
{
std::string value;
if (dispatcher->config_get (name, value)) {
return tl::Variant (value);
} else {
return tl::Variant ();
return default_value;
}
}
@ -86,12 +86,14 @@ Class<lay::Dispatcher> decl_Dispatcher ("lay", "Dispatcher",
"exist. If it does and an error occurred, the error message is printed\n"
"on stderr. In both cases, false is returned.\n"
) +
method_ext ("get_config", &get_config, gsi::arg ("name"),
method_ext ("get_config", &get_config, gsi::arg ("name"), gsi::arg ("default", tl::Variant (), "nil"),
"@brief Gets the value of a local configuration parameter\n"
"\n"
"@param name The name of the configuration parameter whose value shall be obtained (a string)\n"
"\n"
"@return The value of the parameter or nil if there is no such parameter\n"
"@return The value of the parameter or the default value if there is no such parameter\n"
"\n"
"The default value has been added in version 0.30.6."
) +
method ("set_config", (void (lay::Dispatcher::*) (const std::string &, const std::string &)) &lay::Dispatcher::config_set, gsi::arg ("name"), gsi::arg ("value"),
"@brief Set a local configuration parameter with the given name to the given value\n"

View File

@ -1,198 +0,0 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2025 Matthias Koefferlein
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if defined(HAVE_QTBINDINGS)
#include "gsiDeclLayEditorOptionsPage.h"
#include "gsiQtGuiExternals.h"
#include "gsiQtWidgetsExternals.h" // for Qt5
namespace gsi
{
Class<lay::EditorOptionsPage> decl_EditorOptionsPageBase (QT_EXTERNAL_BASE (QWidget) "lay", "EditorOptionsPageBase",
method ("view", &lay::EditorOptionsPage::view,
"@brief Gets the view object this page is associated with\n"
) +
method ("title", &lay::EditorOptionsPage::title,
"@brief Gets the title string of the page\n"
) +
method ("order", &lay::EditorOptionsPage::order,
"@brief Gets the order index of the page\n"
) +
method ("is_focus_page?", &lay::EditorOptionsPage::is_focus_page,
"@brief Gets a flag indicating whether the page is a focus page\n"
"See \\focus_page= for a description is this attribute.\n"
) +
method ("focus_page=", &lay::EditorOptionsPage::set_focus_page, gsi::arg ("flag"),
"@brief Sets a flag indicating whether the page is a focus page\n"
"The focus page is the page that is selected when the tab key is pressed during some plugin action.\n"
) +
method ("is_modal_page?", &lay::EditorOptionsPage::is_modal_page,
"@brief Gets a flag indicating whether the page is a modal page\n"
"See \\modal_page= for a description is this attribute.\n"
) +
method ("modal_page=", &lay::EditorOptionsPage::set_modal_page, gsi::arg ("flag"),
"@brief Sets a flag indicating whether the page is a modal page\n"
"A modal page is shown in a modal dialog upon \\show. Non-modal pages are shown in the "
"editor options dock.\n"
) +
method ("show", &lay::EditorOptionsPage::show,
"@brief Shows the page\n"
"@return A value indicating whether the page was opened non-modal (-1), accepted (1) or rejected (0)\n"
"Provided the page is selected because the plugin is active, this method will "
"open a dialog to show the page if it is modal, or locate the page in the editor options "
"dock and bring it to the front if it is non-modal.\n"
"\n"
"Before the page is shown, \\setup is called. When the page is dismissed (accepted), \\apply is called. "
"You can overload these methods to transfer data to and from the configuration space or to perform other "
"actions, not related to configuration parameters."
) +
method ("apply", &lay::EditorOptionsPage::apply, gsi::arg ("dispatcher"),
"@brief Transfers data from the page to the configuration\n"
) +
method ("setup", &lay::EditorOptionsPage::setup, gsi::arg ("dispatcher"),
"@brief Transfers data from the configuration to the page\n"
),
"@brief The plugin framework's editor options page base class\n"
"\n"
"This class is provided as an interface to the base class implementation for various functions.\n"
"You can use these methods in order to pass down events to the original implementation or access\n"
"objects not created in script space.\n"
"\n"
"It features some useful methods such as 'view' and provides a slot to call for triggering a data "
"transfer ('edited').\n"
"\n"
"Note that even though the page class is derived from QWidget, you can call QWidget methods "
"but not overload virtual methods from QWidget.\n"
"\n"
"This class has been introduced in version 0.30.4.\n"
);
EditorOptionsPageImpl::EditorOptionsPageImpl (const std::string &title, int index)
: lay::EditorOptionsPage (), m_title (title), m_index (index)
{
// .. nothing yet ..
}
void
EditorOptionsPageImpl::call_edited ()
{
lay::EditorOptionsPage::edited ();
}
static void apply_fb (EditorOptionsPageImpl *ep, lay::Dispatcher *root)
{
ep->lay::EditorOptionsPage::apply (root);
}
static void setup_fb (EditorOptionsPageImpl *ep, lay::Dispatcher *root)
{
ep->lay::EditorOptionsPage::setup (root);
}
void
EditorOptionsPageImpl::apply_impl (lay::Dispatcher *root)
{
lay::EditorOptionsPage::apply (root);
}
void
EditorOptionsPageImpl::apply (lay::Dispatcher *root)
{
if (f_apply.can_issue ()) {
f_apply.issue<EditorOptionsPageImpl, lay::Dispatcher *> (&EditorOptionsPageImpl::apply_impl, root);
} else {
EditorOptionsPageImpl::apply_impl (root);
}
}
void
EditorOptionsPageImpl::setup_impl (lay::Dispatcher *root)
{
lay::EditorOptionsPage::setup (root);
}
void
EditorOptionsPageImpl::setup (lay::Dispatcher *root)
{
if (f_setup.can_issue ()) {
f_setup.issue<EditorOptionsPageImpl, lay::Dispatcher *> (&EditorOptionsPageImpl::setup_impl, root);
} else {
EditorOptionsPageImpl::setup_impl (root);
}
}
EditorOptionsPageImpl *new_editor_options_page (const std::string &title, int index)
{
return new EditorOptionsPageImpl (title, index);
}
Class<EditorOptionsPageImpl> decl_EditorOptionsPage (decl_EditorOptionsPageBase, "lay", "EditorOptionsPage",
constructor ("new", &new_editor_options_page, gsi::arg ("title"), gsi::arg ("index"),
"@brief Creates a new EditorOptionsPage object\n"
"@param title The title of the page\n"
"@param index The position of the page in the tab bar\n"
) +
method ("edited", &EditorOptionsPageImpl::call_edited,
"@brief Call this method when some entry widget has changed\n"
"When some entry widget (for example 'editingFinished' slot of a QLineEdit), "
"call this method to initiate a transfer of information from the page to the plugin.\n"
) +
// prevents infinite recursion
method_ext ("apply", &apply_fb, gsi::arg ("dispatcher"), "@hide") +
callback ("apply", &EditorOptionsPageImpl::apply, &EditorOptionsPageImpl::f_apply, gsi::arg ("dispatcher"),
"@brief Reimplement this method to transfer data from the page to the configuration\n"
"In this method, you should transfer all widget data into corresponding configuration updates.\n"
"Use \\Dispatcher#set_config on the dispatcher object ('dispatcher' argument) to set a configuration parameter.\n"
) +
// prevents infinite recursion
method_ext ("setup", &setup_fb, gsi::arg ("dispatcher"), "@hide") +
callback ("setup", &EditorOptionsPageImpl::setup, &EditorOptionsPageImpl::f_setup, gsi::arg ("dispatcher"),
"@brief Reimplement this method to transfer data from the configuration to the page\n"
"In this method, you should transfer all configuration data to the widgets.\n"
"Use \\Dispatcher#get_config on the dispatcher object ('dispatcher' argument) to get a configuration parameter "
"and set the editing widget's state accordingly.\n"
),
"@brief The plugin framework's editor options page\n"
"\n"
"This object provides a way to establish plugin-specific editor options pages.\n"
"\n"
"The preferred way of communication between the page and the plugin is through "
"configuration parameters. One advantage of this approach is that the current state is "
"automatically persisted.\n"
"\n"
"For this purpose, the editor options page has two methods: 'apply' which is supposed to transfer "
"the editor widget's state into configuration parameters. 'setup' does the inverse and transfer "
"configuration parameters into editor widget states. Both methods are called by the system when "
"some transfer is needed.\n"
"\n"
"When you want to respond to widget signals and transfer information, call \\edited "
"in the signal slot. This will trigger a transfer (aka 'apply').\n"
"\n"
"This class has been introduced in version 0.30.4.\n"
);
}
#endif

View File

@ -87,8 +87,16 @@ ACConverter::to_string (const lay::angle_constraint_type &m)
return "any";
} else if (m == lay::AC_Diagonal) {
return "diagonal";
} else if (m == lay::AC_DiagonalOnly) {
return "diagonal_only";
} else if (m == lay::AC_Ortho) {
return "ortho";
} else if (m == lay::AC_Horizontal) {
return "horizontal";
} else if (m == lay::AC_Vertical) {
return "vertical";
} else if (m == lay::AC_Global) {
return "global";
} else {
return "";
}
@ -102,8 +110,16 @@ ACConverter::from_string (const std::string &tt, lay::angle_constraint_type &m)
m = lay::AC_Any;
} else if (t == "diagonal") {
m = lay::AC_Diagonal;
} else if (t == "diagonal_only") {
m = lay::AC_DiagonalOnly;
} else if (t == "ortho") {
m = lay::AC_Ortho;
} else if (t == "horizontal") {
m = lay::AC_Horizontal;
} else if (t == "vertical") {
m = lay::AC_Vertical;
} else if (t == "global") {
m = lay::AC_Global;
} else {
m = lay::AC_Any;
}

View File

@ -103,6 +103,14 @@ Dispatcher::config_finalize ()
}
}
void
Dispatcher::function (const std::string &symbol, const std::string &args)
{
if (mp_delegate) {
mp_delegate->function (symbol, args);
}
}
// Writing and Reading of configuration

View File

@ -87,6 +87,14 @@ public:
// .. this implementation does nothing ..
}
/**
* @brief Generic function call
*/
virtual void function (const std::string & /*symbol*/, const std::string & /*args*/)
{
// .. this implementation does nothing ..
}
/**
* @brief Receives configuration events
*/
@ -250,6 +258,7 @@ protected:
// capture the configuration events so we can change the value of the configuration actions
virtual bool configure (const std::string &name, const std::string &value);
virtual void config_finalize ();
virtual void function (const std::string &symbol, const std::string &args);
private:
Dispatcher (const Dispatcher &);

View File

@ -47,7 +47,7 @@ struct first_of_pair_cmp_f
// Editable implementation
Editable::Editable (lay::Editables *editables)
: mp_editables (editables)
: mp_editables (editables), m_move_transformation_priority (-1)
{
if (editables) {
editables->m_editables.push_back (this);
@ -75,6 +75,20 @@ Editable::~Editable ()
}
}
void
Editable::reset_proposed_move_transformation ()
{
m_move_transformation = db::DTrans ();
m_move_transformation_priority = -1;
}
void
Editable::propose_move_transformation (const db::DTrans &t, unsigned int priority)
{
m_move_transformation = t;
m_move_transformation_priority = priority;
}
// ----------------------------------------------------------------
// Editables implementation
@ -490,6 +504,9 @@ Editables::begin_move (const db::DPoint &p, lay::angle_constraint_type ac)
cancel_edits ();
clear_previous_selection ();
m_move_start = p;
m_move_transform = db::DFTrans ();
m_move_selection = false;
m_any_move_operation = false;
@ -567,25 +584,75 @@ Editables::begin_move (const db::DPoint &p, lay::angle_constraint_type ac)
}
}
void
std::pair<int, db::DTrans>
Editables::move (const db::DPoint &p, lay::angle_constraint_type ac)
{
int move_transformation_priority = -1;
db::DTrans move_transformation (p - m_move_start);
move_transformation *= db::DTrans (m_move_transform);
m_any_move_operation = true;
for (iterator e = begin (); e != end (); ++e) {
e->reset_proposed_move_transformation ();
e->move (p, ac);
auto pmv = e->proposed_move_transformation ();
if (move_transformation_priority < 0 || (pmv.first >= 0 && pmv.first <= move_transformation_priority)) {
move_transformation_priority = pmv.first;
move_transformation = pmv.second;
}
}
return std::make_pair (move_transformation_priority, move_transformation);
}
void
Editables::move_transform (const db::DPoint &p, db::DFTrans t, lay::angle_constraint_type ac)
{
m_any_move_operation = true;
m_move_transform *= t;
for (iterator e = begin (); e != end (); ++e) {
e->move_transform (p, t, ac);
}
}
void
void
Editables::end_move (const db::DVector &v, db::Transaction *transaction)
{
std::unique_ptr<db::Transaction> trans_holder (transaction ? transaction : new db::Transaction (manager (), tl::to_string (tr ("Move"))));
if (m_any_move_operation) {
trans_holder->open ();
// this dummy operation will update the screen:
if (manager ()) {
manager ()->queue (this, new db::Op ());
}
for (iterator e = begin (); e != end (); ++e) {
e->end_move (v);
}
// clear the selection that was set previously
if (m_move_selection) {
clear_selection ();
}
} else {
trans_holder->cancel ();
edit_cancel ();
}
}
void
Editables::end_move (const db::DPoint &p, lay::angle_constraint_type ac, db::Transaction *transaction)
{
std::unique_ptr<db::Transaction> trans_holder (transaction ? transaction : new db::Transaction (manager (), tl::to_string (tr ("Move"))));

View File

@ -326,6 +326,16 @@ public:
// .. by default, nothing is implemented ..
}
/**
* @brief Terminate a "move" operation with compulsory shift vector
*
* @param v The move distance to be applied
*/
virtual void end_move (const db::DVector & /*v*/)
{
// .. by default, nothing is implemented ..
}
/**
* @brief Cancel any pending operations
*
@ -405,13 +415,48 @@ public:
}
protected:
friend class lay::Editables;
Editables *editables ()
{
return mp_editables;
}
/**
* @brief Resets the proposed move transformation
*
* You should not need to call this method from an Editable implementation.
*/
void reset_proposed_move_transformation ();
/**
* @brief Proposes a move transformation
*
* On "move", the Editable can propose an actual move transformation that
* may differ from the actual move distance due to implementation-specific
* snapping.
*
* This method proposes a move transformation with a given priority. The
* Editable with the lowest priority value wins.
*/
void propose_move_transformation (const db::DTrans &mv, unsigned int priority);
/**
* @brief Gets the proposed move transformation and priority
*
* @return A pair with (priority, transformation)
*
* The returned priority is negative if not priority was set.
*/
std::pair<int, db::DTrans> proposed_move_transformation () const
{
return std::make_pair (m_move_transformation_priority, m_move_transformation);
}
private:
Editables *mp_editables;
int m_move_transformation_priority;
db::DTrans m_move_transformation;
};
/**
@ -551,8 +596,16 @@ public:
/**
* @brief Continue "move" operation
*
* The return value is the "proposed move transformation", i.e. a representative
* one used for the actual move. As every interface may decide about the
* actual move transformation (due to specific snapping to objects etc.), the
* return value many be ambiguous and should be used for information purposes
* only.
*
* @return A pair (priority, transformation) where priority is negative if no vector was proposed
*/
void move (const db::DPoint &p, lay::angle_constraint_type ac);
std::pair<int, db::DTrans> move (const db::DPoint &p, lay::angle_constraint_type ac);
/**
* @brief Transform during a move operation
@ -567,6 +620,16 @@ public:
*/
void end_move (const db::DPoint &p, lay::angle_constraint_type ac, db::Transaction *transaction = 0);
/**
* @brief End "move" operation with given vector
*
* If a transaction is given, the operation will be appended to this pending transaction
* The Editables object takes ownership over the Transaction object.
*
* The vector is supposed to be taken "as is" and no snapping shall be applied.
*/
void end_move (const db::DVector &v, db::Transaction *transaction = 0);
/**
* @brief Indicates how many objects are selected.
*
@ -678,6 +741,8 @@ private:
tl::shared_collection<lay::Editable> m_editables;
std::set<lay::Editable *> m_enabled;
db::DPoint m_move_start;
db::DFTrans m_move_transform;
bool m_move_selection;
bool m_any_move_operation;
db::DBox m_last_selected_point;

View File

@ -20,31 +20,34 @@
*/
#if defined(HAVE_QT)
#include "tlInternational.h"
#include "layEditorOptionsPage.h"
#include "layEditorOptionsPages.h"
#include "layLayoutViewBase.h"
#include "tlClassRegistry.h"
#include "tlExceptions.h"
#include <QApplication>
#include <QKeyEvent>
namespace lay
{
// ------------------------------------------------------------------
// EditorOptionsPageCollection implementation
EditorOptionsPageCollection::EditorOptionsPageCollection ()
{
// .. nothing yet ..
}
// ------------------------------------------------------------------
// EditorOptionsPage implementation
EditorOptionsPage::EditorOptionsPage (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
: QWidget (0), mp_owner (0), m_active (true), m_focus_page (false), m_modal_page (false), mp_plugin_declaration (0), mp_dispatcher (dispatcher), mp_view (view)
: mp_owner (0), m_active (true), m_focus_page (false), m_modal_page (false), m_toolbox_widget (false), mp_dispatcher (0), mp_view (0)
{
attach_events ();
init (view, dispatcher);
}
EditorOptionsPage::EditorOptionsPage ()
: QWidget (0), mp_owner (0), m_active (true), m_focus_page (false), m_modal_page (false), mp_plugin_declaration (0), mp_dispatcher (0), mp_view (0)
: mp_owner (0), m_active (true), m_focus_page (false), m_modal_page (false), m_toolbox_widget (false), mp_dispatcher (0), mp_view (0)
{
// .. nothing yet ..
}
@ -62,64 +65,18 @@ EditorOptionsPage::init (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
attach_events ();
}
void
EditorOptionsPage::edited ()
{
apply (dispatcher ());
}
static bool is_parent_widget (QWidget *w, QWidget *parent)
{
while (w && w != parent) {
w = dynamic_cast<QWidget *> (w->parent ());
}
return w == parent;
}
bool
EditorOptionsPage::focusNextPrevChild (bool next)
{
bool res = QWidget::focusNextPrevChild (next);
// Stop making the focus leave the page - this way we can jump back to the
// view on "enter"
if (res && ! is_modal_page () && ! is_parent_widget (QApplication::focusWidget (), this) && focusWidget ()) {
focusWidget ()->setFocus ();
}
return res;
}
void
EditorOptionsPage::keyPressEvent (QKeyEvent *event)
{
BEGIN_PROTECTED
if (! is_modal_page () && event->modifiers () == Qt::NoModifier && event->key () == Qt::Key_Return) {
// The Return key on a non-modal page commits the values and gives back the focus
// to the view
apply (dispatcher ());
view ()->set_focus ();
event->accept ();
} else {
QWidget::keyPressEvent (event);
}
END_PROTECTED
}
void
EditorOptionsPage::set_focus ()
{
setFocus (Qt::TabFocusReason);
QWidget::focusNextPrevChild (true);
}
int
EditorOptionsPage::show ()
{
if (mp_owner && m_active) {
if (! m_active) {
return -1;
} else if (m_toolbox_widget) {
set_focus ();
return 1;
} else if (mp_owner) {
if (! is_modal_page ()) {
mp_owner->make_page_current (this);
return -1;
return 1;
} else {
return mp_owner->exec_modal (this) ? 1 : 0;
}
@ -153,7 +110,7 @@ EditorOptionsPage::on_technology_changed ()
}
void
EditorOptionsPage::set_owner (EditorOptionsPages *owner)
EditorOptionsPage::set_owner (EditorOptionsPageCollection *owner)
{
if (mp_owner) {
mp_owner->unregister_page (this);
@ -166,12 +123,16 @@ EditorOptionsPage::activate (bool active)
{
if (m_active != active) {
m_active = active;
if (mp_owner) {
mp_owner->activate_page (this);
if (m_active) {
if (mp_owner) {
mp_owner->activate_page (this);
}
activated ();
} else {
deactivated ();
}
}
}
}
#endif

View File

@ -20,8 +20,6 @@
*/
#if defined(HAVE_QT)
#ifndef HDR_layEditorOptionsPage
#define HDR_layEditorOptionsPage
@ -29,7 +27,7 @@
#include "tlObject.h"
#include <QWidget>
#include <set>
namespace db
{
@ -44,38 +42,206 @@ class Dispatcher;
class LayoutViewBase;
class Plugin;
class CellView;
class EditorOptionsPages;
class EditorOptionsPage;
class EditorOptionsPageWidget;
/**
* @brief The base class for a object properties page
* @brief An interface managing a collection of EditorOptionPage objects
*/
class LAYBASIC_PUBLIC EditorOptionsPageCollection
{
public:
EditorOptionsPageCollection ();
virtual ~EditorOptionsPageCollection () { }
virtual void unregister_page (EditorOptionsPage *page) = 0;
virtual bool has_content () const = 0;
virtual bool has_modal_content () const = 0;
virtual void make_page_current (EditorOptionsPage *page) = 0;
virtual void activate_page (EditorOptionsPage *page) = 0;
virtual void activate (const lay::Plugin *plugin) = 0;
virtual bool exec_modal (EditorOptionsPage *page) = 0;
virtual std::vector<lay::EditorOptionsPage *> editor_options_pages (const lay::PluginDeclaration *plugin) = 0;
virtual std::vector<lay::EditorOptionsPage *> editor_options_pages () = 0;
virtual lay::EditorOptionsPage *page_with_name (const std::string &name) = 0;
};
/**
* @brief The base class for a editor options page
*
* The object properties page is shown in the editor options panel
* for the active plugin.
*
* Pages can be toolbox widgets, i.e. they are shown in the drawing area
* at the top of the canvas, instead of being shown in the editor options
* panel.
*/
class LAYBASIC_PUBLIC EditorOptionsPage
: public QWidget, public tl::Object
: public tl::Object
{
Q_OBJECT
public:
/**
* @brief Constructor
*/
EditorOptionsPage (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher);
/**
* @brief Default constructor
*/
EditorOptionsPage ();
/**
* @brief Destructor
*/
virtual ~EditorOptionsPage ();
/**
* @brief The title of the page
* This title is used for the tab title the page appears
*/
virtual std::string title () const = 0;
/**
* @brief The order in which the pages appear
* This index specifies the position of the page. The page with the
* lower index appears left.
* The page with order 0 is the default page, picked when the plugin
* becomes active.
*/
virtual int order () const = 0;
/**
* @brief The page name
* Giving a page name allows looking up a page by name.
* The page name is optional and if not specified, a zero pointer
* should be returned.
*/
virtual const char *name () const { return 0; }
/**
* @brief A callback to apply all values
* The page is expected to issue "config_set" calls to the dispatcher
* to deliver the settings.
* This callback is not used for toolbox widgets.
*/
virtual void apply (lay::Dispatcher * /*root*/) { }
/**
* @brief A callback to setup the page
* This callback is expected to set up the page values from
* the configuration, stored inside the dispatcher.
* This callback is not used for toolbox widgets.
*/
virtual void setup (lay::Dispatcher * /*root*/) { }
/**
* @brief A callback to cancel the page edits
* This callback is used for toolbox widgets if the user presses
* "Escape".
*/
virtual void cancel () { }
/**
* @brief A callback to commit the values
* This callback is used for toolbox widgets if the user presses
* "Enter". It can either commit values to the dispatcher
* through "config_set", or perform other functions.
*/
virtual void commit (lay::Dispatcher * /*root*/) { }
/**
* @brief Configure the page
* This interface can be used by plugin implementation to transfer
* data from the plugin to a toolbox widget. This method is not
* used by the system directly.
*/
virtual void configure (const std::string & /*name*/, const std::string & /*value*/) { }
/**
* @brief Called by the system to commit the current settings into some "recently used" list
*/
virtual void commit_recent (lay::Dispatcher * /*root*/) { }
/**
* @brief Called by the system to restore recent settings for a given layer
*/
virtual void config_recent_for_layer (lay::Dispatcher * /*root*/, const db::LayerProperties & /*lp*/, int /*cv_index*/) { }
bool is_focus_page () const { return m_focus_page; }
void set_focus_page (bool f) { m_focus_page = f; }
void set_focus ();
/**
* @brief Sets the focus to the page
* This function is called by the system to establish the focus on this page.
*/
virtual void set_focus () { }
/**
* @brief Returns the widget for the page
* The page itself is not a Qt object. To fetch the corresponding widget, use this method.
*/
virtual EditorOptionsPageWidget *widget () { return 0; }
/**
* @brief Gets a value indicating whether the page is visible
*/
virtual bool is_visible () const { return false; }
/**
* @brief Changes the visibility of the page
*/
virtual void set_visible (bool /*visible*/) { }
/**
* @brief Returns a flag indicating whether the page is a focus page
* Focus pages are pages that are activated when the user presses the Tab
* key in the canvas. Toolbox widgets receive the focus and modal pages
* are shown modally.
*/
bool is_focus_page () const { return m_focus_page; }
/**
* @brief Sets a flag indicating whether the page is a focus page
*/
void set_focus_page (bool f) { m_focus_page = f; }
/**
* @brief Returns a flag indicating whether the page is a modal page
* Modal pages are shown in a modal dialog when they receive the focus.
* Otherwise they remain invisible.
*/
bool is_modal_page () const { return m_modal_page; }
/**
* @brief Sets a flag indicating whether the page is a modal page
*/
void set_modal_page (bool f) { m_modal_page = f; }
/**
* @brief Returns a flag indicating whether the page is a toolbox widget
*/
bool is_toolbox_widget () const { return m_toolbox_widget; }
/**
* @brief Sets a flag indicating whether the page is a toolbox widget
*/
void set_toolbox_widget (bool f) { m_toolbox_widget = f; }
/**
* @brief Gets a value indicating whether the page is active
* A page is active when the corresponding plugin is active
*/
bool active () const { return m_active; }
/**
* @brief Activates a page
* This function is called when the system activates a page because the
* corresponding plugin was activate.
*/
void activate (bool active);
void set_owner (EditorOptionsPages *owner);
/**
* @brief Sets the owner of the page
* This function is used by the system and must not be used otherwise.
*/
void set_owner (EditorOptionsPageCollection *owner);
/**
* @brief Shows the editor page
@ -83,37 +249,68 @@ public:
*/
int show ();
const lay::PluginDeclaration *plugin_declaration () const { return mp_plugin_declaration; }
void set_plugin_declaration (const lay::PluginDeclaration *pd) { mp_plugin_declaration = pd; }
/**
* @brief Gets a value indicating whether the page is for that specific plugin (given by a declaration object)
*/
bool for_plugin_declaration (const lay::PluginDeclaration *pd)
{
return m_plugin_declarations.find (pd) != m_plugin_declarations.end ();
}
void init (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher);
/**
* @brief Sets the plugin the page is associated with
* This function is used by the system and must not be used otherwise.
*/
void set_plugin_declaration (const lay::PluginDeclaration *pd)
{
m_plugin_declarations.clear ();
m_plugin_declarations.insert (pd);
}
/**
* @brief Sets the plugins the page is associated with
* This function is used by the system and must not be used otherwise.
*/
void set_plugin_declarations (const std::vector<const lay::PluginDeclaration *> &pd)
{
m_plugin_declarations.clear ();
m_plugin_declarations.insert (pd.begin (), pd.end ());
}
/**
* @brief Gets the dispatcher the page is connected to
*/
lay::Dispatcher *dispatcher () const
{
return mp_dispatcher;
}
/**
* @brief Gets the view the page is connected to
*/
lay::LayoutViewBase *view () const
{
return mp_view;
}
protected slots:
void edited ();
/**
* @brief Initializes the page
* This function is used by the system and must not be used otherwise.
*/
void init (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher);
protected:
virtual void active_cellview_changed () { }
virtual void technology_changed (const std::string & /*tech*/) { }
virtual bool focusNextPrevChild (bool next);
virtual void keyPressEvent (QKeyEvent *event);
virtual void activated () { }
virtual void deactivated () { }
private:
EditorOptionsPages *mp_owner;
EditorOptionsPageCollection *mp_owner;
bool m_active;
bool m_focus_page;
bool m_modal_page;
const lay::PluginDeclaration *mp_plugin_declaration;
bool m_modal_page, m_toolbox_widget;
std::set<const lay::PluginDeclaration *> m_plugin_declarations;
lay::Dispatcher *mp_dispatcher;
lay::LayoutViewBase *mp_view;
@ -122,8 +319,87 @@ private:
void attach_events ();
};
/**
* @brief A basic factory class for editor options pages
*
* We will use it later to provide a registration-based specialized factory
* for Qt-enabled option pages, which we should not link here.
*
* A factory has a name - if the name matches a plugin name,
* the factory is automatically requested to create a page for
* that plugin.
*
* Otherwise, plugins can request additional pages through
* "additional_editor_options_pages". This is a list of names
* (not plugin names) of page factories. These factories will
* be called to provide additional pages then.
*/
class LAYBASIC_PUBLIC EditorOptionsPageFactoryBase
{
public:
EditorOptionsPageFactoryBase (const char *name)
: m_name (name)
{
// .. nothing yet ..
}
EditorOptionsPageFactoryBase ()
: m_name ()
{
// .. nothing yet ..
}
virtual ~EditorOptionsPageFactoryBase () { }
const std::string &name () const
{
return m_name;
}
virtual lay::EditorOptionsPage *create_page (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher) = 0;
private:
std::string m_name;
};
/**
* @brief A specialized editor options page factory class for a specific type
*
* Register the factory using:
*
* #include "tlClassRegistry.h"
* static tl::RegisteredClass<lay::EditorOptionsPageFactoryBase> s_factory (new lay::EditorOptionsPageFactory<MyClass> (), 0, "MyClass");
*
* Later you can create a page from "MyName" using
*
* page = EditorOptionsPageFactoryBase::create_page_by_name ("MyClass", view, dispatcher);
*/
template <class T>
class LAYBASIC_PUBLIC_TEMPLATE EditorOptionsPageFactory
: public EditorOptionsPageFactoryBase
{
public:
EditorOptionsPageFactory (const char *plugin_name)
: EditorOptionsPageFactoryBase (plugin_name)
{
// .. nothing yet ..
}
EditorOptionsPageFactory ()
: EditorOptionsPageFactoryBase ()
{
// .. nothing yet ..
}
virtual ~EditorOptionsPageFactory () { }
virtual lay::EditorOptionsPage *create_page (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
{
return new T (view, dispatcher);
}
};
}
#endif
#endif // defined(HAVE_QT)

View File

@ -22,7 +22,6 @@
#include "layEditorServiceBase.h"
#include "layEditorOptionsPage.h"
#include "layEditorOptionsPages.h"
#include "layViewport.h"
#include "layLayoutViewBase.h"
#include "laybasicConfig.h"
@ -345,22 +344,14 @@ EditorServiceBase::activated ()
m_active = true;
}
#if defined(HAVE_QT)
std::vector<lay::EditorOptionsPage *>
EditorServiceBase::editor_options_pages ()
{
lay::EditorOptionsPages *eo_pages = mp_view->editor_options_pages ();
lay::EditorOptionsPageCollection *eo_pages = mp_view->editor_options_pages ();
if (!eo_pages) {
return std::vector<lay::EditorOptionsPage *> ();
} else {
std::vector<lay::EditorOptionsPage *> pages;
for (auto p = eo_pages->pages ().begin (); p != eo_pages->pages ().end (); ++p) {
if ((*p)->plugin_declaration () == plugin_declaration ()) {
pages.push_back (*p);
}
}
return pages;
return eo_pages->editor_options_pages (plugin_declaration ());
}
}
@ -378,50 +369,39 @@ EditorServiceBase::focus_page ()
}
bool
EditorServiceBase::key_event (unsigned int key, unsigned int buttons)
EditorServiceBase::key_event (unsigned int key, unsigned int /*buttons*/)
{
if (is_active () && key == Qt::Key_Tab && buttons == 0) {
focus_page_open ();
return true;
if (is_active () && (key == lay::KeyTab || key == lay::KeyBacktab)) {
return focus_page_open () >= 0;
} else {
return false;
}
}
bool
EditorServiceBase::shortcut_override_event (unsigned int key, unsigned int /*buttons*/)
{
auto fp = focus_page ();
return is_active ()
&& (key == lay::KeyTab || key == lay::KeyBacktab)
&& fp
&& (fp->is_modal_page () || fp->is_visible ());
}
int
EditorServiceBase::focus_page_open ()
{
auto fp = focus_page ();
return fp ? fp->show () : 0;
return fp ? fp->show () : -1;
}
void
EditorServiceBase::show_error (tl::Exception &ex)
{
tl::error << ex.msg ();
#if defined(HAVE_QT)
QMessageBox::critical (ui ()->widget (), tr ("Error"), tl::to_qstring (ex.msg ()));
}
#else
bool
EditorServiceBase::key_event (unsigned int key, unsigned int buttons)
{
return false;
}
void
EditorServiceBase::show_error (tl::Exception &ex)
{
tl::error << ex.msg ();
}
int
EditorServiceBase::focus_page_open ()
{
return 0;
}
#endif
}
}

View File

@ -185,6 +185,11 @@ public:
*/
virtual bool key_event (unsigned int /*key*/, unsigned int /*buttons*/);
/**
* @brief Shortcut override event handler
*/
virtual bool shortcut_override_event (unsigned int /*key*/, unsigned int /*buttons*/);
/**
* @brief Mouse press event handler
*/
@ -272,7 +277,6 @@ public:
*/
virtual int focus_page_open ();
#if defined(HAVE_QT)
/**
* @brief Gets the editor options pages associated with this plugin
*/
@ -282,7 +286,6 @@ public:
* @brief Gets the focus page or 0 if there is none
*/
lay::EditorOptionsPage *focus_page ();
#endif
private:
// The marker representing the mouse cursor

View File

@ -91,6 +91,8 @@ Finder::start (lay::LayoutViewBase *view, unsigned int cv_index, const std::vect
{
const lay::CellView &cv = view->cellview (cv_index);
reset_counter ();
m_layers = layers;
mp_layout = &cv->layout ();
mp_view = view;
@ -265,7 +267,7 @@ ShapeFinder::ShapeFinder (bool point_mode, bool top_level_sel, db::ShapeIterator
mp_prop_sel (0), m_inv_prop_sel (false), mp_progress (0),
m_capture_all_shapes (capture_all_shapes)
{
m_tries = point_sel_tests;
m_try_counter = m_tries = point_sel_tests;
}
struct LPContextEqualOp
@ -440,20 +442,29 @@ ShapeFinder::find_internal (lay::LayoutViewBase *view, unsigned int cv_index, co
auto flags_saved = m_flags;
try {
if ((m_flags & db::ShapeIterator::Texts) != 0 && mp_text_info && ! mp_text_info->point_mode ()) {
if ((m_flags & db::ShapeIterator::Texts) != 0 && mp_text_info && ! mp_text_info->point_mode ()) {
m_flags = db::ShapeIterator::Texts;
m_flags = db::ShapeIterator::Texts;
try {
// for catching all labels we search the whole view area
db::DBox scan_region_mu = view->viewport ().box ();
start (view, m_cv_index, trans_mu, region_mu, scan_region_mu, min_level, max_level, layers);
m_flags = db::ShapeIterator::flags_type (flags_saved - db::ShapeIterator::Texts);
} catch (StopException) {
// ...
} catch (...) {
m_flags = flags_saved;
throw;
}
m_flags = db::ShapeIterator::flags_type (flags_saved - db::ShapeIterator::Texts);
}
try {
// another pass with tight search box and without texts
start (view, m_cv_index, trans_mu, region_mu, region_mu, min_level, max_level, layers);
@ -476,12 +487,18 @@ ShapeFinder::checkpoint ()
if (! point_mode ()) {
++*mp_progress;
} else {
if (--m_tries < 0) {
if (--m_try_counter < 0) {
throw StopException ();
}
}
}
void
ShapeFinder::reset_counter ()
{
m_try_counter = m_tries;
}
void
ShapeFinder::visit_cell (const db::Cell &cell, const db::Box &hit_box, const db::Box &scan_box, const db::DCplxTrans &vp, const db::ICplxTrans &t, int /*level*/)
{
@ -814,12 +831,18 @@ InstFinder::checkpoint ()
if (! point_mode ()) {
++*mp_progress;
} else {
if (--m_tries < 0) {
if (--m_try_counter < 0) {
throw StopException ();
}
}
}
void
InstFinder::reset_counter ()
{
m_try_counter = m_tries;
}
bool
InstFinder::consider_cell (const db::Cell &cell) const
{

View File

@ -213,6 +213,11 @@ protected:
*/
virtual void checkpoint () = 0;
/**
* @brief Is called to reset a try counter that stops on "checkpoint"
*/
virtual void reset_counter () = 0;
private:
void do_find (const db::Cell &cell, int level, const db::DCplxTrans &vp, const db::ICplxTrans &t);
@ -317,6 +322,7 @@ protected:
}
virtual void checkpoint ();
virtual void reset_counter ();
private:
virtual void visit_cell (const db::Cell &cell, const db::Box &hit_box, const db::Box &scan_box, const db::DCplxTrans &vp, const db::ICplxTrans &t, int level);
@ -338,7 +344,7 @@ private:
const lay::TextInfo *mp_text_info;
const std::set<db::properties_id_type> *mp_prop_sel;
bool m_inv_prop_sel;
int m_tries;
int m_tries, m_try_counter;
tl::AbsoluteProgress *mp_progress;
std::vector<int> m_context_layers;
std::map<db::cell_index_type, bool> m_cells_with_context;
@ -385,6 +391,7 @@ public:
}
virtual void checkpoint ();
virtual void reset_counter ();
private:
virtual void visit_cell (const db::Cell &cell, const db::Box &hit_box, const db::Box &scan_box, const db::DCplxTrans &vp, const db::ICplxTrans &t, int level);
@ -396,7 +403,7 @@ private:
db::cell_index_type m_topcell;
const std::set<lay::ObjectInstPath> *mp_excludes;
std::vector<lay::ObjectInstPath> m_founds;
int m_tries;
int m_tries, m_try_counter;
bool m_full_arrays;
bool m_enclose_insts;
bool m_visible_layers;

View File

@ -33,6 +33,7 @@
#include "layLayoutCanvas.h"
#include "layRedrawThread.h"
#include "layLayoutViewBase.h"
#include "layEditorOptionsPage.h"
#include "layMarker.h"
#if defined(HAVE_QT)
# include "gtf.h"
@ -238,7 +239,12 @@ LayoutCanvas::init_ui (QWidget *parent)
void
LayoutCanvas::key_event (unsigned int key, unsigned int buttons)
{
if (! (buttons & lay::ShiftButton)) {
if (int (key) == lay::KeyTab || int (key) == lay::KeyBacktab) {
auto page = first_toolbox_widget ();
if (page) {
page->set_focus ();
}
} else if (! (buttons & lay::ShiftButton)) {
if (int (key) == lay::KeyDown) {
down_arrow_key_pressed ();
} else if (int (key) == lay::KeyUp) {
@ -261,6 +267,33 @@ LayoutCanvas::key_event (unsigned int key, unsigned int buttons)
}
}
bool
LayoutCanvas::shortcut_override_event (unsigned int key, unsigned int /*buttons*/)
{
if (int (key) == lay::KeyTab || int (key) == lay::KeyBacktab) {
return first_toolbox_widget () != 0;
} else {
return false;
}
}
lay::EditorOptionsPage *
LayoutCanvas::first_toolbox_widget ()
{
auto pages = mp_view->editor_options_pages ();
if (! pages) {
return 0;
}
auto pv = pages->editor_options_pages ();
for (auto p = pv.begin (); p != pv.end (); ++p) {
if ((*p)->is_toolbox_widget () && (*p)->is_visible ()) {
return *p;
}
}
return 0;
}
void
LayoutCanvas::set_image_cache_size (size_t sz)
{

View File

@ -50,6 +50,7 @@ namespace lay
class LayoutViewBase;
class RedrawThread;
class EditorOptionsPage;
/**
* @brief A class representing one entry in the image cache
@ -459,7 +460,10 @@ private:
tl::Mutex m_mutex;
virtual void key_event (unsigned int key, unsigned int buttons);
virtual bool shortcut_override_event (unsigned int key, unsigned int buttons);
virtual void resize_event (unsigned int width, unsigned int height);
lay::EditorOptionsPage *first_toolbox_widget ();
#if defined(HAVE_QT)
virtual void gtf_probe ();
virtual void paint_event ();

View File

@ -400,7 +400,7 @@ LayoutViewBase::init (db::Manager *mgr)
mp_canvas = new lay::LayoutCanvas (this);
create_plugins ();
LayoutViewBase::create_plugins ();
}
void
@ -4169,7 +4169,7 @@ LayoutViewBase::cancel_edits ()
// the move service takes a special role here as it manages the
// transaction for the collective move operation.
if (mp_move_service) {
mp_move_service->cancel ();
mp_move_service->cancel_transaction ();
}
// cancel all drag and pending edit operations such as move operations.
@ -4186,7 +4186,7 @@ LayoutViewBase::finish_edits ()
// the move service takes a special role here as it manages the
// transaction for the collective move operation.
if (mp_move_service) {
mp_move_service->finish ();
mp_move_service->finish_transaction ();
}
// cancel all drag operations

View File

@ -77,11 +77,12 @@ class MouseTracker;
class ZoomService;
class SelectionService;
class MoveService;
class EditorOptionsPage;
class EditorOptionsPageCollection;
#if defined(HAVE_QT)
class LayerControlPanel;
class HierarchyControlPanel;
class EditorOptionsPages;
#endif
/**
@ -351,6 +352,22 @@ public:
// the base implementation does nothing
}
/**
* @brief Removes a notification
*/
virtual void remove_notification (const LayoutViewNotification & /*notification*/)
{
// the base implementation does nothing
}
/**
* @brief Adds an editor options page as a toolbox widget
*/
virtual void add_toolbox_widget (lay::EditorOptionsPage * /*toolbox_widget*/)
{
// the base implementation does nothing
}
/**
* @brief Gets the explicit title string of the view
*
@ -1899,15 +1916,15 @@ public:
{
return 0;
}
#endif
/**
* @brief Gets the editor options page
*/
virtual lay::EditorOptionsPages *editor_options_pages ()
virtual lay::EditorOptionsPageCollection *editor_options_pages ()
{
return 0;
}
#endif
/**
* @brief Get the current viewport

View File

@ -147,11 +147,6 @@ public:
{
return new MouseTracker (view);
}
virtual bool enable_catchall_editor_options_pages () const
{
return false;
}
};
static tl::RegisteredClass<lay::PluginDeclaration> tracker_decl (new MouseTrackerDeclaration (), -1000, "laybasic::MouseTrackerPlugin");

View File

@ -24,12 +24,17 @@
#include "layEditable.h"
#include "layLayoutViewBase.h"
#include "layEditorUtils.h"
#include "layEditorOptionsPage.h"
#include "laySelector.h"
#include "laybasicConfig.h"
namespace lay
{
LAYBASIC_PUBLIC std::string move_editor_options_name ("move-editor-options");
LAYBASIC_PUBLIC std::string move_function_name ("move-execute");
LAYBASIC_PUBLIC std::string move_distance_setter_name ("move-distance");
// -------------------------------------------------------------
// MoveService implementation
@ -55,7 +60,11 @@ MoveService::deactivated ()
EditorServiceBase::deactivated ();
m_shift = db::DPoint ();
mp_editables->clear_transient_selection ();
drag_cancel ();
if (m_dragging) {
// we don't just call drag_cancel() - this way avoids pending selections with the wrong coordinates
mp_view->edit_cancel ();
}
}
bool
@ -72,6 +81,35 @@ MoveService::configure (const std::string &name, const std::string &value)
return false; // not taken
}
void
MoveService::function (const std::string &name, const std::string &value)
{
if (name == move_function_name) {
try {
db::DVector s;
tl::from_string (value, s);
m_dragging = false;
show_toolbox (false);
ui ()->ungrab_mouse (this);
mp_editables->end_move (s, mp_transaction.release ());
if (m_dragging_transient) {
mp_editables->clear_selection ();
}
drag_cancel ();
} catch (...) {
}
}
}
bool
MoveService::key_event (unsigned int key, unsigned int buttons)
{
@ -79,6 +117,11 @@ MoveService::key_event (unsigned int key, unsigned int buttons)
return true;
}
if (buttons == 0 && (key == lay::KeyEnter || key == lay::KeyReturn)) {
end_move ();
return true;
}
double dx = 0.0, dy = 0.0;
if (int (key) == lay::KeyDown) {
dy = -1.0;
@ -120,14 +163,34 @@ MoveService::key_event (unsigned int key, unsigned int buttons)
}
}
int
MoveService::focus_page_open ()
bool
MoveService::shortcut_override_event (unsigned int key, unsigned int buttons)
{
// This method is called on "Tab" by "key_event". "fp" is null as we don't have a focus page registered.
if (is_active () && dispatcher ()) {
dispatcher ()->menu_activated ("cm_sel_move");
if (! m_dragging) {
if (int (key) == lay::KeyDown ||
int (key) == lay::KeyLeft ||
int (key) == lay::KeyUp ||
int (key) == lay::KeyRight) {
return true;
}
}
return 0;
return lay::EditorServiceBase::shortcut_override_event (key, buttons);
}
void
MoveService::show_toolbox (bool visible)
{
lay::EditorOptionsPage *tb = toolbox_widget ();
if (tb) {
tb->set_visible (visible);
}
}
lay::EditorOptionsPage *
MoveService::toolbox_widget ()
{
return mp_view->editor_options_pages () ? mp_view->editor_options_pages ()->page_with_name (move_editor_options_name) : 0;
}
bool
@ -138,7 +201,23 @@ MoveService::mouse_move_event (const db::DPoint &p, unsigned int buttons, bool p
if (m_dragging) {
set_cursor (lay::Cursor::size_all);
mp_editables->move (p, ac_from_buttons (buttons));
auto pmv = mp_editables->move (p, ac_from_buttons (buttons));
// display the proposed move transformation
if (pmv.first >= 0) {
std::string pos = std::string ("dx: ") + tl::micron_to_string (pmv.second.disp ().x ()) + " dy: " + tl::micron_to_string (pmv.second.disp ().y ());
if (pmv.second.rot () != 0) {
pos += std::string (" ") + ((const db::DFTrans &) pmv.second).to_string ();
}
mp_view->message (pos);
lay::EditorOptionsPage *tb = toolbox_widget ();
if (tb) {
tb->configure (move_distance_setter_name, pmv.second.disp ().to_string ());
}
}
} else if (prio) {
@ -295,6 +374,14 @@ MoveService::start_move (db::Transaction *transaction, bool transient_selection)
return handle_click (pstart, 0, drag_transient, trans_holder.release ());
}
void
MoveService::end_move ()
{
if (m_dragging) {
handle_click (m_mouse_pos, 0, false, 0);
}
}
bool
MoveService::handle_click (const db::DPoint &p, unsigned int buttons, bool drag_transient, db::Transaction *transaction)
{
@ -313,6 +400,8 @@ MoveService::handle_click (const db::DPoint &p, unsigned int buttons, bool drag_
m_dragging = true;
m_dragging_transient = drag_transient;
show_toolbox (true);
ui ()->grab_mouse (this, false);
m_shift = db::DPoint ();
@ -325,7 +414,9 @@ MoveService::handle_click (const db::DPoint &p, unsigned int buttons, bool drag_
m_dragging = false;
show_toolbox (false);
ui ()->ungrab_mouse (this);
mp_editables->end_move (p, ac_from_buttons (buttons), mp_transaction.release ());
if (m_dragging_transient) {
@ -343,13 +434,14 @@ MoveService::drag_cancel ()
{
m_shift = db::DPoint ();
if (m_dragging) {
show_toolbox (false);
ui ()->ungrab_mouse (this);
m_dragging = false;
}
}
void
MoveService::cancel ()
MoveService::cancel_transaction ()
{
if (m_dragging) {
if (mp_transaction.get ()) {
@ -360,7 +452,7 @@ MoveService::cancel ()
}
void
MoveService::finish ()
MoveService::finish_transaction ()
{
if (m_dragging) {
mp_transaction.reset (0);
@ -383,6 +475,14 @@ public:
{
return new MoveService (view);
}
virtual std::vector<std::string> additional_editor_options_pages () const
{
std::vector<std::string> names;
// TODO: provide in a central place instead of borrowing from the edt module
names.push_back ("GenericEditorOptions");
return names;
}
};
static tl::RegisteredClass<lay::PluginDeclaration> move_service_decl (new MoveServiceDeclaration (), -970, "laybasic::MoveServicePlugin");

View File

@ -31,6 +31,10 @@
namespace lay {
LAYBASIC_PUBLIC extern std::string move_editor_options_name;
LAYBASIC_PUBLIC extern std::string move_function_name;
LAYBASIC_PUBLIC extern std::string move_distance_setter_name;
class LayoutViewBase;
class LAYBASIC_PUBLIC MoveService :
@ -41,10 +45,12 @@ public:
~MoveService ();
bool start_move (db::Transaction *transaction = 0, bool transient_selection = false);
void end_move ();
bool configure (const std::string &name, const std::string &value);
void finish ();
void cancel ();
void function (const std::string &name, const std::string &value);
void finish_transaction ();
void cancel_transaction ();
private:
virtual bool mouse_press_event (const db::DPoint &p, unsigned int buttons, bool prio);
@ -54,9 +60,11 @@ private:
virtual bool mouse_release_event (const db::DPoint &p, unsigned int /*buttons*/, bool prio);
virtual bool wheel_event (int delta, bool horizontal, const db::DPoint &p, unsigned int buttons, bool prio);
virtual bool key_event (unsigned int key, unsigned int buttons);
virtual bool shortcut_override_event (unsigned int key, unsigned int buttons);
virtual void drag_cancel ();
virtual void deactivated ();
int focus_page_open ();
void show_toolbox (bool visible);
lay::EditorOptionsPage *toolbox_widget ();
bool handle_click (const db::DPoint &p, unsigned int buttons, bool drag_transient, db::Transaction *transaction);

View File

@ -30,6 +30,7 @@
#include "layPlugin.h"
#include "layDispatcher.h"
#include "layEditorOptionsPage.h"
#include "tlExceptions.h"
#include "tlClassRegistry.h"
@ -317,6 +318,67 @@ PluginDeclaration::register_plugin ()
}
}
std::string
PluginDeclaration::name () const
{
auto plugin_reg = tl::Registrar<lay::PluginDeclaration>::get_instance ();
for (auto i = plugin_reg->begin (); i != plugin_reg->end (); ++i) {
if (i.operator-> () == this) {
return i.current_name ();
}
}
return std::string ();
}
void
PluginDeclaration::get_editor_options_pages (std::vector<lay::EditorOptionsPage *> &pages, lay::LayoutViewBase *view, lay::Dispatcher *dispatcher) const
{
std::string n = name ();
if (n.empty ()) {
return;
}
auto reg = tl::Registrar<lay::EditorOptionsPageFactoryBase>::get_instance ();
for (auto i = reg->begin (); i != reg->end (); ++i) {
lay::EditorOptionsPage *page = 0;
if (i->name () == n) {
page = i->create_page (view, dispatcher);
if (page) {
page->set_plugin_declaration (this);
}
}
if (page) {
pages.push_back (page);
}
}
}
void
PluginDeclaration::get_additional_editor_options_pages (std::vector<EditorOptionsPage *> &pages, LayoutViewBase *view, Dispatcher *dispatcher, const std::map<std::string, std::vector<const lay::PluginDeclaration *> > &names)
{
std::set<std::string> names_seen;
auto reg = tl::Registrar<lay::EditorOptionsPageFactoryBase>::get_instance ();
for (auto i = reg->begin (); i != reg->end (); ++i) {
auto n = names.find (i->name ());
if (n != names.end ()) {
names_seen.insert (i->name ());
lay::EditorOptionsPage *page = i->create_page (view, dispatcher);
if (page) {
page->set_plugin_declarations (n->second);
pages.push_back (page);
}
}
}
for (auto i = names.begin (); i != names.end (); ++i) {
if (names_seen.find (i->first) == names_seen.end ()) {
tl::warn << tl::to_string (tr ("Cannot find additional editor options page: ")) << i->first;
}
}
}
// ----------------------------------------------------------------
// Plugin implementation
@ -523,6 +585,15 @@ Plugin::do_config_set (const std::string &name, const std::string &value, bool f
return false;
}
void
Plugin::call_function (const std::string &symbol, const std::string &args)
{
function (symbol, args);
for (tl::weak_collection<Plugin>::iterator c = m_children.begin (); c != m_children.end (); ++c) {
c->call_function (symbol, args);
}
}
// ---------------------------------------------------------------------------------------------------
// Menu item generators

View File

@ -51,9 +51,9 @@ class ViewService;
class Editable;
class Drawing;
class TechnologyComponentProvider;
class EditorOptionsPage;
#if defined(HAVE_QT)
class Browser;
class EditorOptionsPage;
class ConfigPage;
#endif
@ -170,6 +170,14 @@ public:
*/
virtual ~PluginDeclaration ();
/**
* @brief Gets the name under which the declaration was registered
*
* This is the name used in tl::RegisteredClass.
* If the plugin declaration is not registered, an empty string is returned.
*/
std::string name () const;
/**
* @brief This method is supposed to deliver the option names available
*
@ -323,7 +331,6 @@ public:
return false;
}
#if defined(HAVE_QT)
/**
* @brief Gets the editor options pages
*
@ -331,24 +338,26 @@ public:
* and these will be shown in tabs inside this widget.
*
* The new pages are returned in the "pages" vector. The layout view will take ownership of these pages.
*
* The default implementation collects pages registered through editor options page factories.
*/
virtual void get_editor_options_pages (std::vector<lay::EditorOptionsPage *> & /*pages*/, lay::LayoutViewBase * /*view*/, lay::Dispatcher * /*dispatcher*/) const
{
// .. no pages in the default implementation ..
}
virtual void get_editor_options_pages (std::vector<lay::EditorOptionsPage *> &pages, lay::LayoutViewBase *view, lay::Dispatcher *dispatcher) const;
/**
* @brief Gets a value indicating whether "catchall" editor options pages shall be included
*
* "catchall" editor options pages are ones that are unspecific and render a null "plugin_declaration".
* A plugin can choose to include these pages if it listens to global configuration events.
* Otherwise it should return false here to suppress these pages.
* @brief Gets pages created from registered factories by name
*/
virtual bool enable_catchall_editor_options_pages () const
static void get_additional_editor_options_pages (std::vector<lay::EditorOptionsPage *> &pages, lay::LayoutViewBase *view, lay::Dispatcher *dispatcher, const std::map<std::string, std::vector<const lay::PluginDeclaration *> > &names);
/**
* @brief Returns a list of editor options pages that the plugin wants to inherit
*
* In addition to providing pages through "get_editor_options_pages", the plugin can request pages
* from globally registered factories by name.
*/
virtual std::vector<std::string> additional_editor_options_pages () const
{
return true;
return std::vector<std::string> ();
}
#endif
/**
* @brief Tells if the plugin implements a "lay::ViewService" active mouse mode
@ -744,6 +753,13 @@ public:
// .. this implementation does nothing ..
}
/**
* @brief Generic function call
*
* This method calls "function" on this plugin and all the children.
*/
virtual void call_function (const std::string &symbol, const std::string &args);
#if defined(HAVE_QT)
/**
* @brief Return the lay::Browser interface if this object has one
@ -859,6 +875,17 @@ protected:
// .. the default implementation does nothing ..
}
/**
* @brief Implements a generic function call
*
* This method can be used to establish a communication between a properties page and
* a plugin for example.
*/
virtual void function (const std::string & /*symbol*/, const std::string & /*args*/)
{
// .. this implementation does nothing ..
}
private:
Plugin (const Plugin &);
Plugin &operator= (const Plugin &);

View File

@ -332,11 +332,6 @@ public:
{
return new SelectionService (view);
}
virtual bool enable_catchall_editor_options_pages () const
{
return false;
}
};
static tl::RegisteredClass<lay::PluginDeclaration> selection_service_decl (new SelectionServiceDeclaration (), -980, "laybasic::SelectionServicePlugin");

Some files were not shown because too many files have changed in this diff Show More