This commit is contained in:
Matthias Koefferlein 2019-12-08 20:25:54 +01:00
commit bbb8e1f430
32 changed files with 663 additions and 229 deletions

View File

@ -901,11 +901,6 @@ Service::drag_cancel ()
delete mp_active_ruler;
mp_active_ruler = 0;
}
if (mp_transient_ruler) {
delete mp_transient_ruler;
mp_transient_ruler = 0;
}
}
int
@ -1030,6 +1025,8 @@ Service::begin_move (lay::Editable::MoveMode mode, const db::DPoint &p, lay::ang
// cancel any pending move or drag operations, reset mp_active_ruler
widget ()->drag_cancel (); // KLUDGE: every service does this to the same service manager
clear_transient_selection ();
// choose move mode
if (mode == lay::Editable::Selected) {
@ -1486,6 +1483,7 @@ Service::mouse_click_event (const db::DPoint &p, unsigned int buttons, bool prio
// stop dragging
drag_cancel ();
clear_transient_selection ();
// end the transaction
manager ()->commit ();
@ -1535,6 +1533,7 @@ void
Service::deactivated ()
{
drag_cancel ();
clear_transient_selection ();
}
std::pair<bool, db::DPoint>
@ -1576,6 +1575,8 @@ struct RulerIdComp
void
Service::reduce_rulers (int num)
{
clear_transient_selection ();
lay::AnnotationShapes::iterator rfrom = mp_view->annotation_shapes ().begin ();
lay::AnnotationShapes::iterator rto = mp_view->annotation_shapes ().end ();
@ -1921,6 +1922,21 @@ Service::clear_transient_selection ()
}
}
void
Service::transient_to_selection ()
{
if (mp_transient_ruler) {
for (lay::AnnotationShapes::iterator r = mp_view->annotation_shapes ().begin (); r != mp_view->annotation_shapes ().end (); ++r) {
const ant::Object *robj = dynamic_cast <const ant::Object *> (r->ptr ());
if (robj == mp_transient_ruler->ruler ()) {
m_selected.insert (std::make_pair (r, 0));
selection_to_view ();
return;
}
}
}
}
void
Service::clear_previous_selection ()
{

View File

@ -284,6 +284,11 @@ public:
*/
virtual void clear_previous_selection ();
/**
* @brief Turns the transient selection to the selection
*/
virtual void transient_to_selection ();
/**
* @brief Establish a transient selection
*/
@ -548,7 +553,7 @@ private:
bool select (obj_iterator obj, lay::Editable::SelectionMode mode);
/**
* @brief Clear the selection
* @brief Clears the selection
*/
void clear_selection ();

View File

@ -1063,7 +1063,7 @@ public:
typedef AnnotationRef value_type;
typedef std::map<ant::Service::obj_iterator, unsigned int>::const_iterator iterator_type;
typedef void pointer;
typedef const value_type &reference;
typedef value_type reference;
typedef std::forward_iterator_tag iterator_category;
typedef void difference_type;
@ -1088,7 +1088,7 @@ public:
return *this;
}
value_type operator* () const
reference operator* () const
{
return value_type (*(static_cast<const ant::Object *> (m_iter->first->ptr ())), m_services[m_service]->view ());
}

View File

@ -254,6 +254,7 @@ void NetlistSpiceReader::read (tl::InputStream &stream, db::Netlist &netlist)
mp_circuit = 0;
mp_nets_by_name.reset (0);
m_global_nets.clear ();
m_circuits_read.clear ();
try {
@ -891,11 +892,16 @@ void NetlistSpiceReader::read_circuit (tl::Extractor &ex, const std::string &nc)
} else {
if (cc->pin_count () != nn.size () + m_global_nets.size ()) {
error (tl::sprintf (tl::to_string (tr ("Pin count mismatch between implicit (through call) and explicit circuit definition: %d expected, got %d")), int (cc->pin_count ()), int (nn.size ())));
error (tl::sprintf (tl::to_string (tr ("Pin count mismatch between implicit (through call) and explicit circuit definition: %d expected, got %d in circuit %s")), int (cc->pin_count ()), int (nn.size ()), nc));
}
}
if (m_circuits_read.find (cc) != m_circuits_read.end ()) {
error (tl::sprintf (tl::to_string (tr ("Redefinition of circuit %s")), nc));
}
m_circuits_read.insert (cc);
std::auto_ptr<std::map<std::string, db::Net *> > n2n (mp_nets_by_name.release ());
mp_nets_by_name.reset (0);

View File

@ -28,6 +28,8 @@
#include "tlStream.h"
#include <string>
#include <set>
#include <map>
#include <memory>
namespace db
@ -129,6 +131,7 @@ private:
std::string m_stored_line;
std::map<std::string, bool> m_captured;
std::vector<std::string> m_global_nets;
std::set<const db::Circuit *> m_circuits_read;
void push_stream (const std::string &path);
void pop_stream ();

View File

@ -384,3 +384,21 @@ TEST(10_SubcircuitsNoPins)
);
}
TEST(11_ErrorOnCircuitRedefinition)
{
db::Netlist nl;
std::string path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "nreader11.cir");
std::string msg;
try {
db::NetlistSpiceReader reader;
tl::InputStream is (path);
reader.read (is, nl);
} catch (tl::Exception &ex) {
msg = ex.msg ();
}
EXPECT_EQ (tl::replaced (msg, path, "?"), "Redefinition of circuit SUBCKT in ?, line 20");
}

View File

@ -1,7 +1,8 @@
<ui version="4.0" >
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>CopyModeDialog</class>
<widget class="QDialog" name="CopyModeDialog" >
<property name="geometry" >
<widget class="QDialog" name="CopyModeDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
@ -9,38 +10,56 @@
<height>164</height>
</rect>
</property>
<property name="windowTitle" >
<property name="windowTitle">
<string>Copy Options</string>
</property>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<layout class="QVBoxLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>9</number>
</property>
<property name="topMargin">
<number>9</number>
</property>
<property name="rightMargin">
<number>9</number>
</property>
<property name="bottomMargin">
<number>9</number>
</property>
<item>
<widget class="QGroupBox" name="groupBox" >
<property name="title" >
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Copy Mode</string>
</property>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<layout class="QVBoxLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>9</number>
</property>
<property name="topMargin">
<number>9</number>
</property>
<property name="rightMargin">
<number>9</number>
</property>
<property name="bottomMargin">
<number>9</number>
</property>
<item>
<widget class="QRadioButton" name="shallow_rb" >
<property name="text" >
<widget class="QRadioButton" name="shallow_rb">
<property name="text">
<string>Shallow copy (instances only)</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="deep_rb" >
<property name="text" >
<widget class="QRadioButton" name="deep_rb">
<property name="text">
<string>Deep copy (instances plus cell)</string>
</property>
</widget>
@ -48,12 +67,19 @@
</layout>
</widget>
</item>
<item>
<widget class="QCheckBox" name="dont_ask_cbx">
<property name="text">
<string>Don't ask again (you can always reset this in the editor options)</string>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" >
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
@ -62,12 +88,12 @@
</spacer>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox" >
<property name="orientation" >
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons" >
<set>QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
@ -81,11 +107,11 @@
<receiver>CopyModeDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel" >
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel" >
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
@ -97,11 +123,11 @@
<receiver>CopyModeDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel" >
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel" >
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>

View File

@ -1,7 +1,8 @@
<ui version="4.0" >
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>EditorOptionsGeneric</class>
<widget class="QWidget" name="EditorOptionsGeneric" >
<property name="geometry" >
<widget class="QWidget" name="EditorOptionsGeneric">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
@ -9,34 +10,52 @@
<height>417</height>
</rect>
</property>
<property name="windowTitle" >
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<layout class="QVBoxLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>9</number>
</property>
<property name="topMargin">
<number>9</number>
</property>
<property name="rightMargin">
<number>9</number>
</property>
<property name="bottomMargin">
<number>9</number>
</property>
<item>
<widget class="QGroupBox" name="groupBox" >
<property name="title" >
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Snapping</string>
</property>
<layout class="QGridLayout" >
<property name="margin" >
<layout class="QGridLayout">
<property name="leftMargin">
<number>9</number>
</property>
<property name="spacing" >
<property name="topMargin">
<number>9</number>
</property>
<property name="rightMargin">
<number>9</number>
</property>
<property name="bottomMargin">
<number>9</number>
</property>
<property name="spacing">
<number>6</number>
</property>
<item row="0" column="4" >
<item row="0" column="4">
<spacer>
<property name="orientation" >
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<property name="sizeHint" stdset="0">
<size>
<width>148</width>
<height>16</height>
@ -44,15 +63,15 @@
</property>
</spacer>
</item>
<item row="0" column="2" >
<item row="0" column="2">
<spacer>
<property name="orientation" >
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType" >
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" >
<property name="sizeHint" stdset="0">
<size>
<width>16</width>
<height>20</height>
@ -60,57 +79,55 @@
</property>
</spacer>
</item>
<item row="0" column="3" >
<widget class="QLineEdit" name="edit_grid_le" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>0</hsizetype>
<vsizetype>0</vsizetype>
<item row="0" column="3">
<widget class="QLineEdit" name="edit_grid_le">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip" >
<string>Enter the grid in micron. Can be anisotropic ("gx,gy")</string>
<property name="toolTip">
<string>Enter the grid in micron. Can be anisotropic (&quot;gx,gy&quot;)</string>
</property>
</widget>
</item>
<item row="0" column="0" >
<widget class="QLabel" name="label_5" >
<property name="text" >
<item row="0" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Grid</string>
</property>
</widget>
</item>
<item row="1" column="0" >
<widget class="QLabel" name="label_6" >
<property name="text" >
<item row="1" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Objects </string>
</property>
</widget>
</item>
<item row="0" column="1" >
<widget class="QComboBox" name="grid_cb" >
<item row="0" column="1">
<widget class="QComboBox" name="grid_cb">
<item>
<property name="text" >
<property name="text">
<string>No grid</string>
</property>
</item>
<item>
<property name="text" >
<property name="text">
<string>Global grid</string>
</property>
</item>
<item>
<property name="text" >
<property name="text">
<string>Other grid ...</string>
</property>
</item>
</widget>
</item>
<item row="1" column="1" colspan="4" >
<widget class="QCheckBox" name="snap_objects_cbx" >
<property name="text" >
<item row="1" column="1" colspan="4">
<widget class="QCheckBox" name="snap_objects_cbx">
<property name="text">
<string>Snap to other objects</string>
</property>
</widget>
@ -119,75 +136,84 @@
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2" >
<property name="title" >
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Angle Constraints</string>
</property>
<layout class="QGridLayout" >
<property name="margin" >
<layout class="QGridLayout">
<property name="leftMargin">
<number>9</number>
</property>
<property name="spacing" >
<property name="topMargin">
<number>9</number>
</property>
<property name="rightMargin">
<number>9</number>
</property>
<property name="bottomMargin">
<number>9</number>
</property>
<property name="spacing">
<number>6</number>
</property>
<item row="1" column="0" >
<widget class="QLabel" name="label_3" >
<property name="text" >
<item row="1" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Movements </string>
</property>
</widget>
</item>
<item row="0" column="0" >
<widget class="QLabel" name="label_2" >
<property name="text" >
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Connections </string>
</property>
</widget>
</item>
<item row="0" column="1" >
<widget class="QComboBox" name="conn_angle_cb" >
<item row="0" column="1">
<widget class="QComboBox" name="conn_angle_cb">
<item>
<property name="text" >
<property name="text">
<string>Any Angle</string>
</property>
</item>
<item>
<property name="text" >
<property name="text">
<string>Diagonal</string>
</property>
</item>
<item>
<property name="text" >
<property name="text">
<string>Manhattan</string>
</property>
</item>
</widget>
</item>
<item row="1" column="1" >
<widget class="QComboBox" name="move_angle_cb" >
<item row="1" column="1">
<widget class="QComboBox" name="move_angle_cb">
<item>
<property name="text" >
<property name="text">
<string>Any Direction</string>
</property>
</item>
<item>
<property name="text" >
<property name="text">
<string>Diagonal</string>
</property>
</item>
<item>
<property name="text" >
<property name="text">
<string>Manhattan</string>
</property>
</item>
</widget>
</item>
<item rowspan="2" row="0" column="2" >
<item row="0" column="2" rowspan="2">
<spacer>
<property name="orientation" >
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<property name="sizeHint" stdset="0">
<size>
<width>257</width>
<height>41</height>
@ -199,36 +225,91 @@
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_3" >
<property name="title" >
<string>Selection Mode</string>
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>Hierarchical Features</string>
</property>
<layout class="QGridLayout" >
<property name="margin" >
<layout class="QGridLayout">
<property name="leftMargin">
<number>9</number>
</property>
<property name="spacing" >
<property name="topMargin">
<number>9</number>
</property>
<property name="rightMargin">
<number>9</number>
</property>
<property name="bottomMargin">
<number>9</number>
</property>
<property name="spacing">
<number>6</number>
</property>
<item row="0" column="1" >
<widget class="QCheckBox" name="hier_sel_cbx" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>7</hsizetype>
<vsizetype>0</vsizetype>
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Copy mode</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Shallow select</string>
</property>
</widget>
</item>
<item row="1" column="1" colspan="2">
<widget class="QComboBox" name="hier_copy_mode_cbx">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text" >
<string>Select top level objects only</string>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContentsOnFirstShow</enum>
</property>
<item>
<property name="text">
<string>Shallow mode (instance only)</string>
</property>
</item>
<item>
<property name="text">
<string>Deep mode (instance and cell)</string>
</property>
</item>
<item>
<property name="text">
<string>Ask</string>
</property>
</item>
</widget>
</item>
<item row="0" column="0" >
<widget class="QLabel" name="label_4" >
<property name="text" >
<string>Hierarchy </string>
<item row="1" column="3">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="1" colspan="3">
<widget class="QCheckBox" name="hier_sel_cbx">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Select top level objects only</string>
</property>
</widget>
</item>
@ -236,30 +317,37 @@
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_4" >
<property name="title" >
<widget class="QGroupBox" name="groupBox_4">
<property name="title">
<string>Instance Display</string>
</property>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<layout class="QHBoxLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>9</number>
</property>
<property name="topMargin">
<number>9</number>
</property>
<property name="rightMargin">
<number>9</number>
</property>
<property name="bottomMargin">
<number>9</number>
</property>
<item>
<widget class="QCheckBox" name="show_shapes_cbx" >
<property name="text" >
<widget class="QCheckBox" name="show_shapes_cbx">
<property name="text">
<string>Show shapes when moving (max.</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="max_shapes_le" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>5</hsizetype>
<vsizetype>0</vsizetype>
<widget class="QLineEdit" name="max_shapes_le">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
@ -267,18 +355,18 @@
</widget>
</item>
<item>
<widget class="QLabel" name="label_13" >
<property name="text" >
<widget class="QLabel" name="label_13">
<property name="text">
<string>shapes)</string>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
@ -291,10 +379,10 @@
</item>
<item>
<spacer>
<property name="orientation" >
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" >
<property name="sizeHint" stdset="0">
<size>
<width>121</width>
<height>51</height>

View File

@ -57,6 +57,7 @@ std::string cfg_edit_inst_column_x ("edit-inst-column_x");
std::string cfg_edit_inst_column_y ("edit-inst-column_y");
std::string cfg_edit_inst_place_origin ("edit-inst-place-origin");
std::string cfg_edit_top_level_selection ("edit-top-level-selection");
std::string cfg_edit_hier_copy_mode ("edit-hier-copy-mode");
std::string cfg_edit_show_shapes_of_instances ("edit-show-shapes-of-instances");
std::string cfg_edit_max_shapes_of_instances ("edit-max-shapes-of-instances");
std::string cfg_edit_global_grid ("grid-micron");

View File

@ -68,6 +68,7 @@ extern EDT_PUBLIC std::string cfg_edit_inst_column_x;
extern EDT_PUBLIC std::string cfg_edit_inst_column_y;
extern EDT_PUBLIC std::string cfg_edit_inst_place_origin;
extern EDT_PUBLIC std::string cfg_edit_top_level_selection;
extern EDT_PUBLIC std::string cfg_edit_hier_copy_mode;
extern EDT_PUBLIC std::string cfg_edit_combine_mode;
// ------------------------------------------------------------

View File

@ -196,7 +196,7 @@ CopyModeDialog::~CopyModeDialog ()
}
bool
CopyModeDialog::exec_dialog (unsigned int &mode)
CopyModeDialog::exec_dialog (unsigned int &mode, bool &dont_ask)
{
if (mode == 0) {
shallow_rb->setChecked (true);
@ -207,6 +207,7 @@ CopyModeDialog::exec_dialog (unsigned int &mode)
} else {
mode = 1;
}
dont_ask = dont_ask_cbx->isChecked ();
return true;
} else {
return false;

View File

@ -64,7 +64,7 @@ public:
CopyModeDialog (QWidget *parent);
virtual ~CopyModeDialog ();
bool exec_dialog (unsigned int &mode);
bool exec_dialog (unsigned int &mode, bool &dont_ask);
};
/**

View File

@ -265,6 +265,8 @@ EditorOptionsGeneric::apply (lay::Plugin *root)
root->config_set (cfg_edit_connect_angle_mode, acc.to_string (lay::angle_constraint_type (mp_ui->conn_angle_cb->currentIndex ())));
root->config_set (cfg_edit_top_level_selection, tl::to_string (mp_ui->hier_sel_cbx->isChecked ()));
int cpm = mp_ui->hier_copy_mode_cbx->currentIndex ();
root->config_set (cfg_edit_hier_copy_mode, tl::to_string ((cpm < 0 || cpm > 1) ? -1 : cpm));
root->config_set (cfg_edit_snap_to_objects, tl::to_string (mp_ui->snap_objects_cbx->isChecked ()));
unsigned int max_shapes = 1000;
@ -321,6 +323,10 @@ EditorOptionsGeneric::setup (lay::Plugin *root)
root->config_get (cfg_edit_top_level_selection, top_level_sel);
mp_ui->hier_sel_cbx->setChecked (top_level_sel);
int cpm = -1;
root->config_get (cfg_edit_hier_copy_mode, cpm);
mp_ui->hier_copy_mode_cbx->setCurrentIndex ((cpm < 0 || cpm > 1) ? 2 : cpm);
bool snap_to_objects = false;
root->config_get (cfg_edit_snap_to_objects, snap_to_objects);
mp_ui->snap_objects_cbx->setChecked (snap_to_objects);

View File

@ -1641,7 +1641,7 @@ MainService::boolean_op (int mode)
for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); es != edt_services.end (); ++es) {
for (edt::Service::obj_iterator s = (*es)->selection ().begin (); s != (*es)->selection ().end (); ++s) {
if (int (s->layer ()) == layer_index && ! s->is_cell_inst () && (s->shape ().is_polygon () || s->shape ().is_path () || s->shape ().is_box ())) {
if (! s->is_cell_inst () && int (s->layer ()) == layer_index && (s->shape ().is_polygon () || s->shape ().is_path () || s->shape ().is_box ())) {
db::Cell &cell = view ()->cellview (s->cv_index ())->layout ().cell (s->cell_index ());
if (cell.shapes (s->layer ()).is_valid (s->shape ())) {
cell.shapes (s->layer ()).erase_shape (s->shape ());

View File

@ -198,6 +198,7 @@ public:
virtual void get_options (std::vector < std::pair<std::string, std::string> > &options) const
{
options.push_back (std::pair<std::string, std::string> (cfg_edit_top_level_selection, "false"));
options.push_back (std::pair<std::string, std::string> (cfg_edit_hier_copy_mode, "-1"));
options.push_back (std::pair<std::string, std::string> (cfg_edit_grid, ""));
options.push_back (std::pair<std::string, std::string> (cfg_edit_snap_to_objects, "false"));
options.push_back (std::pair<std::string, std::string> (cfg_edit_move_angle_mode, "any"));

View File

@ -113,6 +113,7 @@ Service::Service (db::Manager *manager, lay::LayoutView *view, db::ShapeIterator
m_connect_ac (lay::AC_Any), m_move_ac (lay::AC_Any), m_alt_ac (lay::AC_Global),
m_snap_to_objects (false),
m_top_level_sel (false), m_show_shapes_of_instances (true), m_max_shapes_of_instances (1000),
m_hier_copy_mode (-1),
m_indicate_secondary_selection (false),
m_seq (0),
dm_selection_to_view (this, &edt::Service::do_selection_to_view)
@ -134,6 +135,7 @@ Service::Service (db::Manager *manager, lay::LayoutView *view)
m_connect_ac (lay::AC_Any), m_move_ac (lay::AC_Any), m_alt_ac (lay::AC_Global),
m_snap_to_objects (true),
m_top_level_sel (false), m_show_shapes_of_instances (true), m_max_shapes_of_instances (1000),
m_hier_copy_mode (-1),
m_indicate_secondary_selection (false),
m_seq (0),
dm_selection_to_view (this, &edt::Service::do_selection_to_view)
@ -255,6 +257,8 @@ Service::configure (const std::string &name, const std::string &value)
return true; // taken
} else if (name == cfg_edit_top_level_selection) {
tl::from_string (value, m_top_level_sel);
} else if (name == cfg_edit_hier_copy_mode) {
tl::from_string (value, m_hier_copy_mode);
}
return false; // not taken
@ -309,18 +313,30 @@ Service::copy_selected ()
edt::CopyModeDialog mode_dialog (view ());
bool need_to_ask_for_copy_mode = false;
for (objects::const_iterator r = m_selection.begin (); r != m_selection.end () && ! need_to_ask_for_copy_mode; ++r) {
if (r->is_cell_inst ()) {
const db::Cell &cell = view ()->cellview (r->cv_index ())->layout ().cell (r->back ().inst_ptr.cell_index ());
if (! cell.is_proxy ()) {
need_to_ask_for_copy_mode = true;
unsigned int inst_mode = 0;
if (m_hier_copy_mode < 0) {
for (objects::const_iterator r = m_selection.begin (); r != m_selection.end () && ! need_to_ask_for_copy_mode; ++r) {
if (r->is_cell_inst ()) {
const db::Cell &cell = view ()->cellview (r->cv_index ())->layout ().cell (r->back ().inst_ptr.cell_index ());
if (! cell.is_proxy ()) {
need_to_ask_for_copy_mode = true;
}
}
}
} else {
inst_mode = (unsigned int) m_hier_copy_mode;
}
unsigned int inst_mode = 0;
bool dont_ask_again = false;
if (! need_to_ask_for_copy_mode || mode_dialog.exec_dialog (inst_mode)) {
if (! need_to_ask_for_copy_mode || mode_dialog.exec_dialog (inst_mode, dont_ask_again)) {
// store the given value "forever"
if (dont_ask_again) {
plugin_root ()->config_set (cfg_edit_hier_copy_mode, tl::to_string (inst_mode));
plugin_root ()->config_end ();
}
// create one ClipboardData object per cv_index because, this one assumes that there is
// only one source layout object.
@ -357,6 +373,9 @@ Service::begin_move (lay::Editable::MoveMode mode, const db::DPoint &p, lay::ang
{
if (view ()->is_editable () && mode == lay::Editable::Selected) {
// flush any pending updates of the markers
dm_selection_to_view.execute ();
m_move_start = p;
m_move_trans = db::DTrans ();
m_move_sel = true; // TODO: there is no "false". Remove this.
@ -1187,6 +1206,15 @@ Service::selection_applies (const lay::ObjectInstPath & /*sel*/) const
return false;
}
void
Service::transient_to_selection ()
{
if (! m_transient_selection.empty ()) {
m_selection.insert (m_transient_selection.begin (), m_transient_selection.end ());
selection_to_view ();
}
}
void
Service::clear_previous_selection ()
{

View File

@ -184,11 +184,6 @@ public:
*/
virtual bool select (const db::DBox &box, lay::Editable::SelectionMode mode);
/**
* @brief Clears the previous selection
*/
virtual void clear_previous_selection ();
/**
* @brief Returns true, if the given selected object is handled by this service
*/
@ -269,11 +264,21 @@ public:
*/
bool select (const lay::ObjectInstPath &obj, lay::Editable::SelectionMode mode);
/**
* @brief Clears the previous selection
*/
void clear_previous_selection ();
/**
* @brief Establish a transient selection
*/
bool transient_select (const db::DPoint &pos);
/**
* @brief Turns the transient selection to the selection
*/
virtual void transient_to_selection ();
/**
* @brief Clear the transient selection
*/
@ -574,6 +579,9 @@ private:
bool m_show_shapes_of_instances;
unsigned int m_max_shapes_of_instances;
// Hierarchical copy mode (-1: ask, 0: shallow, 1: deep)
int m_hier_copy_mode;
// Sequence number of selection
bool m_indicate_secondary_selection;
unsigned long m_seq;

View File

@ -1063,6 +1063,15 @@ Service::clear_previous_selection ()
m_previous_selection.clear ();
}
void
Service::transient_to_selection ()
{
if (mp_transient_view) {
m_selected.insert (std::make_pair (mp_transient_view->image_ref (), 0));
selection_to_view ();
}
}
bool
Service::select (obj_iterator obj, lay::Editable::SelectionMode mode)
{

View File

@ -304,6 +304,11 @@ public:
*/
virtual bool transient_select (const db::DPoint &pos);
/**
* @brief Turns the transient selection to the selection
*/
virtual void transient_to_selection ();
/**
* @brief Clear the transient selection
*/

View File

@ -2275,7 +2275,7 @@ MainWindow::do_cm_duplicate (bool interactive)
{
BEGIN_PROTECTED
if (current_view () && current_view ()->has_selection ()) {
if (current_view ()) {
// Do duplicate simply by concatenating copy & paste currently.
// Save the clipboard state before in order to preserve the current content
@ -2327,7 +2327,7 @@ MainWindow::cm_copy ()
{
BEGIN_PROTECTED
if (current_view () && current_view ()->has_selection ()) {
if (current_view ()) {
current_view ()->copy ();
current_view ()->clear_selection ();
}
@ -2370,7 +2370,7 @@ MainWindow::cm_cut ()
{
BEGIN_PROTECTED
if (current_view () && current_view ()->has_selection ()) {
if (current_view ()) {
current_view ()->cut ();
current_view ()->cancel (); // see del() for reason why cancel is after cut
current_view ()->clear_selection ();
@ -2766,21 +2766,6 @@ MainWindow::update_action_states ()
}
if (mp_menu->is_valid ("edit_menu.copy")) {
Action copy_action = mp_menu->action ("edit_menu.copy");
copy_action.set_enabled (current_view () && current_view ()->has_selection () && edits_enabled ());
}
if (mp_menu->is_valid ("edit_menu.duplicate")) {
Action copy_action = mp_menu->action ("edit_menu.duplicate");
copy_action.set_enabled (current_view () && current_view ()->has_selection () && edits_enabled ());
}
if (mp_menu->is_valid ("edit_menu.cut")) {
Action cut_action = mp_menu->action ("edit_menu.cut");
cut_action.set_enabled (current_view () && current_view ()->has_selection () && edits_enabled ());
}
if (mp_menu->is_valid ("edit_menu.paste")) {
Action paste_action = mp_menu->action ("edit_menu.paste");
paste_action.set_enabled (! db::Clipboard::instance ().empty () && edits_enabled ());

View File

@ -821,6 +821,29 @@ Class<lay::LayoutView> decl_LayoutView (QT_EXTERNAL_BASE (QWidget) "lay", "Layou
"selection. Calling this method is useful to ensure there are no potential interactions with the script's "
"functionality.\n"
) +
gsi::method ("clear_selection", &lay::LayoutView::clear_selection,
"@brief Clears the selection of all objects (shapes, annotations, images ...)\n"
"\n"
"This method has been introduced in version 0.26.2\n"
) +
gsi::method ("clear_transient_selection", &lay::LayoutView::clear_transient_selection,
"@brief Clears the transient selection (mouse-over hightlights) of all objects (shapes, annotations, images ...)\n"
"\n"
"This method has been introduced in version 0.26.2\n"
) +
gsi::method ("transient_to_selection", &lay::LayoutView::transient_to_selection,
"@brief Turns the transient selection into the actual selection\n"
"\n"
"The current selection is cleared before. All highlighted objects under the mouse will become selected. "
"This applies to all types of objects (rulers, shapes, images ...).\n"
"\n"
"This method has been introduced in version 0.26.2\n"
) +
gsi::method ("selection_bbox", &lay::LayoutView::selection_bbox,
"@brief Returns the bounding box of the current selection\n"
"\n"
"This method has been introduced in version 0.26.2\n"
) +
gsi::method ("stop", &lay::LayoutView::stop,
"@brief Stops redraw thread and close any browsers\n"
"This method usually does not need to be called explicitly. The redraw thread is stopped automatically."
@ -1077,7 +1100,6 @@ Class<lay::LayoutView> decl_LayoutView (QT_EXTERNAL_BASE (QWidget) "lay", "Layou
) +
gsi::method_ext ("delete_layers", &delete_layers1, gsi::arg ("iterators"),
"@brief Deletes the layer properties nodes specified by the iterator\n"
"@args iterators\n"
"\n"
"This method deletes the nodes specifies by the iterators. This method is the most convenient way to "
"delete multiple entries.\n"
@ -1837,9 +1859,8 @@ static void cv_show_all_cells (lay::CellViewRef *cv)
}
Class<lay::CellViewRef> decl_CellView ("lay", "CellView",
method ("==", static_cast<bool (lay::CellViewRef::*) (const lay::CellViewRef &) const> (&lay::CellViewRef::operator==),
method ("==", static_cast<bool (lay::CellViewRef::*) (const lay::CellViewRef &) const> (&lay::CellViewRef::operator==), gsi::arg ("other"),
"@brief Equality: indicates whether the cellviews refer to the same one\n"
"@args other\n"
"In version 0.25, the definition of the equality operator has been changed to reflect identity of the "
"cellview. Before that version, identity of the cell shown was implied."
) +
@ -1868,32 +1889,28 @@ Class<lay::CellViewRef> decl_CellView ("lay", "CellView",
"@brief Returns true, if the cellview is valid\n"
"A cellview may become invalid if the corresponding tab is closed for example."
) +
method ("path=|set_path", &lay::CellViewRef::set_unspecific_path,
method ("path=|set_path", &lay::CellViewRef::set_unspecific_path, gsi::arg ("path"),
"@brief Sets the unspecific part of the path explicitly\n"
"@args path\n"
"\n"
"Setting the unspecific part of the path will clear the context path component and\n"
"update the context and target cell.\n"
) +
method ("context_path=|set_context_path", &lay::CellViewRef::set_specific_path,
method ("context_path=|set_context_path", &lay::CellViewRef::set_specific_path, gsi::arg ("path"),
"@brief Sets the context path explicitly\n"
"@args path\n"
"\n"
"This method assumes that the unspecific part of the path \n"
"is established already and that the context path starts\n"
"from the context cell.\n"
) +
method ("cell_index=|set_cell", (void (lay::CellViewRef::*) (lay::CellViewRef::cell_index_type)) &lay::CellViewRef::set_cell,
method ("cell_index=|set_cell", (void (lay::CellViewRef::*) (lay::CellViewRef::cell_index_type)) &lay::CellViewRef::set_cell, gsi::arg ("cell_index"),
"@brief Sets the path to the given cell\n"
"@args cell_index\n"
"\n"
"This method will construct any path to this cell, not a \n"
"particular one. It will clear the context path\n"
"and update the context and target cell. Note that the cell is specified by it's index.\n"
) +
method ("cell_name=|set_cell_name", (void (lay::CellViewRef::*) (const std::string &)) &lay::CellViewRef::set_cell,
method ("cell_name=|set_cell_name", (void (lay::CellViewRef::*) (const std::string &)) &lay::CellViewRef::set_cell, gsi::arg ("cell_name"),
"@brief Sets the cell by name\n"
"@args cell_name\n"
"\n"
"If the name is not a valid one, the cellview will become\n"
"invalid.\n"
@ -1901,9 +1918,8 @@ Class<lay::CellViewRef> decl_CellView ("lay", "CellView",
"particular one. It will clear the context path\n"
"and update the context and target cell.\n"
) +
method_ext ("cell=", set_cell,
method_ext ("cell=", set_cell, gsi::arg ("cell"),
"@brief Sets the cell by reference to a Cell object\n"
"@args cell\n"
"Setting the cell reference to nil invalidates the cellview. "
"This method will construct any path to this cell, not a \n"
"particular one. It will clear the context path\n"
@ -1961,9 +1977,8 @@ Class<lay::CellViewRef> decl_CellView ("lay", "CellView",
"@brief Returns the technology name for the layout behind the given cell view\n"
"This method has been added in version 0.23.\n"
) +
method_ext ("technology=", &apply_technology,
method_ext ("technology=", &apply_technology, gsi::arg ("tech_name"),
"@brief Sets the technology for the layout behind the given cell view\n"
"@args tech_name\n"
"According to the specification of the technology, new layer properties may be loaded "
"or the net tracer may be reconfigured. If the layout is shown in multiple views, the "
"technology is updated for all views.\n"
@ -1972,9 +1987,8 @@ Class<lay::CellViewRef> decl_CellView ("lay", "CellView",
method_ext ("layout", &get_layout,
"@brief Gets the reference to the layout object addressed by this view\n"
) +
method_ext ("descend", &cv_descend,
method_ext ("descend", &cv_descend, gsi::arg ("path"),
"@brief Descends further into the hierarchy.\n"
"@args path\n"
"Adds the given path (given as an array of InstElement objects) to the specific path of the "
"cellview with the given index. In effect, the cell addressed by the terminal of the new path "
"components can be shown in the context of the upper cells, if the minimum hierarchy level is "

View File

@ -301,6 +301,22 @@ Editables::clear_transient_selection ()
signal_transient_selection_changed ();
}
void
Editables::transient_to_selection ()
{
cancel_edits ();
for (iterator e = begin (); e != end (); ++e) {
e->select (db::DBox (), lay::Editable::Reset); // clear selection
e->clear_previous_selection ();
e->transient_to_selection ();
e->clear_transient_selection ();
}
// send a signal to the observers
signal_transient_selection_changed ();
signal_selection_changed ();
}
void
Editables::clear_selection ()
{

View File

@ -182,6 +182,14 @@ public:
return false;
}
/**
* @brief Turns the transient selection to the selection
*/
virtual void transient_to_selection ()
{
// .. nothing yet ..
}
/**
* @brief Clear the transient selection
*
@ -418,7 +426,7 @@ public:
* or must be given in micron units.
*/
db::DBox selection_bbox ();
/**
* @brief transform the selection
*
@ -457,6 +465,11 @@ public:
*/
void clear_transient_selection ();
/**
* @brief Turns the transient selection to the selection
*/
void transient_to_selection ();
/**
* @brief Clear the previous selection
*

View File

@ -5154,7 +5154,7 @@ LayoutView::paste_interactive ()
// operations.
trans->close ();
if (mp_move_service->begin_move (trans.release ())) {
if (mp_move_service->begin_move (trans.release (), false)) {
switch_mode (-1); // move mode
}
}
@ -5167,7 +5167,14 @@ LayoutView::copy ()
} else if (mp_control_panel && mp_control_panel->has_focus ()) {
mp_control_panel->copy ();
} else {
if (lay::Editables::selection_size () == 0) {
// try to use the transient selection for the real one
lay::Editables::transient_to_selection ();
}
lay::Editables::copy ();
}
}
@ -5182,8 +5189,15 @@ LayoutView::cut ()
db::Transaction trans (manager (), tl::to_string (QObject::tr ("Cut Layers")));
mp_control_panel->cut ();
} else {
if (lay::Editables::selection_size () == 0) {
// try to use the transient selection for the real one
lay::Editables::transient_to_selection ();
}
db::Transaction trans (manager (), tl::to_string (QObject::tr ("Cut")));
lay::Editables::cut ();
}
}

View File

@ -38,6 +38,7 @@ MoveService::MoveService (lay::LayoutView *view)
: QObject (),
lay::ViewService (view->view_object_widget ()),
m_dragging (false),
m_dragging_transient (false),
mp_editables (view),
mp_view (view),
m_global_grid (0.001)
@ -148,6 +149,9 @@ MoveService::mouse_move_event (const db::DPoint &p, unsigned int buttons, bool p
}
// track mouse position for the infix move initiation
m_mouse_pos = p;
return ret; // not taken to allow the mouse tracker to receive events as well
}
@ -163,7 +167,7 @@ MoveService::mouse_click_event (const db::DPoint &p, unsigned int buttons, bool
return true;
}
if (prio && (buttons & lay::LeftButton) != 0) {
if (handle_dragging (p, buttons, 0)) {
if (handle_dragging (p, buttons, false, 0)) {
return true;
}
}
@ -216,7 +220,7 @@ bool
MoveService::mouse_press_event (const db::DPoint &p, unsigned int buttons, bool prio)
{
if (prio && (buttons & lay::LeftButton) != 0) {
if (handle_dragging (p, buttons, 0)) {
if (handle_dragging (p, buttons, false, 0)) {
return true;
}
}
@ -230,26 +234,50 @@ MoveService::mouse_press_event (const db::DPoint &p, unsigned int buttons, bool
}
bool
MoveService::begin_move (db::Transaction *transaction)
MoveService::begin_move (db::Transaction *transaction, bool selected_after_move)
{
if (m_dragging) {
return false;
}
std::auto_ptr<db::Transaction> trans_holder (transaction);
drag_cancel ();
bool drag_transient = ! selected_after_move;
if (mp_editables->selection_size () == 0) {
// try to use the transient selection for the real one
mp_editables->transient_to_selection ();
drag_transient = true;
}
if (mp_editables->selection_size () == 0) {
// still nothing selected
return false;
}
db::DBox bbox = mp_editables->selection_bbox ();
if (bbox.empty ()) {
// nothing selected
// nothing (useful) selected
return false;
}
set_cursor (lay::Cursor::size_all);
// emulate a "begin move" at the center of the selection bbox - this will become the reference point
return handle_dragging (bbox.center (), 0, trans_holder.release ());
// emulate a "begin move" at the current mouse position if inside the box or the closest point
// of the box.
db::DPoint pstart = m_mouse_pos;
if (! bbox.contains (pstart)) {
pstart.set_x (std::max (pstart.x (), bbox.p1 ().x ()));
pstart.set_x (std::min (pstart.x (), bbox.p2 ().x ()));
pstart.set_y (std::max (pstart.y (), bbox.p1 ().y ()));
pstart.set_y (std::min (pstart.y (), bbox.p2 ().y ()));
}
return handle_dragging (pstart, 0, drag_transient, trans_holder.release ());
}
bool
MoveService::handle_dragging (const db::DPoint &p, unsigned int buttons, db::Transaction *transaction)
MoveService::handle_dragging (const db::DPoint &p, unsigned int buttons, bool drag_transient, db::Transaction *transaction)
{
std::auto_ptr<db::Transaction> trans_holder (transaction);
@ -267,6 +295,7 @@ MoveService::handle_dragging (const db::DPoint &p, unsigned int buttons, db::Tra
mp_view->clear_transient_selection ();
m_dragging = true;
m_dragging_transient = drag_transient;
widget ()->grab_mouse (this, false);
m_shift = db::DPoint ();
@ -278,8 +307,14 @@ MoveService::handle_dragging (const db::DPoint &p, unsigned int buttons, db::Tra
} else {
m_dragging = false;
widget ()->ungrab_mouse (this);
mp_editables->end_move (p, ac_from_buttons (buttons), mp_transaction.release ());
if (m_dragging_transient) {
mp_editables->clear_selection ();
}
return true;
}

View File

@ -49,7 +49,7 @@ public:
~MoveService ();
virtual bool configure (const std::string &name, const std::string &value);
bool begin_move (db::Transaction *transaction = 0);
bool begin_move (db::Transaction *transaction = 0, bool selected_after_move = true);
private:
virtual bool mouse_press_event (const db::DPoint &p, unsigned int buttons, bool prio);
@ -62,13 +62,15 @@ private:
virtual void drag_cancel ();
virtual void deactivated ();
bool handle_dragging (const db::DPoint &p, unsigned int buttons, db::Transaction *transaction);
bool handle_dragging (const db::DPoint &p, unsigned int buttons, bool drag_transient, db::Transaction *transaction);
bool m_dragging;
bool m_dragging_transient;
lay::Editables *mp_editables;
lay::LayoutView *mp_view;
double m_global_grid;
db::DPoint m_shift;
db::DPoint m_mouse_pos;
std::auto_ptr<db::Transaction> mp_transaction;
};

View File

@ -240,7 +240,8 @@ void Macro::load_from (const std::string &fn)
} else if (m_format == PlainTextFormat || m_format == PlainTextWithHashAnnotationsFormat) {
tl::InputStream stream (path);
m_text = stream.read_all ();
tl::TextInputStream text_stream (stream);
m_text = text_stream.read_all ();
sync_properties_with_text ();
}

View File

@ -422,6 +422,30 @@ TextInputStream::TextInputStream (InputStream &stream)
}
}
std::string
TextInputStream::read_all ()
{
return read_all (std::numeric_limits<size_t>::max ());
}
std::string
TextInputStream::read_all (size_t max_count)
{
std::string text;
while (! at_end () && max_count > 0) {
char c = get_char ();
if (c == 0) {
break;
} else {
--max_count;
text += c;
}
}
return text;
}
const std::string &
TextInputStream::get_line ()
{
@ -430,9 +454,7 @@ TextInputStream::get_line ()
while (! at_end ()) {
char c = get_char ();
if (c == '\r') {
// simply skip CR
} else if (c == '\n' || c == 0) {
if (c == '\n' || c == 0) {
break;
} else {
m_line_buffer += c;
@ -445,31 +467,35 @@ TextInputStream::get_line ()
char
TextInputStream::get_char ()
{
m_line = m_next_line;
const char *c = m_stream.get (1);
if (c == 0) {
m_at_end = true;
return 0;
} else {
if (*c == '\n') {
++m_next_line;
while (true) {
m_line = m_next_line;
const char *c = m_stream.get (1);
if (c == 0) {
m_at_end = true;
return 0;
} else if (*c != '\r' && *c) {
if (*c == '\n') {
++m_next_line;
}
return *c;
}
return *c;
}
}
char
TextInputStream::peek_char ()
{
m_line = m_next_line;
const char *c = m_stream.get (1);
if (c == 0) {
m_at_end = true;
return 0;
} else {
char cc = *c;
m_stream.unget (1);
return cc;
while (true) {
m_line = m_next_line;
const char *c = m_stream.get (1);
if (c == 0) {
m_at_end = true;
return 0;
} else if (*c != '\r' && *c) {
char cc = *c;
m_stream.unget (1);
return cc;
}
}
}

View File

@ -564,7 +564,7 @@ private:
// ---------------------------------------------------------------------------------
/**
* @brief An ASCII input stream
* @brief A text input stream (UTF8 encoded)
*
* This class is put in front of a InputStream to format the input as text input stream.
*/
@ -591,6 +591,18 @@ public:
*/
const std::string &get_line ();
/**
* @brief Reads all remaining bytes into the string
*/
std::string read_all ();
/**
* @brief Reads all remaining bytes into the string
*
* This function reads all remaining of max_count bytes.
*/
std::string read_all (size_t max_count);
/**
* @brief Get a single character
*/

View File

@ -107,3 +107,41 @@ TEST(TextOutputStream)
throw;
}
}
TEST(TextInputStream)
{
std::string fn = tmp_file ("test.txt");
{
tl::OutputStream os (fn, tl::OutputStream::OM_Auto, false);
os << "Hello, world!\nWith another line\n\r\r\nseparated by a LFCR and CRLF.";
}
{
tl::InputStream is (fn);
tl::TextInputStream tis (is);
EXPECT_EQ (tis.get_line (), "Hello, world!");
EXPECT_EQ (tis.line_number (), 1);
EXPECT_EQ (tis.get_line (), "With another line");
EXPECT_EQ (tis.line_number (), 2);
EXPECT_EQ (tis.peek_char (), '\n');
EXPECT_EQ (tis.get_line (), "");
EXPECT_EQ (tis.line_number (), 3);
EXPECT_EQ (tis.peek_char (), 's');
EXPECT_EQ (tis.get_line (), "separated by a LFCR and CRLF.");
EXPECT_EQ (tis.line_number (), 4);
EXPECT_EQ (tis.at_end (), true);
}
{
tl::InputStream is (fn);
tl::TextInputStream tis (is);
EXPECT_EQ (tis.read_all (5), "Hello");
}
{
tl::InputStream is (fn);
tl::TextInputStream tis (is);
EXPECT_EQ (tis.read_all (), "Hello, world!\nWith another line\n\nseparated by a LFCR and CRLF.");
}
}

22
testdata/algo/nreader11.cir vendored Normal file
View File

@ -0,0 +1,22 @@
* written by unit test
* cell SUBCKT
* pin
* pin A
* pin V42
* pin Z
* pin gnd
* pin gnd
.SUBCKT SUBCKT \$1 A[5]<1> V42\x28\x25\x29 Z gnd gnd$1
XD_$1 V42\x28\x25\x29 \$3 Z \$1 HVPMOS PARAMS: L=0.2 W=1 AS=0.18 AD=0.18
+ PS=2.16 PD=2.16
* device instance $2 r0 *1 0,0 HVPMOS
XD_$2 V42\x28\x25\x29 A[5]<1> \$3 \$1 HVPMOS PARAMS: L=0.2 W=1 AS=0.18 AD=0.18
+ PS=2.16 PD=2.16
XD_$3 gnd \$3 gnd gnd$1 HVNMOS PARAMS: L=1.13 W=2.12 PS=6 PD=6 AS=0 AD=0
XD_$4 gnd \$3 Z gnd$1 HVNMOS PARAMS: L=0.4 W=0.4 PS=1.16 PD=1.16 AS=0.19 AD=0.19
XD_$5 gnd A[5]<1> \$3 gnd$1 HVNMOS PARAMS: L=0.4 W=0.4 PS=1.76 PD=1.76 AS=0.19 AD=0.19
.ENDS SUBCKT
.SUBCKT SUBCKT \$1 A[5]<1> V42\x28\x25\x29 Z gnd gnd$1
XD_$13 gnd \$3 gnd gnd$1 HVNMOS PARAMS: L=1.13 W=2.12 PS=6 PD=6 AS=0 AD=0
.ENDS SUBCKT

View File

@ -530,6 +530,40 @@ class Ant_TestClass < TestBase
end
# each_annotation_selected
def test_4
if !RBA.constants.member?(:Application)
return
end
mw = RBA::Application::instance.main_window
mw.close_all
mw.create_layout( 0 )
lv = mw.current_view
a = annot_obj( RBA::DPoint::new( 1.0, 2.0 ), RBA::DPoint::new( 3.0, 4.0 ), "a", "b", "c", 1, 2, false, 3 )
assert_equal( a.is_valid?, false )
lv.insert_annotation( a )
mw.cm_select_all
arr = []
lv.each_annotation_selected { |a| arr.push(a) }
assert_equal(arr.size, 1)
assert_equal(arr[0].to_s, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal")
arr[0].p1 = RBA::DPoint::new(11, 12)
arr = []
lv.each_annotation_selected { |a| arr.push(a) }
assert_equal(arr.size, 1)
assert_equal(arr[0].to_s, "p1=11,12, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal")
mw.close_all
end
end
load("test_epilogue.rb")